diff --git a/public_html/css/game.css b/public_html/css/game.css index df1b658..5b5176d 100644 --- a/public_html/css/game.css +++ b/public_html/css/game.css @@ -33,9 +33,9 @@ body { } /* line 34, C:\Users\Dmytro\Documents\NetBeansProjects\GameProto\public_html\less\game.less */ @media -sass-debug-info{filename{font-family:file\:\/\/C\:\/Users\/Dmytro\/Documents\/NetBeansProjects\/GameProto\/public_html\/less\/game\.less}line{font-family:\0000334}} -.score-bar ul li { +.score-bar ul li.score-item { border: 1px solid #a9a9a9; - padding: 10px; + padding: 7px; border-radius: 5px; display: inline-block; font-weight: bold; @@ -116,6 +116,7 @@ body { .controls { /*clear: both;*/ text-align: center; + margin-bottom: 5px; } .game-state-dioxide.badge { background-color: #000; @@ -163,8 +164,75 @@ body { .rating-desc .progress .progress-bar { width: 100%;} /* End Of NewCards */ +.game-move-number.badge.active { + background-color: #428BCA; +} /*Temporary hide description, until delete it from function*/ .card-description { display: none; } + +.game-screen {display:none;} +.avatar { + width: 141px; + height: 141px; + margin: 0 auto 20px auto; +} +.avatar.active { + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075) inset, 0 0 8px rgba(102, 175, 233, 0.6); + border-color: #66AFE9; +} +.user-info .avatar { + margin-bottom: 0; + width: 70px; + height: 70px; + background-size: 100% 100% !important; +} +.avatar.av-1 { + background: url(../static/images/av1.png) no-repeat center center; +} +.avatar.av-2 { + background: url(../static/images/av2.png) no-repeat center center; +} +.avatar.av-3 { + background: url(../static/images/av3.png) no-repeat center center; +} +.avatar.av-4 { + background: url(../static/images/av4.png) no-repeat center center; +} +.avatar.av-5 { + background: url(../static/images/av5.png) no-repeat center center; +} +.avatar.av-6 { + background: url(../static/images/av6.png) no-repeat center center; +} +.select-country { + display: inline-block; +} +.dropdown ul li { + text-align: left; +} + +.input-group.username { + margin-bottom: 10px; +} + +#starting.preload { + background-image: url(../static/images/preload.gif); + background-repeat: no-repeat; + background-position: center center; +} +#starting.preload > .row { + visibility: hidden; +} +.game-move-complete { + position: relative; + z-index: 1; +} +.foot-logo { + max-height: 50px; +} +.foot-logos { + max-width: 480px; +} \ No newline at end of file diff --git a/public_html/index.html b/public_html/index.html index 19b6a52..ac29b1d 100644 --- a/public_html/index.html +++ b/public_html/index.html @@ -10,47 +10,162 @@ - -
+ +
+
+ +
+
+
+

Start Game

+
+
+
+
+
+
+
+
+
+ +
+ +
+
+ @ + +
+
+
+
+ +
+
+ +
+
+ +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+ +
+
+ +
+
+
+
+ + +
+ + +
+
-
+
Step: - + 1 + 2 + 3 + 4 + 5 +
    -
  • +
  • -
  • +
  • -
  • +
  • -
  • +
  • -
  • +
-
+
-
+
+ + +
-
+

-
-

Available cards

-
+
+
+

Available cards

+
+
-
-

Cards in use

-
+
+
+

Cards in use

+
+
@@ -58,11 +173,37 @@

Cards in use

+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
- + + + diff --git a/public_html/js/app/app.js b/public_html/js/app/app.js index b7b3f4a..f432a3c 100644 --- a/public_html/js/app/app.js +++ b/public_html/js/app/app.js @@ -1,5 +1,12 @@ -define(["app/model", "app/view", "app/rules", "app/disasters", "app/cards", "app/i18n-ui", "jquery"], - function(model, view, rules, disasters, cards, translator, $) { +define(["app/model", + "app/view", + "app/rules", + "app/disasters", + "app/cards", + "app/i18n-ui", + "app/history", + "jquery"], + function(model, view, rules, disasters, cards, translator, history, $) { function GameListener(view) { @@ -8,7 +15,10 @@ define(["app/model", "app/view", "app/rules", "app/disasters", "app/cards", "app }; this.onGameOver = function(event) { - view.gameOver(event); + if (history.enabled()){ + history.save(event.snapshot); + } + view.gameOver(event, history); }; this.onDisaster = function(event) { @@ -29,18 +39,68 @@ define(["app/model", "app/view", "app/rules", "app/disasters", "app/cards", "app } $(document).ready(function() { - + $('#starting').removeClass('preload'); translator.translateUI(); + var player = new model.Player(); var game = new model.Game({ rules: rules, cards: cards, - disasters: disasters + disasters: disasters, + player: player }); + var welcome = new view.Welcome(player); var v = new view.View(game); game.addListener(new GameListener(v)); - game.start(); + + $('.select-avatar .av-1').addClass('active'); + $('.user-info .avatar').attr('class', 'avatar').addClass('av-1'); + player.avatar("av-1"); + + $('#starting input').change(function(){ + var username = $('.username input').val(); + if (username != '' && $('.select-avatar .avatar.active').length) { + player.name(username); + $('.btn.start-game').removeClass('disabled'); + } else { + $('.btn.start-game').addClass('disabled'); + } + }); + //var history = require("app/history"); + var results = history.get(), lineResult; + + if (results) { + var statistic = '

'+t('Statistic')+'

'; + for (var key in results) { + var lineResult = results[key]; + statistic += '
'; + statistic += makeSpan('
'); + statistic += makeSpan(lineResult.player.name + '
' + lineResult.player.region); + var resources = ''; + for (var i in lineResult.resources) { + resources += t(i) + ': ' + lineResult.resources[i] + '
'; + } + statistic += makeSpan(resources); + statistic += '
'; + } + statistic += '
'; + $('#starting > .row').append(statistic); + } + + function makeSpan(html) { + return '
'+html+'
'; + } + + $('.start-game').on('click', function(){ + if ($('.username input').val() != '' && $('.select-avatar .avatar.active').length) { + $('.user-info .user-name span.name').html($('.username input').val()); + + game.start(); + $('.welcome-screen').hide(); + $('.game-screen').show(); + } + }); }); } diff --git a/public_html/js/app/disasters.js b/public_html/js/app/disasters.js index 0d52e06..2a82951 100644 --- a/public_html/js/app/disasters.js +++ b/public_html/js/app/disasters.js @@ -3,7 +3,35 @@ define(["app/model", "app/i18n"], function(model, translator) { flood: new model.Disaster({ name: t("Flood"), type: "bad", + image: "flood.jpg", description: t("Water level increases. It flows over fields reducing food amount. Drinking water becomes polluted with mud. Money spent to resolve problems"), + probability: function(game) { + return 99; + }, + effect: function(game) { + game.resources.money -= 100; + game.resources.water -= 10; + game.resources.food -= 10; + }, + }), + drought: new model.Disaster({ + name: t("Drought"), + type: "bad", + description: t("drought"), + probability: function(game) { + return game.resources.dioxide / 20; + }, + effect: function(game) { + game.resources.money -= 100; + game.resources.water -= 10; + game.resources.food -= 10; + }, + image: 'drought.jpg' + }), + hurricane: new model.Disaster({ + name: t("Hurricane"), + type: "bad", + description: t("hurricane"), probability: function(game) { return game.resources.dioxide / 20; }, @@ -11,7 +39,8 @@ define(["app/model", "app/i18n"], function(model, translator) { game.resources.money -= 100; game.resources.water -= 10; game.resources.food -= 10; - } - }) + }, + image: 'hurricane.jpg' + }), }; }); diff --git a/public_html/js/app/history.js b/public_html/js/app/history.js new file mode 100644 index 0000000..fbcb712 --- /dev/null +++ b/public_html/js/app/history.js @@ -0,0 +1,44 @@ +define(["app/model"], function(Model){ + + function GameHistory(){ + + var key = "_eco_game_history"; + var storage = window.localStorage; + var snapshots = JSON.parse(storage.getItem(key)) || []; + var _capacity = 10; + + function save(){ + storage.setItem(key, JSON.stringify(snapshots)); + } + + this.enabled = function(){ + return storage !== undefined; + }, + + this.save = function(snapshot){ + snapshots.unshift(snapshot); + while (snapshots.length > _capacity){ + snapshots.pop(); + } + save(); + }; + + this.get = function(){ + return snapshots; + }; + + this.clear = function(){ + snapshots = []; + save(); + }; + + this.capacity = function(){ + return _capacity; + }; + + + } + + return new GameHistory(); + +}); \ No newline at end of file diff --git a/public_html/js/app/i18n/ru.js b/public_html/js/app/i18n/ru.js index e852085..eac1b42 100644 --- a/public_html/js/app/i18n/ru.js +++ b/public_html/js/app/i18n/ru.js @@ -47,7 +47,24 @@ define(["app/i18n"], function(translator) { "Food": "Пища", "Dioxide": "CO²", "You cannot take more than":"Ви не можете взяти больше чем", - "cards":"карт" + "cards":"карт", + "You lost":"Ви проиграли", + "You won!!!":"Ви выиграли!", + "Rules":"Правила", + "Rules of Game":"Правила игры", + "Start Game":"Старт игры", + "Сlimate Change":"Смена климата", + "Vocabulary":"Словарь", + "Select region":"Выберите регіон", + "Australia":"Австралия", + "Asia":"Азия", + "Africa":"Африка", + "Europe":"Европа", + "North America":"Северная Америка", + "South America":"Южная Америка", + "Home":"К началу", + "Start Game":"Начало игры", + "Created by":"Разработка:" }); }); diff --git a/public_html/js/app/i18n/ua.js b/public_html/js/app/i18n/ua.js index 3ebd85d..12b4741 100644 --- a/public_html/js/app/i18n/ua.js +++ b/public_html/js/app/i18n/ua.js @@ -47,7 +47,24 @@ define(["app/i18n"], function(translator){ "Food":"Їжа", "Dioxide":"CO²", "You cannot take more than":"Ви не можете взяти більше ніж", - "cards":"карток" + "cards":"карток", + "You lost":"Ви програли", + "You won!!!":"Ви перемогли!", + "Rules":"Правила", + "Rules of Game":"Правила гри", + "Start Game":"Старт гри", + "Сlimate Change":"Зміна клімату", + "Vocabulary":"Словник", + "Select region":"Оберіть регіон", + "Australia":"Австралія", + "Asia":"Азія", + "Africa":"Африка", + "Europe":"Європа", + "North America":"Північна Америка", + "South America":"Південна Америка", + "Home":"На початок", + "Start Game":"Початок гри", + "Created by":"Розробка:" }); }); diff --git a/public_html/js/app/model.js b/public_html/js/app/model.js index 5ca3843..f03481d 100644 --- a/public_html/js/app/model.js +++ b/public_html/js/app/model.js @@ -180,6 +180,10 @@ define([], function() { this.effect = function(game) { return disaster.effect.call(disaster, game); }; + + this.image = function() { + return disaster.image; + }; } function Game(options) { @@ -189,6 +193,7 @@ define([], function() { var move; var gameOver = false; var movesCompleted = []; + var player; var disasters = []; var rules = []; @@ -214,6 +219,8 @@ define([], function() { deck.putCard((options.cards[cardKey])); } } + + player = options.player; }; @@ -223,10 +230,10 @@ define([], function() { this.resources = { money: 1000, - energy: 20, - water: 20, - food: 30, - dioxide: 5 + energy: 40, + water: 60, + food: 50, + dioxide: 40 }; this.start = function() { @@ -245,6 +252,10 @@ define([], function() { }; this.completeMove = function() { + if (this.moveNumber() > 4 && !gameOver) { + this.win(t("You won!!!")); + return; + } applyCards(); checkDisasters(); checkRules(); @@ -307,14 +318,28 @@ define([], function() { } }; + function snapshot(result, reason){ + return { + resources: self.resources, + result: result, + reason: reason, + player: { + name: player.name(), + avatar: player.avatar(), + region: player.region() + }, + move: self.moveNumber() + }; + } + this.lose = function(reason) { - gameOver = true; - notify("onGameOver", {result: "lose", reason: reason}); + gameOver = true; + notify("onGameOver", {result: "lose", reason: reason, snapshot: snapshot("lose", reason)}); }; this.win = function(reason) { gameOver = true; - notify("onGameOver", {result: "win", reason: reason}); + notify("onGameOver", {result: "win", reason: reason, snapshot: snapshot("win", reason)}); }; this.addListener = function(listener) { @@ -358,6 +383,7 @@ define([], function() { }; } + function Rule(rule) { this.isApplicable = function(game) { @@ -369,6 +395,34 @@ define([], function() { }; } + function Player(name, avatar, region){ + var _name = name, + _avatar = avatar, + _region = region; + + this.name = function(newName){ + if (newName){ + _name = newName; + } + return _name; + }; + + this.avatar = function(newAvatar){ + if (newAvatar){ + _avatar = newAvatar; + } + return _avatar; + }; + + this.region = function(newRegion){ + if (newRegion){ + _region = newRegion; + } + return _region; + }; + + } + return { Card: Card, Deck: Deck, @@ -377,7 +431,8 @@ define([], function() { Disaster: Disaster, Rule: Rule, Effect: Effect, - WeightedValueCalculator: WeightedValueCalculator + WeightedValueCalculator: WeightedValueCalculator, + Player: Player }; }); diff --git a/public_html/js/app/rules.js b/public_html/js/app/rules.js index 23a9bee..f71f69c 100644 --- a/public_html/js/app/rules.js +++ b/public_html/js/app/rules.js @@ -3,11 +3,20 @@ define(["app/model"], function(model) { dioxideBelowThresholdRule: new model.Rule({ threshold: 1, condition: function(game) { - return game.resources.dioxide <= this.threshold; + //must make 5 steps, winn if end of game deoxide less trashold + return game.moveNumber() > 4 && game.resources.dioxide <= this.threshold; }, effect: function(game) { game.win(t("You dioxide level is below ") + this.threshold); }}), + dioxideUpperThresholdRule: new model.Rule({ + maxlevel: 50, + condition: function(game) { + return game.resources.dioxide > this.maxlevel; + }, + effect: function(game) { + game.lose(t("You dioxide level is high ") + this.maxlevel); + }}), lackOfResourcesLosesGame: new model.Rule({ condition: function(game) { return game.resources.money <= 0 || diff --git a/public_html/js/app/view.js b/public_html/js/app/view.js index ffb24f1..3e09744 100644 --- a/public_html/js/app/view.js +++ b/public_html/js/app/view.js @@ -1,5 +1,22 @@ define(["jquery"], function($) { + function Welcome(player) { + var self = this; + $('.select-country ul li a').on('click', function(){ + var country = $(this).html(); + $('.select-country button').html(country + ' '); + $('.user-info .country').html(country); + player.region($(this).text()); + }); + $('.select-avatar .avatar').on('click', function(){ + $('.select-avatar .avatar').removeClass('active'); + $(this).addClass('active'); + var avatar = $(this).data("avatar"); + player.avatar(avatar); + $('.user-info .avatar').attr('class', 'avatar').addClass(avatar); + }); + } + function View(game) { var self = this; $(".game-move-complete").click(function() { @@ -18,15 +35,14 @@ define(["jquery"], function($) { }; this.renderMoveNumber = function() { - $(".game-move-number").text(game.moveNumber()); + $(".game-move-number").removeClass('active').eq(game.moveNumber() - 1).addClass('active'); }; this.renderResources = function() { - $(".game-state-money").text(game.resources.money); - $(".game-state-energy").text(game.resources.energy); - $(".game-state-food").text(game.resources.food); - $(".game-state-water").text(game.resources.water); - $(".game-state-dioxide").text(game.resources.dioxide); + //['money', 'energy', 'food', 'water', 'dioxide'] => game.availableResources() + $.each(['money', 'energy', 'food', 'water', 'dioxide'], function(index, resource){ + $(".game-state-" + resource).text(game.resources[resource]); + }); }; this.renderCards = function() { @@ -96,32 +112,38 @@ define(["jquery"], function($) { return template; }; - this.gameOver = function(event) { + this.gameOver = function(event, history) { $(".game-screen").hide(); $(".game-result-screen").removeClass("hidden"); var resultText; var resultClass; if (event.result === "lose") { - resultText = "You lost"; + resultText = t("You lost"); resultClass = "alert-danger"; } else { - resultText = "You won!!!"; + resultText = t("You won!!!"); resultClass = "alert-success"; } - $(".game-result").text(resultText).addClass(resultClass); + var resourceHTML = '
'; + for (var key in game.resources) { + resourceHTML += ': ' + game.resources[key] + '
'; + } + $(".game-result").html(resultText).addClass(resultClass); if (event.reason) { - $(".game-result-reason").text(event.reason).addClass(resultClass); + $(".game-result-reason").html(event.reason + resourceHTML).addClass(resultClass); } }; this.showDisasterNotification = function(event) { var disaster = event.disaster; - $(".game-disaster-name").text(disaster.name()); - $(".game-disaster-description").text(disaster.description()); - var disasterViewClass = (event.disaster.type() === "bad") ? " alert-danger" : "alert-success"; - $(".game-disaster").addClass(disasterViewClass).show(); + var disasterViewClass = (disaster.type() === "bad") ? " alert-danger" : "alert-success"; + var modalWindow = ''; + $('body').append(modalWindow); + $('#modalWindow').modal(); }; this.onFinishMove = function(event) { @@ -138,7 +160,9 @@ define(["jquery"], function($) { }; } - - return {View: View}; + String.prototype.capitalize = function() { + return this.charAt(0).toUpperCase() + this.slice(1); + } + return {View: View, Welcome: Welcome}; }); \ No newline at end of file diff --git a/public_html/js/config.js b/public_html/js/config.js index 4c8361b..aa4ee78 100644 --- a/public_html/js/config.js +++ b/public_html/js/config.js @@ -4,7 +4,7 @@ requirejs.config({ baseUrl: "js/libs", paths: { - app: "../app" + app: "../app", }, shim: { "jquery": { diff --git a/public_html/static/images/JRtzVytQiI4.jpg b/public_html/static/images/JRtzVytQiI4.jpg new file mode 100644 index 0000000..7977081 Binary files /dev/null and b/public_html/static/images/JRtzVytQiI4.jpg differ diff --git a/public_html/static/images/av1.png b/public_html/static/images/av1.png new file mode 100644 index 0000000..85227d0 Binary files /dev/null and b/public_html/static/images/av1.png differ diff --git a/public_html/static/images/av2.png b/public_html/static/images/av2.png new file mode 100644 index 0000000..93e560f Binary files /dev/null and b/public_html/static/images/av2.png differ diff --git a/public_html/static/images/av3.png b/public_html/static/images/av3.png new file mode 100644 index 0000000..af69757 Binary files /dev/null and b/public_html/static/images/av3.png differ diff --git a/public_html/static/images/av4.png b/public_html/static/images/av4.png new file mode 100644 index 0000000..4cbc396 Binary files /dev/null and b/public_html/static/images/av4.png differ diff --git a/public_html/static/images/av5.png b/public_html/static/images/av5.png new file mode 100644 index 0000000..60676ed Binary files /dev/null and b/public_html/static/images/av5.png differ diff --git a/public_html/static/images/av6.png b/public_html/static/images/av6.png new file mode 100644 index 0000000..133ce96 Binary files /dev/null and b/public_html/static/images/av6.png differ diff --git a/public_html/static/images/logo.jpg b/public_html/static/images/logo.jpg new file mode 100644 index 0000000..a15b373 Binary files /dev/null and b/public_html/static/images/logo.jpg differ diff --git a/public_html/static/images/logo_01.jpg b/public_html/static/images/logo_01.jpg new file mode 100644 index 0000000..186a22a Binary files /dev/null and b/public_html/static/images/logo_01.jpg differ diff --git a/public_html/static/images/logo_02.jpg b/public_html/static/images/logo_02.jpg new file mode 100644 index 0000000..177d63d Binary files /dev/null and b/public_html/static/images/logo_02.jpg differ diff --git a/public_html/static/images/logo_03.jpg b/public_html/static/images/logo_03.jpg new file mode 100644 index 0000000..d56ecc6 Binary files /dev/null and b/public_html/static/images/logo_03.jpg differ diff --git a/public_html/static/images/logo_04.jpg b/public_html/static/images/logo_04.jpg new file mode 100644 index 0000000..ca68fd9 Binary files /dev/null and b/public_html/static/images/logo_04.jpg differ diff --git a/public_html/static/images/logo_05.jpg b/public_html/static/images/logo_05.jpg new file mode 100644 index 0000000..98d8481 Binary files /dev/null and b/public_html/static/images/logo_05.jpg differ diff --git a/public_html/static/images/logo_06.jpg b/public_html/static/images/logo_06.jpg new file mode 100644 index 0000000..8e124a7 Binary files /dev/null and b/public_html/static/images/logo_06.jpg differ diff --git a/public_html/static/images/logo_07.jpg b/public_html/static/images/logo_07.jpg new file mode 100644 index 0000000..3a16dc1 Binary files /dev/null and b/public_html/static/images/logo_07.jpg differ diff --git a/public_html/static/images/logo_08.jpg b/public_html/static/images/logo_08.jpg new file mode 100644 index 0000000..d14d2ab Binary files /dev/null and b/public_html/static/images/logo_08.jpg differ diff --git a/public_html/static/images/pl-icon.png b/public_html/static/images/pl-icon.png new file mode 100644 index 0000000..d413d01 Binary files /dev/null and b/public_html/static/images/pl-icon.png differ diff --git a/public_html/static/images/preload.gif b/public_html/static/images/preload.gif new file mode 100644 index 0000000..d84f653 Binary files /dev/null and b/public_html/static/images/preload.gif differ diff --git a/public_html/static/images/ru-icon.png b/public_html/static/images/ru-icon.png new file mode 100644 index 0000000..47da421 Binary files /dev/null and b/public_html/static/images/ru-icon.png differ diff --git a/public_html/static/images/uk-icon.png b/public_html/static/images/uk-icon.png new file mode 100644 index 0000000..09563a2 Binary files /dev/null and b/public_html/static/images/uk-icon.png differ diff --git a/public_html/static/resources/climat_uk.htm b/public_html/static/resources/climat_uk.htm new file mode 100644 index 0000000..f3aa335 --- /dev/null +++ b/public_html/static/resources/climat_uk.htm @@ -0,0 +1,23 @@ + \ No newline at end of file diff --git a/public_html/static/resources/rules_uk.htm b/public_html/static/resources/rules_uk.htm new file mode 100644 index 0000000..1770dfa --- /dev/null +++ b/public_html/static/resources/rules_uk.htm @@ -0,0 +1,41 @@ + \ No newline at end of file diff --git a/public_html/static/resources/vocabulary_uk.htm b/public_html/static/resources/vocabulary_uk.htm new file mode 100644 index 0000000..16c4bd8 --- /dev/null +++ b/public_html/static/resources/vocabulary_uk.htm @@ -0,0 +1,28 @@ + \ No newline at end of file diff --git a/test/unit/history-test.js b/test/unit/history-test.js new file mode 100644 index 0000000..af82de8 --- /dev/null +++ b/test/unit/history-test.js @@ -0,0 +1,54 @@ +define(["app/history"], function(history){ + + describe("History", function(){ + it("should be enabled only if local storage is available", function(){ + expect(history.enabled()).toBe(window.localStorage !== undefined); + }); + }); + + describe("History", function(){ + + beforeEach(function(){ + history.clear(); + }); + + it("should save result to local storage", function(){ + var snapshot = {resources: {water: 100, money: 200}}; + history.save(snapshot); + var snapshots = history.get(); + expect(snapshots).toContain(snapshot); + }); + + it("should save multiple resutls to local storage", function(){ + var snapshot_1 = {resources: {water: 100, money: 200}}; + var snapshot_2 = {resources: {food: 300, money: 100}}; + history.save(snapshot_1); + history.save(snapshot_2); + var snapshots = history.get(); + expect(snapshots).toContain(snapshot_1); + expect(snapshots).toContain(snapshot_2); + }); + + it("should remove all snapshots on clear call", function(){ + history.clear(); + var snapshots = history.get(); + expect(snapshots.length).toBe(0); + }); + + it("should save up to 10 snapshots", function(){ + var firstSnapshot = {value: 0}; + var lastSnapshot = {value: history.capacity()}; + for(var i = 0; i < history.capacity(); i++){ + var snapshot = { value: i }; + history.save(snapshot); + }; + history.save(lastSnapshot); + var snapshots = history.get(); + expect(snapshots).toContain(lastSnapshot); + expect(snapshots).not.toContain(firstSnapshot); + }); + }); + + + +}); \ No newline at end of file