├── .NET ├── library │ ├── .gitignore │ ├── Controllers │ │ ├── AuthorController.cs │ │ ├── BookController.cs │ │ ├── BorrowerController.cs │ │ └── CatalogueController.cs │ ├── DataAccess │ │ ├── AuthorRepository.cs │ │ ├── BookRepository.cs │ │ ├── BorrowerRepository.cs │ │ ├── CatalogueRepository.cs │ │ ├── IAuthorRepository.cs │ │ ├── IBookRepository.cs │ │ ├── IBorrowerRepository.cs │ │ ├── ICatalogueRepository.cs │ │ └── LibraryContext.cs │ ├── Model │ │ ├── Author.cs │ │ ├── Book.cs │ │ ├── BookFormat.cs │ │ ├── BookStock.cs │ │ ├── Borrower.cs │ │ └── CatalogueSearch.cs │ ├── OneBeyondApi.csproj │ ├── OneBeyondApi.sln │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── README.md │ ├── SeedData.cs │ ├── appsettings.Development.json │ └── appsettings.json └── martian-robots │ └── instructions.md ├── .gitignore ├── LICENSE ├── PHP └── library-api-php │ ├── README.md │ ├── controllers │ ├── BookController.php │ ├── LoanController.php │ └── ReservationController.php │ ├── data │ └── data.php │ ├── index.php │ └── models │ ├── Author.php │ ├── Book.php │ ├── BookStock.php │ ├── Borrower.php │ ├── Fine.php │ └── Reservation.php ├── README.md ├── data └── covid │ ├── dataset.7z │ └── instructions.md ├── java ├── fish-tank │ └── instructions.md ├── martian-robots │ └── instructions.md └── tennis-score │ └── instructions.md ├── node ├── fish-tank │ └── instructions.md ├── martian-robots │ └── instructions.md └── tennis-score │ └── instructions.md └── react ├── mysterious-api └── instructions.md └── phone-catalogue ├── images ├── Galaxy_S7.png ├── Honor_10.png ├── IPhone_7.png ├── Moto_G6.png ├── Nokia_7.1.jpg ├── P10_Lite.jpg ├── Xiaomi_MI_A2.jpeg └── ZenPhone_5.jpg ├── instructions.md └── phones.json /.NET/library/.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 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Ll]og/ 33 | [Ll]ogs/ 34 | 35 | # Visual Studio 2015/2017 cache/options directory 36 | .vs/ 37 | # Uncomment if you have tasks that create the project's static files in wwwroot 38 | #wwwroot/ 39 | 40 | # Visual Studio 2017 auto generated files 41 | Generated\ Files/ 42 | 43 | # MSTest test Results 44 | [Tt]est[Rr]esult*/ 45 | [Bb]uild[Ll]og.* 46 | 47 | # NUnit 48 | *.VisualState.xml 49 | TestResult.xml 50 | nunit-*.xml 51 | 52 | # Build Results of an ATL Project 53 | [Dd]ebugPS/ 54 | [Rr]eleasePS/ 55 | dlldata.c 56 | 57 | # Benchmark Results 58 | BenchmarkDotNet.Artifacts/ 59 | 60 | # .NET Core 61 | project.lock.json 62 | project.fragment.lock.json 63 | artifacts/ 64 | 65 | # ASP.NET Scaffolding 66 | ScaffoldingReadMe.txt 67 | 68 | # StyleCop 69 | StyleCopReport.xml 70 | 71 | # Files built by Visual Studio 72 | *_i.c 73 | *_p.c 74 | *_h.h 75 | *.ilk 76 | *.meta 77 | *.obj 78 | *.iobj 79 | *.pch 80 | *.pdb 81 | *.ipdb 82 | *.pgc 83 | *.pgd 84 | *.rsp 85 | *.sbr 86 | *.tlb 87 | *.tli 88 | *.tlh 89 | *.tmp 90 | *.tmp_proj 91 | *_wpftmp.csproj 92 | *.log 93 | *.vspscc 94 | *.vssscc 95 | .builds 96 | *.pidb 97 | *.svclog 98 | *.scc 99 | 100 | # Chutzpah Test files 101 | _Chutzpah* 102 | 103 | # Visual C++ cache files 104 | ipch/ 105 | *.aps 106 | *.ncb 107 | *.opendb 108 | *.opensdf 109 | *.sdf 110 | *.cachefile 111 | *.VC.db 112 | *.VC.VC.opendb 113 | 114 | # Visual Studio profiler 115 | *.psess 116 | *.vsp 117 | *.vspx 118 | *.sap 119 | 120 | # Visual Studio Trace Files 121 | *.e2e 122 | 123 | # TFS 2012 Local Workspace 124 | $tf/ 125 | 126 | # Guidance Automation Toolkit 127 | *.gpState 128 | 129 | # ReSharper is a .NET coding add-in 130 | _ReSharper*/ 131 | *.[Rr]e[Ss]harper 132 | *.DotSettings.user 133 | 134 | # TeamCity is a build add-in 135 | _TeamCity* 136 | 137 | # DotCover is a Code Coverage Tool 138 | *.dotCover 139 | 140 | # AxoCover is a Code Coverage Tool 141 | .axoCover/* 142 | !.axoCover/settings.json 143 | 144 | # Coverlet is a free, cross platform Code Coverage Tool 145 | coverage*.json 146 | coverage*.xml 147 | coverage*.info 148 | 149 | # Visual Studio code coverage results 150 | *.coverage 151 | *.coveragexml 152 | 153 | # NCrunch 154 | _NCrunch_* 155 | .*crunch*.local.xml 156 | nCrunchTemp_* 157 | 158 | # MightyMoose 159 | *.mm.* 160 | AutoTest.Net/ 161 | 162 | # Web workbench (sass) 163 | .sass-cache/ 164 | 165 | # Installshield output folder 166 | [Ee]xpress/ 167 | 168 | # DocProject is a documentation generator add-in 169 | DocProject/buildhelp/ 170 | DocProject/Help/*.HxT 171 | DocProject/Help/*.HxC 172 | DocProject/Help/*.hhc 173 | DocProject/Help/*.hhk 174 | DocProject/Help/*.hhp 175 | DocProject/Help/Html2 176 | DocProject/Help/html 177 | 178 | # Click-Once directory 179 | publish/ 180 | 181 | # Publish Web Output 182 | *.[Pp]ublish.xml 183 | *.azurePubxml 184 | # Note: Comment the next line if you want to checkin your web deploy settings, 185 | # but database connection strings (with potential passwords) will be unencrypted 186 | *.pubxml 187 | *.publishproj 188 | 189 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 190 | # checkin your Azure Web App publish settings, but sensitive information contained 191 | # in these scripts will be unencrypted 192 | PublishScripts/ 193 | 194 | # NuGet Packages 195 | *.nupkg 196 | # NuGet Symbol Packages 197 | *.snupkg 198 | # The packages folder can be ignored because of Package Restore 199 | **/[Pp]ackages/* 200 | # except build/, which is used as an MSBuild target. 201 | !**/[Pp]ackages/build/ 202 | # Uncomment if necessary however generally it will be regenerated when needed 203 | #!**/[Pp]ackages/repositories.config 204 | # NuGet v3's project.json files produces more ignorable files 205 | *.nuget.props 206 | *.nuget.targets 207 | 208 | # Microsoft Azure Build Output 209 | csx/ 210 | *.build.csdef 211 | 212 | # Microsoft Azure Emulator 213 | ecf/ 214 | rcf/ 215 | 216 | # Windows Store app package directories and files 217 | AppPackages/ 218 | BundleArtifacts/ 219 | Package.StoreAssociation.xml 220 | _pkginfo.txt 221 | *.appx 222 | *.appxbundle 223 | *.appxupload 224 | 225 | # Visual Studio cache files 226 | # files ending in .cache can be ignored 227 | *.[Cc]ache 228 | # but keep track of directories ending in .cache 229 | !?*.[Cc]ache/ 230 | 231 | # Others 232 | ClientBin/ 233 | ~$* 234 | *~ 235 | *.dbmdl 236 | *.dbproj.schemaview 237 | *.jfm 238 | *.pfx 239 | *.publishsettings 240 | orleans.codegen.cs 241 | 242 | # Including strong name files can present a security risk 243 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 244 | #*.snk 245 | 246 | # Since there are multiple workflows, uncomment next line to ignore bower_components 247 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 248 | #bower_components/ 249 | 250 | # RIA/Silverlight projects 251 | Generated_Code/ 252 | 253 | # Backup & report files from converting an old project file 254 | # to a newer Visual Studio version. Backup files are not needed, 255 | # because we have git ;-) 256 | _UpgradeReport_Files/ 257 | Backup*/ 258 | UpgradeLog*.XML 259 | UpgradeLog*.htm 260 | ServiceFabricBackup/ 261 | *.rptproj.bak 262 | 263 | # SQL Server files 264 | *.mdf 265 | *.ldf 266 | *.ndf 267 | 268 | # Business Intelligence projects 269 | *.rdl.data 270 | *.bim.layout 271 | *.bim_*.settings 272 | *.rptproj.rsuser 273 | *- [Bb]ackup.rdl 274 | *- [Bb]ackup ([0-9]).rdl 275 | *- [Bb]ackup ([0-9][0-9]).rdl 276 | 277 | # Microsoft Fakes 278 | FakesAssemblies/ 279 | 280 | # GhostDoc plugin setting file 281 | *.GhostDoc.xml 282 | 283 | # Node.js Tools for Visual Studio 284 | .ntvs_analysis.dat 285 | node_modules/ 286 | 287 | # Visual Studio 6 build log 288 | *.plg 289 | 290 | # Visual Studio 6 workspace options file 291 | *.opt 292 | 293 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 294 | *.vbw 295 | 296 | # Visual Studio LightSwitch build output 297 | **/*.HTMLClient/GeneratedArtifacts 298 | **/*.DesktopClient/GeneratedArtifacts 299 | **/*.DesktopClient/ModelManifest.xml 300 | **/*.Server/GeneratedArtifacts 301 | **/*.Server/ModelManifest.xml 302 | _Pvt_Extensions 303 | 304 | # Paket dependency manager 305 | .paket/paket.exe 306 | paket-files/ 307 | 308 | # FAKE - F# Make 309 | .fake/ 310 | 311 | # CodeRush personal settings 312 | .cr/personal 313 | 314 | # Python Tools for Visual Studio (PTVS) 315 | __pycache__/ 316 | *.pyc 317 | 318 | # Cake - Uncomment if you are using it 319 | # tools/** 320 | # !tools/packages.config 321 | 322 | # Tabs Studio 323 | *.tss 324 | 325 | # Telerik's JustMock configuration file 326 | *.jmconfig 327 | 328 | # BizTalk build output 329 | *.btp.cs 330 | *.btm.cs 331 | *.odx.cs 332 | *.xsd.cs 333 | 334 | # OpenCover UI analysis results 335 | OpenCover/ 336 | 337 | # Azure Stream Analytics local run output 338 | ASALocalRun/ 339 | 340 | # MSBuild Binary and Structured Log 341 | *.binlog 342 | 343 | # NVidia Nsight GPU debugger configuration file 344 | *.nvuser 345 | 346 | # MFractors (Xamarin productivity tool) working folder 347 | .mfractor/ 348 | 349 | # Local History for Visual Studio 350 | .localhistory/ 351 | 352 | # BeatPulse healthcheck temp database 353 | healthchecksdb 354 | 355 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 356 | MigrationBackup/ 357 | 358 | # Ionide (cross platform F# VS Code tools) working folder 359 | .ionide/ 360 | 361 | # Fody - auto-generated XML schema 362 | FodyWeavers.xsd 363 | -------------------------------------------------------------------------------- /.NET/library/Controllers/AuthorController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using OneBeyondApi.DataAccess; 3 | using OneBeyondApi.Model; 4 | using System.Collections; 5 | 6 | namespace OneBeyondApi.Controllers 7 | { 8 | [ApiController] 9 | [Route("[controller]")] 10 | public class AuthorController : ControllerBase 11 | { 12 | private readonly ILogger _logger; 13 | private readonly IAuthorRepository _authorRepository; 14 | 15 | public AuthorController(ILogger logger, IAuthorRepository authorRepository) 16 | { 17 | _logger = logger; 18 | _authorRepository = authorRepository; 19 | } 20 | 21 | [HttpGet] 22 | [Route("GetAuthors")] 23 | public IList Get() 24 | { 25 | return _authorRepository.GetAuthors(); 26 | } 27 | 28 | [HttpPost] 29 | [Route("AddAuthor")] 30 | public Guid Post(Author author) 31 | { 32 | return _authorRepository.AddAuthor(author); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /.NET/library/Controllers/BookController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using OneBeyondApi.DataAccess; 3 | using OneBeyondApi.Model; 4 | using System.Collections; 5 | 6 | namespace OneBeyondApi.Controllers 7 | { 8 | [ApiController] 9 | [Route("[controller]")] 10 | public class BookController : ControllerBase 11 | { 12 | private readonly ILogger _logger; 13 | private readonly IBookRepository _bookRepository; 14 | 15 | public BookController(ILogger logger, IBookRepository bookRepository) 16 | { 17 | _logger = logger; 18 | _bookRepository = bookRepository; 19 | } 20 | 21 | [HttpGet] 22 | [Route("GetBooks")] 23 | public IList Get() 24 | { 25 | return _bookRepository.GetBooks(); 26 | } 27 | 28 | [HttpPost] 29 | [Route("AddBook")] 30 | public Guid Post(Book book) 31 | { 32 | return _bookRepository.AddBook(book); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /.NET/library/Controllers/BorrowerController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using OneBeyondApi.DataAccess; 3 | using OneBeyondApi.Model; 4 | using System.Collections; 5 | 6 | namespace OneBeyondApi.Controllers 7 | { 8 | [ApiController] 9 | [Route("[controller]")] 10 | public class BorrowerController : ControllerBase 11 | { 12 | private readonly ILogger _logger; 13 | private readonly IBorrowerRepository _borrowerRepository; 14 | 15 | public BorrowerController(ILogger logger, IBorrowerRepository borrowerRepository) 16 | { 17 | _logger = logger; 18 | _borrowerRepository = borrowerRepository; 19 | } 20 | 21 | [HttpGet] 22 | [Route("GetBorrowers")] 23 | public IList Get() 24 | { 25 | return _borrowerRepository.GetBorrowers(); 26 | } 27 | 28 | [HttpPost] 29 | [Route("AddBorrower")] 30 | public Guid Post(Borrower borrower) 31 | { 32 | return _borrowerRepository.AddBorrower(borrower); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /.NET/library/Controllers/CatalogueController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using OneBeyondApi.DataAccess; 3 | using OneBeyondApi.Model; 4 | using System.Collections; 5 | 6 | namespace OneBeyondApi.Controllers 7 | { 8 | [ApiController] 9 | [Route("[controller]")] 10 | public class CatalogueController : ControllerBase 11 | { 12 | private readonly ILogger _logger; 13 | private readonly ICatalogueRepository _catalogueRepository; 14 | 15 | public CatalogueController(ILogger logger, ICatalogueRepository catalogueRepository) 16 | { 17 | _logger = logger; 18 | _catalogueRepository = catalogueRepository; 19 | } 20 | 21 | [HttpGet] 22 | [Route("GetCatalogue")] 23 | public IList Get() 24 | { 25 | return _catalogueRepository.GetCatalogue(); 26 | } 27 | 28 | [HttpPost] 29 | [Route("SearchCatalogue")] 30 | public IList Post(CatalogueSearch search) 31 | { 32 | return _catalogueRepository.SearchCatalogue(search); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /.NET/library/DataAccess/AuthorRepository.cs: -------------------------------------------------------------------------------- 1 | using OneBeyondApi.Model; 2 | 3 | namespace OneBeyondApi.DataAccess 4 | { 5 | public class AuthorRepository : IAuthorRepository 6 | { 7 | public AuthorRepository() 8 | { 9 | } 10 | public List GetAuthors() 11 | { 12 | using (var context = new LibraryContext()) 13 | { 14 | var list = context.Authors 15 | .ToList(); 16 | return list; 17 | } 18 | } 19 | 20 | public Guid AddAuthor(Author author) 21 | { 22 | using (var context = new LibraryContext()) 23 | { 24 | context.Authors.Add(author); 25 | context.SaveChanges(); 26 | return author.Id; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /.NET/library/DataAccess/BookRepository.cs: -------------------------------------------------------------------------------- 1 | using OneBeyondApi.Model; 2 | 3 | namespace OneBeyondApi.DataAccess 4 | { 5 | public class BookRepository : IBookRepository 6 | { 7 | public BookRepository() 8 | { 9 | } 10 | public List GetBooks() 11 | { 12 | using (var context = new LibraryContext()) 13 | { 14 | var list = context.Books 15 | .ToList(); 16 | return list; 17 | } 18 | } 19 | 20 | public Guid AddBook(Book book) 21 | { 22 | using (var context = new LibraryContext()) 23 | { 24 | context.Books.Add(book); 25 | context.SaveChanges(); 26 | return book.Id; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /.NET/library/DataAccess/BorrowerRepository.cs: -------------------------------------------------------------------------------- 1 | using OneBeyondApi.Model; 2 | 3 | namespace OneBeyondApi.DataAccess 4 | { 5 | public class BorrowerRepository : IBorrowerRepository 6 | { 7 | public BorrowerRepository() 8 | { 9 | } 10 | public List GetBorrowers() 11 | { 12 | using (var context = new LibraryContext()) 13 | { 14 | var list = context.Borrowers 15 | .ToList(); 16 | return list; 17 | } 18 | } 19 | 20 | public Guid AddBorrower(Borrower borrower) 21 | { 22 | using (var context = new LibraryContext()) 23 | { 24 | context.Borrowers.Add(borrower); 25 | context.SaveChanges(); 26 | return borrower.Id; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /.NET/library/DataAccess/CatalogueRepository.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using OneBeyondApi.Model; 3 | 4 | namespace OneBeyondApi.DataAccess 5 | { 6 | public class CatalogueRepository : ICatalogueRepository 7 | { 8 | public CatalogueRepository() 9 | { 10 | } 11 | public List GetCatalogue() 12 | { 13 | using (var context = new LibraryContext()) 14 | { 15 | var list = context.Catalogue 16 | .Include(x => x.Book) 17 | .ThenInclude(x => x.Author) 18 | .Include(x => x.OnLoanTo) 19 | .ToList(); 20 | return list; 21 | } 22 | } 23 | 24 | public List SearchCatalogue(CatalogueSearch search) 25 | { 26 | using (var context = new LibraryContext()) 27 | { 28 | var list = context.Catalogue 29 | .Include(x => x.Book) 30 | .ThenInclude(x => x.Author) 31 | .Include(x => x.OnLoanTo) 32 | .AsQueryable(); 33 | 34 | if (search != null) 35 | { 36 | if (!string.IsNullOrEmpty(search.Author)) { 37 | list = list.Where(x => x.Book.Author.Name.Contains(search.Author)); 38 | } 39 | if (!string.IsNullOrEmpty(search.BookName)) { 40 | list = list.Where(x => x.Book.Name.Contains(search.BookName)); 41 | } 42 | } 43 | 44 | return list.ToList(); 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /.NET/library/DataAccess/IAuthorRepository.cs: -------------------------------------------------------------------------------- 1 | using OneBeyondApi.Model; 2 | 3 | namespace OneBeyondApi.DataAccess 4 | { 5 | public interface IAuthorRepository 6 | { 7 | public List GetAuthors(); 8 | 9 | public Guid AddAuthor(Author author); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /.NET/library/DataAccess/IBookRepository.cs: -------------------------------------------------------------------------------- 1 | using OneBeyondApi.Model; 2 | 3 | namespace OneBeyondApi.DataAccess 4 | { 5 | public interface IBookRepository 6 | { 7 | public List GetBooks(); 8 | 9 | public Guid AddBook(Book book); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /.NET/library/DataAccess/IBorrowerRepository.cs: -------------------------------------------------------------------------------- 1 | using OneBeyondApi.Model; 2 | 3 | namespace OneBeyondApi.DataAccess 4 | { 5 | public interface IBorrowerRepository 6 | { 7 | public List GetBorrowers(); 8 | 9 | public Guid AddBorrower(Borrower borrower); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /.NET/library/DataAccess/ICatalogueRepository.cs: -------------------------------------------------------------------------------- 1 | using OneBeyondApi.Model; 2 | 3 | namespace OneBeyondApi.DataAccess 4 | { 5 | public interface ICatalogueRepository 6 | { 7 | public List GetCatalogue(); 8 | 9 | public List SearchCatalogue(CatalogueSearch search); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /.NET/library/DataAccess/LibraryContext.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using OneBeyondApi.Model; 3 | 4 | namespace OneBeyondApi.DataAccess 5 | { 6 | public class LibraryContext: DbContext 7 | { 8 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) 9 | { 10 | optionsBuilder.UseInMemoryDatabase(databaseName: "AuthorDb"); 11 | } 12 | public DbSet Authors { get; set; } 13 | public DbSet Books { get; set; } 14 | public DbSet Catalogue { get; set; } 15 | public DbSet Borrowers { get; set; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.NET/library/Model/Author.cs: -------------------------------------------------------------------------------- 1 | namespace OneBeyondApi.Model 2 | { 3 | public class Author 4 | { 5 | public Guid Id { get; set; } 6 | public string Name { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /.NET/library/Model/Book.cs: -------------------------------------------------------------------------------- 1 | namespace OneBeyondApi.Model 2 | { 3 | public class Book 4 | { 5 | public Guid Id { get; set; } 6 | public string Name { get; set; } 7 | public Author Author { get; set; } 8 | public BookFormat Format { get; set; } 9 | public string ISBN { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /.NET/library/Model/BookFormat.cs: -------------------------------------------------------------------------------- 1 | namespace OneBeyondApi.Model 2 | { 3 | public enum BookFormat 4 | { 5 | Paperback, 6 | Magazine, 7 | Periodical, 8 | Hardback, 9 | CompactDisc 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /.NET/library/Model/BookStock.cs: -------------------------------------------------------------------------------- 1 | namespace OneBeyondApi.Model 2 | { 3 | public class BookStock 4 | { 5 | public Guid Id { get; set; } 6 | public Book Book { get; set; } 7 | public DateTime? LoanEndDate { get; set; } 8 | public Borrower? OnLoanTo { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /.NET/library/Model/Borrower.cs: -------------------------------------------------------------------------------- 1 | namespace OneBeyondApi.Model 2 | { 3 | public class Borrower 4 | { 5 | public Guid Id { get; set; } 6 | public string Name { get; set; } 7 | public string EmailAddress { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.NET/library/Model/CatalogueSearch.cs: -------------------------------------------------------------------------------- 1 | namespace OneBeyondApi.Model 2 | { 3 | public class CatalogueSearch 4 | { 5 | public string BookName { get; set; } 6 | public string Author { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /.NET/library/OneBeyondApi.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net8.0 4 | enable 5 | enable 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.NET/library/OneBeyondApi.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.5.33502.453 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OneBeyondApi", "OneBeyondApi.csproj", "{6A5CAF29-60BD-4F1F-AA0C-372A9877FF4C}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {6A5CAF29-60BD-4F1F-AA0C-372A9877FF4C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {6A5CAF29-60BD-4F1F-AA0C-372A9877FF4C}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {6A5CAF29-60BD-4F1F-AA0C-372A9877FF4C}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {6A5CAF29-60BD-4F1F-AA0C-372A9877FF4C}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {C0E84BF5-EF55-40C5-9985-C2E6512F93F6} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /.NET/library/Program.cs: -------------------------------------------------------------------------------- 1 | using OneBeyondApi; 2 | using OneBeyondApi.DataAccess; 3 | 4 | var builder = WebApplication.CreateBuilder(args); 5 | 6 | // Add services to the container. 7 | builder.Services.AddScoped(); 8 | builder.Services.AddScoped(); 9 | builder.Services.AddScoped(); 10 | builder.Services.AddScoped(); 11 | 12 | // Seed test data into memory DB 13 | SeedData.SetInitialData(); 14 | 15 | builder.Services.AddControllers(); 16 | // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle 17 | builder.Services.AddEndpointsApiExplorer(); 18 | builder.Services.AddSwaggerGen(); 19 | 20 | var app = builder.Build(); 21 | 22 | // Configure the HTTP request pipeline. 23 | //if (app.Environment.IsDevelopment()) 24 | //{ 25 | app.UseSwagger(); 26 | app.UseSwaggerUI(); 27 | //} 28 | 29 | app.UseHttpsRedirection(); 30 | 31 | app.UseAuthorization(); 32 | 33 | app.MapControllers(); 34 | 35 | app.Run(); 36 | -------------------------------------------------------------------------------- /.NET/library/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:10827", 8 | "sslPort": 44308 9 | } 10 | }, 11 | "profiles": { 12 | "http": { 13 | "commandName": "Project", 14 | "dotnetRunMessages": true, 15 | "launchBrowser": true, 16 | "launchUrl": "swagger", 17 | "applicationUrl": "http://localhost:5031", 18 | "environmentVariables": { 19 | "ASPNETCORE_ENVIRONMENT": "Development" 20 | } 21 | }, 22 | "https": { 23 | "commandName": "Project", 24 | "dotnetRunMessages": true, 25 | "launchBrowser": true, 26 | "launchUrl": "swagger", 27 | "applicationUrl": "https://localhost:7057;http://localhost:5031", 28 | "environmentVariables": { 29 | "ASPNETCORE_ENVIRONMENT": "Development" 30 | } 31 | }, 32 | "IIS Express": { 33 | "commandName": "IISExpress", 34 | "launchBrowser": true, 35 | "launchUrl": "swagger", 36 | "environmentVariables": { 37 | "ASPNETCORE_ENVIRONMENT": "Development" 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /.NET/library/README.md: -------------------------------------------------------------------------------- 1 | # Library Coding Challenges 2 | This project contains a basic API for a fictional library. The library has a catalogue which is made up of a stock of books. It is a .net 8 web api project, using an in memory database - if you want to add additional test data, look at SeedData.cs. 3 | 4 | Each book stock record in the catalogue has an associated Book record, and if currently "On Loan" has a loan end date and an associated "Borrower" 5 | It is possible via the API to retrieve all book stock records in the Catalogue, or to search by Author Name and/or Book Title. Both searches use a Contains search on the relevant Author/Book attributes. 6 | 7 | Books have a name, an associated Author record, a Book Format and an ISBN number. 8 | 9 | Authors have a name. 10 | 11 | Borrowers have a name and an email address. 12 | 13 | There are basic APIs for Books, Authors and Borrowers that will list all entities and allow addition of new records. It is not currently possible via the API to modify the Book Stock in the Catalogue. 14 | 15 | Full docs (and a running instance of the API) can be found at https://library-api.onebeyond.cloud/swagger/index.html 16 | 17 | # .NET Engineer Challenge 18 | 19 | Extend the existing API to add the following functionality: 20 | 1. Add an "On Loan" end point with functionality to get/query the details of all borrowers with active loans and the titles of books they have on loan. 21 | 2. Extend the "On Loan" end point to allow books on loan to be returned. 22 | 3. If books are returned after their loan end date then a fine should be raised against the borrower (data model for fines and relationships with borrowers are left to the candidate to define) 23 | 4. Add functionality to allow a borrower to reserve a particular title that is currently on loan (also consider the case of multiple borrowers all wanting to borrow the same book). The borrower should also be able to query via the API to find out when the book will be available for them. 24 | 25 | 26 | # Mobile Engineer Challenge 27 | Implement a mobile application using MAUI that provides the following functionality 28 | 1. Simple login matching on Borrower Name and Email Address (the library system provider has not heard of security!) 29 | 2. Provide a view of the catalogue, this should only show one entry for each unique book. This should show at least the author name, title of the book, format and ISBN, along with the total number of copies of the book in the libraries catalogue. 30 | 3. For any books allow the user to add to a wishlist. The wishlist should be maintained in app and users can add/remove books from it. 31 | 4. Add functionality in the app to display an app generated push notification when an item on the users wishlist's curent on loan date is reached (or passed). 32 | 33 | -------------------------------------------------------------------------------- /.NET/library/SeedData.cs: -------------------------------------------------------------------------------- 1 | using OneBeyondApi.DataAccess; 2 | using OneBeyondApi.Model; 3 | 4 | namespace OneBeyondApi 5 | { 6 | public class SeedData 7 | { 8 | public static void SetInitialData() 9 | { 10 | var ernestMonkjack = new Author 11 | { 12 | Name = "Ernest Monkjack" 13 | }; 14 | var sarahKennedy = new Author 15 | { 16 | Name = "Sarah Kennedy" 17 | }; 18 | var margaretJones = new Author 19 | { 20 | Name = "Margaret Jones" 21 | }; 22 | 23 | var clayBook = new Book 24 | { 25 | Name = "The Importance of Clay", 26 | Format = BookFormat.Paperback, 27 | Author = ernestMonkjack, 28 | ISBN = "1305718181" 29 | }; 30 | 31 | var agileBook = new Book 32 | { 33 | Name = "Agile Project Management - A Primer", 34 | Format = BookFormat.Hardback, 35 | Author = sarahKennedy, 36 | ISBN = "1293910102" 37 | }; 38 | 39 | var rustBook = new Book 40 | { 41 | Name = "Rust Development Cookbook", 42 | Format = BookFormat.Paperback, 43 | Author = margaretJones, 44 | ISBN = "3134324111" 45 | }; 46 | 47 | var daveSmith = new Borrower 48 | { 49 | Name = "Dave Smith", 50 | EmailAddress = "dave@smithy.com" 51 | }; 52 | 53 | var lianaJames = new Borrower 54 | { 55 | Name = "Liana James", 56 | EmailAddress = "liana@gmail.com" 57 | }; 58 | 59 | var bookOnLoanUntilToday = new BookStock { 60 | Book = clayBook, 61 | OnLoanTo = daveSmith, 62 | LoanEndDate = DateTime.Now.Date 63 | }; 64 | 65 | var bookNotOnLoan = new BookStock 66 | { 67 | Book = clayBook, 68 | OnLoanTo = null, 69 | LoanEndDate = null 70 | }; 71 | 72 | var bookOnLoanUntilNextWeek = new BookStock 73 | { 74 | Book = agileBook, 75 | OnLoanTo = lianaJames, 76 | LoanEndDate = DateTime.Now.Date.AddDays(7) 77 | }; 78 | 79 | var rustBookStock = new BookStock 80 | { 81 | Book = rustBook, 82 | OnLoanTo = null, 83 | LoanEndDate = null 84 | }; 85 | 86 | using (var context = new LibraryContext()) 87 | { 88 | context.Authors.Add(ernestMonkjack); 89 | context.Authors.Add(sarahKennedy); 90 | context.Authors.Add(margaretJones); 91 | 92 | 93 | context.Books.Add(clayBook); 94 | context.Books.Add(agileBook); 95 | context.Books.Add(rustBook); 96 | 97 | context.Borrowers.Add(daveSmith); 98 | context.Borrowers.Add(lianaJames); 99 | 100 | context.Catalogue.Add(bookOnLoanUntilToday); 101 | context.Catalogue.Add(bookNotOnLoan); 102 | context.Catalogue.Add(bookOnLoanUntilNextWeek); 103 | context.Catalogue.Add(rustBookStock); 104 | 105 | context.SaveChanges(); 106 | 107 | } 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /.NET/library/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /.NET/library/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*" 9 | } 10 | -------------------------------------------------------------------------------- /.NET/martian-robots/instructions.md: -------------------------------------------------------------------------------- 1 | # Martian robots 2 | Here we present a problem to solve. We will value the use of tests for the code challenge resolution. 3 | 4 | ## The Problem 5 | 6 | The surface of Mars can be modelled by a rectangular grid around which robots are able to move according to instructions provided from Earth. You are to write a program that determines each sequence of robot positions and reports the final position of the robot. 7 | 8 | A robot position consists of a grid coordinate (a pair of integers: x-coordinate followed by y-coordinate) and an orientation (N, S, E, W for north, south, east, and west). A robot instruction is a string of the letters "L", "R", and "F" which represent, respectively, the instructions: 9 | 10 | * Left: the robot turns left 90 degrees and remains on the current grid point. 11 | * Right: the robot turns right 90 degrees and remains on the current grid point. 12 | * Forward: the robot moves forward one grid point in the direction of the current orientation and maintains the same orientation. 13 | 14 | The direction North corresponds to the direction from grid point (x, y) to grid point (x, y+1). 15 | 16 | There is also a possibility that additional command types may be required in the future andprovision should be made for this. 17 | 18 | Since the grid is rectangular and bounded (...yes Mars is a strange planet), a robot that moves "off" an edge of the grid is lost forever. However, lost robots leave a robot "scent" that prohibits future robots from dropping off the world at the same grid point. The scent is left at the last grid position the robot occupied before disappearing over the edge. An instruction to move "off" the world from a grid point from which a robot has been previously lost is simply ignored by the current robot. 19 | 20 | ## The Input 21 | 22 | The first line of input is the upper-right coordinates of the rectangular world, the lower-left coordinates are assumed to be 0, 0. 23 | 24 | The remaining input consists of a sequence of robot positions and instructions (two lines per robot). A position consists of two integers specifying the initial coordinates of the robot and an orientation (N, S, E, W), all separated by whitespace on one line. A robot instruction is a string of the letters "L", "R", and "F" on one line. 25 | 26 | Each robot is processed sequentially, i.e., finishes executing the robot instructions before the next robot begins execution. 27 | 28 | The maximum value for any coordinate is 50. 29 | 30 | All instruction strings will be less than 100 characters in length. 31 | 32 | ## The Output 33 | 34 | For each robot position/instruction in the input, the output should indicate the final grid position and orientation of the robot. If a robot falls off the edge of the grid the word "LOST" should be printed after the position and orientation. 35 | 36 | ### Sample Input 37 | 38 | ``` 39 | 5 3 40 | 1 1 E 41 | RFRFRFRF 42 | 3 2 N 43 | FRRFLLFFRRFLL 44 | 0 3 W 45 | LLFFFLFLFL 46 | ``` 47 | 48 | ### Sample Output 49 | 50 | ``` 51 | 1 1 E 52 | 3 3 N LOST 53 | 2 3 S 54 | ``` 55 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /PHP/library-api-php/.vscode 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. -------------------------------------------------------------------------------- /PHP/library-api-php/README.md: -------------------------------------------------------------------------------- 1 | # Library Coding Challenges - PHP API 2 | 3 | This project contains a basic API for a fictional library. The library has a catalogue which is made up of a stock of books. This is a PHP API project using in-memory storage for simplicity. If you want to add additional test data, look at the file `data/data.php`. 4 | 5 | Each book stock record in the catalogue has an associated Book record, and if currently "On Loan" it has a loan end date and an associated "Borrower". It is possible via the API to retrieve all book stock records in the Catalogue, or to search by Author Name and/or Book Title. Both searches use a "contains" search on the relevant Author/Book attributes. 6 | 7 | - **Books** have a name, an associated Author record, a Book Format, and an ISBN number. 8 | - **Authors** have a name. 9 | - **Borrowers** have a name and an email address. 10 | 11 | There are basic APIs for Books, Authors, and Borrowers that list all entities and allow addition of new records. It is not currently possible via the API to modify the Book Stock in the Catalogue. 12 | 13 | --- 14 | 15 | ## PHP Engineer Challenge (to be implemented in PHP) 16 | 17 | Extend the existing API to add the following functionality: 18 | 19 | 1. **On Loan Endpoint Enhancements:** 20 | - **List Active Loans:** 21 | Add an "On Loan" endpoint that returns the details of all borrowers with active loans, including the titles of the books they have on loan. 22 | - **Return Books:** 23 | Extend the "On Loan" endpoint to allow books on loan to be returned. If a book is returned after its loan end date then a fine should be raised against the borrower. *Hint:* Define the data model for fines and the relationship with borrowers in `models/Fine.php`. 24 | 25 | 2. **Reservation System:** 26 | - **Reserve a Book:** 27 | Add functionality to allow a borrower to reserve a particular title that is currently on loan (consider multiple borrowers reserving the same book). 28 | - **Query Reservation Status:** 29 | Provide an API endpoint so that a borrower can query when a reserved book will be available. 30 | 31 | --- 32 | 33 | ## Project Structure 34 | 35 | -------------------------------------------------------------------------------- /PHP/library-api-php/controllers/BookController.php: -------------------------------------------------------------------------------- 1 | 'List active loans functionality to be implemented.']); 13 | } 14 | 15 | // POST /loans/return 16 | public function returnBook() { 17 | // TODO: Implement logic to process the return of a book and calculate fines if overdue. 18 | header('Content-Type: application/json'); 19 | echo json_encode(['message' => 'Return book functionality to be implemented.']); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /PHP/library-api-php/controllers/ReservationController.php: -------------------------------------------------------------------------------- 1 | 'Reserve book functionality to be implemented.']); 12 | } 13 | 14 | // GET /reservations 15 | public function status() { 16 | // TODO: Implement logic to return reservation status for a given borrower and book. 17 | header('Content-Type: application/json'); 18 | echo json_encode(['message' => 'Reservation status functionality to be implemented.']); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /PHP/library-api-php/data/data.php: -------------------------------------------------------------------------------- 1 | index(); 14 | } elseif ($uri === '/loans' && $method === 'GET') { 15 | $controller = new LoanController(); 16 | $controller->index(); 17 | } elseif ($uri === '/loans/return' && $method === 'POST') { 18 | $controller = new LoanController(); 19 | $controller->returnBook(); 20 | } elseif ($uri === '/reservations' && $method === 'POST') { 21 | $controller = new ReservationController(); 22 | $controller->reserve(); 23 | } elseif ($uri === '/reservations' && $method === 'GET') { 24 | $controller = new ReservationController(); 25 | $controller->status(); 26 | } else { 27 | http_response_code(404); 28 | echo json_encode(['error' => 'Endpoint not found']); 29 | } 30 | -------------------------------------------------------------------------------- /PHP/library-api-php/models/Author.php: -------------------------------------------------------------------------------- 1 | id = $id; 9 | $this->name = $name; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /PHP/library-api-php/models/Book.php: -------------------------------------------------------------------------------- 1 | id = $id; 12 | $this->title = $title; 13 | $this->authorId = $authorId; 14 | $this->format = $format; 15 | $this->isbn = $isbn; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /PHP/library-api-php/models/BookStock.php: -------------------------------------------------------------------------------- 1 | id = $id; 12 | $this->bookId = $bookId; 13 | $this->isOnLoan = $isOnLoan; 14 | $this->loanEndDate = $loanEndDate; 15 | $this->borrowerId = $borrowerId; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /PHP/library-api-php/models/Borrower.php: -------------------------------------------------------------------------------- 1 | id = $id; 10 | $this->name = $name; 11 | $this->email = $email; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /PHP/library-api-php/models/Fine.php: -------------------------------------------------------------------------------- 1 | id = $id; 11 | $this->borrowerId = $borrowerId; 12 | $this->amount = $amount; 13 | $this->details = $details; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /PHP/library-api-php/models/Reservation.php: -------------------------------------------------------------------------------- 1 | id = $id; 11 | $this->bookId = $bookId; 12 | $this->borrowerId = $borrowerId; 13 | $this->reservedAt = $reservedAt; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Interview Code Challenges 2 | Here you will find some different code challenges options for interviewing at One Beyond. 3 | 4 | ## .NET code tests 5 | 1. [.net Engineer - Library API functionality](/.NET/library/README.md#net-engineer-challenge) 6 | 2. [Mobile Engineer - Mobile Library Application](/.NET/library/README.md#mobile-engineer-challenge) 7 | 8 | ## PHP code tests 9 | 1. [PHP Engineer - Library API functionality](/PHP/library-api-php/README.md) 10 | 11 | 12 | ## Node tests 13 | 1. [Implement the martian robots game](/node/martian-robots/instructions.md) 14 | 2. [Implement the tennis score game](/node/tennis-score/instructions.md) 15 | 16 | ## React code tests 17 | 1. [Build a phone catalogue](/react/phone-catalogue/instructions.md) 18 | 2. [Build an app around a mysterious API](/react/mysterious-api/instructions.md) 19 | 20 | 21 | ## Java tests 22 | 1. [Implement the martian robots game](/java/martian-robots/instructions.md) 23 | 2. [Implement the tennis score game](/java/tennis-score/instructions.md) 24 | 25 | ## Data Visualization tests 26 | 1. [Implement a COVID-19 dashboard](/data/covid/instructions.md) 27 | -------------------------------------------------------------------------------- /data/covid/dataset.7z: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onebeyond/interview-code-challenges/e7bd4947d65010f60f8bd9cc41fc6b6ca1251dff/data/covid/dataset.7z -------------------------------------------------------------------------------- /data/covid/instructions.md: -------------------------------------------------------------------------------- 1 | # Covid-19 Dashboard 2 | This test is intented to evaluate your skills working with data and visualizing it. The source dataset will be provided and the visualization needs to be created using either Power BI or Google Data Studio. 3 | 4 | ## The problem 5 | We have a CSV file containing statistical information about the COVID-19 spread tracking total and new cases and deaths by country and date. We need to create a dashboard showing the totals and the trends so we can examine the state of the spread at any point in time but also the progression. 6 | 7 | ## The input 8 | The dataset is a CSV file located [here](./dataset.7z) 9 | 10 | ## The output 11 | You should provide a report with two pages: 12 | 13 | * A dashboard view with the following: 14 | 1. Total cases 15 | 2. Total deaths 16 | 3. Total % increase over last month 17 | 4. A graph showing the cases trend in months 18 | 5. A graph showing the deaths trend in months 19 | 6. Treemap of countries ordered by deaths 20 | * A report view showing the cases and deaths by month with filtering and drill-through capabilities (free design) 21 | 22 | ### Filters 23 | You should allow the following filters: 24 | 25 | * Continent 26 | * Date period 27 | * Data source 28 | * Country/Province/County (only for the second page) 29 | 30 | Extra bonus points (require external data) 31 | 1. Showing the cases and deaths normalized over the country' population 32 | 2. Source vaccine progress data and integrate it in the report 33 | -------------------------------------------------------------------------------- /java/fish-tank/instructions.md: -------------------------------------------------------------------------------- 1 | # fish-tank 2 | 3 | ## Simulation of a fish tank 4 | 5 | Fish Tank Simulator Introduction 6 | The purpose of this exercise is to design a simulator for a fish tank. 7 | The simulator can be run by a human operator who can populate the fish tank with 8 | various kinds of creatures, add food, and change aspects of the environment 9 | such as temperature. The main focus of this exercise is to model the functions and 10 | objects that are involved, expressing their properties and relationships. 11 | 12 | ## Description 13 | 14 | The simulator has the following properties: 15 | 16 | - there is only one fish tank 17 | - the user can add fish, snails and fish food 18 | - living fish and snails both eat fish foodp 19 | - piranha fish may also eat other fish 20 | 21 | - clockwork fish do not eat anything 22 | - clockwork fish do not breathe; other fish and snails do 23 | 24 | - fish swim at different depths: 25 | - piranha fish and clockwork fish swim at all depths 26 | - sun fish swim at the top 27 | - diver fish swim at the bottom 28 | - the user can vary the temperature of the fish tank 29 | - when the temperature falls below 15 degrees centigrade, piranha fish die and float to the surface 30 | - Events in the fish tank are time based; 31 | - every interval: the user may change the state of the fish tank (adding items, changing the temperature etc.) 32 | - inhabitants that eat do 33 | - inhabitants may be eaten or otherwise die 34 | 35 | ### Extra points 36 | - REST API to allow external clients to interact with the fish tank 37 | - Dockerising the application 38 | -------------------------------------------------------------------------------- /java/martian-robots/instructions.md: -------------------------------------------------------------------------------- 1 | # Martian robots 2 | Here we present a problem to solve. We will value the use of tests for the code challenge resolution. 3 | 4 | ## The Problem 5 | 6 | The surface of Mars can be modelled by a rectangular grid around which robots are able to move according to instructions provided from Earth. You are to write a program that determines each sequence of robot positions and reports the final position of the robot. 7 | 8 | A robot position consists of a grid coordinate (a pair of integers: x-coordinate followed by y-coordinate) and an orientation (N, S, E, W for north, south, east, and west). A robot instruction is a string of the letters "L", "R", and "F" which represent, respectively, the instructions: 9 | 10 | * Left: the robot turns left 90 degrees and remains on the current grid point. 11 | * Right: the robot turns right 90 degrees and remains on the current grid point. 12 | * Forward: the robot moves forward one grid point in the direction of the current orientation and maintains the same orientation. 13 | 14 | The direction North corresponds to the direction from grid point (x, y) to grid point (x, y+1). 15 | 16 | There is also a possibility that additional command types may be required in the future andprovision should be made for this. 17 | 18 | Since the grid is rectangular and bounded (...yes Mars is a strange planet), a robot that moves "off" an edge of the grid is lost forever. However, lost robots leave a robot "scent" that prohibits future robots from dropping off the world at the same grid point. The scent is left at the last grid position the robot occupied before disappearing over the edge. An instruction to move "off" the world from a grid point from which a robot has been previously lost is simply ignored by the current robot. 19 | 20 | ## The Input 21 | 22 | The first line of input is the upper-right coordinates of the rectangular world, the lower-left coordinates are assumed to be 0, 0. 23 | 24 | The remaining input consists of a sequence of robot positions and instructions (two lines per robot). A position consists of two integers specifying the initial coordinates of the robot and an orientation (N, S, E, W), all separated by whitespace on one line. A robot instruction is a string of the letters "L", "R", and "F" on one line. 25 | 26 | Each robot is processed sequentially, i.e., finishes executing the robot instructions before the next robot begins execution. 27 | 28 | The maximum value for any coordinate is 50. 29 | 30 | All instruction strings will be less than 100 characters in length. 31 | 32 | ## The Output 33 | 34 | For each robot position/instruction in the input, the output should indicate the final grid position and orientation of the robot. If a robot falls off the edge of the grid the word "LOST" should be printed after the position and orientation. 35 | 36 | ### Sample Input 37 | 38 | ``` 39 | 5 3 40 | 1 1 E 41 | RFRFRFRF 42 | 3 2 N 43 | FRRFLLFFRRFLL 44 | 0 3 W 45 | LLFFFLFLFL 46 | ``` 47 | 48 | ### Sample Output 49 | 50 | ``` 51 | 1 1 E 52 | 3 3 N LOST 53 | 2 3 S 54 | ``` 55 | -------------------------------------------------------------------------------- /java/tennis-score/instructions.md: -------------------------------------------------------------------------------- 1 | # Tennis score 2 | 3 | This code challenge is about implementing a simple tennis score. Each set is one game. 4 | We highly encourage you to write tests to implement this solution. 5 | 6 | ## Mechanism 7 | The scoring system is rather simple: 8 | 9 | - Each player can have either of these points in one game: 0 15 30 40 10 | - If you have 40 and you win the ball you win the game, however there are special rules: 11 | - If both have 40 the players are deuce. 12 | - If the game is in deuce, the winner of a ball will have advantage and game ball. 13 | - If the player with advantage wins the ball he wins the game 14 | - If the player without advantage wins they are back at deuce. 15 | -------------------------------------------------------------------------------- /node/fish-tank/instructions.md: -------------------------------------------------------------------------------- 1 | # fish-tank 2 | 3 | ## Simulation of a fish tank 4 | 5 | Fish Tank Simulator Introduction 6 | The purpose of this exercise is to design a simulator for a fish tank. 7 | The simulator can be run by a human operator who can populate the fish tank with 8 | various kinds of creatures, add food, and change aspects of the environment 9 | such as temperature. The main focus of this exercise is to model the functions and 10 | objects that are involved, expressing their properties and relationships. 11 | 12 | ## Description 13 | 14 | The simulator has the following properties: 15 | 16 | - there is only one fish tank 17 | - the user can add fish, snails and fish food 18 | - living fish and snails both eat fish foodp 19 | - piranha fish may also eat other fish 20 | 21 | - clockwork fish do not eat anything 22 | - clockwork fish do not breathe; other fish and snails do 23 | 24 | - fish swim at different depths: 25 | - piranha fish and clockwork fish swim at all depths 26 | - sun fish swim at the top 27 | - diver fish swim at the bottom 28 | - the user can vary the temperature of the fish tank 29 | - when the temperature falls below 15 degrees centigrade, piranha fish die and float to the surface 30 | - Events in the fish tank are time based; 31 | - every interval: the user may change the state of the fish tank (adding items, changing the temperature etc.) 32 | - inhabitants that eat do 33 | - inhabitants may be eaten or otherwise die 34 | 35 | ### Extra points 36 | - REST API to allow external clients to interact with the fish tank 37 | - Dockerising the application 38 | -------------------------------------------------------------------------------- /node/martian-robots/instructions.md: -------------------------------------------------------------------------------- 1 | # Martian robots 2 | Here we present a problem to solve. We will value the use of tests for the code challenge resolution. 3 | 4 | ## The Problem 5 | 6 | The surface of Mars can be modelled by a rectangular grid around which robots are able to move according to instructions provided from Earth. You are to write a program that determines each sequence of robot positions and reports the final position of the robot. 7 | 8 | A robot position consists of a grid coordinate (a pair of integers: x-coordinate followed by y-coordinate) and an orientation (N, S, E, W for north, south, east, and west). A robot instruction is a string of the letters "L", "R", and "F" which represent, respectively, the instructions: 9 | 10 | * Left: the robot turns left 90 degrees and remains on the current grid point. 11 | * Right: the robot turns right 90 degrees and remains on the current grid point. 12 | * Forward: the robot moves forward one grid point in the direction of the current orientation and maintains the same orientation. 13 | 14 | The direction North corresponds to the direction from grid point (x, y) to grid point (x, y+1). 15 | 16 | There is also a possibility that additional command types may be required in the future andprovision should be made for this. 17 | 18 | Since the grid is rectangular and bounded (...yes Mars is a strange planet), a robot that moves "off" an edge of the grid is lost forever. However, lost robots leave a robot "scent" that prohibits future robots from dropping off the world at the same grid point. The scent is left at the last grid position the robot occupied before disappearing over the edge. An instruction to move "off" the world from a grid point from which a robot has been previously lost is simply ignored by the current robot. 19 | 20 | ## The Input 21 | 22 | The first line of input is the upper-right coordinates of the rectangular world, the lower-left coordinates are assumed to be 0, 0. 23 | 24 | The remaining input consists of a sequence of robot positions and instructions (two lines per robot). A position consists of two integers specifying the initial coordinates of the robot and an orientation (N, S, E, W), all separated by whitespace on one line. A robot instruction is a string of the letters "L", "R", and "F" on one line. 25 | 26 | Each robot is processed sequentially, i.e., finishes executing the robot instructions before the next robot begins execution. 27 | 28 | The maximum value for any coordinate is 50. 29 | 30 | All instruction strings will be less than 100 characters in length. 31 | 32 | ## The Output 33 | 34 | For each robot position/instruction in the input, the output should indicate the final grid position and orientation of the robot. If a robot falls off the edge of the grid the word "LOST" should be printed after the position and orientation. 35 | 36 | ### Sample Input 37 | 38 | ``` 39 | 5 3 40 | 1 1 E 41 | RFRFRFRF 42 | 3 2 N 43 | FRRFLLFFRRFLL 44 | 0 3 W 45 | LLFFFLFLFL 46 | ``` 47 | 48 | ### Sample Output 49 | 50 | ``` 51 | 1 1 E 52 | 3 3 N LOST 53 | 2 3 S 54 | ``` -------------------------------------------------------------------------------- /node/tennis-score/instructions.md: -------------------------------------------------------------------------------- 1 | # Tennis score 2 | 3 | This code challenge is about implementing a simple tennis score. Each set is one game. 4 | We highly encourage you to write tests to implement this solution. 5 | 6 | ## Mechanism 7 | The scoring system is rather simple: 8 | 9 | - Each player can have either of these points in one game: 0 15 30 40 10 | - If you have 40 and you win the ball you win the game, however there are special rules: 11 | - If both have 40 the players are deuce. 12 | - If the game is in deuce, the winner of a ball will have advantage and game ball. 13 | - If the player with advantage wins the ball he wins the game 14 | - If the player without advantage wins they are back at deuce. -------------------------------------------------------------------------------- /react/mysterious-api/instructions.md: -------------------------------------------------------------------------------- 1 | # Mysterious API 2 | To complete this code challenge, you need to be able to run Docker in your local machine. Everything should be clear from this file, however if you have any questions, please refer them to your Hiring Manager. 3 | 4 | ## Description 5 | You will be given an API, however we won't tell you anything about what problems it solves, how it works or how it behaves. You will need to figure it out and build something cool and original in React around this API. 6 | 7 | ## Usage 8 | Execute the command `docker run -d --name interview-api -p 3000:3000 chaseadams/interview-api` to run your API locally. 9 | 10 | ## Bonus points 11 | 12 | 1. Build a proxy API that consumes this original API Docker container and gracefully handles any upstream intermittent failures. 13 | 2. Provide application-level caching for your proxy. 14 | 3. Dockerise your proxy. 15 | -------------------------------------------------------------------------------- /react/phone-catalogue/images/Galaxy_S7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onebeyond/interview-code-challenges/e7bd4947d65010f60f8bd9cc41fc6b6ca1251dff/react/phone-catalogue/images/Galaxy_S7.png -------------------------------------------------------------------------------- /react/phone-catalogue/images/Honor_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onebeyond/interview-code-challenges/e7bd4947d65010f60f8bd9cc41fc6b6ca1251dff/react/phone-catalogue/images/Honor_10.png -------------------------------------------------------------------------------- /react/phone-catalogue/images/IPhone_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onebeyond/interview-code-challenges/e7bd4947d65010f60f8bd9cc41fc6b6ca1251dff/react/phone-catalogue/images/IPhone_7.png -------------------------------------------------------------------------------- /react/phone-catalogue/images/Moto_G6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onebeyond/interview-code-challenges/e7bd4947d65010f60f8bd9cc41fc6b6ca1251dff/react/phone-catalogue/images/Moto_G6.png -------------------------------------------------------------------------------- /react/phone-catalogue/images/Nokia_7.1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onebeyond/interview-code-challenges/e7bd4947d65010f60f8bd9cc41fc6b6ca1251dff/react/phone-catalogue/images/Nokia_7.1.jpg -------------------------------------------------------------------------------- /react/phone-catalogue/images/P10_Lite.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onebeyond/interview-code-challenges/e7bd4947d65010f60f8bd9cc41fc6b6ca1251dff/react/phone-catalogue/images/P10_Lite.jpg -------------------------------------------------------------------------------- /react/phone-catalogue/images/Xiaomi_MI_A2.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onebeyond/interview-code-challenges/e7bd4947d65010f60f8bd9cc41fc6b6ca1251dff/react/phone-catalogue/images/Xiaomi_MI_A2.jpeg -------------------------------------------------------------------------------- /react/phone-catalogue/images/ZenPhone_5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onebeyond/interview-code-challenges/e7bd4947d65010f60f8bd9cc41fc6b6ca1251dff/react/phone-catalogue/images/ZenPhone_5.jpg -------------------------------------------------------------------------------- /react/phone-catalogue/instructions.md: -------------------------------------------------------------------------------- 1 | # Phone Catalogue 2 | Your task is to write a very simple product catalogue app. 3 | 4 | 1. Write a simple REST API in whatever language you're most comfortable with that... 5 | - Has 1 endpoint `/phones` 6 | - Returns the attached "phones.json" payload (or a free version of it) 7 | - The data can all be mocked, no need for a persistence layer 8 | 2. Write a React app that displays the phones from the API 9 | - Display an initial list with all phones 10 | - When a phone model is selected from the list, it will render a phone detail view displaying a few more details about that phone 11 | - Display a spinner or placeholder component while the API request is ongoing 12 | - Make it look decent. No need for super sophisticated design, but at a minimum, make it somewhat responsive so that it doesn’t look terrible on a mobile phone. Add images for each device. 13 | 3. Push the code to a private github repo with a README.md that explains how to run API & Frontend app 14 | 15 | ## Bonus points 16 | 1. Dockerize the app. 17 | 2. Write realistic unit/end-to-end tests. 18 | -------------------------------------------------------------------------------- /react/phone-catalogue/phones.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 0, 4 | "name": "iPhone 7", 5 | "manufacturer": "Apple", 6 | "description": "iPhone 7 dramatically improves the most important aspects of the iPhone experience. It introduces advanced new camera systems. The best performance and battery life ever in an iPhone. Immersive stereo speakers. The brightest, most colorful iPhone display. Splash and water resistance*. And it looks every bit as powerful as it is. This is iPhone 7.", 7 | "color": "black", 8 | "price": 769, 9 | "imageFileName": "IPhone_7.png", 10 | "screen": "4,7 inch IPS", 11 | "processor": "A10 Fusion", 12 | "ram": 2 13 | }, 14 | { 15 | "id": 1, 16 | "name": "Galaxy S7", 17 | "manufacturer": "Samsung", 18 | "description": "Introducing the smartphone your life can not do without, The Samsung Galaxy S7. Packed with features to keep you both productive and entertained, all in a sleek, slim design that fits comfortably in your hand or pocket.", 19 | "color": "grey", 20 | "price": 209, 21 | "imageFileName": "Galaxy_S7.png", 22 | "screen": "5,1 inch Quad-HD", 23 | "processor": "Snapdragon 820", 24 | "ram": 4 25 | }, 26 | { 27 | "id": 2, 28 | "name": "Honor 10", 29 | "manufacturer": "Huawei", 30 | "description": "Great phone with an excellent interface. One of the best mid price range phones in the market.", 31 | "color": "blue", 32 | "price": 399, 33 | "imageFileName": "Honor_10.png", 34 | "screen": "5,84 inch Full-HD", 35 | "processor": "Kirin 970", 36 | "ram": 6 37 | }, 38 | { 39 | "id": 3, 40 | "name": "P10 Lite", 41 | "manufacturer": "Huawei", 42 | "description": "Great phone with an excellent interface. One of the best mid price range phones in the market.", 43 | "color": "white", 44 | "price": 249, 45 | "imageFileName": "P10_Lite.jpg", 46 | "screen": "5,2 inch Full-HD", 47 | "processor": "Kirin 658", 48 | "ram": 4 49 | }, 50 | { 51 | "id": 4, 52 | "name": "Nokia 7.1", 53 | "manufacturer": "Nokia", 54 | "description": "Great phone with an excellent interface. One of the best mid price range phones in the market.", 55 | "color": "black", 56 | "price": 275, 57 | "imageFileName": "Nokia_7.1.jpg", 58 | "screen": "5,84 inch Full-HD", 59 | "processor": "Octa-core", 60 | "ram": 4 61 | }, 62 | { 63 | "id": 5, 64 | "name": "Zen Phone 5", 65 | "manufacturer": "Asus", 66 | "description": "Great phone with an excellent interface. One of the best mid price range phones in the market.", 67 | "color": "black", 68 | "price": 359, 69 | "imageFileName": "ZenPhone_5.jpg", 70 | "screen": "6,2 inch Full-HD", 71 | "processor": "Snapdragon 636", 72 | "ram": 6 73 | }, 74 | { 75 | "id": 6, 76 | "name": "MI A2", 77 | "manufacturer": "Xiaomi", 78 | "description": "Great phone with an excellent interface. One of the best mid price range phones in the market.", 79 | "color": "black", 80 | "price": 179, 81 | "imageFileName": "Xiaomi_MI_A2.jpeg", 82 | "screen": "5,99 inch Full-HD", 83 | "processor": "Snapdragon 660", 84 | "ram": 6 85 | }, 86 | { 87 | "id": 7, 88 | "name": "Moto G6", 89 | "manufacturer": "Motorola", 90 | "description": "Great phone with an excellent interface. One of the best mid price range phones in the market.", 91 | "color": "black", 92 | "price": 199, 93 | "imageFileName": "Moto_G6.png", 94 | "screen": "5,7 inch Full-HD", 95 | "processor": "Snapdragon 450", 96 | "ram": 3 97 | } 98 | ] --------------------------------------------------------------------------------