JavaScript ライブラリーを使い倒そう #buildinsider
Upcoming SlideShare
Loading in...5
×
 

JavaScript ライブラリーを使い倒そう #buildinsider

on

  • 7,496 views

2013/06/08

2013/06/08
第1回Build Insider OFFLINE講演資料

Statistics

Views

Total Views
7,496
Views on SlideShare
6,750
Embed Views
746

Actions

Likes
24
Downloads
50
Comments
0

9 Embeds 746

http://www.buildinsider.net 500
https://twitter.com 119
http://192.168.1.131 39
https://cybozulive.com 29
http://www29.atwiki.jp 23
http://triweb.hits.unisys.co.jp 20
http://s.deeeki.com 13
http://server01 2
http://intra-cm01.tx-bb.local 1
More...

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

CC Attribution License

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

JavaScript ライブラリーを使い倒そう #buildinsider JavaScript ライブラリーを使い倒そう #buildinsider Presentation Transcript

  • JavaScript ライブラリーを使い倒そう~2013/06/08 第1回Build Insider OFFLINE講演資料~Wingsプロジェクト安西 剛http://www.wings.msn.to/
  • 2自己紹介安西 剛(やすにし つよし)@tsuyokWingsプロジェクトNECビッグローブ在籍マイブームはDDD
  • 3 3
  • 4質問• A:デザイナ、マネージャ等 非エンジニア• B:主にサーバエンジニアで、たまにブラウザのJSを書く• C:サーバサイドのJSを書いている• D:すべての機能をJSだけで書いている• E:10人以上のJavaScriptチームで一つのプロダクトを開発している
  • 5セッションのゴール• JavaScriptのライブラリを知る• ライブラリからJavaScriptの動向を知る• 動向から今日の見所のセッションを知るJavaScriptがもっと書きたくなる!
  • 6アジェンダ1. JavaScriptが置かれた背景2. 手間を省こう系3. 言語特性補う系4. フレームワーク5. ゲーム系6. サーバ系7. 開発効率化系(JavaScriptのテスト)8. まとめ
  • 7 7まず前フリ
  • 8 8http://www.flickr.com/photos/mujitra/3556469060/かつてのWeb
  • 9かつてのWebはJavaScriptは邪魔者• ブラウザのJavaScript仕様が違う• そもそもバグが…• ダイヤルアップ接続のため、多くのそして大きいファイルをダウンロードすると重くなるページはシンプルにJavaScriptはできるだけ使わない
  • 10 10http://www.flickr.com/photos/moneyblognewz/5300999179/そこで登場
  • 11 11https://maps.google.co.jp/「Ajax」登場
  • 12Webページも表現豊かに• GoogleMapsがきっかけにAjaxが注目• 「非同期」通信• JavaScriptをみんなが使い始めた• Webページがアプリケーションらしくなってきたやっていいんだ!
  • 13 13時は進み
  • 14 14http://commons.wikimedia.org/wiki/User:Zach_Vegahttp://developer.android.com/distribute/googleplay/promote/brand.htmlhttp://windows.microsoft.com/ja-jp/windows-8/meethttp://www.w3.org/html/logo/index.htmlhttp://nodejs.org/logos/http://www.mozilla.jp/firefoxos/JavaScript天国がやってきた!
  • 15 15その分
  • 16 16http://www.flickr.com/photos/robellisphotography/6057722540/大量なコード
  • 17 17http://www.flickr.com/photos/bitterjug/7670055210/複雑化
  • 18 18http://www.flickr.com/photos/xlordashx/2942697333しんどい
  • 19 19http://www.flickr.com/photos/paul_lowry/2266388742/ライブラリが重要!
  • 20今日お話するライブラリ1.手間を省こう系2.言語特性補う系3.フレームワーク4.ゲーム系5.サーバ系6.開発効率化系
  • 21 21(1)手間を省こう系
  • 22手間を省こう系1.jQuery、prototype.js2.UI系• 個別ライブラリ• jQueryUI3.UIフレームワーク• TwitterBootstrap4.ページ表示速度に気をつけよう
  • 23手間を省こう系1.jQuery、prototype.js2.UI系• 個別ライブラリ• jQueryUI3.UIフレームワーク• TwitterBootstrap4.ページ表示速度に気をつけよう
  • 24jQuery、prototype.js• JavaScriptとHTMLの相互作用を強化するJavaScriptライブラリ。• クロスブラウザでも同様の記述方法で処理が可能
  • 25手間を省こう系1.jQuery、prototype.js2.UI系• 個別ライブラリ• jQueryUI3.UIフレームワーク• TwitterBootstrap4.ページ表示速度に気をつけよう
  • 26UI系のライブラリ• JavaScript、CSS、HTMLをできるだけ書かないというコンセプト• JavaScriptファイルを読み込み、HTML及び少量のJavaScriptコードで機能を実現する• ピュアなJavaScriptのみで動作するライブラリやjQueryのプラグインとして動作するライブラリなどがある• 大量に存在する
  • 27UI系のライブラリ• Chosen(かっこいいセレクトボックス)• 竹取JS(縦書)• FullCalendar(GoogleCalendarライクなカレンダー)• jqPlot(グラフを表現)など・・・
  • 28jQueryUI• jQuery UIは、jQueryを拡張するプラグインの一種で、ユーザインターフェイス(UI)に関わる機能を多く提供分類 機能名 概要InteractionsDraggable 要素をドラッグ可能にするDroppable 要素をドロップ可能にするResizable 要素をサイズ変更できるようにするSelectable 要素をマウス操作で選択できるようにするSortable 要素の並べ替えを可能にするWidgetsAccordion アコーディオンパネルAutocomplete オートコンプリート機能Button ボタンDatepicker 日付入力ボックスDialog ダイアログMenu メニューProgressbar プログレス(進捗)バーSlider スライダーSpinner スピナーTabs タブパネルTooltip ツールチップEffectsEffect 基本的なアニメーションColor Animation 色を変化させるアニメーションToggle/Hide/Show 要素の表示/非表示にアニメーションを利用Toggle Class/Add Class/Remove Class/Switch Classスタイルクラスの適用/解除にアニメーションを利用
  • 29jQueryUI• jQueryUIのサイトでデザインのカスタマイズが可能http://jqueryui.com/themeroller/
  • 30手間を省こう系1.jQuery、prototype.js2.UI系• 個別ライブラリ• jQueryUI3.UIフレームワーク• TwitterBootstrap4.ページ表示速度に気をつけよう
  • 31UIフレームワーク系• JavaScriptもCSSも書かずに、HTMLだけでレイアウトや動的なUI処理などを行い、開発を短縮• JavaScriptが苦手な(例えばデザイナーさん)方も動的なUIが表現できる• デザインやCSSが苦手なエンジニアの方もHTMLを書くだけで整ったデザインのサイトを作成することができる• CSSフレームワークとも呼ばれている• その代わり、デフォルトでは限定的なデザイン
  • 32TwitterBootstrap• Twitter社が開発しているフレームワーク• 定義されているClassをHTMLに指定するだけで、グリッドレイアウトや動的なUIコンポーネントを表現できる1 1 1 1 1 1 1 1 1 1 1 12 2 2 2 2 24 5 34 84 5 + offset312分割されたグリッドレイアウト
  • 33その他jQueryMobile
  • 34 34あとは
  • 35 35
  • 36手間を省こう系1.jQuery、prototype.js2.UI系• 個別ライブラリ• jQueryUI3.UIフレームワーク• TwitterBootstrap4.ページ表示速度に気をつけよう
  • 37ページ表示速度に注意!基礎的なページ表示速度のポイント(コーディングではない)
  • 38 38(2)言語特性補う系
  • 39 39JavaScriptの特性
  • 40この答えは?var foo = function(){var a = 3, b = 5;var bar = function() {var b = 7, c = 11;a += b + c;}bar();// a と b はどうなっている?} JavaScript The Good Parts(Douglas Crockford著 オライリー社)より
  • 41これはなんという?var myObject = (function() {var value = 0;return {increment : function (inc) {value += typeof inc === ‘number’ ? inc : 1;},getValue : function() {return value;}}()); JavaScript The Good Parts(Douglas Crockford著 オライリー社)より
  • 42言語特性の特殊性• プロトタイプベースのオブジェクト指向(プロトタイプチェーン)• スコープチェーン• コールバック(関数をパラメータ渡せる、など)など…
  • 43 43CoffeeScript
  • 44CoffeeScript• JavaScriptの言語特性のよくある「罠」を自動的に回避• JavaScriptにコンパイルして実行する(node.jsでコンパイル可能なコマンドをインストール)• クラスベースのオブジェクト指向をサポート
  • 45CoffeeScript(罠回避)###複数行に渡るコメント#### 単行のコメント# セミコロンは不要x = 1# 演算子(==ではなくis)の違いif x is 1# ブロック(JavaScriptでいう「{...}」)はインデントで表現# 関数の実行はカッコがあっても無くても良いalert("Hello World!")alert "Hello World!"// Generated by CoffeeScript 1.4.0/*複数行に渡るコメント*/(function() {var x;x = 1;if (x === 1) {alert("Hello World!");alert("Hello World!");}}).call(this);
  • 46CoffeeScript(クラスベースのOO)###クラス型オブジェクト指向#### クラス宣言class Member# 変数の宣言yasunishi: Hello # publicなインスタンス変数@yamada: Hello # publicなstatic変数takano = Hello # privateなstatic変数# コンストラクタ(@を付けることで引数をインスタンス変数に格納)constructor: (@yasunishi) -># メンバ関数func: ->@yasunishi # publicなインスタンス変数へアクセスMember.yamada # publicなstatic変数へアクセスtakano # privateなstatic変数へアクセスMember = (function() {var takano;Member.prototype.yasunishi = Hello;Member.yamada = Hello;takano = Hello;function Member(yasunishi) {this.yasunishi = yasunishi;}Member.prototype.func = function() {this.yasunishi;Member.yamada;return takano;};Member.staticfunc = function() {return this.yamada;};return Member;})();(下の続き)# staticなメンバ関数@staticfunc: -># staticな関数からstaticなプロパティへは@でアクセスできる@yamada
  • 47その他• Dart• Kotlin• Haxe• TypeScript
  • 48 48(3)フレームワーク
  • 49JavaScriptフレームワーク背景• JavaScriptソフトウェアの複雑化、大規模化• 多くの人数での開発が必要になっている• 設計上サーバサイドとの役割分担が重要
  • 50JavaScriptフレームワークポイント• HTMLとの関係性がポイント• サーバサイドと違い、マウスなどイベントがあるため、MVCと言われているが、サーバサイドのMVCとは考え方が違う• フレームワークによって、MVCの責務(そもそもMVCと言えるか?も含め)に差異がある• ということで、デファクトと言い切れるライブラリが無い
  • 51JavaScriptフレームワークhttp://caliper.io/blog/2013/Javascript-Framework-Popularity/
  • 52フレームワークの分類• MVCフレームワーク• Backbone.js• MVVMフレームワーク• Knockout• CoffeScript対応MVCフレームワーク(クラスベースのOO)• Batman.js• Spine.js• ViewとModelのデータバインディング• Angular.js• Ember.js• イベント管理、非同期処理• RxJS
  • 53フレームワークの分類• MVCフレームワーク• Backbone.js• MVVMフレームワーク• Knockout• CoffeScript対応MVCフレームワーク(クラスベースのOO)• Batman.js• Spine.js• ViewとModelのデータバインディング• Angular.js• Ember.js• イベント管理、非同期処理• RxJS
  • 54Ember.js• ビューとコントローラーを紐付け、HTMLDOM更新部分を省略し、シンプルに記述することができるフレームワーク(データバインディング)• DOMの更新は煩雑になりやすいため、ビューとJavaScriptコードが行うことを明確に分割でき、可読性を上げることができる。• テンプレートエンジンは、handlebars。
  • 55Ember.js 簡単なサンプルvar App = Ember.Application.create();App.ApplicationController = Ember.ArrayController.create();// どのテンプレートに適用するかを指定App.ApplicationView = Ember.View.extend({templateName: application});App.ApplicationController.set(content, [{name: アプリを作ろう! Android入門 ~ゼロから学ぶアプリの作成から公開まで,price : 1995},{name: TECHNICAL MASTER はじめてのJSP&サーブレット Eclipse 3.7Indigo+Tomcat 7対応版, price : 2730},{name: Windows Azure Platform開発入門, price : 3990}]);// 表示処理開始App.initialize();<script type="text/x-handlebars" data-template-name="application"><h1>書籍一覧</h1><div><table border="1"><tr><td>名称</td><td>価格</td></tr><!-- ループを行い、本を表示する -->{{#each App.ApplicationController}}<tr><td>{{name}}</td><td>定価{{price}}円</td></tr>{{/each}}</table></div></script>
  • 56フレームワークの分類• MVCフレームワーク• Backbone.js• CoffeScript対応MVCフレームワーク(クラスベースのOO)• Batman.js• Spine.js• MVVMフレームワーク• Knockout• ViewとModelのデータバインディング• Angular.js• Ember.js• イベント管理、非同期処理• RxJS
  • 57[app名]/css[app名]/css/mixin.styl[app名]/css/index.styl[app名]/slug.json[app名]/package.json[app名]/Procfile[app名]/.npmignore[app名]/app[app名]/app/index.coffee[app名]/app/lib[app名]/app/lib/setup.coffee[app名]/app/controllers[app名]/app/models[app名]/app/views[app名]/test[app名]/test/specs[app名]/test/specs/.gitkeep[app名]/test/public[app名]/test/public/lib[app名]/test/public/lib/jasmine.css[app名]/test/public/lib/jasmine.js[app名]/test/public/lib/jasmine.html.js[app名]/test/public/index.html[app名]/public[app名]/public/favicon.ico[app名]/public/index.html設定ファイルCSSファイルSpineアプリケーションテストファイルWebサーバで公開されるドキュメントルートAppクラスライブラリディレクトリコントローラーディレクトリモデルディレクトリビューディレクトリSpine.js アプリケーションの作成• Node.jsでインストール「npm install -g spine.app hem」• コマンドでアプリケーションファイル作成「spine app [アプリケーション名]」「spine model [モデル名]」
  • 58Spine.js アプリケーションの作成• 関連ファイルのインストール「cd [アプリケーション]」「npm install .」• CoffeeScriptコンパイル(ビルド)とサーバ起動「hem build」「hem server」
  • 59Spine.js Controllerのサンプルclass Books extends Spine.Controllerconstructor: ->super# URLが/listで、表示された時点でデータを取得する@routes/list: ->@getBookList()# 本の一覧を取得し、描画するgetBookList: ->Book.fetch()# データが取得された時の処理Book.bind "refresh", (data) =># 取得した本のデータをitemsに設定@items = data[0]# 本の一覧を描画する@render()# 本の一覧を描画する (6)render: ->@html require(views/books)(@items)
  • 60Spine.js ModelのサンプルSpine = require(spine)class Book extends Spine.Model# モデルが持つデータを定義する。本は名前と価格を持つ@configure name, "price"# データをJSONから取得するため、Ajaxのクラスを継承する@extend Spine.Model.Ajax# 取得するJSONのURLを指定。このサンプルでは、ファイルはpublic/dataに作成。@url: "/data/books.json"module.exports = Book{"books": [{"name" : "アプリを作ろう! Android入門 ~ゼロから学ぶアプリの作成から公開まで","price": 1995},{"name" : "TECHNICAL MASTER はじめてのJSP&サーブレットEclipse 3.7 Indigo+Tomcat 7対応版","price": 2730},{"name" : "Windows Azure Platform開発入門","price": 3990}]}
  • 61Spine.js テンプレートサンプル<table border="1"><tr><td>名前</td><td>価格</td></tr><% for book in @books: %><tr><td><%= book.name %></td><td>定価<%= book.price %>円</td></tr><% end %></table><link rel="stylesheet" href="/application.css" type="text/css" charset="utf-8"><script src="/application.js" type="text/javascript" charset="utf-8"></script><script type="text/javascript" charset="utf-8">var jQuery = require("jqueryify");var exports = this;jQuery(function(){var App = require("index");exports.app = new App({el: $("body")});});</script></head><body><h1>書籍一覧</h1><!-- ここに本の一覧を表示する --><div id="booklist"></div></body></html>
  • 62Spine.js テンプレートサンプル
  • 63 63(4)ゲーム系
  • 64ゲーム系• 単純ではあるが作りやすく、ハードルが低い• オブジェクト指向を採用している• プログラミング教育にも適している。キャラクターをオブジェクトと考えやすい。• ゲームフレームワーク• Enchant.js• JAction(スマートフォン用)• Arctic.js(DeNA開発)など
  • 65enchant.js• ゲームが作りやすいように最適化されたフレームワーク• オブジェクト指向• イベントドリブンで、イベントは非同期処理• プラグインによる拡張が可能• サンプルだけでなく画像素材も提供されている• enchant.jsで作ったゲームを公開するサイトhttp://9leap.net/
  • 66enchant.js// ミサイルClassvar Missile = enchant.Class.create(enchant.Sprite, {initialize: function(x, y, speed){enchant.Sprite.call(this);// ミサイルの画像と座標を指定するthis.x = x; this.y = y;this.image = game.assets[img/bar.png];this.width = 3; this.height = 16;// ミサイルの進むスピードthis.vy = speed;// ミサイルを動かすthis.addEventListener(enterframe, function(){this.y -= this.vy;// 画面外に出たら削除if(this.y > 320 || this.x > 320){this.remove();}});
  • 67 67(5)サーバ系
  • 68サーバ系• Node.jsとはサーバサイドJavaScript。実際は、Google Chrome用に開発されたJavaScriptエンジンV8 が搭載されており、ファイルI/O やネットワーク関連など、サーバサイドならではの基本的な機能を付加している。
  • 69サーバ系• 特徴• イベントループ実行する処理をイベントキューに一旦格納し、順番に実行する。• ノンブロッキングI/Oデータの入出力において、データの送受信の完了を待たずに他の処理を開始する方式• このような特徴からWebSocketでの処理に有効• あまり同期的な処理には向かない。書きにくい。• Express、Flatiron.jsなどのフレームワークがある
  • 70Express.js• Node.js向けのWebアプリケーションフレームワーク。• サーバの作成、ルーティングやセッション管理など、Webアプリケーションに必要な最低限の機能を用意している。• Node.jsのパフォーマンスを生かして軽量に動作する。機能 概要サーバーの作成 静的コンテンツの配信、Expressのアプリケーションが動作するhttp、httpsのサーバを立ち上げることができるルーティング リクエストメソッド(POST、GET)及びURLによってどのような動作をするかをルーティングハンドラとして処理を記述するミドルウェア Basic認証、Cookie、ログなどの設定が可能なAPI。例外処理 アプリケーション内で発生した例外を処理することができるテンプレートエンジンのサポートJadeやEJSなどのテンプレートエンジンをサポートし、ルーティングと組み合わせることで、Webページを表示するセッション・サポート HTTPセッション管理をサポートする
  • 71Route(ルーティングメソッド)View(テンプレートエンジン)app.jsnode.jsサーバプロセスクライアントリクエストURLごとに分配データと合わせてHTMLを生成リクエストオブジェクト生成HTMLレスポンスオブジェクトを使用しレスポンス命令レスポンスサーバプロセス起動時に初期処理を行い常駐するExpress.js
  • 72 72(6)テスト系
  • 73 73テストの考え方
  • 74要件リリース見積要件定義基本設計詳細設計 実装結合テスト総合テスト受入テスト基本的なテストの考え方単体テスト品質をあとで担保する
  • 75 http://www.flickr.com/photos/carbonnyc/4740025131/sizes/l/in/photostream/市場の変化~スピード加速へ~
  • 76http://www.flickr.com/photos/59937401@N07/5858004830/sizes/z/in/photostream/リリースして検証しないとわからない
  • 77http://www.flickr.com/photos/59937401@N07/5858004830/sizes/z/in/photostream/頻繁なリリースが必要
  • 78なぜテストを行うのか• テストコード+自動テスト• テスト駆動開発• 継続的インテグレーション• クロスブラウザのテスト品質をあとで担保する品質を作りこむのではなく
  • 79テストコードの記述・実行• テスティングフレームワーク• Mocha• Qunit• Jasmine• アサートモジュール• chai.js• クロスブラウザ自動テスト• Buster.js• JSTestDriver
  • 80テスティングフレームワーク Mocha• Node.jsでもブラウザでも動くテスティングフレームワーク• BDD(振る舞い駆動開発)• TDD(テスト駆動開発)• exportスタイル• jQueryをテストすることを目的としたテスティングフレームワークQUnitの記述方法であるQUnitスタイル• テストの合否を判定するアサーションモジュールは含まれていないため、chai.jsなど個別のアサーションモジュールを使用する必要がある
  • 81
  • 82クロスブラウザテスト JSTestDriver• さまざまなブラウザ環境で、JavaScriptのテストを行うことを想定したテストモジュール。• サーバプロセスを立ち上げ、各ブラウザでアクセスしておくだけで、テストを実行するとアクセスしたブラウザでテストが実行さる。
  • 83クロスブラウザテスト JSTestDriverJSTestDriverサーバ接続テスト実行→各ブラウザで実行
  • 84モック、スタブなどテストダブル• JavaScriptでテストを行う場合、Ajax通信やコールバックの扱いなど、単純にテストが難しい場合がある。Ajaxやテスト対象のオブジェクトなどをスタブに置き換えてテストを行う方法がテストダブル• Sinon.jsやJsMockitoというライブラリがある
  • 85テストダブル sinon.js/*** Ajax通信を偽装してテストをする場合*/var getBooks = function(callback) {jQuery.ajax({url: "booksdata.json",success: function (data) {callback(data);}});};// テストコードsuite(Ajax通信を偽装してテストを行う, function(){var xhr, requests;setup(function(){// ajax処理の偽装xhr = sinon.useFakeXMLHttpRequest();requests = [];xhr.onCreate = function (req) { requests.push(req); };});teardown(function() {xhr.restore();});suite(#getBooks(), function(){test(テストデータでの確認, function(){// Ajaxのレスポンスを指定してテストを行うvar callback = sinon.spy();getBooks(callback);// レスポンスの偽装requests[0].respond(200, {"Content-Type":"application/json"}, [{"books":[{"name": "test"}]}]);// レスポンスのJSONが想定通りに来ているか確認expect(callback.calledWith([{"books":[{"name":"test"}]}])).to.eql(true);});});});
  • 86コードの静的解析• JSHint• 構文解析• 関数の複雑度• jscoverage• コードカバレッジ
  • 87Jenkins CI環境JenkinsLinuxPHPテストWindowsAndroidテストWebテストLinuxNode.jsテストMaciPhoneテストLinuxCI環境を構築JSTestDriverGitLabChefServer
  • 88 88まとめ
  • 89今日お話したライブラリ1.手間を省こう系2.言語特性補う系3.フレームワーク4.ゲーム系5.サーバ系6.開発効率化系
  • 90 90http://www.flickr.com/photos/mujitra/3556469060/かつてのWeb
  • 91 91http://commons.wikimedia.org/wiki/User:Zach_Vegahttp://developer.android.com/distribute/googleplay/promote/brand.htmlhttp://windows.microsoft.com/ja-jp/windows-8/meethttp://www.w3.org/html/logo/index.htmlhttp://nodejs.org/logos/http://www.mozilla.jp/firefoxos/
  • 92 92http://www.flickr.com/photos/robellisphotography/6057722540/大量なコード
  • 93 93http://www.flickr.com/photos/bitterjug/7670055210/複雑化
  • 94まとめ• プログラミング言語としてのJavaScript• 言語特性が他の言語と違う部分がある• テスト自動化(CIなど)• 複雑化によりフレームワークが台頭
  • 95http://www.flickr.com/photos/22290288@N03/5865032805/
  • 96http://www.flickr.com/photos/codepo8/8692028483/
  • 97まとめ(今後)• HTML5の普及• FFOS• 複雑化、大規模化はどんどん進む• すべてがJavaScriptで完結可能• 一部の先進的な開発者だけでなく、エンタープライズも含め、プログラミング言語として、本気で取り組む必要がある• そういう意味で、フレームワークやテストは必須• より設計が重要となってくる• 今後は、もっとライブラリの重要度が増してくる
  • 98 98http://commons.wikimedia.org/wiki/User:Zach_Vegahttp://developer.android.com/distribute/googleplay/promote/brand.htmlhttp://windows.microsoft.com/ja-jp/windows-8/meethttp://www.w3.org/html/logo/index.htmlhttp://nodejs.org/logos/http://www.mozilla.jp/firefoxos/JavaScript天国がやってきた!
  • 99 99