Skip to content
This repository was archived by the owner on Jul 1, 2020. It is now read-only.

Commit 2d9ba48

Browse files
committed
3rd party addon validation #57, #66, #67
- Can now validate external 3rd party addons, asked in issue #57, #66, #67 (like: ngTagsInput, Angular Multiselect, Dropdown multi-select, etc....) - Also fixed some French translations #73
1 parent fda90d0 commit 2d9ba48

File tree

16 files changed

+697
-153
lines changed

16 files changed

+697
-153
lines changed

bower.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "angular-validation-ghiscoding",
3-
"version": "1.4.8",
3+
"version": "1.4.9",
44
"author": "Ghislain B.",
55
"description": "Angular-Validation Directive and Service (ghiscoding)",
66
"main": [

dist/angular-validation.min.js

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ <h1>Angular-Validation Directive|Service (ghiscoding)</h1>
3232
<button type="button" name="btn_goto_Service" class="btn btn-default" ng-click="goto('/validate-service')">Service</button>
3333
<button type="button" name="btn_goto_2forms" class="btn btn-default" ng-click="goto('/validate-2forms')">2 Forms</button>
3434
<button type="button" name="btn_goto_ngrepeat" class="btn btn-default" ng-click="goto('/validate-ngRepeat')">ngRepeat</button>
35+
<a name="btn_goto_3rdpartyaddon" class="btn btn-default" href="more-examples/addon-3rdParty/">3rd Party Addon</a>
3536
</div>
3637

3738
<br/><hr/>

locales/validation/fr.json

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,26 +10,26 @@
1010
"INVALID_BETWEEN_NUM": "Doit être une valeur numérique, entre {0} et {1}. ",
1111
"INVALID_BOOLEAN": "Doit contenir qu'une valeur vraie ou fausse. ",
1212
"INVALID_CREDIT_CARD": "Doit être un numéro de carte de crédit valide. ",
13-
"INVALID_DATE_EURO_LONG": "Doit être un format de date valide (dd-mm-yyyy) OU (dd/mm/yyyy). ",
14-
"INVALID_DATE_EURO_LONG_BETWEEN": "Doit être un format de date valide (dd-mm-yyyy) OU (dd/mm/yyyy) entre {0} et {1}. ",
15-
"INVALID_DATE_EURO_LONG_MAX": "Doit être une date valide (dd-mm-yyyy) OU (dd/mm/yyyy), égale ou inférieure à {0}. ",
16-
"INVALID_DATE_EURO_LONG_MIN": "Doit être une date valide (dd-mm-yyyy) OU (dd/mm/yyyy), égale ou supérieure à {0}. ",
17-
"INVALID_DATE_EURO_SHORT": "Doit être un format de date valide (dd-mm-yy) OU (dd/mm/yy). ",
18-
"INVALID_DATE_EURO_SHORT_BETWEEN": "Doit être un format de date valide (dd-mm-yy) OU (dd/mm/yy) entre {0} et {1}. ",
19-
"INVALID_DATE_EURO_SHORT_MAX": "Doit être une date valide (dd-mm-yy) OU (dd/mm/yy), égale ou inférieure à {0}. ",
20-
"INVALID_DATE_EURO_SHORT_MIN": "Doit être une date valide (dd-mm-yy) OU (dd/mm/yy), égale ou supérieure à {0}. ",
21-
"INVALID_DATE_ISO": "Doit être un format de date valide (yyyy-mm-dd). ",
22-
"INVALID_DATE_ISO_BETWEEN": "Doit être un format de date valide (yyyy-mm-dd) entre {0} et {1}. ",
23-
"INVALID_DATE_ISO_MAX": "Doit être une date valide (yyyy-mm-dd), égale ou inférieure à {0}. ",
24-
"INVALID_DATE_ISO_MIN": "Doit être une date valide (yyyy-mm-dd), égale ou supérieure à {0}. ",
25-
"INVALID_DATE_US_LONG": "Doit être un format de date valide (mm/dd/yyyy) OU (mm-dd-yyyy). ",
26-
"INVALID_DATE_US_LONG_BETWEEN": "Doit être un format de date valide (mm/dd/yyyy) OU (mm-dd-yyyy) entre {0} et {1}. ",
27-
"INVALID_DATE_US_LONG_MAX": "Doit être une date valide (mm/dd/yyyy) OU (mm-dd-yyyy), égale ou inférieure à {0}. ",
28-
"INVALID_DATE_US_LONG_MIN": "Doit être une date valide (mm/dd/yyyy) OU (mm-dd-yyyy), égale ou supérieure à {0}. ",
29-
"INVALID_DATE_US_SHORT": "Doit être un format de date valide (mm/dd/yy) OU (mm-dd-yy). ",
30-
"INVALID_DATE_US_SHORT_BETWEEN": "Doit être un format de date valide (mm/dd/yy) OU (mm-dd-yy) entre {0} et {1}. ",
31-
"INVALID_DATE_US_SHORT_MAX": "Doit être une date valide (mm/dd/yy) OU (mm-dd-yy), égale ou inférieure à {0}. ",
32-
"INVALID_DATE_US_SHORT_MIN": "Doit être une date valide (mm/dd/yy) OU (mm-dd-yy), égale ou supérieure à {0}. ",
13+
"INVALID_DATE_EURO_LONG": "Doit être un format de date valide (jj-mm-aaaa) OU (jj/mm/aaaa). ",
14+
"INVALID_DATE_EURO_LONG_BETWEEN": "Doit être un format de date valide (jj-mm-aaaa) OU (jj/mm/aaaa) entre {0} et {1}. ",
15+
"INVALID_DATE_EURO_LONG_MAX": "Doit être une date valide (jj-mm-aaaa) OU (jj/mm/aaaa), égale ou inférieure à {0}. ",
16+
"INVALID_DATE_EURO_LONG_MIN": "Doit être une date valide (jj-mm-aaaa) OU (jj/mm/aaaa), égale ou supérieure à {0}. ",
17+
"INVALID_DATE_EURO_SHORT": "Doit être un format de date valide (jj-mm-aa) OU (jj/mm/aa). ",
18+
"INVALID_DATE_EURO_SHORT_BETWEEN": "Doit être un format de date valide (jj-mm-aa) OU (jj/mm/aa) entre {0} et {1}. ",
19+
"INVALID_DATE_EURO_SHORT_MAX": "Doit être une date valide (jj-mm-aa) OU (jj/mm/aa), égale ou inférieure à {0}. ",
20+
"INVALID_DATE_EURO_SHORT_MIN": "Doit être une date valide (jj-mm-aa) OU (jj/mm/aa), égale ou supérieure à {0}. ",
21+
"INVALID_DATE_ISO": "Doit être un format de date valide (aaaa-mm-jj). ",
22+
"INVALID_DATE_ISO_BETWEEN": "Doit être un format de date valide (aaaa-mm-jj) entre {0} et {1}. ",
23+
"INVALID_DATE_ISO_MAX": "Doit être une date valide (aaaa-mm-jj), égale ou inférieure à {0}. ",
24+
"INVALID_DATE_ISO_MIN": "Doit être une date valide (aaaa-mm-jj), égale ou supérieure à {0}. ",
25+
"INVALID_DATE_US_LONG": "Doit être un format de date valide (mm/jj/aaaa) OU (mm-jj-aaaa). ",
26+
"INVALID_DATE_US_LONG_BETWEEN": "Doit être un format de date valide (mm/jj/aaaa) OU (mm-jj-aaaa) entre {0} et {1}. ",
27+
"INVALID_DATE_US_LONG_MAX": "Doit être une date valide (mm/jj/aaaa) OU (mm-jj-aaaa), égale ou inférieure à {0}. ",
28+
"INVALID_DATE_US_LONG_MIN": "Doit être une date valide (mm/jj/aaaa) OU (mm-jj-aaaa), égale ou supérieure à {0}. ",
29+
"INVALID_DATE_US_SHORT": "Doit être un format de date valide (mm/jj/aa) OU (mm-jj-aa). ",
30+
"INVALID_DATE_US_SHORT_BETWEEN": "Doit être un format de date valide (mm/jj/aa) OU (mm-jj-aa) entre {0} et {1}. ",
31+
"INVALID_DATE_US_SHORT_MAX": "Doit être une date valide (mm/jj/aa) OU (mm-jj-aa), égale ou inférieure à {0}. ",
32+
"INVALID_DATE_US_SHORT_MIN": "Doit être une date valide (mm/jj/aa) OU (mm-jj-aa), égale ou supérieure à {0}. ",
3333
"INVALID_DIGITS": "Doit être {0} chiffres. ",
3434
"INVALID_DIGITS_BETWEEN": "Doit être entre {0} et {1} chiffres. ",
3535
"INVALID_EMAIL": "Doit être une adresse courriel valide. ",
@@ -74,17 +74,17 @@
7474
"INPUT7": "IP (IPV4)",
7575
"INPUT8": "Carte de Crédit",
7676
"INPUT9": "Entre(2,6) Caractères",
77-
"INPUT10": "Date ISO (yyyy-mm-dd)",
78-
"INPUT11": "Date US LONG (mm/dd/yyyy)",
77+
"INPUT10": "Date ISO (aaaa-mm-jj)",
78+
"INPUT11": "Date US LONG (mm/jj/aaaa)",
7979
"INPUT12": "Time (hh:mm OU hh:mm:ss) -- NON Requis",
8080
"INPUT13": "AlphaDashSpaces + Requis + Minimum(5) Caractères -- DOIT UTILISER: validation-error-to=\" \"",
8181
"INPUT14": "Alphanumérique + Requis -- NG-DISABLED",
8282
"INPUT15": "Mot de Passe",
8383
"INPUT16": "Mot de Passe (Confirmation)",
8484
"INPUT17": "Different Mot de Passe",
8585
"INPUT18": "Alphanumérique + Exactement(3) + Requis -- debounce(3sec)",
86-
"INPUT19": "Date ISO (yyyy-mm-dd ) -- condition minimal >= 2001-01-01 ",
87-
"INPUT20": "Date US COURT (mm/dd/yy) -- entre les dates 12/01/99 et 12/31/15",
86+
"INPUT19": "Date ISO (aaaa-mm-jj ) -- condition minimal >= 2001-01-01 ",
87+
"INPUT20": "Date US COURT (mm/jj/aa) -- entre les dates 12/01/99 et 12/31/15",
8888
"INPUT21": "Choix dans cette liste (banana,orange,ice cream)",
8989
"FIRST_NAME": "Prénom",
9090
"LAST_NAME": "Nom de Famille",

more-examples/addon-3rdParty/app.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
'use strict';
2+
3+
var myApp = angular.module('myApp', ['ghiscoding.validation', 'pascalprecht.translate', 'ngTagsInput', 'angularjs-dropdown-multiselect',
4+
'hljs', 'isteven-multi-select']);
5+
6+
myApp.config(['$compileProvider', function ($compileProvider) {
7+
$compileProvider.debugInfoEnabled(false);
8+
}])
9+
.config(['$translateProvider', function ($translateProvider) {
10+
$translateProvider.useStaticFilesLoader({
11+
prefix: '../../locales/validation/',
12+
suffix: '.json'
13+
});
14+
// load English ('en') table on startup
15+
$translateProvider.preferredLanguage('en').fallbackLanguage('en');
16+
}]);
17+
18+
myApp.controller('Ctrl', ['validationService', function (validationService) {
19+
var vm = this;
20+
var myValidation = new validationService({ controllerAs: vm, formName: 'vm.test', preValidateFormElements: false });
21+
22+
vm.tags1 = [
23+
{ id: 1, text: 'Tag1' },
24+
{ id: 2, text: 'Tag2' },
25+
{ id: 3, text: 'Tag3' }
26+
];
27+
vm.tags2 = [
28+
{ id: 1, text: 'Tag7' },
29+
{ id: 2, text: 'Tag8' },
30+
{ id: 3, text: 'abc' }
31+
];
32+
33+
vm.select1model = [];
34+
vm.select1data = [
35+
{id: 1, label: "Joe"},
36+
{id: 2, label: "John"},
37+
{id: 3, label: "Jane"}
38+
];
39+
40+
vm.modernBrowsers = [
41+
{ name: "Opera", maker: "Opera Software", ticked: true, icon: "<img src='https://cdn1.iconfinder.com/data/icons/fatcow/32/opera.png' />" },
42+
{ name: "Internet Explorer", maker: "Microsoft", ticked: false, icon: "<img src='https://cdn1.iconfinder.com/data/icons/fatcow/32/internet_explorer.png' />" },
43+
{ name: "Firefox", maker: "Mozilla Foundation", ticked: false, icon: "<img src='https://cdn1.iconfinder.com/data/icons/humano2/32x32/apps/firefox-icon.png' />" },
44+
{ name: "Safari", maker: "Apple", ticked: false, icon: "<img src='https://cdn1.iconfinder.com/data/icons/fatcow/32x32/safari_browser.png' />" },
45+
{ name: "Chrome", maker: "Google", ticked: false, icon: "<img src='https://cdn1.iconfinder.com/data/icons/google_jfk_icons_by_carlosjj/32/chrome.png' />" }
46+
];
47+
}]);
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
<!DOCTYPE html>
2+
<html ng-app="myApp" ng-strict-di ng-cloak="">
3+
<head>
4+
<meta charset="utf-8" />
5+
<title>Angular-Validation Example with Interpolation</title>
6+
<link rel="stylesheet" href="../../style.css">
7+
<link rel="stylesheet" href="https://netdna.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
8+
<link rel="stylesheet" href="http://mbenford.github.io/ngTagsInput/css/ng-tags-input.min.css" />
9+
<link rel="stylesheet" href="http://isteven.github.io/angular-multi-select/css/isteven-multi-select.css">
10+
</head>
11+
12+
<body ng-controller="Ctrl as vm">
13+
<div class="container">
14+
<h2>Validation examples with external 3rd party addons </h2>
15+
16+
<div class="alert alert-info alert-dismissable">
17+
<span class="glyphicon glyphicon-link" aria-hidden="true"></span>
18+
<a href="https://github.com/ghiscoding/angular-validation/wiki/3rd-Party-Addons">Wiki - 3rd Party Addons</a>
19+
</div>
20+
21+
<div class="alert alert-danger alert-dismissable" ng-show="vm.test.$validationSummary.length &gt; 0">
22+
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
23+
<h4><strong>ERRORS!</strong></h4>
24+
<ul>
25+
<li ng-repeat="item in vm.test.$validationSummary">{{ item.friendlyName != '' ? item.friendlyName : item.field }}: {{item.message}}</li>
26+
</ul>
27+
</div>
28+
29+
<hr/>
30+
31+
<form name="vm.test">
32+
<div class="form-group">
33+
<label>
34+
<a href="http://dotansimha.github.io/angularjs-dropdown-multiselect/">(project site)</a>
35+
Dropdown MultiSelect
36+
</label>
37+
<div name="select1"
38+
ng-dropdown-multiselect=""
39+
options="vm.select1data"
40+
selected-model="vm.select1model"
41+
ng-model="vm.select1model"
42+
extra-settings="{externalIdProp: ''}"
43+
validation="in_list:John,Jane|required" validation-array-objprop="label">
44+
</div>
45+
</div>
46+
47+
<div class="form-group">
48+
<label>
49+
<a href="http://isteven.github.io/angular-multi-select/#/main">(project site)</a>
50+
Dropdown AngularJs Multi-Select
51+
</label>
52+
<div name="select2"
53+
isteven-multi-select=""
54+
ng-model="vm.outputBrowsers"
55+
input-model="vm.modernBrowsers"
56+
output-model="vm.outputBrowsers"
57+
button-label="icon name"
58+
item-label="icon name maker"
59+
tick-property="ticked"
60+
validation="in_list:Firefox,Chrome|required"
61+
validation-array-objprop="name">
62+
</div>
63+
</div>
64+
65+
<div class="form-group">
66+
<label>
67+
<a href="http://mbenford.github.io/ngTagsInput/">(project site)</a>
68+
ngTagsInput
69+
</label>
70+
<i>&lt;valid-array-require-how-many="one"&gt;</i>
71+
<tags-input name="input1"
72+
ng-model="vm.tags1"
73+
validation="in_list:Tag4,Tag5|required"
74+
validation-array-objprop="text">
75+
</tags-input>
76+
</div>
77+
78+
<div id="tag2" class="form-group">
79+
<label>
80+
<a href="http://mbenford.github.io/ngTagsInput/">(project site)</a>
81+
ngTagsInput
82+
</label>
83+
<i>&lt;valid-array-require-how-many="all"&gt;</i>
84+
<tags-input name="input2"
85+
ng-model="vm.tags2"
86+
validation="pattern=/Tag[0-9]/i:alt=Must be a Tag with a number.|required"
87+
validation-array-objprop="text"
88+
valid-array-require-how-many="all">
89+
</tags-input>
90+
</div>
91+
</form>
92+
<hr/>
93+
<div class="form-actions">
94+
<button type="submit" name="save_btn" class="btn btn-primary" ng-disabled="vm.test.$invalid" ng-click="">{{ 'SAVE' | translate }}</button>
95+
</div>
96+
<hr/>
97+
98+
<div class="alert alert-warning alert-dismissable">
99+
<strong>We can validate an input array by 2 ways:</strong>
100+
<ol>
101+
<li>&lt;valid-array-require-how-many="<b>one</b>"&gt; (default), if 1 value is found good, the complete input set is Valid.</li>
102+
<li>&lt;valid-array-require-how-many="<b>all</b>"&gt;. For the input to be Valid, we need "all" array values to be valid.</li>
103+
</ol>
104+
</div>
105+
</div>
106+
107+
<!-- external librairies CDN -->
108+
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.js"></script>
109+
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular-route.js"></script>
110+
111+
<!-- angular-translate -->
112+
<!-- Visit Angular-Translate https://github.com/PascalPrecht/angular-translate -->
113+
<script src="../../vendors/angular-translate/angular-translate.min.js"></script>
114+
<script src="../../vendors/angular-translate/angular-translate-loader-static-files.min.js"></script>
115+
116+
<!-- ngTagsInput -->
117+
<script src="http://mbenford.github.io/ngTagsInput/js/ng-tags-input.min.js"></script>
118+
119+
<!-- AngularJS Dropdown MultiSelect -->
120+
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min.js"></script>
121+
<script type="text/javascript" src="https://rawgit.com/pc035860/angular-highlightjs/master/angular-highlightjs.js"></script>
122+
<script src="https://rawgit.com/dotansimha/angularjs-dropdown-multiselect/master/src/angularjs-dropdown-multiselect.js"></script>
123+
124+
<!-- AngularJS Multi-Select -->
125+
<script src="https://rawgit.com/isteven/angular-multi-select/master/isteven-multi-select.js"></script>
126+
127+
<!-- Angular-Validation -->
128+
<script type="text/javascript" src="../../dist/angular-validation.min.js"></script>
129+
<!--
130+
<script type="text/javascript" src="../../src/validation-directive.js"></script>
131+
<script type="text/javascript" src="../../src/validation-service.js"></script>
132+
<script type="text/javascript" src="../../src/validation-common.js"></script>
133+
<script type="text/javascript" src="../../src/validation-rules.js"></script>
134+
-->
135+
136+
<!-- my application -->
137+
<script type="text/javascript" src="app.js"></script>
138+
</body>
139+
</html>

more-examples/angular-ui-calendar/index.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
<div class="container">
1212
<h2>Example of Angular-Validation Date validation error after select from ui datepicker.</h2>
1313
<hr/>
14-
<label class="control-label">Min Date {{vm.minDate}}</label>
15-
<label class="control-label">Max Date {{vm.maxDate}}</label>
14+
<label class="control-label">Min Date: {{vm.minDate | date:'dd/MM/yyyy'}}</label> |
15+
<label class="control-label">Max Date {{vm.maxDate | date:'dd/MM/yyyy'}}</label>
1616
<hr/>
1717
<form name="vm.test">
1818
<label class="control-label">Date</label>
@@ -49,7 +49,7 @@ <h2>Example of Angular-Validation Date validation error after select from ui dat
4949
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
5050
<h4><strong>ERRORS!</strong></h4>
5151
<ul>
52-
<li ng-repeat="item in vm.test.$validationSummary">{{ item.friendlyName != '' ? item.friendlyName : item.field }}: {{item.message}}</li>
52+
<li ng-repeat="item in vm.test.$validationSummary">{{ item.field }}: {{item.message}}</li>
5353
</ul>
5454
</div>
5555

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "angular-validation-ghiscoding",
3-
"version": "1.4.8",
3+
"version": "1.4.9",
44
"author": "Ghislain B.",
55
"description": "Angular-Validation Directive and Service (ghiscoding)",
66
"main": "app.js",

protractor/angularUI_spec.js

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
describe('Angular-Validation with AngularUI Tests:', function () {
2+
// global variables
3+
var validDate = "01/10/2015";
4+
var invalidOverDate = "03/10/2015";
5+
var invalidTypoDate = "03/10/201";
6+
var invalidDateMsg = "dateOfChange: Needs to be a valid date format (dd-mm-yyyy) OR (dd/mm/yyyy) between 02/10/2005 and 02/10/2015.";
7+
8+
describe('When choosing `more-examples` AngularUI', function () {
9+
it('Should navigate to home page', function () {
10+
browser.get('http://localhost/Github/angular-validation/more-examples/angular-ui-calendar/');
11+
12+
// Find the title element
13+
var titleElement = element(by.css('h2'));
14+
15+
// Assert that the text element has the expected value.
16+
// Protractor patches 'expect' to understand promises.
17+
expect(titleElement.getText()).toEqual('Example of Angular-Validation Date validation error after select from ui datepicker.');
18+
});
19+
20+
it('Should enter valid date expect no errors on input and validation summary', function () {
21+
var elmInput = $('[name=dateOfChange]');
22+
elmInput.sendKeys(validDate);
23+
elmInput.sendKeys(protractor.Key.TAB);
24+
25+
// validation summary should become empty
26+
var itemRows = element.all(by.binding('message'));
27+
expect(itemRows.count()).toBe(0);
28+
});
29+
30+
it('Should enter outside of range date and show dateOfChange error on input and ValidationSummary', function () {
31+
var elmInput = $('[name=dateOfChange]');
32+
elmInput.sendKeys(invalidOverDate);
33+
elmInput.sendKeys(protractor.Key.TAB);
34+
35+
var itemRows = element.all(by.binding('message'));
36+
var inputName;
37+
38+
for (var i = 0, j = 0, ln = itemRows.length; i < ln; i++) {
39+
expect(itemRows.get(i).getText()).toEqual(invalidDateMsg);
40+
}
41+
});
42+
43+
it('Should enter wrong date format and show dateOfChange error on input and ValidationSummary', function () {
44+
var elmInput = $('[name=dateOfChange]');
45+
elmInput.sendKeys(invalidTypoDate);
46+
elmInput.sendKeys(protractor.Key.TAB);
47+
48+
var itemRows = element.all(by.binding('message'));
49+
var inputName;
50+
51+
for (var i = 0, j = 0, ln = itemRows.length; i < ln; i++) {
52+
expect(itemRows.get(i).getText()).toEqual(invalidDateMsg);
53+
}
54+
});
55+
});
56+
});

0 commit comments

Comments
 (0)