|
Home | Switchboard | Unix Administration | Red Hat | TCP/IP Networks | Neoliberalism | Toxic Managers |
(slightly skeptical) Educational society promoting "Back to basics" movement against IT overcomplexity and bastardization of classic Unix |
Recommended Books | Humor |
|
JavaScript has object model completely different and superior to Java. It is called prototype based model. The language itself has nothing to do with Java. The name was chosen for marketing reasons.
|
Prototype Based Model could be described as Object Oriented model that is distinct from class based model introduced by Simula-75 and inherited by C++ and Java.
Prototype-based languages and systems are made up of self describing (abstractable) objects, unlike classical object oriented systems in which objects are described by classes. It is based on using associative arrays for objects. They are (of course) dynamically extensible, and you can put methods in there, too. And you can do that dynamically, which is impossible in static (class-based) OO languages.
In Perl terms it is like a copy of hash structure without coping of the data, but with copying of procedure references if they exist.
Prototype-based OO model is conceptually simpler than class-based OO model, but is more flexible and more powerful. Here is a relevant quote from Wikipedia
Prototype-orientation, or more commonly, prototype based programming, is a specific style of object-oriented programming. The first example of a prototype based language was Self, work which has been copied in other projects such as Cecil, JavaScript, NewtonScript, Io and the MOO programming language.
With traditional OO systems, objects come in two general types. Classes organize the basic layout and functionality of other objects, and instances are "usable" objects based on the pattern inside a particular class. Using such a system typically means designing the classes you'll need, and then writing a program that creates various instances of those classes for the user to work with.
If you look inside the computer you can quickly see the reason for this dichotomy. The classes are in fact collections of code for the objects, which is the same for all instances, whereas the instances are collections of memory holding the object's data, which is what really distinguishes them from each other (a concept known as state). This model works well with traditional compilers and languages in general, which basically write code and then have that code manipulate data.
For instance, lets say you're making an address book application that can phone people. You would have a class called Person to hold the list of people. People have names and a phone number. If you were to look at such a program you would find that your Person was represented by a block of memory with the code for dialing the phone, and the various instances (Bob, Mary, etc.) are blocks of memory with a pointer to their class, along with the name and phone number. When you ask the system to phone Bob, it looks up Bob's phone number from the instance data, and then looks up the phone method by following the pointer back to the code in the Person class.
However these systems have a serious problem that is only notable as system size grows. Programs rarely remain static, and invariably the original class structure becomes less useful. That results in more code being added to new classes, which largely negates the value of OO systems.
It would be easier if your program could change the behavior of these underlying classes, but in most systems they are compiled code that can't be changed.
Prototype languages avoid this problem by dispensing with the duality that causes the problem. Instead of data-containing instances and function-containing classes, they just have objects, and nothing but objects.
To make a new object you make a copy of an existing one. All such systems start with at least a single Object loaded up, but they all have a list of common objects to work from which makes it more like a traditional system. When you copy an object you get an entirely new one that starts with the same default behaviors as it's original. Instead of having a pointer to a class, this new object contains a pointer to the object that created it.
In fact the new object is largely empty. It will only start growing in memory if and when the program changes it. This is quite different than a traditional OO system, where every instance of a class always sets aside a known amount of memory. Here the basic object consists of only one pointer.
Additional data can be added to any object at any time. If you want your new Person to have a name of "Bob", just go ahead and add it. The object will, at that point, grow to hold the new data as needed.
This is a very important distinction with conventional languages. Since the objects grow as needed, you can add anything to any object. Want Bob's object to have a "cell phone"? Go ahead. Mary has a "fax number"? Fine. In fact every object in such a system tends to be different than every other, not only in the data itself, but in what data is being recorded.
Its also important to consider that the same sort of "add anything" rule applies to methods as well as data. If your Mary object needs a new method that no one else needs, say "send fax", you can add that method using the same methodology. For this reason most prototype based languages refer to both data and methods as "slots".
Prototype based languages tend to start with a selection of basic objects that you can make copies of. In general these objects tend to have method definitions only, relying on the programmer to add the data as needed. For instance, a Point object that can record positions on the screen might contain methods for adding and subtracting points, but it wouldn't in fact include the x and y definitions – that would be up to the programmer to add to the individual point objects they copy.
All of this results in a tremendous amount of flexibility. Bugs in existing object methods can be fixed as easily as sending the new code (in the form of blocks) into the appropriate "slot". You can turn any object into one that handles remote invocation by replacing methods in the same fashion. Class design becomes a much simpler task, notably because you can easily change the "class" definitions at any point in time, and more importantly, within any application (ie, one app can fix bugs in Object and no one else will see this change).
Further information about prototype based programming object oriented languages is available via the following URLs.
Languages:
Workshops
|
Switchboard | ||||
Latest | |||||
Past week | |||||
Past month |
Slashdot
Re:Deja vu by RovingSlug (Score:2) Saturday March 27, @01:11PM
prototype based languages (Score:5, Informative)
by Jecel Assumpcao Jr (5602) on Saturday March 27, @01:40PM (#8689938)
(http://www.merlintec.com/)When running a program, it is very likely that you will want to create new objects as you go along. You have some alternatives:
- call a magic constructor function (C++ and friends)
- send a message like "new" to a factory object (like a class in Smalltalk)
- send a message like "copy" or "clone" to an object that is like the one you want to create
In the third case you might find out that you can get by with a set of "prototype" objects to copy from and you don't need classes at all. But to actually eliminate classes you will have to find solutions to the other things they do for you like hold the behaviors for the objects (you can put them in the objects themselves, for example) and reflection (Self uses special "mirror objects" for that).
There are several different styles of prototype based languages [dekorte.com].
Re:prototype based languages (Score:4, Interesting)
by Piquan (49943) on Saturday March 27, @04:40PM (#8691002)Re:Deja vu by ZenFu (Score:1) Saturday March 27, @02:18PMBeing a Lisp programmer, I'm always looking for new ideas to bring into my Lisp programs. It looks like Lisp-- possibly even CLOS-- could support prototype-based programming without extensive pain.
One thing that I'm wondering about in prototype-based OOP is redefining stuff. In Smalltalk and CLOS (I don't know Self), you can redefine methods over classes on the fly, or change member variable definitions, or whatever. I take advantage of this to have a production server running for months while I make improvements.
But in a prototype language, this looks, well, difficult. If your methods are associated with prototype objects, then if you have existing non-prototype objects and change a method, then would the non-prototype objects get the method def passed down, or what?
It seems like a prototype language would also have problems with multiple inheritance and multiple dispatch, but it looks like they've licked those too. Interesting.
- Inheritance in Prototype-based Languages by ingenuus (Score:3) Saturday March 27, @06:32PM
Re:Deja vu (Score:4, Informative)
by angel'o'sphere (80593) <{ed.rotnemoo} {ta} {redienhcs.olegna}> on Saturday March 27, @03:23PM (#8690506)
(http://www.oomentor.de/ | Last Journal: Saturday February 15, @08:36AM)What's a "prototype-based object-oriented" language and how does it differ from C++ and Java?In Java and C++ you have classes. In a prototyped language usually not, there you only have objects.
To make it simple, lets look at the java.util.Hashtable.
Suppose if you write this:
class MyClass {} the compiler would do this:
Object MyClass = new HashTable();So, instead of defining a class, you just created an empty object
... I used a Hashtable, because that makes the later explanations more easy, it could have been simply an object of course. So far your class has no properties
... no data and no methods. So you likely would write something like this:
class MyClass {
Object start;
Object end;
}As prototyped languages are usually typeless you would only need to write this:
class MyClass {
start;
end;
}
Our hypotetical compiler makes this from your typed code:
Object MyClass = new Hashtable();
// define a "new class"
MyClass.add("start", null);
MyClass.add("end", null);So, instead of "defining" a class, like you did in Java or C++, you only created an object in the most global namespace. That object is called "MyClass" just as your class would have been called.
That object has two "slots" with the names "start" and "stop", just like a class would have two attributes of type Object.
So: the concept is called prototyping, because you would usually initialize the MyClass object more properly, so that "start" and "end" would have a value and would not be empty.
Now comes the interesting point: we know how to make classes now. How to make objects from them?
Well, all Objects have a method called "new".
In java you would write new MyClass(). But you could of course assume a class had a static method called NEW().
So MyClass.NEW() would create a new object of type MyClass. That method is usualy build into the language and every "class" has it. So, what does NEW() do? It "clones" the object MyClass.
In Java we have a class MyClass, and with new we create objects. The objects have some kind of poitner to their class.
In a prototyped language you only have objects. If you say new to them, they simply create a clone from themselves. The original object is called "prototype" or "traits". Instead of calling a constructor to initialize such a new created object it is fully initialized with default values during teh cloning.
Why did I use a Hashtable as example? Well, you simply can tell a Hashtable to clone itself
... if the Hashtable describes a prototype. The slots in a Hashtable are similar to teh slots in an object of an prototyped language. Suich a slot usualy has a name and can hold any object ... methods are objects as well :D You can merge objects
... and so you do not only get a new object but also a new "class". Thats one way how inheritance could be implemented. But usualy you use nested Hashtables for inheritance, as yoou most often want single inheritance only .. and merging is used for mixins .... another term wixh would need an explanaition as long as this one. Regards,
angel'o'sphere
Amazon.com
In recent years, an alternative to the traditional class-based object-oriented language model has emerged. In this prototype-based paradigm, there are no classes. Rather, new kinds of objects are formed more directly by composing concrete, full-fledged objects, which are often referred to as prototypes. When compared to class-based languages, prototype-based languages are conceptually simpler, and have many other characteristics that make them appealing, especially for the development of evolving, exploratory and/or distributed software systems. The distinction between class-based and prototype-based systems reflects a long-lasting philosophical dispute concerning the representation of abstractions. Class-based languages, such as Smalltalk, C++ and Java, explicitly use classes to represent similarity among collections of objects. Prototype-based systems, such as Self, NewtonScript and Omega, do not rely so much on advance categorization, but rather try to make the concepts in the problem domain as tangible and intuitive as possible. A typical argument in favor of prototypes is that people seem to be much better at dealing with specific examples first, then generalizing from them, than they are at absorbing general abstract principles first and later applying them in particular cases. This book presents the history and development of prototype-based programming and describes a number of prototype-based programming languages and applications. Such range from programs for portable digital appliances, graphical user-interface management systems for desktop and workstations, and cutting edge research on software visualisation and program restructuring. The book will be suitable for advanced software development practitioners, graduate students, and researchers active in the field.
[PDF]
View as HTML
Page 1. Advanced issues in object oriented programming, prototype based languages
page: 1 out of 1 Advanced Issues in Object Oriented Programming Object Based ...
www.doc.ic.ac.uk/~scd/Teaching/ObjectBased.pdf
My friend Dave Fayram (who helped bring advanced LSI classification to Ruby's classifier) has heeded Matz's advice to learn Io and is bringing me with him. I have been thinking a lot about prototyped versus class-based languages lately and once I really understood it, I fell in love. I have a feeling I will be writing a lot about this topic, but here is a brief introduction.# Class-based Ruby class Animal attr_accessor :name end # A class can be instantiated amoeba = Animal.new amoeba.name = "Greenie" # A new class needs to be defined to sub-class class Dog < Animal def bark puts @name + " says woof!" end end # A sub-class can be instantiated lassie = Dog.new lassie.name = "Lassie" lassie.bark # => Lassie says woof!
Notice in the Io version that you never ever define a class. You don't need to.
# Prototype-based Io Animal := Object clone # An object can be instantiated amoeba := Animal clone amoeba name := "Greenie" # An object can be used to sub-class Dog := Animal clone Dog bark := method( write(name .. " says woof!") ) # An object can be instantiated lassie := Dog clone lassie name := "Lassie" lassie bark # => Lassie says woof!
You will notice some syntactical differences immediately. First, instead of the dot (.) operator, Io uses spaces (note: technically, with a couple lines of Io you can actually make Io use the dot operator or the arrow operator (->) or anything else you would like).
Next, you will notice that instead of making a new instance of a class, when you use prototype-based languages you clone objects. This is the foundation of prototyping… defining classes is unnecessary, everything is just an object! Furthermore, every object is essentially a hash where you can set the values of the hash as methods for that object.
You get a sense for this kind of idea in Ruby when you do this:
class Hmm end Hmm.class # => Class
So the class of the
Hmm
class is a class… classes are instance objects ofClass
. In short, almost everything in Ruby is an object already, except whas is the class ofClass
?Class.class # => Class
If you have never seen this before, you might want to take a minute to recuperate from the aneurism this should have caused. If fact, this is a conundrum found in all class-based programming languages and is solved in various different ways (in Ruby, Matz chose to solve this paradox by making
Class
a singleton class).The important part to take away from this discussion is that almost everything in Ruby is an object, even classes. Prototyping embraces this fact and takes it the last step necessary for the abstraction and completely removes the distinction between a class and an object. Once you see it this way, you will notice that having classes at all is a crutch… an unnecessary layer that doesn't add to object-oriented programming… in fact it makes things more confusing to have the separation at times.
How could class-based programming make things more confusing you ask? The answer lies in metaprogramming. Metaprogramming in Ruby can be beautifully easy. Here is a canonical example:
# Meta-programming-free class Foo def bar @bar end def bar=(bar) @bar = bar end end # Meta-programming added with the method "attr_accessor" class Foo attr_accessor :bar end
However, more involved metaprogramming, like that found in Rails' ActiveRecord implements metaprogramming for thing like
has_many
in the following way.module AnimalSounds def bark puts "woof" end def self.append_features(base) super base.extend(ClassMethods) end module ClassMethods def create_sound(attr_name) define_method(attr_name) { puts "Method #{attr_name} called" } end end end class Pet include AnimalSounds create_sound :meow end fido = Pet.new fido.bark fido.meow
The implementation of
create_sound
is very convoluted, though in the end we are left with a very nice interface. The convolution is birthed from the separation between classes and instances in Ruby. When you give up your grasp of classes and enter the world of prototyped languages, metaprogramming at this level falls into place much easier and cleaner.AnimalSounds := Object clone AnimalSounds bark := "woof" AnimalSounds createSound := method(attrName, self setSlot(attrName, block("Method " .. attrName .. " called")) ) Pet := Object clone appendProto(AnimalSounds) Pet createSound("meow") fido := Pet clone fido bark fido meow
Interesting, isn't it. I wonder what Rails's ActiveRecord and it's engines would look like in Io, don't you?
As a final mention to the power of prototyping, I would like to mention ActionScript, which is Macromedia's programming language available within Flash. On the face of it, it looks like any other class-based programming language, but the class of
Class
paradox is mute because ActionScript a prototype-based language. The "Class" is basically a clone of anObject
. Think on that. Classes are just a prototype pattern.Posted in Io, Programming, Ruby | 14 comments
Comments
- nukeedit
Blaine Cook said about 1 hour later:
ActionScript := ECMAScript clone appendProto(flashInterface)
JavaScript := ECMAScript clone appendProto(browserInterface)
So that's why I like JavaScript so much…
:-)
- nukeedit
Erwin Lech said about 16 hours later:
So does this mean JavaScript is a prototype based language too?
- nukeedit
Lucas Carlson said about 16 hours later:
Yes, JavaScript is prototype-based and very fun to work with when you discover that. :)
- nukeedit
topfunky said about 19 hours later:
Totally off topic, but this is a beautiful theme and it's great to see it in use!
- nukeedit
John Nowak said 2 days later:
This is my main reason for using Io. I simply cannot use Python or Ruby at this point (not that I ever could-I used Scheme prior). The syntax is general is also beautiful.That said, Io still has some rough edges, as it is a very young language. On the plus side though, that means you can join in and help resolve the remaining issues in a way you find most agreeable. Go on… give it a shot…
- nukeedit
Dennis said 2 days later:
Recently I was playing with Squeak Smalltalk. It's a live system, you make changes to the image as it runs. I added a couple properties to the Character class (author, createdate). Immediately, the properties were available in every character in the system…all the dev tools I was running, the text editors, everything using characters now had the new properties available.
Would something like this work in a prototype-based language? If not, Smalltalk classes aren't just a prototype pattern.
(In any case, Io sure is intriguing.)
- nukeedit
Lucas Carlson said 2 days later:
Yes, inheritance works just as well in prototype-based languages. Add a couple methods to the Object class and you get them everywhere.
- nukeedit
Dennis said 2 days later:
Forgive me being dense, but if you clone bar from foo, and later add a property to foo, does it show up in the already-created bar? (Ie., the cloned object maintains a reference to the object it was cloned from, rather than simply copying it?)
- nukeedit
Lucas Carlson said 2 days later:
No need to apologize. The answer is yes, but don't take my word for it, download and try for yourself: http://iolanguage.com/downloads/
- nukeedit
Dennis said 2 days later:
Thanks. Good idea :) Although I'm a little worried that after I try it I won't be happy with anything else!
- nukeedit
Jeremy Voorhis said 6 days later:
So clone is not so much a deep copy of an object as it is a quasi-inheritence mechanism.
To make sure I understand correctly…
- Adding methods and properties to an Io object is very much akin to calling
define_method
and friends withininstance_eval
in Ruby.- Clone acts as if it is creating a deep copy until you add methods or properties to a cloned object, then it acts more similarly to a superclass in Ruby. If so, that was what I did not understand yet about prototype-based programming.
- nukeedit
Jules said 6 days later:
With prototypes, the relationship between class/superclass is the same as instance/class. An instance has a reference to a class in it, and a class has a reference to its superclass.
So if you have a List object/class, and you create an instance:
myList := List clone
Then myList contains a reference to List. And if a propery/method in myList isn't found, it looks in List:
List bar := method("This is bar" print) myList foo := method("This is foo" print)
myList bar # looks in List mylist foo # looks in myList
So you could argue that myList is a subclass of List. You can subclass it or make an instance:
anotherList := myList clone
So clone returns a fresh object with only one propery: the reference to the superclass.
- nukeedit
mre said 34 days later:
If you clone an array containing strings in Ruby and then modify the string objects of the original array with string.gsub!(regex) the string objects of the clone will be modified as well!
- nukeedit
phil said 34 days later:
Quite a nifty Actionscript tool btw is the free open-source MotionTwin Actionscript Compiler ( http://mtasc.org , written in OCaml, www.ocaml-tutorial.org). The author is also the driving force behind http://nekovm.org, an interesting virtual machine project for scripting languages & language design.
Google matched content |
Prototype-based programming - Wikipedia, the free encyclopedia
Object-based PLs page of Rainer Blome
Open Directory - Computers Programming Languages Object-oriented Languages
Papers about Self and OO Programming
Background on Object Oriented Programming
Mark Zeren's Newton Programming Page
I first started programming the Newton in January 1994. Since then, I've learned that what really attracts me to Newton development is the NewtonScript language. Created by Walter Smith, NewtonScript is a small functional, garbage collected language which uses a prototype based (as opposed to class based) inheritence mechanism. It is very well adapted to low memory environments and to user interface programming.
If you are curious about NewtonScript or Newton programming I encourage you to check out Apple's developer web pages. There you will find the Newton Toolkit (for Windows and MacOS), documentation, and many other freely available resources for Newton development. For a complete set of Newton links check out Rob Bruce's Ultimate Newton Site.
Society
Groupthink : Two Party System as Polyarchy : Corruption of Regulators : Bureaucracies : Understanding Micromanagers and Control Freaks : Toxic Managers : Harvard Mafia : Diplomatic Communication : Surviving a Bad Performance Review : Insufficient Retirement Funds as Immanent Problem of Neoliberal Regime : PseudoScience : Who Rules America : Neoliberalism : The Iron Law of Oligarchy : Libertarian Philosophy
Quotes
War and Peace : Skeptical Finance : John Kenneth Galbraith :Talleyrand : Oscar Wilde : Otto Von Bismarck : Keynes : George Carlin : Skeptics : Propaganda : SE quotes : Language Design and Programming Quotes : Random IT-related quotes : Somerset Maugham : Marcus Aurelius : Kurt Vonnegut : Eric Hoffer : Winston Churchill : Napoleon Bonaparte : Ambrose Bierce : Bernard Shaw : Mark Twain Quotes
Bulletin:
Vol 25, No.12 (December, 2013) Rational Fools vs. Efficient Crooks The efficient markets hypothesis : Political Skeptic Bulletin, 2013 : Unemployment Bulletin, 2010 : Vol 23, No.10 (October, 2011) An observation about corporate security departments : Slightly Skeptical Euromaydan Chronicles, June 2014 : Greenspan legacy bulletin, 2008 : Vol 25, No.10 (October, 2013) Cryptolocker Trojan (Win32/Crilock.A) : Vol 25, No.08 (August, 2013) Cloud providers as intelligence collection hubs : Financial Humor Bulletin, 2010 : Inequality Bulletin, 2009 : Financial Humor Bulletin, 2008 : Copyleft Problems Bulletin, 2004 : Financial Humor Bulletin, 2011 : Energy Bulletin, 2010 : Malware Protection Bulletin, 2010 : Vol 26, No.1 (January, 2013) Object-Oriented Cult : Political Skeptic Bulletin, 2011 : Vol 23, No.11 (November, 2011) Softpanorama classification of sysadmin horror stories : Vol 25, No.05 (May, 2013) Corporate bullshit as a communication method : Vol 25, No.06 (June, 2013) A Note on the Relationship of Brooks Law and Conway Law
History:
Fifty glorious years (1950-2000): the triumph of the US computer engineering : Donald Knuth : TAoCP and its Influence of Computer Science : Richard Stallman : Linus Torvalds : Larry Wall : John K. Ousterhout : CTSS : Multix OS Unix History : Unix shell history : VI editor : History of pipes concept : Solaris : MS DOS : Programming Languages History : PL/1 : Simula 67 : C : History of GCC development : Scripting Languages : Perl history : OS History : Mail : DNS : SSH : CPU Instruction Sets : SPARC systems 1987-2006 : Norton Commander : Norton Utilities : Norton Ghost : Frontpage history : Malware Defense History : GNU Screen : OSS early history
Classic books:
The Peter Principle : Parkinson Law : 1984 : The Mythical Man-Month : How to Solve It by George Polya : The Art of Computer Programming : The Elements of Programming Style : The Unix Hater’s Handbook : The Jargon file : The True Believer : Programming Pearls : The Good Soldier Svejk : The Power Elite
Most popular humor pages:
Manifest of the Softpanorama IT Slacker Society : Ten Commandments of the IT Slackers Society : Computer Humor Collection : BSD Logo Story : The Cuckoo's Egg : IT Slang : C++ Humor : ARE YOU A BBS ADDICT? : The Perl Purity Test : Object oriented programmers of all nations : Financial Humor : Financial Humor Bulletin, 2008 : Financial Humor Bulletin, 2010 : The Most Comprehensive Collection of Editor-related Humor : Programming Language Humor : Goldman Sachs related humor : Greenspan humor : C Humor : Scripting Humor : Real Programmers Humor : Web Humor : GPL-related Humor : OFM Humor : Politically Incorrect Humor : IDS Humor : "Linux Sucks" Humor : Russian Musical Humor : Best Russian Programmer Humor : Microsoft plans to buy Catholic Church : Richard Stallman Related Humor : Admin Humor : Perl-related Humor : Linus Torvalds Related humor : PseudoScience Related Humor : Networking Humor : Shell Humor : Financial Humor Bulletin, 2011 : Financial Humor Bulletin, 2012 : Financial Humor Bulletin, 2013 : Java Humor : Software Engineering Humor : Sun Solaris Related Humor : Education Humor : IBM Humor : Assembler-related Humor : VIM Humor : Computer Viruses Humor : Bright tomorrow is rescheduled to a day after tomorrow : Classic Computer Humor
The Last but not Least Technology is dominated by two types of people: those who understand what they do not manage and those who manage what they do not understand ~Archibald Putt. Ph.D
Copyright © 1996-2021 by Softpanorama Society. www.softpanorama.org was initially created as a service to the (now defunct) UN Sustainable Development Networking Programme (SDNP) without any remuneration. This document is an industrial compilation designed and created exclusively for educational use and is distributed under the Softpanorama Content License. Original materials copyright belong to respective owners. Quotes are made for educational purposes only in compliance with the fair use doctrine.
FAIR USE NOTICE This site contains copyrighted material the use of which has not always been specifically authorized by the copyright owner. We are making such material available to advance understanding of computer science, IT technology, economic, scientific, and social issues. We believe this constitutes a 'fair use' of any such copyrighted material as provided by section 107 of the US Copyright Law according to which such material can be distributed without profit exclusively for research and educational purposes.
This is a Spartan WHYFF (We Help You For Free) site written by people for whom English is not a native language. Grammar and spelling errors should be expected. The site contain some broken links as it develops like a living tree...
|
You can use PayPal to to buy a cup of coffee for authors of this site |
Disclaimer:
The statements, views and opinions presented on this web page are those of the author (or referenced source) and are not endorsed by, nor do they necessarily reflect, the opinions of the Softpanorama society. We do not warrant the correctness of the information provided or its fitness for any purpose. The site uses AdSense so you need to be aware of Google privacy policy. You you do not want to be tracked by Google please disable Javascript for this site. This site is perfectly usable without Javascript.
Last modified: March 12, 2019