Angularjs ngTable doesn´t shows row just added - angularjs

I have ngTable with some rows.
My ngTable is showing into view:'configClinicasClinicas.html' without problem.
I have created a new view to add a row into "addClinica.html".
My data rows is coming from my local node server.
To test, I initially loaded the ui-route state('configuracoes.clinicas.clinicas') to show the table.
After that, I click a button to load a new state('configuracoes.clinicas.addclinica') to add a new row. Next, I post the new data to server. So far so good, no problem until here.
The problem is that after I post the new data row to server,I use $state.go to load my table again but my new row just posted doesn´t appears in the table. I can see the new row is coming from server, but it is not showing in the table.
My new added row appears on the table as a blank row without data.
If I click again to add a new row I get the error of "Duplicates in a repeater are not allowed".
I am a newbie with ngTable.
What am I missiing here?
//Error:
Error: [ngRepeat:dupes] Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: row in $data track by row.id, Duplicate key: undefined, Duplicate value: {"clinica":{"id":6,"nome":"sadf","endereco":"sadf","bairro":"sadf","cidade":"sdfsaass","uf":"sdafasd","telefone":"sadfasd","isAtivo":true,"coord":{"id":2,"latitude":-49.4,"longitude":23.2}}}
http://errors.angularjs.org/1.6.1/ngRepeat/dupes?p0=row%20in%20%24data%20tr…%7B%22id%22%3A2%2C%22latitude%22%3A-49.4%2C%22longitude%22%3A23.2%7D%7D%7D
at angular.js:68
at ngRepeatAction (angular.js:30804)
at $watchCollectionAction (angular.js:17677)
at Scope.$digest (angular.js:17814)
at Scope.$apply (angular.js:18080)
at done (angular.js:12210)
at completeRequest (angular.js:12436)
at XMLHttpRequest.requestLoaded (angular.js:12364)
//configClinicasClinicas.html'
<p>
<a class="btn btn-sm btn-success" ui-sref="configuracoes.clinicas.addclinica">Add Clinic
</a>
</p>
<table ng-table="tableParams" class="table table-bordered table-striped table-condensed">
<tr ng-repeat="row in $data track by row.id">
<td data-title="'Nome'" filter="{name: 'text'}" sortable="'nome'">{{row.nome}}</td>
<td align="center" valign="center" data-title="'Endereço'"> {{row.endereco}}</td>
<td align="center" valign="center" data-title="'Bairro'" > {{row.bairro}}</td>
<td align="center" valign="center" data-title="'Cidade'" > {{row.cidade}}</td>
<td align="center" valign="center" data-title="'Estado'" > {{row.uf}}</td>
<td align="center" valign="center" data-title="'Telefone'" > {{row.telefone}}</td>
<td align="center" valign="center" data-title="'Ativo'"> <span ng-class="row.isAtivo ? 'label label-info' : 'label label-danger' "> {{row.isAtivo ? "Ativo":"Inativo"}} </span></td>
</tr>
</table>
</table>
//addClinica.html
<div class="col-md-9">
<form class="form-horizontal">
<fieldset>
<legend>
Dados da clínica
</legend>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right" for="registro">
ID
</label>
<div class="col-sm-5 col-lg-4">
<input id="registro" name="clinica.id" ng-model="clinica.id" type="number" class="form-control inline">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right" for="nome" title="Nome">
Nome *
</label>
<div class="col-sm-5 col-lg-4">
<input name="clinica.nome" id="nome" ng-model="clinica.nome" class="form-control " type="text" required="required" maxlength="60">
</div>
</div>
</fieldset>
...
....
<div class="col-xs-12 no-padding pull-right">
<div class="clearfix form-actions">
<div class="col-md-offset-3 col-md-9">
<a class="btn btn-primary" ng-click="saveClinica(clinica)">
<i class="fa fa-check bigger-110"></i>
Save
</a>
<a class="btn btn-success" ui-sref="smenupacientes.clinicas.clinicas()">
<i class="fa fa-close bigger-110"></i>
Cancel
</a>
</div>
</div>
</div>
</form>
</div>
//JS
angular.module("clinang", ["ngTable", "ui.router","ui.bootstrap"]);
angular.module("clinang").config(function($stateProvider, $urlMatcherFactoryProvider,$urlRouterProvider,$locationProvider) {
//$locationProvider.html5Mode(true);
$urlMatcherFactoryProvider.caseInsensitive(true);
// the known route, with missing '/' - let's create alias
$urlRouterProvider.when('', '/pacientes');
// the unknown
$urlRouterProvider.otherwise('/404');
$stateProvider
.... other states
.state('configuracoes.clinicas.addclinica', {
url: '/addclicnica',
views:{
'configclinicasaddclicnica#configuracoes.clinicas':{
templateUrl: '/views/addClinica.html',
controller: 'configClinicaClinicaAddClinicaCtrl'
}
}
})
.state('configuracoes.clinicas.clinicas', {
url: '/configclinicasclinicas',
views:{
'configclinicasclinicas#configuracoes.clinicas':{
templateUrl: '/views/configClinicasClinicas.html',
controller: 'configClinicaClinicaCtrl'
}
}
})
});
//Controllers
ngular.module("clinang").controller('configClinicaClinicaAddClinicaCtrl',['$scope','$http', '$state','NgTableParams', function($scope,$http, $state,NgTableParams) {
$scope.clinica={};
$scope.saveClinica=function(clinica){
var coord={id:2, latitude:-49.4, longitude:23.2};
clinica.coord=coord;
$http.post('/clinicas',{clinica}).then(function(response){
delete $scope.clinica;
$state.go('configuracoes.clinicas.clinicas');
}, function(error){
console.log(error)
})
}
}]);
angular.module("clinang").controller('configClinicaClinicaCtrl',['$scope','$http', '$state','NgTableParams', function($scope,$http, $state,NgTableParams) {
$scope.tableParams = new NgTableParams({}, {
getData: function(params) {
return $http.get('/clinicas',{params:{where:params}}).then(function(response){
params.total(response.data.length); // recal. page nav controls
console.log(JSON.stringify(response.data));
return response.data;
}, function(error){
console.log(error)
})
}})
}]);

Related

How to avoid loading data from server every time doing sorting/paging with ngtable

I am using ngtable (1.0.0) to display records fetched from server side. My controller js looks like this:
ristoreApp.controller("fmCtrl",
['$scope', '$filter', 'fmFactory', 'NgTableParams', function($scope, $filter, fmFactory, NgTableParams) {
var self = this;
$scope.selection = '0';
$scope.fmSearch = function () {
if ($scope.selection == '0') {
self.tableParams = new NgTableParams({
page: 1, // show first page
count: 10, // count per page
sorting: {
frReportId: 'asc'
}
}, {
getData: function (params) {
return fmFactory.getAll()
.then(function(response) {
var reports = response.data;
params.total(reports.length);
console.log(params.total());
var sorted = params.sorting() ? $filter('orderBy')(reports, params.orderBy()) : reports;
return sorted.slice((params.page() - 1) * params.count(), params.page() * params.count());
});
}
});
}
}
}]
)
HTML for the table:
<div ng-controller="fmCtrl as fm">
<div class="container">
<div class="row top-margin-80">
<div class="col-md-12">
<div class="input-group" id="adv-search">
<input type="text" class="form-control" ng-model="keyword" placeholder="Enter MRN or report ID" />
<div class="input-group-btn">
<div class="btn-group" role="group">
<div class="dropdown dropdown-lg">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false"><span class="caret"></span></button>
<div class="dropdown-menu dropdown-menu-right" role="menu">
<form class="form-horizontal" role="form">
<div class="form-group">
<label for="filter">Search by</label>
<select class="form-control" ng-model="selection">
<option value="0" selected>All Reports</option>
<option value="1" >MRN</option>
<option value="2">ReportID</option>
</select>
</div>
<div class="form-group">
<input class="form-control" type="text" ng-model="optionword" ng-hide="selection == '0'"/>
</div>
</form>
</div>
</div>
<button type="button" class="btn btn-primary" ng-click="fmSearch()"><span class="glyphicon glyphicon-search" aria-hidden="true"></span></button>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="container">
<table ng-table="fm.tableParams" class="table table-bordered table-striped table-condensed" show-filter="false">
<tr ng-repeat="report in $data">
<td data-title="'ReportId'" filter="{frReportId: 'text'}" sortable="'frReportId'" class="text-center">
{{report.frReportId}}</td>
<td data-title="'BlockId'" filter="{frBlockId: 'text'}" sortable="'frBlockId'" class="text-center">
{{report.frBlockId}}</td>
<td data-title="'MRN'" filter="{mrn: 'text'}" sortable="'mrn'" class="text-center">
{{report.mrn}}</td>
<td data-title="'Name'" filter="{frFullName: 'text'}" sortable="'frFullName'" class="text-center">
{{report.frFullName}}</td>
<td data-title="'Diagnosis'" filter="{frDiagnosis: 'text'}" sortable="'frDiagnosis'" class="text-center">
{{report.frDiagnosis}}</td>
<td data-title="'File'" class="text-center"><a ng-href="{{report.filepath}}">{{report.frReportId}}.xml</a>
</td>
</tr>
</table>
</div>
</div>
It works, well sort of. Problem is whenever I click on the titles to sort and page button to go to next page, it makes an ajax call to server to retrieve data again. I have over 2000 records in the database, every time I do something to the table, it takes 5 seconds to respond which is very annoying. How do I make it load the data only the first time and cache it on client side for future manipulation?
Finally got it to work. Solution is to move the ajax call var Ajax = fmFactory.getAll(); outside ngtable constructor.
var Ajax = fmFactory.getAll();
self.tableParams = new NgTableParams({
page: 1, // show first page
count: 10, // count per page
sorting: {
frReportId: 'asc'
}
}, {
getData: function (params) {
return Ajax.then(function(response) {
var reports = response.data;
params.total(reports.length);
console.log(params.total());
var sorted = params.sorting() ? $filter('orderBy')(reports, params.orderBy()) : reports;
return sorted.slice((params.page() - 1) * params.count(), params.page() * params.count());
});
}
});

Bind data from table to modal

I'm trying to get the data from a row (once clicked) to fill a pop-up modal window with that row of data. And then you should be able to change the data and resubmit, updating the data in the table.
The below is the code for firstly my table, and then the modal.
The data that fills the table is retrieved through a $http get request, but when the data inside the modal is changed and the table is updated subsequently, the json file retrieved does not need to be updated.
I feel I've done a large amount of searching, but all the other answers have pointed me in different directions to what I seek, or I'm searching for the wrong thing.
I'm not seeking a full solution, but if anyone could guide me in the right direction that would be very helpful. Thanks in advance for any knowledge you can share on this.
To reiterate, this is what I'm struggling with:
"I'm trying to get the data from a row (once clicked) to fill a pop-up modal window with that row of data. And then you should be able to change the data and resubmit, updating the data in the table. "
<body>
<div data-ng-app="peopleInformation" data-ng-controller="myCtrl" class="jumbotron">
<div class="panel panel-default">
<div class="panel-heading">Essential Information</div>
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Age</th>
<th>Nickname</th>
</tr>
</thead>
<tbody>
<tr data-ng-repeat="data in myData" data-ng-click="modify(data)">
<td>{{ data.FirstName }}</td>
<td>{{ data.LastName }}</td>
<td>{{ data.Age }}</td>
<td>{{ data.Nickname }}</td>
</tr>
</tbody>
</table>
<button type="button" class="btn btn-info pull-right" data-ng-click="new()">Add
</button>
</div>
</div>
</div>
</body>
Here is my modal html:
<div class="modal fade" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Your row of data</h4>
</div>
<div class="modal-body" name="modelData">
<form class="form-horizontal pull-left form-width" role="form">
<div class="form-group">
<label class="control-label col-sm-4" for="first">First Name:</label>
<div class="col-sm-8">
<input type="text" class="form-control" id="first" ng-bind="FirstName">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-4" for="last">Last Name:</label>
<div class="col-sm-8">
<input type="text" class="form-control" id="last" ng-bind="LastName">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-4" for="age">Age:</label>
<div class="col-sm-8">
<input type="text" class="form-control" id="age" ng-bind="Age">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-4" for="nick">Nickname:</label>
<div class="col-sm-8">
<input type="text" class="form-control" id="nick" ng-bind="Nickname">
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger pull-left" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-success pull-right" data-dismiss="modal">Submit</button>
</div>
</div>
</div>
</div>
Here is my JS so far too:
var app = angular.module('peopleInformation', ['ngAnimate','ui.bootstrap']);
app.controller('myCtrl', function($scope, $http, $uibModal) {
$http.get("xxxxxx.json").success(function(response){
$scope.myData = response.People;
});
$scope.modify = function(currentData){
var modalInstance = $uibModal.open({
templateUrl: 'myModalContent.html',
controller: 'ModalInstanceCtrl',
resolve: {
details: function() {
return currentData;
}
}
});
};
});
app.controller('ModalInstanceCtrl', function ($scope, $uibModalInstance, details){
$scope.FirstName = details.FirstName;
$scope.LastName = details.LastName;
$scope.Age = details.Age;
$scope.Nickname = details.Nickname;
});

View not updating after form submit

my ng-repeat is not updating after attempting to add an item to scope.
Here is my html:
<div class="col-lg-12">
<div class="panel-group" id="accordion">
<div class="panel panel-collapse panel-default" id="topPanel">
<div class="panel-heading" data-toggle="collapse" data-target="#top-action-panel-body">
<h4 class="panel-title">
Collapsible Group Item #1
</h4>
</div>
<div id="top-action-panel-body" class="panel-collapse collapse">
<div class="panel-body">
<form class="ih_enterprise_api_stock_item_new form-horizontal form-stock-item-add" ng-submit="test()" ng-controller="InventoryAddCtrl" id="ihenterprise_logisticsbundle_stockItem">
<div class="form-group">
<label class="col-sm-4 control-label control-label required" for="ihenterprise_logisticsbundle_stockItem_name">Name</label>
<div class="col-sm-8">
<input type="text" id="ihenterprise_logisticsbundle_stockItem_name" name="ihenterprise_logisticsbundle_stockItem[name]" required="required" maxlength="255" ng-model="formData.name" class="form-control form-control">
</div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label control-label required" for="ihenterprise_logisticsbundle_stockItem_itemNo">Item no</label>
<div class="col-sm-8">
<input type="text" id="ihenterprise_logisticsbundle_stockItem_itemNo" name="ihenterprise_logisticsbundle_stockItem[itemNo]" required="required" maxlength="255" ng-model="formData.itemNo" class="form-control form-control">
</div>
</div>
<div class="row">
<div class="col-md-4 col-md-offset-4">
<input type="submit" class="btn btn-success" value="Tilføj">
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-12" ng-controller="InventoryListCtrl">
<div class="panel panel-default" style="color: black; text-align: left">
<div class="panel-heading">
<h3>Lager liste</h3>
</div>
<div class="panel-body table-responsive">
<table class="table table-condensed table-expanding">
</table><table class="table table-condensed table-expanding">
<thead>
<tr>
<th> </th>
<th>Id</th>
<th>Created At</th>
<th>Navn</th>
</tr>
</thead>
<tbody>
<tr ng-repeat-start="stockItem in stockItems" data-toggle="collapse" data-target="#stockItem_{{stockItem.id}} " class="accordion-toggle">
<td>
<button class="btn btn-default btn-xs"><span class="glyphicon glyphicon-eye-open"></span></button>
</td>
<td>{{stockItem.id}} </td>
<td>{{stockItem.created_at}} </td>
<td>{{stockItem.name}} </td>
</tr>
<tr ng-repeat-end="">
<td colspan="6" class="hiddenRow">
<div class="accordian-body collapse" id="package_{{stockItem.id}} ">
test
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
Here is my code:
App.js
'use strict';
var app = angular.module('cmfApp', [
'ngRoute',
]);
angular.module('cmfApp.controllers', []);
InventoryRouting.js
angular.module('cmfApp').config(function($routeProvider){
$routeProvider.
when('/inventory', {
templateUrl: Routing.generate('ih_enterprise_user_dashboard_inventory'),
controller: 'InventoryListCtrl'
})
});
InventoryController.js
angular.module('cmfApp').controller('InventoryAddCtrl', ['$scope', '$http', '$timeout', function($scope, $http, $timeout){
$scope.submit = function() {
var postData = {
ihenterprise_logisticsbundle_stockItem: {
name: $scope.formData.name,
itemNo: $scope.formData.itemNo
}
}
$http({
method : 'POST',
url : Routing.generate('ih_enterprise_api_stock_item_new'),
data : $.param(postData), // pass in data as strings
headers : { 'Content-Type': 'application/x-www-form-urlencoded' } // set the headers so angular passing info as form data (not request payload)
})
.success(function(data) {
// the code you want to run in the next digest
$scope.$apply(function(data){
$scope.stockItems = $scope.stockItems.concat(data);
});
//console.log($scope.stockItems);
}).error(function(error) {
console.log(error);
});
};
$scope.test = function() {
console.log("here");
$scope.stockItems.push({
id: 1000,
name: 'potato',
created_at: '1111'
});
console.log($scope.stockItems);
}
}]);
Ignore the HTTP request, i was thinking it was a HTTP related issue, but it seems much more fundamental, as i attempted to just insert a plain object on submit.
You seem to be instantiating the InventoryListCtrl twice: Once in the route definition, and again in the HTML template. As a result, when you update the stockItems array, it's not updating the same array used in the view.
Try removing the ng-controller="InventoryListCtrl" from the template.
This will make InventoryListCtrl be the controller for the entire HTML template (b/c of the route definition). InventoryAddCtrl is used inside the template and it will inherit the scope of InventoryListCtrl. So when you update $scope.stockItems from either controller, you'll now be updating the same object.

Loading partial view into the main view AngularJS

I have a partial view, which I plan to include in different pages.
I tried out the following to load the partial view but the view doesn't display the values stored in the model.
Angular controller:
//This gets the required data as JSON
AdminService.getSettings(function (callback) {
$scope.attributes = callback;
$scope.groups = _.groupBy($scope.attributes, "Group");
$scope.previous = angular.copy($scope.attributes);
//This gets the partial view and adds to the main view
CommonService.SettingsListView_get(function (callback) {
angular.element('#settingsList').html(callback);
});
});
MVC Controller:
public ActionResult SettingsList()
{
return PartialView();
}
View: Main
<body ng-app="AngularAdmin" ng-cloak>
<div ng-controller="SettingsCtrl" id="top" ng-init="init()">
<br />
<div id="settingsList" >
</div>
View:partial
<div class="panel-group" id="accordion">
<div style="padding:5px 0"><button ng-click="updateAttributes(attributes)" class="btn btn-primary"><span class="glyphicon glyphicon-floppy-disk"></span> Update Settings</button></div>
<div class="panel panel-primary" data-ng-repeat="(items, item) in groups" ng-style="$index < 11 ? panelStyle[$index] : commonPanelStyle">
<div class="panel-heading" ng-style="$index < 11 ? panelHeaderStyle[$index] : commonPanelHeaderStyle">
<a data-toggle="collapse" href="#accordion{{$index}}" ng-style="anchorStyle">
<h4 class="panel-title">
{{ items }}
</h4>
</a>
</div>
<div id="accordion{{$index}}" class="panel-collapse collapse">
<div class="panel-body" ng-style="$index < 11 ? panelBodyStyle[$index] : commonPanelBodyStyle">
<table class="table">
<tr>
<th>Attribute</th>
<th>Description</th>
<th>Value</th>
<th>Taken from</th>
<th>Editable</th>
<th>Delete</th>
</tr>
<tr data-ng-repeat="i in item">
<td> {{ i.AttributeName }} </td>
<td> {{ i.Description }} </td>
<td> <input type="text" ng-model="i.Value" class="form-control" ng-disabled="{{!i.Editable}}" />
</td>
<td><span ng-bind="i.TakenFrom | settingsfilter">{{ Heritage }}</span> </td>
<td><span ng-class="i.Editable | activefilter : { icon1 : 'glyphicon-edit', icon2 : 'glyphicon-remove'}" class="glyphicon" style="font-weight: bolder"></span></td>
<td><span ng-click="deleteAttribute(i.AttributeGuid)" ng-class="i.TakenFrom | deletefilter : 1" class="glyphicon" style="font-weight: bolder"></span></td>
</tr>
</table>
<button style="float:right" class="btn btn-default" ng-click="updateAttributes(item)"><span class="glyphicon glyphicon-floppy-disk"></span> Update <em>{{ items }}</em> Settings </button>
</div>
</div>
Issue:
I can't display the settings data I can see {{ items }} and nothing else in the view.
The preferred way to achieve this is to create a "settingsList" directive and set the templateUrl to the url of the partial view. You could get rid of this:
CommonService.SettingsListView_get(function (callback) {
angular.element('#settingsList').html(callback);
});
and replace this:
<div id="settingsList" >
</div>
with this:
<div settingsList></div>
If for some reason this isn't possible in your situation, try changing your controller code the following (you'll need to inject the $compile service):
CommonService.SettingsListView_get(function (callback) {
var element = angular.element(callback);
$compile(element)($scope);
angular.element('#settingsList').append(element);
$scope.digest();
});
this code working good :
CommonService.SettingsListView_get(function (callback) {
var element `enter code here`= angular.element(callback);
$compile(angular.element('#settingsList').append(element))($scope);
});

How to switch from a bootstrap modal to a angular modal

I am switching from the bootstrap modals to Ekathuwa Angular Modals. I have a table that when I click on the "Number" a modal opens with the input fields populated with the selected objects properties. I have it working with the bootstrap modals but i am lost on how to do it the angular way.
plunkr
controller :
//editChangeOrderModal
$scope.currentItem = null;
$scope.editChangeOrderModal = function (model) {
$ekathuwa.modal({
id: 'editChangeOrderModal',
scope: $scope.currentItem = model,
templateURL: "modal-template.html"
});
};
view :
<table class=" table table-bordred table-striped table-hover">
<tr>
<th style="font-weight: bold;">Number</th>
<th style="font-weight: bold;">Date</th>
<th style="font-weight: bold;">Name</th>
</tr>
<tr ng-repeat="job in ChangeOrders" class=" pointer">
<td ng-click="editChangeOrderModal(job)">{{job.ChangeOrderNumber}}</td>
<td>{{job.ChangeOrderDate}}</td>
<td>{{job.ChangeOrderName}}</td>
</tr>
</table>
<div class="col-xs-12">
<div class="inline-fields" style="margin-top:30px">
<label>Name:</label>
<input style="width:150px" ng-model="currentItem.ChangeOrderName" type="text">
</div>
<div class="inline-fields">
<label>Number:</label>
<input style="width:150px" ng-model="currentItem.ChangeOrderNumber" type="text">
</div>
<div class="inline-fields">
<label>Date:</label>
<input style="width:150px" ng-model="currentItem.ChangeOrderDate" type="date">
</div>
<br/>
<input style="float:right"
ng-click="printEditChangeOrderModal(currentItem)"
type="button"
value="Print"
go-click="#"/>
<input style="float:right"
ng-click="updateChangeOrder(currentItem)"
type="button"
value="Save"
go-click="#"/>
<input style="float:right"
type="button"
data-dismiss="modal"
value="Exit"
go-click="#"/>
</div>
I think the problem is with this line,
scope: $scope.currentItem = model,
I changed to this
$scope.currentItem = null;
$scope.editChangeOrderModal = function(model) {
$scope.currentItem = model;
console.log(model);
$ekathuwa.modal({
id: "editChangeOrderModal",
scope:$scope,
templateURL: "modal-template.html"
});
}
I forked your [plunker]: http://plnkr.co/edit/OTJA6n7WADN5bprZaQco?p=info

Resources