├── .gitignore ├── LICENSE ├── README.md ├── analysis_options.yaml ├── darrrt ├── 1-blankbadge │ ├── pubspec.yaml │ └── web │ │ ├── index.html │ │ ├── main.dart │ │ └── styles.css ├── 2-inputnamebadge │ ├── pubspec.yaml │ └── web │ │ ├── index.html │ │ ├── main.dart │ │ └── styles.css ├── 3-buttonbadge │ ├── pubspec.yaml │ └── web │ │ ├── index.html │ │ ├── main.dart │ │ └── styles.css ├── 4-classbadge │ ├── pubspec.yaml │ └── web │ │ ├── index.html │ │ ├── main.dart │ │ └── styles.css └── 5-final │ ├── .idea │ ├── .name │ ├── final.iml │ ├── misc.xml │ ├── modules.xml │ ├── vcs.xml │ └── workspace.xml │ ├── pubspec.yaml │ └── web │ ├── index.html │ ├── main.dart │ └── styles.css ├── live-demo ├── Dockerfile ├── app.yaml ├── bin │ └── server.dart ├── lib │ ├── client │ │ └── piratesapi.dart │ ├── common │ │ ├── messages.dart │ │ └── utils.dart │ └── server │ │ └── piratesapi.dart ├── pubspec.yaml └── web │ ├── piratebadge.css │ ├── piratebadge.dart │ └── piratebadge.html ├── ng2 ├── 1-skeleton │ ├── .gitignore │ ├── LICENSE │ ├── analysis_options.yaml │ ├── lib │ │ └── app_component.dart │ ├── pubspec.yaml │ └── web │ │ ├── index.html │ │ ├── main.dart │ │ └── styles.css ├── 2-blankbadge │ ├── .gitignore │ ├── LICENSE │ ├── analysis_options.yaml │ ├── lib │ │ ├── app_component.dart │ │ ├── app_component.html │ │ └── src │ │ │ ├── badge_component.css │ │ │ ├── badge_component.dart │ │ │ └── badge_component.html │ ├── pubspec.yaml │ └── web │ │ ├── index.html │ │ ├── main.dart │ │ └── styles.css ├── 3-inputnamebadge │ ├── .gitignore │ ├── LICENSE │ ├── analysis_options.yaml │ ├── lib │ │ ├── app_component.dart │ │ ├── app_component.html │ │ └── src │ │ │ ├── badge_component.css │ │ │ ├── badge_component.dart │ │ │ └── badge_component.html │ ├── pubspec.yaml │ └── web │ │ ├── index.html │ │ ├── main.dart │ │ └── styles.css ├── 4-buttonbadge │ ├── .gitignore │ ├── LICENSE │ ├── analysis_options.yaml │ ├── lib │ │ ├── app_component.dart │ │ ├── app_component.html │ │ └── src │ │ │ ├── badge_component.css │ │ │ ├── badge_component.dart │ │ │ └── badge_component.html │ ├── pubspec.yaml │ └── web │ │ ├── index.html │ │ ├── main.dart │ │ └── styles.css ├── 5-piratenameservice │ ├── .gitignore │ ├── LICENSE │ ├── analysis_options.yaml │ ├── lib │ │ ├── app_component.dart │ │ ├── app_component.html │ │ └── src │ │ │ ├── badge_component.css │ │ │ ├── badge_component.dart │ │ │ ├── badge_component.html │ │ │ └── name_service.dart │ ├── pubspec.yaml │ └── web │ │ ├── index.html │ │ ├── main.dart │ │ └── styles.css └── 6-readjsonfile │ ├── .gitignore │ ├── LICENSE │ ├── analysis_options.yaml │ ├── lib │ ├── app_component.dart │ ├── app_component.html │ └── src │ │ ├── badge_component.css │ │ ├── badge_component.dart │ │ ├── badge_component.html │ │ └── name_service.dart │ ├── pubspec.yaml │ └── web │ ├── index.html │ ├── main.dart │ └── styles.css ├── runtests.sh └── server ├── 1-starter ├── bin │ └── piratesnest.dart ├── lib │ ├── common │ │ ├── messages.dart │ │ └── utils.dart │ └── server │ │ └── piratesapi.dart └── pubspec.yaml ├── 2-simple ├── bin │ └── piratesnest.dart ├── lib │ ├── common │ │ ├── messages.dart │ │ └── utils.dart │ └── server │ │ └── piratesapi.dart └── pubspec.yaml ├── 4-extended ├── bin │ └── piratesnest.dart ├── lib │ ├── common │ │ ├── messages.dart │ │ └── utils.dart │ └── server │ │ └── piratesapi.dart └── pubspec.yaml ├── 5-generated ├── bin │ └── piratesnest.dart ├── lib │ ├── client │ │ └── piratesapi.dart │ ├── common │ │ ├── messages.dart │ │ └── utils.dart │ └── server │ │ └── piratesapi.dart └── pubspec.yaml ├── 6-client ├── bin │ └── piratesnest.dart ├── lib │ ├── client │ │ └── piratesapi.dart │ ├── common │ │ ├── messages.dart │ │ └── utils.dart │ └── server │ │ └── piratesapi.dart ├── pubspec.yaml └── web │ ├── piratebadge.css │ ├── piratebadge.dart │ └── piratebadge.html ├── 7-serve ├── bin │ └── piratesnest.dart ├── lib │ ├── client │ │ └── piratesapi.dart │ ├── common │ │ ├── messages.dart │ │ └── utils.dart │ └── server │ │ └── piratesapi.dart ├── pubspec.yaml └── web │ ├── piratebadge.css │ ├── piratebadge.dart │ └── piratebadge.html └── working-dir ├── bin └── piratesnest.dart ├── lib ├── common │ ├── messages.dart │ └── utils.dart └── server │ └── piratesapi.dart └── pubspec.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | packages 3 | out 4 | build 5 | .buildlog 6 | .pub 7 | .idea 8 | .packages 9 | .swp 10 | pubspec.lock 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2016, the Dart project authors. All rights reserved. 2 | Redistribution and use in source and binary forms, with or without 3 | modification, are permitted provided that the following conditions are 4 | met: 5 | 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above 9 | copyright notice, this list of conditions and the following 10 | disclaimer in the documentation and/or other materials provided 11 | with the distribution. 12 | * Neither the name of Google Inc. nor the names of its 13 | contributors may be used to endorse or promote products derived 14 | from this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Dart Code Lab Samples 2 | ============================ 3 | [![first-timers-only](http://img.shields.io/badge/first--timers--only-friendly-blue.svg?style=flat-square)](http://www.firsttimersonly.com/) 4 | 5 | These are small Dart samples used by the following codelabs: 6 | 7 | * (**Needs updates**) [Beware the Nest o' Pirates][server-codelab], which shows you how to write a RESTful Dart server. 8 | * (**Deprecated**) [Avast Ye Pirates][ng2-codelab], where you learn to build an Angular 2 web app. 9 | * (**Deprecated**) [Original pirate codelab written using dart:html][client-codelab], where you learn to build a web app. 10 | * (**Moved**) [AngularDart Components Lottery Simulator][] has moved to [site-webdev][] under [examples/acx/lottery](https://github.com/dart-lang/site-webdev/tree/master/examples/acx/lottery). 11 | 12 | For links to the latest Dart codelabs, see [dartlang.org/codelabs](https://www.dartlang.org/codelabs). 13 | 14 | Repository structure 15 | ----------------- 16 | 17 | - Each top-level folder holds the sources to an individual codelab. 18 | - `runtests.sh`: bash script that runs dartanalyzer on all Dart source files in the web directory. 19 | 20 | Testing 21 | ---------------- 22 | 23 | Currently, drone.io tests only whether the .dart files under web/ pass static analysis (dartanalyzer). We could do real unit testing, and we could do better with HTML samples. 24 | 25 | [AngularDart Components Lottery Simulator]: https://webdev.dartlang.org/codelabs/angular_components 26 | [client-codelab]: https://webdev.dartlang.org/codelabs/darrrt 27 | [ng2-codelab]: https://webdev.dartlang.org/codelabs/ng2 28 | [server-codelab]: https://dart-lang.github.io/server/codelab/ 29 | [site-webdev]: https://github.com/dart-lang/site-webdev -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # Supported lint rules and documentation: 2 | # http://dart-lang.github.io/linter/lints/ 3 | 4 | analyzer: 5 | strong-mode: true 6 | exclude: 7 | - lib/client/piratesapi.dart 8 | 9 | linter: 10 | rules: 11 | - avoid_empty_else 12 | - cancel_subscriptions 13 | - close_sinks 14 | - comment_references 15 | - control_flow_in_finally 16 | - empty_statements 17 | - hash_and_equals 18 | - iterable_contains_unrelated_type 19 | - list_remove_unrelated_type 20 | - test_types_in_equals 21 | - throw_in_finally 22 | - unrelated_type_equality_checks 23 | - valid_regexps 24 | 25 | # - always_declare_return_types -- doesn't interact well with strong mode 26 | # - always_specify_types -- doesn't interact well with strong mode 27 | - annotate_overrides 28 | # - avoid_as -- jmesserly recommends avoiding 29 | - avoid_init_to_null 30 | - avoid_return_types_on_setters 31 | - await_only_futures 32 | - camel_case_types 33 | - constant_identifier_names 34 | - empty_catches 35 | - empty_constructor_bodies 36 | - implementation_imports 37 | - library_names 38 | - library_prefixes 39 | - non_constant_identifier_names 40 | - one_member_abstracts 41 | - only_throw_errors 42 | - overridden_fields 43 | # - package_api_docs # This is example code, not public APIs 44 | - package_prefixed_library_names 45 | - prefer_is_not_empty 46 | # - public_member_api_docs # This is example code, not public APIs 47 | - slash_for_doc_comments 48 | - sort_constructors_first 49 | - sort_unnamed_constructors_first 50 | - super_goes_last 51 | - type_annotate_public_apis 52 | - type_init_formals 53 | - unnecessary_brace_in_string_interps 54 | - unnecessary_getters_setters 55 | 56 | - package_names 57 | -------------------------------------------------------------------------------- /darrrt/1-blankbadge/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: avast_ye_pirates 2 | description: Write a Dart web app code lab 3 | dependencies: 4 | browser: ^0.10.0+2 5 | 6 | homepage: https://webdev.dartlang.org/codelabs/darrrt 7 | gist: https://gist.github.com/Sfshaza/9642dce02da158457f12 8 | dartpad: https://dartpad.dartlang.org/9642dce02da158457f12 9 | -------------------------------------------------------------------------------- /darrrt/1-blankbadge/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 15 | Pirate badge 16 | 17 | 18 | 19 | 20 | 21 | 22 |

Pirate badge

23 | 24 |
25 | TO DO: Put the UI widgets here. 26 |
27 |
28 |
29 | Arrr! Me name is 30 |
31 |
32 | 33 |
34 |
35 | 36 | 37 | -------------------------------------------------------------------------------- /darrrt/1-blankbadge/web/main.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | // This app starts out with almost no Dart code, as described 6 | // in Step 1 of the code lab (dartlang.org/codelabs/darrrt/). 7 | 8 | void main() { 9 | // Your app starts here. 10 | // In Step 2, you'll add code to listen for updates for the pirate badge. 11 | } 12 | -------------------------------------------------------------------------------- /darrrt/1-blankbadge/web/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #F8F8F8; 3 | font-family: 'Open Sans', sans-serif; 4 | font-size: 14px; 5 | font-weight: normal; 6 | line-height: 1.2em; 7 | margin: 15px; 8 | } 9 | 10 | h1, p { 11 | color: #333; 12 | } 13 | .widgets { 14 | padding-bottom: 20pt; 15 | float: left; 16 | } 17 | .badge { 18 | border: 2px solid brown; 19 | border-radius: 1em; 20 | background: red; 21 | font-size: 14pt; 22 | width: 14em; 23 | height: 7em; 24 | text-align: center; 25 | float: left; 26 | margin-left: 20px; 27 | white-space: nowrap; 28 | overflow: hidden; 29 | } 30 | .greeting { 31 | color: white; 32 | font-family: sans-serif; 33 | padding: 0.5em; 34 | } 35 | .name { 36 | color: black; 37 | background: white; 38 | font-family: "Marker Felt", cursive; 39 | font-size: 25pt; 40 | padding-top: 1.0em; 41 | padding-bottom: 0.7em; 42 | height: 16px; 43 | } 44 | #generateButton { 45 | font-size: 12pt; 46 | margin-top: 20px; 47 | } 48 | input[type="text"] { 49 | font-size: 12pt; 50 | margin-top: 10pt; 51 | margin-bottom: 10pt; 52 | width: 12em; 53 | } 54 | @media all and (max-width: 500px) { 55 | .badge { 56 | margin-left: 0px; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /darrrt/2-inputnamebadge/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: avast_ye_pirates 2 | description: Write a Dart web app code lab 3 | dependencies: 4 | browser: ^0.10.0+2 5 | 6 | homepage: https://webdev.dartlang.org/codelabs/darrrt 7 | gist: https://gist.github.com/Sfshaza/e78a858a1b8cfce15bbf 8 | dartpad: https://dartpad.dartlang.org/e78a858a1b8cfce15bbf 9 | -------------------------------------------------------------------------------- /darrrt/2-inputnamebadge/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 15 | Pirate badge 16 | 17 | 18 | 19 | 20 | 21 | 22 |

Pirate badge

23 | 24 |
25 |
26 | 27 |
28 |
29 |
30 |
31 | Arrr! Me name is 32 |
33 |
34 | 35 |
36 |
37 | 38 | 39 | -------------------------------------------------------------------------------- /darrrt/2-inputnamebadge/web/main.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | // In Step 2 of the code lab (dartlang.org/codelabs/darrrt/), 6 | // you added an input field to the app. 7 | 8 | import 'dart:html'; 9 | 10 | void main() { 11 | querySelector('#inputName').onInput.listen(updateBadge); 12 | } 13 | 14 | void updateBadge(Event e) { 15 | querySelector('#badgeName').text = (e.target as InputElement).value; 16 | } 17 | -------------------------------------------------------------------------------- /darrrt/2-inputnamebadge/web/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #F8F8F8; 3 | font-family: 'Open Sans', sans-serif; 4 | font-size: 14px; 5 | font-weight: normal; 6 | line-height: 1.2em; 7 | margin: 15px; 8 | } 9 | 10 | h1, p { 11 | color: #333; 12 | } 13 | .widgets { 14 | padding-bottom: 20pt; 15 | float: left; 16 | } 17 | .badge { 18 | border: 2px solid brown; 19 | border-radius: 1em; 20 | background: red; 21 | font-size: 14pt; 22 | width: 14em; 23 | height: 7em; 24 | text-align: center; 25 | float: left; 26 | margin-left: 20px; 27 | white-space: nowrap; 28 | overflow: hidden; 29 | } 30 | .greeting { 31 | color: white; 32 | font-family: sans-serif; 33 | padding: 0.5em; 34 | } 35 | .name { 36 | color: black; 37 | background: white; 38 | font-family: "Marker Felt", cursive; 39 | font-size: 25pt; 40 | padding-top: 1.0em; 41 | padding-bottom: 0.7em; 42 | height: 16px; 43 | } 44 | #generateButton { 45 | font-size: 12pt; 46 | margin-top: 20px; 47 | } 48 | input[type="text"] { 49 | font-size: 12pt; 50 | margin-top: 10pt; 51 | margin-bottom: 10pt; 52 | width: 12em; 53 | } 54 | @media all and (max-width: 500px) { 55 | .badge { 56 | margin-left: 0px; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /darrrt/3-buttonbadge/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: avast_ye_pirates 2 | description: Write a Dart web app code lab 3 | dependencies: 4 | browser: ^0.10.0+2 5 | 6 | homepage: https://webdev.dartlang.org/codelabs/darrrt 7 | gist: https://gist.github.com/Sfshaza/feac8311871e29bc50a7 8 | dartpad: https://dartpad.dartlang.org/feac8311871e29bc50a7 9 | -------------------------------------------------------------------------------- /darrrt/3-buttonbadge/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 15 | Pirate badge 16 | 17 | 18 | 19 | 20 | 21 | 22 |

Pirate badge

23 | 24 |
25 |
26 | 27 |
28 |
29 | 30 |
31 |
32 |
33 |
34 | Arrr! Me name is 35 |
36 |
37 | 38 |
39 |
40 | 41 | 42 | -------------------------------------------------------------------------------- /darrrt/3-buttonbadge/web/main.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | // In Step 3 of the code lab (dartlang.org/codelabs/darrrt/), 6 | // you added a button to the app. 7 | 8 | import 'dart:html'; 9 | 10 | ButtonElement genButton; 11 | 12 | void main() { 13 | querySelector('#inputName').onInput.listen(updateBadge); 14 | genButton = querySelector('#generateButton'); 15 | genButton.onClick.listen(generateBadge); 16 | } 17 | 18 | void updateBadge(Event e) { 19 | String inputName = (e.target as InputElement).value; 20 | 21 | setBadgeName(inputName); 22 | if (inputName.trim().isEmpty) { 23 | genButton 24 | ..disabled = false 25 | ..text = 'Aye! Gimme a name!'; 26 | } else { 27 | genButton 28 | ..disabled = true 29 | ..text = 'Arrr! Write yer name!'; 30 | } 31 | } 32 | 33 | void generateBadge(Event e) { 34 | setBadgeName('Anne Bonney'); 35 | } 36 | 37 | void setBadgeName(String newName) { 38 | querySelector('#badgeName').text = newName; 39 | } 40 | -------------------------------------------------------------------------------- /darrrt/3-buttonbadge/web/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #F8F8F8; 3 | font-family: 'Open Sans', sans-serif; 4 | font-size: 14px; 5 | font-weight: normal; 6 | line-height: 1.2em; 7 | margin: 15px; 8 | } 9 | 10 | h1, p { 11 | color: #333; 12 | } 13 | .widgets { 14 | padding-bottom: 20pt; 15 | float: left; 16 | } 17 | .badge { 18 | border: 2px solid brown; 19 | border-radius: 1em; 20 | background: red; 21 | font-size: 14pt; 22 | width: 14em; 23 | height: 7em; 24 | text-align: center; 25 | float: left; 26 | margin-left: 20px; 27 | white-space: nowrap; 28 | overflow: hidden; 29 | } 30 | .greeting { 31 | color: white; 32 | font-family: sans-serif; 33 | padding: 0.5em; 34 | } 35 | .name { 36 | color: black; 37 | background: white; 38 | font-family: "Marker Felt", cursive; 39 | font-size: 25pt; 40 | padding-top: 1.0em; 41 | padding-bottom: 0.7em; 42 | height: 16px; 43 | } 44 | #generateButton { 45 | font-size: 12pt; 46 | margin-top: 20px; 47 | } 48 | input[type="text"] { 49 | font-size: 12pt; 50 | margin-top: 10pt; 51 | margin-bottom: 10pt; 52 | width: 12em; 53 | } 54 | @media all and (max-width: 500px) { 55 | .badge { 56 | margin-left: 0px; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /darrrt/4-classbadge/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: avast_ye_pirates 2 | description: Write a Dart web app code lab 3 | dependencies: 4 | browser: ^0.10.0+2 5 | 6 | homepage: https://webdev.dartlang.org/codelabs/darrrt 7 | gist: https://gist.github.com/Sfshaza/445dcc541fd4dedf1b4c 8 | dartpad: https://dartpad.dartlang.org/445dcc541fd4dedf1b4c 9 | -------------------------------------------------------------------------------- /darrrt/4-classbadge/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 15 | Pirate badge 16 | 17 | 18 | 19 | 20 | 21 | 22 |

Pirate badge

23 | 24 |
25 |
26 | 27 |
28 |
29 | 30 |
31 |
32 |
33 |
34 | Arrr! Me name is 35 |
36 |
37 | 38 |
39 |
40 | 41 | 42 | -------------------------------------------------------------------------------- /darrrt/4-classbadge/web/main.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | // In Step 4 of the code lab (dartlang.org/codelabs/darrrt/), 6 | // you created a PirateName class. 7 | 8 | import 'dart:html'; 9 | import 'dart:math' show Random; 10 | 11 | ButtonElement genButton; 12 | 13 | void main() { 14 | querySelector('#inputName').onInput.listen(updateBadge); 15 | genButton = querySelector('#generateButton'); 16 | genButton.onClick.listen(generateBadge); 17 | } 18 | 19 | void updateBadge(Event e) { 20 | String inputName = (e.target as InputElement).value; 21 | 22 | setBadgeName(new PirateName(firstName: inputName)); 23 | if (inputName.trim().isEmpty) { 24 | genButton 25 | ..disabled = false 26 | ..text = 'Aye! Gimme a name!'; 27 | } else { 28 | genButton 29 | ..disabled = true 30 | ..text = 'Arrr! Write yer name!'; 31 | } 32 | } 33 | 34 | void generateBadge(Event e) { 35 | setBadgeName(new PirateName()); 36 | } 37 | 38 | void setBadgeName(PirateName newName) { 39 | querySelector('#badgeName').text = newName.pirateName; 40 | } 41 | 42 | class PirateName { 43 | static final Random indexGen = new Random(); 44 | 45 | String _firstName; 46 | String _appellation; 47 | 48 | PirateName({String firstName, String appellation}) { 49 | if (firstName == null) { 50 | _firstName = names[indexGen.nextInt(names.length)]; 51 | } else { 52 | _firstName = firstName; 53 | } 54 | if (appellation == null) { 55 | _appellation = 56 | appellations[indexGen.nextInt(appellations.length)]; 57 | } else { 58 | _appellation = appellation; 59 | } 60 | } 61 | 62 | @override 63 | String toString() => pirateName; 64 | 65 | String get pirateName => 66 | _firstName.isEmpty ? '' : '$_firstName the $_appellation'; 67 | 68 | static final List names = [ 69 | 'Anne', 'Mary', 'Jack', 'Morgan', 'Roger', 70 | 'Bill', 'Ragnar', 'Ed', 'John', 'Jane' ]; 71 | static final List appellations = [ 72 | 'Jackal', 'King', 'Red', 'Stalwart', 'Axe', 73 | 'Young', 'Brave', 'Eager', 'Wily', 'Zesty']; 74 | } 75 | -------------------------------------------------------------------------------- /darrrt/4-classbadge/web/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #F8F8F8; 3 | font-family: 'Open Sans', sans-serif; 4 | font-size: 14px; 5 | font-weight: normal; 6 | line-height: 1.2em; 7 | margin: 15px; 8 | } 9 | 10 | h1, p { 11 | color: #333; 12 | } 13 | .widgets { 14 | padding-bottom: 20pt; 15 | float: left; 16 | } 17 | .badge { 18 | border: 2px solid brown; 19 | border-radius: 1em; 20 | background: red; 21 | font-size: 14pt; 22 | width: 14em; 23 | height: 7em; 24 | text-align: center; 25 | float: left; 26 | margin-left: 20px; 27 | white-space: nowrap; 28 | overflow: hidden; 29 | } 30 | .greeting { 31 | color: white; 32 | font-family: sans-serif; 33 | padding: 0.5em; 34 | } 35 | .name { 36 | color: black; 37 | background: white; 38 | font-family: "Marker Felt", cursive; 39 | font-size: 25pt; 40 | padding-top: 1.0em; 41 | padding-bottom: 0.7em; 42 | height: 16px; 43 | } 44 | #generateButton { 45 | font-size: 12pt; 46 | margin-top: 20px; 47 | } 48 | input[type="text"] { 49 | font-size: 12pt; 50 | margin-top: 10pt; 51 | margin-bottom: 10pt; 52 | width: 12em; 53 | } 54 | @media all and (max-width: 500px) { 55 | .badge { 56 | margin-left: 0px; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /darrrt/5-final/.idea/.name: -------------------------------------------------------------------------------- 1 | final -------------------------------------------------------------------------------- /darrrt/5-final/.idea/final.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /darrrt/5-final/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /darrrt/5-final/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /darrrt/5-final/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /darrrt/5-final/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: avast_ye_pirates 2 | description: Write a Dart web app code lab 3 | dependencies: 4 | browser: ^0.10.0+2 5 | 6 | homepage: https://webdev.dartlang.org/codelabs/darrrt 7 | gist: https://gist.github.com/Sfshaza/eb2a7982598793c8d984 8 | dartpad: https://dartpad.dartlang.org/eb2a7982598793c8d984 9 | -------------------------------------------------------------------------------- /darrrt/5-final/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 15 | Pirate badge 16 | 17 | 18 | 19 | 20 | 21 | 22 |

Pirate badge

23 | 24 |
25 |
26 | 27 |
28 |
29 | 30 |
31 |
32 |
33 |
34 | Arrr! Me name is 35 |
36 |
37 | 38 |
39 |
40 | 41 | 42 | -------------------------------------------------------------------------------- /darrrt/5-final/web/main.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | // Demonstrates: 6 | // list, maps, random, strings, string interpolation 7 | // cascade, fat arrow, ternary operator 8 | // named constructors 9 | // optional parameters 10 | // a class 11 | // getters 12 | // static class-level methods/fields 13 | // top-level variables and functions 14 | // typecasting with 'as' 15 | // import, also with show 16 | // dart:core, html, math, convert and async libraries 17 | 18 | // In Step 5 of the code lab (dartlang.org/codelabs/darrrt/), 19 | // you read the pirate names from a JSON file. 20 | 21 | import 'dart:html'; 22 | import 'dart:math' show Random; 23 | import 'dart:convert' show JSON; 24 | import 'dart:async' show Future; 25 | 26 | ButtonElement genButton; 27 | SpanElement badgeNameElement; 28 | 29 | Future main() async { 30 | InputElement inputField = querySelector('#inputName'); 31 | inputField.onInput.listen(updateBadge); 32 | genButton = querySelector('#generateButton'); 33 | genButton.onClick.listen(generateBadge); 34 | 35 | badgeNameElement = querySelector('#badgeName'); 36 | 37 | try { 38 | await PirateName.readyThePirates(); 39 | // on success 40 | inputField.disabled = false; //enable 41 | genButton.disabled = false; //enable 42 | } catch (arrr) { 43 | print('Error initializing pirate names: $arrr'); 44 | badgeNameElement.text = 'Arrr! No names.'; 45 | } 46 | } 47 | 48 | void updateBadge(Event e) { 49 | String inputName = (e.target as InputElement).value; 50 | 51 | setBadgeName(new PirateName(firstName: inputName)); 52 | if (inputName.trim().isEmpty) { 53 | genButton 54 | ..disabled = false 55 | ..text = 'Aye! Gimme a name!'; 56 | } else { 57 | genButton 58 | ..disabled = true 59 | ..text = 'Arrr! Write yer name!'; 60 | } 61 | } 62 | 63 | void generateBadge(Event e) { 64 | setBadgeName(new PirateName()); 65 | } 66 | 67 | void setBadgeName(PirateName newName) { 68 | if (newName == null) return; 69 | 70 | badgeNameElement.text = newName.pirateName; 71 | } 72 | 73 | class PirateName { 74 | static final Random indexGen = new Random(); 75 | 76 | static List names = []; 77 | static List appellations = []; 78 | 79 | String _firstName; 80 | String _appellation; 81 | 82 | PirateName({String firstName, String appellation}) { 83 | if (firstName == null) { 84 | _firstName = names[indexGen.nextInt(names.length)]; 85 | } else { 86 | _firstName = firstName; 87 | } 88 | if (appellation == null) { 89 | _appellation = 90 | appellations[indexGen.nextInt(appellations.length)]; 91 | } else { 92 | _appellation = appellation; 93 | } 94 | } 95 | 96 | @override 97 | String toString() => pirateName; 98 | 99 | String get pirateName => 100 | _firstName.isEmpty ? '' : '$_firstName the $_appellation'; 101 | 102 | static Future readyThePirates() async { 103 | String path = 104 | 'https://www.dartlang.org/f/piratenames.json'; 105 | String jsonString = await HttpRequest.getString(path); 106 | _parsePirateNamesFromJSON(jsonString); 107 | } 108 | 109 | static void _parsePirateNamesFromJSON(String jsonString) { 110 | Map pirateNames = JSON.decode(jsonString); 111 | names = pirateNames['names'] as List; 112 | appellations = pirateNames['appellations'] as List; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /darrrt/5-final/web/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #F8F8F8; 3 | font-family: 'Open Sans', sans-serif; 4 | font-size: 14px; 5 | font-weight: normal; 6 | line-height: 1.2em; 7 | margin: 15px; 8 | } 9 | 10 | h1, p { 11 | color: #333; 12 | } 13 | .widgets { 14 | padding-bottom: 20pt; 15 | float: left; 16 | } 17 | .badge { 18 | border: 2px solid brown; 19 | border-radius: 1em; 20 | background: red; 21 | font-size: 14pt; 22 | width: 14em; 23 | height: 7em; 24 | text-align: center; 25 | float: left; 26 | margin-left: 20px; 27 | white-space: nowrap; 28 | overflow: hidden; 29 | } 30 | .greeting { 31 | color: white; 32 | font-family: sans-serif; 33 | padding: 0.5em; 34 | } 35 | .name { 36 | color: black; 37 | background: white; 38 | font-family: "Marker Felt", cursive; 39 | font-size: 25pt; 40 | padding-top: 1.0em; 41 | padding-bottom: 0.7em; 42 | height: 16px; 43 | } 44 | #generateButton { 45 | font-size: 12pt; 46 | margin-top: 20px; 47 | } 48 | input[type="text"] { 49 | font-size: 12pt; 50 | margin-top: 10pt; 51 | margin-bottom: 10pt; 52 | width: 12em; 53 | } 54 | @media all and (max-width: 500px) { 55 | .badge { 56 | margin-left: 0px; 57 | } 58 | } 59 | 60 | -------------------------------------------------------------------------------- /live-demo/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM google/dart-runtime -------------------------------------------------------------------------------- /live-demo/app.yaml: -------------------------------------------------------------------------------- 1 | version: 1 2 | runtime: custom 3 | vm: true 4 | api_version: 1 5 | threadsafe: true 6 | 7 | health_check: 8 | enable_health_check: False 9 | check_interval_sec: 1 10 | timeout_sec: 1 11 | 12 | manual_scaling: 13 | instances: 1 14 | -------------------------------------------------------------------------------- /live-demo/bin/server.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | library piratesnest; 6 | 7 | import 'dart:async'; 8 | import 'dart:io'; 9 | 10 | import 'package:appengine/appengine.dart'; 11 | import 'package:gcloud/service_scope.dart' as scope; 12 | 13 | import 'package:http_server/http_server.dart'; 14 | import 'package:logging/logging.dart'; 15 | import 'package:rpc/rpc.dart'; 16 | 17 | import 'package:server_code_lab/server/piratesapi.dart'; 18 | 19 | final ApiServer _apiServer = new ApiServer(prettyPrint: true); 20 | final Logger _pirateLogger = new Logger('pirate'); 21 | 22 | // Create a virtual directory used to serve our client code from 23 | // the 'build/web' directory. 24 | final String _buildPath = 25 | Platform.script.resolve('../build/web/').toFilePath(); 26 | final VirtualDirectory _clientDir = new VirtualDirectory(_buildPath); 27 | 28 | Future main() async { 29 | // Add a bit of logging... 30 | Logger.root..level = Level.INFO 31 | ..onRecord.listen(print); 32 | 33 | // Set up a server serving the pirate API. 34 | _apiServer.addApi(new PiratesApi()); 35 | _apiServer.enableDiscoveryApi(); 36 | runAppEngine(requestHandler); 37 | } 38 | 39 | Future requestHandler(HttpRequest request) { 40 | return scope.fork(() async { 41 | scope.register(#pirate.sessionId, request.session.id); 42 | _pirateLogger.info('Handling request for session: ${request.session.id}'); 43 | 44 | if (request.uri.path.startsWith('/piratesApi') || 45 | request.uri.path.startsWith('/discovery')) { 46 | // Handle the API request. 47 | var apiResponse; 48 | try { 49 | var apiRequest = 50 | new HttpApiRequest.fromHttpRequest(request); 51 | apiResponse = await _apiServer.handleHttpApiRequest(apiRequest); 52 | } catch (error, stack) { 53 | var exception = 54 | error is Error ? new Exception(error.toString()) : error; 55 | apiResponse = new HttpApiResponse.error( 56 | HttpStatus.INTERNAL_SERVER_ERROR, exception.toString(), 57 | exception, stack); 58 | } 59 | return sendApiResponse(apiResponse, request.response); 60 | } else if (request.uri.path == '/') { 61 | // Redirect to the piratebadge.html file. This will initiate 62 | // loading the client application. 63 | request.response.redirect(Uri.parse('/piratebadge.html')); 64 | } else { 65 | // Disable x-frame-options SAMEORIGIN requirement. This allows 66 | // the website to load the client app into an iframe from a 67 | // different origin. 68 | request.response.headers.set('X-Frame-Options', 'ALLOWALL'); 69 | // Just serve the requested file (path) from the virtual directory, 70 | // minus the preceeding '/'. This will fail with a 404 Not Found 71 | // if the request is not for a valid file. 72 | var fileUri = new Uri.file(_buildPath) 73 | .resolve(request.uri.path.substring(1)); 74 | _clientDir.serveFile(new File(fileUri.toFilePath()), request); 75 | } 76 | }); 77 | } 78 | -------------------------------------------------------------------------------- /live-demo/lib/client/piratesapi.dart: -------------------------------------------------------------------------------- 1 | library server_code_lab.piratesApi.client; 2 | 3 | import 'dart:core' as core; 4 | import 'dart:collection' as collection; 5 | import 'dart:async' as async; 6 | import 'dart:convert' as convert; 7 | 8 | import 'package:_discoveryapis_commons/_discoveryapis_commons.dart' as commons; 9 | import 'package:crypto/crypto.dart' as crypto; 10 | import 'package:http/http.dart' as http; 11 | import 'package:server_code_lab/common/messages.dart'; 12 | export 'package:_discoveryapis_commons/_discoveryapis_commons.dart' show 13 | ApiRequestError, DetailedApiRequestError; 14 | 15 | const core.String USER_AGENT = 'dart-api-client piratesApi/v1'; 16 | 17 | class PiratesApi { 18 | 19 | final commons.ApiRequester _requester; 20 | 21 | PiratesApi(http.Client client, {core.String rootUrl: "http://localhost:9090/", core.String servicePath: "piratesApi/v1/"}) : 22 | _requester = new commons.ApiRequester(client, rootUrl, servicePath, USER_AGENT); 23 | 24 | /** 25 | * Request parameters: 26 | * 27 | * [name] - Path parameter: 'name'. 28 | * 29 | * [appellation] - Path parameter: 'appellation'. 30 | * 31 | * Completes with a [Pirate]. 32 | * 33 | * Completes with a [commons.ApiRequestError] if the API endpoint returned an 34 | * error. 35 | * 36 | * If the used [http.Client] completes with an error when making a REST call, 37 | * this method will complete with the same error. 38 | */ 39 | async.Future firePirate(core.String name, core.String appellation) { 40 | var _url = null; 41 | var _queryParams = new core.Map(); 42 | var _uploadMedia = null; 43 | var _uploadOptions = null; 44 | var _downloadOptions = commons.DownloadOptions.Metadata; 45 | var _body = null; 46 | 47 | if (name == null) { 48 | throw new core.ArgumentError("Parameter name is required."); 49 | } 50 | if (appellation == null) { 51 | throw new core.ArgumentError("Parameter appellation is required."); 52 | } 53 | 54 | 55 | _url = 'pirate/' + commons.Escaper.ecapeVariable('$name') + '/the/' + commons.Escaper.ecapeVariable('$appellation'); 56 | 57 | var _response = _requester.request(_url, 58 | "DELETE", 59 | body: _body, 60 | queryParams: _queryParams, 61 | uploadOptions: _uploadOptions, 62 | uploadMedia: _uploadMedia, 63 | downloadOptions: _downloadOptions); 64 | return _response.then((data) => PirateFactory.fromJson(data)); 65 | } 66 | 67 | /** 68 | * [request] - The metadata request object. 69 | * 70 | * Request parameters: 71 | * 72 | * Completes with a [Pirate]. 73 | * 74 | * Completes with a [commons.ApiRequestError] if the API endpoint returned an 75 | * error. 76 | * 77 | * If the used [http.Client] completes with an error when making a REST call, 78 | * this method will complete with the same error. 79 | */ 80 | async.Future hirePirate(Pirate request) { 81 | var _url = null; 82 | var _queryParams = new core.Map(); 83 | var _uploadMedia = null; 84 | var _uploadOptions = null; 85 | var _downloadOptions = commons.DownloadOptions.Metadata; 86 | var _body = null; 87 | 88 | if (request != null) { 89 | _body = convert.JSON.encode(PirateFactory.toJson(request)); 90 | } 91 | 92 | 93 | _url = 'pirate'; 94 | 95 | var _response = _requester.request(_url, 96 | "POST", 97 | body: _body, 98 | queryParams: _queryParams, 99 | uploadOptions: _uploadOptions, 100 | uploadMedia: _uploadMedia, 101 | downloadOptions: _downloadOptions); 102 | return _response.then((data) => PirateFactory.fromJson(data)); 103 | } 104 | 105 | /** 106 | * Request parameters: 107 | * 108 | * Completes with a [core.List]. 109 | * 110 | * Completes with a [commons.ApiRequestError] if the API endpoint returned an 111 | * error. 112 | * 113 | * If the used [http.Client] completes with an error when making a REST call, 114 | * this method will complete with the same error. 115 | */ 116 | async.Future> listPirates() { 117 | var _url = null; 118 | var _queryParams = new core.Map(); 119 | var _uploadMedia = null; 120 | var _uploadOptions = null; 121 | var _downloadOptions = commons.DownloadOptions.Metadata; 122 | var _body = null; 123 | 124 | 125 | 126 | _url = 'pirates'; 127 | 128 | var _response = _requester.request(_url, 129 | "GET", 130 | body: _body, 131 | queryParams: _queryParams, 132 | uploadOptions: _uploadOptions, 133 | uploadMedia: _uploadMedia, 134 | downloadOptions: _downloadOptions); 135 | return _response.then((data) => data.map((value) => PirateFactory.fromJson(value)).toList()); 136 | } 137 | 138 | /** 139 | * Request parameters: 140 | * 141 | * Completes with a [core.Map>]. 142 | * 143 | * Completes with a [commons.ApiRequestError] if the API endpoint returned an 144 | * error. 145 | * 146 | * If the used [http.Client] completes with an error when making a REST call, 147 | * this method will complete with the same error. 148 | */ 149 | async.Future>> properPirates() { 150 | var _url = null; 151 | var _queryParams = new core.Map(); 152 | var _uploadMedia = null; 153 | var _uploadOptions = null; 154 | var _downloadOptions = commons.DownloadOptions.Metadata; 155 | var _body = null; 156 | 157 | 158 | 159 | _url = 'proper/pirates'; 160 | 161 | var _response = _requester.request(_url, 162 | "GET", 163 | body: _body, 164 | queryParams: _queryParams, 165 | uploadOptions: _uploadOptions, 166 | uploadMedia: _uploadMedia, 167 | downloadOptions: _downloadOptions); 168 | return _response.then((data) => data); 169 | } 170 | 171 | /** 172 | * Request parameters: 173 | * 174 | * Completes with a [Pirate]. 175 | * 176 | * Completes with a [commons.ApiRequestError] if the API endpoint returned an 177 | * error. 178 | * 179 | * If the used [http.Client] completes with an error when making a REST call, 180 | * this method will complete with the same error. 181 | */ 182 | async.Future shanghaiAPirate() { 183 | var _url = null; 184 | var _queryParams = new core.Map(); 185 | var _uploadMedia = null; 186 | var _uploadOptions = null; 187 | var _downloadOptions = commons.DownloadOptions.Metadata; 188 | var _body = null; 189 | 190 | 191 | 192 | _url = 'shanghai'; 193 | 194 | var _response = _requester.request(_url, 195 | "GET", 196 | body: _body, 197 | queryParams: _queryParams, 198 | uploadOptions: _uploadOptions, 199 | uploadMedia: _uploadMedia, 200 | downloadOptions: _downloadOptions); 201 | return _response.then((data) => PirateFactory.fromJson(data)); 202 | } 203 | 204 | } 205 | 206 | 207 | 208 | class PirateFactory { 209 | static Pirate fromJson(core.Map _json) { 210 | var message = new Pirate(); 211 | if (_json.containsKey("appellation")) { 212 | message.appellation = _json["appellation"]; 213 | } 214 | if (_json.containsKey("name")) { 215 | message.name = _json["name"]; 216 | } 217 | return message; 218 | } 219 | 220 | static core.Map toJson(Pirate message) { 221 | var _json = new core.Map(); 222 | if (message.appellation != null) { 223 | _json["appellation"] = message.appellation; 224 | } 225 | if (message.name != null) { 226 | _json["name"] = message.name; 227 | } 228 | return _json; 229 | } 230 | } 231 | 232 | 233 | -------------------------------------------------------------------------------- /live-demo/lib/common/messages.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | library pirate.messages; 6 | 7 | // This class is used to send data back and forth between the 8 | // client and server. It is automatically serialized and 9 | // deserialized by the RPC package. 10 | class Pirate { 11 | String name; 12 | String appellation; 13 | 14 | // A message class must have a default constructor taking no 15 | // arguments. 16 | Pirate(); 17 | 18 | // It is fine to have other named constructors. 19 | Pirate.fromString(String pirateName) { 20 | var parts = pirateName.split(' the '); 21 | name = parts[0]; 22 | appellation = parts[1]; 23 | } 24 | 25 | @override 26 | String toString() => name.isEmpty ? '' : '$name the $appellation'; 27 | } 28 | -------------------------------------------------------------------------------- /live-demo/lib/common/utils.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | library pirate.utils; 6 | 7 | import 'dart:math' show Random; 8 | 9 | import 'messages.dart'; 10 | 11 | // Proper pirate names. 12 | const List pirateNames = const [ "Anne", "Bette", "Cate", "Dawn", 13 | "Elise", "Faye", "Ginger", "Harriot", "Izzy", "Jane", "Kaye", "Liz", "Maria", 14 | "Nell", "Olive", "Pat","Queenie", "Rae", "Sal", "Tam", "Uma", "Violet", 15 | "Wilma", "Xana", "Yvonne", "Zelda", "Abe", "Billy", "Caleb", "Davie", "Eb", 16 | "Frank", "Gabe", "House", "Icarus", "Jack", "Kurt", "Larry", "Mike", "Nolan", 17 | "Oliver", "Pat", "Quib", "Roy", "Sal", "Tom", "Ube", "Val", "Walt", "Xavier", 18 | "Yvan", "Zeb"]; 19 | 20 | // Proper pirate appellations. 21 | const List pirateAppellations = const [ "Awesome", "Captain", "Even", 22 | "Fighter", "Great", "Hearty", "Jackal", "King", "Lord", "Mighty", "Noble", 23 | "Old", "Powerful", "Quick", "Red", "Stalwart", "Tank", "Ultimate", "Vicious", 24 | "Wily", "aXe", "Young", "Brave", "Eager", "Kind", "Sandy", "Xeric", "Yellow", 25 | "Zesty"]; 26 | 27 | // Clearly invalid pirate appellations. 28 | const List _forbiddenAppellations = const [ 29 | '', 30 | 'sweet', 31 | 'handsome', 32 | 'beautiful', 33 | 'weak', 34 | 'wuss', 35 | 'chicken', 36 | 'fearful', 37 | ]; 38 | 39 | // Helper method for validating whether the given pirate is truly a pirate! 40 | bool truePirate(Pirate pirate) => pirate.name != null && 41 | pirate.name.trim().isNotEmpty && pirate.appellation != null && 42 | !_forbiddenAppellations.contains(pirate.appellation.toLowerCase()); 43 | 44 | // Shared class for shanghaiing (generating) pirates. 45 | class PirateShanghaier { 46 | static final Random indexGen = new Random(); 47 | 48 | Pirate shanghaiAPirate({String name, String appellation}) { 49 | var pirate = new Pirate(); 50 | pirate.name = 51 | name != null ? name : pirateNames[indexGen.nextInt(pirateNames.length)]; 52 | pirate.appellation = appellation != null 53 | ? appellation 54 | : pirateAppellations[indexGen.nextInt(pirateAppellations.length)]; 55 | return truePirate(pirate) ? pirate : null; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /live-demo/lib/server/piratesapi.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | library pirate.server; 6 | 7 | import 'package:gcloud/service_scope.dart' as scope; 8 | import 'package:rpc/rpc.dart'; 9 | 10 | import '../common/messages.dart'; 11 | import '../common/utils.dart'; 12 | 13 | // This class defines the interface that the server provides. 14 | @ApiClass(version: 'v1') 15 | class PiratesApi { 16 | final Map> _pirateCrews = {}; 17 | final PirateShanghaier _shanghaier = new PirateShanghaier(); 18 | 19 | // Getter to maintain a per user pirate crew. 20 | Map get pirateCrew { 21 | var sessionId = scope.lookup(#pirate.sessionId); 22 | assert(sessionId != null); 23 | var crew = _pirateCrews[sessionId]; 24 | if (crew == null) { 25 | crew = {}; 26 | var captain = new Pirate.fromString('Lars the Captain'); 27 | crew[captain.toString()] = captain; 28 | _pirateCrews[sessionId] = crew; 29 | } 30 | return crew; 31 | } 32 | 33 | @ApiMethod(method: 'POST', path: 'pirate') 34 | Pirate hirePirate(Pirate newPirate) { 35 | // Make sure this is a real pirate... 36 | if (!truePirate(newPirate)) { 37 | throw new BadRequestError( 38 | '$newPirate cannot be a pirate. \'Tis not a pirate name!'); 39 | } 40 | var pirateName = newPirate.toString(); 41 | if (pirateCrew.containsKey(pirateName)) { 42 | throw new BadRequestError( 43 | '$newPirate is already part of your crew!'); 44 | } 45 | 46 | // Add pirate to store. 47 | pirateCrew[pirateName] = newPirate; 48 | return newPirate; 49 | } 50 | 51 | @ApiMethod(method: 'DELETE', path: 'pirate/{name}/the/{appellation}') 52 | Pirate firePirate(String name, String appellation) { 53 | var pirate = new Pirate() 54 | ..name = Uri.decodeComponent(name) 55 | ..appellation = Uri.decodeComponent(appellation); 56 | var pirateName = pirate.toString(); 57 | if (!pirateCrew.containsKey(pirateName)) { 58 | throw new NotFoundError( 59 | 'Could not find pirate \'$pirate\'!' + 60 | 'Maybe they\'ve abandoned ship!'); 61 | } 62 | return pirateCrew.remove(pirateName); 63 | } 64 | 65 | @ApiMethod(method: 'GET', path: 'pirates') 66 | List listPirates() { 67 | return pirateCrew.values.toList(); 68 | } 69 | 70 | @ApiMethod(path: 'shanghai') // Default HTTP method is GET. 71 | Pirate shanghaiAPirate() { 72 | var pirate = _shanghaier.shanghaiAPirate(); 73 | if (pirate == null) { 74 | throw new InternalServerError('Ran out of pirates!'); 75 | } 76 | return pirate; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /live-demo/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: server_code_lab 2 | version: 0.1.0 3 | author: Dart Team 4 | description: Code-lab server sample. 5 | environment: 6 | sdk: '>=1.9.0 <2.0.0' 7 | dependencies: 8 | _discoveryapis_commons: '^0.1.0' 9 | appengine: '^0.3.0' 10 | browser: '^0.10.0+2' 11 | crypto: '^0.9.0' 12 | gcloud: '^0.2.0+1' 13 | http: '^0.11.1' 14 | http_server: '^0.9.5+1' 15 | logging_handlers: '^0.8.0' 16 | rpc: '^0.4.1' 17 | -------------------------------------------------------------------------------- /live-demo/web/piratebadge.css: -------------------------------------------------------------------------------- 1 | @import url(//fonts.googleapis.com/css?family=Roboto&subset=latin,latin-ext); 2 | 3 | body { 4 | background-color: #f5f5f5; 5 | font-family: 'Roboto', sans-serif; 6 | font-size: 14px; 7 | font-weight: normal; 8 | line-height: 1.2em; 9 | margin: 15px; 10 | color: #424242; 11 | } 12 | h1 { 13 | font-weight: normal; 14 | font-size: 32px; 15 | margin-bottom: 30px; 16 | } 17 | button { 18 | font-family: inherit; 19 | font-size: 14px; 20 | margin: 20px auto 0; 21 | box-shadow: 0 1px 1.5px 0 rgba(0, 0, 0, 0.12), 0 1px 1px 0 rgba(0, 0, 0, 0.24); 22 | border-radius: 2px; 23 | border: none; 24 | padding: 6px 8px; 25 | text-transform: uppercase; 26 | background: #e3e3e3; 27 | color: black; 28 | outline: none; 29 | -webkit-transition: all 0.2s ease-in; 30 | transition: all 0.2s ease-in; 31 | display: block; 32 | } 33 | button[disabled] { 34 | background-color: #d8d8d8 !important; 35 | color: #a0a0a0 !important; 36 | } 37 | button:active { 38 | box-shadow: 0 10px 10px 0 rgba(0, 0, 0, 0.19), 0 6px 3px 0 rgba(0, 0, 0, 0.23); 39 | } 40 | button:not(:disabled) { 41 | cursor: pointer; 42 | } 43 | input[type="text"] { 44 | outline: none; 45 | font-family: inherit; 46 | font-size: 16px; 47 | border: none; 48 | border-bottom: 1px solid #ddd; 49 | background: none; 50 | } 51 | select { 52 | font-family: inherit; 53 | border: none; 54 | outline: none; 55 | background: white; 56 | } 57 | select:focus option:checked, select option:hover { 58 | background: linear-gradient(#000000, #000000); 59 | color: #bbb; 60 | } 61 | select option { 62 | border-bottom: 1px solid #d2d2d2; 63 | padding: 8px 6px; 64 | outline: none; 65 | } 66 | select option:checked { 67 | background: linear-gradient(#f0f0f0, #f0f0f0); 68 | } 69 | .widgets { 70 | padding-bottom: 20px; 71 | margin-bottom: 20px; 72 | margin-right: 20px; 73 | float: left; 74 | } 75 | .form { 76 | overflow: hidden; 77 | } 78 | .badge, .pirates { 79 | border-radius: 2px; 80 | font-size: 19px; 81 | width: 14em; 82 | text-align: center; 83 | white-space: nowrap; 84 | overflow: hidden; 85 | box-shadow: 0 1px 1.5px 0 rgba(0, 0, 0, 0.12), 0 1px 1px 0 rgba(0, 0, 0, 0.24); 86 | } 87 | .badge { 88 | background: #f44336; 89 | height: 7em; 90 | } 91 | .pirates { 92 | background: #2196f3; 93 | } 94 | .greeting { 95 | color: white; 96 | padding: 0.5em; 97 | font-size: 20px; 98 | } 99 | .name { 100 | color: black; 101 | background: white; 102 | font-family: "Marker Felt", cursive; 103 | font-size: 30px; 104 | padding: 1em 0; 105 | height: 16px; 106 | } 107 | #pirateList { 108 | width: 100%; 109 | height: 14em; 110 | } 111 | #generateButton { 112 | margin-bottom: 100px; 113 | } 114 | #storeButton { 115 | background: #2196f3; 116 | color: white; 117 | } 118 | #storeButton:hover { 119 | background: #1e88e5; 120 | } 121 | #storeButton:active { 122 | background: #1976d2; 123 | } 124 | #killButton { 125 | background: black; 126 | color: white; 127 | } 128 | #killButton:hover, 129 | #killButton:active { 130 | background: #212121; 131 | } 132 | #inputName { 133 | margin: 30px 0 0; 134 | width: 14em; 135 | padding: 5px 0; 136 | } 137 | #inputName + span { 138 | display: block; 139 | width: 10px; 140 | height: 2px; 141 | background: #2196f3; 142 | position: relative; 143 | top: -2px; 144 | left: 50%; 145 | visibility: hidden; 146 | -webkit-transition: all .2s ease-in; 147 | transition: all .2s ease-in; 148 | } 149 | #inputName:focus + span { 150 | width: 100%; 151 | left: 0; 152 | visibility: visible; 153 | } 154 | div::selection, button::selection { 155 | background: none; 156 | } 157 | div::-moz-selection, button::-moz-selection { 158 | background: none; 159 | } 160 | @media all and (max-width: 600px) { 161 | #generateButton { 162 | margin-bottom: 0; 163 | } 164 | } 165 | @media all and (max-width: 560px) { 166 | h1 { 167 | text-align: center; 168 | } 169 | .form { 170 | width: 16em; 171 | margin: 0 auto; 172 | } 173 | .widgets, .badge, .pirates, button, #inputName { 174 | float: none; 175 | margin-left: auto; 176 | margin-right: auto; 177 | } 178 | #inputName { 179 | width: 100%; 180 | } 181 | .widgets { 182 | margin-bottom: 50px; 183 | padding-bottom: 0; 184 | } 185 | } 186 | /* This is needed for proper ripple effect on buttons */ 187 | button { 188 | position: relative; 189 | overflow: hidden; 190 | } 191 | button .ripple { 192 | position: absolute; 193 | display: block; 194 | border-radius: 100%; 195 | width: 0; 196 | height: 0; 197 | pointer-events: none; 198 | background: rgba(0, 0, 0, .2); 199 | -webkit-transform: translate(-50%, -50%); 200 | transform: translate(-50%, -50%); 201 | } 202 | button .ripple.show { 203 | -webkit-animation: ripple .3s ease-in; 204 | animation: ripple .3s ease-in; 205 | } 206 | #storeButton .ripple, 207 | #killButton .ripple { 208 | background: rgba(255, 255, 255, .2); 209 | } 210 | @-webkit-keyframes ripple { 211 | from { 212 | width: 0; 213 | } 214 | to { 215 | width: 200%; 216 | padding-top: 200%; 217 | } 218 | } 219 | @keyframes ripple { 220 | from { 221 | width: 0; 222 | } 223 | to { 224 | width: 200%; 225 | padding-top: 200%; 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /live-demo/web/piratebadge.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, 2015 the Dart project authors. 2 | // Please see the AUTHORS file for details. All rights reserved. 3 | // Use of this source code is governed by a BSD-style license that can be 4 | // found in the LICENSE file. 5 | 6 | import 'dart:async'; 7 | import 'dart:html'; 8 | 9 | import 'package:http/browser_client.dart'; 10 | import 'package:server_code_lab/client/piratesapi.dart'; 11 | import 'package:server_code_lab/common/messages.dart'; 12 | import 'package:server_code_lab/common/utils.dart'; 13 | 14 | final String treasureKey = 'pirateName'; 15 | 16 | ButtonElement genButton; 17 | ButtonElement storeButton; 18 | ButtonElement fireButton; 19 | ButtonElement slayButton; 20 | SpanElement badgeNameElement; 21 | SelectElement pirateList; 22 | 23 | // By default the generated client code uses 24 | // 'http://localhost:9090/'. Since our server is running on 25 | // port 8088 (8080 on appengine) we override the default url when instantiating 26 | // the generated PiratesApi class. 27 | final String _serverUrl = 'pirates-nest.appspot.com/'; 28 | //final String _serverUrl = 'localhost:8080/'; 29 | final BrowserClient _client = new BrowserClient(); 30 | PiratesApi _api; 31 | PirateShanghaier _shanghaier; 32 | 33 | Future main() async { 34 | // We need to determine if the client is using http or https 35 | // and use the same protocol for the client stub requests 36 | // (the protocol includes the ':'). 37 | var protocol = window.location.protocol; 38 | if (!['http:', 'https:'].contains(protocol)) { 39 | // Default to http if unknown protocol. 40 | protocol = 'http:'; 41 | } 42 | _api = new PiratesApi(_client, rootUrl: '$protocol//$_serverUrl'); 43 | _shanghaier = new PirateShanghaier(); 44 | 45 | InputElement inputField = querySelector('#inputName'); 46 | inputField.onInput.listen(updateBadge); 47 | genButton = querySelector('#generateButton'); 48 | genButton.onClick.listen(generateBadge); 49 | inputField.disabled = false; //enable 50 | genButton.disabled = false; //enable 51 | badgeNameElement = querySelector('#badgeName'); 52 | storeButton = querySelector('#storeButton'); 53 | storeButton.onClick.listen(storeBadge); 54 | pirateList = querySelector('#pirateList'); 55 | pirateList.onClick.listen(selectListener); 56 | fireButton = querySelector('#fireButton'); 57 | fireButton.onClick.listen(removeBadge); 58 | slayButton = querySelector('#slayButton'); 59 | slayButton.onClick.listen(removeAllBadges); 60 | setBadgeName(getBadgeNameFromStorage()); 61 | refreshList(); 62 | 63 | var buttons = querySelectorAll("button"); 64 | buttons.onClick.listen(addRippleEffect); 65 | } 66 | 67 | Future refreshList() async { 68 | List pirates = await _api.listPirates(); 69 | pirateList.children.clear(); 70 | pirates.forEach((pirate) { 71 | var option = new OptionElement(data: pirate.toString()); 72 | pirateList.add(option, 0); 73 | }); 74 | 75 | var disabled = true; 76 | if (pirateList.length > 0) { 77 | disabled = false; 78 | } 79 | 80 | new Future.delayed(new Duration(milliseconds: 300), () { 81 | slayButton.disabled = disabled; 82 | }); 83 | } 84 | 85 | void updateBadge(Event e) { 86 | String inputName = (e.target as InputElement).value.trim(); 87 | var pirate = _shanghaier.shanghaiAPirate(name: inputName); 88 | setBadgeName(pirate); 89 | if (inputName.trim().isEmpty) { 90 | genButton 91 | ..disabled = false 92 | ..text = 'Aye! Gimme a name!'; 93 | storeButton..disabled = true; 94 | } else { 95 | genButton 96 | ..disabled = true 97 | ..text = 'Arrr! Write yer name!'; 98 | storeButton..disabled = false; 99 | } 100 | } 101 | 102 | Future storeBadge(Event e) async { 103 | var pirateName = badgeNameElement.text; 104 | if (pirateName == null || pirateName.isEmpty) return null; 105 | var pirate = new Pirate.fromString(pirateName); 106 | try { 107 | await _api.hirePirate(pirate); 108 | } catch (error) { 109 | window.alert(error.message); 110 | } 111 | new Future.delayed(new Duration(milliseconds: 300), () { 112 | storeButton 113 | ..disabled = true 114 | ..text = 'Pirate hired!'; 115 | }); 116 | refreshList(); 117 | } 118 | 119 | Future selectListener(Event e) async { 120 | fireButton.disabled = false; 121 | } 122 | 123 | Future removeBadge(Event e) async { 124 | var idx = pirateList.selectedIndex; 125 | if (idx < 0 || idx >= pirateList.options.length) return null; 126 | var option = pirateList.options.elementAt(idx); 127 | var pirate = new Pirate.fromString(option.label); 128 | try { 129 | await _api.firePirate(pirate.name, pirate.appellation); 130 | } catch (error) { 131 | window.alert(error.message); 132 | } 133 | new Future.delayed(new Duration(milliseconds: 300), () { 134 | fireButton.disabled = true; 135 | }); 136 | refreshList(); 137 | } 138 | 139 | Future removeAllBadges(Event e) async { 140 | for (var option in pirateList.options) { 141 | var pirate = new Pirate.fromString(option.label); 142 | try { 143 | await _api.firePirate(pirate.name, pirate.appellation); 144 | } catch (error) { 145 | // ignoring errors. 146 | } 147 | } 148 | new Future.delayed(new Duration(milliseconds: 300), () { 149 | fireButton.disabled = true; 150 | slayButton.disabled = true; 151 | }); 152 | refreshList(); 153 | } 154 | 155 | void generateBadge(Event e) { 156 | var pirate = _shanghaier.shanghaiAPirate(); 157 | setBadgeName(pirate); 158 | } 159 | 160 | void setBadgeName(Pirate pirate) { 161 | if (pirate == null || pirate.toString().isEmpty) { 162 | badgeNameElement.text = ''; 163 | storeButton.disabled = true; 164 | return; 165 | } 166 | badgeNameElement.text = pirate.toString(); 167 | window.localStorage[treasureKey] = pirate.toString(); 168 | storeButton 169 | ..disabled = false 170 | ..text = 'Hire pirate!'; 171 | } 172 | 173 | Pirate getBadgeNameFromStorage() { 174 | String storedName = window.localStorage[treasureKey]; 175 | if (storedName != null && storedName.contains(' the ')) { 176 | return new Pirate.fromString(storedName); 177 | } else { 178 | return null; 179 | } 180 | } 181 | 182 | void addRippleEffect(MouseEvent e) { 183 | var button = e.target as ButtonElement; 184 | var ripple = button.querySelector('.ripple'); 185 | 186 | // we need to delete existing ripple element 187 | if (ripple != null) { 188 | ripple.remove(); 189 | } 190 | 191 | var x = e.client.x - button.getBoundingClientRect().left; 192 | var y = e.client.y - button.getBoundingClientRect().top; 193 | 194 | ripple = new SpanElement() 195 | ..classes.add("ripple") 196 | ..style.left = "${x}px" 197 | ..style.top = "${y}px" 198 | ..classes.add("show"); 199 | 200 | button.append(ripple); 201 | } 202 | -------------------------------------------------------------------------------- /live-demo/web/piratebadge.html: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Pirate badge 12 | 14 | 15 | 16 | 17 |

Pirate badge

18 | 19 |
20 |
21 | 22 | 23 |
24 |
25 | 26 |
27 |
28 |
29 |
30 |
31 | Arrr! Me name is 32 |
33 |
34 | 35 |
36 |
37 |
38 | 39 |
40 |
41 |
42 |
43 |
44 | Pirate crew! 45 |
46 | 47 |
48 |
49 | 50 |
51 |
52 | 53 |
54 |
55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /ng2/1-skeleton/.gitignore: -------------------------------------------------------------------------------- 1 | # Files and directories created by pub 2 | .packages 3 | .pub/ 4 | build/ 5 | # Remove the following pattern if you wish to check in your lock file 6 | pubspec.lock 7 | 8 | # Directory created by dartdoc 9 | doc/api/ 10 | -------------------------------------------------------------------------------- /ng2/1-skeleton/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 ng2-dart-samples 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 | 23 | -------------------------------------------------------------------------------- /ng2/1-skeleton/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | analyzer: 2 | strong-mode: true 3 | # exclude: 4 | # - path/to/excluded/files/** 5 | 6 | # Lint rules and documentation, see http://dart-lang.github.io/linter/lints 7 | linter: 8 | rules: 9 | - cancel_subscriptions 10 | - close_sinks 11 | - hash_and_equals 12 | - iterable_contains_unrelated_type 13 | - list_remove_unrelated_type 14 | - test_types_in_equals 15 | - unrelated_type_equality_checks 16 | - valid_regexps 17 | -------------------------------------------------------------------------------- /ng2/1-skeleton/lib/app_component.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017, the Dart project authors. 2 | // All rights reserved. Use of this source code 3 | // is governed by a BSD-style license that can be 4 | // found in the LICENSE file. 5 | 6 | import 'package:angular2/angular2.dart'; 7 | 8 | @Component( 9 | selector: 'my-app', 10 | template: '

Hello {{name}}

', 11 | ) 12 | class AppComponent { 13 | var name = 'Angular'; 14 | } 15 | -------------------------------------------------------------------------------- /ng2/1-skeleton/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: pirate_badge 2 | description: A simple AngularDart app 3 | version: 0.0.1 4 | environment: 5 | sdk: '>=1.24.0 <2.0.0' 6 | dependencies: 7 | angular2: ^3.0.0 8 | dev_dependencies: 9 | browser: ^0.10.0 10 | dart_to_js_script_rewriter: ^1.0.1 11 | transformers: 12 | - angular2: 13 | entry_points: web/main.dart 14 | - dart_to_js_script_rewriter 15 | web: 16 | compiler: 17 | debug: dartdevc 18 | -------------------------------------------------------------------------------- /ng2/1-skeleton/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 11 | 12 | Hello Angular 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | Loading... 22 | 23 | 24 | -------------------------------------------------------------------------------- /ng2/1-skeleton/web/main.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017, the Dart project authors. 2 | // All rights reserved. Use of this source code 3 | // is governed by a BSD-style license that can be 4 | // found in the LICENSE file. 5 | 6 | import 'package:angular2/platform/browser.dart'; 7 | 8 | import 'package:pirate_badge/app_component.dart'; 9 | 10 | void main() { 11 | bootstrap(AppComponent); 12 | } 13 | -------------------------------------------------------------------------------- /ng2/1-skeleton/web/styles.css: -------------------------------------------------------------------------------- 1 | /* Master Styles */ 2 | h1 { 3 | color: #369; 4 | font-family: Arial, Helvetica, sans-serif; 5 | font-size: 250%; 6 | } 7 | h2, h3 { 8 | color: #444; 9 | font-family: Arial, Helvetica, sans-serif; 10 | font-weight: lighter; 11 | } 12 | body { 13 | margin: 2em; 14 | } 15 | body, input[text], button { 16 | color: #888; 17 | font-family: Cambria, Georgia; 18 | } 19 | a { 20 | cursor: pointer; 21 | cursor: hand; 22 | } 23 | button { 24 | font-family: Arial; 25 | background-color: #eee; 26 | border: none; 27 | padding: 5px 10px; 28 | border-radius: 4px; 29 | cursor: pointer; 30 | cursor: hand; 31 | } 32 | button:hover { 33 | background-color: #cfd8dc; 34 | } 35 | button:disabled { 36 | background-color: #eee; 37 | color: #aaa; 38 | cursor: auto; 39 | } 40 | 41 | /* Navigation link styles */ 42 | nav a { 43 | padding: 5px 10px; 44 | text-decoration: none; 45 | margin-top: 10px; 46 | display: inline-block; 47 | background-color: #eee; 48 | border-radius: 4px; 49 | } 50 | nav a:visited, a:link { 51 | color: #607D8B; 52 | } 53 | nav a:hover { 54 | color: #039be5; 55 | background-color: #CFD8DC; 56 | } 57 | nav a.active { 58 | color: #039be5; 59 | } 60 | 61 | /* items class */ 62 | .items { 63 | margin: 0 0 2em 0; 64 | list-style-type: none; 65 | padding: 0; 66 | width: 24em; 67 | } 68 | .items li { 69 | cursor: pointer; 70 | position: relative; 71 | left: 0; 72 | background-color: #EEE; 73 | margin: .5em; 74 | padding: .3em 0; 75 | height: 1.6em; 76 | border-radius: 4px; 77 | } 78 | .items li:hover { 79 | color: #607D8B; 80 | background-color: #DDD; 81 | left: .1em; 82 | } 83 | .items li.selected { 84 | background-color: #CFD8DC; 85 | color: white; 86 | } 87 | .items li.selected:hover { 88 | background-color: #BBD8DC; 89 | } 90 | .items .text { 91 | position: relative; 92 | top: -3px; 93 | } 94 | .items .badge { 95 | display: inline-block; 96 | font-size: small; 97 | color: white; 98 | padding: 0.8em 0.7em 0 0.7em; 99 | background-color: #607D8B; 100 | line-height: 1em; 101 | position: relative; 102 | left: -1px; 103 | top: -4px; 104 | height: 1.8em; 105 | margin-right: .8em; 106 | border-radius: 4px 0 0 4px; 107 | } 108 | /* everywhere else */ 109 | * { 110 | font-family: Arial, Helvetica, sans-serif; 111 | } 112 | -------------------------------------------------------------------------------- /ng2/2-blankbadge/.gitignore: -------------------------------------------------------------------------------- 1 | # Files and directories created by pub 2 | .packages 3 | .pub/ 4 | build/ 5 | # Remove the following pattern if you wish to check in your lock file 6 | pubspec.lock 7 | 8 | # Directory created by dartdoc 9 | doc/api/ 10 | -------------------------------------------------------------------------------- /ng2/2-blankbadge/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 ng2-dart-samples 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 | 23 | -------------------------------------------------------------------------------- /ng2/2-blankbadge/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | analyzer: 2 | strong-mode: true 3 | # exclude: 4 | # - path/to/excluded/files/** 5 | 6 | # Lint rules and documentation, see http://dart-lang.github.io/linter/lints 7 | linter: 8 | rules: 9 | - cancel_subscriptions 10 | - close_sinks 11 | - hash_and_equals 12 | - iterable_contains_unrelated_type 13 | - list_remove_unrelated_type 14 | - test_types_in_equals 15 | - unrelated_type_equality_checks 16 | - valid_regexps 17 | -------------------------------------------------------------------------------- /ng2/2-blankbadge/lib/app_component.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017, the Dart project authors. 2 | // All rights reserved. Use of this source code 3 | // is governed by a BSD-style license that can be 4 | // found in the LICENSE file. 5 | 6 | import 'package:angular2/angular2.dart'; 7 | 8 | import 'src/badge_component.dart'; 9 | 10 | @Component( 11 | selector: 'my-app', 12 | templateUrl: 'app_component.html', 13 | directives: const [BadgeComponent], 14 | ) 15 | class AppComponent { 16 | var name = 'Angular'; 17 | } 18 | -------------------------------------------------------------------------------- /ng2/2-blankbadge/lib/app_component.html: -------------------------------------------------------------------------------- 1 | 7 | 8 |

Avast, Ye Pirates

9 | 10 | -------------------------------------------------------------------------------- /ng2/2-blankbadge/lib/src/badge_component.css: -------------------------------------------------------------------------------- 1 | .widgets { 2 | padding-bottom: 20pt; 3 | float: left; 4 | } 5 | .badge { 6 | border: 2px solid brown; 7 | border-radius: 1em; 8 | background: red; 9 | font-size: 14pt; 10 | width: 14em; 11 | height: 7em; 12 | text-align: center; 13 | float: left; 14 | margin-left: 20px; 15 | white-space: nowrap; 16 | overflow: hidden; 17 | } 18 | .greeting { 19 | color: white; 20 | font-family: sans-serif; 21 | padding: 0.5em; 22 | } 23 | .name { 24 | color: black; 25 | background: white; 26 | font-family: "Marker Felt", cursive; 27 | font-size: 25pt; 28 | padding-top: 1.0em; 29 | padding-bottom: 0.7em; 30 | height: 16px; 31 | } 32 | button { 33 | font-size: 12pt; 34 | margin-top: 20px; 35 | display: block; 36 | } 37 | input[type="text"] { 38 | font-size: 12pt; 39 | margin-top: 10pt; 40 | margin-bottom: 10pt; 41 | width: 12em; 42 | display: block; 43 | } 44 | @media all and (max-width: 500px) { 45 | .badge { 46 | margin-left: 0; 47 | } 48 | } -------------------------------------------------------------------------------- /ng2/2-blankbadge/lib/src/badge_component.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017, the Dart project authors. 2 | // All rights reserved. Use of this source code 3 | // is governed by a BSD-style license that can be 4 | // found in the LICENSE file. 5 | 6 | import 'package:angular2/angular2.dart'; 7 | 8 | @Component( 9 | selector: 'pirate-badge', 10 | templateUrl: 'badge_component.html', 11 | styleUrls: const ['badge_component.css'], 12 | ) 13 | class BadgeComponent { 14 | String badgeName = 'Sundar'; 15 | } 16 | -------------------------------------------------------------------------------- /ng2/2-blankbadge/lib/src/badge_component.html: -------------------------------------------------------------------------------- 1 | 7 | 8 |
9 |
Arrr! Me name is
10 |
{{badgeName}}
11 |
12 | -------------------------------------------------------------------------------- /ng2/2-blankbadge/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: pirate_badge 2 | description: A simple AngularDart app 3 | version: 0.0.1 4 | environment: 5 | sdk: '>=1.24.0 <2.0.0' 6 | dependencies: 7 | angular2: ^3.0.0 8 | dev_dependencies: 9 | browser: ^0.10.0 10 | dart_to_js_script_rewriter: ^1.0.1 11 | transformers: 12 | - angular2: 13 | entry_points: web/main.dart 14 | - dart_to_js_script_rewriter 15 | web: 16 | compiler: 17 | debug: dartdevc 18 | -------------------------------------------------------------------------------- /ng2/2-blankbadge/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 11 | 12 | Avast, Ye Pirates 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | Loading... 22 | 23 | 24 | -------------------------------------------------------------------------------- /ng2/2-blankbadge/web/main.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017, the Dart project authors. 2 | // All rights reserved. Use of this source code 3 | // is governed by a BSD-style license that can be 4 | // found in the LICENSE file. 5 | 6 | import 'package:angular2/platform/browser.dart'; 7 | 8 | import 'package:pirate_badge/app_component.dart'; 9 | 10 | void main() { 11 | bootstrap(AppComponent); 12 | } 13 | -------------------------------------------------------------------------------- /ng2/2-blankbadge/web/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #F8F8F8; 3 | font-family: 'Open Sans', sans-serif; 4 | font-size: 14px; 5 | font-weight: normal; 6 | line-height: 1.2em; 7 | margin: 15px; 8 | } 9 | -------------------------------------------------------------------------------- /ng2/3-inputnamebadge/.gitignore: -------------------------------------------------------------------------------- 1 | # Files and directories created by pub 2 | .packages 3 | .pub/ 4 | build/ 5 | # Remove the following pattern if you wish to check in your lock file 6 | pubspec.lock 7 | 8 | # Directory created by dartdoc 9 | doc/api/ 10 | -------------------------------------------------------------------------------- /ng2/3-inputnamebadge/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 ng2-dart-samples 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 | 23 | -------------------------------------------------------------------------------- /ng2/3-inputnamebadge/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | analyzer: 2 | strong-mode: true 3 | # exclude: 4 | # - path/to/excluded/files/** 5 | 6 | # Lint rules and documentation, see http://dart-lang.github.io/linter/lints 7 | linter: 8 | rules: 9 | - cancel_subscriptions 10 | - close_sinks 11 | - hash_and_equals 12 | - iterable_contains_unrelated_type 13 | - list_remove_unrelated_type 14 | - test_types_in_equals 15 | - unrelated_type_equality_checks 16 | - valid_regexps 17 | -------------------------------------------------------------------------------- /ng2/3-inputnamebadge/lib/app_component.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017, the Dart project authors. 2 | // All rights reserved. Use of this source code 3 | // is governed by a BSD-style license that can be 4 | // found in the LICENSE file. 5 | 6 | import 'package:angular2/angular2.dart'; 7 | 8 | import 'src/badge_component.dart'; 9 | 10 | @Component( 11 | selector: 'my-app', 12 | templateUrl: 'app_component.html', 13 | directives: const [BadgeComponent], 14 | ) 15 | class AppComponent { 16 | var name = 'Angular'; 17 | } 18 | -------------------------------------------------------------------------------- /ng2/3-inputnamebadge/lib/app_component.html: -------------------------------------------------------------------------------- 1 | 7 | 8 |

Avast, Ye Pirates

9 | 10 | -------------------------------------------------------------------------------- /ng2/3-inputnamebadge/lib/src/badge_component.css: -------------------------------------------------------------------------------- 1 | .widgets { 2 | padding-bottom: 20pt; 3 | float: left; 4 | } 5 | .badge { 6 | border: 2px solid brown; 7 | border-radius: 1em; 8 | background: red; 9 | font-size: 14pt; 10 | width: 14em; 11 | height: 7em; 12 | text-align: center; 13 | float: left; 14 | margin-left: 20px; 15 | white-space: nowrap; 16 | overflow: hidden; 17 | } 18 | .greeting { 19 | color: white; 20 | font-family: sans-serif; 21 | padding: 0.5em; 22 | } 23 | .name { 24 | color: black; 25 | background: white; 26 | font-family: "Marker Felt", cursive; 27 | font-size: 25pt; 28 | padding-top: 1.0em; 29 | padding-bottom: 0.7em; 30 | height: 16px; 31 | } 32 | button { 33 | font-size: 12pt; 34 | margin-top: 20px; 35 | display: block; 36 | } 37 | input[type="text"] { 38 | font-size: 12pt; 39 | margin-top: 10pt; 40 | margin-bottom: 10pt; 41 | width: 12em; 42 | display: block; 43 | } 44 | @media all and (max-width: 500px) { 45 | .badge { 46 | margin-left: 0; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /ng2/3-inputnamebadge/lib/src/badge_component.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017, the Dart project authors. 2 | // All rights reserved. Use of this source code 3 | // is governed by a BSD-style license that can be 4 | // found in the LICENSE file. 5 | 6 | import 'package:angular2/angular2.dart'; 7 | 8 | @Component( 9 | selector: 'pirate-badge', 10 | templateUrl: 'badge_component.html', 11 | styleUrls: const ['badge_component.css'], 12 | ) 13 | class BadgeComponent { 14 | String badgeName = ''; 15 | 16 | void updateBadge(String inputName) { 17 | badgeName = inputName; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ng2/3-inputnamebadge/lib/src/badge_component.html: -------------------------------------------------------------------------------- 1 | 7 | 8 |
9 | 11 |
12 | 13 |
14 |
Arrr! Me name is
15 |
{{badgeName}}
16 |
17 | -------------------------------------------------------------------------------- /ng2/3-inputnamebadge/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: pirate_badge 2 | description: A simple AngularDart app 3 | version: 0.0.1 4 | environment: 5 | sdk: '>=1.24.0 <2.0.0' 6 | dependencies: 7 | angular2: ^3.0.0 8 | dev_dependencies: 9 | browser: ^0.10.0 10 | dart_to_js_script_rewriter: ^1.0.1 11 | transformers: 12 | - angular2: 13 | entry_points: web/main.dart 14 | - dart_to_js_script_rewriter 15 | web: 16 | compiler: 17 | debug: dartdevc 18 | -------------------------------------------------------------------------------- /ng2/3-inputnamebadge/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 11 | 12 | Avast, Ye Pirates 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | Loading... 22 | 23 | 24 | -------------------------------------------------------------------------------- /ng2/3-inputnamebadge/web/main.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017, the Dart project authors. 2 | // All rights reserved. Use of this source code 3 | // is governed by a BSD-style license that can be 4 | // found in the LICENSE file. 5 | 6 | import 'package:angular2/platform/browser.dart'; 7 | 8 | import 'package:pirate_badge/app_component.dart'; 9 | 10 | void main() { 11 | bootstrap(AppComponent); 12 | } 13 | -------------------------------------------------------------------------------- /ng2/3-inputnamebadge/web/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #F8F8F8; 3 | font-family: 'Open Sans', sans-serif; 4 | font-size: 14px; 5 | font-weight: normal; 6 | line-height: 1.2em; 7 | margin: 15px; 8 | } 9 | -------------------------------------------------------------------------------- /ng2/4-buttonbadge/.gitignore: -------------------------------------------------------------------------------- 1 | # Files and directories created by pub 2 | .packages 3 | .pub/ 4 | build/ 5 | # Remove the following pattern if you wish to check in your lock file 6 | pubspec.lock 7 | 8 | # Directory created by dartdoc 9 | doc/api/ 10 | -------------------------------------------------------------------------------- /ng2/4-buttonbadge/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 ng2-dart-samples 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 | 23 | -------------------------------------------------------------------------------- /ng2/4-buttonbadge/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | analyzer: 2 | strong-mode: true 3 | # exclude: 4 | # - path/to/excluded/files/** 5 | 6 | # Lint rules and documentation, see http://dart-lang.github.io/linter/lints 7 | linter: 8 | rules: 9 | - cancel_subscriptions 10 | - close_sinks 11 | - hash_and_equals 12 | - iterable_contains_unrelated_type 13 | - list_remove_unrelated_type 14 | - test_types_in_equals 15 | - unrelated_type_equality_checks 16 | - valid_regexps 17 | -------------------------------------------------------------------------------- /ng2/4-buttonbadge/lib/app_component.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017, the Dart project authors. 2 | // All rights reserved. Use of this source code 3 | // is governed by a BSD-style license that can be 4 | // found in the LICENSE file. 5 | 6 | import 'package:angular2/angular2.dart'; 7 | 8 | import 'src/badge_component.dart'; 9 | 10 | @Component( 11 | selector: 'my-app', 12 | templateUrl: 'app_component.html', 13 | directives: const [BadgeComponent], 14 | ) 15 | class AppComponent { 16 | var name = 'Angular'; 17 | } 18 | -------------------------------------------------------------------------------- /ng2/4-buttonbadge/lib/app_component.html: -------------------------------------------------------------------------------- 1 | 7 | 8 |

Avast, Ye Pirates

9 | 10 | -------------------------------------------------------------------------------- /ng2/4-buttonbadge/lib/src/badge_component.css: -------------------------------------------------------------------------------- 1 | .widgets { 2 | padding-bottom: 20pt; 3 | float: left; 4 | } 5 | .badge { 6 | border: 2px solid brown; 7 | border-radius: 1em; 8 | background: red; 9 | font-size: 14pt; 10 | width: 14em; 11 | height: 7em; 12 | text-align: center; 13 | float: left; 14 | margin-left: 20px; 15 | white-space: nowrap; 16 | overflow: hidden; 17 | } 18 | .greeting { 19 | color: white; 20 | font-family: sans-serif; 21 | padding: 0.5em; 22 | } 23 | .name { 24 | color: black; 25 | background: white; 26 | font-family: "Marker Felt", cursive; 27 | font-size: 25pt; 28 | padding-top: 1.0em; 29 | padding-bottom: 0.7em; 30 | height: 16px; 31 | } 32 | button { 33 | font-size: 12pt; 34 | margin-top: 20px; 35 | display: block; 36 | } 37 | input[type="text"] { 38 | font-size: 12pt; 39 | margin-top: 10pt; 40 | margin-bottom: 10pt; 41 | width: 12em; 42 | display: block; 43 | } 44 | @media all and (max-width: 500px) { 45 | .badge { 46 | margin-left: 0; 47 | } 48 | } -------------------------------------------------------------------------------- /ng2/4-buttonbadge/lib/src/badge_component.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017, the Dart project authors. 2 | // All rights reserved. Use of this source code 3 | // is governed by a BSD-style license that can be 4 | // found in the LICENSE file. 5 | 6 | import 'package:angular2/angular2.dart'; 7 | 8 | @Component( 9 | selector: 'pirate-badge', 10 | templateUrl: 'badge_component.html', 11 | styleUrls: const ['badge_component.css'], 12 | ) 13 | class BadgeComponent { 14 | String badgeName = ''; 15 | String buttonText = 'Aye! Gimme a name!'; 16 | bool isButtonEnabled = true; 17 | 18 | void generateBadge() { 19 | badgeName = 'Anne Bonney'; 20 | } 21 | 22 | void updateBadge(String inputName) { 23 | badgeName = inputName; 24 | if (inputName.trim().isEmpty) { 25 | buttonText = 'Aye! Gimme a name!'; 26 | isButtonEnabled = true; 27 | } else { 28 | buttonText = 'Arrr! Write yer name!'; 29 | isButtonEnabled = false; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ng2/4-buttonbadge/lib/src/badge_component.html: -------------------------------------------------------------------------------- 1 | 7 | 8 |
9 | 11 | 14 |
15 | 16 |
17 |
Arrr! Me name is
18 |
{{badgeName}}
19 |
20 | -------------------------------------------------------------------------------- /ng2/4-buttonbadge/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: pirate_badge 2 | description: A simple AngularDart app 3 | version: 0.0.1 4 | environment: 5 | sdk: '>=1.24.0 <2.0.0' 6 | dependencies: 7 | angular2: ^3.0.0 8 | dev_dependencies: 9 | browser: ^0.10.0 10 | dart_to_js_script_rewriter: ^1.0.1 11 | transformers: 12 | - angular2: 13 | entry_points: web/main.dart 14 | - dart_to_js_script_rewriter 15 | web: 16 | compiler: 17 | debug: dartdevc 18 | -------------------------------------------------------------------------------- /ng2/4-buttonbadge/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 11 | 12 | Avast, Ye Pirates 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | Loading... 22 | 23 | 24 | -------------------------------------------------------------------------------- /ng2/4-buttonbadge/web/main.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017, the Dart project authors. 2 | // All rights reserved. Use of this source code 3 | // is governed by a BSD-style license that can be 4 | // found in the LICENSE file. 5 | 6 | import 'package:angular2/platform/browser.dart'; 7 | 8 | import 'package:pirate_badge/app_component.dart'; 9 | 10 | void main() { 11 | bootstrap(AppComponent); 12 | } 13 | -------------------------------------------------------------------------------- /ng2/4-buttonbadge/web/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #F8F8F8; 3 | font-family: 'Open Sans', sans-serif; 4 | font-size: 14px; 5 | font-weight: normal; 6 | line-height: 1.2em; 7 | margin: 15px; 8 | } 9 | -------------------------------------------------------------------------------- /ng2/5-piratenameservice/.gitignore: -------------------------------------------------------------------------------- 1 | # Files and directories created by pub 2 | .packages 3 | .pub/ 4 | build/ 5 | # Remove the following pattern if you wish to check in your lock file 6 | pubspec.lock 7 | 8 | # Directory created by dartdoc 9 | doc/api/ 10 | -------------------------------------------------------------------------------- /ng2/5-piratenameservice/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 ng2-dart-samples 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 | 23 | -------------------------------------------------------------------------------- /ng2/5-piratenameservice/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | analyzer: 2 | strong-mode: true 3 | # exclude: 4 | # - path/to/excluded/files/** 5 | 6 | # Lint rules and documentation, see http://dart-lang.github.io/linter/lints 7 | linter: 8 | rules: 9 | - cancel_subscriptions 10 | - close_sinks 11 | - hash_and_equals 12 | - iterable_contains_unrelated_type 13 | - list_remove_unrelated_type 14 | - test_types_in_equals 15 | - unrelated_type_equality_checks 16 | - valid_regexps 17 | -------------------------------------------------------------------------------- /ng2/5-piratenameservice/lib/app_component.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017, the Dart project authors. 2 | // All rights reserved. Use of this source code 3 | // is governed by a BSD-style license that can be 4 | // found in the LICENSE file. 5 | 6 | import 'package:angular2/angular2.dart'; 7 | 8 | import 'src/badge_component.dart'; 9 | 10 | @Component( 11 | selector: 'my-app', 12 | templateUrl: 'app_component.html', 13 | directives: const [BadgeComponent], 14 | ) 15 | class AppComponent { 16 | var name = 'Angular'; 17 | } 18 | -------------------------------------------------------------------------------- /ng2/5-piratenameservice/lib/app_component.html: -------------------------------------------------------------------------------- 1 | 7 | 8 |

Avast, Ye Pirates

9 | 10 | -------------------------------------------------------------------------------- /ng2/5-piratenameservice/lib/src/badge_component.css: -------------------------------------------------------------------------------- 1 | .widgets { 2 | padding-bottom: 20pt; 3 | float: left; 4 | } 5 | .badge { 6 | border: 2px solid brown; 7 | border-radius: 1em; 8 | background: red; 9 | font-size: 14pt; 10 | width: 14em; 11 | height: 7em; 12 | text-align: center; 13 | float: left; 14 | margin-left: 20px; 15 | white-space: nowrap; 16 | overflow: hidden; 17 | } 18 | .greeting { 19 | color: white; 20 | font-family: sans-serif; 21 | padding: 0.5em; 22 | } 23 | .name { 24 | color: black; 25 | background: white; 26 | font-family: "Marker Felt", cursive; 27 | font-size: 25pt; 28 | padding-top: 1.0em; 29 | padding-bottom: 0.7em; 30 | height: 16px; 31 | } 32 | button { 33 | font-size: 12pt; 34 | margin-top: 20px; 35 | display: block; 36 | } 37 | input[type="text"] { 38 | font-size: 12pt; 39 | margin-top: 10pt; 40 | margin-bottom: 10pt; 41 | width: 12em; 42 | display: block; 43 | } 44 | @media all and (max-width: 500px) { 45 | .badge { 46 | margin-left: 0; 47 | } 48 | } -------------------------------------------------------------------------------- /ng2/5-piratenameservice/lib/src/badge_component.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017, the Dart project authors. 2 | // All rights reserved. Use of this source code 3 | // is governed by a BSD-style license that can be 4 | // found in the LICENSE file. 5 | 6 | import 'package:angular2/angular2.dart'; 7 | 8 | import 'name_service.dart'; 9 | 10 | @Component( 11 | selector: 'pirate-badge', 12 | templateUrl: 'badge_component.html', 13 | styleUrls: const ['badge_component.css'], 14 | providers: const [NameService], 15 | ) 16 | class BadgeComponent { 17 | final NameService _nameService; 18 | String badgeName = ''; 19 | String buttonText = 'Aye! Gimme a name!'; 20 | bool isButtonEnabled = true; 21 | 22 | BadgeComponent(this._nameService); 23 | 24 | void generateBadge() { 25 | setBadgeName(); 26 | } 27 | 28 | void updateBadge(String inputName) { 29 | setBadgeName(inputName); 30 | if (inputName.trim().isEmpty) { 31 | buttonText = 'Aye! Gimme a name!'; 32 | isButtonEnabled = true; 33 | } else { 34 | buttonText = 'Arrr! Write yer name!'; 35 | isButtonEnabled = false; 36 | } 37 | } 38 | 39 | void setBadgeName([String newName = '']) { 40 | if (newName == null) return; 41 | badgeName = _nameService.getPirateName(newName); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /ng2/5-piratenameservice/lib/src/badge_component.html: -------------------------------------------------------------------------------- 1 | 7 | 8 |
9 | 10 | 13 |
14 |
15 |
Arrr! Me name is
16 |
{{badgeName}}
17 |
18 | -------------------------------------------------------------------------------- /ng2/5-piratenameservice/lib/src/name_service.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017, the Dart project authors. 2 | // All rights reserved. Use of this source code 3 | // is governed by a BSD-style license that can be 4 | // found in the LICENSE file. 5 | 6 | import 'dart:math' show Random; 7 | 8 | import 'package:angular2/angular2.dart'; 9 | 10 | @Injectable() 11 | class NameService { 12 | static final Random _indexGen = new Random(); 13 | 14 | final _names = [ 15 | 'Anne', 'Mary', 'Jack', 'Morgan', 'Roger', // 16 | 'Bill', 'Ragnar', 'Ed', 'John', 'Jane' 17 | ]; 18 | final _appellations = [ 19 | 'Jackal', 'King', 'Red', 'Stalwart', 'Axe', // 20 | 'Young', 'Brave', 'Eager', 'Wily', 'Zesty' 21 | ]; 22 | 23 | String _randomFirstName() => _names[_indexGen.nextInt(_names.length)]; 24 | 25 | String _randomAppellation() => 26 | _appellations[_indexGen.nextInt(_appellations.length)]; 27 | 28 | String getPirateName(String firstName) { 29 | if (firstName == null || firstName.trim().isEmpty) { 30 | firstName = _randomFirstName(); 31 | } 32 | 33 | return '$firstName the ${_randomAppellation()}'; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /ng2/5-piratenameservice/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: pirate_badge 2 | description: A simple AngularDart app 3 | version: 0.0.1 4 | environment: 5 | sdk: '>=1.24.0 <2.0.0' 6 | dependencies: 7 | angular2: ^3.0.0 8 | dev_dependencies: 9 | browser: ^0.10.0 10 | dart_to_js_script_rewriter: ^1.0.1 11 | transformers: 12 | - angular2: 13 | entry_points: web/main.dart 14 | - dart_to_js_script_rewriter 15 | web: 16 | compiler: 17 | debug: dartdevc 18 | -------------------------------------------------------------------------------- /ng2/5-piratenameservice/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 11 | 12 | Avast, Ye Pirates 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | Loading... 22 | 23 | 24 | -------------------------------------------------------------------------------- /ng2/5-piratenameservice/web/main.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017, the Dart project authors. 2 | // All rights reserved. Use of this source code 3 | // is governed by a BSD-style license that can be 4 | // found in the LICENSE file. 5 | 6 | import 'package:angular2/platform/browser.dart'; 7 | 8 | import 'package:pirate_badge/app_component.dart'; 9 | 10 | void main() { 11 | bootstrap(AppComponent); 12 | } 13 | -------------------------------------------------------------------------------- /ng2/5-piratenameservice/web/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #F8F8F8; 3 | font-family: 'Open Sans', sans-serif; 4 | font-size: 14px; 5 | font-weight: normal; 6 | line-height: 1.2em; 7 | margin: 15px; 8 | } 9 | -------------------------------------------------------------------------------- /ng2/6-readjsonfile/.gitignore: -------------------------------------------------------------------------------- 1 | # Files and directories created by pub 2 | .packages 3 | .pub/ 4 | build/ 5 | # Remove the following pattern if you wish to check in your lock file 6 | pubspec.lock 7 | 8 | # Directory created by dartdoc 9 | doc/api/ 10 | -------------------------------------------------------------------------------- /ng2/6-readjsonfile/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 ng2-dart-samples 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 | 23 | -------------------------------------------------------------------------------- /ng2/6-readjsonfile/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | analyzer: 2 | strong-mode: true 3 | # exclude: 4 | # - path/to/excluded/files/** 5 | 6 | # Lint rules and documentation, see http://dart-lang.github.io/linter/lints 7 | linter: 8 | rules: 9 | - cancel_subscriptions 10 | - close_sinks 11 | - hash_and_equals 12 | - iterable_contains_unrelated_type 13 | - list_remove_unrelated_type 14 | - test_types_in_equals 15 | - unrelated_type_equality_checks 16 | - valid_regexps 17 | -------------------------------------------------------------------------------- /ng2/6-readjsonfile/lib/app_component.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017, the Dart project authors. 2 | // All rights reserved. Use of this source code 3 | // is governed by a BSD-style license that can be 4 | // found in the LICENSE file. 5 | 6 | import 'package:angular2/angular2.dart'; 7 | 8 | import 'src/badge_component.dart'; 9 | 10 | @Component( 11 | selector: 'my-app', 12 | templateUrl: 'app_component.html', 13 | directives: const [BadgeComponent], 14 | ) 15 | class AppComponent { 16 | var name = 'Angular'; 17 | } 18 | -------------------------------------------------------------------------------- /ng2/6-readjsonfile/lib/app_component.html: -------------------------------------------------------------------------------- 1 | 7 | 8 |

Avast, Ye Pirates

9 | 10 | -------------------------------------------------------------------------------- /ng2/6-readjsonfile/lib/src/badge_component.css: -------------------------------------------------------------------------------- 1 | .widgets { 2 | padding-bottom: 20pt; 3 | float: left; 4 | } 5 | .badge { 6 | border: 2px solid brown; 7 | border-radius: 1em; 8 | background: red; 9 | font-size: 14pt; 10 | width: 14em; 11 | height: 7em; 12 | text-align: center; 13 | float: left; 14 | margin-left: 20px; 15 | white-space: nowrap; 16 | overflow: hidden; 17 | } 18 | .greeting { 19 | color: white; 20 | font-family: sans-serif; 21 | padding: 0.5em; 22 | } 23 | .name { 24 | color: black; 25 | background: white; 26 | font-family: "Marker Felt", cursive; 27 | font-size: 25pt; 28 | padding-top: 1.0em; 29 | padding-bottom: 0.7em; 30 | height: 16px; 31 | } 32 | button { 33 | font-size: 12pt; 34 | margin-top: 20px; 35 | display: block; 36 | } 37 | input[type="text"] { 38 | font-size: 12pt; 39 | margin-top: 10pt; 40 | margin-bottom: 10pt; 41 | width: 12em; 42 | display: block; 43 | } 44 | @media all and (max-width: 500px) { 45 | .badge { 46 | margin-left: 0; 47 | } 48 | } -------------------------------------------------------------------------------- /ng2/6-readjsonfile/lib/src/badge_component.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017, the Dart project authors. 2 | // All rights reserved. Use of this source code 3 | // is governed by a BSD-style license that can be 4 | // found in the LICENSE file. 5 | 6 | import 'dart:async'; 7 | 8 | import 'package:angular2/angular2.dart'; 9 | 10 | import 'name_service.dart'; 11 | 12 | @Component( 13 | selector: 'pirate-badge', 14 | templateUrl: 'badge_component.html', 15 | styleUrls: const ['badge_component.css'], 16 | providers: const [NameService], 17 | ) 18 | class BadgeComponent implements OnInit { 19 | final NameService _nameService; 20 | String badgeName = ''; 21 | String buttonText = 'Aye! Gimme a name!'; 22 | bool isButtonEnabled = false; 23 | bool isInputEnabled = false; 24 | 25 | BadgeComponent(this._nameService); 26 | 27 | @override 28 | Future ngOnInit() async { 29 | try { 30 | await _nameService.readyThePirates(); 31 | // on success 32 | isButtonEnabled = true; 33 | isInputEnabled = true; 34 | } catch (arrr) { 35 | badgeName = 'Arrr! No names.'; 36 | print('Error initializing pirate names: $arrr'); 37 | } 38 | } 39 | 40 | void generateBadge() { 41 | setBadgeName(); 42 | } 43 | 44 | void updateBadge(String inputName) { 45 | setBadgeName(inputName); 46 | if (inputName.trim().isEmpty) { 47 | buttonText = 'Aye! Gimme a name!'; 48 | isButtonEnabled = true; 49 | } else { 50 | buttonText = 'Arrr! Write yer name!'; 51 | isButtonEnabled = false; 52 | } 53 | } 54 | 55 | void setBadgeName([String newName = '']) { 56 | if (newName == null) return; 57 | badgeName = _nameService.getPirateName(newName); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /ng2/6-readjsonfile/lib/src/badge_component.html: -------------------------------------------------------------------------------- 1 | 7 | 8 |
9 | 11 | 14 |
15 |
16 |
Arrr! Me name is
17 |
{{badgeName}}
18 |
19 | -------------------------------------------------------------------------------- /ng2/6-readjsonfile/lib/src/name_service.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017, the Dart project authors. 2 | // All rights reserved. Use of this source code 3 | // is governed by a BSD-style license that can be 4 | // found in the LICENSE file. 5 | 6 | import 'dart:async'; 7 | import 'dart:convert'; 8 | import 'dart:html'; 9 | import 'dart:math' show Random; 10 | 11 | import 'package:angular2/angular2.dart'; 12 | 13 | const _namesPath = 'https://www.dartlang.org/f/piratenames.json'; 14 | 15 | @Injectable() 16 | class NameService { 17 | static final Random _indexGen = new Random(); 18 | 19 | final _names = []; 20 | final _appellations = []; 21 | 22 | String _randomFirstName() => _names[_indexGen.nextInt(_names.length)]; 23 | 24 | String _randomAppellation() => 25 | _appellations[_indexGen.nextInt(_appellations.length)]; 26 | 27 | Future readyThePirates() async { 28 | if (_names.isNotEmpty && _appellations.isNotEmpty) return; 29 | 30 | var jsonString = await HttpRequest.getString(_namesPath); 31 | var pirateNames = JSON.decode(jsonString); 32 | _names.addAll(pirateNames['names']); 33 | _appellations.addAll(pirateNames['appellations']); 34 | } 35 | 36 | String getPirateName(String firstName) { 37 | if (firstName == null || firstName.trim().isEmpty) { 38 | firstName = _randomFirstName(); 39 | } 40 | 41 | return '$firstName the ${_randomAppellation()}'; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /ng2/6-readjsonfile/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: pirate_badge 2 | description: A simple AngularDart app 3 | version: 0.0.1 4 | environment: 5 | sdk: '>=1.24.0 <2.0.0' 6 | dependencies: 7 | angular2: ^3.0.0 8 | dev_dependencies: 9 | browser: ^0.10.0 10 | dart_to_js_script_rewriter: ^1.0.1 11 | transformers: 12 | - angular2: 13 | entry_points: web/main.dart 14 | - dart_to_js_script_rewriter 15 | web: 16 | compiler: 17 | debug: dartdevc 18 | -------------------------------------------------------------------------------- /ng2/6-readjsonfile/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 11 | 12 | Avast, Ye Pirates 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | Loading... 22 | 23 | 24 | -------------------------------------------------------------------------------- /ng2/6-readjsonfile/web/main.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017, the Dart project authors. 2 | // All rights reserved. Use of this source code 3 | // is governed by a BSD-style license that can be 4 | // found in the LICENSE file. 5 | 6 | import 'package:angular2/platform/browser.dart'; 7 | 8 | import 'package:pirate_badge/app_component.dart'; 9 | 10 | void main() { 11 | bootstrap(AppComponent); 12 | } 13 | -------------------------------------------------------------------------------- /ng2/6-readjsonfile/web/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #F8F8F8; 3 | font-family: 'Open Sans', sans-serif; 4 | font-size: 14px; 5 | font-weight: normal; 6 | line-height: 1.2em; 7 | margin: 15px; 8 | } 9 | -------------------------------------------------------------------------------- /runtests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | shopt -s nullglob 4 | 5 | EXITSTATUS=0 6 | PASSING=0 7 | WARNINGS=0 8 | FAILURES=0 9 | 10 | ##### 11 | # Type Analysis 12 | 13 | #ANA="dart_analyzer --fatal-type-errors --extended-exit-code --type-checks-for-inferred-types" 14 | # use new experimental analyzer 15 | ANA="dartanalyzer --fatal-type-errors" 16 | 17 | echo 18 | echo "Type Analysis, running dart_analyzer..." 19 | 20 | pub_result=`pub install` 21 | cmd="$ANA --package-root packages" 22 | 23 | for dir in web/* 24 | do 25 | echo $dir 26 | # Run pub if there is a pubspec in this code directory. 27 | # if [ -a "$dir/pubspec.yaml" ]; then 28 | # pub_result=`pushd $dir && pub install && popd` 29 | # cmd="$ANA --package-root $dir/packages" 30 | # else 31 | # cmd="$ANA" 32 | # fi 33 | 34 | # Loop through each Dart file in this code directory. 35 | files="$dir/*.dart" 36 | for file in $files 37 | do 38 | results=`$cmd $file 2>&1` 39 | exit_code=$? 40 | if [ $exit_code -eq 2 ]; then 41 | let FAILURES++ 42 | EXITSTATUS=1 43 | echo "$results" 44 | echo "$file: FAILURE." 45 | elif [ $exit_code -eq 1 ]; then 46 | let WARNINGS++ 47 | echo "$results" 48 | echo "$file: WARNING." 49 | elif [ $exit_code -eq 0 ]; then 50 | let PASSING++ 51 | echo "$results" 52 | echo "$file: Passed analysis." 53 | else 54 | echo "$file: Unknown exit code: $exit_code." 55 | fi 56 | # Remove the output directory so that subsequent test runs will still see 57 | # the warnings and errors. 58 | rm -rf out/ 59 | done 60 | done 61 | 62 | echo 63 | echo "####################################################" 64 | echo "PASSING = $PASSING" 65 | echo "WARNINGS = $WARNINGS" 66 | echo "FAILURES = $FAILURES" 67 | echo "####################################################" 68 | echo 69 | exit $EXITSTATUS 70 | -------------------------------------------------------------------------------- /server/1-starter/bin/piratesnest.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | library piratesnest; 6 | 7 | import 'dart:async'; 8 | import 'dart:io'; 9 | 10 | import 'package:logging/logging.dart'; 11 | import 'package:rpc/rpc.dart'; 12 | 13 | import 'package:server_code_lab/server/piratesapi.dart'; 14 | 15 | final ApiServer _apiServer = new ApiServer(prettyPrint: true); 16 | 17 | Future main() async { 18 | // Add a bit of logging... 19 | Logger.root..level = Level.INFO 20 | ..onRecord.listen(print); 21 | 22 | // Set up a server serving the pirate API. 23 | _apiServer.addApi(new PiratesApi()); 24 | HttpServer server = 25 | await HttpServer.bind(InternetAddress.ANY_IP_V4, 8088); 26 | server.listen((request) => _apiServer.httpRequestHandler(request)); 27 | print('Server listening on http://${server.address.host}:' 28 | '${server.port}'); 29 | } 30 | -------------------------------------------------------------------------------- /server/1-starter/lib/common/messages.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | library pirate.messages; 6 | 7 | // This class is used to send data back and forth between the 8 | // client and server. It is automatically serialized and 9 | // deserialized by the RPC package. 10 | class Pirate { 11 | String name; 12 | String appellation; 13 | 14 | // A message class must have a default constructor taking no 15 | // arguments. 16 | Pirate(); 17 | 18 | // It is fine to have other named constructors. 19 | Pirate.fromString(String pirateName) { 20 | var parts = pirateName.split(' the '); 21 | name = parts[0]; 22 | appellation = parts[1]; 23 | } 24 | 25 | @override 26 | String toString() => name.isEmpty ? '' : '$name the $appellation'; 27 | } 28 | -------------------------------------------------------------------------------- /server/1-starter/lib/common/utils.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | library pirate.utils; 6 | 7 | import 'dart:math' show Random; 8 | 9 | import 'messages.dart'; 10 | 11 | // Proper pirate names. 12 | const List pirateNames = const [ 13 | "Anne", "Bette", "Cate", "Dawn", "Elise", "Faye", "Ginger", 14 | "Harriot", "Izzy", "Jane", "Kaye", "Liz", "Maria", "Nell", 15 | "Olive", "Pat", "Queenie", "Rae", "Sal", "Tam", "Uma", 16 | "Violet", "Wilma", "Xana", "Yvonne", "Zelda", "Abe", 17 | "Billy", "Caleb", "Davie", "Eb", "Frank", "Gabe", "House", 18 | "Icarus", "Jack", "Kurt", "Larry", "Mike", "Nolan", 19 | "Oliver", "Pat", "Quib", "Roy", "Sal", "Tom", "Ube", 20 | "Val", "Walt", "Xavier", "Yvan", "Zeb" 21 | ]; 22 | 23 | // Proper pirate appellations. 24 | const List pirateAppellations = const [ 25 | "Awesome", "Captain", "Even", "Fighter", "Great", 26 | "Hearty", "Jackal", "King", "Lord", "Mighty", 27 | "Noble", "Old", "Powerful", "Quick", "Red", 28 | "Stalwart", "Tank", "Ultimate", "Vicious", 29 | "Wily", "aXe", "Young", "Brave", "Eager", 30 | "Kind", "Sandy", "Xeric", "Yellow", "Zesty" 31 | ]; 32 | 33 | // Clearly invalid pirate appellations. 34 | const List _forbiddenAppellations = const [ 35 | '', 'sweet', 'handsome', 'beautiful', 'weak', 'wuss', 36 | 'chicken', 'fearful' 37 | ]; 38 | 39 | // Helper method for validating whether the given pirate is truly a pirate! 40 | bool truePirate(Pirate pirate) => pirate.name != null && 41 | pirate.name.trim().isNotEmpty && 42 | pirate.appellation != null && 43 | !_forbiddenAppellations 44 | .contains(pirate.appellation.toLowerCase()); 45 | 46 | // Shared class for shanghaiing (generating) pirates. 47 | class PirateShanghaier { 48 | static final Random indexGen = new Random(); 49 | 50 | Pirate shanghaiAPirate({String name, String appellation}) { 51 | var pirate = new Pirate(); 52 | pirate.name = name != null 53 | ? name 54 | : pirateNames[indexGen.nextInt(pirateNames.length)]; 55 | pirate.appellation = appellation != null 56 | ? appellation 57 | : pirateAppellations[ 58 | indexGen.nextInt(pirateAppellations.length)]; 59 | return truePirate(pirate) ? pirate : null; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /server/1-starter/lib/server/piratesapi.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | library pirate.server; 6 | 7 | import 'package:rpc/rpc.dart'; 8 | 9 | import '../common/messages.dart'; 10 | import '../common/utils.dart'; 11 | 12 | // This class defines the interface that the server provides. 13 | class PiratesApi { 14 | final Map _pirateCrew = {}; 15 | final PirateShanghaier _shanghaier = new PirateShanghaier(); 16 | 17 | PiratesApi() { 18 | var captain = new Pirate.fromString('Lars the Captain'); 19 | _pirateCrew[captain.toString()] = captain; 20 | } 21 | 22 | // Returns a list of the pirate crew. 23 | List listPirates() { 24 | return _pirateCrew.values.toList(); 25 | } 26 | 27 | // Generates (shanghais) and returns a new pirate. 28 | // Does not add the new pirate to the crew. 29 | Pirate shanghaiAPirate() { 30 | var pirate = _shanghaier.shanghaiAPirate(); 31 | if (pirate == null) { 32 | throw new InternalServerError('Ran out of pirates!'); 33 | } 34 | return pirate; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /server/1-starter/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: server_code_lab 2 | version: 0.1.0 3 | author: Dart Team 4 | description: Code-lab server sample. 5 | environment: 6 | sdk: '>=1.9.0 <2.0.0' 7 | dependencies: 8 | _discoveryapis_commons: ^0.1.0 9 | browser: ^0.10.0+2 10 | crypto: ^0.9.0 11 | http: ^0.11.1 12 | logging_handlers: ^0.8.0 13 | rpc: ^0.5.0 14 | 15 | homepage: https://dart-lang.github.io/server/codelab/ 16 | -------------------------------------------------------------------------------- /server/2-simple/bin/piratesnest.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | library piratesnest; 6 | 7 | import 'dart:async'; 8 | import 'dart:io'; 9 | 10 | import 'package:logging/logging.dart'; 11 | import 'package:rpc/rpc.dart'; 12 | 13 | import 'package:server_code_lab/server/piratesapi.dart'; 14 | 15 | final ApiServer _apiServer = new ApiServer(prettyPrint: true); 16 | 17 | Future main() async { 18 | // Add a bit of logging... 19 | Logger.root..level = Level.INFO 20 | ..onRecord.listen(print); 21 | 22 | // Set up a server serving the pirate API. 23 | _apiServer.addApi(new PiratesApi()); 24 | HttpServer server = 25 | await HttpServer.bind(InternetAddress.ANY_IP_V4, 8088); 26 | server.listen((request) => _apiServer.httpRequestHandler(request)); 27 | print('Server listening on http://${server.address.host}:' 28 | '${server.port}'); 29 | } 30 | -------------------------------------------------------------------------------- /server/2-simple/lib/common/messages.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | library pirate.messages; 6 | 7 | // This class is used to send data back and forth between the 8 | // client and server. It is automatically serialized and 9 | // deserialized by the RPC package. 10 | class Pirate { 11 | String name; 12 | String appellation; 13 | 14 | // A message class must have a default constructor taking no 15 | // arguments. 16 | Pirate(); 17 | 18 | // It is fine to have other named constructors. 19 | Pirate.fromString(String pirateName) { 20 | var parts = pirateName.split(' the '); 21 | name = parts[0]; 22 | appellation = parts[1]; 23 | } 24 | 25 | @override 26 | String toString() => name.isEmpty ? '' : '$name the $appellation'; 27 | } 28 | -------------------------------------------------------------------------------- /server/2-simple/lib/common/utils.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | library pirate.utils; 6 | 7 | import 'dart:math' show Random; 8 | 9 | import 'messages.dart'; 10 | 11 | // Proper pirate names. 12 | const List pirateNames = const [ 13 | "Anne", "Bette", "Cate", "Dawn", "Elise", "Faye", "Ginger", 14 | "Harriot", "Izzy", "Jane", "Kaye", "Liz", "Maria", "Nell", 15 | "Olive", "Pat", "Queenie", "Rae", "Sal", "Tam", "Uma", 16 | "Violet", "Wilma", "Xana", "Yvonne", "Zelda", "Abe", 17 | "Billy", "Caleb", "Davie", "Eb", "Frank", "Gabe", "House", 18 | "Icarus", "Jack", "Kurt", "Larry", "Mike", "Nolan", 19 | "Oliver", "Pat", "Quib", "Roy", "Sal", "Tom", "Ube", 20 | "Val", "Walt", "Xavier", "Yvan", "Zeb" 21 | ]; 22 | 23 | // Proper pirate appellations. 24 | const List pirateAppellations = const [ 25 | "Awesome", "Captain", "Even", "Fighter", "Great", 26 | "Hearty", "Jackal", "King", "Lord", "Mighty", 27 | "Noble", "Old", "Powerful", "Quick", "Red", 28 | "Stalwart", "Tank", "Ultimate", "Vicious", 29 | "Wily", "aXe", "Young", "Brave", "Eager", 30 | "Kind", "Sandy", "Xeric", "Yellow", "Zesty" 31 | ]; 32 | 33 | // Clearly invalid pirate appellations. 34 | const List _forbiddenAppellations = const [ 35 | '', 'sweet', 'handsome', 'beautiful', 'weak', 'wuss', 36 | 'chicken', 'fearful' 37 | ]; 38 | 39 | // Helper method for validating whether the given pirate is truly a pirate! 40 | bool truePirate(Pirate pirate) => pirate.name != null && 41 | pirate.name.trim().isNotEmpty && 42 | pirate.appellation != null && 43 | !_forbiddenAppellations 44 | .contains(pirate.appellation.toLowerCase()); 45 | 46 | // Shared class for shanghaiing (generating) pirates. 47 | class PirateShanghaier { 48 | static final Random indexGen = new Random(); 49 | 50 | Pirate shanghaiAPirate({String name, String appellation}) { 51 | var pirate = new Pirate(); 52 | pirate.name = name != null 53 | ? name 54 | : pirateNames[indexGen.nextInt(pirateNames.length)]; 55 | pirate.appellation = appellation != null 56 | ? appellation 57 | : pirateAppellations[ 58 | indexGen.nextInt(pirateAppellations.length)]; 59 | return truePirate(pirate) ? pirate : null; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /server/2-simple/lib/server/piratesapi.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | library pirate.server; 6 | 7 | import 'package:rpc/rpc.dart'; 8 | 9 | import '../common/messages.dart'; 10 | import '../common/utils.dart'; 11 | 12 | // This class defines the interface that the server provides. 13 | @ApiClass(version: 'v1') 14 | class PiratesApi { 15 | final Map _pirateCrew = {}; 16 | final PirateShanghaier _shanghaier = new PirateShanghaier(); 17 | 18 | PiratesApi() { 19 | var captain = new Pirate.fromString('Lars the Captain'); 20 | _pirateCrew[captain.toString()] = captain; 21 | } 22 | 23 | // Returns a list of the pirate crew. 24 | @ApiMethod(path: 'pirates') 25 | List listPirates() { 26 | return _pirateCrew.values.toList(); 27 | } 28 | 29 | // Generates (shanghais) and returns a new pirate. 30 | // Does not add the new pirate to the crew. 31 | @ApiMethod(path: 'shanghai') 32 | Pirate shanghaiAPirate() { 33 | var pirate = _shanghaier.shanghaiAPirate(); 34 | if (pirate == null) { 35 | throw new InternalServerError('Ran out of pirates!'); 36 | } 37 | return pirate; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /server/2-simple/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: server_code_lab 2 | version: 0.1.0 3 | author: Dart Team 4 | description: Code-lab server sample. 5 | environment: 6 | sdk: '>=1.9.0 <2.0.0' 7 | dependencies: 8 | _discoveryapis_commons: ^0.1.0 9 | browser: ^0.10.0+2 10 | crypto: ^0.9.0 11 | http: ^0.11.1 12 | logging_handlers: ^0.8.0 13 | rpc: ^0.5.0 14 | 15 | homepage: https://dart-lang.github.io/server/codelab/ 16 | -------------------------------------------------------------------------------- /server/4-extended/bin/piratesnest.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | library piratesnest; 6 | 7 | import 'dart:async'; 8 | import 'dart:io'; 9 | 10 | import 'package:logging/logging.dart'; 11 | import 'package:rpc/rpc.dart'; 12 | 13 | import 'package:server_code_lab/server/piratesapi.dart'; 14 | 15 | final ApiServer _apiServer = new ApiServer(prettyPrint: true); 16 | 17 | Future main() async { 18 | // Add a bit of logging... 19 | Logger.root..level = Level.INFO 20 | ..onRecord.listen(print); 21 | 22 | // Set up a server serving the pirate API. 23 | _apiServer.addApi(new PiratesApi()); 24 | HttpServer server = 25 | await HttpServer.bind(InternetAddress.ANY_IP_V4, 8088); 26 | server.listen((request) => _apiServer.httpRequestHandler(request)); 27 | print('Server listening on http://${server.address.host}:' 28 | '${server.port}'); 29 | } 30 | -------------------------------------------------------------------------------- /server/4-extended/lib/common/messages.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | library pirate.messages; 6 | 7 | // This class is used to send data back and forth between the 8 | // client and server. It is automatically serialized and 9 | // deserialized by the RPC package. 10 | class Pirate { 11 | String name; 12 | String appellation; 13 | 14 | // A message class must have a default constructor taking no 15 | // arguments. 16 | Pirate(); 17 | 18 | // It is fine to have other named constructors. 19 | Pirate.fromString(String pirateName) { 20 | var parts = pirateName.split(' the '); 21 | name = parts[0]; 22 | appellation = parts[1]; 23 | } 24 | 25 | @override 26 | String toString() => name.isEmpty ? '' : '$name the $appellation'; 27 | } 28 | -------------------------------------------------------------------------------- /server/4-extended/lib/common/utils.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | library pirate.utils; 6 | 7 | import 'dart:math' show Random; 8 | 9 | import 'messages.dart'; 10 | 11 | // Proper pirate names. 12 | const List pirateNames = const [ 13 | "Anne", "Bette", "Cate", "Dawn", "Elise", "Faye", "Ginger", 14 | "Harriot", "Izzy", "Jane", "Kaye", "Liz", "Maria", "Nell", 15 | "Olive", "Pat", "Queenie", "Rae", "Sal", "Tam", "Uma", 16 | "Violet", "Wilma", "Xana", "Yvonne", "Zelda", "Abe", 17 | "Billy", "Caleb", "Davie", "Eb", "Frank", "Gabe", "House", 18 | "Icarus", "Jack", "Kurt", "Larry", "Mike", "Nolan", 19 | "Oliver", "Pat", "Quib", "Roy", "Sal", "Tom", "Ube", 20 | "Val", "Walt", "Xavier", "Yvan", "Zeb" 21 | ]; 22 | 23 | // Proper pirate appellations. 24 | const List pirateAppellations = const [ 25 | "Awesome", "Captain", "Even", "Fighter", "Great", 26 | "Hearty", "Jackal", "King", "Lord", "Mighty", 27 | "Noble", "Old", "Powerful", "Quick", "Red", 28 | "Stalwart", "Tank", "Ultimate", "Vicious", 29 | "Wily", "aXe", "Young", "Brave", "Eager", 30 | "Kind", "Sandy", "Xeric", "Yellow", "Zesty" 31 | ]; 32 | 33 | // Clearly invalid pirate appellations. 34 | const List _forbiddenAppellations = const [ 35 | '', 'sweet', 'handsome', 'beautiful', 'weak', 'wuss', 36 | 'chicken', 'fearful' 37 | ]; 38 | 39 | // Helper method for validating whether the given pirate is truly a pirate! 40 | bool truePirate(Pirate pirate) => pirate.name != null && 41 | pirate.name.trim().isNotEmpty && 42 | pirate.appellation != null && 43 | !_forbiddenAppellations 44 | .contains(pirate.appellation.toLowerCase()); 45 | 46 | // Shared class for shanghaiing (generating) pirates. 47 | class PirateShanghaier { 48 | static final Random indexGen = new Random(); 49 | 50 | Pirate shanghaiAPirate({String name, String appellation}) { 51 | var pirate = new Pirate(); 52 | pirate.name = name != null 53 | ? name 54 | : pirateNames[indexGen.nextInt(pirateNames.length)]; 55 | pirate.appellation = appellation != null 56 | ? appellation 57 | : pirateAppellations[ 58 | indexGen.nextInt(pirateAppellations.length)]; 59 | return truePirate(pirate) ? pirate : null; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /server/4-extended/lib/server/piratesapi.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | library pirate.server; 6 | 7 | import 'package:rpc/rpc.dart'; 8 | 9 | import '../common/messages.dart'; 10 | import '../common/utils.dart'; 11 | 12 | // This class defines the interface that the server provides. 13 | @ApiClass(version: 'v1') 14 | class PiratesApi { 15 | final Map _pirateCrew = {}; 16 | final PirateShanghaier _shanghaier = new PirateShanghaier(); 17 | 18 | PiratesApi() { 19 | var captain = new Pirate.fromString('Lars the Captain'); 20 | _pirateCrew[captain.toString()] = captain; 21 | } 22 | 23 | @ApiMethod(method: 'POST', path: 'pirate') 24 | Pirate hirePirate(Pirate newPirate) { 25 | // Make sure this is a real pirate... 26 | if (!truePirate(newPirate)) { 27 | throw new BadRequestError( 28 | '$newPirate cannot be a pirate. \'Tis not a pirate name!'); 29 | } 30 | var pirateName = newPirate.toString(); 31 | if (_pirateCrew.containsKey(pirateName)) { 32 | throw new BadRequestError( 33 | '$newPirate is already part of your crew!'); 34 | } 35 | 36 | // Add the pirate to the crew. 37 | _pirateCrew[pirateName] = newPirate; 38 | return newPirate; 39 | } 40 | 41 | @ApiMethod( 42 | method: 'DELETE', path: 'pirate/{name}/the/{appellation}') 43 | Pirate firePirate(String name, String appellation) { 44 | var pirate = new Pirate() 45 | ..name = Uri.decodeComponent(name) 46 | ..appellation = Uri.decodeComponent(appellation); 47 | var pirateName = pirate.toString(); 48 | if (!_pirateCrew.containsKey(pirateName)) { 49 | throw new NotFoundError('Could not find pirate \'$pirate\'! ' + 50 | 'Maybe they\'ve abandoned ship!'); 51 | } 52 | return _pirateCrew.remove(pirateName); 53 | } 54 | 55 | // Returns a list of the pirate crew. 56 | @ApiMethod(method: 'GET', path: 'pirates') 57 | List listPirates() { 58 | return _pirateCrew.values.toList(); 59 | } 60 | 61 | // Generates (shanghais) and returns a new pirate. 62 | // Does not add the new pirate to the crew. 63 | @ApiMethod(path: 'shanghai') // Default HTTP method is GET. 64 | Pirate shanghaiAPirate() { 65 | var pirate = _shanghaier.shanghaiAPirate(); 66 | if (pirate == null) { 67 | throw new InternalServerError('Ran out of pirates!'); 68 | } 69 | return pirate; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /server/4-extended/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: server_code_lab 2 | version: 0.1.0 3 | author: Dart Team 4 | description: Code-lab server sample. 5 | environment: 6 | sdk: '>=1.9.0 <2.0.0' 7 | dependencies: 8 | _discoveryapis_commons: ^0.1.0 9 | browser: ^0.10.0+2 10 | crypto: ^0.9.0 11 | http: ^0.11.1 12 | logging_handlers: ^0.8.0 13 | rpc: ^0.5.0 14 | 15 | homepage: https://dart-lang.github.io/server/codelab/ 16 | -------------------------------------------------------------------------------- /server/5-generated/bin/piratesnest.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | library piratesnest; 6 | 7 | import 'dart:async'; 8 | import 'dart:io'; 9 | 10 | import 'package:logging/logging.dart'; 11 | import 'package:rpc/rpc.dart'; 12 | 13 | import 'package:server_code_lab/server/piratesapi.dart'; 14 | 15 | final ApiServer _apiServer = new ApiServer(prettyPrint: true); 16 | 17 | Future main() async { 18 | // Add a bit of logging... 19 | Logger.root..level = Level.INFO 20 | ..onRecord.listen(print); 21 | 22 | // Set up a server serving the pirate API. 23 | _apiServer.addApi(new PiratesApi()); 24 | HttpServer server = 25 | await HttpServer.bind(InternetAddress.ANY_IP_V4, 8088); 26 | server.listen((request) => _apiServer.httpRequestHandler(request)); 27 | print('Server listening on http://${server.address.host}:' 28 | '${server.port}'); 29 | } 30 | -------------------------------------------------------------------------------- /server/5-generated/lib/client/piratesapi.dart: -------------------------------------------------------------------------------- 1 | library server_code_lab.piratesApi.client; 2 | 3 | import 'dart:core' as core; 4 | import 'dart:collection' as collection; 5 | import 'dart:async' as async; 6 | import 'dart:convert' as convert; 7 | 8 | import 'package:_discoveryapis_commons/_discoveryapis_commons.dart' 9 | as commons; 10 | import 'package:crypto/crypto.dart' as crypto; 11 | import 'package:http/http.dart' as http; 12 | import 'package:server_code_lab/common/messages.dart'; 13 | export 'package:_discoveryapis_commons/_discoveryapis_commons.dart' 14 | show ApiRequestError, DetailedApiRequestError; 15 | 16 | const core.String USER_AGENT = 'dart-api-client piratesApi/v1'; 17 | 18 | class PiratesApi { 19 | final commons.ApiRequester _requester; 20 | 21 | PiratesApi(http.Client client, 22 | {core.String rootUrl: "http://localhost:8080/", 23 | core.String servicePath: "piratesApi/v1/"}) 24 | : _requester = new commons.ApiRequester( 25 | client, rootUrl, servicePath, USER_AGENT); 26 | 27 | /** 28 | * Request parameters: 29 | * 30 | * [name] - Path parameter: 'name'. 31 | * 32 | * [appellation] - Path parameter: 'appellation'. 33 | * 34 | * Completes with a [Pirate]. 35 | * 36 | * Completes with a [commons.ApiRequestError] if the API endpoint returned an 37 | * error. 38 | * 39 | * If the used [http.Client] completes with an error when making a REST call, 40 | * this method will complete with the same error. 41 | */ 42 | async.Future firePirate( 43 | core.String name, core.String appellation) { 44 | var _url = null; 45 | var _queryParams = new core.Map(); 46 | var _uploadMedia = null; 47 | var _uploadOptions = null; 48 | var _downloadOptions = commons.DownloadOptions.Metadata; 49 | var _body = null; 50 | 51 | if (name == null) { 52 | throw new core.ArgumentError("Parameter name is required."); 53 | } 54 | if (appellation == null) { 55 | throw new core.ArgumentError( 56 | "Parameter appellation is required."); 57 | } 58 | 59 | _url = 'pirate/' + 60 | commons.Escaper.ecapeVariable('$name') + 61 | '/the/' + 62 | commons.Escaper.ecapeVariable('$appellation'); 63 | 64 | var _response = _requester.request(_url, "DELETE", 65 | body: _body, 66 | queryParams: _queryParams, 67 | uploadOptions: _uploadOptions, 68 | uploadMedia: _uploadMedia, 69 | downloadOptions: _downloadOptions); 70 | return _response.then((data) => PirateFactory.fromJson(data)); 71 | } 72 | 73 | /** 74 | * [request] - The metadata request object. 75 | * 76 | * Request parameters: 77 | * 78 | * Completes with a [Pirate]. 79 | * 80 | * Completes with a [commons.ApiRequestError] if the API endpoint returned an 81 | * error. 82 | * 83 | * If the used [http.Client] completes with an error when making a REST call, 84 | * this method will complete with the same error. 85 | */ 86 | async.Future hirePirate(Pirate request) { 87 | var _url = null; 88 | var _queryParams = new core.Map(); 89 | var _uploadMedia = null; 90 | var _uploadOptions = null; 91 | var _downloadOptions = commons.DownloadOptions.Metadata; 92 | var _body = null; 93 | 94 | if (request != null) { 95 | _body = convert.JSON.encode(PirateFactory.toJson(request)); 96 | } 97 | 98 | _url = 'pirate'; 99 | 100 | var _response = _requester.request(_url, "POST", 101 | body: _body, 102 | queryParams: _queryParams, 103 | uploadOptions: _uploadOptions, 104 | uploadMedia: _uploadMedia, 105 | downloadOptions: _downloadOptions); 106 | return _response.then((data) => PirateFactory.fromJson(data)); 107 | } 108 | 109 | /** 110 | * Request parameters: 111 | * 112 | * Completes with a [core.List]. 113 | * 114 | * Completes with a [commons.ApiRequestError] if the API endpoint returned an 115 | * error. 116 | * 117 | * If the used [http.Client] completes with an error when making a REST call, 118 | * this method will complete with the same error. 119 | */ 120 | async.Future> listPirates() { 121 | var _url = null; 122 | var _queryParams = new core.Map(); 123 | var _uploadMedia = null; 124 | var _uploadOptions = null; 125 | var _downloadOptions = commons.DownloadOptions.Metadata; 126 | var _body = null; 127 | 128 | _url = 'pirates'; 129 | 130 | var _response = _requester.request(_url, "GET", 131 | body: _body, 132 | queryParams: _queryParams, 133 | uploadOptions: _uploadOptions, 134 | uploadMedia: _uploadMedia, 135 | downloadOptions: _downloadOptions); 136 | return _response.then((data) => 137 | data.map((value) => PirateFactory.fromJson(value)).toList()); 138 | } 139 | 140 | /** 141 | * Request parameters: 142 | * 143 | * Completes with a [Pirate]. 144 | * 145 | * Completes with a [commons.ApiRequestError] if the API endpoint returned an 146 | * error. 147 | * 148 | * If the used [http.Client] completes with an error when making a REST call, 149 | * this method will complete with the same error. 150 | */ 151 | async.Future shanghaiAPirate() { 152 | var _url = null; 153 | var _queryParams = new core.Map(); 154 | var _uploadMedia = null; 155 | var _uploadOptions = null; 156 | var _downloadOptions = commons.DownloadOptions.Metadata; 157 | var _body = null; 158 | 159 | _url = 'shanghai'; 160 | 161 | var _response = _requester.request(_url, "GET", 162 | body: _body, 163 | queryParams: _queryParams, 164 | uploadOptions: _uploadOptions, 165 | uploadMedia: _uploadMedia, 166 | downloadOptions: _downloadOptions); 167 | return _response.then((data) => PirateFactory.fromJson(data)); 168 | } 169 | } 170 | 171 | class PirateFactory { 172 | static Pirate fromJson(core.Map _json) { 173 | var message = new Pirate(); 174 | if (_json.containsKey("appellation")) { 175 | message.appellation = _json["appellation"]; 176 | } 177 | if (_json.containsKey("name")) { 178 | message.name = _json["name"]; 179 | } 180 | return message; 181 | } 182 | 183 | static core.Map toJson(Pirate message) { 184 | var _json = new core.Map(); 185 | if (message.appellation != null) { 186 | _json["appellation"] = message.appellation; 187 | } 188 | if (message.name != null) { 189 | _json["name"] = message.name; 190 | } 191 | return _json; 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /server/5-generated/lib/common/messages.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | library pirate.messages; 6 | 7 | // This class is used to send data back and forth between the 8 | // client and server. It is automatically serialized and 9 | // deserialized by the RPC package. 10 | class Pirate { 11 | String name; 12 | String appellation; 13 | 14 | // A message class must have a default constructor taking no 15 | // arguments. 16 | Pirate(); 17 | 18 | // It is fine to have other named constructors. 19 | Pirate.fromString(String pirateName) { 20 | var parts = pirateName.split(' the '); 21 | name = parts[0]; 22 | appellation = parts[1]; 23 | } 24 | 25 | @override 26 | String toString() => name.isEmpty ? '' : '$name the $appellation'; 27 | } 28 | -------------------------------------------------------------------------------- /server/5-generated/lib/common/utils.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | library pirate.utils; 6 | 7 | import 'dart:math' show Random; 8 | 9 | import 'messages.dart'; 10 | 11 | // Proper pirate names. 12 | const List pirateNames = const [ 13 | "Anne", "Bette", "Cate", "Dawn", "Elise", "Faye", "Ginger", 14 | "Harriot", "Izzy", "Jane", "Kaye", "Liz", "Maria", "Nell", 15 | "Olive", "Pat", "Queenie", "Rae", "Sal", "Tam", "Uma", 16 | "Violet", "Wilma", "Xana", "Yvonne", "Zelda", "Abe", 17 | "Billy", "Caleb", "Davie", "Eb", "Frank", "Gabe", "House", 18 | "Icarus", "Jack", "Kurt", "Larry", "Mike", "Nolan", 19 | "Oliver", "Pat", "Quib", "Roy", "Sal", "Tom", "Ube", 20 | "Val", "Walt", "Xavier", "Yvan", "Zeb" 21 | ]; 22 | 23 | // Proper pirate appellations. 24 | const List pirateAppellations = const [ 25 | "Awesome", "Captain", "Even", "Fighter", "Great", 26 | "Hearty", "Jackal", "King", "Lord", "Mighty", 27 | "Noble", "Old", "Powerful", "Quick", "Red", 28 | "Stalwart", "Tank", "Ultimate", "Vicious", 29 | "Wily", "aXe", "Young", "Brave", "Eager", 30 | "Kind", "Sandy", "Xeric", "Yellow", "Zesty" 31 | ]; 32 | 33 | // Clearly invalid pirate appellations. 34 | const List _forbiddenAppellations = const [ 35 | '', 'sweet', 'handsome', 'beautiful', 'weak', 'wuss', 36 | 'chicken', 'fearful' 37 | ]; 38 | 39 | // Helper method for validating whether the given pirate is truly a pirate! 40 | bool truePirate(Pirate pirate) => pirate.name != null && 41 | pirate.name.trim().isNotEmpty && 42 | pirate.appellation != null && 43 | !_forbiddenAppellations 44 | .contains(pirate.appellation.toLowerCase()); 45 | 46 | // Shared class for shanghaiing (generating) pirates. 47 | class PirateShanghaier { 48 | static final Random indexGen = new Random(); 49 | 50 | Pirate shanghaiAPirate({String name, String appellation}) { 51 | var pirate = new Pirate(); 52 | pirate.name = name != null 53 | ? name 54 | : pirateNames[indexGen.nextInt(pirateNames.length)]; 55 | pirate.appellation = appellation != null 56 | ? appellation 57 | : pirateAppellations[ 58 | indexGen.nextInt(pirateAppellations.length)]; 59 | return truePirate(pirate) ? pirate : null; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /server/5-generated/lib/server/piratesapi.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | library pirate.server; 6 | 7 | import 'package:rpc/rpc.dart'; 8 | 9 | import '../common/messages.dart'; 10 | import '../common/utils.dart'; 11 | 12 | // This class defines the interface that the server provides. 13 | @ApiClass(version: 'v1') 14 | class PiratesApi { 15 | final Map _pirateCrew = {}; 16 | final PirateShanghaier _shanghaier = new PirateShanghaier(); 17 | 18 | PiratesApi() { 19 | var captain = new Pirate.fromString('Lars the Captain'); 20 | _pirateCrew[captain.toString()] = captain; 21 | } 22 | 23 | @ApiMethod(method: 'POST', path: 'pirate') 24 | Pirate hirePirate(Pirate newPirate) { 25 | // Make sure this is a real pirate... 26 | if (!truePirate(newPirate)) { 27 | throw new BadRequestError( 28 | '$newPirate cannot be a pirate. \'Tis not a pirate name!'); 29 | } 30 | var pirateName = newPirate.toString(); 31 | if (_pirateCrew.containsKey(pirateName)) { 32 | throw new BadRequestError( 33 | '$newPirate is already part of your crew!'); 34 | } 35 | 36 | // Add the pirate to the crew. 37 | _pirateCrew[pirateName] = newPirate; 38 | return newPirate; 39 | } 40 | 41 | @ApiMethod( 42 | method: 'DELETE', path: 'pirate/{name}/the/{appellation}') 43 | Pirate firePirate(String name, String appellation) { 44 | var pirate = new Pirate() 45 | ..name = Uri.decodeComponent(name) 46 | ..appellation = Uri.decodeComponent(appellation); 47 | var pirateName = pirate.toString(); 48 | if (!_pirateCrew.containsKey(pirateName)) { 49 | throw new NotFoundError('Could not find pirate \'$pirate\'! ' + 50 | 'Maybe they\'ve abandoned ship!'); 51 | } 52 | return _pirateCrew.remove(pirateName); 53 | } 54 | 55 | // Returns a list of the pirate crew. 56 | @ApiMethod(method: 'GET', path: 'pirates') 57 | List listPirates() { 58 | return _pirateCrew.values.toList(); 59 | } 60 | 61 | // Generates (shanghais) and returns a new pirate. 62 | // Does not add the new pirate to the crew. 63 | @ApiMethod(path: 'shanghai') // Default HTTP method is GET. 64 | Pirate shanghaiAPirate() { 65 | var pirate = _shanghaier.shanghaiAPirate(); 66 | if (pirate == null) { 67 | throw new InternalServerError('Ran out of pirates!'); 68 | } 69 | return pirate; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /server/5-generated/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: server_code_lab 2 | version: 0.1.0 3 | author: Dart Team 4 | description: Code-lab server sample. 5 | environment: 6 | sdk: '>=1.9.0 <2.0.0' 7 | dependencies: 8 | _discoveryapis_commons: ^0.1.0 9 | browser: ^0.10.0+2 10 | crypto: ^0.9.0 11 | http: ^0.11.1 12 | logging_handlers: ^0.8.0 13 | rpc: ^0.5.0 14 | 15 | homepage: https://dart-lang.github.io/server/codelab/ 16 | -------------------------------------------------------------------------------- /server/6-client/bin/piratesnest.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | library piratesnest; 6 | 7 | import 'dart:async'; 8 | import 'dart:io'; 9 | 10 | import 'package:logging/logging.dart'; 11 | import 'package:rpc/rpc.dart'; 12 | 13 | import 'package:server_code_lab/server/piratesapi.dart'; 14 | 15 | final ApiServer _apiServer = new ApiServer(prettyPrint: true); 16 | 17 | Future main() async { 18 | // Add a bit of logging... 19 | Logger.root..level = Level.INFO 20 | ..onRecord.listen(print); 21 | 22 | // Set up a server serving the pirate API. 23 | _apiServer.addApi(new PiratesApi()); 24 | HttpServer server = 25 | await HttpServer.bind(InternetAddress.ANY_IP_V4, 8088); 26 | server.listen((request) => _apiServer.httpRequestHandler(request)); 27 | print('Server listening on http://${server.address.host}:' 28 | '${server.port}'); 29 | } 30 | -------------------------------------------------------------------------------- /server/6-client/lib/client/piratesapi.dart: -------------------------------------------------------------------------------- 1 | library server_code_lab.piratesApi.client; 2 | 3 | import 'dart:core' as core; 4 | import 'dart:collection' as collection; 5 | import 'dart:async' as async; 6 | import 'dart:convert' as convert; 7 | 8 | import 'package:_discoveryapis_commons/_discoveryapis_commons.dart' 9 | as commons; 10 | import 'package:crypto/crypto.dart' as crypto; 11 | import 'package:http/http.dart' as http; 12 | import 'package:server_code_lab/common/messages.dart'; 13 | export 'package:_discoveryapis_commons/_discoveryapis_commons.dart' 14 | show ApiRequestError, DetailedApiRequestError; 15 | 16 | const core.String USER_AGENT = 'dart-api-client piratesApi/v1'; 17 | 18 | class PiratesApi { 19 | final commons.ApiRequester _requester; 20 | 21 | PiratesApi(http.Client client, 22 | {core.String rootUrl: "http://localhost:8080/", 23 | core.String servicePath: "piratesApi/v1/"}) 24 | : _requester = new commons.ApiRequester( 25 | client, rootUrl, servicePath, USER_AGENT); 26 | 27 | /** 28 | * Request parameters: 29 | * 30 | * [name] - Path parameter: 'name'. 31 | * 32 | * [appellation] - Path parameter: 'appellation'. 33 | * 34 | * Completes with a [Pirate]. 35 | * 36 | * Completes with a [commons.ApiRequestError] if the API endpoint returned an 37 | * error. 38 | * 39 | * If the used [http.Client] completes with an error when making a REST call, 40 | * this method will complete with the same error. 41 | */ 42 | async.Future firePirate( 43 | core.String name, core.String appellation) { 44 | var _url = null; 45 | var _queryParams = new core.Map(); 46 | var _uploadMedia = null; 47 | var _uploadOptions = null; 48 | var _downloadOptions = commons.DownloadOptions.Metadata; 49 | var _body = null; 50 | 51 | if (name == null) { 52 | throw new core.ArgumentError("Parameter name is required."); 53 | } 54 | if (appellation == null) { 55 | throw new core.ArgumentError( 56 | "Parameter appellation is required."); 57 | } 58 | 59 | _url = 'pirate/' + 60 | commons.Escaper.ecapeVariable('$name') + 61 | '/the/' + 62 | commons.Escaper.ecapeVariable('$appellation'); 63 | 64 | var _response = _requester.request(_url, "DELETE", 65 | body: _body, 66 | queryParams: _queryParams, 67 | uploadOptions: _uploadOptions, 68 | uploadMedia: _uploadMedia, 69 | downloadOptions: _downloadOptions); 70 | return _response.then((data) => PirateFactory.fromJson(data)); 71 | } 72 | 73 | /** 74 | * [request] - The metadata request object. 75 | * 76 | * Request parameters: 77 | * 78 | * Completes with a [Pirate]. 79 | * 80 | * Completes with a [commons.ApiRequestError] if the API endpoint returned an 81 | * error. 82 | * 83 | * If the used [http.Client] completes with an error when making a REST call, 84 | * this method will complete with the same error. 85 | */ 86 | async.Future hirePirate(Pirate request) { 87 | var _url = null; 88 | var _queryParams = new core.Map(); 89 | var _uploadMedia = null; 90 | var _uploadOptions = null; 91 | var _downloadOptions = commons.DownloadOptions.Metadata; 92 | var _body = null; 93 | 94 | if (request != null) { 95 | _body = convert.JSON.encode(PirateFactory.toJson(request)); 96 | } 97 | 98 | _url = 'pirate'; 99 | 100 | var _response = _requester.request(_url, "POST", 101 | body: _body, 102 | queryParams: _queryParams, 103 | uploadOptions: _uploadOptions, 104 | uploadMedia: _uploadMedia, 105 | downloadOptions: _downloadOptions); 106 | return _response.then((data) => PirateFactory.fromJson(data)); 107 | } 108 | 109 | /** 110 | * Request parameters: 111 | * 112 | * Completes with a [core.List]. 113 | * 114 | * Completes with a [commons.ApiRequestError] if the API endpoint returned an 115 | * error. 116 | * 117 | * If the used [http.Client] completes with an error when making a REST call, 118 | * this method will complete with the same error. 119 | */ 120 | async.Future> listPirates() { 121 | var _url = null; 122 | var _queryParams = new core.Map(); 123 | var _uploadMedia = null; 124 | var _uploadOptions = null; 125 | var _downloadOptions = commons.DownloadOptions.Metadata; 126 | var _body = null; 127 | 128 | _url = 'pirates'; 129 | 130 | var _response = _requester.request(_url, "GET", 131 | body: _body, 132 | queryParams: _queryParams, 133 | uploadOptions: _uploadOptions, 134 | uploadMedia: _uploadMedia, 135 | downloadOptions: _downloadOptions); 136 | return _response.then((data) => 137 | data.map((value) => PirateFactory.fromJson(value)).toList()); 138 | } 139 | 140 | /** 141 | * Request parameters: 142 | * 143 | * Completes with a [Pirate]. 144 | * 145 | * Completes with a [commons.ApiRequestError] if the API endpoint returned an 146 | * error. 147 | * 148 | * If the used [http.Client] completes with an error when making a REST call, 149 | * this method will complete with the same error. 150 | */ 151 | async.Future shanghaiAPirate() { 152 | var _url = null; 153 | var _queryParams = new core.Map(); 154 | var _uploadMedia = null; 155 | var _uploadOptions = null; 156 | var _downloadOptions = commons.DownloadOptions.Metadata; 157 | var _body = null; 158 | 159 | _url = 'shanghai'; 160 | 161 | var _response = _requester.request(_url, "GET", 162 | body: _body, 163 | queryParams: _queryParams, 164 | uploadOptions: _uploadOptions, 165 | uploadMedia: _uploadMedia, 166 | downloadOptions: _downloadOptions); 167 | return _response.then((data) => PirateFactory.fromJson(data)); 168 | } 169 | } 170 | 171 | class PirateFactory { 172 | static Pirate fromJson(core.Map _json) { 173 | var message = new Pirate(); 174 | if (_json.containsKey("appellation")) { 175 | message.appellation = _json["appellation"]; 176 | } 177 | if (_json.containsKey("name")) { 178 | message.name = _json["name"]; 179 | } 180 | return message; 181 | } 182 | 183 | static core.Map toJson(Pirate message) { 184 | var _json = new core.Map(); 185 | if (message.appellation != null) { 186 | _json["appellation"] = message.appellation; 187 | } 188 | if (message.name != null) { 189 | _json["name"] = message.name; 190 | } 191 | return _json; 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /server/6-client/lib/common/messages.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | library pirate.messages; 6 | 7 | // This class is used to send data back and forth between the 8 | // client and server. It is automatically serialized and 9 | // deserialized by the RPC package. 10 | class Pirate { 11 | String name; 12 | String appellation; 13 | 14 | // A message class must have a default constructor taking no 15 | // arguments. 16 | Pirate(); 17 | 18 | // It is fine to have other named constructors. 19 | Pirate.fromString(String pirateName) { 20 | var parts = pirateName.split(' the '); 21 | name = parts[0]; 22 | appellation = parts[1]; 23 | } 24 | 25 | @override 26 | String toString() => name.isEmpty ? '' : '$name the $appellation'; 27 | } 28 | -------------------------------------------------------------------------------- /server/6-client/lib/common/utils.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | library pirate.utils; 6 | 7 | import 'dart:math' show Random; 8 | 9 | import 'messages.dart'; 10 | 11 | // Proper pirate names. 12 | const List pirateNames = const [ 13 | "Anne", "Bette", "Cate", "Dawn", "Elise", "Faye", "Ginger", 14 | "Harriot", "Izzy", "Jane", "Kaye", "Liz", "Maria", "Nell", 15 | "Olive", "Pat", "Queenie", "Rae", "Sal", "Tam", "Uma", 16 | "Violet", "Wilma", "Xana", "Yvonne", "Zelda", "Abe", 17 | "Billy", "Caleb", "Davie", "Eb", "Frank", "Gabe", "House", 18 | "Icarus", "Jack", "Kurt", "Larry", "Mike", "Nolan", 19 | "Oliver", "Pat", "Quib", "Roy", "Sal", "Tom", "Ube", 20 | "Val", "Walt", "Xavier", "Yvan", "Zeb" 21 | ]; 22 | 23 | // Proper pirate appellations. 24 | const List pirateAppellations = const [ 25 | "Awesome", "Captain", "Even", "Fighter", "Great", 26 | "Hearty", "Jackal", "King", "Lord", "Mighty", 27 | "Noble", "Old", "Powerful", "Quick", "Red", 28 | "Stalwart", "Tank", "Ultimate", "Vicious", 29 | "Wily", "aXe", "Young", "Brave", "Eager", 30 | "Kind", "Sandy", "Xeric", "Yellow", "Zesty" 31 | ]; 32 | 33 | // Clearly invalid pirate appellations. 34 | const List _forbiddenAppellations = const [ 35 | '', 'sweet', 'handsome', 'beautiful', 'weak', 'wuss', 36 | 'chicken', 'fearful' 37 | ]; 38 | 39 | // Helper method for validating whether the given pirate is truly a pirate! 40 | bool truePirate(Pirate pirate) => pirate.name != null && 41 | pirate.name.trim().isNotEmpty && 42 | pirate.appellation != null && 43 | !_forbiddenAppellations 44 | .contains(pirate.appellation.toLowerCase()); 45 | 46 | // Shared class for shanghaiing (generating) pirates. 47 | class PirateShanghaier { 48 | static final Random indexGen = new Random(); 49 | 50 | Pirate shanghaiAPirate({String name, String appellation}) { 51 | var pirate = new Pirate(); 52 | pirate.name = name != null 53 | ? name 54 | : pirateNames[indexGen.nextInt(pirateNames.length)]; 55 | pirate.appellation = appellation != null 56 | ? appellation 57 | : pirateAppellations[ 58 | indexGen.nextInt(pirateAppellations.length)]; 59 | return truePirate(pirate) ? pirate : null; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /server/6-client/lib/server/piratesapi.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | library pirate.server; 6 | 7 | import 'package:rpc/rpc.dart'; 8 | 9 | import '../common/messages.dart'; 10 | import '../common/utils.dart'; 11 | 12 | // This class defines the interface that the server provides. 13 | @ApiClass(version: 'v1') 14 | class PiratesApi { 15 | final Map _pirateCrew = {}; 16 | final PirateShanghaier _shanghaier = new PirateShanghaier(); 17 | 18 | PiratesApi() { 19 | var captain = new Pirate.fromString('Lars the Captain'); 20 | _pirateCrew[captain.toString()] = captain; 21 | } 22 | 23 | @ApiMethod(method: 'POST', path: 'pirate') 24 | Pirate hirePirate(Pirate newPirate) { 25 | // Make sure this is a real pirate... 26 | if (!truePirate(newPirate)) { 27 | throw new BadRequestError( 28 | '$newPirate cannot be a pirate. \'Tis not a pirate name!'); 29 | } 30 | var pirateName = newPirate.toString(); 31 | if (_pirateCrew.containsKey(pirateName)) { 32 | throw new BadRequestError( 33 | '$newPirate is already part of your crew!'); 34 | } 35 | 36 | // Add the pirate to the crew. 37 | _pirateCrew[pirateName] = newPirate; 38 | return newPirate; 39 | } 40 | 41 | @ApiMethod( 42 | method: 'DELETE', path: 'pirate/{name}/the/{appellation}') 43 | Pirate firePirate(String name, String appellation) { 44 | var pirate = new Pirate() 45 | ..name = Uri.decodeComponent(name) 46 | ..appellation = Uri.decodeComponent(appellation); 47 | var pirateName = pirate.toString(); 48 | if (!_pirateCrew.containsKey(pirateName)) { 49 | throw new NotFoundError('Could not find pirate \'$pirate\'! ' + 50 | 'Maybe they\'ve abandoned ship!'); 51 | } 52 | return _pirateCrew.remove(pirateName); 53 | } 54 | 55 | // Returns a list of the pirate crew. 56 | @ApiMethod(method: 'GET', path: 'pirates') 57 | List listPirates() { 58 | return _pirateCrew.values.toList(); 59 | } 60 | 61 | // Generates (shanghais) and returns a new pirate. 62 | // Does not add the new pirate to the crew. 63 | @ApiMethod(path: 'shanghai') // Default HTTP method is GET. 64 | Pirate shanghaiAPirate() { 65 | var pirate = _shanghaier.shanghaiAPirate(); 66 | if (pirate == null) { 67 | throw new InternalServerError('Ran out of pirates!'); 68 | } 69 | return pirate; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /server/6-client/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: server_code_lab 2 | version: 0.1.0 3 | author: Dart Team 4 | description: Code-lab server sample. 5 | environment: 6 | sdk: '>=1.9.0 <2.0.0' 7 | dependencies: 8 | _discoveryapis_commons: ^0.1.0 9 | browser: ^0.10.0+2 10 | crypto: ^0.9.0 11 | http: ^0.11.1 12 | logging_handlers: ^0.8.0 13 | rpc: ^0.5.0 14 | 15 | homepage: https://dart-lang.github.io/server/codelab/ 16 | -------------------------------------------------------------------------------- /server/6-client/web/piratebadge.css: -------------------------------------------------------------------------------- 1 | @import url(//fonts.googleapis.com/css?family=Roboto&subset=latin,latin-ext); 2 | 3 | body { 4 | background-color: #f5f5f5; 5 | font-family: 'Roboto', sans-serif; 6 | font-size: 14px; 7 | font-weight: normal; 8 | line-height: 1.2em; 9 | margin: 15px; 10 | color: #424242; 11 | } 12 | h1 { 13 | font-weight: normal; 14 | font-size: 32px; 15 | margin-bottom: 30px; 16 | } 17 | button { 18 | font-family: inherit; 19 | font-size: 14px; 20 | margin: 20px auto 0; 21 | box-shadow: 0 1px 1.5px 0 rgba(0, 0, 0, 0.12), 0 1px 1px 0 rgba(0, 0, 0, 0.24); 22 | border-radius: 2px; 23 | border: none; 24 | padding: 6px 8px; 25 | text-transform: uppercase; 26 | background: #e3e3e3; 27 | color: black; 28 | outline: none; 29 | -webkit-transition: all 0.2s ease-in; 30 | transition: all 0.2s ease-in; 31 | display: block; 32 | } 33 | button[disabled] { 34 | background-color: #d8d8d8 !important; 35 | color: #a0a0a0 !important; 36 | } 37 | button:active { 38 | box-shadow: 0 10px 10px 0 rgba(0, 0, 0, 0.19), 0 6px 3px 0 rgba(0, 0, 0, 0.23); 39 | } 40 | button:not(:disabled) { 41 | cursor: pointer; 42 | } 43 | input[type="text"] { 44 | outline: none; 45 | font-family: inherit; 46 | font-size: 16px; 47 | border: none; 48 | border-bottom: 1px solid #ddd; 49 | background: none; 50 | } 51 | select { 52 | font-family: inherit; 53 | border: none; 54 | outline: none; 55 | background: white; 56 | } 57 | select:focus option:checked, select option:hover { 58 | background: linear-gradient(#000000, #000000); 59 | color: #bbb; 60 | } 61 | select option { 62 | border-bottom: 1px solid #d2d2d2; 63 | padding: 8px 6px; 64 | outline: none; 65 | } 66 | select option:checked { 67 | background: linear-gradient(#f0f0f0, #f0f0f0); 68 | } 69 | .widgets { 70 | padding-bottom: 20px; 71 | margin-bottom: 20px; 72 | margin-right: 20px; 73 | float: left; 74 | } 75 | .form { 76 | overflow: hidden; 77 | } 78 | .badge, .pirates { 79 | border-radius: 2px; 80 | font-size: 19px; 81 | width: 14em; 82 | text-align: center; 83 | white-space: nowrap; 84 | overflow: hidden; 85 | box-shadow: 0 1px 1.5px 0 rgba(0, 0, 0, 0.12), 0 1px 1px 0 rgba(0, 0, 0, 0.24); 86 | } 87 | .badge { 88 | background: #f44336; 89 | height: 7em; 90 | } 91 | .pirates { 92 | background: #2196f3; 93 | } 94 | .greeting { 95 | color: white; 96 | padding: 0.5em; 97 | font-size: 20px; 98 | } 99 | .name { 100 | color: black; 101 | background: white; 102 | font-family: "Marker Felt", cursive; 103 | font-size: 30px; 104 | padding: 1em 0; 105 | height: 16px; 106 | } 107 | #pirateList { 108 | width: 100%; 109 | height: 14em; 110 | } 111 | #generateButton { 112 | margin-bottom: 100px; 113 | } 114 | #storeButton { 115 | background: #2196f3; 116 | color: white; 117 | } 118 | #storeButton:hover { 119 | background: #1e88e5; 120 | } 121 | #storeButton:active { 122 | background: #1976d2; 123 | } 124 | #killButton { 125 | background: black; 126 | color: white; 127 | } 128 | #killButton:hover, 129 | #killButton:active { 130 | background: #212121; 131 | } 132 | #inputName { 133 | margin: 30px 0 0; 134 | width: 14em; 135 | padding: 5px 0; 136 | } 137 | #inputName + span { 138 | display: block; 139 | width: 10px; 140 | height: 2px; 141 | background: #2196f3; 142 | position: relative; 143 | top: -2px; 144 | left: 50%; 145 | visibility: hidden; 146 | -webkit-transition: all .2s ease-in; 147 | transition: all .2s ease-in; 148 | } 149 | #inputName:focus + span { 150 | width: 100%; 151 | left: 0; 152 | visibility: visible; 153 | } 154 | div::selection, button::selection { 155 | background: none; 156 | } 157 | div::-moz-selection, button::-moz-selection { 158 | background: none; 159 | } 160 | @media all and (max-width: 600px) { 161 | #generateButton { 162 | margin-bottom: 0; 163 | } 164 | } 165 | @media all and (max-width: 560px) { 166 | h1 { 167 | text-align: center; 168 | } 169 | .form { 170 | width: 16em; 171 | margin: 0 auto; 172 | } 173 | .widgets, .badge, .pirates, button, #inputName { 174 | float: none; 175 | margin-left: auto; 176 | margin-right: auto; 177 | } 178 | #inputName { 179 | width: 100%; 180 | } 181 | .widgets { 182 | margin-bottom: 50px; 183 | padding-bottom: 0; 184 | } 185 | } 186 | /* This is needed for proper ripple effect on buttons */ 187 | button { 188 | position: relative; 189 | overflow: hidden; 190 | } 191 | button .ripple { 192 | position: absolute; 193 | display: block; 194 | border-radius: 100%; 195 | width: 0; 196 | height: 0; 197 | pointer-events: none; 198 | background: rgba(0, 0, 0, .2); 199 | -webkit-transform: translate(-50%, -50%); 200 | transform: translate(-50%, -50%); 201 | } 202 | button .ripple.show { 203 | -webkit-animation: ripple .3s ease-in; 204 | animation: ripple .3s ease-in; 205 | } 206 | #storeButton .ripple, 207 | #killButton .ripple { 208 | background: rgba(255, 255, 255, .2); 209 | } 210 | @-webkit-keyframes ripple { 211 | from { 212 | width: 0; 213 | } 214 | to { 215 | width: 200%; 216 | padding-top: 200%; 217 | } 218 | } 219 | @keyframes ripple { 220 | from { 221 | width: 0; 222 | } 223 | to { 224 | width: 200%; 225 | padding-top: 200%; 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /server/6-client/web/piratebadge.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, 2015 the Dart project authors. 2 | // Please see the AUTHORS file for details. All rights reserved. 3 | // Use of this source code is governed by a BSD-style license that can be 4 | // found in the LICENSE file. 5 | 6 | import 'dart:async'; 7 | import 'dart:html'; 8 | 9 | import 'package:http/browser_client.dart'; 10 | import 'package:server_code_lab/client/piratesapi.dart'; 11 | import 'package:server_code_lab/common/messages.dart'; 12 | import 'package:server_code_lab/common/utils.dart'; 13 | 14 | final String treasureKey = 'pirateName'; 15 | 16 | ButtonElement genButton; 17 | ButtonElement storeButton; 18 | ButtonElement fireButton; 19 | ButtonElement slayButton; 20 | SpanElement badgeNameElement; 21 | SelectElement pirateList; 22 | 23 | // By default the generated client code uses 24 | // 'http://localhost:8080/'. Since our server is running on 25 | // port 8088 we override the default url when instantiating 26 | // the generated PiratesApi class. 27 | final String _serverUrl = 'localhost:8088/'; 28 | final BrowserClient _client = new BrowserClient(); 29 | PiratesApi _api; 30 | PirateShanghaier _shanghaier; 31 | 32 | Future main() async { 33 | // We need to determine if the client is using http or https 34 | // and use the same protocol for the client stub requests 35 | // (the protocol includes the ':'). 36 | var protocol = window.location.protocol; 37 | if (!['http:', 'https:'].contains(protocol)) { 38 | // Default to http if unknown protocol. 39 | protocol = 'http:'; 40 | } 41 | _api = new PiratesApi(_client, rootUrl: '$protocol//$_serverUrl'); 42 | _shanghaier = new PirateShanghaier(); 43 | 44 | InputElement inputField = querySelector('#inputName'); 45 | inputField.onInput.listen(updateBadge); 46 | genButton = querySelector('#generateButton'); 47 | genButton.onClick.listen(generateBadge); 48 | inputField.disabled = false; //enable 49 | genButton.disabled = false; //enable 50 | badgeNameElement = querySelector('#badgeName'); 51 | storeButton = querySelector('#storeButton'); 52 | storeButton.onClick.listen(storeBadge); 53 | pirateList = querySelector('#pirateList'); 54 | pirateList.onClick.listen(selectListener); 55 | fireButton = querySelector('#fireButton'); 56 | fireButton.onClick.listen(removeBadge); 57 | slayButton = querySelector('#slayButton'); 58 | slayButton.onClick.listen(removeAllBadges); 59 | setBadgeName(getBadgeNameFromStorage()); 60 | refreshList(); 61 | 62 | var buttons = querySelectorAll("button"); 63 | buttons.onClick.listen(addRippleEffect); 64 | } 65 | 66 | Future refreshList() async { 67 | List pirates = await _api.listPirates(); 68 | pirateList.children.clear(); 69 | pirates.forEach((pirate) { 70 | var option = new OptionElement(data: pirate.toString()); 71 | pirateList.add(option, 0); 72 | }); 73 | 74 | var disabled = true; 75 | if (pirateList.length > 0) { 76 | disabled = false; 77 | } 78 | 79 | new Future.delayed(new Duration(milliseconds: 300), () { 80 | slayButton.disabled = disabled; 81 | }); 82 | } 83 | 84 | void updateBadge(Event e) { 85 | String inputName = (e.target as InputElement).value.trim(); 86 | var pirate = _shanghaier.shanghaiAPirate(name: inputName); 87 | setBadgeName(pirate); 88 | if (inputName.trim().isEmpty) { 89 | genButton 90 | ..disabled = false 91 | ..text = 'Aye! Gimme a name!'; 92 | storeButton..disabled = true; 93 | } else { 94 | genButton 95 | ..disabled = true 96 | ..text = 'Arrr! Write yer name!'; 97 | storeButton..disabled = false; 98 | } 99 | } 100 | 101 | Future storeBadge(Event e) async { 102 | var pirateName = badgeNameElement.text; 103 | if (pirateName == null || pirateName.isEmpty) return null; 104 | var pirate = new Pirate.fromString(pirateName); 105 | try { 106 | await _api.hirePirate(pirate); 107 | } catch (error) { 108 | window.alert(error.message); 109 | } 110 | new Future.delayed(new Duration(milliseconds: 300), () { 111 | storeButton 112 | ..disabled = true 113 | ..text = 'Pirate hired!'; 114 | }); 115 | refreshList(); 116 | } 117 | 118 | Future selectListener(Event e) async { 119 | fireButton.disabled = false; 120 | } 121 | 122 | Future removeBadge(Event e) async { 123 | var idx = pirateList.selectedIndex; 124 | if (idx < 0 || idx >= pirateList.options.length) return null; 125 | var option = pirateList.options.elementAt(idx); 126 | var pirate = new Pirate.fromString(option.label); 127 | try { 128 | await _api.firePirate(pirate.name, pirate.appellation); 129 | } catch (error) { 130 | window.alert(error.message); 131 | } 132 | new Future.delayed(new Duration(milliseconds: 300), () { 133 | fireButton.disabled = true; 134 | }); 135 | refreshList(); 136 | } 137 | 138 | Future removeAllBadges(Event e) async { 139 | for (var option in pirateList.options) { 140 | var pirate = new Pirate.fromString(option.label); 141 | try { 142 | await _api.firePirate(pirate.name, pirate.appellation); 143 | } catch (error) { 144 | // ignoring errors. 145 | } 146 | } 147 | new Future.delayed(new Duration(milliseconds: 300), () { 148 | fireButton.disabled = true; 149 | slayButton.disabled = true; 150 | }); 151 | refreshList(); 152 | } 153 | 154 | void generateBadge(Event e) { 155 | var pirate = _shanghaier.shanghaiAPirate(); 156 | setBadgeName(pirate); 157 | } 158 | 159 | void setBadgeName(Pirate pirate) { 160 | if (pirate == null || pirate.toString().isEmpty) { 161 | badgeNameElement.text = ''; 162 | storeButton.disabled = true; 163 | return; 164 | } 165 | badgeNameElement.text = pirate.toString(); 166 | window.localStorage[treasureKey] = pirate.toString(); 167 | storeButton 168 | ..disabled = false 169 | ..text = 'Hire pirate!'; 170 | } 171 | 172 | Pirate getBadgeNameFromStorage() { 173 | String storedName = window.localStorage[treasureKey]; 174 | if (storedName != null && storedName.contains(' the ')) { 175 | return new Pirate.fromString(storedName); 176 | } else { 177 | return null; 178 | } 179 | } 180 | 181 | void addRippleEffect(MouseEvent e) { 182 | var button = e.target as ButtonElement; 183 | var ripple = button.querySelector(".ripple"); 184 | 185 | // we need to delete existing ripple element 186 | if (ripple != null) { 187 | ripple.remove(); 188 | } 189 | 190 | var x = e.client.x - button.getBoundingClientRect().left; 191 | var y = e.client.y - button.getBoundingClientRect().top; 192 | 193 | ripple = new SpanElement() 194 | ..classes.add("ripple") 195 | ..style.left = "${x}px" 196 | ..style.top = "${y}px" 197 | ..classes.add("show"); 198 | 199 | button.append(ripple); 200 | } 201 | -------------------------------------------------------------------------------- /server/6-client/web/piratebadge.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | 11 | 12 | 13 | Pirate badge 14 | 15 | 16 | 17 | 18 | 19 | 20 |

Pirate badge

21 | 22 |
23 |
24 | 25 | 26 |
27 |
28 | 29 |
30 |
31 |
32 |
33 |
34 | Arrr! Me name is 35 |
36 |
37 | 38 |
39 |
40 |
41 | 42 |
43 |
44 |
45 |
46 |
47 | Pirate crew! 48 |
49 | 50 |
51 |
52 | 53 |
54 |
55 | 56 |
57 |
58 | 59 | 60 | -------------------------------------------------------------------------------- /server/7-serve/bin/piratesnest.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | library piratesnest; 6 | 7 | import 'dart:async'; 8 | import 'dart:io'; 9 | 10 | import 'package:http_server/http_server.dart'; 11 | import 'package:logging/logging.dart'; 12 | import 'package:rpc/rpc.dart'; 13 | 14 | import 'package:server_code_lab/server/piratesapi.dart'; 15 | 16 | final ApiServer _apiServer = new ApiServer(prettyPrint: true); 17 | 18 | // Create a virtual directory used to serve our client code from 19 | // the 'build/web' directory. 20 | final String _buildPath = 21 | Platform.script.resolve('../build/web/').toFilePath(); 22 | final VirtualDirectory _clientDir = new VirtualDirectory(_buildPath); 23 | 24 | Future main() async { 25 | // Add a bit of logging... 26 | Logger.root..level = Level.INFO 27 | ..onRecord.listen(print); 28 | 29 | // Set up a server serving the pirate API. 30 | _apiServer.addApi(new PiratesApi()); 31 | HttpServer server = 32 | await HttpServer.bind(InternetAddress.ANY_IP_V4, 8088); 33 | server.listen(requestHandler); 34 | print('Server listening on http://${server.address.host}:' 35 | '${server.port}'); 36 | } 37 | 38 | Future requestHandler(HttpRequest request) async { 39 | if (request.uri.path.startsWith('/piratesApi')) { 40 | // Handle the API request. 41 | var apiResponse; 42 | try { 43 | var apiRequest = new HttpApiRequest.fromHttpRequest(request); 44 | apiResponse = 45 | await _apiServer.handleHttpApiRequest(apiRequest); 46 | } catch (error, stack) { 47 | var exception = 48 | error is Error ? new Exception(error.toString()) : error; 49 | apiResponse = new HttpApiResponse.error( 50 | HttpStatus.INTERNAL_SERVER_ERROR, exception.toString(), 51 | exception, stack); 52 | } 53 | return sendApiResponse(apiResponse, request.response); 54 | } else if (request.uri.path == '/') { 55 | // Redirect to the piratebadge.html file. This will initiate 56 | // loading the client application. 57 | request.response.redirect(Uri.parse('/piratebadge.html')); 58 | } else { 59 | // Serve the requested file (path) from the virtual directory, 60 | // minus the preceeding '/'. This will fail with a 404 Not Found 61 | // if the request is not for a valid file. 62 | var fileUri = new Uri.file(_buildPath) 63 | .resolve(request.uri.path.substring(1)); 64 | _clientDir.serveFile(new File(fileUri.toFilePath()), request); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /server/7-serve/lib/client/piratesapi.dart: -------------------------------------------------------------------------------- 1 | library server_code_lab.piratesApi.client; 2 | 3 | import 'dart:core' as core; 4 | import 'dart:collection' as collection; 5 | import 'dart:async' as async; 6 | import 'dart:convert' as convert; 7 | 8 | import 'package:_discoveryapis_commons/_discoveryapis_commons.dart' 9 | as commons; 10 | import 'package:crypto/crypto.dart' as crypto; 11 | import 'package:http/http.dart' as http; 12 | import 'package:server_code_lab/common/messages.dart'; 13 | export 'package:_discoveryapis_commons/_discoveryapis_commons.dart' 14 | show ApiRequestError, DetailedApiRequestError; 15 | 16 | const core.String USER_AGENT = 'dart-api-client piratesApi/v1'; 17 | 18 | class PiratesApi { 19 | final commons.ApiRequester _requester; 20 | 21 | PiratesApi(http.Client client, 22 | {core.String rootUrl: "http://localhost:8080/", 23 | core.String servicePath: "piratesApi/v1/"}) 24 | : _requester = new commons.ApiRequester( 25 | client, rootUrl, servicePath, USER_AGENT); 26 | 27 | /** 28 | * Request parameters: 29 | * 30 | * [name] - Path parameter: 'name'. 31 | * 32 | * [appellation] - Path parameter: 'appellation'. 33 | * 34 | * Completes with a [Pirate]. 35 | * 36 | * Completes with a [commons.ApiRequestError] if the API endpoint returned an 37 | * error. 38 | * 39 | * If the used [http.Client] completes with an error when making a REST call, 40 | * this method will complete with the same error. 41 | */ 42 | async.Future firePirate( 43 | core.String name, core.String appellation) { 44 | var _url = null; 45 | var _queryParams = new core.Map(); 46 | var _uploadMedia = null; 47 | var _uploadOptions = null; 48 | var _downloadOptions = commons.DownloadOptions.Metadata; 49 | var _body = null; 50 | 51 | if (name == null) { 52 | throw new core.ArgumentError("Parameter name is required."); 53 | } 54 | if (appellation == null) { 55 | throw new core.ArgumentError( 56 | "Parameter appellation is required."); 57 | } 58 | 59 | _url = 'pirate/' + 60 | commons.Escaper.ecapeVariable('$name') + 61 | '/the/' + 62 | commons.Escaper.ecapeVariable('$appellation'); 63 | 64 | var _response = _requester.request(_url, "DELETE", 65 | body: _body, 66 | queryParams: _queryParams, 67 | uploadOptions: _uploadOptions, 68 | uploadMedia: _uploadMedia, 69 | downloadOptions: _downloadOptions); 70 | return _response.then((data) => PirateFactory.fromJson(data)); 71 | } 72 | 73 | /** 74 | * [request] - The metadata request object. 75 | * 76 | * Request parameters: 77 | * 78 | * Completes with a [Pirate]. 79 | * 80 | * Completes with a [commons.ApiRequestError] if the API endpoint returned an 81 | * error. 82 | * 83 | * If the used [http.Client] completes with an error when making a REST call, 84 | * this method will complete with the same error. 85 | */ 86 | async.Future hirePirate(Pirate request) { 87 | var _url = null; 88 | var _queryParams = new core.Map(); 89 | var _uploadMedia = null; 90 | var _uploadOptions = null; 91 | var _downloadOptions = commons.DownloadOptions.Metadata; 92 | var _body = null; 93 | 94 | if (request != null) { 95 | _body = convert.JSON.encode(PirateFactory.toJson(request)); 96 | } 97 | 98 | _url = 'pirate'; 99 | 100 | var _response = _requester.request(_url, "POST", 101 | body: _body, 102 | queryParams: _queryParams, 103 | uploadOptions: _uploadOptions, 104 | uploadMedia: _uploadMedia, 105 | downloadOptions: _downloadOptions); 106 | return _response.then((data) => PirateFactory.fromJson(data)); 107 | } 108 | 109 | /** 110 | * Request parameters: 111 | * 112 | * Completes with a [core.List]. 113 | * 114 | * Completes with a [commons.ApiRequestError] if the API endpoint returned an 115 | * error. 116 | * 117 | * If the used [http.Client] completes with an error when making a REST call, 118 | * this method will complete with the same error. 119 | */ 120 | async.Future> listPirates() { 121 | var _url = null; 122 | var _queryParams = new core.Map(); 123 | var _uploadMedia = null; 124 | var _uploadOptions = null; 125 | var _downloadOptions = commons.DownloadOptions.Metadata; 126 | var _body = null; 127 | 128 | _url = 'pirates'; 129 | 130 | var _response = _requester.request(_url, "GET", 131 | body: _body, 132 | queryParams: _queryParams, 133 | uploadOptions: _uploadOptions, 134 | uploadMedia: _uploadMedia, 135 | downloadOptions: _downloadOptions); 136 | return _response.then((data) => 137 | data.map((value) => PirateFactory.fromJson(value)).toList()); 138 | } 139 | 140 | /** 141 | * Request parameters: 142 | * 143 | * Completes with a [Pirate]. 144 | * 145 | * Completes with a [commons.ApiRequestError] if the API endpoint returned an 146 | * error. 147 | * 148 | * If the used [http.Client] completes with an error when making a REST call, 149 | * this method will complete with the same error. 150 | */ 151 | async.Future shanghaiAPirate() { 152 | var _url = null; 153 | var _queryParams = new core.Map(); 154 | var _uploadMedia = null; 155 | var _uploadOptions = null; 156 | var _downloadOptions = commons.DownloadOptions.Metadata; 157 | var _body = null; 158 | 159 | _url = 'shanghai'; 160 | 161 | var _response = _requester.request(_url, "GET", 162 | body: _body, 163 | queryParams: _queryParams, 164 | uploadOptions: _uploadOptions, 165 | uploadMedia: _uploadMedia, 166 | downloadOptions: _downloadOptions); 167 | return _response.then((data) => PirateFactory.fromJson(data)); 168 | } 169 | } 170 | 171 | class PirateFactory { 172 | static Pirate fromJson(core.Map _json) { 173 | var message = new Pirate(); 174 | if (_json.containsKey("appellation")) { 175 | message.appellation = _json["appellation"]; 176 | } 177 | if (_json.containsKey("name")) { 178 | message.name = _json["name"]; 179 | } 180 | return message; 181 | } 182 | 183 | static core.Map toJson(Pirate message) { 184 | var _json = new core.Map(); 185 | if (message.appellation != null) { 186 | _json["appellation"] = message.appellation; 187 | } 188 | if (message.name != null) { 189 | _json["name"] = message.name; 190 | } 191 | return _json; 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /server/7-serve/lib/common/messages.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | library pirate.messages; 6 | 7 | // This class is used to send data back and forth between the 8 | // client and server. It is automatically serialized and 9 | // deserialized by the RPC package. 10 | class Pirate { 11 | String name; 12 | String appellation; 13 | 14 | // A message class must have a default constructor taking no 15 | // arguments. 16 | Pirate(); 17 | 18 | // It is fine to have other named constructors. 19 | Pirate.fromString(String pirateName) { 20 | var parts = pirateName.split(' the '); 21 | name = parts[0]; 22 | appellation = parts[1]; 23 | } 24 | 25 | @override 26 | String toString() => name.isEmpty ? '' : '$name the $appellation'; 27 | } 28 | -------------------------------------------------------------------------------- /server/7-serve/lib/common/utils.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | library pirate.utils; 6 | 7 | import 'dart:math' show Random; 8 | 9 | import 'messages.dart'; 10 | 11 | // Proper pirate names. 12 | const List pirateNames = const [ 13 | "Anne", "Bette", "Cate", "Dawn", "Elise", "Faye", "Ginger", 14 | "Harriot", "Izzy", "Jane", "Kaye", "Liz", "Maria", "Nell", 15 | "Olive", "Pat", "Queenie", "Rae", "Sal", "Tam", "Uma", 16 | "Violet", "Wilma", "Xana", "Yvonne", "Zelda", "Abe", 17 | "Billy", "Caleb", "Davie", "Eb", "Frank", "Gabe", "House", 18 | "Icarus", "Jack", "Kurt", "Larry", "Mike", "Nolan", 19 | "Oliver", "Pat", "Quib", "Roy", "Sal", "Tom", "Ube", 20 | "Val", "Walt", "Xavier", "Yvan", "Zeb" 21 | ]; 22 | 23 | // Proper pirate appellations. 24 | const List pirateAppellations = const [ 25 | "Awesome", "Captain", "Even", "Fighter", "Great", 26 | "Hearty", "Jackal", "King", "Lord", "Mighty", 27 | "Noble", "Old", "Powerful", "Quick", "Red", 28 | "Stalwart", "Tank", "Ultimate", "Vicious", 29 | "Wily", "aXe", "Young", "Brave", "Eager", 30 | "Kind", "Sandy", "Xeric", "Yellow", "Zesty" 31 | ]; 32 | 33 | // Clearly invalid pirate appellations. 34 | const List _forbiddenAppellations = const [ 35 | '', 'sweet', 'handsome', 'beautiful', 'weak', 'wuss', 36 | 'chicken', 'fearful' 37 | ]; 38 | 39 | // Helper method for validating whether the given pirate is truly a pirate! 40 | bool truePirate(Pirate pirate) => pirate.name != null && 41 | pirate.name.trim().isNotEmpty && 42 | pirate.appellation != null && 43 | !_forbiddenAppellations 44 | .contains(pirate.appellation.toLowerCase()); 45 | 46 | // Shared class for shanghaiing (generating) pirates. 47 | class PirateShanghaier { 48 | static final Random indexGen = new Random(); 49 | 50 | Pirate shanghaiAPirate({String name, String appellation}) { 51 | var pirate = new Pirate(); 52 | pirate.name = name != null 53 | ? name 54 | : pirateNames[indexGen.nextInt(pirateNames.length)]; 55 | pirate.appellation = appellation != null 56 | ? appellation 57 | : pirateAppellations[ 58 | indexGen.nextInt(pirateAppellations.length)]; 59 | return truePirate(pirate) ? pirate : null; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /server/7-serve/lib/server/piratesapi.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | library pirate.server; 6 | 7 | import 'package:rpc/rpc.dart'; 8 | 9 | import '../common/messages.dart'; 10 | import '../common/utils.dart'; 11 | 12 | // This class defines the interface that the server provides. 13 | @ApiClass(version: 'v1') 14 | class PiratesApi { 15 | final Map _pirateCrew = {}; 16 | final PirateShanghaier _shanghaier = new PirateShanghaier(); 17 | 18 | PiratesApi() { 19 | var captain = new Pirate.fromString('Lars the Captain'); 20 | _pirateCrew[captain.toString()] = captain; 21 | } 22 | 23 | @ApiMethod(method: 'POST', path: 'pirate') 24 | Pirate hirePirate(Pirate newPirate) { 25 | // Make sure this is a real pirate... 26 | if (!truePirate(newPirate)) { 27 | throw new BadRequestError( 28 | '$newPirate cannot be a pirate. \'Tis not a pirate name!'); 29 | } 30 | var pirateName = newPirate.toString(); 31 | if (_pirateCrew.containsKey(pirateName)) { 32 | throw new BadRequestError( 33 | '$newPirate is already part of your crew!'); 34 | } 35 | 36 | // Add the pirate to the crew. 37 | _pirateCrew[pirateName] = newPirate; 38 | return newPirate; 39 | } 40 | 41 | @ApiMethod( 42 | method: 'DELETE', path: 'pirate/{name}/the/{appellation}') 43 | Pirate firePirate(String name, String appellation) { 44 | var pirate = new Pirate() 45 | ..name = Uri.decodeComponent(name) 46 | ..appellation = Uri.decodeComponent(appellation); 47 | var pirateName = pirate.toString(); 48 | if (!_pirateCrew.containsKey(pirateName)) { 49 | throw new NotFoundError('Could not find pirate \'$pirate\'! ' + 50 | 'Maybe they\'ve abandoned ship!'); 51 | } 52 | return _pirateCrew.remove(pirateName); 53 | } 54 | 55 | // Returns a list of the pirate crew. 56 | @ApiMethod(method: 'GET', path: 'pirates') 57 | List listPirates() { 58 | return _pirateCrew.values.toList(); 59 | } 60 | 61 | // Generates (shanghais) and returns a new pirate. 62 | // Does not add the new pirate to the crew. 63 | @ApiMethod(path: 'shanghai') // Default HTTP method is GET. 64 | Pirate shanghaiAPirate() { 65 | var pirate = _shanghaier.shanghaiAPirate(); 66 | if (pirate == null) { 67 | throw new InternalServerError('Ran out of pirates!'); 68 | } 69 | return pirate; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /server/7-serve/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: server_code_lab 2 | version: 0.1.0 3 | author: Dart Team 4 | description: Code-lab server sample. 5 | environment: 6 | sdk: '>=1.9.0 <2.0.0' 7 | dependencies: 8 | _discoveryapis_commons: ^0.1.0 9 | browser: ^0.10.0+2 10 | crypto: ^0.9.0 11 | http: ^0.11.1 12 | http_server: ^0.9.5+1 13 | logging_handlers: ^0.8.0 14 | rpc: ^0.5.0 15 | 16 | homepage: https://dart-lang.github.io/server/codelab/ 17 | -------------------------------------------------------------------------------- /server/7-serve/web/piratebadge.css: -------------------------------------------------------------------------------- 1 | @import url(//fonts.googleapis.com/css?family=Roboto&subset=latin,latin-ext); 2 | 3 | body { 4 | background-color: #f5f5f5; 5 | font-family: 'Roboto', sans-serif; 6 | font-size: 14px; 7 | font-weight: normal; 8 | line-height: 1.2em; 9 | margin: 15px; 10 | color: #424242; 11 | } 12 | h1 { 13 | font-weight: normal; 14 | font-size: 32px; 15 | margin-bottom: 30px; 16 | } 17 | button { 18 | font-family: inherit; 19 | font-size: 14px; 20 | margin: 20px auto 0; 21 | box-shadow: 0 1px 1.5px 0 rgba(0, 0, 0, 0.12), 0 1px 1px 0 rgba(0, 0, 0, 0.24); 22 | border-radius: 2px; 23 | border: none; 24 | padding: 6px 8px; 25 | text-transform: uppercase; 26 | background: #e3e3e3; 27 | color: black; 28 | outline: none; 29 | -webkit-transition: all 0.2s ease-in; 30 | transition: all 0.2s ease-in; 31 | display: block; 32 | } 33 | button[disabled] { 34 | background-color: #d8d8d8 !important; 35 | color: #a0a0a0 !important; 36 | } 37 | button:active { 38 | box-shadow: 0 10px 10px 0 rgba(0, 0, 0, 0.19), 0 6px 3px 0 rgba(0, 0, 0, 0.23); 39 | } 40 | button:not(:disabled) { 41 | cursor: pointer; 42 | } 43 | input[type="text"] { 44 | outline: none; 45 | font-family: inherit; 46 | font-size: 16px; 47 | border: none; 48 | border-bottom: 1px solid #ddd; 49 | background: none; 50 | } 51 | select { 52 | font-family: inherit; 53 | border: none; 54 | outline: none; 55 | background: white; 56 | } 57 | select:focus option:checked, select option:hover { 58 | background: linear-gradient(#000000, #000000); 59 | color: #bbb; 60 | } 61 | select option { 62 | border-bottom: 1px solid #d2d2d2; 63 | padding: 8px 6px; 64 | outline: none; 65 | } 66 | select option:checked { 67 | background: linear-gradient(#f0f0f0, #f0f0f0); 68 | } 69 | .widgets { 70 | padding-bottom: 20px; 71 | margin-bottom: 20px; 72 | margin-right: 20px; 73 | float: left; 74 | } 75 | .form { 76 | overflow: hidden; 77 | } 78 | .badge, .pirates { 79 | border-radius: 2px; 80 | font-size: 19px; 81 | width: 14em; 82 | text-align: center; 83 | white-space: nowrap; 84 | overflow: hidden; 85 | box-shadow: 0 1px 1.5px 0 rgba(0, 0, 0, 0.12), 0 1px 1px 0 rgba(0, 0, 0, 0.24); 86 | } 87 | .badge { 88 | background: #f44336; 89 | height: 7em; 90 | } 91 | .pirates { 92 | background: #2196f3; 93 | } 94 | .greeting { 95 | color: white; 96 | padding: 0.5em; 97 | font-size: 20px; 98 | } 99 | .name { 100 | color: black; 101 | background: white; 102 | font-family: "Marker Felt", cursive; 103 | font-size: 30px; 104 | padding: 1em 0; 105 | height: 16px; 106 | } 107 | #pirateList { 108 | width: 100%; 109 | height: 14em; 110 | } 111 | #generateButton { 112 | margin-bottom: 100px; 113 | } 114 | #storeButton { 115 | background: #2196f3; 116 | color: white; 117 | } 118 | #storeButton:hover { 119 | background: #1e88e5; 120 | } 121 | #storeButton:active { 122 | background: #1976d2; 123 | } 124 | #killButton { 125 | background: black; 126 | color: white; 127 | } 128 | #killButton:hover, 129 | #killButton:active { 130 | background: #212121; 131 | } 132 | #inputName { 133 | margin: 30px 0 0; 134 | width: 14em; 135 | padding: 5px 0; 136 | } 137 | #inputName + span { 138 | display: block; 139 | width: 10px; 140 | height: 2px; 141 | background: #2196f3; 142 | position: relative; 143 | top: -2px; 144 | left: 50%; 145 | visibility: hidden; 146 | -webkit-transition: all .2s ease-in; 147 | transition: all .2s ease-in; 148 | } 149 | #inputName:focus + span { 150 | width: 100%; 151 | left: 0; 152 | visibility: visible; 153 | } 154 | div::selection, button::selection { 155 | background: none; 156 | } 157 | div::-moz-selection, button::-moz-selection { 158 | background: none; 159 | } 160 | @media all and (max-width: 600px) { 161 | #generateButton { 162 | margin-bottom: 0; 163 | } 164 | } 165 | @media all and (max-width: 560px) { 166 | h1 { 167 | text-align: center; 168 | } 169 | .form { 170 | width: 16em; 171 | margin: 0 auto; 172 | } 173 | .widgets, .badge, .pirates, button, #inputName { 174 | float: none; 175 | margin-left: auto; 176 | margin-right: auto; 177 | } 178 | #inputName { 179 | width: 100%; 180 | } 181 | .widgets { 182 | margin-bottom: 50px; 183 | padding-bottom: 0; 184 | } 185 | } 186 | /* This is needed for proper ripple effect on buttons */ 187 | button { 188 | position: relative; 189 | overflow: hidden; 190 | } 191 | button .ripple { 192 | position: absolute; 193 | display: block; 194 | border-radius: 100%; 195 | width: 0; 196 | height: 0; 197 | pointer-events: none; 198 | background: rgba(0, 0, 0, .2); 199 | -webkit-transform: translate(-50%, -50%); 200 | transform: translate(-50%, -50%); 201 | } 202 | button .ripple.show { 203 | -webkit-animation: ripple .3s ease-in; 204 | animation: ripple .3s ease-in; 205 | } 206 | #storeButton .ripple, 207 | #killButton .ripple { 208 | background: rgba(255, 255, 255, .2); 209 | } 210 | @-webkit-keyframes ripple { 211 | from { 212 | width: 0; 213 | } 214 | to { 215 | width: 200%; 216 | padding-top: 200%; 217 | } 218 | } 219 | @keyframes ripple { 220 | from { 221 | width: 0; 222 | } 223 | to { 224 | width: 200%; 225 | padding-top: 200%; 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /server/7-serve/web/piratebadge.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, 2015 the Dart project authors. 2 | // Please see the AUTHORS file for details. All rights reserved. 3 | // Use of this source code is governed by a BSD-style license that can be 4 | // found in the LICENSE file. 5 | 6 | import 'dart:async'; 7 | import 'dart:html'; 8 | 9 | import 'package:http/browser_client.dart'; 10 | import 'package:server_code_lab/client/piratesapi.dart'; 11 | import 'package:server_code_lab/common/messages.dart'; 12 | import 'package:server_code_lab/common/utils.dart'; 13 | 14 | final String treasureKey = 'pirateName'; 15 | 16 | ButtonElement genButton; 17 | ButtonElement storeButton; 18 | ButtonElement fireButton; 19 | ButtonElement slayButton; 20 | SpanElement badgeNameElement; 21 | SelectElement pirateList; 22 | 23 | // By default the generated client code uses 24 | // 'http://localhost:8080/'. Since our server is running on 25 | // port 8088 we override the default url when instantiating 26 | // the generated PiratesApi class. 27 | final String _serverUrl = 'localhost:8088/'; 28 | final BrowserClient _client = new BrowserClient(); 29 | PiratesApi _api; 30 | PirateShanghaier _shanghaier; 31 | 32 | Future main() async { 33 | // We need to determine if the client is using http or https 34 | // and use the same protocol for the client stub requests 35 | // (the protocol includes the ':'). 36 | var protocol = window.location.protocol; 37 | if (!['http:', 'https:'].contains(protocol)) { 38 | // Default to http if unknown protocol. 39 | protocol = 'http:'; 40 | } 41 | _api = new PiratesApi(_client, rootUrl: '$protocol//$_serverUrl'); 42 | _shanghaier = new PirateShanghaier(); 43 | 44 | InputElement inputField = querySelector('#inputName'); 45 | inputField.onInput.listen(updateBadge); 46 | genButton = querySelector('#generateButton'); 47 | genButton.onClick.listen(generateBadge); 48 | inputField.disabled = false; //enable 49 | genButton.disabled = false; //enable 50 | badgeNameElement = querySelector('#badgeName'); 51 | storeButton = querySelector('#storeButton'); 52 | storeButton.onClick.listen(storeBadge); 53 | pirateList = querySelector('#pirateList'); 54 | pirateList.onClick.listen(selectListener); 55 | fireButton = querySelector('#fireButton'); 56 | fireButton.onClick.listen(removeBadge); 57 | slayButton = querySelector('#slayButton'); 58 | slayButton.onClick.listen(removeAllBadges); 59 | setBadgeName(getBadgeNameFromStorage()); 60 | refreshList(); 61 | 62 | var buttons = querySelectorAll("button"); 63 | buttons.onClick.listen(addRippleEffect); 64 | } 65 | 66 | Future refreshList() async { 67 | List pirates = await _api.listPirates(); 68 | pirateList.children.clear(); 69 | pirates.forEach((pirate) { 70 | var option = new OptionElement(data: pirate.toString()); 71 | pirateList.add(option, 0); 72 | }); 73 | 74 | var disabled = true; 75 | if (pirateList.length > 0) { 76 | disabled = false; 77 | } 78 | 79 | new Future.delayed(new Duration(milliseconds: 300), () { 80 | slayButton.disabled = disabled; 81 | }); 82 | } 83 | 84 | void updateBadge(Event e) { 85 | String inputName = (e.target as InputElement).value.trim(); 86 | var pirate = _shanghaier.shanghaiAPirate(name: inputName); 87 | setBadgeName(pirate); 88 | if (inputName.trim().isEmpty) { 89 | genButton 90 | ..disabled = false 91 | ..text = 'Aye! Gimme a name!'; 92 | storeButton..disabled = true; 93 | } else { 94 | genButton 95 | ..disabled = true 96 | ..text = 'Arrr! Write yer name!'; 97 | storeButton..disabled = false; 98 | } 99 | } 100 | 101 | Future storeBadge(Event e) async { 102 | var pirateName = badgeNameElement.text; 103 | if (pirateName == null || pirateName.isEmpty) return null; 104 | var pirate = new Pirate.fromString(pirateName); 105 | try { 106 | await _api.hirePirate(pirate); 107 | } catch (error) { 108 | window.alert(error.message); 109 | } 110 | new Future.delayed(new Duration(milliseconds: 300), () { 111 | storeButton 112 | ..disabled = true 113 | ..text = 'Pirate hired!'; 114 | }); 115 | refreshList(); 116 | } 117 | 118 | Future selectListener(Event e) async { 119 | fireButton.disabled = false; 120 | } 121 | 122 | Future removeBadge(Event e) async { 123 | var idx = pirateList.selectedIndex; 124 | if (idx < 0 || idx >= pirateList.options.length) return null; 125 | var option = pirateList.options.elementAt(idx); 126 | var pirate = new Pirate.fromString(option.label); 127 | try { 128 | await _api.firePirate(pirate.name, pirate.appellation); 129 | } catch (error) { 130 | window.alert(error.message); 131 | } 132 | new Future.delayed(new Duration(milliseconds: 300), () { 133 | fireButton.disabled = true; 134 | }); 135 | refreshList(); 136 | } 137 | 138 | Future removeAllBadges(Event e) async { 139 | for (var option in pirateList.options) { 140 | var pirate = new Pirate.fromString(option.label); 141 | try { 142 | await _api.firePirate(pirate.name, pirate.appellation); 143 | } catch (error) { 144 | // ignoring errors. 145 | } 146 | } 147 | new Future.delayed(new Duration(milliseconds: 300), () { 148 | fireButton.disabled = true; 149 | slayButton.disabled = true; 150 | }); 151 | refreshList(); 152 | } 153 | 154 | void generateBadge(Event e) { 155 | var pirate = _shanghaier.shanghaiAPirate(); 156 | setBadgeName(pirate); 157 | } 158 | 159 | void setBadgeName(Pirate pirate) { 160 | if (pirate == null || pirate.toString().isEmpty) { 161 | badgeNameElement.text = ''; 162 | storeButton.disabled = true; 163 | return; 164 | } 165 | badgeNameElement.text = pirate.toString(); 166 | window.localStorage[treasureKey] = pirate.toString(); 167 | storeButton 168 | ..disabled = false 169 | ..text = 'Hire pirate!'; 170 | } 171 | 172 | Pirate getBadgeNameFromStorage() { 173 | String storedName = window.localStorage[treasureKey]; 174 | if (storedName != null && storedName.contains(' the ')) { 175 | return new Pirate.fromString(storedName); 176 | } else { 177 | return null; 178 | } 179 | } 180 | 181 | void addRippleEffect(MouseEvent e) { 182 | var button = e.target as ButtonElement; 183 | var ripple = button.querySelector(".ripple"); 184 | 185 | // we need to delete existing ripple element 186 | if (ripple != null) { 187 | ripple.remove(); 188 | } 189 | 190 | var x = e.client.x - button.getBoundingClientRect().left; 191 | var y = e.client.y - button.getBoundingClientRect().top; 192 | 193 | ripple = new SpanElement() 194 | ..classes.add("ripple") 195 | ..style.left = "${x}px" 196 | ..style.top = "${y}px" 197 | ..classes.add("show"); 198 | 199 | button.append(ripple); 200 | } 201 | -------------------------------------------------------------------------------- /server/7-serve/web/piratebadge.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | 11 | 12 | 13 | Pirate badge 14 | 15 | 16 | 17 | 18 | 19 | 20 |

Pirate badge

21 | 22 |
23 |
24 | 25 | 26 |
27 |
28 | 29 |
30 |
31 |
32 |
33 |
34 | Arrr! Me name is 35 |
36 |
37 | 38 |
39 |
40 |
41 | 42 |
43 |
44 |
45 |
46 |
47 | Pirate crew! 48 |
49 | 50 |
51 |
52 | 53 |
54 |
55 | 56 |
57 |
58 | 59 | 60 | -------------------------------------------------------------------------------- /server/working-dir/bin/piratesnest.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | library piratesnest; 6 | 7 | import 'dart:async'; 8 | import 'dart:io'; 9 | 10 | import 'package:logging/logging.dart'; 11 | import 'package:rpc/rpc.dart'; 12 | 13 | import 'package:server_code_lab/server/piratesapi.dart'; 14 | 15 | final ApiServer _apiServer = new ApiServer(prettyPrint: true); 16 | 17 | Future main() async { 18 | // Add a bit of logging... 19 | Logger.root 20 | ..level = Level.INFO 21 | ..onRecord.listen(print); 22 | 23 | // Set up a server serving the pirate API. 24 | _apiServer.addApi(new PiratesApi()); 25 | HttpServer server = await HttpServer.bind(InternetAddress.ANY_IP_V4, 8088); 26 | server.listen((request) => _apiServer.httpRequestHandler(request)); 27 | print('Server listening on http://${server.address.host}:' 28 | '${server.port}'); 29 | } 30 | -------------------------------------------------------------------------------- /server/working-dir/lib/common/messages.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | library pirate.messages; 6 | 7 | // This class is used to send data back and forth between the 8 | // client and server. It is automatically serialized and 9 | // deserialized by the RPC package. 10 | class Pirate { 11 | String name; 12 | String appellation; 13 | 14 | // A message class must have a default constructor taking no 15 | // arguments. 16 | Pirate(); 17 | 18 | // It is fine to have other named constructors. 19 | Pirate.fromString(String pirateName) { 20 | var parts = pirateName.split(' the '); 21 | name = parts[0]; 22 | appellation = parts[1]; 23 | } 24 | 25 | @override 26 | String toString() => name.isEmpty ? '' : '$name the $appellation'; 27 | } 28 | -------------------------------------------------------------------------------- /server/working-dir/lib/common/utils.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | library pirate.utils; 6 | 7 | import 'dart:math' show Random; 8 | 9 | import 'messages.dart'; 10 | 11 | // Proper pirate names. 12 | const List pirateNames = const [ 13 | "Anne", "Bette", "Cate", "Dawn", "Elise", "Faye", "Ginger", 14 | "Harriot", "Izzy", "Jane", "Kaye", "Liz", "Maria", "Nell", 15 | "Olive", "Pat", "Queenie", "Rae", "Sal", "Tam", "Uma", 16 | "Violet", "Wilma", "Xana", "Yvonne", "Zelda", "Abe", 17 | "Billy", "Caleb", "Davie", "Eb", "Frank", "Gabe", "House", 18 | "Icarus", "Jack", "Kurt", "Larry", "Mike", "Nolan", 19 | "Oliver", "Pat", "Quib", "Roy", "Sal", "Tom", "Ube", 20 | "Val", "Walt", "Xavier", "Yvan", "Zeb" 21 | ]; 22 | 23 | // Proper pirate appellations. 24 | const List pirateAppellations = const [ 25 | "Awesome", "Captain", "Even", "Fighter", "Great", 26 | "Hearty", "Jackal", "King", "Lord", "Mighty", 27 | "Noble", "Old", "Powerful", "Quick", "Red", 28 | "Stalwart", "Tank", "Ultimate", "Vicious", 29 | "Wily", "aXe", "Young", "Brave", "Eager", 30 | "Kind", "Sandy", "Xeric", "Yellow", "Zesty" 31 | ]; 32 | 33 | // Clearly invalid pirate appellations. 34 | const List _forbiddenAppellations = const [ 35 | '', 'sweet', 'handsome', 'beautiful', 'weak', 'wuss', 36 | 'chicken', 'fearful' 37 | ]; 38 | 39 | // Helper method for validating whether the given pirate is truly a pirate! 40 | bool truePirate(Pirate pirate) => pirate.name != null && 41 | pirate.name.trim().isNotEmpty && 42 | pirate.appellation != null && 43 | !_forbiddenAppellations 44 | .contains(pirate.appellation.toLowerCase()); 45 | 46 | // Shared class for shanghaiing (generating) pirates. 47 | class PirateShanghaier { 48 | static final Random indexGen = new Random(); 49 | 50 | Pirate shanghaiAPirate({String name, String appellation}) { 51 | var pirate = new Pirate(); 52 | pirate.name = name != null 53 | ? name 54 | : pirateNames[indexGen.nextInt(pirateNames.length)]; 55 | pirate.appellation = appellation != null 56 | ? appellation 57 | : pirateAppellations[ 58 | indexGen.nextInt(pirateAppellations.length)]; 59 | return truePirate(pirate) ? pirate : null; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /server/working-dir/lib/server/piratesapi.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | library pirate.server; 6 | 7 | import 'package:rpc/rpc.dart'; 8 | 9 | import '../common/messages.dart'; 10 | import '../common/utils.dart'; 11 | 12 | // This class defines the interface that the server provides. 13 | class PiratesApi { 14 | final Map _pirateCrew = {}; 15 | final PirateShanghaier _shanghaier = new PirateShanghaier(); 16 | 17 | PiratesApi() { 18 | var captain = new Pirate.fromString('Lars the Captain'); 19 | _pirateCrew[captain.toString()] = captain; 20 | } 21 | 22 | // Returns a list of the pirate crew. 23 | List listPirates() { 24 | return _pirateCrew.values.toList(); 25 | } 26 | 27 | // Generates (shanghais) and returns a new pirate. 28 | // Does not add the new pirate to the crew. 29 | Pirate shanghaiAPirate() { 30 | var pirate = _shanghaier.shanghaiAPirate(); 31 | if (pirate == null) { 32 | throw new InternalServerError('Ran out of pirates!'); 33 | } 34 | return pirate; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /server/working-dir/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: server_code_lab 2 | version: 0.1.0 3 | author: Dart Team 4 | description: Code-lab server sample. 5 | environment: 6 | sdk: '>=1.9.0 <2.0.0' 7 | dependencies: 8 | _discoveryapis_commons: ^0.1.0 9 | browser: ^0.10.0+2 10 | crypto: ^0.9.0 11 | http: ^0.11.1 12 | logging_handlers: ^0.8.0 13 | rpc: ^0.5.0 14 | 15 | homepage: https://dart-lang.github.io/server/codelab/ 16 | --------------------------------------------------------------------------------