"Hello World" in MVC Pattern - javascript

In an interview for some company, I was asked this question.
What design patterns do you know...then I was told to write simplest "hello world" application based on MVC Design Pattern.
I came up with a JavaScript program
var arr = ["a","b","c","d"]; // this is an array, same as store or model
alert(arr[0]); // this is controller
//and browser alert is a view.
later I was told that alert is a view. The basic concept about MVC I know is any changes in Model are reported to View. And there is a controller in between to call the methods.
Can you correct my approach, or come up with an alternate solution for hello world MVC application. Also explain subtle aspects of MVC.
Thanks.

var M = {}, V = {}, C = {};
M.data = "hello world";
V.render = function (M) { alert(M.data); }
C.handleOnload = function () { V.render(M); }
window.onload = C.handleOnLoad;
Controller (C) listens on some kind of interaction/event stream. In this case it's the page's loading event.
Model (M) is an abstraction of a data source.
View (V) knows how to render data from the Model.
The Controller tells to View to do something with something from the Model.
In this example
the View knows nothing about the Model apart from it implements some interface
the Model knows nothing of the View and the Controller
the Controller knows about both the Model and the View and tells the View to go do something with the data from the Model.
Note the above example is a severe simplification for demonstrating purposes. For real "hello world" examples in the JS MVC world go take a look at todoMVC

Better Example
var M = {}, V = {}, C = {};
/* Model View Controller Pattern with Form Example */
/* Controller Handles the Events */
M = {
data: {
userName : "Dummy Guy",
userNumber : "000000000"
},
setData : function(d){
this.data.userName = d.userName;
this.data.userNumber = d.userNumber;
},
getData : function(){
return data;
}
}
V = {
userName : document.querySelector("#inputUserName"),
userNumber : document.querySelector("#inputUserNumber"),
update: function(M){
this.userName.value = M.data.userName;
this.userNumber.value = M.data.userNumber;
}
}
C = {
model: M,
view: V,
handler: function(){
this.view.update(this.model);
}
}
document.querySelector(".submitBtn").addEventListener("click", function(){
C.handler.call(C);
});
/* Model Handles the Data */
/* View Handles the Display */

MVC Architecture
I have written an article about MVC architecture. Here is only some code present,hope anyone finds it helpful.
//Modal
var modal = { data: "This is data"};
//View
var view = { display : function () {
console.log ("////////////////////////////");
console.log ( modal.data);
console.log ("////////////////////////////");
}
};
//Controller
var controller = ( function () {
view.display();
})();
From the above example just understand that there are three different units in this design where each has a specific job to perform. Let's build the MVC design from the above infra structure .There can be more than one view and Observer, here only another view is created first.
// Modal
var modal = { data: "This is data"};
// View
var slashView = { display : function () {
console.log ("////////////////////////////");
console.log ( modal.data);
console.log ("////////////////////////////");
}
};
var starView = { display : function () {
console.log ("****************************");
console.log ( modal.data);
console.log ("****************************");
}
};
// Controller
var controller = ( function () {
slashView.display();
starView.display();
})();
What is understood here is that the modal must not be dependent upon either the view or viewers or the operations performed on the data. The data modal can stand alone but the view and controller are required because one needs to show the data and the other needs to manipulate it. Thus view and controller are created because of the modal and not the other way round.
//Modal
var modal = {
data : ["JS in object based language"," JS implements prototypal inheritance"]
};
// View is created with modal
function View(m) {
this.modal = m;
this.display = function () {
console.log("***********************************");
console.log(this.modal.data[0]);
console.log("***********************************");
};
}
function Controller(v){
this.view = v;
this.informView = function(){
// update the modal
this.view.display();
};
}
// Test
var consoleView = new View(modal);
var controller = new Controller(consoleView);
controller.informView();
From the above it can be seen that there has been a link established between view and the controller. And this is one of the requirement of MVC pattern. To demonstrate the change in the modal let's change the program and observe that change in the state of modal is done independently and reflects in view.
//Modal
function Modal(){
this.state = 0;
this.data = ["JS is object based language","JS implements prototypal inheritance"];
//
this.getState = function (){
return this.state;
};
this.changeState = function (value) {
this.state = value;
};
}
// View is created with modal
function View(m) {
this.modal = m;
this.display = function () {
console.log("***********************************");
console.log(this.modal.data[modal.getState()]);
console.log("***********************************");
};
}
//controller is created with the view
function Controller(v){
this.view = v;
this.updateView = function(){
// update the view
this.view.display();
};
}
// Test
var modal = new Modal();
var consoleView = new View(modal);
var controller = new Controller(consoleView);
controller.updateView();
// change the state of the modal
modal.changeState(1);
controller.updateView();
When the state of the modal is changed the controller has sent the message to the view to update itself. It is fine, but still one main concept is left to be implemented and that is the observer or controller needs to be identified by the modal . In order to see this happening, there has to be a link between modal and the controller so that any number of controller can show the interest in the modal, this is considered as registering the observer to the modal. This relation ship is implemented using the concept that observer does not exist in the air. Its existence come because of having interest in the modal thus when it is created it has to be created using the modal that it needs to show interest or in other words it has an access to the modal. Let's look at the example below and see how this MVC design pattern is achieved simply and elegantly using JavaScript.
function Modal(){
var stateChanged = false;
var state = 0;
var listeners = [];
var data = ["JS is object based language","JS implements prototypal inheritance"];
// To access the data
this.getData = function(){
return data;
};
// To get the current state
this.getState = function (){
return state;
};
// For simplicity sake we have added this helper function here to show
// what happens when the state of the data is changed
this.changeState = function (value) {
state = value;
stateChanged = true;
notifyAllObservers();
};
// All interested parties get notified of change
function notifyAllObservers (){
var i;
for(i = 0; i < listeners.length; i++){
listeners[i].notify();
}
};
// All interested parties are stored in an array of list
this.addObserver = function (listener){
listeners.push(listener);
};
}
// View class, View is created with modal
function View(m) {
this.modal = m;
this.display = function () {
console.log("***********************************");
var data = this.modal.getData();
console.log(data[modal.getState()]);
console.log("***********************************");
};
}
// Controller or Observer class has access to both modal and a view
function Controller(m,v){
this.view = v;
this.modal = m;
this.modal.addObserver(this);
// update view
this.updateView = function(){
this.view.display();
};
// Receives notification from the modal
this.notify = function(){
// state has changed
this.updateView();
};
}
// Test
var modal = new Modal();
var consoleView = new View(modal);
var controller = new Controller(modal,consoleView);
// change the state of the modal
modal.changeState(1);
modal.changeState(0);
modal.changeState(1);
modal.changeState(0);
From the above it can be seen that the observer has register itself using modal addObsever function and establishes a link to the modal. Once all instances are created. Modal state was changed manually to show the effect in the view. Typically in GUI environment, the change is usually done either with a user pressing any button or from any other external input. We can simulate the external input from the random generator and observe the effect. Here in the example below, some more elements are added in the data to show the effect clearly.
function Modal(){
var stateChanged = false;
var state = 0;
var listeners = [];
var data = [
"JS is object based language","JS implements prototypal inheritance",
"JS has many functional language features", "JS is loosely typed language",
"JS still dominates the Web", "JS is getting matured ","JS shares code
through prototypal inheritance","JS has many useful libraries like JQuery",
"JS is now known as ECMAScript","JS is said to rule the future of Web for
many years"];
//
this.getData = function(){
return data;
};
//
this.getState = function (){
return state;
};
this.changeState = function (value) {
state = value;
stateChanged = true;
notifyAllObservers();
};
function notifyAllObservers (){
var i;
for(i = 0; i < listeners.length; i++){
listeners[i].notify();
}
}
this.addObserver = function (listner){
listeners.push(listner);
};
}
// View is created with modal
function View(m) {
this.modal = m;
this.display = function () {
console.log("****************************************************");
var data = this.modal.getData();
console.log(data[modal.getState()]);
};
//Adding external simulation of user sending input
this.pressButton = function(){
var seed = 10;
var number = Math.round(Math.random() * seed) ;
// change the state of modal
this.modal.changeState(number);
};
}
// Controller class needs modal and view to communicate
function Controller(m,v){
this.view = v;
//console.log(this.view.display);
this.modal = m;
this.modal.addObserver(this);
this.updateView = function(){
// update the view
//console.log(this.view);
this.view.display();
};
this.notify = function(){
// state has changed
this.updateView();
};
}
// Test
var modal = new Modal();
var consoleView = new View(modal);
var controller = new Controller(modal,consoleView);
// change the state of the modal
for ( var i = 0 ; i < 10; i++){
consoleView.pressButton();
}
The above example demonstrates the use of MVC frame work where a modal is kept independent of the view and and the controller. The modal representing the data is responsible of notifying all the interested parties that has shown the interest and registered themselves with the modal. As soon as any change happens notification is send to the parties and action is left upon them. The example below is slightly different from the above where only newly added data is shown by the observer.
function Modal(){
var stateChanged = false;
var listeners = [];
var data = ["JS is object based language"];
// To retrieve the data
this.getData = function(){
return data;
};
// To change the data by any action
this.modifyData = function (string) {
( data.length === 1 )? data.push(string): data.unshift(string);
stateChanged = true;
notifyAllObservers();
};
// Notifies all observers
function notifyAllObservers (){
var i;
for(i = 0; i < listeners.length; i++){
listeners[i].notify();
}
}
// Requires to register all observers
this.addObserver = function (listener){
listeners.push(listener);
};
}
// View is created with modal
function View(m) {
this.modal = m;
this.display = function () {
console.log("****************************************************");
var data = this.modal.getData();
console.log(data[0]);
console.log("****************************************************");
};
//Adding external simulation of user sending input
this.pressButton = function(string){
// change the state of modal
this.modal.modifyData(string);
};
}
// View class
function Controller(m,v){
this.view = v;
this.modal = m;
this.modal.addObserver(this);
// Updates the view
this.updateView = function(){
this.view.display();
};
// When notifies by the modal send the request of update
this.notify = function(){
// state has changed
this.updateView();
};
}
// Test
var modal = new Modal();
var consoleView = new View(modal);
var controller = new Controller(modal,consoleView);
consoleView.pressButton();
consoleView.pressButton("JS dominates the web world");
consoleView.pressButton("JQuery is a useful library of JS");
The last thing which one may like to add is to delete the observer when not needed.This can be done through adding a method called removeObserver(object) in the modal calls. The above MVC design pattern can be more refined by using subcalssing and having common function present in the top class making the design as simple as possible but it is left on some other article. Hope it helps.

MVC is a design pattern that should be used to structure your application. MVC stands for Model, View, Control. It basically sais that you should separate your business-logic (Model) from your User Interface (View) and your Control-Logic.
For example:
You have a user class, that loads users from the database, can save em. This is your model.
You have a Controller that uses the User class to log a user in.
After the controller is done, it displays a Template containing the Text "Welcome $username".
Also, the Model should not know about the View and the Controller, the View should not know about the Controller, whereas the Controller knows about the Model and the View.
Wikipedia on MVC: http://de.wikipedia.org/wiki/Model_View_Controller

I think you're kind of missing the point here.
MVC is a pattern you'd use for designing an application. I think at the minimum you'd expect to be able to change the model, and see the change reflected in the view.
You'd typically have an object to represent the model, a different object to represent the "view" (which would probably mediate between the model and the HTML objects that you're using as the view) and a controller, which would take inputs from your HTML objects and update the model.
So you change an edit field, the edit field tells the controller, the controller updates the model, the model fires events that the controller uses to update any other view components that depend on this data.
It'd be a few more lines to implement a "hello world" version, but I think this is what I'd be looking for from an interview question like this.

So I made a simple example MVC with data output at console.log().
let model = {
data: {
text: "Hello World",
},
};
let view = {
init: function () {
this.render();
},
render: function () {
console.log(model.data.text);
},
};
let controller = {
init: function () {
view.init();
},
};
controller.init();

Related

How to get the javascript file path at run-time

Requirement:
I want to find all the backbone views (src file path) used to develop an existing page. In our case each back-view will be maintained in a separate js file. In a nutshell I want to find the js files path (views which are extending Backbone view).
What I have tried:
I our case we have a wrapper view which is extending Backbone view, further all views will extends the wrapper view. So In the initialize method of wrapper-view I am generating error to get the call stack and further I am able to find the js-file-paths.
var WrapperView = Backbone.View.extend({
initialize: function() {
this.track();
},
track : function() {
try{
throw new Error("STACK");
}
catch(e){
this.$el.attr('view-url', e.stack.match(/\bhttps?:\/\/.*js*(?=(?:(?!http)[\s\S])*https?:\/\/\S*backbone-min\.js)/)[0]);
}
if(Object.observe){
Object.observe(this, function(changes){
var eleProp = _.filter(changes, function(prop){ return prop.name == "$el"; })[0];
if(!eleProp) return;
eleProp.object.$el.attr('view-url', j$(eleProp.oldValue).attr('view-url'));
}, ["update"])
}
}
});
var ChildView = WrapperView.extend({
initialize: function() {
WrapperView.prototype.initialize.apply(this);
this.track();
}
});
Backbone will invoke ------> ChildView.initialize --------> WrapperView.initialize();
As the ChildView.initialize function call is in call stack, I can get the file path.
What I want:
Though above solution is working, I don't want to include my track logic in the WrapperView, as it may not guarantee that all child views will call the WrapperView.prototype.initialize and I don't want to touch the framework src. So to fix this I included the track logic in Backbone.View (Js plugin) itself instead of WrapperView.
(function(){
var _viewExtend = Backbone.View.extend;
var newExtend = function (protoProps, classProps) {
var _init = protoProps.initialize;
var newInit = function(){
try{
throw new Error("STACK");
}
catch(e){
this.$el.attr('view-url', e.stack.match(/\bhttps?:\/\/.*js*(?=(?:(?!http)[\s\S])*https?:\/\/\S*backbone-min\.js)/)[0]);
}
if(Object.observe){
Object.observe(this, function(changes){
var eleProp = _.filter(changes, function(prop){ return prop.name == "$el"; })[0];
if(!eleProp) return;
eleProp.object.$el.attr('view-url', j$(eleProp.oldValue).attr('view-url'));
}, ["update"]);
}
return _init.apply(this, arguments);
};
protoProps.initialize = newInit;
return _viewExtend.call(this, protoProps, classProps);
};
Backbone.View.extend = newExtend;
})();
But the call stack not included the childview file path as the no call got made from child-view, so please help me to find a way get the things done.
Backbone will invoke ------> newInit (stack generated here) --------> Childview.initialize();
Note: If any other approach is there to achieve the requirement, please let me know.

Returning a knockout view model on pushstate / popstate

I've been trying for some time to save a ko viewmodel to the browser history and return it on a popstate event. Currently no errors are being thrown, but nothing is being changed on the popstate. The basic flow of what I'm trying goes like this:
var storeViewModel = function (){
return ko.toJSON(viewModel);
};
function viewModel() {
var self = this;
self.records = ko.observableArray();
// add an object to the array and save view model
self.addRecord = function () {
self.records.push(new record());
// call the storeViewModel function push viewModel to history
history.pushState(storeViewModel(), "");
}
// set view model to stored view model object on forward / back navigation navigation
window.onpopstate = function (event) {
self = ko.utils.parseJson(event.state);
}
}
ko.applyBindings(new viewModel());
I've read the mozilla documentation for this several times. Everything seems to make sense, but I am having trouble in implementation. Thanks for any help!
You wouldn't save the viewmodel, but the data it contains.
The most convenient way to do that is by employing automatic mapping. Knockout has the [mapping plugin][1] for this; it allows you to easily turn raw data into a working viewmodel, and a working viewmodel back into raw data.
By default the mapping plugin maps all properties of the raw data to observable or observableArray, respectively, but that can be fine-tuned in the mapping definition (see documentation).
This basically works like this:
ko.mapping.fromJS(data, {/* mapping definition */}, self);
and back like this:
ko.mapping.toJS(self);
I'd recommend setting up all your viewmodels so they can bootstrap themselves from raw data:
function Record(data) {
var self = this;
// init
ko.mapping.fromJS(data, Record.mapping, self);
}
Record.mapping = {
// mapping definition for Record objects, kept separately as a constructor
// property to keep it out of the individual Record objects
};
and
function RecordPlayer(data) {
var self = this;
self.records = ko.observableArray();
self.init(data);
self.state = ko.pureComputed(function () {
return ko.mapping.toJS(self);
});
}
RecordPlayer.mapping = {
// mapping rules for ViewModel objects
records: {
create: function (options) {
return new Record(options.data);
}
}
};
RecordPlayer.prototype.init = function (data) {
// extend a default data layout with the actual data
data = ko.utils.extend({
records: []
}, data);
ko.mapping.fromJS(data, ViewModel.mapping, this);
};
RecordPlayer.prototype.addRecord = function () {
this.records.push(new Record());
};
The mapping plugin keeps track of all the properties it mapped in the .fromJS step and only returns those in the .toJS() step. Any other properties, like computeds, will be ignored.
That's also the reason for the ko.utils.extend - to establish the baseline set of properties that you want the mapping plugin to handle.
The state computed now changes every time the state-relevant data changes, due to knockout's built-in dependency tracking.
Now what's left is handling the page load event:
// initialize the viewmodel
var player = new RecordPlayer(/* data e.g. from Ajax */);
// subscribe to VM state changes (except for changes due to popState)
var popStateActive = false;
player.state.subscribe(function (data) {
if (popStateActive) return;
history.pushState(ko.toJSON(data), "");
});
// subscribe to window state changes
player.utils.registerEventHandler(window, "popstate", function (event) {
popStateActive = true;
player.init( ko.utils.parseJson(event.state) );
popStateActive = false;
});
// and run it
ko.applyBindings(player);
You can expand and run the code snippet below to see it in action.
function Record(data) {
var self = this;
// init
ko.mapping.fromJS(data, Record.mapping, self);
}
Record.mapping = {
// mapping definition for Record objects, kept separately as a constructor
// property to keep it out of the individual Record objects
};
function RecordPlayer(data) {
var self = this;
self.records = ko.observableArray();
self.init(data);
self.state = ko.pureComputed(function() {
return ko.mapping.toJS(self);
});
}
RecordPlayer.mapping = {
// mapping rules for RecordPlayer objects
records: {
create: function(options) {
return new Record(options.data);
}
}
};
RecordPlayer.prototype.init = function(data) {
// extend a default data layout with the actual data
data = ko.utils.extend({
records: []
}, data);
ko.mapping.fromJS(data, RecordPlayer.mapping, this);
};
RecordPlayer.prototype.addRecord = function() {
this.records.push(new Record());
};
RecordPlayer.prototype.pushState = function() {
history.pushState(this.state(), "");
};
// initialize the viewmodel
var player = new RecordPlayer( /* optional: data e.g. from Ajax */ );
var popStateActive = false;
// subscribe to VM state changes (except for changes due to popState)
player.state.subscribe(function(data) {
if (popStateActive) return;
history.pushState(ko.toJSON(data), "");
});
// subscribe to window state changes
ko.utils.registerEventHandler(window, "popstate", function(event) {
popStateActive = true;
player.init(ko.utils.parseJson(event.state));
popStateActive = false;
});
// and run it
ko.applyBindings(player);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.min.js"></script>
<p>Records:
<span data-bind="foreach: records">
<span>(o)</span>
</span>
</p>
<p>There are <span data-bind="text: records().length"></span> records in the player.</p>
<button data-bind="click: addRecord">Add record</button>
<button data-bind="click: function () { history.back(); }">Undo (<code>history.back()<code>)</button>

How to replace jquery with the mithril equivalent?

Something like :
peer.on('open', function(id){ // this is a non jquery event listener
$('#pid').text(id);
});
With something like...this is not correct:
peer.on('open', function(id){
m('#pid',[id])
});
Is this even the right approach? Should I be establishing a controller and model before I attempt to convert from jquery?
More details:
I am trying to rewrite the connect function in the PeerJS example: https://github.com/peers/peerjs/blob/master/examples/chat.html
If your event listener is something like websockets, then the event happens outside of Mithril, which means you need to manage redrawing yourself. This is what you'll need to do:
Store your data in an independent model
Use that model when rendering your Mithril view
On the open event, update your model, then call m.redraw()
Conceptual example:
var myModel = { id: 'blank' }
var MyComponent = {
view: function () {
return m('#pid', myModel.id)
}
}
m.mount(document.getElementById('app'), MyComponent)
// This happens outside mithril, so you need to redraw yourself
peer.on('open', function(id) {
myModel.id = id
m.redraw()
})
In Mithril, you should not try to touch the DOM directly. Your event handler should modify the View-Model's state, which should be accessed in your View method. If you post more code, I could give a more detailed explanation of how it pieces together.
Here is a bare-bones example that shows the data flowing through Mithril. Your situation will need to be more complicated but I'm not currently able to parse through all of that peer.js code.
http://codepen.io/anon/pen/eNBeQL?editors=001
var demo = {};
//define the view-model
demo.vm = {
init: function() {
//a running list of todos
demo.vm.description = m.prop('');
//adds a todo to the list, and clears the description field for user convenience
demo.vm.set = function(description) {
if (description) {
demo.vm.description(description);
}
};
}
};
//simple controller
demo.controller = function() {
demo.vm.init()
};
//here's the view
demo.view = function() {
return m("html", [
m("body", [
m("button", {onclick: demo.vm.set.bind(demo.vm, "This is set from the handler")}, "Set the description"),
m("div", demo.vm.description())
])
]);
};
//initialize the application
m.module(document, demo);
Notice that the button is calling a method on the View-Model (set), which is setting the value of a property (vm.description). This causes the View to re-render, and the div to show the new value (m("div", demo.vm.description())).

How do you handle with control binding in jquery

I have a question about jquery and DOM manipulation. How do you handle with DOM controls for e.g.
I have to get value from text input so I could this in ways:
var SomeClass = function() {
var control;
this.setControl = function(c) {
control = c;
}
this.getValue = function() {
return control.val();
}
}
$(document).ready(function() {
var sc = new SomeClass(); // of course control could be passed in contructor as well
sc.setControl($('#CONTROL'));
console.log(sc.getValue());
});
OR
var SomeClass = function() {
var control = $('#CONTROL');
this.getValue = function() {
return control.val();
}
}
$(document).ready(function() {
var sc = new SomeClass();
console.log(sc.getValue());
});
what is your opinion? What is better or maybe this is pile of trash therefore what is the best solution. Plz dont send me to backbone, spine and so on Im interesed in only in jquery.
best!
EDIT:
do you separate logic from UI or you are mixing it?
more complicated example
in js file you have a class that uses text control and in the secound js file also you need values from this input. What you are doing? you just call everytime $('#control') or create a third js file where would be a separated "class" to manipulate this input?
It would make more sense to move the setValue() inside the constructor:
SomeClass = function(c) {
var control = c;
return {
getValue: function() {
return control.val();
}
}
}
var x = new SomeClass($('input'));
alert(x.getValue());
However, I'm not sure how valuable this kind of information hiding will be. Perhaps as some kind of view wrapper.
In many cases you wouldn't need this wrapper, so just:
var $x = $('input'); // keep reference to a bunch of <input> elements.

Having more then one Jquery Dialog box and only closing one instance at a time

I am trying to implement multiple instances of Jquery's Dialog box in the same site. The problem is that I have two instances that I initiate with a new'able function like so:
function Modal(param) {
this.modal = null;var that = this;
var init = funciton (param) {
that.setupWindow(param);
}
this.setupWindow = function (param) {
var selector = param.selector;
var params = {} // dialog options go here
this.modal = $(selector);
this.modal.dialog(params);
}
}
var f_inst = new Modal({selector: '#f_modal'});
var s_inst = new Modal({selector: '#s_modal'});
Problem:
if I call f_inst.modal.dialog('close') or s_inst.modal.dialog('close'), this action will actually close both instances of the dialog box.
These two dialog boxes are using two different templates to render them.
If this is a default behavior in jquery ui dialog box, does anyone out there have a better solution?
YUI 2 Container modal widget works very good when trying to have multiple instances of the container widget. I am trying to find a modal that offers similar functionality.
Thanks in advance.
-eric
I think you want to change this to that in all cases
function Modal(param) {
var that = this;
that.modal = null;
var init = funciton (param) {
that.setupWindow(param);
}
that.setupWindow = function (param) {
var selector = param.selector;
var params = {} // dialog options go here
that.modal = $(selector);
that.modal.dialog(params);
}
}
var f_inst = new Modal({selector: '#f_modal'});
var s_inst = new Modal({selector: '#s_modal'});
I did not test this - but I believe this.setUpWindow is tied to the Modal function which there is only one of, even if you new up multiple instances they are referencing the same object/function
by wiring everything to the that var you will actually get separate instances

Categories

Resources