AngularJs 指令詳解及示例代碼
對(duì)于指令,可以把它簡(jiǎn)單的理解成在特定DOM元素上運(yùn)行的函數(shù),指令可以擴(kuò)展這個(gè)元素的功能。
首先來看個(gè)完整的參數(shù)示例再來詳細(xì)的介紹各個(gè)參數(shù)的作用及用法:
angular.module('myApp', [])
.directive('myDirective', function() {
return {
restrict: String,
priority: Number,
terminal: Boolean,
template: String or Template Function:
function(tElement, tAttrs) {...},
templateUrl: String,
replace: Boolean or String,
scope: Boolean or Object,
transclude: Boolean,
controller: String or
function(scope, element, attrs, transclude, otherInjectables) { ... },
controllerAs: String,
require: String,
link: function(scope, iElement, iAttrs) { ... },
compile: // 返回一個(gè)對(duì)象或連接函數(shù),如下所示:
function(tElement, tAttrs, transclude) {
return {
pre: function(scope, iElement, iAttrs, controller) { ... },
post: function(scope, iElement, iAttrs, controller) { ... }
}
return function postLink(...) { ... }
}
};
});
restrict[string]
restrict是一個(gè)可選的參數(shù)。用于指定該指令在DOM中以何種形式被聲明。默認(rèn)值是A,即以屬性的形式來進(jìn)行聲明。
可選值如下:
E(元素)
<my-directive></my-directive>
A(屬性,默認(rèn)值)
<div my-directive="expression"></div>
C(類名)
<div class="my-directive:expression;"></div>
M(注釋)
<--directive:my-directive expression-->
一般考慮到瀏覽器的兼容性,強(qiáng)烈建議使用默認(rèn)的屬性就可以即即以屬性的形式來進(jìn)行聲明。最后一種方式建議再不要求逼格指數(shù)的時(shí)候千萬不要用。
Code:
angular.module('app',[])
.directive('myDirective', function () {
return {
restrict: 'E',
template: '<a
};
})
HtmlCode:
<my-directive></my-directive>
效果:
priority[int]
大多數(shù)指令會(huì)忽略這個(gè)參數(shù),使用默認(rèn)值0,但也有些場(chǎng)景設(shè)置高優(yōu)先級(jí)是非常重要甚至是必須的。例如,ngRepeat將這個(gè)參數(shù)設(shè)置為1000,這樣就可以保證在同一元素上,它總是在其他指令之前被調(diào)用。
terminal[bool]
這個(gè)參數(shù)用來停止運(yùn)行當(dāng)前元素上比本指令優(yōu)先級(jí)低的指令。但同當(dāng)前指令優(yōu)先級(jí)相同的指令還是會(huì)被執(zhí)行。
例如:ngIf的優(yōu)先級(jí)略高于ngView(它們操控的實(shí)際就是terminal參數(shù)),如果ngIf的表達(dá)式值為true,ngView就可以被正常執(zhí)行,但如果ngIf表達(dá)式的值為false,由于ngView的優(yōu)先級(jí)較低就不會(huì)被執(zhí)行。
template[string or function]
template參數(shù)是可選的,必須被設(shè)置為以下兩種形式之一:
一段HTML文本;
一個(gè)可以接受兩個(gè)參數(shù)的函數(shù),參數(shù)為tElement和tAttrs,并返回一個(gè)代表模板的字符串。tElement和tAttrs中的t代表template,是相對(duì)于instance的。
首先演示下第二種用法:
angular.module('app',[])
.directive('myDirective', function () {
return {
restrict: 'EAC',
template: function (elem, attr) {
return "<a href='" + attr.value + "'>" + attr.text + "</a>";
}
};
})
HtmlCode:(效果同上,不做演示了)
<my-directive value="http://www.baidu.com" text="百度"></my-directive>
<div my-directive
value="http://www.baidu.com"
text="百度"></div>
templateUrl[string or function]
templateUrl是可選的參數(shù),可以是以下類型:
一個(gè)代表外部HTML文件路徑的字符串;
一個(gè)可以接受兩個(gè)參數(shù)的函數(shù),參數(shù)為tElement和tAttrs,并返回一個(gè)外部HTML文件路徑的字符串。
無論哪種方式,模板的URL都將通過ng內(nèi)置的安全層,特別是$getTrustedResourceUrl,這樣可以保護(hù)模板不會(huì)被不信任的源加載。 默認(rèn)情況下,調(diào)用指令時(shí)會(huì)在后臺(tái)通過Ajax來請(qǐng)求HTML模板文件。加載大量的模板將嚴(yán)重拖慢一個(gè)客戶端應(yīng)用的速度。為了避免延遲,可以在部署應(yīng)用之前對(duì)HTML模板進(jìn)行緩存。
Code:
angular.module('app',[])
.directive('myDirective', function () {
return {
restrict: 'AEC',
templateUrl: function (elem, attr) {
return attr.value + ".html"; //當(dāng)然這里我們可以直接指定路徑,同時(shí)在模板中可以包含表達(dá)式
}
};
})
replace[bool]
replace是一個(gè)可選參數(shù),如果設(shè)置了這個(gè)參數(shù),值必須為true,因?yàn)槟J(rèn)值為false。默認(rèn)值意味著模板會(huì)被當(dāng)作子元素插入到調(diào)用此指令的元素內(nèi)部,
例如上面的示例默認(rèn)值情況下,生成的html代碼如下:
<my-directive value="http://www.baidu.com" text="百度"><a href="http://www.baidu.com">百度</a></my-directive>
如果設(shè)置replace=true
<a href="http://www.baidu.com" value="http://www.baidu.com" text="百度">百度</a>
據(jù)我觀察,這種效果只有設(shè)置restrict="E"的情況下,才會(huì)表現(xiàn)出實(shí)際效果。
介紹完基本的指令參數(shù)后,就要涉及到更重要的作用域參數(shù)了...
scope參數(shù)[bool or object]
scope參數(shù)是可選的,可以被設(shè)置為true或一個(gè)對(duì)象。默認(rèn)值是false。
如果一個(gè)元素上有多個(gè)指令使用了隔離作用域,其中只有一個(gè)可以生效。只有指令模板中的根元素可以獲得一個(gè)新的作用域。因此,對(duì)于這些對(duì)象來說scope默認(rèn)被設(shè)置為true。內(nèi)置指令ng-controller的作用,就是從父級(jí)作用域繼承并創(chuàng)建一個(gè)新的子作用域。它會(huì)創(chuàng)建一個(gè)新的從父作用域繼承而來的子作用域。這里的繼承就不在贅述,和面向?qū)ο笾械睦^承基本是一直的。
首先我們來分析一段代碼:
<div ng-app="app" ng-init="name= '祖父'">
<div ng-init="name='父親'">
第一代:{{ name }}
<div ng-init="name= '兒子'" ng-controller="SomeController">
第二代: {{ name }}
<div ng-init="name='孫子'">
第三代: {{ name }}
</div>
</div>
</div>
</div>
我們發(fā)現(xiàn)第一代,我們初始化name為父親,但是第二代和第三代其實(shí)是一個(gè)作用域,那么他們的name其實(shí)是一個(gè)對(duì)象,因此出現(xiàn)的效果如下:
第一代:父親
第二代: 孫子
第三代: 孫子
我們?cè)谛薷囊幌麓a,把第三代隔離開來再看看效果:
<div ng-app="app"ng-init="name= '祖父'">
<div ng-init="name='父親'">
第一代:{{ name }}
<div ng-init="name= '兒子'" ng-controller="SomeController">
第二代: {{ name }}
<div ng-init="name='孫子'" ng-controller="SecondController">
第三代: {{ name }}
</div>
</div>
</div>
</div>
angular.module('app', [])
.controller('SomeController',function($scope) {
})
.controller('SecondController', function ($scope) {
})
效果如下:
第一代:父親
第二代: 兒子
第三代: 孫子
在修改下代碼來看看繼承:
<div ng-app="app"ng-init="name= '祖父的吻'">
<div>
第一代:{{ name }}
<div ng-controller="SomeController">
第二代: {{ name }}
<div ng-controller="SecondController">
第三代: {{ name }}
</div>
</div>
</div>
</div>
效果如下:
第一代:祖父的吻
第二代: 祖父的吻
第三代: 祖父的吻
如果要?jiǎng)?chuàng)建一個(gè)能夠從外部原型繼承作用域的指令,將scope屬性設(shè)置為true,簡(jiǎn)單來說就是可繼承的隔離,即不能反向影響父作用域。
再來看個(gè)例子:
angular.module('myApp', [])
.controller('MainController', function ($scope) {
})
.directive('myDirective', function () {
return {
restrict: 'A',
scope:false,//切換為{},true測(cè)試
priority: 100,
template: '<div>內(nèi)部:{{ myProperty }}<input ng-model="myProperty"/></div>'
};
});
Html代碼:
<div ng-controller='MainController' ng-init="myProperty='Hello World!'">
外部: {{ myProperty}}
<input ng-model="myProperty" />
<div my-directive></div>
</div>
當(dāng)我們改變scope的值我們會(huì)發(fā)現(xiàn)
false:繼承但不隔離

true:繼承并隔離

{}:隔離且不繼承

transclude
transclude是一個(gè)可選的參數(shù)。默認(rèn)值是false。嵌入通常用來創(chuàng)建可復(fù)用的組件,典型的例子是模態(tài)對(duì)話框或?qū)Ш綑?。我們可以將整個(gè)模板,包括其中的指令通過嵌入全部傳入一個(gè)指令中。指令的內(nèi)部可以訪問外部指令的作用域,并且模板也可以訪問外部的作用域?qū)ο?/span>。為了將作用域傳遞進(jìn)去,scope參數(shù)的值必須通過{}或true設(shè)置成隔離作用域。如果沒有設(shè)置scope參數(shù),那么指令內(nèi)部的作用域?qū)⒈辉O(shè)置為傳入模板的作用域。
只有當(dāng)你希望創(chuàng)建一個(gè)可以包含任意內(nèi)容的指令時(shí),才使用transclude: true。
我們來看兩個(gè)例子-導(dǎo)航欄:
<div side-box title="TagCloud">
<div class="tagcloud">
<a href="">Graphics</a>
<a href="">ng</a>
<a href="">D3</a>
<a href="">Front-end</a>
<a href="">Startup</a>
</div>
</div>
JsCode:
angular.module('myApp', [])
.directive('sideBox', function() {
return {
restrict: 'EA',
scope: {
title: '@'
},
transclude: true,
template: '<div class="sidebox"><div class="content"><h2 class="header">' +
'{{ title }}</h2><span class="content" ng-transclude></span></div></div>'
};
});
這段代碼告訴ng編譯器,將它從DOM元素中獲取的內(nèi)容放到它發(fā)現(xiàn)ng-transclude指令的地方。
再來你看個(gè)官網(wǎng)的例子:
angular.module('docsIsoFnBindExample', [])
.controller('Controller', ['$scope', '$timeout', function($scope, $timeout) {
$scope.name = 'Tobias';
$scope.hideDialog = function () {
$scope.dialogIsHidden = true;
$timeout(function () {
$scope.dialogIsHidden = false;
}, 2000);
};
}])
.directive('myDialog', function() {
return {
restrict: 'E',
transclude: true,
scope: {
'close': '&onClose'
},
templateUrl: 'my-dialog-close.html'
};
});
my-dialog-close.html
my-dialog-close.html <div class="alert"> <a href class="close" ng-click="close()">×</a> <div ng-transclude></div> </div>
indext.html
<div ng-controller="Controller">
<my-dialog ng-hide="dialogIsHidden" on-close="hideDialog()">
Check out the contents, {{name}}!
</my-dialog>
</div>
如果指令使用了transclude參數(shù),那么在控制器無法正常監(jiān)聽數(shù)據(jù)模型的變化了。建議在鏈接函數(shù)里使用$watch服務(wù)。
controller[string or function]
controller參數(shù)可以是一個(gè)字符串或一個(gè)函數(shù)。當(dāng)設(shè)置為字符串時(shí),會(huì)以字符串的值為名字,來查找注冊(cè)在應(yīng)用中的控制器的構(gòu)造函數(shù).
angular.module('myApp', [])
.directive('myDirective', function() {
restrict: 'A',
controller: 'SomeController'
})
可以在指令內(nèi)部通過匿名構(gòu)造函數(shù)的方式來定義一個(gè)內(nèi)聯(lián)的控制器
angular.module('myApp',[])
.directive('myDirective', function() {
restrict: 'A',
controller:
function($scope, $element, $attrs, $transclude) {
// 控制器邏輯放在這里
}
});
我們可以將任意可以被注入的ng服務(wù)注入到控制器中,便可以在指令中使用它了。控制器中也有一些特殊的服務(wù)可以被注入到指令當(dāng)中。這些服務(wù)有:
1. $scope
與指令元素相關(guān)聯(lián)的當(dāng)前作用域。
2. $element
當(dāng)前指令對(duì)應(yīng)的元素。
3. $attrs
由當(dāng)前元素的屬性組成的對(duì)象。
<div id="aDiv"class="box"></div>
具有如下的屬性對(duì)象:
{
id: "aDiv",
class: "box"
}
4. $transclude
嵌入鏈接函數(shù)會(huì)與對(duì)應(yīng)的嵌入作用域進(jìn)行預(yù)綁定。transclude鏈接函數(shù)是實(shí)際被執(zhí)行用來克隆元素和操作DOM的函數(shù)。
angular.module('myApp',[])
.directive('myLink', function () {
return {
restrict: 'EA',
transclude: true,
controller:
function ($scope, $element,$attrs,$transclude) {
$transclude(function (clone) {
var a = angular.element('<a>');
a.attr('href', $attrs.value);
a.text(clone.text());
$element.append(a);
});
}
};
});
html
<my-link value="http://www.baidu.com">百度</my-link>
<div my-link value="http://www.google.com">谷歌</div>
僅在compile參數(shù)中使用transcludeFn是推薦的做法。link函數(shù)可以將指令互相隔離開來,而controller則定義可復(fù)用的行為。如果我們希望將當(dāng)前指令的API暴露給其他指令使用,可以使用controller參數(shù),否則可以使用link來構(gòu)造當(dāng)前指令元素的功能性(即內(nèi)部功能)。如果我們使用了scope.$watch()或者想要與DOM元素做實(shí)時(shí)的交互,使用鏈接會(huì)是更好的選擇。使用了嵌入,控制器中的作用域所反映的作用域可能與我們所期望的不一樣,這種情況下,$scope對(duì)象無法保證可以被正常更新。當(dāng)想要同當(dāng)前屏幕上的作用域交互時(shí),可以使用傳入到link函數(shù)中的scope參數(shù)。
controllerAs[string]
controllerAs參數(shù)用來設(shè)置控制器的別名,這樣就可以在視圖中引用控制器甚至無需注入$scope。
<div ng-controller="MainController as main">
<input type="text" ng-model="main.name" />
<span>{{ main.name }}</span>
</div>
JsCode:
angular.module('myApp',[])
.controller('MainController', function () {
this.name = "Halower";
});
控制器的別名使路由和指令具有創(chuàng)建匿名控制器的強(qiáng)大能力。這種能力可以將動(dòng)態(tài)的對(duì)象創(chuàng)建成為控制器,并且這個(gè)對(duì)象是隔離的、易于測(cè)試。
require[string or string[]]
require為字符串代表另外一個(gè)指令的名字。require會(huì)將控制器注入到其所指定的指令中,并作為當(dāng)前指令的鏈接函數(shù)的第四個(gè)參數(shù)。字符串或數(shù)組元素的值是會(huì)在當(dāng)前指令的作用域中使用的指令名稱。在任何情況下,ng編譯器在查找子控制器時(shí)都會(huì)參考當(dāng)前指令的模板。
- 如果不使用^前綴,指令只會(huì)在自身的元素上查找控制器。指令定義只會(huì)查找定義在指令作當(dāng)前用域中的ng-model=""
- 如果使用?前綴,在當(dāng)前指令中沒有找到所需要的控制器,會(huì)將null作為傳給link函數(shù)的第四個(gè)參數(shù)。
- 如果添加了^前綴,指令會(huì)在上游的指令鏈中查找require參數(shù)所指定的控制器。
- 如果添加了?^ 將前面兩個(gè)選項(xiàng)的行為組合起來,我們可選擇地加載需要的指令并在父指令鏈中進(jìn)行查找
- 如果沒有任何前綴,指令將會(huì)在自身所提供的控制器中進(jìn)行查找,如果沒有找到任何控制器(或具有指定名字的指令)就拋出一個(gè)錯(cuò)誤
compile【object or function】
compile選項(xiàng)本身并不會(huì)被頻繁使用,但是link函數(shù)則會(huì)被經(jīng)常使用。本質(zhì)上,當(dāng)我們?cè)O(shè)置了link選項(xiàng),實(shí)際上是創(chuàng)建了一個(gè)postLink() 鏈接函數(shù),以便compile() 函數(shù)可以定義鏈接函數(shù)。通常情況下,如果設(shè)置了compile函數(shù),說明我們希望在指令和實(shí)時(shí)數(shù)據(jù)被放到DOM中之前進(jìn)行DOM操作,在這個(gè)函數(shù)中進(jìn)行諸如添加和刪除節(jié)點(diǎn)等DOM操作是安全的。
compile和link選項(xiàng)是互斥的。如果同時(shí)設(shè)置了這兩個(gè)選項(xiàng),那么會(huì)把compile所返回的函數(shù)當(dāng)作鏈接函數(shù),而link選項(xiàng)本身則會(huì)被忽略。
編譯函數(shù)負(fù)責(zé)對(duì)模板DOM進(jìn)行轉(zhuǎn)換。鏈接函數(shù)負(fù)責(zé)將作用域和DOM進(jìn)行鏈接。 在作用域同DOM鏈接之前可以手動(dòng)操作DOM。在實(shí)踐中,編寫自定義指令時(shí)這種操作是非常罕見的,但有幾個(gè)內(nèi)置指令提供了這樣的功能。
link
compile: function(tEle, tAttrs, transcludeFn) {
//todo:
return function(scope, ele, attrs) {
// 鏈接函數(shù)
};
鏈接函數(shù)是可選的。如果定義了編譯函數(shù),它會(huì)返回鏈接函數(shù),因此當(dāng)兩個(gè)函數(shù)都定義時(shí),編譯函數(shù)會(huì)重載鏈接函數(shù)。如果我們的指令很簡(jiǎn)單,并且不需要額外的設(shè)置,可以從工廠函數(shù)(回調(diào)函數(shù))返回一個(gè)函數(shù)來代替對(duì)象。如果這樣做了,這個(gè)函數(shù)就是鏈接函數(shù)。
ngModel
它提供更底層的API來處理控制器內(nèi)的數(shù)據(jù),這個(gè)API用來處理數(shù)據(jù)綁定、驗(yàn)證、 CSS更新等不實(shí)際操作DOM的事情,ngModel 控制器會(huì)隨 ngModel 被一直注入到指令中,其中包含了一些方法。為了訪問ngModelController必須使用require設(shè)置.
ngModelController常用的元素如下:
1.為了設(shè)置作用域中的視圖值,需要調(diào)用 ngModel.$setViewValue() 函數(shù)。
$setViewValue() 方法適合于在自定義指令中監(jiān)聽自定義事件(比如使用具有回調(diào)函數(shù)的jQuery插件),我們會(huì)希望在回調(diào)時(shí)設(shè)置$viewValue并執(zhí)行digest循環(huán)。
angular.module('myApp')
.directive('myDirective', function() {
return {
require: '?ngModel',
link: function(scope, ele, attrs, ngModel) {
if (!ngModel) return;
$(function() {
ele.datepicker({
//回調(diào)函數(shù)
onSelect: function(date) {
// 設(shè)置視圖和調(diào)用 apply
scope.$apply(function() {
ngModel.$setViewValue(date);
});
}
});
});
}
};
});
2.$render方法可以定義視圖具體的渲染方式
3.屬性
1. $viewValue
$viewValue屬性保存著更新視圖所需的實(shí)際字符串。
2. $modelValue
$modelValue由數(shù)據(jù)模型持有。 $modelValue和$viewValue可能是不同的,取決于$parser流水線是否對(duì)其進(jìn)行了操作。
3. $parsers
$parsers 的值是一個(gè)由函數(shù)組成的數(shù)組,其中的函數(shù)會(huì)以流水線的形式被逐一調(diào)用。ngModel 從DOM中讀取的值會(huì)被傳入$parsers中的函數(shù),并依次被其中的解析器處理。
4. $formatters
$formatters的值是一個(gè)由函數(shù)組成的數(shù)組,其中的函數(shù)會(huì)以流水線的形式在數(shù)據(jù)模型的值發(fā)生變化時(shí)被逐一調(diào)用。它和$parser流水線互不影響,用來對(duì)值進(jìn)行格式化和轉(zhuǎn)換,以便在綁定了這個(gè)值的控件中顯示。
5. $viewChangeListeners
$viewChangeListeners的值是一個(gè)由函數(shù)組成的數(shù)組,其中的函數(shù)會(huì)以流水線的形式在視圖中的值發(fā)生變化時(shí)被逐一調(diào)用。通過$viewChangeListeners,可以在無需使用$watch的情況下實(shí)現(xiàn)類似的行為。由于返回值會(huì)被忽略,因此這些函數(shù)不需要返回值。
6. $error
$error對(duì)象中保存著沒有通過驗(yàn)證的驗(yàn)證器名稱以及對(duì)應(yīng)的錯(cuò)誤信息。
7. $pristine
$pristine的值是布爾型的,可以告訴我們用戶是否對(duì)控件進(jìn)行了修改。
8. $dirty
$dirty的值和$pristine相反,可以告訴我們用戶是否和控件進(jìn)行過交互。
9. $valid
$valid值可以告訴我們當(dāng)前的控件中是否有錯(cuò)誤。當(dāng)有錯(cuò)誤時(shí)值為false, 沒有錯(cuò)誤時(shí)值為true。
10. $invalid
$invalid值可以告訴我們當(dāng)前控件中是否存在至少一個(gè)錯(cuò)誤,它的值和$valid相反。
以上就是關(guān)于AngularJS的指令知識(shí)資料整理,后續(xù)繼續(xù)補(bǔ)充,謝謝大家對(duì)本站的支持!
相關(guān)文章
Angular實(shí)現(xiàn)二級(jí)導(dǎo)航欄
這篇文章主要為大家詳細(xì)介紹了Angular實(shí)現(xiàn)二級(jí)導(dǎo)航欄,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03
angular.js+node.js實(shí)現(xiàn)下載圖片處理詳解
這篇文章主要介紹了angular.js+node.js實(shí)現(xiàn)下載圖片處理的相關(guān)資料,文中介紹的非常詳細(xì),對(duì)大家具有一定的參考價(jià)值,需要的朋友們下面來一起看看吧。2017-03-03
angular 用Observable實(shí)現(xiàn)異步調(diào)用的方法
這篇文章主要介紹了angular 用Observable實(shí)現(xiàn)異步調(diào)用的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-12-12
angular ngClick阻止冒泡使用默認(rèn)行為的方法
這篇文章主要介紹了angular ngClick阻止冒泡使用默認(rèn)行為的方法,較為詳細(xì)的分析了AngularJS中ngClick事件執(zhí)行原理與阻止冒泡的實(shí)現(xiàn)技巧,需要的朋友可以參考下2016-11-11
Angular之jwt令牌身份驗(yàn)證的實(shí)現(xiàn)
這篇文章主要介紹了Angular之jwt令牌身份驗(yàn)證的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02
使用AngularJS對(duì)表單提交內(nèi)容進(jìn)行驗(yàn)證的操作方法
AngularJS是一款優(yōu)秀的前端JS框架,已經(jīng)被用于Google的多款產(chǎn)品當(dāng)中。下面通過本文給大家分享使用AngularJS對(duì)表單提交內(nèi)容進(jìn)行驗(yàn)證的操作方法,需要的的朋友參考下吧2017-07-07
Angular 4 依賴注入學(xué)習(xí)教程之FactoryProvider的使用(四)
這篇文章主要給大家介紹了關(guān)于Angular 4 依賴注入之FactoryProvider使用的相關(guān)資料,文中介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Angular4具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起看看吧。2017-06-06

