Already someone
wrote about
the Java Trap, but what I'm going to say here is not about the
trap, but about the crap.
It's my own, personal opinion about
Java and why it should always be avoided when possible, as usual
it has nothing to do with Gentoo, it's just me, got that?
First of all, I must to say I love OOP, C++ is my main language if I want to write something
complex, but Java is too much cruft for me. I don't like
the syntax, the missing features such as operators' overloading
and the partial inheritance. And I don't like the speed decrease
that it adds to your program.
Now, this decrease was always advertised
as a derived problem due to the platform independence of Java: you
write and compile it once, and you run it everywhere... Yeah sure,
keep on trying...
Let face the reality: a good written C or C++ program is more multiplatform
than Java, if you write it with QT or even GTK+ it will be more
portable than something in Java.
The first problem is that quite every
Java software out there requires Sun's version of Java, and this
means that you are limited to one implementation, which is released
just for a few systems: Sun's Solaris, obviously, Linux i386 and
amd64, Windows, OSX. There are a few other implementation such as
blackdown and ibm that covers ppc and ppc64 machines and IBM's operating
systems, but this is still limited: there is no Java version native
for FreeBSD for example, and you need to build it using unofficial
patches.
Also, recent programs started using
SWT for the GUI, that binds itself to a native GUI framework such
as GTK+, thus requiring access to native libraries to do the work.
This means that you don't have anymore a "no need for native libraries"
program, because it really requires them anyway... it's simpler
to just use GTK, isn't it?
As final note, the "it's java, it's
in a sandbox, it won't kill your system" assert is no more valid:
using native libraries (such as SWT) let java get outside the sandbox,
and SWT is enough to do so. Azureus, for example, can kill your
system eating CPU continously, as it goes out of the sandbox.
Be nice, don't let anyone fall over
the java crap, it smells bad :)
I recently returned from
JavaOne 2005 in San
Francisco. The show was impressive for a number of reasons. The attendance
seemed to be about 30% larger than last year's. The same could be said for
the number of tutorials, sessions and BOFs. For example, there were enough
BOFs to run until 11:00pm at night. Many of the sessions were filled to
capacity, with over 600 attendees each technical presentation.
Given my strong background in C++, I am used
to a more amorphous attitude toward languages. Therefore, I was surprised to
see that there still is a vibrancy to Java that I do not see with C++.
Among the many interesting things that I saw,
two stand out: Eclipse and the scripting language called Groovy. I already
have written about Eclipse, so here I simply note that Eclipse now seems to
dominate the Java IDE world. Groovy, on the other hand, is new. It prompted
me to look at Python-like scripting languages that run in a Java
environment.
In this article, I discuss
Jython and
Groovy, two
scripting languages that use the Java runtime environment. By the way,
JavaScript has nothing to do with the Java language, so it is not considered
here.
Jython
Jython is an interpret
uilt-in entities, Jython produces Java
compatible structures that it passes back and forth to the JVM. The code
below uses the Jython interactive shell, in which Jython takes the Python
built-in list structure and converts it to a Java list structure that is
then passed to the Java println function that then passes the result to the
JVM.
>>> print ['a','list','of','strings']
['a', 'list', 'of', 'strings']
>>>
Here is a simple program that uses the Java
Swing library to produce a trivial GUI application:
"""\
A simple demonstration of creating a swing tree widget from a
Python dictionary.
"""
import java
import javax
from pawt import swing
from pawt import awt
sampleData = {
'PyObject': {
'PyInteger':None,
'PyFloat':None,
'PyComplex':None,
'PySequence': {
'PyArray':None,
'PyList':None,
'PyTuple':None,
'PyString':None,
},
'PyClass': {
'PyJavaClass':None,
},
},
'sys':None,
'Py':None,
'PyException':None,
'__builtin__':None,
'ThreadState':None,
}
Node = swing.tree.DefaultMutableTreeNode
def addNode(tree, key, value):
node = Node(key)
tree.add(node)
if value is not None:
addLeaves(node, value.items())
def addLeaves(node, items):
items.sort()
for key, value in items:
addNode(node, key, value)
def makeTree(name, data):
tree = Node("Sample Tree")
addLeaves(tree, data.items())
return swing.JTree(tree)
def exit(e):
java.lang.System.exit(0)
if __name__ == '__main__':
tree = makeTree('Some JPython Classes', sampleData)
button = swing.JButton('Close Me!', actionPerformed=exit)
f = swing.JFrame("GridBag Layout Example");
p = swing.JFrame.getContentPane(f)
gb = awt.GridBagLayout()
p.setLayout(gb)
c = awt.GridBagConstraints();
c.weightx = 1.0;
c.fill = awt.GridBagConstraints.BOTH;
gb.setConstraints(tree, c);
c.gridx = 0;
c.gridy = awt.GridBagConstraints.RELATIVE;
gb.setConstraints(button, c);
p.add(tree)
p.add(button)
f.pack();
f.setSize(f.getPreferredSize());
f.show();
Jython has two main advantages. First, the
language is Python and has all of its strengths, including clean and
consistent syntax, introspection, dynamic creation of classes, properties
and attributes. Second, it runs at the speed of the JVM. On the other hand,
Jython also has two chief weakness. First is its need to convert constantly
between Python and Java structures. Second, Jython has not received much
work in recent years. That is about to change, however; the current
maintainer, Brian Zimmer, recently received three grants to continue work on
Jython.
The bottom line is if you know Python, then
you know Jython. The big gain is ready access to libraries such as Swing,
awt and so on.
er for the Python language. It is written in
Java to run under the Java VM. To handle Python b
Groovy
Groovy is a new language based on features
from Ruby, Python and Haskell. However, its runtime environment is any JVM.
The language syntax attempts to be Java-like, while making the form of the
language much simpler. Groovy is a statically typed language, so it requires
a compile step before producing Java byte code. Groovy does not currently
have an interpreter, although it does have a shell.
Groovy documentation offers an impressive
list of features:
- Closure support
- Native syntax for Lists and Maps
- Groovy Markup
- Groovy Path expression language
- Groovlets for implementing Servlets
easily in simple Groovy scripts
- Groovy SQL for making SQL more Groovy
- Groovy Beans for simpler syntax for
working with beans
- Groovy Template Engines which are
pluggable, simple to use, integrate GPath and compile to bytecode
- Ant scripting
- Regex syntax for neater scripting with
regular expressions
- Operator Overloading to simplify working
with datatypes Collections and Maps
- Polymorphic iteration and autoboxing
- Compiles straight to Java bytecode
- Works cleanly with all existing Java
objects and libraries
An interesting feature of Groovy is found its
definition and use of closure:
A closure in Groovy is an anonymous chunk
of code surrounded by braces that takes zero, one or more arguments,
returns a value, and can reference and use variables declared in its
surrounding lexical scope (i.e., the scope at its definition point). A
closure is like an anonymous inner class in Java. It is often used in
the same way. However, Groovy closures are more powerful and often more
convenient to specify and use.
Groovy's uses Java's standard types for
things such as dictionaries and lists. This means no translation is needed
between Groovy code and the JVM. This may improve execution time, depending
on the application.
Closures and Anonymous
Classes
Groovy's documentation provides an example
that illustrates the benefits of using closures in place of anonymous
classes. Using an anonymous class, we can write:
Button b = new Button ("Push Me");
b.onClick (new Action() {
public void execute (Object target)
{
buttonClicked();
}
});
</programlisting>
<para>
Using a closure, this becomes:
</para>
<programlisting>
Button b = new Button ("Push Me");
b.onClick { buttonClicked() }
Another nice feature of Groovy is its "each
operator, which is used to iterate over a collection:
SomeCollection stuff = new SomeCollection();
stuff.each() someClosure
// for example:
def myList = [1,2,4,5,6]
myList.each { println it } // where 'it' is current collection item
// outputs:
1
2
3
4
5
6
Groovy also has built-in structured
"builders" for languages such as XML, HTML and more. Again, a simple example
illustrates how natural it is to build structured text:
xml = new groovy.xml.MarkupBuilder()
def myList = ['acct1':['id':123111, 'type':'savings', 'balance':1234.56],
'acct2':['id':221212, 'type':'checking', 'balance':2010.02]]
doc = xml.accounts() {
for (entry in myList)
acct(id:entry.key) {
for (thing in entry.value)
item(name:thing.key, type=thing.value)
}
}
This small code fragment outputs:
<accounts>
<acct id='acct2'>
<item name='type'>checking</item>
<item name='id'>221212</item>
<item name='balance'>2010.02</item>
</acct>
<acct id='acct1'>
<item name='type'>savings</item>
<item name='id'>123111</item>
<item name='balance'>1234.56</item>
</acct>
Contrasting Jython and
Groovy
Bindings
In the following example, the use of variable
c is caught at compile time in a statically defined language. Only when a is
greater than b is the use of the undefined variable, c, detected in an
interpreted language.
a = 1
b = 2
if a > b:
print c
print a,b
Another major difference between a compiled
language and an interpreted one is when things are bound to their
references. In Groovy, the following code prints "Bound to local variable":
def varA = "Bound to global variable"
def closure = { varA }
public class C {
def varA = "Bound to local variable"
def closure = { varA } // bound to local varA at definition time
public def f = closure // f bound to local closure
};
def c = new C(); // create instance of C using new
println c.f() // invoke f in C
in Jython, the equivalent-looking code prints
"Bound to global variable":
varA = "Bound to global variable"
closure = lambda: varA
class C:
varA = "Bound to local variable"
closure = lambda self: varA
f = closure
c = C()
print c.f()
For those wanting more flexibility, the
Jython/Python bindings are handier. For those wanting more stability, the
Groovy implementation may be more desirable.
Currying
Currying function arguments is another
difference. Groovy has a special "curry" mechanism to bind arguments to a
function. In the following example, "foo bar" is printed:
def c = { arg1, arg2-> println "${arg1} ${arg2}" }
def d = c.curry("foo")
d("bar")
Jython inherits Python's natural ability to
curry arguments using a number of techniques. One is:
def c(arg1, arg2): print arg1,arg2
def d(arg2): c("foo",arg2)
d("bar")
Maturity
Jython has been around a long time and is
based on a mature language, Python. However, its development has stalled in
recent years. Groovy is a relatively new language and thus still is
developing. For example, its error diagnostics leave a lot to be desired.
Also, at the moment, Groovy's following is much smaller than Jython's or
Python's. However, both languages are picking up development activity, so
you have a chance to influence both languages if you want to become
involved.
Page 2 and scripting languages (Score:5, Interesting)
by MarkEst1973 (769601)
on Thursday June 30, @09:59PM (#12956728)
The entire second page of the article talks about scripting
languages, specifically Javascript (in browsers) and Groovy.
1. Kudos to the
Groovy [codehaus.org] authors. They've
even garnered James Gosling's attention. If you write Java code and
consider yourself even a little bit of a forward thinker, look up
Groovy. It's a very important JSR (JSR-241 specifically).
2. He talks about Javascript solely from the point of view of the
browser. Yes, I agree that Javascript is predominently implemented in a
browser, but it's reach can be felt everywhere. Javascript ==
ActionScript (Flash scripting language). Javascript == CFScript (ColdFusion
scripting language). Javascript object notation == Python object
notation.
But what about Javascript and
Rhino's [mozilla.org] inclusion in
Java 6 [sun.com]? I've been using Rhino as a server side language
for a while now because Struts is way too verbose for my taste. I just
want a thin glue layer between the web interface and my java components.
I'm sick and tired of endless xml configuration (that means you, too,
EJB!). A Rhino script on the server (with embedded Request, Response,
Application, and Session objects) is the perfect glue that does not need
xml configuration. (See also Groovy's Groovlets for a thin glue layer).
3. Javascript has been called Lisp in C's clothing. Javascript (via
Rhino) will be included in Java 6. I also read that Java 6 will allow
access to the parse trees created by the javac compiler (same link as
Java 6 above).
Java is now Lisp? Paul Graham writes about
9 features [paulgraham.com]
that made Lisp unique when it debuted in the 50s. Access to the parse
trees is one of the most advanced features of Lisp. He argues that when
a language has all 9 features (and Java today is at about #5), you've
not created a new language but a dialect of Lisp.
I am a Very Big Fan of dynamic languages that can flex like a pretzel
to fit my problem domain. Is Java evolving to be that pretzel?
Scripting language talk... (Score:3,
Insightful)
by MrDomino (799876) <mrdomino.gmail@com> on Thursday June 30,
@10:19PM (#12956857)
|
From TFA:When people talk about
scripting languages, they often talk about things that
are more toward having a developer be able to slap
something together rally quickly and get a demo out the
door in minutes. How fast the thing runs or how well the
thing scales or how large a system you can build tend to
be secondary considerations.
...
This is nit-picking, I know, but I
was under the impression that scripting languages were actually
defined by the presence of an actively-running interpreter during
execution, making it possible to, e.g., construct and execute
statements at runtime with things like PHP's exec() or
Lua [lua.org]'s
do(file|string) functions (see: http://www.lua.org/pil/8.html [lua.org]
for discussion on dofile and Lua's status as a scripting language).
I wasn't aware that capability for rapid prototyping or language
speed had anything to do with it.
Taking that into consideration, then,
would Java with JIT [wikipedia.org]
qualify as an interpreted or compiled language? I'm not sure,
myself---any thoughts?
That aside, a solid interview. Java
looks to be pretty interesting; though in its current form it does
bug the hell out of me (System.out.println()? Yeah, yeah, OO, but
come on, three nested levels of scope just to get to a command
line?), its progress has been impressive, and it's an innovative
idea. |
Java - unfulfilled promisses (Score:2)
by guacamole (24270) on
Thursday June 30, @10:50PM (#12957047)
|
I think the biggest selling point of
Java was the cross-platform compatibility. However, 10 years later,
I think that it is clear that this promise was largely a fraud. Java
was a perhaps a good new platform for writing enterprise
applications and applications for certain consumer niches for those
developers who didn't want to deal with the unsafe languages like C
or C++ or those who were fooled by Sun into believing that Java is
the best thing since whatever, but cross-platform compatibility for
large applications still remains problematic. For example, most
vendors of fairly complex java applications I have seen, not only
require you to use a certain version of OS and a web browser (if
that's an applet) but also they demand a certain version of the java
virtual machine is used and with certain patches on some operating
systems. And if you don't meet their requirements, you often run
into problems. I bet a python or a perl script would have fared much
better in many of those settings as far as portability is concerned.
|
Last year at OScon, I gave a presentation entitled
What Book Sales Tell Us About the State of the Tech Industry.
One of the conclusions I drew was that
Java was in decline, as its share of total programming
language book sales had dropped by five percentage points in
the twelve months ending June 2004. Well, we just re-ran
those numbers, and saw a startling reversal.
Here's the updated trend graph showing programming
language market share as reflected by weekly book
sales reported by Neilsen Bookscan from January 2003
to mid-June 2005...
[Apr 20, 2005]
JRegexer 0.3 This version removes external browsing, adds a simple
internal browser for viewing JavaDoc, adds support for find, find/start, split,
and split/limit, adds automatic recompilation and parsing, improves the
formatting of results, and fixes a few bugs.
JRegexer is a small and simple tool to develop
and test regexes that are parsed with java.util.regex.*.
I'm fairly sure you could accurately gauge the maturity of a
programming team by the amount of superstition in the source
code they produce. Code superstitions are a milder form of
cargo cult software development, in which you find people
writing code constructs that have no conceivable value with
respect to the functions that the code is meant to fulfill.
A recent conversation reminded me of an example I find
particularly disturbing. Sample code for dealing with JDBC is
particularly prone to being littered with this particular error,
as shown below. (I suspect that is not coincidental; I'll be
coming back to that.) I have elided most braces out for clarity
and terseness - imagine that this is a cross between Java and
Python:
import java.sql.*;
public class JdbcSample {
public static void main(String[] args) {
Connection conn = null;
try
conn = DriverManager.getConnection("jdbc:someUrl");
// ...more JDBC stuff...
catch (SQLException ex)
// Too often that is silently ignored, but that's another blog entry
finally
if (conn != null)
try
conn.close();
catch (SQLException sqlEx)
conn = null;
}
The "superstition" part is that setting the connection to
null can have absolutely no useful effect; being a local
variable, "conn" will become eligible for garbage collection as
soon as it goes out of scope anyway, which the most rudimentary
analysis of flow control reveals it will immediately after being
set to null.
I am always particularly interested in finding out what goes
on in the minds of programmers who write this kind of thing,
because that will sometimes reveal the roots of the
superstition. Most of the time, though, if you raise question in
a design review the programmer will say something like "I copied
and pasted it from sample code". This is how the superstitions
spread - and it's also a red flag with respect to the team's
practice maturity - but rarely an occasion to gain insight into
why the superstition took hold, which is what you'll need to
know in "remedial" training.
Now, the "null" concept, obvious as it seems, is a likely
place for superstitions to accrete around. If you look closely,
"null" is nothing but obvious. Comparing Java and Smalltalk, for
instance, we find that they differ radically with respect to
calling instance methods on null, or "nil" as it's called in
Smalltalk; "nil" does have some instance methods you can call.
Also, what is the type of the "null" value in Java ? It is a
special type called "the null type", which looks like a sensible
answer but incidentally breaks the consistency of the type
system; the only types which are assignable to variables are the
type of the variable or subtypes of that type, so "null type"
should be a subclass of every Java class. (It actually works
that way in Eiffel, as Nat Pryce reminds me - see comments.)
See also
here for another example of a null-related Java
superstition, also surprisingly common, as you can verify by
Googling for "equals null".
In the case of JDBC, I would bet that idioms of resource
allocation and deallocation inherited from non-garbage collected
languages, like C, were the main force in establishing the
superstition. Even people new to Java get used to not calling
"dispose" or "delete" to deallocate objects, but unfortunately
the design of the JDBC "bridges" between the object and
relational worlds suffer from a throwback to idioms of explicit
resource allocation/deallocation.
Owing to what many see as a major design flaw in Java, "going
out of scope" cannot be relied on as an indicator that a
resource is no longer in use, either, so whenever they deal with
JDBC Java programmers are suddenly thrown back into a different
world, one where deallocation is something to think about, like
not forgetting your keys at home. And so, in precisely the same
way as I occasionally found myself patting my pockets to check
for home keys when I left the office, our fingers
reflexively type in the closest equivalent we find in Java to an
explicit deallocation - setting to null.
You may object that the setting-to-null superstition is
totally harmless. So is throwing salt over your shoulder. While
this may be true of one particular superstition, I would
be particularly concerned about a team which had many such
habits, just like you wouldn't want to trust much of importance
your batty old aunt who avoids stepping on cracks, stays home on
Fridays, crosses herself on seeing a black cat, but always sends
you candy for Christmas.
Posted by Morendil at November 15, 2004
04:57 PM
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...
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
|