diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f403193 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f403193 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..73ff239 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f403193 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..73ff239 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f403193 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..73ff239 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..3b00020 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f403193 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..73ff239 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..3b00020 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..275077f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f403193 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..73ff239 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..3b00020 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..275077f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/README b/README deleted file mode 100644 index 734abaf..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -This file was created by IntelliJ IDEA 11.1.1 for binding GitHub repository \ No newline at end of file diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f403193 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..73ff239 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..3b00020 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..275077f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/README b/README deleted file mode 100644 index 734abaf..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -This file was created by IntelliJ IDEA 11.1.1 for binding GitHub repository \ No newline at end of file diff --git a/Simple-jdbc-statistics.iml b/Simple-jdbc-statistics.iml new file mode 100644 index 0000000..ca90a9b --- /dev/null +++ b/Simple-jdbc-statistics.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f403193 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..73ff239 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..3b00020 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..275077f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/README b/README deleted file mode 100644 index 734abaf..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -This file was created by IntelliJ IDEA 11.1.1 for binding GitHub repository \ No newline at end of file diff --git a/Simple-jdbc-statistics.iml b/Simple-jdbc-statistics.iml new file mode 100644 index 0000000..ca90a9b --- /dev/null +++ b/Simple-jdbc-statistics.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/lib/h2-1.3.166.jar b/lib/h2-1.3.166.jar new file mode 100644 index 0000000..4985063 --- /dev/null +++ b/lib/h2-1.3.166.jar Binary files differ diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f403193 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..73ff239 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..3b00020 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..275077f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/README b/README deleted file mode 100644 index 734abaf..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -This file was created by IntelliJ IDEA 11.1.1 for binding GitHub repository \ No newline at end of file diff --git a/Simple-jdbc-statistics.iml b/Simple-jdbc-statistics.iml new file mode 100644 index 0000000..ca90a9b --- /dev/null +++ b/Simple-jdbc-statistics.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/lib/h2-1.3.166.jar b/lib/h2-1.3.166.jar new file mode 100644 index 0000000..4985063 --- /dev/null +++ b/lib/h2-1.3.166.jar Binary files differ diff --git a/lib/servlet-api-2.5.jar b/lib/servlet-api-2.5.jar new file mode 100644 index 0000000..20b5755 --- /dev/null +++ b/lib/servlet-api-2.5.jar Binary files differ diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f403193 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..73ff239 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..3b00020 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..275077f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/README b/README deleted file mode 100644 index 734abaf..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -This file was created by IntelliJ IDEA 11.1.1 for binding GitHub repository \ No newline at end of file diff --git a/Simple-jdbc-statistics.iml b/Simple-jdbc-statistics.iml new file mode 100644 index 0000000..ca90a9b --- /dev/null +++ b/Simple-jdbc-statistics.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/lib/h2-1.3.166.jar b/lib/h2-1.3.166.jar new file mode 100644 index 0000000..4985063 --- /dev/null +++ b/lib/h2-1.3.166.jar Binary files differ diff --git a/lib/servlet-api-2.5.jar b/lib/servlet-api-2.5.jar new file mode 100644 index 0000000..20b5755 --- /dev/null +++ b/lib/servlet-api-2.5.jar Binary files differ diff --git a/lib/slf4j-api-1.6.4.jar b/lib/slf4j-api-1.6.4.jar new file mode 100644 index 0000000..4d23f41 --- /dev/null +++ b/lib/slf4j-api-1.6.4.jar Binary files differ diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f403193 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..73ff239 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..3b00020 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..275077f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/README b/README deleted file mode 100644 index 734abaf..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -This file was created by IntelliJ IDEA 11.1.1 for binding GitHub repository \ No newline at end of file diff --git a/Simple-jdbc-statistics.iml b/Simple-jdbc-statistics.iml new file mode 100644 index 0000000..ca90a9b --- /dev/null +++ b/Simple-jdbc-statistics.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/lib/h2-1.3.166.jar b/lib/h2-1.3.166.jar new file mode 100644 index 0000000..4985063 --- /dev/null +++ b/lib/h2-1.3.166.jar Binary files differ diff --git a/lib/servlet-api-2.5.jar b/lib/servlet-api-2.5.jar new file mode 100644 index 0000000..20b5755 --- /dev/null +++ b/lib/servlet-api-2.5.jar Binary files differ diff --git a/lib/slf4j-api-1.6.4.jar b/lib/slf4j-api-1.6.4.jar new file mode 100644 index 0000000..4d23f41 --- /dev/null +++ b/lib/slf4j-api-1.6.4.jar Binary files differ diff --git a/lib/slf4j-simple-1.6.4.jar b/lib/slf4j-simple-1.6.4.jar new file mode 100644 index 0000000..3d1b8d9 --- /dev/null +++ b/lib/slf4j-simple-1.6.4.jar Binary files differ diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f403193 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..73ff239 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..3b00020 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..275077f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/README b/README deleted file mode 100644 index 734abaf..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -This file was created by IntelliJ IDEA 11.1.1 for binding GitHub repository \ No newline at end of file diff --git a/Simple-jdbc-statistics.iml b/Simple-jdbc-statistics.iml new file mode 100644 index 0000000..ca90a9b --- /dev/null +++ b/Simple-jdbc-statistics.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/lib/h2-1.3.166.jar b/lib/h2-1.3.166.jar new file mode 100644 index 0000000..4985063 --- /dev/null +++ b/lib/h2-1.3.166.jar Binary files differ diff --git a/lib/servlet-api-2.5.jar b/lib/servlet-api-2.5.jar new file mode 100644 index 0000000..20b5755 --- /dev/null +++ b/lib/servlet-api-2.5.jar Binary files differ diff --git a/lib/slf4j-api-1.6.4.jar b/lib/slf4j-api-1.6.4.jar new file mode 100644 index 0000000..4d23f41 --- /dev/null +++ b/lib/slf4j-api-1.6.4.jar Binary files differ diff --git a/lib/slf4j-simple-1.6.4.jar b/lib/slf4j-simple-1.6.4.jar new file mode 100644 index 0000000..3d1b8d9 --- /dev/null +++ b/lib/slf4j-simple-1.6.4.jar Binary files differ diff --git a/lib/ssr-0.1.jar b/lib/ssr-0.1.jar new file mode 100644 index 0000000..65dfcf4 --- /dev/null +++ b/lib/ssr-0.1.jar Binary files differ diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f403193 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..73ff239 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..3b00020 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..275077f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/README b/README deleted file mode 100644 index 734abaf..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -This file was created by IntelliJ IDEA 11.1.1 for binding GitHub repository \ No newline at end of file diff --git a/Simple-jdbc-statistics.iml b/Simple-jdbc-statistics.iml new file mode 100644 index 0000000..ca90a9b --- /dev/null +++ b/Simple-jdbc-statistics.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/lib/h2-1.3.166.jar b/lib/h2-1.3.166.jar new file mode 100644 index 0000000..4985063 --- /dev/null +++ b/lib/h2-1.3.166.jar Binary files differ diff --git a/lib/servlet-api-2.5.jar b/lib/servlet-api-2.5.jar new file mode 100644 index 0000000..20b5755 --- /dev/null +++ b/lib/servlet-api-2.5.jar Binary files differ diff --git a/lib/slf4j-api-1.6.4.jar b/lib/slf4j-api-1.6.4.jar new file mode 100644 index 0000000..4d23f41 --- /dev/null +++ b/lib/slf4j-api-1.6.4.jar Binary files differ diff --git a/lib/slf4j-simple-1.6.4.jar b/lib/slf4j-simple-1.6.4.jar new file mode 100644 index 0000000..3d1b8d9 --- /dev/null +++ b/lib/slf4j-simple-1.6.4.jar Binary files differ diff --git a/lib/ssr-0.1.jar b/lib/ssr-0.1.jar new file mode 100644 index 0000000..65dfcf4 --- /dev/null +++ b/lib/ssr-0.1.jar Binary files differ diff --git a/lib/vst-0.4.jar b/lib/vst-0.4.jar new file mode 100644 index 0000000..db63792 --- /dev/null +++ b/lib/vst-0.4.jar Binary files differ diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f403193 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..73ff239 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..3b00020 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..275077f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/README b/README deleted file mode 100644 index 734abaf..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -This file was created by IntelliJ IDEA 11.1.1 for binding GitHub repository \ No newline at end of file diff --git a/Simple-jdbc-statistics.iml b/Simple-jdbc-statistics.iml new file mode 100644 index 0000000..ca90a9b --- /dev/null +++ b/Simple-jdbc-statistics.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/lib/h2-1.3.166.jar b/lib/h2-1.3.166.jar new file mode 100644 index 0000000..4985063 --- /dev/null +++ b/lib/h2-1.3.166.jar Binary files differ diff --git a/lib/servlet-api-2.5.jar b/lib/servlet-api-2.5.jar new file mode 100644 index 0000000..20b5755 --- /dev/null +++ b/lib/servlet-api-2.5.jar Binary files differ diff --git a/lib/slf4j-api-1.6.4.jar b/lib/slf4j-api-1.6.4.jar new file mode 100644 index 0000000..4d23f41 --- /dev/null +++ b/lib/slf4j-api-1.6.4.jar Binary files differ diff --git a/lib/slf4j-simple-1.6.4.jar b/lib/slf4j-simple-1.6.4.jar new file mode 100644 index 0000000..3d1b8d9 --- /dev/null +++ b/lib/slf4j-simple-1.6.4.jar Binary files differ diff --git a/lib/ssr-0.1.jar b/lib/ssr-0.1.jar new file mode 100644 index 0000000..65dfcf4 --- /dev/null +++ b/lib/ssr-0.1.jar Binary files differ diff --git a/lib/vst-0.4.jar b/lib/vst-0.4.jar new file mode 100644 index 0000000..db63792 --- /dev/null +++ b/lib/vst-0.4.jar Binary files differ diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..ac2dbe1 --- /dev/null +++ b/readme.md @@ -0,0 +1 @@ +A simple wrapper around jdbc drivers what will show current jdbc stats of the running queries on a simple web page on port 18080. \ No newline at end of file diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f403193 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..73ff239 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..3b00020 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..275077f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/README b/README deleted file mode 100644 index 734abaf..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -This file was created by IntelliJ IDEA 11.1.1 for binding GitHub repository \ No newline at end of file diff --git a/Simple-jdbc-statistics.iml b/Simple-jdbc-statistics.iml new file mode 100644 index 0000000..ca90a9b --- /dev/null +++ b/Simple-jdbc-statistics.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/lib/h2-1.3.166.jar b/lib/h2-1.3.166.jar new file mode 100644 index 0000000..4985063 --- /dev/null +++ b/lib/h2-1.3.166.jar Binary files differ diff --git a/lib/servlet-api-2.5.jar b/lib/servlet-api-2.5.jar new file mode 100644 index 0000000..20b5755 --- /dev/null +++ b/lib/servlet-api-2.5.jar Binary files differ diff --git a/lib/slf4j-api-1.6.4.jar b/lib/slf4j-api-1.6.4.jar new file mode 100644 index 0000000..4d23f41 --- /dev/null +++ b/lib/slf4j-api-1.6.4.jar Binary files differ diff --git a/lib/slf4j-simple-1.6.4.jar b/lib/slf4j-simple-1.6.4.jar new file mode 100644 index 0000000..3d1b8d9 --- /dev/null +++ b/lib/slf4j-simple-1.6.4.jar Binary files differ diff --git a/lib/ssr-0.1.jar b/lib/ssr-0.1.jar new file mode 100644 index 0000000..65dfcf4 --- /dev/null +++ b/lib/ssr-0.1.jar Binary files differ diff --git a/lib/vst-0.4.jar b/lib/vst-0.4.jar new file mode 100644 index 0000000..db63792 --- /dev/null +++ b/lib/vst-0.4.jar Binary files differ diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..ac2dbe1 --- /dev/null +++ b/readme.md @@ -0,0 +1 @@ +A simple wrapper around jdbc drivers what will show current jdbc stats of the running queries on a simple web page on port 18080. \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/ConnectionLogger.java b/src/nl/astraeus/jdbc/ConnectionLogger.java new file mode 100644 index 0000000..c3e243f --- /dev/null +++ b/src/nl/astraeus/jdbc/ConnectionLogger.java @@ -0,0 +1,279 @@ +package nl.astraeus.jdbc; + +import java.sql.*; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Executor; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:12:34 PM + */ +public class ConnectionLogger implements Connection { + private Connection connection; + + private long milli; + private long nano; + private String lastSql; + + public ConnectionLogger(Connection connection) { + this.connection = connection; + this.lastSql = ""; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(QueryType.UNKNOWN, sql, m, n); + } + + public void commit() throws SQLException { + clearTime(); + + connection.commit(); + + log("commit"); + } + + public void rollback() throws SQLException { + clearTime(); + + connection.rollback(); + + log("rollback"); + } + + public void close() throws SQLException { + clearTime(); + + connection.close(); + + log("close"); + } + + public PreparedStatement prepareStatement(String sql) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, autoGeneratedKeys); + } + + public PreparedStatement prepareStatement(String sql, int columnIndexes[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnIndexes); + } + + public PreparedStatement prepareStatement(String sql, String columnNames[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnNames); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public Statement createStatement() throws SQLException { + return connection.createStatement(); + } + + public CallableStatement prepareCall(String sql) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql); + } + + public String nativeSQL(String sql) throws SQLException { + lastSql = sql; + return connection.nativeSQL(sql); + } + + public void setAutoCommit(boolean autoCommit) throws SQLException { + connection.setAutoCommit(autoCommit); + } + + public boolean getAutoCommit() throws SQLException { + return connection.getAutoCommit(); + } + + public boolean isClosed() throws SQLException { + return connection.isClosed(); + } + + public DatabaseMetaData getMetaData() throws SQLException { + return connection.getMetaData(); + } + + public void setReadOnly(boolean readOnly) throws SQLException { + connection.setReadOnly(readOnly); + } + + public boolean isReadOnly() throws SQLException { + return connection.isReadOnly(); + } + + public void setCatalog(String catalog) throws SQLException { + connection.setCatalog(catalog); + } + + public String getCatalog() throws SQLException { + return connection.getCatalog(); + } + + public void setTransactionIsolation(int level) throws SQLException { + connection.setTransactionIsolation(level); + } + + public int getTransactionIsolation() throws SQLException { + return connection.getTransactionIsolation(); + } + + public SQLWarning getWarnings() throws SQLException { + return connection.getWarnings(); + } + + public void clearWarnings() throws SQLException { + connection.clearWarnings(); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency); + } + + public Map> getTypeMap() throws SQLException { + return connection.getTypeMap(); + } + + public void setTypeMap(Map> map) throws SQLException { + connection.setTypeMap(map); + } + + public void setHoldability(int holdability) throws SQLException { + connection.setHoldability(holdability); + } + + public int getHoldability() throws SQLException { + return connection.getHoldability(); + } + + public Savepoint setSavepoint() throws SQLException { + return connection.setSavepoint(); + } + + public Savepoint setSavepoint(String name) throws SQLException { + return connection.setSavepoint(name); + } + + public void rollback(Savepoint savepoint) throws SQLException { + connection.rollback(); + } + + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + connection.releaseSavepoint(savepoint); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public Clob createClob() throws SQLException { + return connection.createClob(); + } + + public Blob createBlob() throws SQLException { + return connection.createBlob(); + } + + public NClob createNClob() throws SQLException { + return connection.createNClob(); + } + + public SQLXML createSQLXML() throws SQLException { + return connection.createSQLXML(); + } + + public boolean isValid(int timeout) throws SQLException { + return connection.isValid(timeout); + } + + public void setClientInfo(String name, String value) throws SQLClientInfoException { + connection.setClientInfo(name, value); + } + + public void setClientInfo(Properties properties) throws SQLClientInfoException { + connection.setClientInfo(properties); + } + + public String getClientInfo(String name) throws SQLException { + return connection.getClientInfo(name); + } + + public Properties getClientInfo() throws SQLException { + return connection.getClientInfo(); + } + + public Array createArrayOf(String typeName, Object[] elements) throws SQLException { + return connection.createArrayOf(typeName, elements); + } + + public Struct createStruct(String typeName, Object[] attributes) throws SQLException { + return connection.createStruct(typeName, attributes); + } + + @Override + public void setSchema(String schema) throws SQLException { + connection.setSchema(schema); + } + + @Override + public String getSchema() throws SQLException { + return connection.getSchema(); + } + + @Override + public void abort(Executor executor) throws SQLException { + connection.abort(executor); + } + + @Override + public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { + connection.setNetworkTimeout(executor, milliseconds); + } + + @Override + public int getNetworkTimeout() throws SQLException { + return connection.getNetworkTimeout(); + } + + public T unwrap(Class iface) throws SQLException { + return connection.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return connection.isWrapperFor(iface); + } +} diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f403193 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..73ff239 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..3b00020 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..275077f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/README b/README deleted file mode 100644 index 734abaf..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -This file was created by IntelliJ IDEA 11.1.1 for binding GitHub repository \ No newline at end of file diff --git a/Simple-jdbc-statistics.iml b/Simple-jdbc-statistics.iml new file mode 100644 index 0000000..ca90a9b --- /dev/null +++ b/Simple-jdbc-statistics.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/lib/h2-1.3.166.jar b/lib/h2-1.3.166.jar new file mode 100644 index 0000000..4985063 --- /dev/null +++ b/lib/h2-1.3.166.jar Binary files differ diff --git a/lib/servlet-api-2.5.jar b/lib/servlet-api-2.5.jar new file mode 100644 index 0000000..20b5755 --- /dev/null +++ b/lib/servlet-api-2.5.jar Binary files differ diff --git a/lib/slf4j-api-1.6.4.jar b/lib/slf4j-api-1.6.4.jar new file mode 100644 index 0000000..4d23f41 --- /dev/null +++ b/lib/slf4j-api-1.6.4.jar Binary files differ diff --git a/lib/slf4j-simple-1.6.4.jar b/lib/slf4j-simple-1.6.4.jar new file mode 100644 index 0000000..3d1b8d9 --- /dev/null +++ b/lib/slf4j-simple-1.6.4.jar Binary files differ diff --git a/lib/ssr-0.1.jar b/lib/ssr-0.1.jar new file mode 100644 index 0000000..65dfcf4 --- /dev/null +++ b/lib/ssr-0.1.jar Binary files differ diff --git a/lib/vst-0.4.jar b/lib/vst-0.4.jar new file mode 100644 index 0000000..db63792 --- /dev/null +++ b/lib/vst-0.4.jar Binary files differ diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..ac2dbe1 --- /dev/null +++ b/readme.md @@ -0,0 +1 @@ +A simple wrapper around jdbc drivers what will show current jdbc stats of the running queries on a simple web page on port 18080. \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/ConnectionLogger.java b/src/nl/astraeus/jdbc/ConnectionLogger.java new file mode 100644 index 0000000..c3e243f --- /dev/null +++ b/src/nl/astraeus/jdbc/ConnectionLogger.java @@ -0,0 +1,279 @@ +package nl.astraeus.jdbc; + +import java.sql.*; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Executor; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:12:34 PM + */ +public class ConnectionLogger implements Connection { + private Connection connection; + + private long milli; + private long nano; + private String lastSql; + + public ConnectionLogger(Connection connection) { + this.connection = connection; + this.lastSql = ""; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(QueryType.UNKNOWN, sql, m, n); + } + + public void commit() throws SQLException { + clearTime(); + + connection.commit(); + + log("commit"); + } + + public void rollback() throws SQLException { + clearTime(); + + connection.rollback(); + + log("rollback"); + } + + public void close() throws SQLException { + clearTime(); + + connection.close(); + + log("close"); + } + + public PreparedStatement prepareStatement(String sql) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, autoGeneratedKeys); + } + + public PreparedStatement prepareStatement(String sql, int columnIndexes[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnIndexes); + } + + public PreparedStatement prepareStatement(String sql, String columnNames[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnNames); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public Statement createStatement() throws SQLException { + return connection.createStatement(); + } + + public CallableStatement prepareCall(String sql) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql); + } + + public String nativeSQL(String sql) throws SQLException { + lastSql = sql; + return connection.nativeSQL(sql); + } + + public void setAutoCommit(boolean autoCommit) throws SQLException { + connection.setAutoCommit(autoCommit); + } + + public boolean getAutoCommit() throws SQLException { + return connection.getAutoCommit(); + } + + public boolean isClosed() throws SQLException { + return connection.isClosed(); + } + + public DatabaseMetaData getMetaData() throws SQLException { + return connection.getMetaData(); + } + + public void setReadOnly(boolean readOnly) throws SQLException { + connection.setReadOnly(readOnly); + } + + public boolean isReadOnly() throws SQLException { + return connection.isReadOnly(); + } + + public void setCatalog(String catalog) throws SQLException { + connection.setCatalog(catalog); + } + + public String getCatalog() throws SQLException { + return connection.getCatalog(); + } + + public void setTransactionIsolation(int level) throws SQLException { + connection.setTransactionIsolation(level); + } + + public int getTransactionIsolation() throws SQLException { + return connection.getTransactionIsolation(); + } + + public SQLWarning getWarnings() throws SQLException { + return connection.getWarnings(); + } + + public void clearWarnings() throws SQLException { + connection.clearWarnings(); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency); + } + + public Map> getTypeMap() throws SQLException { + return connection.getTypeMap(); + } + + public void setTypeMap(Map> map) throws SQLException { + connection.setTypeMap(map); + } + + public void setHoldability(int holdability) throws SQLException { + connection.setHoldability(holdability); + } + + public int getHoldability() throws SQLException { + return connection.getHoldability(); + } + + public Savepoint setSavepoint() throws SQLException { + return connection.setSavepoint(); + } + + public Savepoint setSavepoint(String name) throws SQLException { + return connection.setSavepoint(name); + } + + public void rollback(Savepoint savepoint) throws SQLException { + connection.rollback(); + } + + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + connection.releaseSavepoint(savepoint); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public Clob createClob() throws SQLException { + return connection.createClob(); + } + + public Blob createBlob() throws SQLException { + return connection.createBlob(); + } + + public NClob createNClob() throws SQLException { + return connection.createNClob(); + } + + public SQLXML createSQLXML() throws SQLException { + return connection.createSQLXML(); + } + + public boolean isValid(int timeout) throws SQLException { + return connection.isValid(timeout); + } + + public void setClientInfo(String name, String value) throws SQLClientInfoException { + connection.setClientInfo(name, value); + } + + public void setClientInfo(Properties properties) throws SQLClientInfoException { + connection.setClientInfo(properties); + } + + public String getClientInfo(String name) throws SQLException { + return connection.getClientInfo(name); + } + + public Properties getClientInfo() throws SQLException { + return connection.getClientInfo(); + } + + public Array createArrayOf(String typeName, Object[] elements) throws SQLException { + return connection.createArrayOf(typeName, elements); + } + + public Struct createStruct(String typeName, Object[] attributes) throws SQLException { + return connection.createStruct(typeName, attributes); + } + + @Override + public void setSchema(String schema) throws SQLException { + connection.setSchema(schema); + } + + @Override + public String getSchema() throws SQLException { + return connection.getSchema(); + } + + @Override + public void abort(Executor executor) throws SQLException { + connection.abort(executor); + } + + @Override + public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { + connection.setNetworkTimeout(executor, milliseconds); + } + + @Override + public int getNetworkTimeout() throws SQLException { + return connection.getNetworkTimeout(); + } + + public T unwrap(Class iface) throws SQLException { + return connection.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return connection.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/Driver.java b/src/nl/astraeus/jdbc/Driver.java new file mode 100644 index 0000000..8317172 --- /dev/null +++ b/src/nl/astraeus/jdbc/Driver.java @@ -0,0 +1,116 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.http.SimpleWebServer; +import nl.astraeus.jdbc.web.JdbcStatisticsServlet; +import nl.astraeus.jdbc.web.ResourceServlet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.*; +import java.util.Enumeration; +import java.util.Properties; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:54:37 PM + */ +public class Driver implements java.sql.Driver { + private final static Logger log = LoggerFactory.getLogger(Driver.class); + + final private static String URL_PREFIX = "jdbc:stat:"; + + private java.sql.Driver driver = null; + private String[] drivers = { + "org.postgresql.Driver", + "oracle.jdbc.driver.OracleDriver", + "com.sybase.jdbc2.jdbc.SybDriver", + "net.sourceforge.jtds.jdbc.Driver", + "com.microsoft.jdbc.sqlserver.SQLServerDriver", + "com.microsoft.sqlserver.jdbc.SQLServerDriver", + "weblogic.jdbc.sqlserver.SQLServerDriver", + "com.informix.jdbc.IfxDriver", + "org.apache.derby.jdbc.ClientDriver", + "org.apache.derby.jdbc.EmbeddedDriver", + "com.mysql.jdbc.Driver", + "org.hsqldb.jdbcDriver", + "org.h2.Driver" }; + + static { + log.debug("Loading driver class " + Driver.class.getName()); + + try { + DriverManager.registerDriver(new Driver()); + } catch (SQLException e) { + log.error("", e); + } + } + + public Driver() { + for (String dr : drivers) { + try { + Class.forName(dr); + } catch (Throwable e) { + log.debug("Can't instantiate driver: " + dr, e); + } + } + } + + private java.sql.Driver findDriver(String url) throws SQLException { + Enumeration e = DriverManager.getDrivers(); + + while (e.hasMoreElements()) { + java.sql.Driver d = (java.sql.Driver) e.nextElement(); + + if (d.acceptsURL(url)) { + return d; + } + } + + throw new SQLException("Driver not found: " + url); + } + + public Connection connect(String url, Properties info) throws SQLException { + url = url.substring(URL_PREFIX.length()); + + if (driver == null) { + driver = findDriver(url); + } + + if (driver != null) { + SimpleWebServer server = new SimpleWebServer(18080); + + server.addServlet(new JdbcStatisticsServlet(), "/"); + server.addServlet(new ResourceServlet(), "/resources/*"); + + server.start(); + } + + return new ConnectionLogger(driver.connect(url, info)); + } + + public boolean acceptsURL(String url) throws SQLException { + return (url != null && url.startsWith(URL_PREFIX)); + } + + public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { + return driver.getPropertyInfo(url, info); + } + + public int getMajorVersion() { + return driver.getMajorVersion(); + } + + public int getMinorVersion() { + return driver.getMinorVersion(); + } + + public boolean jdbcCompliant() { + return driver.jdbcCompliant(); + } + + @Override + public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException { + return driver.getParentLogger(); + } +} diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f403193 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..73ff239 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..3b00020 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..275077f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/README b/README deleted file mode 100644 index 734abaf..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -This file was created by IntelliJ IDEA 11.1.1 for binding GitHub repository \ No newline at end of file diff --git a/Simple-jdbc-statistics.iml b/Simple-jdbc-statistics.iml new file mode 100644 index 0000000..ca90a9b --- /dev/null +++ b/Simple-jdbc-statistics.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/lib/h2-1.3.166.jar b/lib/h2-1.3.166.jar new file mode 100644 index 0000000..4985063 --- /dev/null +++ b/lib/h2-1.3.166.jar Binary files differ diff --git a/lib/servlet-api-2.5.jar b/lib/servlet-api-2.5.jar new file mode 100644 index 0000000..20b5755 --- /dev/null +++ b/lib/servlet-api-2.5.jar Binary files differ diff --git a/lib/slf4j-api-1.6.4.jar b/lib/slf4j-api-1.6.4.jar new file mode 100644 index 0000000..4d23f41 --- /dev/null +++ b/lib/slf4j-api-1.6.4.jar Binary files differ diff --git a/lib/slf4j-simple-1.6.4.jar b/lib/slf4j-simple-1.6.4.jar new file mode 100644 index 0000000..3d1b8d9 --- /dev/null +++ b/lib/slf4j-simple-1.6.4.jar Binary files differ diff --git a/lib/ssr-0.1.jar b/lib/ssr-0.1.jar new file mode 100644 index 0000000..65dfcf4 --- /dev/null +++ b/lib/ssr-0.1.jar Binary files differ diff --git a/lib/vst-0.4.jar b/lib/vst-0.4.jar new file mode 100644 index 0000000..db63792 --- /dev/null +++ b/lib/vst-0.4.jar Binary files differ diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..ac2dbe1 --- /dev/null +++ b/readme.md @@ -0,0 +1 @@ +A simple wrapper around jdbc drivers what will show current jdbc stats of the running queries on a simple web page on port 18080. \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/ConnectionLogger.java b/src/nl/astraeus/jdbc/ConnectionLogger.java new file mode 100644 index 0000000..c3e243f --- /dev/null +++ b/src/nl/astraeus/jdbc/ConnectionLogger.java @@ -0,0 +1,279 @@ +package nl.astraeus.jdbc; + +import java.sql.*; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Executor; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:12:34 PM + */ +public class ConnectionLogger implements Connection { + private Connection connection; + + private long milli; + private long nano; + private String lastSql; + + public ConnectionLogger(Connection connection) { + this.connection = connection; + this.lastSql = ""; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(QueryType.UNKNOWN, sql, m, n); + } + + public void commit() throws SQLException { + clearTime(); + + connection.commit(); + + log("commit"); + } + + public void rollback() throws SQLException { + clearTime(); + + connection.rollback(); + + log("rollback"); + } + + public void close() throws SQLException { + clearTime(); + + connection.close(); + + log("close"); + } + + public PreparedStatement prepareStatement(String sql) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, autoGeneratedKeys); + } + + public PreparedStatement prepareStatement(String sql, int columnIndexes[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnIndexes); + } + + public PreparedStatement prepareStatement(String sql, String columnNames[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnNames); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public Statement createStatement() throws SQLException { + return connection.createStatement(); + } + + public CallableStatement prepareCall(String sql) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql); + } + + public String nativeSQL(String sql) throws SQLException { + lastSql = sql; + return connection.nativeSQL(sql); + } + + public void setAutoCommit(boolean autoCommit) throws SQLException { + connection.setAutoCommit(autoCommit); + } + + public boolean getAutoCommit() throws SQLException { + return connection.getAutoCommit(); + } + + public boolean isClosed() throws SQLException { + return connection.isClosed(); + } + + public DatabaseMetaData getMetaData() throws SQLException { + return connection.getMetaData(); + } + + public void setReadOnly(boolean readOnly) throws SQLException { + connection.setReadOnly(readOnly); + } + + public boolean isReadOnly() throws SQLException { + return connection.isReadOnly(); + } + + public void setCatalog(String catalog) throws SQLException { + connection.setCatalog(catalog); + } + + public String getCatalog() throws SQLException { + return connection.getCatalog(); + } + + public void setTransactionIsolation(int level) throws SQLException { + connection.setTransactionIsolation(level); + } + + public int getTransactionIsolation() throws SQLException { + return connection.getTransactionIsolation(); + } + + public SQLWarning getWarnings() throws SQLException { + return connection.getWarnings(); + } + + public void clearWarnings() throws SQLException { + connection.clearWarnings(); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency); + } + + public Map> getTypeMap() throws SQLException { + return connection.getTypeMap(); + } + + public void setTypeMap(Map> map) throws SQLException { + connection.setTypeMap(map); + } + + public void setHoldability(int holdability) throws SQLException { + connection.setHoldability(holdability); + } + + public int getHoldability() throws SQLException { + return connection.getHoldability(); + } + + public Savepoint setSavepoint() throws SQLException { + return connection.setSavepoint(); + } + + public Savepoint setSavepoint(String name) throws SQLException { + return connection.setSavepoint(name); + } + + public void rollback(Savepoint savepoint) throws SQLException { + connection.rollback(); + } + + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + connection.releaseSavepoint(savepoint); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public Clob createClob() throws SQLException { + return connection.createClob(); + } + + public Blob createBlob() throws SQLException { + return connection.createBlob(); + } + + public NClob createNClob() throws SQLException { + return connection.createNClob(); + } + + public SQLXML createSQLXML() throws SQLException { + return connection.createSQLXML(); + } + + public boolean isValid(int timeout) throws SQLException { + return connection.isValid(timeout); + } + + public void setClientInfo(String name, String value) throws SQLClientInfoException { + connection.setClientInfo(name, value); + } + + public void setClientInfo(Properties properties) throws SQLClientInfoException { + connection.setClientInfo(properties); + } + + public String getClientInfo(String name) throws SQLException { + return connection.getClientInfo(name); + } + + public Properties getClientInfo() throws SQLException { + return connection.getClientInfo(); + } + + public Array createArrayOf(String typeName, Object[] elements) throws SQLException { + return connection.createArrayOf(typeName, elements); + } + + public Struct createStruct(String typeName, Object[] attributes) throws SQLException { + return connection.createStruct(typeName, attributes); + } + + @Override + public void setSchema(String schema) throws SQLException { + connection.setSchema(schema); + } + + @Override + public String getSchema() throws SQLException { + return connection.getSchema(); + } + + @Override + public void abort(Executor executor) throws SQLException { + connection.abort(executor); + } + + @Override + public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { + connection.setNetworkTimeout(executor, milliseconds); + } + + @Override + public int getNetworkTimeout() throws SQLException { + return connection.getNetworkTimeout(); + } + + public T unwrap(Class iface) throws SQLException { + return connection.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return connection.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/Driver.java b/src/nl/astraeus/jdbc/Driver.java new file mode 100644 index 0000000..8317172 --- /dev/null +++ b/src/nl/astraeus/jdbc/Driver.java @@ -0,0 +1,116 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.http.SimpleWebServer; +import nl.astraeus.jdbc.web.JdbcStatisticsServlet; +import nl.astraeus.jdbc.web.ResourceServlet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.*; +import java.util.Enumeration; +import java.util.Properties; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:54:37 PM + */ +public class Driver implements java.sql.Driver { + private final static Logger log = LoggerFactory.getLogger(Driver.class); + + final private static String URL_PREFIX = "jdbc:stat:"; + + private java.sql.Driver driver = null; + private String[] drivers = { + "org.postgresql.Driver", + "oracle.jdbc.driver.OracleDriver", + "com.sybase.jdbc2.jdbc.SybDriver", + "net.sourceforge.jtds.jdbc.Driver", + "com.microsoft.jdbc.sqlserver.SQLServerDriver", + "com.microsoft.sqlserver.jdbc.SQLServerDriver", + "weblogic.jdbc.sqlserver.SQLServerDriver", + "com.informix.jdbc.IfxDriver", + "org.apache.derby.jdbc.ClientDriver", + "org.apache.derby.jdbc.EmbeddedDriver", + "com.mysql.jdbc.Driver", + "org.hsqldb.jdbcDriver", + "org.h2.Driver" }; + + static { + log.debug("Loading driver class " + Driver.class.getName()); + + try { + DriverManager.registerDriver(new Driver()); + } catch (SQLException e) { + log.error("", e); + } + } + + public Driver() { + for (String dr : drivers) { + try { + Class.forName(dr); + } catch (Throwable e) { + log.debug("Can't instantiate driver: " + dr, e); + } + } + } + + private java.sql.Driver findDriver(String url) throws SQLException { + Enumeration e = DriverManager.getDrivers(); + + while (e.hasMoreElements()) { + java.sql.Driver d = (java.sql.Driver) e.nextElement(); + + if (d.acceptsURL(url)) { + return d; + } + } + + throw new SQLException("Driver not found: " + url); + } + + public Connection connect(String url, Properties info) throws SQLException { + url = url.substring(URL_PREFIX.length()); + + if (driver == null) { + driver = findDriver(url); + } + + if (driver != null) { + SimpleWebServer server = new SimpleWebServer(18080); + + server.addServlet(new JdbcStatisticsServlet(), "/"); + server.addServlet(new ResourceServlet(), "/resources/*"); + + server.start(); + } + + return new ConnectionLogger(driver.connect(url, info)); + } + + public boolean acceptsURL(String url) throws SQLException { + return (url != null && url.startsWith(URL_PREFIX)); + } + + public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { + return driver.getPropertyInfo(url, info); + } + + public int getMajorVersion() { + return driver.getMajorVersion(); + } + + public int getMinorVersion() { + return driver.getMinorVersion(); + } + + public boolean jdbcCompliant() { + return driver.jdbcCompliant(); + } + + @Override + public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException { + return driver.getParentLogger(); + } +} diff --git a/src/nl/astraeus/jdbc/JdbcLogger.java b/src/nl/astraeus/jdbc/JdbcLogger.java new file mode 100644 index 0000000..f4bc125 --- /dev/null +++ b/src/nl/astraeus/jdbc/JdbcLogger.java @@ -0,0 +1,113 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.jdbc.util.Util; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/** + * User: riennentjes + * Date: Jul 12, 2008 + * Time: 9:15:21 AM + */ +public class JdbcLogger { + private final static Logger logger = LoggerFactory.getLogger(JdbcLogger.class); + + private final static JdbcLogger instance = new JdbcLogger(); + + public static JdbcLogger get() { + return instance; + } + + public final static class LogEntry { + public QueryType type; + public String sql; + public long milli; + public long nano; + public int count; + public int hash; + + public LogEntry(int hash, QueryType type, String sql, long milli, long nano) { + this.hash = hash; + this.type = type; + this.sql = sql; + this.milli = milli; + this.nano = nano; + this.count = 1; + } + + public void addCount(long milli, long nano) { + synchronized (this) { + count++; + this.milli += milli; + this.nano += nano; + } + } + + public int getCount() { + return count; + } + + public String getMilli() { + return Util.formatNano(milli*1000000/count); + } + + public String getNano() { + return Util.formatNano(nano/count); + } + + public String getTotal() { + return Util.formatNano(nano); + } + + public String getSql() { + return sql; + } + } + + private Map queries; + + public JdbcLogger() { + queries = new ConcurrentHashMap(); + } + + public void logEntry(QueryType type, String sql, long milli, long nano) { + int hash = sql.hashCode(); + LogEntry entry = queries.get(hash); + + if (entry == null) { + entry = new LogEntry(hash, type, sql, milli, nano); + queries.put(hash, entry); + } else { + entry.addCount(milli, nano); + } + + if (queries.size() > 1000) { + List toRemove = new LinkedList(); + List values = new LinkedList(queries.values()); + + Collections.sort(values, new Comparator() { + @Override + public int compare(LogEntry o1, LogEntry o2) { + return o1.count - o2.count; + } + }); + + while (queries.size() > 900) { + queries.remove(values.remove(0).hash); + + } + } + } + + public static void log(QueryType type, String sql, long milli, long nano) { + instance.logEntry(type, sql, milli, nano); + } + + public Collection getEntries() { + return queries.values(); + } + +} diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f403193 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..73ff239 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..3b00020 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..275077f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/README b/README deleted file mode 100644 index 734abaf..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -This file was created by IntelliJ IDEA 11.1.1 for binding GitHub repository \ No newline at end of file diff --git a/Simple-jdbc-statistics.iml b/Simple-jdbc-statistics.iml new file mode 100644 index 0000000..ca90a9b --- /dev/null +++ b/Simple-jdbc-statistics.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/lib/h2-1.3.166.jar b/lib/h2-1.3.166.jar new file mode 100644 index 0000000..4985063 --- /dev/null +++ b/lib/h2-1.3.166.jar Binary files differ diff --git a/lib/servlet-api-2.5.jar b/lib/servlet-api-2.5.jar new file mode 100644 index 0000000..20b5755 --- /dev/null +++ b/lib/servlet-api-2.5.jar Binary files differ diff --git a/lib/slf4j-api-1.6.4.jar b/lib/slf4j-api-1.6.4.jar new file mode 100644 index 0000000..4d23f41 --- /dev/null +++ b/lib/slf4j-api-1.6.4.jar Binary files differ diff --git a/lib/slf4j-simple-1.6.4.jar b/lib/slf4j-simple-1.6.4.jar new file mode 100644 index 0000000..3d1b8d9 --- /dev/null +++ b/lib/slf4j-simple-1.6.4.jar Binary files differ diff --git a/lib/ssr-0.1.jar b/lib/ssr-0.1.jar new file mode 100644 index 0000000..65dfcf4 --- /dev/null +++ b/lib/ssr-0.1.jar Binary files differ diff --git a/lib/vst-0.4.jar b/lib/vst-0.4.jar new file mode 100644 index 0000000..db63792 --- /dev/null +++ b/lib/vst-0.4.jar Binary files differ diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..ac2dbe1 --- /dev/null +++ b/readme.md @@ -0,0 +1 @@ +A simple wrapper around jdbc drivers what will show current jdbc stats of the running queries on a simple web page on port 18080. \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/ConnectionLogger.java b/src/nl/astraeus/jdbc/ConnectionLogger.java new file mode 100644 index 0000000..c3e243f --- /dev/null +++ b/src/nl/astraeus/jdbc/ConnectionLogger.java @@ -0,0 +1,279 @@ +package nl.astraeus.jdbc; + +import java.sql.*; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Executor; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:12:34 PM + */ +public class ConnectionLogger implements Connection { + private Connection connection; + + private long milli; + private long nano; + private String lastSql; + + public ConnectionLogger(Connection connection) { + this.connection = connection; + this.lastSql = ""; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(QueryType.UNKNOWN, sql, m, n); + } + + public void commit() throws SQLException { + clearTime(); + + connection.commit(); + + log("commit"); + } + + public void rollback() throws SQLException { + clearTime(); + + connection.rollback(); + + log("rollback"); + } + + public void close() throws SQLException { + clearTime(); + + connection.close(); + + log("close"); + } + + public PreparedStatement prepareStatement(String sql) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, autoGeneratedKeys); + } + + public PreparedStatement prepareStatement(String sql, int columnIndexes[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnIndexes); + } + + public PreparedStatement prepareStatement(String sql, String columnNames[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnNames); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public Statement createStatement() throws SQLException { + return connection.createStatement(); + } + + public CallableStatement prepareCall(String sql) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql); + } + + public String nativeSQL(String sql) throws SQLException { + lastSql = sql; + return connection.nativeSQL(sql); + } + + public void setAutoCommit(boolean autoCommit) throws SQLException { + connection.setAutoCommit(autoCommit); + } + + public boolean getAutoCommit() throws SQLException { + return connection.getAutoCommit(); + } + + public boolean isClosed() throws SQLException { + return connection.isClosed(); + } + + public DatabaseMetaData getMetaData() throws SQLException { + return connection.getMetaData(); + } + + public void setReadOnly(boolean readOnly) throws SQLException { + connection.setReadOnly(readOnly); + } + + public boolean isReadOnly() throws SQLException { + return connection.isReadOnly(); + } + + public void setCatalog(String catalog) throws SQLException { + connection.setCatalog(catalog); + } + + public String getCatalog() throws SQLException { + return connection.getCatalog(); + } + + public void setTransactionIsolation(int level) throws SQLException { + connection.setTransactionIsolation(level); + } + + public int getTransactionIsolation() throws SQLException { + return connection.getTransactionIsolation(); + } + + public SQLWarning getWarnings() throws SQLException { + return connection.getWarnings(); + } + + public void clearWarnings() throws SQLException { + connection.clearWarnings(); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency); + } + + public Map> getTypeMap() throws SQLException { + return connection.getTypeMap(); + } + + public void setTypeMap(Map> map) throws SQLException { + connection.setTypeMap(map); + } + + public void setHoldability(int holdability) throws SQLException { + connection.setHoldability(holdability); + } + + public int getHoldability() throws SQLException { + return connection.getHoldability(); + } + + public Savepoint setSavepoint() throws SQLException { + return connection.setSavepoint(); + } + + public Savepoint setSavepoint(String name) throws SQLException { + return connection.setSavepoint(name); + } + + public void rollback(Savepoint savepoint) throws SQLException { + connection.rollback(); + } + + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + connection.releaseSavepoint(savepoint); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public Clob createClob() throws SQLException { + return connection.createClob(); + } + + public Blob createBlob() throws SQLException { + return connection.createBlob(); + } + + public NClob createNClob() throws SQLException { + return connection.createNClob(); + } + + public SQLXML createSQLXML() throws SQLException { + return connection.createSQLXML(); + } + + public boolean isValid(int timeout) throws SQLException { + return connection.isValid(timeout); + } + + public void setClientInfo(String name, String value) throws SQLClientInfoException { + connection.setClientInfo(name, value); + } + + public void setClientInfo(Properties properties) throws SQLClientInfoException { + connection.setClientInfo(properties); + } + + public String getClientInfo(String name) throws SQLException { + return connection.getClientInfo(name); + } + + public Properties getClientInfo() throws SQLException { + return connection.getClientInfo(); + } + + public Array createArrayOf(String typeName, Object[] elements) throws SQLException { + return connection.createArrayOf(typeName, elements); + } + + public Struct createStruct(String typeName, Object[] attributes) throws SQLException { + return connection.createStruct(typeName, attributes); + } + + @Override + public void setSchema(String schema) throws SQLException { + connection.setSchema(schema); + } + + @Override + public String getSchema() throws SQLException { + return connection.getSchema(); + } + + @Override + public void abort(Executor executor) throws SQLException { + connection.abort(executor); + } + + @Override + public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { + connection.setNetworkTimeout(executor, milliseconds); + } + + @Override + public int getNetworkTimeout() throws SQLException { + return connection.getNetworkTimeout(); + } + + public T unwrap(Class iface) throws SQLException { + return connection.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return connection.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/Driver.java b/src/nl/astraeus/jdbc/Driver.java new file mode 100644 index 0000000..8317172 --- /dev/null +++ b/src/nl/astraeus/jdbc/Driver.java @@ -0,0 +1,116 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.http.SimpleWebServer; +import nl.astraeus.jdbc.web.JdbcStatisticsServlet; +import nl.astraeus.jdbc.web.ResourceServlet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.*; +import java.util.Enumeration; +import java.util.Properties; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:54:37 PM + */ +public class Driver implements java.sql.Driver { + private final static Logger log = LoggerFactory.getLogger(Driver.class); + + final private static String URL_PREFIX = "jdbc:stat:"; + + private java.sql.Driver driver = null; + private String[] drivers = { + "org.postgresql.Driver", + "oracle.jdbc.driver.OracleDriver", + "com.sybase.jdbc2.jdbc.SybDriver", + "net.sourceforge.jtds.jdbc.Driver", + "com.microsoft.jdbc.sqlserver.SQLServerDriver", + "com.microsoft.sqlserver.jdbc.SQLServerDriver", + "weblogic.jdbc.sqlserver.SQLServerDriver", + "com.informix.jdbc.IfxDriver", + "org.apache.derby.jdbc.ClientDriver", + "org.apache.derby.jdbc.EmbeddedDriver", + "com.mysql.jdbc.Driver", + "org.hsqldb.jdbcDriver", + "org.h2.Driver" }; + + static { + log.debug("Loading driver class " + Driver.class.getName()); + + try { + DriverManager.registerDriver(new Driver()); + } catch (SQLException e) { + log.error("", e); + } + } + + public Driver() { + for (String dr : drivers) { + try { + Class.forName(dr); + } catch (Throwable e) { + log.debug("Can't instantiate driver: " + dr, e); + } + } + } + + private java.sql.Driver findDriver(String url) throws SQLException { + Enumeration e = DriverManager.getDrivers(); + + while (e.hasMoreElements()) { + java.sql.Driver d = (java.sql.Driver) e.nextElement(); + + if (d.acceptsURL(url)) { + return d; + } + } + + throw new SQLException("Driver not found: " + url); + } + + public Connection connect(String url, Properties info) throws SQLException { + url = url.substring(URL_PREFIX.length()); + + if (driver == null) { + driver = findDriver(url); + } + + if (driver != null) { + SimpleWebServer server = new SimpleWebServer(18080); + + server.addServlet(new JdbcStatisticsServlet(), "/"); + server.addServlet(new ResourceServlet(), "/resources/*"); + + server.start(); + } + + return new ConnectionLogger(driver.connect(url, info)); + } + + public boolean acceptsURL(String url) throws SQLException { + return (url != null && url.startsWith(URL_PREFIX)); + } + + public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { + return driver.getPropertyInfo(url, info); + } + + public int getMajorVersion() { + return driver.getMajorVersion(); + } + + public int getMinorVersion() { + return driver.getMinorVersion(); + } + + public boolean jdbcCompliant() { + return driver.jdbcCompliant(); + } + + @Override + public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException { + return driver.getParentLogger(); + } +} diff --git a/src/nl/astraeus/jdbc/JdbcLogger.java b/src/nl/astraeus/jdbc/JdbcLogger.java new file mode 100644 index 0000000..f4bc125 --- /dev/null +++ b/src/nl/astraeus/jdbc/JdbcLogger.java @@ -0,0 +1,113 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.jdbc.util.Util; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/** + * User: riennentjes + * Date: Jul 12, 2008 + * Time: 9:15:21 AM + */ +public class JdbcLogger { + private final static Logger logger = LoggerFactory.getLogger(JdbcLogger.class); + + private final static JdbcLogger instance = new JdbcLogger(); + + public static JdbcLogger get() { + return instance; + } + + public final static class LogEntry { + public QueryType type; + public String sql; + public long milli; + public long nano; + public int count; + public int hash; + + public LogEntry(int hash, QueryType type, String sql, long milli, long nano) { + this.hash = hash; + this.type = type; + this.sql = sql; + this.milli = milli; + this.nano = nano; + this.count = 1; + } + + public void addCount(long milli, long nano) { + synchronized (this) { + count++; + this.milli += milli; + this.nano += nano; + } + } + + public int getCount() { + return count; + } + + public String getMilli() { + return Util.formatNano(milli*1000000/count); + } + + public String getNano() { + return Util.formatNano(nano/count); + } + + public String getTotal() { + return Util.formatNano(nano); + } + + public String getSql() { + return sql; + } + } + + private Map queries; + + public JdbcLogger() { + queries = new ConcurrentHashMap(); + } + + public void logEntry(QueryType type, String sql, long milli, long nano) { + int hash = sql.hashCode(); + LogEntry entry = queries.get(hash); + + if (entry == null) { + entry = new LogEntry(hash, type, sql, milli, nano); + queries.put(hash, entry); + } else { + entry.addCount(milli, nano); + } + + if (queries.size() > 1000) { + List toRemove = new LinkedList(); + List values = new LinkedList(queries.values()); + + Collections.sort(values, new Comparator() { + @Override + public int compare(LogEntry o1, LogEntry o2) { + return o1.count - o2.count; + } + }); + + while (queries.size() > 900) { + queries.remove(values.remove(0).hash); + + } + } + } + + public static void log(QueryType type, String sql, long milli, long nano) { + instance.logEntry(type, sql, milli, nano); + } + + public Collection getEntries() { + return queries.values(); + } + +} diff --git a/src/nl/astraeus/jdbc/PreparedStatementLogger.java b/src/nl/astraeus/jdbc/PreparedStatementLogger.java new file mode 100644 index 0000000..98aefc7 --- /dev/null +++ b/src/nl/astraeus/jdbc/PreparedStatementLogger.java @@ -0,0 +1,577 @@ +package nl.astraeus.jdbc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.InputStream; +import java.io.Reader; +import java.math.BigDecimal; +import java.net.URL; +import java.sql.*; +import java.util.Calendar; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 7:47:57 PM + */ +public class PreparedStatementLogger implements PreparedStatement { + private final static Logger log = LoggerFactory.getLogger(PreparedStatementLogger.class); + + private PreparedStatement statement; + + private String sql; + private QueryType type; + private long milli; + private long nano; + + //private ArrayList parameters; + + public PreparedStatementLogger(PreparedStatement statement) { + this.statement = statement; + this.sql = ""; + this.type = QueryType.UNKNOWN; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(QueryType type, String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(type, sql, m, n); + } + + public PreparedStatementLogger(Connection connection, String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql); + } + + public PreparedStatementLogger(Connection connection, String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatementLogger(Connection connection, String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, autoGeneratedKeys); + } + + public PreparedStatementLogger(Connection connection, String sql, int[] columnIndexes) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnIndexes); + } + + public PreparedStatementLogger(Connection connection, String sql, String[] columnNames) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnNames); + } + + public boolean execute() throws SQLException { + clearTime(); + + boolean result = statement.execute(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery() throws SQLException { + clearTime(); + + ResultSet result = statement.executeQuery(); + + log(type, sql); + + return result; + } + + public int executeUpdate() throws SQLException { + clearTime(); + + int result = statement.executeUpdate(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + ResultSet result = statement.executeQuery(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnNames); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnNames); + + log(type, sql); + + return result; + } + + + public void setNull(int parameterIndex, int sqlType) throws SQLException { + statement.setNull(parameterIndex, sqlType); + } + + public void setBoolean(int parameterIndex, boolean x) throws SQLException { + statement.setBoolean(parameterIndex, x); + } + + public void setByte(int parameterIndex, byte x) throws SQLException { + statement.setByte(parameterIndex, x); + } + + public void setShort(int parameterIndex, short x) throws SQLException { + statement.setShort(parameterIndex, x); + } + + public void setInt(int parameterIndex, int x) throws SQLException { + statement.setInt(parameterIndex, x); + } + + public void setLong(int parameterIndex, long x) throws SQLException { + statement.setLong(parameterIndex, x); + } + + public void setFloat(int parameterIndex, float x) throws SQLException { + statement.setFloat(parameterIndex, x); + } + + public void setDouble(int parameterIndex, double x) throws SQLException { + statement.setDouble(parameterIndex, x); + } + + public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { + statement.setBigDecimal(parameterIndex, x); + } + + public void setString(int parameterIndex, String x) throws SQLException { + statement.setString(parameterIndex, x); + } + + public void setBytes(int parameterIndex, byte x[]) throws SQLException { + statement.setBytes(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x) throws SQLException { + statement.setDate(parameterIndex, x); + } + + public void setTime(int parameterIndex, Time x) throws SQLException { + statement.setTime(parameterIndex, x); + } + + public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { + statement.setTimestamp(parameterIndex, x); + } + + public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setUnicodeStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType); + } + + public void setObject(int parameterIndex, Object x) throws SQLException { + statement.setObject(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setRef(int parameterIndex, Ref x) throws SQLException { + statement.setRef(parameterIndex, x); + } + + public void setBlob(int parameterIndex, Blob x) throws SQLException { + statement.setBlob(parameterIndex, x); + } + + public void setClob(int parameterIndex, Clob x) throws SQLException { + statement.setClob(parameterIndex, x); + } + + public void setArray(int parameterIndex, Array x) throws SQLException { + statement.setArray(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { + statement.setDate(parameterIndex, x, cal); + } + + public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { + statement.setTime(parameterIndex, x, cal); + } + + public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { + statement.setTimestamp(parameterIndex, x, cal); + } + + public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException { + statement.setNull(parameterIndex, sqlType, typeName); + } + + public void setURL(int parameterIndex, URL x) throws SQLException { + statement.setURL(parameterIndex, x); + } + + public void setRowId(int parameterIndex, RowId x) throws SQLException { + statement.setRowId(parameterIndex, x); + } + + public void setNString(int parameterIndex, String value) throws SQLException { + statement.setNString(parameterIndex, value); + } + + public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException { + statement.setNCharacterStream(parameterIndex, value, length); + } + + public void setNClob(int parameterIndex, NClob value) throws SQLException { + statement.setNClob(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setClob(parameterIndex, reader, length); + } + + public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException { + statement.setBlob(parameterIndex, inputStream, length); + } + + public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setNClob(parameterIndex, reader, length); + } + + public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException { + statement.setSQLXML(parameterIndex, xmlObject); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType, scaleOrLength); + } + + public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException { + statement.setAsciiStream(parameterIndex, x); + } + + public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException { + statement.setBinaryStream(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException { + statement.setCharacterStream(parameterIndex, reader); + } + + public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException { + statement.setNCharacterStream(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader) throws SQLException { + statement.setClob(parameterIndex, reader); + } + + public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException { + statement.setBlob(parameterIndex, inputStream); + } + + public void setNClob(int parameterIndex, Reader reader) throws SQLException { + statement.setNClob(parameterIndex, reader); + } + + + public void close() throws SQLException { + sql = ""; + type = QueryType.UNKNOWN; + milli = 0; + nano = 0; + + statement.close(); + } + + public ResultSetMetaData getMetaData() throws SQLException { + return statement.getMetaData(); + } + + public void clearParameters() throws SQLException { + statement.clearParameters(); + } + + public ParameterMetaData getParameterMetaData() throws SQLException { + return statement.getParameterMetaData(); + } + + public void addBatch() throws SQLException { + statement.addBatch(); + } + + public int getMaxFieldSize() throws SQLException { + return statement.getMaxFieldSize(); + } + + public void setMaxFieldSize(int max) throws SQLException { + statement.setMaxFieldSize(max); + } + + public int getMaxRows() throws SQLException { + return statement.getMaxRows(); + } + + public void setMaxRows(int max) throws SQLException { + statement.setMaxRows(max); + } + + public void setEscapeProcessing(boolean enable) throws SQLException { + statement.setEscapeProcessing(enable); + } + + public int getQueryTimeout() throws SQLException { + return statement.getQueryTimeout(); + } + + public void setQueryTimeout(int seconds) throws SQLException { + statement.setQueryTimeout(seconds); + } + + public void cancel() throws SQLException { + statement.cancel(); + } + + public SQLWarning getWarnings() throws SQLException { + return statement.getWarnings(); + } + + public void clearWarnings() throws SQLException { + statement.clearWarnings(); + } + + public void setCursorName(String name) throws SQLException { + statement.setCursorName(name); + } + + public boolean execute(String sql) throws SQLException { + return statement.execute(sql); + } + + public ResultSet getResultSet() throws SQLException { + return statement.getResultSet(); + } + + public int getUpdateCount() throws SQLException { + return statement.getUpdateCount(); + } + + public boolean getMoreResults() throws SQLException { + return statement.getMoreResults(); + } + + public void setFetchDirection(int direction) throws SQLException { + statement.setFetchDirection(direction); + } + + public int getFetchDirection() throws SQLException { + return statement.getFetchDirection(); + } + + public void setFetchSize(int rows) throws SQLException { + statement.setFetchSize(rows); + } + + public int getFetchSize() throws SQLException { + return statement.getFetchSize(); + } + + public int getResultSetConcurrency() throws SQLException { + return statement.getResultSetConcurrency(); + } + + public int getResultSetType() throws SQLException { + return statement.getResultSetType(); + } + + public void addBatch(String sql) throws SQLException { + statement.addBatch(sql); + } + + public void clearBatch() throws SQLException { + statement.clearBatch(); + } + + public int[] executeBatch() throws SQLException { + return statement.executeBatch(); + } + + public Connection getConnection() throws SQLException { + return statement.getConnection(); + } + + public boolean getMoreResults(int current) throws SQLException { + return statement.getMoreResults(current); + } + + public ResultSet getGeneratedKeys() throws SQLException { + return statement.getGeneratedKeys(); + } + + public int getResultSetHoldability() throws SQLException { + return statement.getResultSetHoldability(); + } + + public boolean isClosed() throws SQLException { + return statement.isClosed(); + } + + public void setPoolable(boolean poolable) throws SQLException { + statement.setPoolable(poolable); + } + + public boolean isPoolable() throws SQLException { + return statement.isPoolable(); + } + + @Override + public void closeOnCompletion() throws SQLException { + statement.closeOnCompletion();; + } + + @Override + public boolean isCloseOnCompletion() throws SQLException { + return statement.isCloseOnCompletion(); + } + + public T unwrap(Class iface) throws SQLException { + return statement.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return statement.isWrapperFor(iface); + } +} diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f403193 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..73ff239 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..3b00020 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..275077f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/README b/README deleted file mode 100644 index 734abaf..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -This file was created by IntelliJ IDEA 11.1.1 for binding GitHub repository \ No newline at end of file diff --git a/Simple-jdbc-statistics.iml b/Simple-jdbc-statistics.iml new file mode 100644 index 0000000..ca90a9b --- /dev/null +++ b/Simple-jdbc-statistics.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/lib/h2-1.3.166.jar b/lib/h2-1.3.166.jar new file mode 100644 index 0000000..4985063 --- /dev/null +++ b/lib/h2-1.3.166.jar Binary files differ diff --git a/lib/servlet-api-2.5.jar b/lib/servlet-api-2.5.jar new file mode 100644 index 0000000..20b5755 --- /dev/null +++ b/lib/servlet-api-2.5.jar Binary files differ diff --git a/lib/slf4j-api-1.6.4.jar b/lib/slf4j-api-1.6.4.jar new file mode 100644 index 0000000..4d23f41 --- /dev/null +++ b/lib/slf4j-api-1.6.4.jar Binary files differ diff --git a/lib/slf4j-simple-1.6.4.jar b/lib/slf4j-simple-1.6.4.jar new file mode 100644 index 0000000..3d1b8d9 --- /dev/null +++ b/lib/slf4j-simple-1.6.4.jar Binary files differ diff --git a/lib/ssr-0.1.jar b/lib/ssr-0.1.jar new file mode 100644 index 0000000..65dfcf4 --- /dev/null +++ b/lib/ssr-0.1.jar Binary files differ diff --git a/lib/vst-0.4.jar b/lib/vst-0.4.jar new file mode 100644 index 0000000..db63792 --- /dev/null +++ b/lib/vst-0.4.jar Binary files differ diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..ac2dbe1 --- /dev/null +++ b/readme.md @@ -0,0 +1 @@ +A simple wrapper around jdbc drivers what will show current jdbc stats of the running queries on a simple web page on port 18080. \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/ConnectionLogger.java b/src/nl/astraeus/jdbc/ConnectionLogger.java new file mode 100644 index 0000000..c3e243f --- /dev/null +++ b/src/nl/astraeus/jdbc/ConnectionLogger.java @@ -0,0 +1,279 @@ +package nl.astraeus.jdbc; + +import java.sql.*; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Executor; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:12:34 PM + */ +public class ConnectionLogger implements Connection { + private Connection connection; + + private long milli; + private long nano; + private String lastSql; + + public ConnectionLogger(Connection connection) { + this.connection = connection; + this.lastSql = ""; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(QueryType.UNKNOWN, sql, m, n); + } + + public void commit() throws SQLException { + clearTime(); + + connection.commit(); + + log("commit"); + } + + public void rollback() throws SQLException { + clearTime(); + + connection.rollback(); + + log("rollback"); + } + + public void close() throws SQLException { + clearTime(); + + connection.close(); + + log("close"); + } + + public PreparedStatement prepareStatement(String sql) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, autoGeneratedKeys); + } + + public PreparedStatement prepareStatement(String sql, int columnIndexes[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnIndexes); + } + + public PreparedStatement prepareStatement(String sql, String columnNames[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnNames); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public Statement createStatement() throws SQLException { + return connection.createStatement(); + } + + public CallableStatement prepareCall(String sql) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql); + } + + public String nativeSQL(String sql) throws SQLException { + lastSql = sql; + return connection.nativeSQL(sql); + } + + public void setAutoCommit(boolean autoCommit) throws SQLException { + connection.setAutoCommit(autoCommit); + } + + public boolean getAutoCommit() throws SQLException { + return connection.getAutoCommit(); + } + + public boolean isClosed() throws SQLException { + return connection.isClosed(); + } + + public DatabaseMetaData getMetaData() throws SQLException { + return connection.getMetaData(); + } + + public void setReadOnly(boolean readOnly) throws SQLException { + connection.setReadOnly(readOnly); + } + + public boolean isReadOnly() throws SQLException { + return connection.isReadOnly(); + } + + public void setCatalog(String catalog) throws SQLException { + connection.setCatalog(catalog); + } + + public String getCatalog() throws SQLException { + return connection.getCatalog(); + } + + public void setTransactionIsolation(int level) throws SQLException { + connection.setTransactionIsolation(level); + } + + public int getTransactionIsolation() throws SQLException { + return connection.getTransactionIsolation(); + } + + public SQLWarning getWarnings() throws SQLException { + return connection.getWarnings(); + } + + public void clearWarnings() throws SQLException { + connection.clearWarnings(); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency); + } + + public Map> getTypeMap() throws SQLException { + return connection.getTypeMap(); + } + + public void setTypeMap(Map> map) throws SQLException { + connection.setTypeMap(map); + } + + public void setHoldability(int holdability) throws SQLException { + connection.setHoldability(holdability); + } + + public int getHoldability() throws SQLException { + return connection.getHoldability(); + } + + public Savepoint setSavepoint() throws SQLException { + return connection.setSavepoint(); + } + + public Savepoint setSavepoint(String name) throws SQLException { + return connection.setSavepoint(name); + } + + public void rollback(Savepoint savepoint) throws SQLException { + connection.rollback(); + } + + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + connection.releaseSavepoint(savepoint); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public Clob createClob() throws SQLException { + return connection.createClob(); + } + + public Blob createBlob() throws SQLException { + return connection.createBlob(); + } + + public NClob createNClob() throws SQLException { + return connection.createNClob(); + } + + public SQLXML createSQLXML() throws SQLException { + return connection.createSQLXML(); + } + + public boolean isValid(int timeout) throws SQLException { + return connection.isValid(timeout); + } + + public void setClientInfo(String name, String value) throws SQLClientInfoException { + connection.setClientInfo(name, value); + } + + public void setClientInfo(Properties properties) throws SQLClientInfoException { + connection.setClientInfo(properties); + } + + public String getClientInfo(String name) throws SQLException { + return connection.getClientInfo(name); + } + + public Properties getClientInfo() throws SQLException { + return connection.getClientInfo(); + } + + public Array createArrayOf(String typeName, Object[] elements) throws SQLException { + return connection.createArrayOf(typeName, elements); + } + + public Struct createStruct(String typeName, Object[] attributes) throws SQLException { + return connection.createStruct(typeName, attributes); + } + + @Override + public void setSchema(String schema) throws SQLException { + connection.setSchema(schema); + } + + @Override + public String getSchema() throws SQLException { + return connection.getSchema(); + } + + @Override + public void abort(Executor executor) throws SQLException { + connection.abort(executor); + } + + @Override + public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { + connection.setNetworkTimeout(executor, milliseconds); + } + + @Override + public int getNetworkTimeout() throws SQLException { + return connection.getNetworkTimeout(); + } + + public T unwrap(Class iface) throws SQLException { + return connection.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return connection.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/Driver.java b/src/nl/astraeus/jdbc/Driver.java new file mode 100644 index 0000000..8317172 --- /dev/null +++ b/src/nl/astraeus/jdbc/Driver.java @@ -0,0 +1,116 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.http.SimpleWebServer; +import nl.astraeus.jdbc.web.JdbcStatisticsServlet; +import nl.astraeus.jdbc.web.ResourceServlet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.*; +import java.util.Enumeration; +import java.util.Properties; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:54:37 PM + */ +public class Driver implements java.sql.Driver { + private final static Logger log = LoggerFactory.getLogger(Driver.class); + + final private static String URL_PREFIX = "jdbc:stat:"; + + private java.sql.Driver driver = null; + private String[] drivers = { + "org.postgresql.Driver", + "oracle.jdbc.driver.OracleDriver", + "com.sybase.jdbc2.jdbc.SybDriver", + "net.sourceforge.jtds.jdbc.Driver", + "com.microsoft.jdbc.sqlserver.SQLServerDriver", + "com.microsoft.sqlserver.jdbc.SQLServerDriver", + "weblogic.jdbc.sqlserver.SQLServerDriver", + "com.informix.jdbc.IfxDriver", + "org.apache.derby.jdbc.ClientDriver", + "org.apache.derby.jdbc.EmbeddedDriver", + "com.mysql.jdbc.Driver", + "org.hsqldb.jdbcDriver", + "org.h2.Driver" }; + + static { + log.debug("Loading driver class " + Driver.class.getName()); + + try { + DriverManager.registerDriver(new Driver()); + } catch (SQLException e) { + log.error("", e); + } + } + + public Driver() { + for (String dr : drivers) { + try { + Class.forName(dr); + } catch (Throwable e) { + log.debug("Can't instantiate driver: " + dr, e); + } + } + } + + private java.sql.Driver findDriver(String url) throws SQLException { + Enumeration e = DriverManager.getDrivers(); + + while (e.hasMoreElements()) { + java.sql.Driver d = (java.sql.Driver) e.nextElement(); + + if (d.acceptsURL(url)) { + return d; + } + } + + throw new SQLException("Driver not found: " + url); + } + + public Connection connect(String url, Properties info) throws SQLException { + url = url.substring(URL_PREFIX.length()); + + if (driver == null) { + driver = findDriver(url); + } + + if (driver != null) { + SimpleWebServer server = new SimpleWebServer(18080); + + server.addServlet(new JdbcStatisticsServlet(), "/"); + server.addServlet(new ResourceServlet(), "/resources/*"); + + server.start(); + } + + return new ConnectionLogger(driver.connect(url, info)); + } + + public boolean acceptsURL(String url) throws SQLException { + return (url != null && url.startsWith(URL_PREFIX)); + } + + public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { + return driver.getPropertyInfo(url, info); + } + + public int getMajorVersion() { + return driver.getMajorVersion(); + } + + public int getMinorVersion() { + return driver.getMinorVersion(); + } + + public boolean jdbcCompliant() { + return driver.jdbcCompliant(); + } + + @Override + public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException { + return driver.getParentLogger(); + } +} diff --git a/src/nl/astraeus/jdbc/JdbcLogger.java b/src/nl/astraeus/jdbc/JdbcLogger.java new file mode 100644 index 0000000..f4bc125 --- /dev/null +++ b/src/nl/astraeus/jdbc/JdbcLogger.java @@ -0,0 +1,113 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.jdbc.util.Util; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/** + * User: riennentjes + * Date: Jul 12, 2008 + * Time: 9:15:21 AM + */ +public class JdbcLogger { + private final static Logger logger = LoggerFactory.getLogger(JdbcLogger.class); + + private final static JdbcLogger instance = new JdbcLogger(); + + public static JdbcLogger get() { + return instance; + } + + public final static class LogEntry { + public QueryType type; + public String sql; + public long milli; + public long nano; + public int count; + public int hash; + + public LogEntry(int hash, QueryType type, String sql, long milli, long nano) { + this.hash = hash; + this.type = type; + this.sql = sql; + this.milli = milli; + this.nano = nano; + this.count = 1; + } + + public void addCount(long milli, long nano) { + synchronized (this) { + count++; + this.milli += milli; + this.nano += nano; + } + } + + public int getCount() { + return count; + } + + public String getMilli() { + return Util.formatNano(milli*1000000/count); + } + + public String getNano() { + return Util.formatNano(nano/count); + } + + public String getTotal() { + return Util.formatNano(nano); + } + + public String getSql() { + return sql; + } + } + + private Map queries; + + public JdbcLogger() { + queries = new ConcurrentHashMap(); + } + + public void logEntry(QueryType type, String sql, long milli, long nano) { + int hash = sql.hashCode(); + LogEntry entry = queries.get(hash); + + if (entry == null) { + entry = new LogEntry(hash, type, sql, milli, nano); + queries.put(hash, entry); + } else { + entry.addCount(milli, nano); + } + + if (queries.size() > 1000) { + List toRemove = new LinkedList(); + List values = new LinkedList(queries.values()); + + Collections.sort(values, new Comparator() { + @Override + public int compare(LogEntry o1, LogEntry o2) { + return o1.count - o2.count; + } + }); + + while (queries.size() > 900) { + queries.remove(values.remove(0).hash); + + } + } + } + + public static void log(QueryType type, String sql, long milli, long nano) { + instance.logEntry(type, sql, milli, nano); + } + + public Collection getEntries() { + return queries.values(); + } + +} diff --git a/src/nl/astraeus/jdbc/PreparedStatementLogger.java b/src/nl/astraeus/jdbc/PreparedStatementLogger.java new file mode 100644 index 0000000..98aefc7 --- /dev/null +++ b/src/nl/astraeus/jdbc/PreparedStatementLogger.java @@ -0,0 +1,577 @@ +package nl.astraeus.jdbc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.InputStream; +import java.io.Reader; +import java.math.BigDecimal; +import java.net.URL; +import java.sql.*; +import java.util.Calendar; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 7:47:57 PM + */ +public class PreparedStatementLogger implements PreparedStatement { + private final static Logger log = LoggerFactory.getLogger(PreparedStatementLogger.class); + + private PreparedStatement statement; + + private String sql; + private QueryType type; + private long milli; + private long nano; + + //private ArrayList parameters; + + public PreparedStatementLogger(PreparedStatement statement) { + this.statement = statement; + this.sql = ""; + this.type = QueryType.UNKNOWN; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(QueryType type, String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(type, sql, m, n); + } + + public PreparedStatementLogger(Connection connection, String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql); + } + + public PreparedStatementLogger(Connection connection, String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatementLogger(Connection connection, String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, autoGeneratedKeys); + } + + public PreparedStatementLogger(Connection connection, String sql, int[] columnIndexes) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnIndexes); + } + + public PreparedStatementLogger(Connection connection, String sql, String[] columnNames) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnNames); + } + + public boolean execute() throws SQLException { + clearTime(); + + boolean result = statement.execute(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery() throws SQLException { + clearTime(); + + ResultSet result = statement.executeQuery(); + + log(type, sql); + + return result; + } + + public int executeUpdate() throws SQLException { + clearTime(); + + int result = statement.executeUpdate(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + ResultSet result = statement.executeQuery(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnNames); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnNames); + + log(type, sql); + + return result; + } + + + public void setNull(int parameterIndex, int sqlType) throws SQLException { + statement.setNull(parameterIndex, sqlType); + } + + public void setBoolean(int parameterIndex, boolean x) throws SQLException { + statement.setBoolean(parameterIndex, x); + } + + public void setByte(int parameterIndex, byte x) throws SQLException { + statement.setByte(parameterIndex, x); + } + + public void setShort(int parameterIndex, short x) throws SQLException { + statement.setShort(parameterIndex, x); + } + + public void setInt(int parameterIndex, int x) throws SQLException { + statement.setInt(parameterIndex, x); + } + + public void setLong(int parameterIndex, long x) throws SQLException { + statement.setLong(parameterIndex, x); + } + + public void setFloat(int parameterIndex, float x) throws SQLException { + statement.setFloat(parameterIndex, x); + } + + public void setDouble(int parameterIndex, double x) throws SQLException { + statement.setDouble(parameterIndex, x); + } + + public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { + statement.setBigDecimal(parameterIndex, x); + } + + public void setString(int parameterIndex, String x) throws SQLException { + statement.setString(parameterIndex, x); + } + + public void setBytes(int parameterIndex, byte x[]) throws SQLException { + statement.setBytes(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x) throws SQLException { + statement.setDate(parameterIndex, x); + } + + public void setTime(int parameterIndex, Time x) throws SQLException { + statement.setTime(parameterIndex, x); + } + + public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { + statement.setTimestamp(parameterIndex, x); + } + + public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setUnicodeStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType); + } + + public void setObject(int parameterIndex, Object x) throws SQLException { + statement.setObject(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setRef(int parameterIndex, Ref x) throws SQLException { + statement.setRef(parameterIndex, x); + } + + public void setBlob(int parameterIndex, Blob x) throws SQLException { + statement.setBlob(parameterIndex, x); + } + + public void setClob(int parameterIndex, Clob x) throws SQLException { + statement.setClob(parameterIndex, x); + } + + public void setArray(int parameterIndex, Array x) throws SQLException { + statement.setArray(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { + statement.setDate(parameterIndex, x, cal); + } + + public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { + statement.setTime(parameterIndex, x, cal); + } + + public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { + statement.setTimestamp(parameterIndex, x, cal); + } + + public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException { + statement.setNull(parameterIndex, sqlType, typeName); + } + + public void setURL(int parameterIndex, URL x) throws SQLException { + statement.setURL(parameterIndex, x); + } + + public void setRowId(int parameterIndex, RowId x) throws SQLException { + statement.setRowId(parameterIndex, x); + } + + public void setNString(int parameterIndex, String value) throws SQLException { + statement.setNString(parameterIndex, value); + } + + public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException { + statement.setNCharacterStream(parameterIndex, value, length); + } + + public void setNClob(int parameterIndex, NClob value) throws SQLException { + statement.setNClob(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setClob(parameterIndex, reader, length); + } + + public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException { + statement.setBlob(parameterIndex, inputStream, length); + } + + public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setNClob(parameterIndex, reader, length); + } + + public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException { + statement.setSQLXML(parameterIndex, xmlObject); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType, scaleOrLength); + } + + public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException { + statement.setAsciiStream(parameterIndex, x); + } + + public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException { + statement.setBinaryStream(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException { + statement.setCharacterStream(parameterIndex, reader); + } + + public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException { + statement.setNCharacterStream(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader) throws SQLException { + statement.setClob(parameterIndex, reader); + } + + public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException { + statement.setBlob(parameterIndex, inputStream); + } + + public void setNClob(int parameterIndex, Reader reader) throws SQLException { + statement.setNClob(parameterIndex, reader); + } + + + public void close() throws SQLException { + sql = ""; + type = QueryType.UNKNOWN; + milli = 0; + nano = 0; + + statement.close(); + } + + public ResultSetMetaData getMetaData() throws SQLException { + return statement.getMetaData(); + } + + public void clearParameters() throws SQLException { + statement.clearParameters(); + } + + public ParameterMetaData getParameterMetaData() throws SQLException { + return statement.getParameterMetaData(); + } + + public void addBatch() throws SQLException { + statement.addBatch(); + } + + public int getMaxFieldSize() throws SQLException { + return statement.getMaxFieldSize(); + } + + public void setMaxFieldSize(int max) throws SQLException { + statement.setMaxFieldSize(max); + } + + public int getMaxRows() throws SQLException { + return statement.getMaxRows(); + } + + public void setMaxRows(int max) throws SQLException { + statement.setMaxRows(max); + } + + public void setEscapeProcessing(boolean enable) throws SQLException { + statement.setEscapeProcessing(enable); + } + + public int getQueryTimeout() throws SQLException { + return statement.getQueryTimeout(); + } + + public void setQueryTimeout(int seconds) throws SQLException { + statement.setQueryTimeout(seconds); + } + + public void cancel() throws SQLException { + statement.cancel(); + } + + public SQLWarning getWarnings() throws SQLException { + return statement.getWarnings(); + } + + public void clearWarnings() throws SQLException { + statement.clearWarnings(); + } + + public void setCursorName(String name) throws SQLException { + statement.setCursorName(name); + } + + public boolean execute(String sql) throws SQLException { + return statement.execute(sql); + } + + public ResultSet getResultSet() throws SQLException { + return statement.getResultSet(); + } + + public int getUpdateCount() throws SQLException { + return statement.getUpdateCount(); + } + + public boolean getMoreResults() throws SQLException { + return statement.getMoreResults(); + } + + public void setFetchDirection(int direction) throws SQLException { + statement.setFetchDirection(direction); + } + + public int getFetchDirection() throws SQLException { + return statement.getFetchDirection(); + } + + public void setFetchSize(int rows) throws SQLException { + statement.setFetchSize(rows); + } + + public int getFetchSize() throws SQLException { + return statement.getFetchSize(); + } + + public int getResultSetConcurrency() throws SQLException { + return statement.getResultSetConcurrency(); + } + + public int getResultSetType() throws SQLException { + return statement.getResultSetType(); + } + + public void addBatch(String sql) throws SQLException { + statement.addBatch(sql); + } + + public void clearBatch() throws SQLException { + statement.clearBatch(); + } + + public int[] executeBatch() throws SQLException { + return statement.executeBatch(); + } + + public Connection getConnection() throws SQLException { + return statement.getConnection(); + } + + public boolean getMoreResults(int current) throws SQLException { + return statement.getMoreResults(current); + } + + public ResultSet getGeneratedKeys() throws SQLException { + return statement.getGeneratedKeys(); + } + + public int getResultSetHoldability() throws SQLException { + return statement.getResultSetHoldability(); + } + + public boolean isClosed() throws SQLException { + return statement.isClosed(); + } + + public void setPoolable(boolean poolable) throws SQLException { + statement.setPoolable(poolable); + } + + public boolean isPoolable() throws SQLException { + return statement.isPoolable(); + } + + @Override + public void closeOnCompletion() throws SQLException { + statement.closeOnCompletion();; + } + + @Override + public boolean isCloseOnCompletion() throws SQLException { + return statement.isCloseOnCompletion(); + } + + public T unwrap(Class iface) throws SQLException { + return statement.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return statement.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/QueryType.java b/src/nl/astraeus/jdbc/QueryType.java new file mode 100644 index 0000000..744fbfc --- /dev/null +++ b/src/nl/astraeus/jdbc/QueryType.java @@ -0,0 +1,24 @@ +package nl.astraeus.jdbc; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:32:49 PM + */ +public enum QueryType { + PLAIN("plain"), + PREPARED("prepared"), + CALLABLE("callable"), + UNKNOWN("unknown"); + + private String description; + + QueryType(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } + +} diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f403193 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..73ff239 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..3b00020 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..275077f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/README b/README deleted file mode 100644 index 734abaf..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -This file was created by IntelliJ IDEA 11.1.1 for binding GitHub repository \ No newline at end of file diff --git a/Simple-jdbc-statistics.iml b/Simple-jdbc-statistics.iml new file mode 100644 index 0000000..ca90a9b --- /dev/null +++ b/Simple-jdbc-statistics.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/lib/h2-1.3.166.jar b/lib/h2-1.3.166.jar new file mode 100644 index 0000000..4985063 --- /dev/null +++ b/lib/h2-1.3.166.jar Binary files differ diff --git a/lib/servlet-api-2.5.jar b/lib/servlet-api-2.5.jar new file mode 100644 index 0000000..20b5755 --- /dev/null +++ b/lib/servlet-api-2.5.jar Binary files differ diff --git a/lib/slf4j-api-1.6.4.jar b/lib/slf4j-api-1.6.4.jar new file mode 100644 index 0000000..4d23f41 --- /dev/null +++ b/lib/slf4j-api-1.6.4.jar Binary files differ diff --git a/lib/slf4j-simple-1.6.4.jar b/lib/slf4j-simple-1.6.4.jar new file mode 100644 index 0000000..3d1b8d9 --- /dev/null +++ b/lib/slf4j-simple-1.6.4.jar Binary files differ diff --git a/lib/ssr-0.1.jar b/lib/ssr-0.1.jar new file mode 100644 index 0000000..65dfcf4 --- /dev/null +++ b/lib/ssr-0.1.jar Binary files differ diff --git a/lib/vst-0.4.jar b/lib/vst-0.4.jar new file mode 100644 index 0000000..db63792 --- /dev/null +++ b/lib/vst-0.4.jar Binary files differ diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..ac2dbe1 --- /dev/null +++ b/readme.md @@ -0,0 +1 @@ +A simple wrapper around jdbc drivers what will show current jdbc stats of the running queries on a simple web page on port 18080. \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/ConnectionLogger.java b/src/nl/astraeus/jdbc/ConnectionLogger.java new file mode 100644 index 0000000..c3e243f --- /dev/null +++ b/src/nl/astraeus/jdbc/ConnectionLogger.java @@ -0,0 +1,279 @@ +package nl.astraeus.jdbc; + +import java.sql.*; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Executor; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:12:34 PM + */ +public class ConnectionLogger implements Connection { + private Connection connection; + + private long milli; + private long nano; + private String lastSql; + + public ConnectionLogger(Connection connection) { + this.connection = connection; + this.lastSql = ""; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(QueryType.UNKNOWN, sql, m, n); + } + + public void commit() throws SQLException { + clearTime(); + + connection.commit(); + + log("commit"); + } + + public void rollback() throws SQLException { + clearTime(); + + connection.rollback(); + + log("rollback"); + } + + public void close() throws SQLException { + clearTime(); + + connection.close(); + + log("close"); + } + + public PreparedStatement prepareStatement(String sql) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, autoGeneratedKeys); + } + + public PreparedStatement prepareStatement(String sql, int columnIndexes[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnIndexes); + } + + public PreparedStatement prepareStatement(String sql, String columnNames[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnNames); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public Statement createStatement() throws SQLException { + return connection.createStatement(); + } + + public CallableStatement prepareCall(String sql) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql); + } + + public String nativeSQL(String sql) throws SQLException { + lastSql = sql; + return connection.nativeSQL(sql); + } + + public void setAutoCommit(boolean autoCommit) throws SQLException { + connection.setAutoCommit(autoCommit); + } + + public boolean getAutoCommit() throws SQLException { + return connection.getAutoCommit(); + } + + public boolean isClosed() throws SQLException { + return connection.isClosed(); + } + + public DatabaseMetaData getMetaData() throws SQLException { + return connection.getMetaData(); + } + + public void setReadOnly(boolean readOnly) throws SQLException { + connection.setReadOnly(readOnly); + } + + public boolean isReadOnly() throws SQLException { + return connection.isReadOnly(); + } + + public void setCatalog(String catalog) throws SQLException { + connection.setCatalog(catalog); + } + + public String getCatalog() throws SQLException { + return connection.getCatalog(); + } + + public void setTransactionIsolation(int level) throws SQLException { + connection.setTransactionIsolation(level); + } + + public int getTransactionIsolation() throws SQLException { + return connection.getTransactionIsolation(); + } + + public SQLWarning getWarnings() throws SQLException { + return connection.getWarnings(); + } + + public void clearWarnings() throws SQLException { + connection.clearWarnings(); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency); + } + + public Map> getTypeMap() throws SQLException { + return connection.getTypeMap(); + } + + public void setTypeMap(Map> map) throws SQLException { + connection.setTypeMap(map); + } + + public void setHoldability(int holdability) throws SQLException { + connection.setHoldability(holdability); + } + + public int getHoldability() throws SQLException { + return connection.getHoldability(); + } + + public Savepoint setSavepoint() throws SQLException { + return connection.setSavepoint(); + } + + public Savepoint setSavepoint(String name) throws SQLException { + return connection.setSavepoint(name); + } + + public void rollback(Savepoint savepoint) throws SQLException { + connection.rollback(); + } + + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + connection.releaseSavepoint(savepoint); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public Clob createClob() throws SQLException { + return connection.createClob(); + } + + public Blob createBlob() throws SQLException { + return connection.createBlob(); + } + + public NClob createNClob() throws SQLException { + return connection.createNClob(); + } + + public SQLXML createSQLXML() throws SQLException { + return connection.createSQLXML(); + } + + public boolean isValid(int timeout) throws SQLException { + return connection.isValid(timeout); + } + + public void setClientInfo(String name, String value) throws SQLClientInfoException { + connection.setClientInfo(name, value); + } + + public void setClientInfo(Properties properties) throws SQLClientInfoException { + connection.setClientInfo(properties); + } + + public String getClientInfo(String name) throws SQLException { + return connection.getClientInfo(name); + } + + public Properties getClientInfo() throws SQLException { + return connection.getClientInfo(); + } + + public Array createArrayOf(String typeName, Object[] elements) throws SQLException { + return connection.createArrayOf(typeName, elements); + } + + public Struct createStruct(String typeName, Object[] attributes) throws SQLException { + return connection.createStruct(typeName, attributes); + } + + @Override + public void setSchema(String schema) throws SQLException { + connection.setSchema(schema); + } + + @Override + public String getSchema() throws SQLException { + return connection.getSchema(); + } + + @Override + public void abort(Executor executor) throws SQLException { + connection.abort(executor); + } + + @Override + public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { + connection.setNetworkTimeout(executor, milliseconds); + } + + @Override + public int getNetworkTimeout() throws SQLException { + return connection.getNetworkTimeout(); + } + + public T unwrap(Class iface) throws SQLException { + return connection.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return connection.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/Driver.java b/src/nl/astraeus/jdbc/Driver.java new file mode 100644 index 0000000..8317172 --- /dev/null +++ b/src/nl/astraeus/jdbc/Driver.java @@ -0,0 +1,116 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.http.SimpleWebServer; +import nl.astraeus.jdbc.web.JdbcStatisticsServlet; +import nl.astraeus.jdbc.web.ResourceServlet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.*; +import java.util.Enumeration; +import java.util.Properties; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:54:37 PM + */ +public class Driver implements java.sql.Driver { + private final static Logger log = LoggerFactory.getLogger(Driver.class); + + final private static String URL_PREFIX = "jdbc:stat:"; + + private java.sql.Driver driver = null; + private String[] drivers = { + "org.postgresql.Driver", + "oracle.jdbc.driver.OracleDriver", + "com.sybase.jdbc2.jdbc.SybDriver", + "net.sourceforge.jtds.jdbc.Driver", + "com.microsoft.jdbc.sqlserver.SQLServerDriver", + "com.microsoft.sqlserver.jdbc.SQLServerDriver", + "weblogic.jdbc.sqlserver.SQLServerDriver", + "com.informix.jdbc.IfxDriver", + "org.apache.derby.jdbc.ClientDriver", + "org.apache.derby.jdbc.EmbeddedDriver", + "com.mysql.jdbc.Driver", + "org.hsqldb.jdbcDriver", + "org.h2.Driver" }; + + static { + log.debug("Loading driver class " + Driver.class.getName()); + + try { + DriverManager.registerDriver(new Driver()); + } catch (SQLException e) { + log.error("", e); + } + } + + public Driver() { + for (String dr : drivers) { + try { + Class.forName(dr); + } catch (Throwable e) { + log.debug("Can't instantiate driver: " + dr, e); + } + } + } + + private java.sql.Driver findDriver(String url) throws SQLException { + Enumeration e = DriverManager.getDrivers(); + + while (e.hasMoreElements()) { + java.sql.Driver d = (java.sql.Driver) e.nextElement(); + + if (d.acceptsURL(url)) { + return d; + } + } + + throw new SQLException("Driver not found: " + url); + } + + public Connection connect(String url, Properties info) throws SQLException { + url = url.substring(URL_PREFIX.length()); + + if (driver == null) { + driver = findDriver(url); + } + + if (driver != null) { + SimpleWebServer server = new SimpleWebServer(18080); + + server.addServlet(new JdbcStatisticsServlet(), "/"); + server.addServlet(new ResourceServlet(), "/resources/*"); + + server.start(); + } + + return new ConnectionLogger(driver.connect(url, info)); + } + + public boolean acceptsURL(String url) throws SQLException { + return (url != null && url.startsWith(URL_PREFIX)); + } + + public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { + return driver.getPropertyInfo(url, info); + } + + public int getMajorVersion() { + return driver.getMajorVersion(); + } + + public int getMinorVersion() { + return driver.getMinorVersion(); + } + + public boolean jdbcCompliant() { + return driver.jdbcCompliant(); + } + + @Override + public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException { + return driver.getParentLogger(); + } +} diff --git a/src/nl/astraeus/jdbc/JdbcLogger.java b/src/nl/astraeus/jdbc/JdbcLogger.java new file mode 100644 index 0000000..f4bc125 --- /dev/null +++ b/src/nl/astraeus/jdbc/JdbcLogger.java @@ -0,0 +1,113 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.jdbc.util.Util; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/** + * User: riennentjes + * Date: Jul 12, 2008 + * Time: 9:15:21 AM + */ +public class JdbcLogger { + private final static Logger logger = LoggerFactory.getLogger(JdbcLogger.class); + + private final static JdbcLogger instance = new JdbcLogger(); + + public static JdbcLogger get() { + return instance; + } + + public final static class LogEntry { + public QueryType type; + public String sql; + public long milli; + public long nano; + public int count; + public int hash; + + public LogEntry(int hash, QueryType type, String sql, long milli, long nano) { + this.hash = hash; + this.type = type; + this.sql = sql; + this.milli = milli; + this.nano = nano; + this.count = 1; + } + + public void addCount(long milli, long nano) { + synchronized (this) { + count++; + this.milli += milli; + this.nano += nano; + } + } + + public int getCount() { + return count; + } + + public String getMilli() { + return Util.formatNano(milli*1000000/count); + } + + public String getNano() { + return Util.formatNano(nano/count); + } + + public String getTotal() { + return Util.formatNano(nano); + } + + public String getSql() { + return sql; + } + } + + private Map queries; + + public JdbcLogger() { + queries = new ConcurrentHashMap(); + } + + public void logEntry(QueryType type, String sql, long milli, long nano) { + int hash = sql.hashCode(); + LogEntry entry = queries.get(hash); + + if (entry == null) { + entry = new LogEntry(hash, type, sql, milli, nano); + queries.put(hash, entry); + } else { + entry.addCount(milli, nano); + } + + if (queries.size() > 1000) { + List toRemove = new LinkedList(); + List values = new LinkedList(queries.values()); + + Collections.sort(values, new Comparator() { + @Override + public int compare(LogEntry o1, LogEntry o2) { + return o1.count - o2.count; + } + }); + + while (queries.size() > 900) { + queries.remove(values.remove(0).hash); + + } + } + } + + public static void log(QueryType type, String sql, long milli, long nano) { + instance.logEntry(type, sql, milli, nano); + } + + public Collection getEntries() { + return queries.values(); + } + +} diff --git a/src/nl/astraeus/jdbc/PreparedStatementLogger.java b/src/nl/astraeus/jdbc/PreparedStatementLogger.java new file mode 100644 index 0000000..98aefc7 --- /dev/null +++ b/src/nl/astraeus/jdbc/PreparedStatementLogger.java @@ -0,0 +1,577 @@ +package nl.astraeus.jdbc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.InputStream; +import java.io.Reader; +import java.math.BigDecimal; +import java.net.URL; +import java.sql.*; +import java.util.Calendar; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 7:47:57 PM + */ +public class PreparedStatementLogger implements PreparedStatement { + private final static Logger log = LoggerFactory.getLogger(PreparedStatementLogger.class); + + private PreparedStatement statement; + + private String sql; + private QueryType type; + private long milli; + private long nano; + + //private ArrayList parameters; + + public PreparedStatementLogger(PreparedStatement statement) { + this.statement = statement; + this.sql = ""; + this.type = QueryType.UNKNOWN; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(QueryType type, String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(type, sql, m, n); + } + + public PreparedStatementLogger(Connection connection, String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql); + } + + public PreparedStatementLogger(Connection connection, String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatementLogger(Connection connection, String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, autoGeneratedKeys); + } + + public PreparedStatementLogger(Connection connection, String sql, int[] columnIndexes) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnIndexes); + } + + public PreparedStatementLogger(Connection connection, String sql, String[] columnNames) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnNames); + } + + public boolean execute() throws SQLException { + clearTime(); + + boolean result = statement.execute(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery() throws SQLException { + clearTime(); + + ResultSet result = statement.executeQuery(); + + log(type, sql); + + return result; + } + + public int executeUpdate() throws SQLException { + clearTime(); + + int result = statement.executeUpdate(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + ResultSet result = statement.executeQuery(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnNames); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnNames); + + log(type, sql); + + return result; + } + + + public void setNull(int parameterIndex, int sqlType) throws SQLException { + statement.setNull(parameterIndex, sqlType); + } + + public void setBoolean(int parameterIndex, boolean x) throws SQLException { + statement.setBoolean(parameterIndex, x); + } + + public void setByte(int parameterIndex, byte x) throws SQLException { + statement.setByte(parameterIndex, x); + } + + public void setShort(int parameterIndex, short x) throws SQLException { + statement.setShort(parameterIndex, x); + } + + public void setInt(int parameterIndex, int x) throws SQLException { + statement.setInt(parameterIndex, x); + } + + public void setLong(int parameterIndex, long x) throws SQLException { + statement.setLong(parameterIndex, x); + } + + public void setFloat(int parameterIndex, float x) throws SQLException { + statement.setFloat(parameterIndex, x); + } + + public void setDouble(int parameterIndex, double x) throws SQLException { + statement.setDouble(parameterIndex, x); + } + + public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { + statement.setBigDecimal(parameterIndex, x); + } + + public void setString(int parameterIndex, String x) throws SQLException { + statement.setString(parameterIndex, x); + } + + public void setBytes(int parameterIndex, byte x[]) throws SQLException { + statement.setBytes(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x) throws SQLException { + statement.setDate(parameterIndex, x); + } + + public void setTime(int parameterIndex, Time x) throws SQLException { + statement.setTime(parameterIndex, x); + } + + public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { + statement.setTimestamp(parameterIndex, x); + } + + public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setUnicodeStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType); + } + + public void setObject(int parameterIndex, Object x) throws SQLException { + statement.setObject(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setRef(int parameterIndex, Ref x) throws SQLException { + statement.setRef(parameterIndex, x); + } + + public void setBlob(int parameterIndex, Blob x) throws SQLException { + statement.setBlob(parameterIndex, x); + } + + public void setClob(int parameterIndex, Clob x) throws SQLException { + statement.setClob(parameterIndex, x); + } + + public void setArray(int parameterIndex, Array x) throws SQLException { + statement.setArray(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { + statement.setDate(parameterIndex, x, cal); + } + + public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { + statement.setTime(parameterIndex, x, cal); + } + + public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { + statement.setTimestamp(parameterIndex, x, cal); + } + + public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException { + statement.setNull(parameterIndex, sqlType, typeName); + } + + public void setURL(int parameterIndex, URL x) throws SQLException { + statement.setURL(parameterIndex, x); + } + + public void setRowId(int parameterIndex, RowId x) throws SQLException { + statement.setRowId(parameterIndex, x); + } + + public void setNString(int parameterIndex, String value) throws SQLException { + statement.setNString(parameterIndex, value); + } + + public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException { + statement.setNCharacterStream(parameterIndex, value, length); + } + + public void setNClob(int parameterIndex, NClob value) throws SQLException { + statement.setNClob(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setClob(parameterIndex, reader, length); + } + + public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException { + statement.setBlob(parameterIndex, inputStream, length); + } + + public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setNClob(parameterIndex, reader, length); + } + + public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException { + statement.setSQLXML(parameterIndex, xmlObject); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType, scaleOrLength); + } + + public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException { + statement.setAsciiStream(parameterIndex, x); + } + + public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException { + statement.setBinaryStream(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException { + statement.setCharacterStream(parameterIndex, reader); + } + + public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException { + statement.setNCharacterStream(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader) throws SQLException { + statement.setClob(parameterIndex, reader); + } + + public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException { + statement.setBlob(parameterIndex, inputStream); + } + + public void setNClob(int parameterIndex, Reader reader) throws SQLException { + statement.setNClob(parameterIndex, reader); + } + + + public void close() throws SQLException { + sql = ""; + type = QueryType.UNKNOWN; + milli = 0; + nano = 0; + + statement.close(); + } + + public ResultSetMetaData getMetaData() throws SQLException { + return statement.getMetaData(); + } + + public void clearParameters() throws SQLException { + statement.clearParameters(); + } + + public ParameterMetaData getParameterMetaData() throws SQLException { + return statement.getParameterMetaData(); + } + + public void addBatch() throws SQLException { + statement.addBatch(); + } + + public int getMaxFieldSize() throws SQLException { + return statement.getMaxFieldSize(); + } + + public void setMaxFieldSize(int max) throws SQLException { + statement.setMaxFieldSize(max); + } + + public int getMaxRows() throws SQLException { + return statement.getMaxRows(); + } + + public void setMaxRows(int max) throws SQLException { + statement.setMaxRows(max); + } + + public void setEscapeProcessing(boolean enable) throws SQLException { + statement.setEscapeProcessing(enable); + } + + public int getQueryTimeout() throws SQLException { + return statement.getQueryTimeout(); + } + + public void setQueryTimeout(int seconds) throws SQLException { + statement.setQueryTimeout(seconds); + } + + public void cancel() throws SQLException { + statement.cancel(); + } + + public SQLWarning getWarnings() throws SQLException { + return statement.getWarnings(); + } + + public void clearWarnings() throws SQLException { + statement.clearWarnings(); + } + + public void setCursorName(String name) throws SQLException { + statement.setCursorName(name); + } + + public boolean execute(String sql) throws SQLException { + return statement.execute(sql); + } + + public ResultSet getResultSet() throws SQLException { + return statement.getResultSet(); + } + + public int getUpdateCount() throws SQLException { + return statement.getUpdateCount(); + } + + public boolean getMoreResults() throws SQLException { + return statement.getMoreResults(); + } + + public void setFetchDirection(int direction) throws SQLException { + statement.setFetchDirection(direction); + } + + public int getFetchDirection() throws SQLException { + return statement.getFetchDirection(); + } + + public void setFetchSize(int rows) throws SQLException { + statement.setFetchSize(rows); + } + + public int getFetchSize() throws SQLException { + return statement.getFetchSize(); + } + + public int getResultSetConcurrency() throws SQLException { + return statement.getResultSetConcurrency(); + } + + public int getResultSetType() throws SQLException { + return statement.getResultSetType(); + } + + public void addBatch(String sql) throws SQLException { + statement.addBatch(sql); + } + + public void clearBatch() throws SQLException { + statement.clearBatch(); + } + + public int[] executeBatch() throws SQLException { + return statement.executeBatch(); + } + + public Connection getConnection() throws SQLException { + return statement.getConnection(); + } + + public boolean getMoreResults(int current) throws SQLException { + return statement.getMoreResults(current); + } + + public ResultSet getGeneratedKeys() throws SQLException { + return statement.getGeneratedKeys(); + } + + public int getResultSetHoldability() throws SQLException { + return statement.getResultSetHoldability(); + } + + public boolean isClosed() throws SQLException { + return statement.isClosed(); + } + + public void setPoolable(boolean poolable) throws SQLException { + statement.setPoolable(poolable); + } + + public boolean isPoolable() throws SQLException { + return statement.isPoolable(); + } + + @Override + public void closeOnCompletion() throws SQLException { + statement.closeOnCompletion();; + } + + @Override + public boolean isCloseOnCompletion() throws SQLException { + return statement.isCloseOnCompletion(); + } + + public T unwrap(Class iface) throws SQLException { + return statement.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return statement.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/QueryType.java b/src/nl/astraeus/jdbc/QueryType.java new file mode 100644 index 0000000..744fbfc --- /dev/null +++ b/src/nl/astraeus/jdbc/QueryType.java @@ -0,0 +1,24 @@ +package nl.astraeus.jdbc; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:32:49 PM + */ +public enum QueryType { + PLAIN("plain"), + PREPARED("prepared"), + CALLABLE("callable"), + UNKNOWN("unknown"); + + private String description; + + QueryType(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } + +} diff --git a/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java new file mode 100644 index 0000000..07aac40 --- /dev/null +++ b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java @@ -0,0 +1,68 @@ +package nl.astraeus.jdbc.example; + +import java.sql.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 7:32 PM + */ +public class JdbcStatisticsExample { + + + public static void main(String [] args) throws Exception { + Class.forName("org.h2.Driver"); + Class.forName("nl.astraeus.jdbc.Driver"); + + new JdbcStatisticsExample(); + } + + public JdbcStatisticsExample() throws Exception { + Connection conn = DriverManager.getConnection("jdbc:stat:jdbc:h2:mem:test"); + + Statement statement = null; + + statement = conn.createStatement(); + statement.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + + boolean running = true; + int count = 1; + PreparedStatement ps = null; + + while (running) { + Thread.sleep(10); + + String TableName = "TEST"+(System.nanoTime() % 1000); + + try { + ps = conn.prepareStatement("SELECT COUNT(*) FROM "+TableName); + ResultSet rs = ps.executeQuery(); + } catch (SQLException e) { + statement = conn.createStatement(); + statement.execute("CREATE TABLE "+TableName+" (ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + } finally { + if (ps!=null) { + ps.close(); + } + } + + ps = conn.prepareStatement("INSERT INTO "+TableName+" VALUES (?, ?)"); + + ps.setInt(1, count++); + ps.setString(2, "String "+System.currentTimeMillis()); + + ps.execute(); + ps.close(); + + Thread.sleep(10); + + ps = conn.prepareStatement("SELECT * FROM "+TableName); + ResultSet rs = ps.executeQuery(); + statement.close(); + } + + conn.close(); + } +} diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f403193 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..73ff239 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..3b00020 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..275077f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/README b/README deleted file mode 100644 index 734abaf..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -This file was created by IntelliJ IDEA 11.1.1 for binding GitHub repository \ No newline at end of file diff --git a/Simple-jdbc-statistics.iml b/Simple-jdbc-statistics.iml new file mode 100644 index 0000000..ca90a9b --- /dev/null +++ b/Simple-jdbc-statistics.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/lib/h2-1.3.166.jar b/lib/h2-1.3.166.jar new file mode 100644 index 0000000..4985063 --- /dev/null +++ b/lib/h2-1.3.166.jar Binary files differ diff --git a/lib/servlet-api-2.5.jar b/lib/servlet-api-2.5.jar new file mode 100644 index 0000000..20b5755 --- /dev/null +++ b/lib/servlet-api-2.5.jar Binary files differ diff --git a/lib/slf4j-api-1.6.4.jar b/lib/slf4j-api-1.6.4.jar new file mode 100644 index 0000000..4d23f41 --- /dev/null +++ b/lib/slf4j-api-1.6.4.jar Binary files differ diff --git a/lib/slf4j-simple-1.6.4.jar b/lib/slf4j-simple-1.6.4.jar new file mode 100644 index 0000000..3d1b8d9 --- /dev/null +++ b/lib/slf4j-simple-1.6.4.jar Binary files differ diff --git a/lib/ssr-0.1.jar b/lib/ssr-0.1.jar new file mode 100644 index 0000000..65dfcf4 --- /dev/null +++ b/lib/ssr-0.1.jar Binary files differ diff --git a/lib/vst-0.4.jar b/lib/vst-0.4.jar new file mode 100644 index 0000000..db63792 --- /dev/null +++ b/lib/vst-0.4.jar Binary files differ diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..ac2dbe1 --- /dev/null +++ b/readme.md @@ -0,0 +1 @@ +A simple wrapper around jdbc drivers what will show current jdbc stats of the running queries on a simple web page on port 18080. \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/ConnectionLogger.java b/src/nl/astraeus/jdbc/ConnectionLogger.java new file mode 100644 index 0000000..c3e243f --- /dev/null +++ b/src/nl/astraeus/jdbc/ConnectionLogger.java @@ -0,0 +1,279 @@ +package nl.astraeus.jdbc; + +import java.sql.*; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Executor; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:12:34 PM + */ +public class ConnectionLogger implements Connection { + private Connection connection; + + private long milli; + private long nano; + private String lastSql; + + public ConnectionLogger(Connection connection) { + this.connection = connection; + this.lastSql = ""; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(QueryType.UNKNOWN, sql, m, n); + } + + public void commit() throws SQLException { + clearTime(); + + connection.commit(); + + log("commit"); + } + + public void rollback() throws SQLException { + clearTime(); + + connection.rollback(); + + log("rollback"); + } + + public void close() throws SQLException { + clearTime(); + + connection.close(); + + log("close"); + } + + public PreparedStatement prepareStatement(String sql) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, autoGeneratedKeys); + } + + public PreparedStatement prepareStatement(String sql, int columnIndexes[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnIndexes); + } + + public PreparedStatement prepareStatement(String sql, String columnNames[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnNames); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public Statement createStatement() throws SQLException { + return connection.createStatement(); + } + + public CallableStatement prepareCall(String sql) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql); + } + + public String nativeSQL(String sql) throws SQLException { + lastSql = sql; + return connection.nativeSQL(sql); + } + + public void setAutoCommit(boolean autoCommit) throws SQLException { + connection.setAutoCommit(autoCommit); + } + + public boolean getAutoCommit() throws SQLException { + return connection.getAutoCommit(); + } + + public boolean isClosed() throws SQLException { + return connection.isClosed(); + } + + public DatabaseMetaData getMetaData() throws SQLException { + return connection.getMetaData(); + } + + public void setReadOnly(boolean readOnly) throws SQLException { + connection.setReadOnly(readOnly); + } + + public boolean isReadOnly() throws SQLException { + return connection.isReadOnly(); + } + + public void setCatalog(String catalog) throws SQLException { + connection.setCatalog(catalog); + } + + public String getCatalog() throws SQLException { + return connection.getCatalog(); + } + + public void setTransactionIsolation(int level) throws SQLException { + connection.setTransactionIsolation(level); + } + + public int getTransactionIsolation() throws SQLException { + return connection.getTransactionIsolation(); + } + + public SQLWarning getWarnings() throws SQLException { + return connection.getWarnings(); + } + + public void clearWarnings() throws SQLException { + connection.clearWarnings(); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency); + } + + public Map> getTypeMap() throws SQLException { + return connection.getTypeMap(); + } + + public void setTypeMap(Map> map) throws SQLException { + connection.setTypeMap(map); + } + + public void setHoldability(int holdability) throws SQLException { + connection.setHoldability(holdability); + } + + public int getHoldability() throws SQLException { + return connection.getHoldability(); + } + + public Savepoint setSavepoint() throws SQLException { + return connection.setSavepoint(); + } + + public Savepoint setSavepoint(String name) throws SQLException { + return connection.setSavepoint(name); + } + + public void rollback(Savepoint savepoint) throws SQLException { + connection.rollback(); + } + + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + connection.releaseSavepoint(savepoint); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public Clob createClob() throws SQLException { + return connection.createClob(); + } + + public Blob createBlob() throws SQLException { + return connection.createBlob(); + } + + public NClob createNClob() throws SQLException { + return connection.createNClob(); + } + + public SQLXML createSQLXML() throws SQLException { + return connection.createSQLXML(); + } + + public boolean isValid(int timeout) throws SQLException { + return connection.isValid(timeout); + } + + public void setClientInfo(String name, String value) throws SQLClientInfoException { + connection.setClientInfo(name, value); + } + + public void setClientInfo(Properties properties) throws SQLClientInfoException { + connection.setClientInfo(properties); + } + + public String getClientInfo(String name) throws SQLException { + return connection.getClientInfo(name); + } + + public Properties getClientInfo() throws SQLException { + return connection.getClientInfo(); + } + + public Array createArrayOf(String typeName, Object[] elements) throws SQLException { + return connection.createArrayOf(typeName, elements); + } + + public Struct createStruct(String typeName, Object[] attributes) throws SQLException { + return connection.createStruct(typeName, attributes); + } + + @Override + public void setSchema(String schema) throws SQLException { + connection.setSchema(schema); + } + + @Override + public String getSchema() throws SQLException { + return connection.getSchema(); + } + + @Override + public void abort(Executor executor) throws SQLException { + connection.abort(executor); + } + + @Override + public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { + connection.setNetworkTimeout(executor, milliseconds); + } + + @Override + public int getNetworkTimeout() throws SQLException { + return connection.getNetworkTimeout(); + } + + public T unwrap(Class iface) throws SQLException { + return connection.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return connection.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/Driver.java b/src/nl/astraeus/jdbc/Driver.java new file mode 100644 index 0000000..8317172 --- /dev/null +++ b/src/nl/astraeus/jdbc/Driver.java @@ -0,0 +1,116 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.http.SimpleWebServer; +import nl.astraeus.jdbc.web.JdbcStatisticsServlet; +import nl.astraeus.jdbc.web.ResourceServlet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.*; +import java.util.Enumeration; +import java.util.Properties; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:54:37 PM + */ +public class Driver implements java.sql.Driver { + private final static Logger log = LoggerFactory.getLogger(Driver.class); + + final private static String URL_PREFIX = "jdbc:stat:"; + + private java.sql.Driver driver = null; + private String[] drivers = { + "org.postgresql.Driver", + "oracle.jdbc.driver.OracleDriver", + "com.sybase.jdbc2.jdbc.SybDriver", + "net.sourceforge.jtds.jdbc.Driver", + "com.microsoft.jdbc.sqlserver.SQLServerDriver", + "com.microsoft.sqlserver.jdbc.SQLServerDriver", + "weblogic.jdbc.sqlserver.SQLServerDriver", + "com.informix.jdbc.IfxDriver", + "org.apache.derby.jdbc.ClientDriver", + "org.apache.derby.jdbc.EmbeddedDriver", + "com.mysql.jdbc.Driver", + "org.hsqldb.jdbcDriver", + "org.h2.Driver" }; + + static { + log.debug("Loading driver class " + Driver.class.getName()); + + try { + DriverManager.registerDriver(new Driver()); + } catch (SQLException e) { + log.error("", e); + } + } + + public Driver() { + for (String dr : drivers) { + try { + Class.forName(dr); + } catch (Throwable e) { + log.debug("Can't instantiate driver: " + dr, e); + } + } + } + + private java.sql.Driver findDriver(String url) throws SQLException { + Enumeration e = DriverManager.getDrivers(); + + while (e.hasMoreElements()) { + java.sql.Driver d = (java.sql.Driver) e.nextElement(); + + if (d.acceptsURL(url)) { + return d; + } + } + + throw new SQLException("Driver not found: " + url); + } + + public Connection connect(String url, Properties info) throws SQLException { + url = url.substring(URL_PREFIX.length()); + + if (driver == null) { + driver = findDriver(url); + } + + if (driver != null) { + SimpleWebServer server = new SimpleWebServer(18080); + + server.addServlet(new JdbcStatisticsServlet(), "/"); + server.addServlet(new ResourceServlet(), "/resources/*"); + + server.start(); + } + + return new ConnectionLogger(driver.connect(url, info)); + } + + public boolean acceptsURL(String url) throws SQLException { + return (url != null && url.startsWith(URL_PREFIX)); + } + + public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { + return driver.getPropertyInfo(url, info); + } + + public int getMajorVersion() { + return driver.getMajorVersion(); + } + + public int getMinorVersion() { + return driver.getMinorVersion(); + } + + public boolean jdbcCompliant() { + return driver.jdbcCompliant(); + } + + @Override + public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException { + return driver.getParentLogger(); + } +} diff --git a/src/nl/astraeus/jdbc/JdbcLogger.java b/src/nl/astraeus/jdbc/JdbcLogger.java new file mode 100644 index 0000000..f4bc125 --- /dev/null +++ b/src/nl/astraeus/jdbc/JdbcLogger.java @@ -0,0 +1,113 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.jdbc.util.Util; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/** + * User: riennentjes + * Date: Jul 12, 2008 + * Time: 9:15:21 AM + */ +public class JdbcLogger { + private final static Logger logger = LoggerFactory.getLogger(JdbcLogger.class); + + private final static JdbcLogger instance = new JdbcLogger(); + + public static JdbcLogger get() { + return instance; + } + + public final static class LogEntry { + public QueryType type; + public String sql; + public long milli; + public long nano; + public int count; + public int hash; + + public LogEntry(int hash, QueryType type, String sql, long milli, long nano) { + this.hash = hash; + this.type = type; + this.sql = sql; + this.milli = milli; + this.nano = nano; + this.count = 1; + } + + public void addCount(long milli, long nano) { + synchronized (this) { + count++; + this.milli += milli; + this.nano += nano; + } + } + + public int getCount() { + return count; + } + + public String getMilli() { + return Util.formatNano(milli*1000000/count); + } + + public String getNano() { + return Util.formatNano(nano/count); + } + + public String getTotal() { + return Util.formatNano(nano); + } + + public String getSql() { + return sql; + } + } + + private Map queries; + + public JdbcLogger() { + queries = new ConcurrentHashMap(); + } + + public void logEntry(QueryType type, String sql, long milli, long nano) { + int hash = sql.hashCode(); + LogEntry entry = queries.get(hash); + + if (entry == null) { + entry = new LogEntry(hash, type, sql, milli, nano); + queries.put(hash, entry); + } else { + entry.addCount(milli, nano); + } + + if (queries.size() > 1000) { + List toRemove = new LinkedList(); + List values = new LinkedList(queries.values()); + + Collections.sort(values, new Comparator() { + @Override + public int compare(LogEntry o1, LogEntry o2) { + return o1.count - o2.count; + } + }); + + while (queries.size() > 900) { + queries.remove(values.remove(0).hash); + + } + } + } + + public static void log(QueryType type, String sql, long milli, long nano) { + instance.logEntry(type, sql, milli, nano); + } + + public Collection getEntries() { + return queries.values(); + } + +} diff --git a/src/nl/astraeus/jdbc/PreparedStatementLogger.java b/src/nl/astraeus/jdbc/PreparedStatementLogger.java new file mode 100644 index 0000000..98aefc7 --- /dev/null +++ b/src/nl/astraeus/jdbc/PreparedStatementLogger.java @@ -0,0 +1,577 @@ +package nl.astraeus.jdbc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.InputStream; +import java.io.Reader; +import java.math.BigDecimal; +import java.net.URL; +import java.sql.*; +import java.util.Calendar; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 7:47:57 PM + */ +public class PreparedStatementLogger implements PreparedStatement { + private final static Logger log = LoggerFactory.getLogger(PreparedStatementLogger.class); + + private PreparedStatement statement; + + private String sql; + private QueryType type; + private long milli; + private long nano; + + //private ArrayList parameters; + + public PreparedStatementLogger(PreparedStatement statement) { + this.statement = statement; + this.sql = ""; + this.type = QueryType.UNKNOWN; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(QueryType type, String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(type, sql, m, n); + } + + public PreparedStatementLogger(Connection connection, String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql); + } + + public PreparedStatementLogger(Connection connection, String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatementLogger(Connection connection, String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, autoGeneratedKeys); + } + + public PreparedStatementLogger(Connection connection, String sql, int[] columnIndexes) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnIndexes); + } + + public PreparedStatementLogger(Connection connection, String sql, String[] columnNames) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnNames); + } + + public boolean execute() throws SQLException { + clearTime(); + + boolean result = statement.execute(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery() throws SQLException { + clearTime(); + + ResultSet result = statement.executeQuery(); + + log(type, sql); + + return result; + } + + public int executeUpdate() throws SQLException { + clearTime(); + + int result = statement.executeUpdate(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + ResultSet result = statement.executeQuery(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnNames); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnNames); + + log(type, sql); + + return result; + } + + + public void setNull(int parameterIndex, int sqlType) throws SQLException { + statement.setNull(parameterIndex, sqlType); + } + + public void setBoolean(int parameterIndex, boolean x) throws SQLException { + statement.setBoolean(parameterIndex, x); + } + + public void setByte(int parameterIndex, byte x) throws SQLException { + statement.setByte(parameterIndex, x); + } + + public void setShort(int parameterIndex, short x) throws SQLException { + statement.setShort(parameterIndex, x); + } + + public void setInt(int parameterIndex, int x) throws SQLException { + statement.setInt(parameterIndex, x); + } + + public void setLong(int parameterIndex, long x) throws SQLException { + statement.setLong(parameterIndex, x); + } + + public void setFloat(int parameterIndex, float x) throws SQLException { + statement.setFloat(parameterIndex, x); + } + + public void setDouble(int parameterIndex, double x) throws SQLException { + statement.setDouble(parameterIndex, x); + } + + public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { + statement.setBigDecimal(parameterIndex, x); + } + + public void setString(int parameterIndex, String x) throws SQLException { + statement.setString(parameterIndex, x); + } + + public void setBytes(int parameterIndex, byte x[]) throws SQLException { + statement.setBytes(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x) throws SQLException { + statement.setDate(parameterIndex, x); + } + + public void setTime(int parameterIndex, Time x) throws SQLException { + statement.setTime(parameterIndex, x); + } + + public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { + statement.setTimestamp(parameterIndex, x); + } + + public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setUnicodeStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType); + } + + public void setObject(int parameterIndex, Object x) throws SQLException { + statement.setObject(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setRef(int parameterIndex, Ref x) throws SQLException { + statement.setRef(parameterIndex, x); + } + + public void setBlob(int parameterIndex, Blob x) throws SQLException { + statement.setBlob(parameterIndex, x); + } + + public void setClob(int parameterIndex, Clob x) throws SQLException { + statement.setClob(parameterIndex, x); + } + + public void setArray(int parameterIndex, Array x) throws SQLException { + statement.setArray(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { + statement.setDate(parameterIndex, x, cal); + } + + public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { + statement.setTime(parameterIndex, x, cal); + } + + public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { + statement.setTimestamp(parameterIndex, x, cal); + } + + public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException { + statement.setNull(parameterIndex, sqlType, typeName); + } + + public void setURL(int parameterIndex, URL x) throws SQLException { + statement.setURL(parameterIndex, x); + } + + public void setRowId(int parameterIndex, RowId x) throws SQLException { + statement.setRowId(parameterIndex, x); + } + + public void setNString(int parameterIndex, String value) throws SQLException { + statement.setNString(parameterIndex, value); + } + + public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException { + statement.setNCharacterStream(parameterIndex, value, length); + } + + public void setNClob(int parameterIndex, NClob value) throws SQLException { + statement.setNClob(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setClob(parameterIndex, reader, length); + } + + public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException { + statement.setBlob(parameterIndex, inputStream, length); + } + + public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setNClob(parameterIndex, reader, length); + } + + public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException { + statement.setSQLXML(parameterIndex, xmlObject); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType, scaleOrLength); + } + + public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException { + statement.setAsciiStream(parameterIndex, x); + } + + public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException { + statement.setBinaryStream(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException { + statement.setCharacterStream(parameterIndex, reader); + } + + public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException { + statement.setNCharacterStream(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader) throws SQLException { + statement.setClob(parameterIndex, reader); + } + + public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException { + statement.setBlob(parameterIndex, inputStream); + } + + public void setNClob(int parameterIndex, Reader reader) throws SQLException { + statement.setNClob(parameterIndex, reader); + } + + + public void close() throws SQLException { + sql = ""; + type = QueryType.UNKNOWN; + milli = 0; + nano = 0; + + statement.close(); + } + + public ResultSetMetaData getMetaData() throws SQLException { + return statement.getMetaData(); + } + + public void clearParameters() throws SQLException { + statement.clearParameters(); + } + + public ParameterMetaData getParameterMetaData() throws SQLException { + return statement.getParameterMetaData(); + } + + public void addBatch() throws SQLException { + statement.addBatch(); + } + + public int getMaxFieldSize() throws SQLException { + return statement.getMaxFieldSize(); + } + + public void setMaxFieldSize(int max) throws SQLException { + statement.setMaxFieldSize(max); + } + + public int getMaxRows() throws SQLException { + return statement.getMaxRows(); + } + + public void setMaxRows(int max) throws SQLException { + statement.setMaxRows(max); + } + + public void setEscapeProcessing(boolean enable) throws SQLException { + statement.setEscapeProcessing(enable); + } + + public int getQueryTimeout() throws SQLException { + return statement.getQueryTimeout(); + } + + public void setQueryTimeout(int seconds) throws SQLException { + statement.setQueryTimeout(seconds); + } + + public void cancel() throws SQLException { + statement.cancel(); + } + + public SQLWarning getWarnings() throws SQLException { + return statement.getWarnings(); + } + + public void clearWarnings() throws SQLException { + statement.clearWarnings(); + } + + public void setCursorName(String name) throws SQLException { + statement.setCursorName(name); + } + + public boolean execute(String sql) throws SQLException { + return statement.execute(sql); + } + + public ResultSet getResultSet() throws SQLException { + return statement.getResultSet(); + } + + public int getUpdateCount() throws SQLException { + return statement.getUpdateCount(); + } + + public boolean getMoreResults() throws SQLException { + return statement.getMoreResults(); + } + + public void setFetchDirection(int direction) throws SQLException { + statement.setFetchDirection(direction); + } + + public int getFetchDirection() throws SQLException { + return statement.getFetchDirection(); + } + + public void setFetchSize(int rows) throws SQLException { + statement.setFetchSize(rows); + } + + public int getFetchSize() throws SQLException { + return statement.getFetchSize(); + } + + public int getResultSetConcurrency() throws SQLException { + return statement.getResultSetConcurrency(); + } + + public int getResultSetType() throws SQLException { + return statement.getResultSetType(); + } + + public void addBatch(String sql) throws SQLException { + statement.addBatch(sql); + } + + public void clearBatch() throws SQLException { + statement.clearBatch(); + } + + public int[] executeBatch() throws SQLException { + return statement.executeBatch(); + } + + public Connection getConnection() throws SQLException { + return statement.getConnection(); + } + + public boolean getMoreResults(int current) throws SQLException { + return statement.getMoreResults(current); + } + + public ResultSet getGeneratedKeys() throws SQLException { + return statement.getGeneratedKeys(); + } + + public int getResultSetHoldability() throws SQLException { + return statement.getResultSetHoldability(); + } + + public boolean isClosed() throws SQLException { + return statement.isClosed(); + } + + public void setPoolable(boolean poolable) throws SQLException { + statement.setPoolable(poolable); + } + + public boolean isPoolable() throws SQLException { + return statement.isPoolable(); + } + + @Override + public void closeOnCompletion() throws SQLException { + statement.closeOnCompletion();; + } + + @Override + public boolean isCloseOnCompletion() throws SQLException { + return statement.isCloseOnCompletion(); + } + + public T unwrap(Class iface) throws SQLException { + return statement.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return statement.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/QueryType.java b/src/nl/astraeus/jdbc/QueryType.java new file mode 100644 index 0000000..744fbfc --- /dev/null +++ b/src/nl/astraeus/jdbc/QueryType.java @@ -0,0 +1,24 @@ +package nl.astraeus.jdbc; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:32:49 PM + */ +public enum QueryType { + PLAIN("plain"), + PREPARED("prepared"), + CALLABLE("callable"), + UNKNOWN("unknown"); + + private String description; + + QueryType(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } + +} diff --git a/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java new file mode 100644 index 0000000..07aac40 --- /dev/null +++ b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java @@ -0,0 +1,68 @@ +package nl.astraeus.jdbc.example; + +import java.sql.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 7:32 PM + */ +public class JdbcStatisticsExample { + + + public static void main(String [] args) throws Exception { + Class.forName("org.h2.Driver"); + Class.forName("nl.astraeus.jdbc.Driver"); + + new JdbcStatisticsExample(); + } + + public JdbcStatisticsExample() throws Exception { + Connection conn = DriverManager.getConnection("jdbc:stat:jdbc:h2:mem:test"); + + Statement statement = null; + + statement = conn.createStatement(); + statement.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + + boolean running = true; + int count = 1; + PreparedStatement ps = null; + + while (running) { + Thread.sleep(10); + + String TableName = "TEST"+(System.nanoTime() % 1000); + + try { + ps = conn.prepareStatement("SELECT COUNT(*) FROM "+TableName); + ResultSet rs = ps.executeQuery(); + } catch (SQLException e) { + statement = conn.createStatement(); + statement.execute("CREATE TABLE "+TableName+" (ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + } finally { + if (ps!=null) { + ps.close(); + } + } + + ps = conn.prepareStatement("INSERT INTO "+TableName+" VALUES (?, ?)"); + + ps.setInt(1, count++); + ps.setString(2, "String "+System.currentTimeMillis()); + + ps.execute(); + ps.close(); + + Thread.sleep(10); + + ps = conn.prepareStatement("SELECT * FROM "+TableName); + ResultSet rs = ps.executeQuery(); + statement.close(); + } + + conn.close(); + } +} diff --git a/src/nl/astraeus/jdbc/util/IOUtils.java b/src/nl/astraeus/jdbc/util/IOUtils.java new file mode 100644 index 0000000..ce95d9d --- /dev/null +++ b/src/nl/astraeus/jdbc/util/IOUtils.java @@ -0,0 +1,38 @@ +package nl.astraeus.jdbc.util; + +import java.io.*; + +/** + * User: rnentjes + * Date: 4/9/12 + * Time: 2:33 PM + */ +public class IOUtils { + + public static String toString(InputStream in) throws IOException { + assert in != null; + + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + StringBuilder buffer = new StringBuilder(); + + while(reader.ready()) { + buffer.append(reader.readLine()); + buffer.append("\n"); + } + + return buffer.toString(); + } finally { + in.close(); + } + } + + public static void copy(InputStream in, OutputStream out) throws IOException { + byte [] buffer = new byte[1<<16]; + int bytes; + + while((bytes = in.read(buffer)) > 0) { + out.write(buffer, 0, bytes); + } + } +} diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f403193 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..73ff239 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..3b00020 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..275077f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/README b/README deleted file mode 100644 index 734abaf..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -This file was created by IntelliJ IDEA 11.1.1 for binding GitHub repository \ No newline at end of file diff --git a/Simple-jdbc-statistics.iml b/Simple-jdbc-statistics.iml new file mode 100644 index 0000000..ca90a9b --- /dev/null +++ b/Simple-jdbc-statistics.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/lib/h2-1.3.166.jar b/lib/h2-1.3.166.jar new file mode 100644 index 0000000..4985063 --- /dev/null +++ b/lib/h2-1.3.166.jar Binary files differ diff --git a/lib/servlet-api-2.5.jar b/lib/servlet-api-2.5.jar new file mode 100644 index 0000000..20b5755 --- /dev/null +++ b/lib/servlet-api-2.5.jar Binary files differ diff --git a/lib/slf4j-api-1.6.4.jar b/lib/slf4j-api-1.6.4.jar new file mode 100644 index 0000000..4d23f41 --- /dev/null +++ b/lib/slf4j-api-1.6.4.jar Binary files differ diff --git a/lib/slf4j-simple-1.6.4.jar b/lib/slf4j-simple-1.6.4.jar new file mode 100644 index 0000000..3d1b8d9 --- /dev/null +++ b/lib/slf4j-simple-1.6.4.jar Binary files differ diff --git a/lib/ssr-0.1.jar b/lib/ssr-0.1.jar new file mode 100644 index 0000000..65dfcf4 --- /dev/null +++ b/lib/ssr-0.1.jar Binary files differ diff --git a/lib/vst-0.4.jar b/lib/vst-0.4.jar new file mode 100644 index 0000000..db63792 --- /dev/null +++ b/lib/vst-0.4.jar Binary files differ diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..ac2dbe1 --- /dev/null +++ b/readme.md @@ -0,0 +1 @@ +A simple wrapper around jdbc drivers what will show current jdbc stats of the running queries on a simple web page on port 18080. \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/ConnectionLogger.java b/src/nl/astraeus/jdbc/ConnectionLogger.java new file mode 100644 index 0000000..c3e243f --- /dev/null +++ b/src/nl/astraeus/jdbc/ConnectionLogger.java @@ -0,0 +1,279 @@ +package nl.astraeus.jdbc; + +import java.sql.*; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Executor; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:12:34 PM + */ +public class ConnectionLogger implements Connection { + private Connection connection; + + private long milli; + private long nano; + private String lastSql; + + public ConnectionLogger(Connection connection) { + this.connection = connection; + this.lastSql = ""; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(QueryType.UNKNOWN, sql, m, n); + } + + public void commit() throws SQLException { + clearTime(); + + connection.commit(); + + log("commit"); + } + + public void rollback() throws SQLException { + clearTime(); + + connection.rollback(); + + log("rollback"); + } + + public void close() throws SQLException { + clearTime(); + + connection.close(); + + log("close"); + } + + public PreparedStatement prepareStatement(String sql) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, autoGeneratedKeys); + } + + public PreparedStatement prepareStatement(String sql, int columnIndexes[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnIndexes); + } + + public PreparedStatement prepareStatement(String sql, String columnNames[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnNames); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public Statement createStatement() throws SQLException { + return connection.createStatement(); + } + + public CallableStatement prepareCall(String sql) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql); + } + + public String nativeSQL(String sql) throws SQLException { + lastSql = sql; + return connection.nativeSQL(sql); + } + + public void setAutoCommit(boolean autoCommit) throws SQLException { + connection.setAutoCommit(autoCommit); + } + + public boolean getAutoCommit() throws SQLException { + return connection.getAutoCommit(); + } + + public boolean isClosed() throws SQLException { + return connection.isClosed(); + } + + public DatabaseMetaData getMetaData() throws SQLException { + return connection.getMetaData(); + } + + public void setReadOnly(boolean readOnly) throws SQLException { + connection.setReadOnly(readOnly); + } + + public boolean isReadOnly() throws SQLException { + return connection.isReadOnly(); + } + + public void setCatalog(String catalog) throws SQLException { + connection.setCatalog(catalog); + } + + public String getCatalog() throws SQLException { + return connection.getCatalog(); + } + + public void setTransactionIsolation(int level) throws SQLException { + connection.setTransactionIsolation(level); + } + + public int getTransactionIsolation() throws SQLException { + return connection.getTransactionIsolation(); + } + + public SQLWarning getWarnings() throws SQLException { + return connection.getWarnings(); + } + + public void clearWarnings() throws SQLException { + connection.clearWarnings(); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency); + } + + public Map> getTypeMap() throws SQLException { + return connection.getTypeMap(); + } + + public void setTypeMap(Map> map) throws SQLException { + connection.setTypeMap(map); + } + + public void setHoldability(int holdability) throws SQLException { + connection.setHoldability(holdability); + } + + public int getHoldability() throws SQLException { + return connection.getHoldability(); + } + + public Savepoint setSavepoint() throws SQLException { + return connection.setSavepoint(); + } + + public Savepoint setSavepoint(String name) throws SQLException { + return connection.setSavepoint(name); + } + + public void rollback(Savepoint savepoint) throws SQLException { + connection.rollback(); + } + + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + connection.releaseSavepoint(savepoint); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public Clob createClob() throws SQLException { + return connection.createClob(); + } + + public Blob createBlob() throws SQLException { + return connection.createBlob(); + } + + public NClob createNClob() throws SQLException { + return connection.createNClob(); + } + + public SQLXML createSQLXML() throws SQLException { + return connection.createSQLXML(); + } + + public boolean isValid(int timeout) throws SQLException { + return connection.isValid(timeout); + } + + public void setClientInfo(String name, String value) throws SQLClientInfoException { + connection.setClientInfo(name, value); + } + + public void setClientInfo(Properties properties) throws SQLClientInfoException { + connection.setClientInfo(properties); + } + + public String getClientInfo(String name) throws SQLException { + return connection.getClientInfo(name); + } + + public Properties getClientInfo() throws SQLException { + return connection.getClientInfo(); + } + + public Array createArrayOf(String typeName, Object[] elements) throws SQLException { + return connection.createArrayOf(typeName, elements); + } + + public Struct createStruct(String typeName, Object[] attributes) throws SQLException { + return connection.createStruct(typeName, attributes); + } + + @Override + public void setSchema(String schema) throws SQLException { + connection.setSchema(schema); + } + + @Override + public String getSchema() throws SQLException { + return connection.getSchema(); + } + + @Override + public void abort(Executor executor) throws SQLException { + connection.abort(executor); + } + + @Override + public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { + connection.setNetworkTimeout(executor, milliseconds); + } + + @Override + public int getNetworkTimeout() throws SQLException { + return connection.getNetworkTimeout(); + } + + public T unwrap(Class iface) throws SQLException { + return connection.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return connection.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/Driver.java b/src/nl/astraeus/jdbc/Driver.java new file mode 100644 index 0000000..8317172 --- /dev/null +++ b/src/nl/astraeus/jdbc/Driver.java @@ -0,0 +1,116 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.http.SimpleWebServer; +import nl.astraeus.jdbc.web.JdbcStatisticsServlet; +import nl.astraeus.jdbc.web.ResourceServlet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.*; +import java.util.Enumeration; +import java.util.Properties; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:54:37 PM + */ +public class Driver implements java.sql.Driver { + private final static Logger log = LoggerFactory.getLogger(Driver.class); + + final private static String URL_PREFIX = "jdbc:stat:"; + + private java.sql.Driver driver = null; + private String[] drivers = { + "org.postgresql.Driver", + "oracle.jdbc.driver.OracleDriver", + "com.sybase.jdbc2.jdbc.SybDriver", + "net.sourceforge.jtds.jdbc.Driver", + "com.microsoft.jdbc.sqlserver.SQLServerDriver", + "com.microsoft.sqlserver.jdbc.SQLServerDriver", + "weblogic.jdbc.sqlserver.SQLServerDriver", + "com.informix.jdbc.IfxDriver", + "org.apache.derby.jdbc.ClientDriver", + "org.apache.derby.jdbc.EmbeddedDriver", + "com.mysql.jdbc.Driver", + "org.hsqldb.jdbcDriver", + "org.h2.Driver" }; + + static { + log.debug("Loading driver class " + Driver.class.getName()); + + try { + DriverManager.registerDriver(new Driver()); + } catch (SQLException e) { + log.error("", e); + } + } + + public Driver() { + for (String dr : drivers) { + try { + Class.forName(dr); + } catch (Throwable e) { + log.debug("Can't instantiate driver: " + dr, e); + } + } + } + + private java.sql.Driver findDriver(String url) throws SQLException { + Enumeration e = DriverManager.getDrivers(); + + while (e.hasMoreElements()) { + java.sql.Driver d = (java.sql.Driver) e.nextElement(); + + if (d.acceptsURL(url)) { + return d; + } + } + + throw new SQLException("Driver not found: " + url); + } + + public Connection connect(String url, Properties info) throws SQLException { + url = url.substring(URL_PREFIX.length()); + + if (driver == null) { + driver = findDriver(url); + } + + if (driver != null) { + SimpleWebServer server = new SimpleWebServer(18080); + + server.addServlet(new JdbcStatisticsServlet(), "/"); + server.addServlet(new ResourceServlet(), "/resources/*"); + + server.start(); + } + + return new ConnectionLogger(driver.connect(url, info)); + } + + public boolean acceptsURL(String url) throws SQLException { + return (url != null && url.startsWith(URL_PREFIX)); + } + + public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { + return driver.getPropertyInfo(url, info); + } + + public int getMajorVersion() { + return driver.getMajorVersion(); + } + + public int getMinorVersion() { + return driver.getMinorVersion(); + } + + public boolean jdbcCompliant() { + return driver.jdbcCompliant(); + } + + @Override + public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException { + return driver.getParentLogger(); + } +} diff --git a/src/nl/astraeus/jdbc/JdbcLogger.java b/src/nl/astraeus/jdbc/JdbcLogger.java new file mode 100644 index 0000000..f4bc125 --- /dev/null +++ b/src/nl/astraeus/jdbc/JdbcLogger.java @@ -0,0 +1,113 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.jdbc.util.Util; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/** + * User: riennentjes + * Date: Jul 12, 2008 + * Time: 9:15:21 AM + */ +public class JdbcLogger { + private final static Logger logger = LoggerFactory.getLogger(JdbcLogger.class); + + private final static JdbcLogger instance = new JdbcLogger(); + + public static JdbcLogger get() { + return instance; + } + + public final static class LogEntry { + public QueryType type; + public String sql; + public long milli; + public long nano; + public int count; + public int hash; + + public LogEntry(int hash, QueryType type, String sql, long milli, long nano) { + this.hash = hash; + this.type = type; + this.sql = sql; + this.milli = milli; + this.nano = nano; + this.count = 1; + } + + public void addCount(long milli, long nano) { + synchronized (this) { + count++; + this.milli += milli; + this.nano += nano; + } + } + + public int getCount() { + return count; + } + + public String getMilli() { + return Util.formatNano(milli*1000000/count); + } + + public String getNano() { + return Util.formatNano(nano/count); + } + + public String getTotal() { + return Util.formatNano(nano); + } + + public String getSql() { + return sql; + } + } + + private Map queries; + + public JdbcLogger() { + queries = new ConcurrentHashMap(); + } + + public void logEntry(QueryType type, String sql, long milli, long nano) { + int hash = sql.hashCode(); + LogEntry entry = queries.get(hash); + + if (entry == null) { + entry = new LogEntry(hash, type, sql, milli, nano); + queries.put(hash, entry); + } else { + entry.addCount(milli, nano); + } + + if (queries.size() > 1000) { + List toRemove = new LinkedList(); + List values = new LinkedList(queries.values()); + + Collections.sort(values, new Comparator() { + @Override + public int compare(LogEntry o1, LogEntry o2) { + return o1.count - o2.count; + } + }); + + while (queries.size() > 900) { + queries.remove(values.remove(0).hash); + + } + } + } + + public static void log(QueryType type, String sql, long milli, long nano) { + instance.logEntry(type, sql, milli, nano); + } + + public Collection getEntries() { + return queries.values(); + } + +} diff --git a/src/nl/astraeus/jdbc/PreparedStatementLogger.java b/src/nl/astraeus/jdbc/PreparedStatementLogger.java new file mode 100644 index 0000000..98aefc7 --- /dev/null +++ b/src/nl/astraeus/jdbc/PreparedStatementLogger.java @@ -0,0 +1,577 @@ +package nl.astraeus.jdbc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.InputStream; +import java.io.Reader; +import java.math.BigDecimal; +import java.net.URL; +import java.sql.*; +import java.util.Calendar; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 7:47:57 PM + */ +public class PreparedStatementLogger implements PreparedStatement { + private final static Logger log = LoggerFactory.getLogger(PreparedStatementLogger.class); + + private PreparedStatement statement; + + private String sql; + private QueryType type; + private long milli; + private long nano; + + //private ArrayList parameters; + + public PreparedStatementLogger(PreparedStatement statement) { + this.statement = statement; + this.sql = ""; + this.type = QueryType.UNKNOWN; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(QueryType type, String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(type, sql, m, n); + } + + public PreparedStatementLogger(Connection connection, String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql); + } + + public PreparedStatementLogger(Connection connection, String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatementLogger(Connection connection, String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, autoGeneratedKeys); + } + + public PreparedStatementLogger(Connection connection, String sql, int[] columnIndexes) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnIndexes); + } + + public PreparedStatementLogger(Connection connection, String sql, String[] columnNames) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnNames); + } + + public boolean execute() throws SQLException { + clearTime(); + + boolean result = statement.execute(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery() throws SQLException { + clearTime(); + + ResultSet result = statement.executeQuery(); + + log(type, sql); + + return result; + } + + public int executeUpdate() throws SQLException { + clearTime(); + + int result = statement.executeUpdate(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + ResultSet result = statement.executeQuery(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnNames); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnNames); + + log(type, sql); + + return result; + } + + + public void setNull(int parameterIndex, int sqlType) throws SQLException { + statement.setNull(parameterIndex, sqlType); + } + + public void setBoolean(int parameterIndex, boolean x) throws SQLException { + statement.setBoolean(parameterIndex, x); + } + + public void setByte(int parameterIndex, byte x) throws SQLException { + statement.setByte(parameterIndex, x); + } + + public void setShort(int parameterIndex, short x) throws SQLException { + statement.setShort(parameterIndex, x); + } + + public void setInt(int parameterIndex, int x) throws SQLException { + statement.setInt(parameterIndex, x); + } + + public void setLong(int parameterIndex, long x) throws SQLException { + statement.setLong(parameterIndex, x); + } + + public void setFloat(int parameterIndex, float x) throws SQLException { + statement.setFloat(parameterIndex, x); + } + + public void setDouble(int parameterIndex, double x) throws SQLException { + statement.setDouble(parameterIndex, x); + } + + public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { + statement.setBigDecimal(parameterIndex, x); + } + + public void setString(int parameterIndex, String x) throws SQLException { + statement.setString(parameterIndex, x); + } + + public void setBytes(int parameterIndex, byte x[]) throws SQLException { + statement.setBytes(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x) throws SQLException { + statement.setDate(parameterIndex, x); + } + + public void setTime(int parameterIndex, Time x) throws SQLException { + statement.setTime(parameterIndex, x); + } + + public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { + statement.setTimestamp(parameterIndex, x); + } + + public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setUnicodeStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType); + } + + public void setObject(int parameterIndex, Object x) throws SQLException { + statement.setObject(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setRef(int parameterIndex, Ref x) throws SQLException { + statement.setRef(parameterIndex, x); + } + + public void setBlob(int parameterIndex, Blob x) throws SQLException { + statement.setBlob(parameterIndex, x); + } + + public void setClob(int parameterIndex, Clob x) throws SQLException { + statement.setClob(parameterIndex, x); + } + + public void setArray(int parameterIndex, Array x) throws SQLException { + statement.setArray(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { + statement.setDate(parameterIndex, x, cal); + } + + public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { + statement.setTime(parameterIndex, x, cal); + } + + public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { + statement.setTimestamp(parameterIndex, x, cal); + } + + public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException { + statement.setNull(parameterIndex, sqlType, typeName); + } + + public void setURL(int parameterIndex, URL x) throws SQLException { + statement.setURL(parameterIndex, x); + } + + public void setRowId(int parameterIndex, RowId x) throws SQLException { + statement.setRowId(parameterIndex, x); + } + + public void setNString(int parameterIndex, String value) throws SQLException { + statement.setNString(parameterIndex, value); + } + + public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException { + statement.setNCharacterStream(parameterIndex, value, length); + } + + public void setNClob(int parameterIndex, NClob value) throws SQLException { + statement.setNClob(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setClob(parameterIndex, reader, length); + } + + public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException { + statement.setBlob(parameterIndex, inputStream, length); + } + + public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setNClob(parameterIndex, reader, length); + } + + public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException { + statement.setSQLXML(parameterIndex, xmlObject); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType, scaleOrLength); + } + + public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException { + statement.setAsciiStream(parameterIndex, x); + } + + public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException { + statement.setBinaryStream(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException { + statement.setCharacterStream(parameterIndex, reader); + } + + public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException { + statement.setNCharacterStream(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader) throws SQLException { + statement.setClob(parameterIndex, reader); + } + + public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException { + statement.setBlob(parameterIndex, inputStream); + } + + public void setNClob(int parameterIndex, Reader reader) throws SQLException { + statement.setNClob(parameterIndex, reader); + } + + + public void close() throws SQLException { + sql = ""; + type = QueryType.UNKNOWN; + milli = 0; + nano = 0; + + statement.close(); + } + + public ResultSetMetaData getMetaData() throws SQLException { + return statement.getMetaData(); + } + + public void clearParameters() throws SQLException { + statement.clearParameters(); + } + + public ParameterMetaData getParameterMetaData() throws SQLException { + return statement.getParameterMetaData(); + } + + public void addBatch() throws SQLException { + statement.addBatch(); + } + + public int getMaxFieldSize() throws SQLException { + return statement.getMaxFieldSize(); + } + + public void setMaxFieldSize(int max) throws SQLException { + statement.setMaxFieldSize(max); + } + + public int getMaxRows() throws SQLException { + return statement.getMaxRows(); + } + + public void setMaxRows(int max) throws SQLException { + statement.setMaxRows(max); + } + + public void setEscapeProcessing(boolean enable) throws SQLException { + statement.setEscapeProcessing(enable); + } + + public int getQueryTimeout() throws SQLException { + return statement.getQueryTimeout(); + } + + public void setQueryTimeout(int seconds) throws SQLException { + statement.setQueryTimeout(seconds); + } + + public void cancel() throws SQLException { + statement.cancel(); + } + + public SQLWarning getWarnings() throws SQLException { + return statement.getWarnings(); + } + + public void clearWarnings() throws SQLException { + statement.clearWarnings(); + } + + public void setCursorName(String name) throws SQLException { + statement.setCursorName(name); + } + + public boolean execute(String sql) throws SQLException { + return statement.execute(sql); + } + + public ResultSet getResultSet() throws SQLException { + return statement.getResultSet(); + } + + public int getUpdateCount() throws SQLException { + return statement.getUpdateCount(); + } + + public boolean getMoreResults() throws SQLException { + return statement.getMoreResults(); + } + + public void setFetchDirection(int direction) throws SQLException { + statement.setFetchDirection(direction); + } + + public int getFetchDirection() throws SQLException { + return statement.getFetchDirection(); + } + + public void setFetchSize(int rows) throws SQLException { + statement.setFetchSize(rows); + } + + public int getFetchSize() throws SQLException { + return statement.getFetchSize(); + } + + public int getResultSetConcurrency() throws SQLException { + return statement.getResultSetConcurrency(); + } + + public int getResultSetType() throws SQLException { + return statement.getResultSetType(); + } + + public void addBatch(String sql) throws SQLException { + statement.addBatch(sql); + } + + public void clearBatch() throws SQLException { + statement.clearBatch(); + } + + public int[] executeBatch() throws SQLException { + return statement.executeBatch(); + } + + public Connection getConnection() throws SQLException { + return statement.getConnection(); + } + + public boolean getMoreResults(int current) throws SQLException { + return statement.getMoreResults(current); + } + + public ResultSet getGeneratedKeys() throws SQLException { + return statement.getGeneratedKeys(); + } + + public int getResultSetHoldability() throws SQLException { + return statement.getResultSetHoldability(); + } + + public boolean isClosed() throws SQLException { + return statement.isClosed(); + } + + public void setPoolable(boolean poolable) throws SQLException { + statement.setPoolable(poolable); + } + + public boolean isPoolable() throws SQLException { + return statement.isPoolable(); + } + + @Override + public void closeOnCompletion() throws SQLException { + statement.closeOnCompletion();; + } + + @Override + public boolean isCloseOnCompletion() throws SQLException { + return statement.isCloseOnCompletion(); + } + + public T unwrap(Class iface) throws SQLException { + return statement.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return statement.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/QueryType.java b/src/nl/astraeus/jdbc/QueryType.java new file mode 100644 index 0000000..744fbfc --- /dev/null +++ b/src/nl/astraeus/jdbc/QueryType.java @@ -0,0 +1,24 @@ +package nl.astraeus.jdbc; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:32:49 PM + */ +public enum QueryType { + PLAIN("plain"), + PREPARED("prepared"), + CALLABLE("callable"), + UNKNOWN("unknown"); + + private String description; + + QueryType(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } + +} diff --git a/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java new file mode 100644 index 0000000..07aac40 --- /dev/null +++ b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java @@ -0,0 +1,68 @@ +package nl.astraeus.jdbc.example; + +import java.sql.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 7:32 PM + */ +public class JdbcStatisticsExample { + + + public static void main(String [] args) throws Exception { + Class.forName("org.h2.Driver"); + Class.forName("nl.astraeus.jdbc.Driver"); + + new JdbcStatisticsExample(); + } + + public JdbcStatisticsExample() throws Exception { + Connection conn = DriverManager.getConnection("jdbc:stat:jdbc:h2:mem:test"); + + Statement statement = null; + + statement = conn.createStatement(); + statement.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + + boolean running = true; + int count = 1; + PreparedStatement ps = null; + + while (running) { + Thread.sleep(10); + + String TableName = "TEST"+(System.nanoTime() % 1000); + + try { + ps = conn.prepareStatement("SELECT COUNT(*) FROM "+TableName); + ResultSet rs = ps.executeQuery(); + } catch (SQLException e) { + statement = conn.createStatement(); + statement.execute("CREATE TABLE "+TableName+" (ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + } finally { + if (ps!=null) { + ps.close(); + } + } + + ps = conn.prepareStatement("INSERT INTO "+TableName+" VALUES (?, ?)"); + + ps.setInt(1, count++); + ps.setString(2, "String "+System.currentTimeMillis()); + + ps.execute(); + ps.close(); + + Thread.sleep(10); + + ps = conn.prepareStatement("SELECT * FROM "+TableName); + ResultSet rs = ps.executeQuery(); + statement.close(); + } + + conn.close(); + } +} diff --git a/src/nl/astraeus/jdbc/util/IOUtils.java b/src/nl/astraeus/jdbc/util/IOUtils.java new file mode 100644 index 0000000..ce95d9d --- /dev/null +++ b/src/nl/astraeus/jdbc/util/IOUtils.java @@ -0,0 +1,38 @@ +package nl.astraeus.jdbc.util; + +import java.io.*; + +/** + * User: rnentjes + * Date: 4/9/12 + * Time: 2:33 PM + */ +public class IOUtils { + + public static String toString(InputStream in) throws IOException { + assert in != null; + + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + StringBuilder buffer = new StringBuilder(); + + while(reader.ready()) { + buffer.append(reader.readLine()); + buffer.append("\n"); + } + + return buffer.toString(); + } finally { + in.close(); + } + } + + public static void copy(InputStream in, OutputStream out) throws IOException { + byte [] buffer = new byte[1<<16]; + int bytes; + + while((bytes = in.read(buffer)) > 0) { + out.write(buffer, 0, bytes); + } + } +} diff --git a/src/nl/astraeus/jdbc/util/Util.java b/src/nl/astraeus/jdbc/util/Util.java new file mode 100644 index 0000000..eaa853b --- /dev/null +++ b/src/nl/astraeus/jdbc/util/Util.java @@ -0,0 +1,25 @@ +package nl.astraeus.jdbc.util; + +import java.text.DecimalFormat; +import java.text.NumberFormat; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 12:28 PM + */ +public class Util { + // utility functions + public static String formatNano(long l) { + NumberFormat format = new DecimalFormat("###,##0.000000"); + + return format.format((double) l / 1000000.0); + } + + public static void printMemoryUsage() { + System.out.println("Used memory: "+((Runtime.getRuntime().totalMemory() / (1024*1024))-(Runtime.getRuntime().freeMemory() / (1024*1024)))); + System.out.println("Free memory: "+(Runtime.getRuntime().freeMemory() / (1024*1024))); + System.out.println("Total memory: "+(Runtime.getRuntime().totalMemory() / (1024*1024))); + System.out.println("Max memory: "+(Runtime.getRuntime().maxMemory() / (1024*1024))); + } +} diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f403193 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..73ff239 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..3b00020 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..275077f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/README b/README deleted file mode 100644 index 734abaf..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -This file was created by IntelliJ IDEA 11.1.1 for binding GitHub repository \ No newline at end of file diff --git a/Simple-jdbc-statistics.iml b/Simple-jdbc-statistics.iml new file mode 100644 index 0000000..ca90a9b --- /dev/null +++ b/Simple-jdbc-statistics.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/lib/h2-1.3.166.jar b/lib/h2-1.3.166.jar new file mode 100644 index 0000000..4985063 --- /dev/null +++ b/lib/h2-1.3.166.jar Binary files differ diff --git a/lib/servlet-api-2.5.jar b/lib/servlet-api-2.5.jar new file mode 100644 index 0000000..20b5755 --- /dev/null +++ b/lib/servlet-api-2.5.jar Binary files differ diff --git a/lib/slf4j-api-1.6.4.jar b/lib/slf4j-api-1.6.4.jar new file mode 100644 index 0000000..4d23f41 --- /dev/null +++ b/lib/slf4j-api-1.6.4.jar Binary files differ diff --git a/lib/slf4j-simple-1.6.4.jar b/lib/slf4j-simple-1.6.4.jar new file mode 100644 index 0000000..3d1b8d9 --- /dev/null +++ b/lib/slf4j-simple-1.6.4.jar Binary files differ diff --git a/lib/ssr-0.1.jar b/lib/ssr-0.1.jar new file mode 100644 index 0000000..65dfcf4 --- /dev/null +++ b/lib/ssr-0.1.jar Binary files differ diff --git a/lib/vst-0.4.jar b/lib/vst-0.4.jar new file mode 100644 index 0000000..db63792 --- /dev/null +++ b/lib/vst-0.4.jar Binary files differ diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..ac2dbe1 --- /dev/null +++ b/readme.md @@ -0,0 +1 @@ +A simple wrapper around jdbc drivers what will show current jdbc stats of the running queries on a simple web page on port 18080. \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/ConnectionLogger.java b/src/nl/astraeus/jdbc/ConnectionLogger.java new file mode 100644 index 0000000..c3e243f --- /dev/null +++ b/src/nl/astraeus/jdbc/ConnectionLogger.java @@ -0,0 +1,279 @@ +package nl.astraeus.jdbc; + +import java.sql.*; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Executor; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:12:34 PM + */ +public class ConnectionLogger implements Connection { + private Connection connection; + + private long milli; + private long nano; + private String lastSql; + + public ConnectionLogger(Connection connection) { + this.connection = connection; + this.lastSql = ""; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(QueryType.UNKNOWN, sql, m, n); + } + + public void commit() throws SQLException { + clearTime(); + + connection.commit(); + + log("commit"); + } + + public void rollback() throws SQLException { + clearTime(); + + connection.rollback(); + + log("rollback"); + } + + public void close() throws SQLException { + clearTime(); + + connection.close(); + + log("close"); + } + + public PreparedStatement prepareStatement(String sql) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, autoGeneratedKeys); + } + + public PreparedStatement prepareStatement(String sql, int columnIndexes[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnIndexes); + } + + public PreparedStatement prepareStatement(String sql, String columnNames[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnNames); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public Statement createStatement() throws SQLException { + return connection.createStatement(); + } + + public CallableStatement prepareCall(String sql) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql); + } + + public String nativeSQL(String sql) throws SQLException { + lastSql = sql; + return connection.nativeSQL(sql); + } + + public void setAutoCommit(boolean autoCommit) throws SQLException { + connection.setAutoCommit(autoCommit); + } + + public boolean getAutoCommit() throws SQLException { + return connection.getAutoCommit(); + } + + public boolean isClosed() throws SQLException { + return connection.isClosed(); + } + + public DatabaseMetaData getMetaData() throws SQLException { + return connection.getMetaData(); + } + + public void setReadOnly(boolean readOnly) throws SQLException { + connection.setReadOnly(readOnly); + } + + public boolean isReadOnly() throws SQLException { + return connection.isReadOnly(); + } + + public void setCatalog(String catalog) throws SQLException { + connection.setCatalog(catalog); + } + + public String getCatalog() throws SQLException { + return connection.getCatalog(); + } + + public void setTransactionIsolation(int level) throws SQLException { + connection.setTransactionIsolation(level); + } + + public int getTransactionIsolation() throws SQLException { + return connection.getTransactionIsolation(); + } + + public SQLWarning getWarnings() throws SQLException { + return connection.getWarnings(); + } + + public void clearWarnings() throws SQLException { + connection.clearWarnings(); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency); + } + + public Map> getTypeMap() throws SQLException { + return connection.getTypeMap(); + } + + public void setTypeMap(Map> map) throws SQLException { + connection.setTypeMap(map); + } + + public void setHoldability(int holdability) throws SQLException { + connection.setHoldability(holdability); + } + + public int getHoldability() throws SQLException { + return connection.getHoldability(); + } + + public Savepoint setSavepoint() throws SQLException { + return connection.setSavepoint(); + } + + public Savepoint setSavepoint(String name) throws SQLException { + return connection.setSavepoint(name); + } + + public void rollback(Savepoint savepoint) throws SQLException { + connection.rollback(); + } + + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + connection.releaseSavepoint(savepoint); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public Clob createClob() throws SQLException { + return connection.createClob(); + } + + public Blob createBlob() throws SQLException { + return connection.createBlob(); + } + + public NClob createNClob() throws SQLException { + return connection.createNClob(); + } + + public SQLXML createSQLXML() throws SQLException { + return connection.createSQLXML(); + } + + public boolean isValid(int timeout) throws SQLException { + return connection.isValid(timeout); + } + + public void setClientInfo(String name, String value) throws SQLClientInfoException { + connection.setClientInfo(name, value); + } + + public void setClientInfo(Properties properties) throws SQLClientInfoException { + connection.setClientInfo(properties); + } + + public String getClientInfo(String name) throws SQLException { + return connection.getClientInfo(name); + } + + public Properties getClientInfo() throws SQLException { + return connection.getClientInfo(); + } + + public Array createArrayOf(String typeName, Object[] elements) throws SQLException { + return connection.createArrayOf(typeName, elements); + } + + public Struct createStruct(String typeName, Object[] attributes) throws SQLException { + return connection.createStruct(typeName, attributes); + } + + @Override + public void setSchema(String schema) throws SQLException { + connection.setSchema(schema); + } + + @Override + public String getSchema() throws SQLException { + return connection.getSchema(); + } + + @Override + public void abort(Executor executor) throws SQLException { + connection.abort(executor); + } + + @Override + public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { + connection.setNetworkTimeout(executor, milliseconds); + } + + @Override + public int getNetworkTimeout() throws SQLException { + return connection.getNetworkTimeout(); + } + + public T unwrap(Class iface) throws SQLException { + return connection.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return connection.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/Driver.java b/src/nl/astraeus/jdbc/Driver.java new file mode 100644 index 0000000..8317172 --- /dev/null +++ b/src/nl/astraeus/jdbc/Driver.java @@ -0,0 +1,116 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.http.SimpleWebServer; +import nl.astraeus.jdbc.web.JdbcStatisticsServlet; +import nl.astraeus.jdbc.web.ResourceServlet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.*; +import java.util.Enumeration; +import java.util.Properties; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:54:37 PM + */ +public class Driver implements java.sql.Driver { + private final static Logger log = LoggerFactory.getLogger(Driver.class); + + final private static String URL_PREFIX = "jdbc:stat:"; + + private java.sql.Driver driver = null; + private String[] drivers = { + "org.postgresql.Driver", + "oracle.jdbc.driver.OracleDriver", + "com.sybase.jdbc2.jdbc.SybDriver", + "net.sourceforge.jtds.jdbc.Driver", + "com.microsoft.jdbc.sqlserver.SQLServerDriver", + "com.microsoft.sqlserver.jdbc.SQLServerDriver", + "weblogic.jdbc.sqlserver.SQLServerDriver", + "com.informix.jdbc.IfxDriver", + "org.apache.derby.jdbc.ClientDriver", + "org.apache.derby.jdbc.EmbeddedDriver", + "com.mysql.jdbc.Driver", + "org.hsqldb.jdbcDriver", + "org.h2.Driver" }; + + static { + log.debug("Loading driver class " + Driver.class.getName()); + + try { + DriverManager.registerDriver(new Driver()); + } catch (SQLException e) { + log.error("", e); + } + } + + public Driver() { + for (String dr : drivers) { + try { + Class.forName(dr); + } catch (Throwable e) { + log.debug("Can't instantiate driver: " + dr, e); + } + } + } + + private java.sql.Driver findDriver(String url) throws SQLException { + Enumeration e = DriverManager.getDrivers(); + + while (e.hasMoreElements()) { + java.sql.Driver d = (java.sql.Driver) e.nextElement(); + + if (d.acceptsURL(url)) { + return d; + } + } + + throw new SQLException("Driver not found: " + url); + } + + public Connection connect(String url, Properties info) throws SQLException { + url = url.substring(URL_PREFIX.length()); + + if (driver == null) { + driver = findDriver(url); + } + + if (driver != null) { + SimpleWebServer server = new SimpleWebServer(18080); + + server.addServlet(new JdbcStatisticsServlet(), "/"); + server.addServlet(new ResourceServlet(), "/resources/*"); + + server.start(); + } + + return new ConnectionLogger(driver.connect(url, info)); + } + + public boolean acceptsURL(String url) throws SQLException { + return (url != null && url.startsWith(URL_PREFIX)); + } + + public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { + return driver.getPropertyInfo(url, info); + } + + public int getMajorVersion() { + return driver.getMajorVersion(); + } + + public int getMinorVersion() { + return driver.getMinorVersion(); + } + + public boolean jdbcCompliant() { + return driver.jdbcCompliant(); + } + + @Override + public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException { + return driver.getParentLogger(); + } +} diff --git a/src/nl/astraeus/jdbc/JdbcLogger.java b/src/nl/astraeus/jdbc/JdbcLogger.java new file mode 100644 index 0000000..f4bc125 --- /dev/null +++ b/src/nl/astraeus/jdbc/JdbcLogger.java @@ -0,0 +1,113 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.jdbc.util.Util; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/** + * User: riennentjes + * Date: Jul 12, 2008 + * Time: 9:15:21 AM + */ +public class JdbcLogger { + private final static Logger logger = LoggerFactory.getLogger(JdbcLogger.class); + + private final static JdbcLogger instance = new JdbcLogger(); + + public static JdbcLogger get() { + return instance; + } + + public final static class LogEntry { + public QueryType type; + public String sql; + public long milli; + public long nano; + public int count; + public int hash; + + public LogEntry(int hash, QueryType type, String sql, long milli, long nano) { + this.hash = hash; + this.type = type; + this.sql = sql; + this.milli = milli; + this.nano = nano; + this.count = 1; + } + + public void addCount(long milli, long nano) { + synchronized (this) { + count++; + this.milli += milli; + this.nano += nano; + } + } + + public int getCount() { + return count; + } + + public String getMilli() { + return Util.formatNano(milli*1000000/count); + } + + public String getNano() { + return Util.formatNano(nano/count); + } + + public String getTotal() { + return Util.formatNano(nano); + } + + public String getSql() { + return sql; + } + } + + private Map queries; + + public JdbcLogger() { + queries = new ConcurrentHashMap(); + } + + public void logEntry(QueryType type, String sql, long milli, long nano) { + int hash = sql.hashCode(); + LogEntry entry = queries.get(hash); + + if (entry == null) { + entry = new LogEntry(hash, type, sql, milli, nano); + queries.put(hash, entry); + } else { + entry.addCount(milli, nano); + } + + if (queries.size() > 1000) { + List toRemove = new LinkedList(); + List values = new LinkedList(queries.values()); + + Collections.sort(values, new Comparator() { + @Override + public int compare(LogEntry o1, LogEntry o2) { + return o1.count - o2.count; + } + }); + + while (queries.size() > 900) { + queries.remove(values.remove(0).hash); + + } + } + } + + public static void log(QueryType type, String sql, long milli, long nano) { + instance.logEntry(type, sql, milli, nano); + } + + public Collection getEntries() { + return queries.values(); + } + +} diff --git a/src/nl/astraeus/jdbc/PreparedStatementLogger.java b/src/nl/astraeus/jdbc/PreparedStatementLogger.java new file mode 100644 index 0000000..98aefc7 --- /dev/null +++ b/src/nl/astraeus/jdbc/PreparedStatementLogger.java @@ -0,0 +1,577 @@ +package nl.astraeus.jdbc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.InputStream; +import java.io.Reader; +import java.math.BigDecimal; +import java.net.URL; +import java.sql.*; +import java.util.Calendar; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 7:47:57 PM + */ +public class PreparedStatementLogger implements PreparedStatement { + private final static Logger log = LoggerFactory.getLogger(PreparedStatementLogger.class); + + private PreparedStatement statement; + + private String sql; + private QueryType type; + private long milli; + private long nano; + + //private ArrayList parameters; + + public PreparedStatementLogger(PreparedStatement statement) { + this.statement = statement; + this.sql = ""; + this.type = QueryType.UNKNOWN; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(QueryType type, String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(type, sql, m, n); + } + + public PreparedStatementLogger(Connection connection, String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql); + } + + public PreparedStatementLogger(Connection connection, String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatementLogger(Connection connection, String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, autoGeneratedKeys); + } + + public PreparedStatementLogger(Connection connection, String sql, int[] columnIndexes) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnIndexes); + } + + public PreparedStatementLogger(Connection connection, String sql, String[] columnNames) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnNames); + } + + public boolean execute() throws SQLException { + clearTime(); + + boolean result = statement.execute(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery() throws SQLException { + clearTime(); + + ResultSet result = statement.executeQuery(); + + log(type, sql); + + return result; + } + + public int executeUpdate() throws SQLException { + clearTime(); + + int result = statement.executeUpdate(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + ResultSet result = statement.executeQuery(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnNames); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnNames); + + log(type, sql); + + return result; + } + + + public void setNull(int parameterIndex, int sqlType) throws SQLException { + statement.setNull(parameterIndex, sqlType); + } + + public void setBoolean(int parameterIndex, boolean x) throws SQLException { + statement.setBoolean(parameterIndex, x); + } + + public void setByte(int parameterIndex, byte x) throws SQLException { + statement.setByte(parameterIndex, x); + } + + public void setShort(int parameterIndex, short x) throws SQLException { + statement.setShort(parameterIndex, x); + } + + public void setInt(int parameterIndex, int x) throws SQLException { + statement.setInt(parameterIndex, x); + } + + public void setLong(int parameterIndex, long x) throws SQLException { + statement.setLong(parameterIndex, x); + } + + public void setFloat(int parameterIndex, float x) throws SQLException { + statement.setFloat(parameterIndex, x); + } + + public void setDouble(int parameterIndex, double x) throws SQLException { + statement.setDouble(parameterIndex, x); + } + + public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { + statement.setBigDecimal(parameterIndex, x); + } + + public void setString(int parameterIndex, String x) throws SQLException { + statement.setString(parameterIndex, x); + } + + public void setBytes(int parameterIndex, byte x[]) throws SQLException { + statement.setBytes(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x) throws SQLException { + statement.setDate(parameterIndex, x); + } + + public void setTime(int parameterIndex, Time x) throws SQLException { + statement.setTime(parameterIndex, x); + } + + public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { + statement.setTimestamp(parameterIndex, x); + } + + public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setUnicodeStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType); + } + + public void setObject(int parameterIndex, Object x) throws SQLException { + statement.setObject(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setRef(int parameterIndex, Ref x) throws SQLException { + statement.setRef(parameterIndex, x); + } + + public void setBlob(int parameterIndex, Blob x) throws SQLException { + statement.setBlob(parameterIndex, x); + } + + public void setClob(int parameterIndex, Clob x) throws SQLException { + statement.setClob(parameterIndex, x); + } + + public void setArray(int parameterIndex, Array x) throws SQLException { + statement.setArray(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { + statement.setDate(parameterIndex, x, cal); + } + + public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { + statement.setTime(parameterIndex, x, cal); + } + + public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { + statement.setTimestamp(parameterIndex, x, cal); + } + + public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException { + statement.setNull(parameterIndex, sqlType, typeName); + } + + public void setURL(int parameterIndex, URL x) throws SQLException { + statement.setURL(parameterIndex, x); + } + + public void setRowId(int parameterIndex, RowId x) throws SQLException { + statement.setRowId(parameterIndex, x); + } + + public void setNString(int parameterIndex, String value) throws SQLException { + statement.setNString(parameterIndex, value); + } + + public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException { + statement.setNCharacterStream(parameterIndex, value, length); + } + + public void setNClob(int parameterIndex, NClob value) throws SQLException { + statement.setNClob(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setClob(parameterIndex, reader, length); + } + + public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException { + statement.setBlob(parameterIndex, inputStream, length); + } + + public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setNClob(parameterIndex, reader, length); + } + + public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException { + statement.setSQLXML(parameterIndex, xmlObject); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType, scaleOrLength); + } + + public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException { + statement.setAsciiStream(parameterIndex, x); + } + + public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException { + statement.setBinaryStream(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException { + statement.setCharacterStream(parameterIndex, reader); + } + + public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException { + statement.setNCharacterStream(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader) throws SQLException { + statement.setClob(parameterIndex, reader); + } + + public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException { + statement.setBlob(parameterIndex, inputStream); + } + + public void setNClob(int parameterIndex, Reader reader) throws SQLException { + statement.setNClob(parameterIndex, reader); + } + + + public void close() throws SQLException { + sql = ""; + type = QueryType.UNKNOWN; + milli = 0; + nano = 0; + + statement.close(); + } + + public ResultSetMetaData getMetaData() throws SQLException { + return statement.getMetaData(); + } + + public void clearParameters() throws SQLException { + statement.clearParameters(); + } + + public ParameterMetaData getParameterMetaData() throws SQLException { + return statement.getParameterMetaData(); + } + + public void addBatch() throws SQLException { + statement.addBatch(); + } + + public int getMaxFieldSize() throws SQLException { + return statement.getMaxFieldSize(); + } + + public void setMaxFieldSize(int max) throws SQLException { + statement.setMaxFieldSize(max); + } + + public int getMaxRows() throws SQLException { + return statement.getMaxRows(); + } + + public void setMaxRows(int max) throws SQLException { + statement.setMaxRows(max); + } + + public void setEscapeProcessing(boolean enable) throws SQLException { + statement.setEscapeProcessing(enable); + } + + public int getQueryTimeout() throws SQLException { + return statement.getQueryTimeout(); + } + + public void setQueryTimeout(int seconds) throws SQLException { + statement.setQueryTimeout(seconds); + } + + public void cancel() throws SQLException { + statement.cancel(); + } + + public SQLWarning getWarnings() throws SQLException { + return statement.getWarnings(); + } + + public void clearWarnings() throws SQLException { + statement.clearWarnings(); + } + + public void setCursorName(String name) throws SQLException { + statement.setCursorName(name); + } + + public boolean execute(String sql) throws SQLException { + return statement.execute(sql); + } + + public ResultSet getResultSet() throws SQLException { + return statement.getResultSet(); + } + + public int getUpdateCount() throws SQLException { + return statement.getUpdateCount(); + } + + public boolean getMoreResults() throws SQLException { + return statement.getMoreResults(); + } + + public void setFetchDirection(int direction) throws SQLException { + statement.setFetchDirection(direction); + } + + public int getFetchDirection() throws SQLException { + return statement.getFetchDirection(); + } + + public void setFetchSize(int rows) throws SQLException { + statement.setFetchSize(rows); + } + + public int getFetchSize() throws SQLException { + return statement.getFetchSize(); + } + + public int getResultSetConcurrency() throws SQLException { + return statement.getResultSetConcurrency(); + } + + public int getResultSetType() throws SQLException { + return statement.getResultSetType(); + } + + public void addBatch(String sql) throws SQLException { + statement.addBatch(sql); + } + + public void clearBatch() throws SQLException { + statement.clearBatch(); + } + + public int[] executeBatch() throws SQLException { + return statement.executeBatch(); + } + + public Connection getConnection() throws SQLException { + return statement.getConnection(); + } + + public boolean getMoreResults(int current) throws SQLException { + return statement.getMoreResults(current); + } + + public ResultSet getGeneratedKeys() throws SQLException { + return statement.getGeneratedKeys(); + } + + public int getResultSetHoldability() throws SQLException { + return statement.getResultSetHoldability(); + } + + public boolean isClosed() throws SQLException { + return statement.isClosed(); + } + + public void setPoolable(boolean poolable) throws SQLException { + statement.setPoolable(poolable); + } + + public boolean isPoolable() throws SQLException { + return statement.isPoolable(); + } + + @Override + public void closeOnCompletion() throws SQLException { + statement.closeOnCompletion();; + } + + @Override + public boolean isCloseOnCompletion() throws SQLException { + return statement.isCloseOnCompletion(); + } + + public T unwrap(Class iface) throws SQLException { + return statement.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return statement.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/QueryType.java b/src/nl/astraeus/jdbc/QueryType.java new file mode 100644 index 0000000..744fbfc --- /dev/null +++ b/src/nl/astraeus/jdbc/QueryType.java @@ -0,0 +1,24 @@ +package nl.astraeus.jdbc; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:32:49 PM + */ +public enum QueryType { + PLAIN("plain"), + PREPARED("prepared"), + CALLABLE("callable"), + UNKNOWN("unknown"); + + private String description; + + QueryType(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } + +} diff --git a/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java new file mode 100644 index 0000000..07aac40 --- /dev/null +++ b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java @@ -0,0 +1,68 @@ +package nl.astraeus.jdbc.example; + +import java.sql.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 7:32 PM + */ +public class JdbcStatisticsExample { + + + public static void main(String [] args) throws Exception { + Class.forName("org.h2.Driver"); + Class.forName("nl.astraeus.jdbc.Driver"); + + new JdbcStatisticsExample(); + } + + public JdbcStatisticsExample() throws Exception { + Connection conn = DriverManager.getConnection("jdbc:stat:jdbc:h2:mem:test"); + + Statement statement = null; + + statement = conn.createStatement(); + statement.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + + boolean running = true; + int count = 1; + PreparedStatement ps = null; + + while (running) { + Thread.sleep(10); + + String TableName = "TEST"+(System.nanoTime() % 1000); + + try { + ps = conn.prepareStatement("SELECT COUNT(*) FROM "+TableName); + ResultSet rs = ps.executeQuery(); + } catch (SQLException e) { + statement = conn.createStatement(); + statement.execute("CREATE TABLE "+TableName+" (ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + } finally { + if (ps!=null) { + ps.close(); + } + } + + ps = conn.prepareStatement("INSERT INTO "+TableName+" VALUES (?, ?)"); + + ps.setInt(1, count++); + ps.setString(2, "String "+System.currentTimeMillis()); + + ps.execute(); + ps.close(); + + Thread.sleep(10); + + ps = conn.prepareStatement("SELECT * FROM "+TableName); + ResultSet rs = ps.executeQuery(); + statement.close(); + } + + conn.close(); + } +} diff --git a/src/nl/astraeus/jdbc/util/IOUtils.java b/src/nl/astraeus/jdbc/util/IOUtils.java new file mode 100644 index 0000000..ce95d9d --- /dev/null +++ b/src/nl/astraeus/jdbc/util/IOUtils.java @@ -0,0 +1,38 @@ +package nl.astraeus.jdbc.util; + +import java.io.*; + +/** + * User: rnentjes + * Date: 4/9/12 + * Time: 2:33 PM + */ +public class IOUtils { + + public static String toString(InputStream in) throws IOException { + assert in != null; + + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + StringBuilder buffer = new StringBuilder(); + + while(reader.ready()) { + buffer.append(reader.readLine()); + buffer.append("\n"); + } + + return buffer.toString(); + } finally { + in.close(); + } + } + + public static void copy(InputStream in, OutputStream out) throws IOException { + byte [] buffer = new byte[1<<16]; + int bytes; + + while((bytes = in.read(buffer)) > 0) { + out.write(buffer, 0, bytes); + } + } +} diff --git a/src/nl/astraeus/jdbc/util/Util.java b/src/nl/astraeus/jdbc/util/Util.java new file mode 100644 index 0000000..eaa853b --- /dev/null +++ b/src/nl/astraeus/jdbc/util/Util.java @@ -0,0 +1,25 @@ +package nl.astraeus.jdbc.util; + +import java.text.DecimalFormat; +import java.text.NumberFormat; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 12:28 PM + */ +public class Util { + // utility functions + public static String formatNano(long l) { + NumberFormat format = new DecimalFormat("###,##0.000000"); + + return format.format((double) l / 1000000.0); + } + + public static void printMemoryUsage() { + System.out.println("Used memory: "+((Runtime.getRuntime().totalMemory() / (1024*1024))-(Runtime.getRuntime().freeMemory() / (1024*1024)))); + System.out.println("Free memory: "+(Runtime.getRuntime().freeMemory() / (1024*1024))); + System.out.println("Total memory: "+(Runtime.getRuntime().totalMemory() / (1024*1024))); + System.out.println("Max memory: "+(Runtime.getRuntime().maxMemory() / (1024*1024))); + } +} diff --git a/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java b/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java new file mode 100644 index 0000000..a162d6f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java @@ -0,0 +1,90 @@ +package nl.astraeus.jdbc.web; + +import nl.astraeus.jdbc.util.IOUtils; +import nl.astraeus.jdbc.util.Util; +import nl.astraeus.jdbc.web.page.Menu; +import nl.astraeus.jdbc.web.page.Page; +import nl.astraeus.jdbc.web.page.QueryOverview; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import java.io.IOException; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:05 PM + */ +public class JdbcStatisticsServlet extends HttpServlet { + + private String head; + private String bottom; + + @Override + public void init() throws ServletException { + super.init(); + + try { + head = IOUtils.toString(getClass().getResourceAsStream("head.html")); + bottom = IOUtils.toString(getClass().getResourceAsStream("bottom.html")); + } catch (IOException e) { + throw new ServletException(e); + } + + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + doPost(req, resp); + } + + @Override + protected void doPost(final HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + long nano = System.nanoTime(); + + HttpSession session = req.getSession(); + boolean ajax = "true".equals(req.getParameter("ajax")); + + resp.setContentType("text/html"); + + Page page = (Page)session.getAttribute("page"); + Page menu = (Page)session.getAttribute("menu"); + + session.setMaxInactiveInterval(1800); + + if (menu == null) { + menu = new Menu(); + + session.setAttribute("menu", menu); + } + + if (page == null || "menumain".equals(req.getParameter("action"))) { + page = new QueryOverview(); + } else if ("diagnostics".equals(req.getParameter("action"))) { + //page = new Diagnostics(); + } else { + page = page .processRequest(req); + } + + menu.processRequest(req); + + session.setAttribute("page", page); + + if (!ajax) { + resp.getWriter().print(head); + } + + resp.getWriter().print(menu.render(req)); + resp.getWriter().print(page.render(req)); + + if (!ajax) { + resp.getWriter().print(bottom); + } + + System.out.println("Request ends, time="+ Util.formatNano(System.nanoTime() - nano) +", page="+page.getClass().getSimpleName()); + } + +} diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f403193 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..73ff239 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..3b00020 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..275077f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/README b/README deleted file mode 100644 index 734abaf..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -This file was created by IntelliJ IDEA 11.1.1 for binding GitHub repository \ No newline at end of file diff --git a/Simple-jdbc-statistics.iml b/Simple-jdbc-statistics.iml new file mode 100644 index 0000000..ca90a9b --- /dev/null +++ b/Simple-jdbc-statistics.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/lib/h2-1.3.166.jar b/lib/h2-1.3.166.jar new file mode 100644 index 0000000..4985063 --- /dev/null +++ b/lib/h2-1.3.166.jar Binary files differ diff --git a/lib/servlet-api-2.5.jar b/lib/servlet-api-2.5.jar new file mode 100644 index 0000000..20b5755 --- /dev/null +++ b/lib/servlet-api-2.5.jar Binary files differ diff --git a/lib/slf4j-api-1.6.4.jar b/lib/slf4j-api-1.6.4.jar new file mode 100644 index 0000000..4d23f41 --- /dev/null +++ b/lib/slf4j-api-1.6.4.jar Binary files differ diff --git a/lib/slf4j-simple-1.6.4.jar b/lib/slf4j-simple-1.6.4.jar new file mode 100644 index 0000000..3d1b8d9 --- /dev/null +++ b/lib/slf4j-simple-1.6.4.jar Binary files differ diff --git a/lib/ssr-0.1.jar b/lib/ssr-0.1.jar new file mode 100644 index 0000000..65dfcf4 --- /dev/null +++ b/lib/ssr-0.1.jar Binary files differ diff --git a/lib/vst-0.4.jar b/lib/vst-0.4.jar new file mode 100644 index 0000000..db63792 --- /dev/null +++ b/lib/vst-0.4.jar Binary files differ diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..ac2dbe1 --- /dev/null +++ b/readme.md @@ -0,0 +1 @@ +A simple wrapper around jdbc drivers what will show current jdbc stats of the running queries on a simple web page on port 18080. \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/ConnectionLogger.java b/src/nl/astraeus/jdbc/ConnectionLogger.java new file mode 100644 index 0000000..c3e243f --- /dev/null +++ b/src/nl/astraeus/jdbc/ConnectionLogger.java @@ -0,0 +1,279 @@ +package nl.astraeus.jdbc; + +import java.sql.*; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Executor; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:12:34 PM + */ +public class ConnectionLogger implements Connection { + private Connection connection; + + private long milli; + private long nano; + private String lastSql; + + public ConnectionLogger(Connection connection) { + this.connection = connection; + this.lastSql = ""; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(QueryType.UNKNOWN, sql, m, n); + } + + public void commit() throws SQLException { + clearTime(); + + connection.commit(); + + log("commit"); + } + + public void rollback() throws SQLException { + clearTime(); + + connection.rollback(); + + log("rollback"); + } + + public void close() throws SQLException { + clearTime(); + + connection.close(); + + log("close"); + } + + public PreparedStatement prepareStatement(String sql) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, autoGeneratedKeys); + } + + public PreparedStatement prepareStatement(String sql, int columnIndexes[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnIndexes); + } + + public PreparedStatement prepareStatement(String sql, String columnNames[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnNames); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public Statement createStatement() throws SQLException { + return connection.createStatement(); + } + + public CallableStatement prepareCall(String sql) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql); + } + + public String nativeSQL(String sql) throws SQLException { + lastSql = sql; + return connection.nativeSQL(sql); + } + + public void setAutoCommit(boolean autoCommit) throws SQLException { + connection.setAutoCommit(autoCommit); + } + + public boolean getAutoCommit() throws SQLException { + return connection.getAutoCommit(); + } + + public boolean isClosed() throws SQLException { + return connection.isClosed(); + } + + public DatabaseMetaData getMetaData() throws SQLException { + return connection.getMetaData(); + } + + public void setReadOnly(boolean readOnly) throws SQLException { + connection.setReadOnly(readOnly); + } + + public boolean isReadOnly() throws SQLException { + return connection.isReadOnly(); + } + + public void setCatalog(String catalog) throws SQLException { + connection.setCatalog(catalog); + } + + public String getCatalog() throws SQLException { + return connection.getCatalog(); + } + + public void setTransactionIsolation(int level) throws SQLException { + connection.setTransactionIsolation(level); + } + + public int getTransactionIsolation() throws SQLException { + return connection.getTransactionIsolation(); + } + + public SQLWarning getWarnings() throws SQLException { + return connection.getWarnings(); + } + + public void clearWarnings() throws SQLException { + connection.clearWarnings(); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency); + } + + public Map> getTypeMap() throws SQLException { + return connection.getTypeMap(); + } + + public void setTypeMap(Map> map) throws SQLException { + connection.setTypeMap(map); + } + + public void setHoldability(int holdability) throws SQLException { + connection.setHoldability(holdability); + } + + public int getHoldability() throws SQLException { + return connection.getHoldability(); + } + + public Savepoint setSavepoint() throws SQLException { + return connection.setSavepoint(); + } + + public Savepoint setSavepoint(String name) throws SQLException { + return connection.setSavepoint(name); + } + + public void rollback(Savepoint savepoint) throws SQLException { + connection.rollback(); + } + + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + connection.releaseSavepoint(savepoint); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public Clob createClob() throws SQLException { + return connection.createClob(); + } + + public Blob createBlob() throws SQLException { + return connection.createBlob(); + } + + public NClob createNClob() throws SQLException { + return connection.createNClob(); + } + + public SQLXML createSQLXML() throws SQLException { + return connection.createSQLXML(); + } + + public boolean isValid(int timeout) throws SQLException { + return connection.isValid(timeout); + } + + public void setClientInfo(String name, String value) throws SQLClientInfoException { + connection.setClientInfo(name, value); + } + + public void setClientInfo(Properties properties) throws SQLClientInfoException { + connection.setClientInfo(properties); + } + + public String getClientInfo(String name) throws SQLException { + return connection.getClientInfo(name); + } + + public Properties getClientInfo() throws SQLException { + return connection.getClientInfo(); + } + + public Array createArrayOf(String typeName, Object[] elements) throws SQLException { + return connection.createArrayOf(typeName, elements); + } + + public Struct createStruct(String typeName, Object[] attributes) throws SQLException { + return connection.createStruct(typeName, attributes); + } + + @Override + public void setSchema(String schema) throws SQLException { + connection.setSchema(schema); + } + + @Override + public String getSchema() throws SQLException { + return connection.getSchema(); + } + + @Override + public void abort(Executor executor) throws SQLException { + connection.abort(executor); + } + + @Override + public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { + connection.setNetworkTimeout(executor, milliseconds); + } + + @Override + public int getNetworkTimeout() throws SQLException { + return connection.getNetworkTimeout(); + } + + public T unwrap(Class iface) throws SQLException { + return connection.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return connection.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/Driver.java b/src/nl/astraeus/jdbc/Driver.java new file mode 100644 index 0000000..8317172 --- /dev/null +++ b/src/nl/astraeus/jdbc/Driver.java @@ -0,0 +1,116 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.http.SimpleWebServer; +import nl.astraeus.jdbc.web.JdbcStatisticsServlet; +import nl.astraeus.jdbc.web.ResourceServlet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.*; +import java.util.Enumeration; +import java.util.Properties; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:54:37 PM + */ +public class Driver implements java.sql.Driver { + private final static Logger log = LoggerFactory.getLogger(Driver.class); + + final private static String URL_PREFIX = "jdbc:stat:"; + + private java.sql.Driver driver = null; + private String[] drivers = { + "org.postgresql.Driver", + "oracle.jdbc.driver.OracleDriver", + "com.sybase.jdbc2.jdbc.SybDriver", + "net.sourceforge.jtds.jdbc.Driver", + "com.microsoft.jdbc.sqlserver.SQLServerDriver", + "com.microsoft.sqlserver.jdbc.SQLServerDriver", + "weblogic.jdbc.sqlserver.SQLServerDriver", + "com.informix.jdbc.IfxDriver", + "org.apache.derby.jdbc.ClientDriver", + "org.apache.derby.jdbc.EmbeddedDriver", + "com.mysql.jdbc.Driver", + "org.hsqldb.jdbcDriver", + "org.h2.Driver" }; + + static { + log.debug("Loading driver class " + Driver.class.getName()); + + try { + DriverManager.registerDriver(new Driver()); + } catch (SQLException e) { + log.error("", e); + } + } + + public Driver() { + for (String dr : drivers) { + try { + Class.forName(dr); + } catch (Throwable e) { + log.debug("Can't instantiate driver: " + dr, e); + } + } + } + + private java.sql.Driver findDriver(String url) throws SQLException { + Enumeration e = DriverManager.getDrivers(); + + while (e.hasMoreElements()) { + java.sql.Driver d = (java.sql.Driver) e.nextElement(); + + if (d.acceptsURL(url)) { + return d; + } + } + + throw new SQLException("Driver not found: " + url); + } + + public Connection connect(String url, Properties info) throws SQLException { + url = url.substring(URL_PREFIX.length()); + + if (driver == null) { + driver = findDriver(url); + } + + if (driver != null) { + SimpleWebServer server = new SimpleWebServer(18080); + + server.addServlet(new JdbcStatisticsServlet(), "/"); + server.addServlet(new ResourceServlet(), "/resources/*"); + + server.start(); + } + + return new ConnectionLogger(driver.connect(url, info)); + } + + public boolean acceptsURL(String url) throws SQLException { + return (url != null && url.startsWith(URL_PREFIX)); + } + + public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { + return driver.getPropertyInfo(url, info); + } + + public int getMajorVersion() { + return driver.getMajorVersion(); + } + + public int getMinorVersion() { + return driver.getMinorVersion(); + } + + public boolean jdbcCompliant() { + return driver.jdbcCompliant(); + } + + @Override + public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException { + return driver.getParentLogger(); + } +} diff --git a/src/nl/astraeus/jdbc/JdbcLogger.java b/src/nl/astraeus/jdbc/JdbcLogger.java new file mode 100644 index 0000000..f4bc125 --- /dev/null +++ b/src/nl/astraeus/jdbc/JdbcLogger.java @@ -0,0 +1,113 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.jdbc.util.Util; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/** + * User: riennentjes + * Date: Jul 12, 2008 + * Time: 9:15:21 AM + */ +public class JdbcLogger { + private final static Logger logger = LoggerFactory.getLogger(JdbcLogger.class); + + private final static JdbcLogger instance = new JdbcLogger(); + + public static JdbcLogger get() { + return instance; + } + + public final static class LogEntry { + public QueryType type; + public String sql; + public long milli; + public long nano; + public int count; + public int hash; + + public LogEntry(int hash, QueryType type, String sql, long milli, long nano) { + this.hash = hash; + this.type = type; + this.sql = sql; + this.milli = milli; + this.nano = nano; + this.count = 1; + } + + public void addCount(long milli, long nano) { + synchronized (this) { + count++; + this.milli += milli; + this.nano += nano; + } + } + + public int getCount() { + return count; + } + + public String getMilli() { + return Util.formatNano(milli*1000000/count); + } + + public String getNano() { + return Util.formatNano(nano/count); + } + + public String getTotal() { + return Util.formatNano(nano); + } + + public String getSql() { + return sql; + } + } + + private Map queries; + + public JdbcLogger() { + queries = new ConcurrentHashMap(); + } + + public void logEntry(QueryType type, String sql, long milli, long nano) { + int hash = sql.hashCode(); + LogEntry entry = queries.get(hash); + + if (entry == null) { + entry = new LogEntry(hash, type, sql, milli, nano); + queries.put(hash, entry); + } else { + entry.addCount(milli, nano); + } + + if (queries.size() > 1000) { + List toRemove = new LinkedList(); + List values = new LinkedList(queries.values()); + + Collections.sort(values, new Comparator() { + @Override + public int compare(LogEntry o1, LogEntry o2) { + return o1.count - o2.count; + } + }); + + while (queries.size() > 900) { + queries.remove(values.remove(0).hash); + + } + } + } + + public static void log(QueryType type, String sql, long milli, long nano) { + instance.logEntry(type, sql, milli, nano); + } + + public Collection getEntries() { + return queries.values(); + } + +} diff --git a/src/nl/astraeus/jdbc/PreparedStatementLogger.java b/src/nl/astraeus/jdbc/PreparedStatementLogger.java new file mode 100644 index 0000000..98aefc7 --- /dev/null +++ b/src/nl/astraeus/jdbc/PreparedStatementLogger.java @@ -0,0 +1,577 @@ +package nl.astraeus.jdbc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.InputStream; +import java.io.Reader; +import java.math.BigDecimal; +import java.net.URL; +import java.sql.*; +import java.util.Calendar; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 7:47:57 PM + */ +public class PreparedStatementLogger implements PreparedStatement { + private final static Logger log = LoggerFactory.getLogger(PreparedStatementLogger.class); + + private PreparedStatement statement; + + private String sql; + private QueryType type; + private long milli; + private long nano; + + //private ArrayList parameters; + + public PreparedStatementLogger(PreparedStatement statement) { + this.statement = statement; + this.sql = ""; + this.type = QueryType.UNKNOWN; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(QueryType type, String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(type, sql, m, n); + } + + public PreparedStatementLogger(Connection connection, String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql); + } + + public PreparedStatementLogger(Connection connection, String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatementLogger(Connection connection, String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, autoGeneratedKeys); + } + + public PreparedStatementLogger(Connection connection, String sql, int[] columnIndexes) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnIndexes); + } + + public PreparedStatementLogger(Connection connection, String sql, String[] columnNames) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnNames); + } + + public boolean execute() throws SQLException { + clearTime(); + + boolean result = statement.execute(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery() throws SQLException { + clearTime(); + + ResultSet result = statement.executeQuery(); + + log(type, sql); + + return result; + } + + public int executeUpdate() throws SQLException { + clearTime(); + + int result = statement.executeUpdate(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + ResultSet result = statement.executeQuery(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnNames); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnNames); + + log(type, sql); + + return result; + } + + + public void setNull(int parameterIndex, int sqlType) throws SQLException { + statement.setNull(parameterIndex, sqlType); + } + + public void setBoolean(int parameterIndex, boolean x) throws SQLException { + statement.setBoolean(parameterIndex, x); + } + + public void setByte(int parameterIndex, byte x) throws SQLException { + statement.setByte(parameterIndex, x); + } + + public void setShort(int parameterIndex, short x) throws SQLException { + statement.setShort(parameterIndex, x); + } + + public void setInt(int parameterIndex, int x) throws SQLException { + statement.setInt(parameterIndex, x); + } + + public void setLong(int parameterIndex, long x) throws SQLException { + statement.setLong(parameterIndex, x); + } + + public void setFloat(int parameterIndex, float x) throws SQLException { + statement.setFloat(parameterIndex, x); + } + + public void setDouble(int parameterIndex, double x) throws SQLException { + statement.setDouble(parameterIndex, x); + } + + public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { + statement.setBigDecimal(parameterIndex, x); + } + + public void setString(int parameterIndex, String x) throws SQLException { + statement.setString(parameterIndex, x); + } + + public void setBytes(int parameterIndex, byte x[]) throws SQLException { + statement.setBytes(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x) throws SQLException { + statement.setDate(parameterIndex, x); + } + + public void setTime(int parameterIndex, Time x) throws SQLException { + statement.setTime(parameterIndex, x); + } + + public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { + statement.setTimestamp(parameterIndex, x); + } + + public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setUnicodeStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType); + } + + public void setObject(int parameterIndex, Object x) throws SQLException { + statement.setObject(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setRef(int parameterIndex, Ref x) throws SQLException { + statement.setRef(parameterIndex, x); + } + + public void setBlob(int parameterIndex, Blob x) throws SQLException { + statement.setBlob(parameterIndex, x); + } + + public void setClob(int parameterIndex, Clob x) throws SQLException { + statement.setClob(parameterIndex, x); + } + + public void setArray(int parameterIndex, Array x) throws SQLException { + statement.setArray(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { + statement.setDate(parameterIndex, x, cal); + } + + public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { + statement.setTime(parameterIndex, x, cal); + } + + public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { + statement.setTimestamp(parameterIndex, x, cal); + } + + public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException { + statement.setNull(parameterIndex, sqlType, typeName); + } + + public void setURL(int parameterIndex, URL x) throws SQLException { + statement.setURL(parameterIndex, x); + } + + public void setRowId(int parameterIndex, RowId x) throws SQLException { + statement.setRowId(parameterIndex, x); + } + + public void setNString(int parameterIndex, String value) throws SQLException { + statement.setNString(parameterIndex, value); + } + + public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException { + statement.setNCharacterStream(parameterIndex, value, length); + } + + public void setNClob(int parameterIndex, NClob value) throws SQLException { + statement.setNClob(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setClob(parameterIndex, reader, length); + } + + public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException { + statement.setBlob(parameterIndex, inputStream, length); + } + + public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setNClob(parameterIndex, reader, length); + } + + public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException { + statement.setSQLXML(parameterIndex, xmlObject); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType, scaleOrLength); + } + + public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException { + statement.setAsciiStream(parameterIndex, x); + } + + public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException { + statement.setBinaryStream(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException { + statement.setCharacterStream(parameterIndex, reader); + } + + public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException { + statement.setNCharacterStream(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader) throws SQLException { + statement.setClob(parameterIndex, reader); + } + + public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException { + statement.setBlob(parameterIndex, inputStream); + } + + public void setNClob(int parameterIndex, Reader reader) throws SQLException { + statement.setNClob(parameterIndex, reader); + } + + + public void close() throws SQLException { + sql = ""; + type = QueryType.UNKNOWN; + milli = 0; + nano = 0; + + statement.close(); + } + + public ResultSetMetaData getMetaData() throws SQLException { + return statement.getMetaData(); + } + + public void clearParameters() throws SQLException { + statement.clearParameters(); + } + + public ParameterMetaData getParameterMetaData() throws SQLException { + return statement.getParameterMetaData(); + } + + public void addBatch() throws SQLException { + statement.addBatch(); + } + + public int getMaxFieldSize() throws SQLException { + return statement.getMaxFieldSize(); + } + + public void setMaxFieldSize(int max) throws SQLException { + statement.setMaxFieldSize(max); + } + + public int getMaxRows() throws SQLException { + return statement.getMaxRows(); + } + + public void setMaxRows(int max) throws SQLException { + statement.setMaxRows(max); + } + + public void setEscapeProcessing(boolean enable) throws SQLException { + statement.setEscapeProcessing(enable); + } + + public int getQueryTimeout() throws SQLException { + return statement.getQueryTimeout(); + } + + public void setQueryTimeout(int seconds) throws SQLException { + statement.setQueryTimeout(seconds); + } + + public void cancel() throws SQLException { + statement.cancel(); + } + + public SQLWarning getWarnings() throws SQLException { + return statement.getWarnings(); + } + + public void clearWarnings() throws SQLException { + statement.clearWarnings(); + } + + public void setCursorName(String name) throws SQLException { + statement.setCursorName(name); + } + + public boolean execute(String sql) throws SQLException { + return statement.execute(sql); + } + + public ResultSet getResultSet() throws SQLException { + return statement.getResultSet(); + } + + public int getUpdateCount() throws SQLException { + return statement.getUpdateCount(); + } + + public boolean getMoreResults() throws SQLException { + return statement.getMoreResults(); + } + + public void setFetchDirection(int direction) throws SQLException { + statement.setFetchDirection(direction); + } + + public int getFetchDirection() throws SQLException { + return statement.getFetchDirection(); + } + + public void setFetchSize(int rows) throws SQLException { + statement.setFetchSize(rows); + } + + public int getFetchSize() throws SQLException { + return statement.getFetchSize(); + } + + public int getResultSetConcurrency() throws SQLException { + return statement.getResultSetConcurrency(); + } + + public int getResultSetType() throws SQLException { + return statement.getResultSetType(); + } + + public void addBatch(String sql) throws SQLException { + statement.addBatch(sql); + } + + public void clearBatch() throws SQLException { + statement.clearBatch(); + } + + public int[] executeBatch() throws SQLException { + return statement.executeBatch(); + } + + public Connection getConnection() throws SQLException { + return statement.getConnection(); + } + + public boolean getMoreResults(int current) throws SQLException { + return statement.getMoreResults(current); + } + + public ResultSet getGeneratedKeys() throws SQLException { + return statement.getGeneratedKeys(); + } + + public int getResultSetHoldability() throws SQLException { + return statement.getResultSetHoldability(); + } + + public boolean isClosed() throws SQLException { + return statement.isClosed(); + } + + public void setPoolable(boolean poolable) throws SQLException { + statement.setPoolable(poolable); + } + + public boolean isPoolable() throws SQLException { + return statement.isPoolable(); + } + + @Override + public void closeOnCompletion() throws SQLException { + statement.closeOnCompletion();; + } + + @Override + public boolean isCloseOnCompletion() throws SQLException { + return statement.isCloseOnCompletion(); + } + + public T unwrap(Class iface) throws SQLException { + return statement.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return statement.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/QueryType.java b/src/nl/astraeus/jdbc/QueryType.java new file mode 100644 index 0000000..744fbfc --- /dev/null +++ b/src/nl/astraeus/jdbc/QueryType.java @@ -0,0 +1,24 @@ +package nl.astraeus.jdbc; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:32:49 PM + */ +public enum QueryType { + PLAIN("plain"), + PREPARED("prepared"), + CALLABLE("callable"), + UNKNOWN("unknown"); + + private String description; + + QueryType(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } + +} diff --git a/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java new file mode 100644 index 0000000..07aac40 --- /dev/null +++ b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java @@ -0,0 +1,68 @@ +package nl.astraeus.jdbc.example; + +import java.sql.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 7:32 PM + */ +public class JdbcStatisticsExample { + + + public static void main(String [] args) throws Exception { + Class.forName("org.h2.Driver"); + Class.forName("nl.astraeus.jdbc.Driver"); + + new JdbcStatisticsExample(); + } + + public JdbcStatisticsExample() throws Exception { + Connection conn = DriverManager.getConnection("jdbc:stat:jdbc:h2:mem:test"); + + Statement statement = null; + + statement = conn.createStatement(); + statement.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + + boolean running = true; + int count = 1; + PreparedStatement ps = null; + + while (running) { + Thread.sleep(10); + + String TableName = "TEST"+(System.nanoTime() % 1000); + + try { + ps = conn.prepareStatement("SELECT COUNT(*) FROM "+TableName); + ResultSet rs = ps.executeQuery(); + } catch (SQLException e) { + statement = conn.createStatement(); + statement.execute("CREATE TABLE "+TableName+" (ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + } finally { + if (ps!=null) { + ps.close(); + } + } + + ps = conn.prepareStatement("INSERT INTO "+TableName+" VALUES (?, ?)"); + + ps.setInt(1, count++); + ps.setString(2, "String "+System.currentTimeMillis()); + + ps.execute(); + ps.close(); + + Thread.sleep(10); + + ps = conn.prepareStatement("SELECT * FROM "+TableName); + ResultSet rs = ps.executeQuery(); + statement.close(); + } + + conn.close(); + } +} diff --git a/src/nl/astraeus/jdbc/util/IOUtils.java b/src/nl/astraeus/jdbc/util/IOUtils.java new file mode 100644 index 0000000..ce95d9d --- /dev/null +++ b/src/nl/astraeus/jdbc/util/IOUtils.java @@ -0,0 +1,38 @@ +package nl.astraeus.jdbc.util; + +import java.io.*; + +/** + * User: rnentjes + * Date: 4/9/12 + * Time: 2:33 PM + */ +public class IOUtils { + + public static String toString(InputStream in) throws IOException { + assert in != null; + + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + StringBuilder buffer = new StringBuilder(); + + while(reader.ready()) { + buffer.append(reader.readLine()); + buffer.append("\n"); + } + + return buffer.toString(); + } finally { + in.close(); + } + } + + public static void copy(InputStream in, OutputStream out) throws IOException { + byte [] buffer = new byte[1<<16]; + int bytes; + + while((bytes = in.read(buffer)) > 0) { + out.write(buffer, 0, bytes); + } + } +} diff --git a/src/nl/astraeus/jdbc/util/Util.java b/src/nl/astraeus/jdbc/util/Util.java new file mode 100644 index 0000000..eaa853b --- /dev/null +++ b/src/nl/astraeus/jdbc/util/Util.java @@ -0,0 +1,25 @@ +package nl.astraeus.jdbc.util; + +import java.text.DecimalFormat; +import java.text.NumberFormat; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 12:28 PM + */ +public class Util { + // utility functions + public static String formatNano(long l) { + NumberFormat format = new DecimalFormat("###,##0.000000"); + + return format.format((double) l / 1000000.0); + } + + public static void printMemoryUsage() { + System.out.println("Used memory: "+((Runtime.getRuntime().totalMemory() / (1024*1024))-(Runtime.getRuntime().freeMemory() / (1024*1024)))); + System.out.println("Free memory: "+(Runtime.getRuntime().freeMemory() / (1024*1024))); + System.out.println("Total memory: "+(Runtime.getRuntime().totalMemory() / (1024*1024))); + System.out.println("Max memory: "+(Runtime.getRuntime().maxMemory() / (1024*1024))); + } +} diff --git a/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java b/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java new file mode 100644 index 0000000..a162d6f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java @@ -0,0 +1,90 @@ +package nl.astraeus.jdbc.web; + +import nl.astraeus.jdbc.util.IOUtils; +import nl.astraeus.jdbc.util.Util; +import nl.astraeus.jdbc.web.page.Menu; +import nl.astraeus.jdbc.web.page.Page; +import nl.astraeus.jdbc.web.page.QueryOverview; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import java.io.IOException; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:05 PM + */ +public class JdbcStatisticsServlet extends HttpServlet { + + private String head; + private String bottom; + + @Override + public void init() throws ServletException { + super.init(); + + try { + head = IOUtils.toString(getClass().getResourceAsStream("head.html")); + bottom = IOUtils.toString(getClass().getResourceAsStream("bottom.html")); + } catch (IOException e) { + throw new ServletException(e); + } + + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + doPost(req, resp); + } + + @Override + protected void doPost(final HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + long nano = System.nanoTime(); + + HttpSession session = req.getSession(); + boolean ajax = "true".equals(req.getParameter("ajax")); + + resp.setContentType("text/html"); + + Page page = (Page)session.getAttribute("page"); + Page menu = (Page)session.getAttribute("menu"); + + session.setMaxInactiveInterval(1800); + + if (menu == null) { + menu = new Menu(); + + session.setAttribute("menu", menu); + } + + if (page == null || "menumain".equals(req.getParameter("action"))) { + page = new QueryOverview(); + } else if ("diagnostics".equals(req.getParameter("action"))) { + //page = new Diagnostics(); + } else { + page = page .processRequest(req); + } + + menu.processRequest(req); + + session.setAttribute("page", page); + + if (!ajax) { + resp.getWriter().print(head); + } + + resp.getWriter().print(menu.render(req)); + resp.getWriter().print(page.render(req)); + + if (!ajax) { + resp.getWriter().print(bottom); + } + + System.out.println("Request ends, time="+ Util.formatNano(System.nanoTime() - nano) +", page="+page.getClass().getSimpleName()); + } + +} diff --git a/src/nl/astraeus/jdbc/web/ResourceServlet.java b/src/nl/astraeus/jdbc/web/ResourceServlet.java new file mode 100644 index 0000000..7abfe6f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/ResourceServlet.java @@ -0,0 +1,49 @@ +package nl.astraeus.jdbc.web; + +import nl.astraeus.jdbc.util.IOUtils; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.InputStream; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:05 PM + */ +public class ResourceServlet extends HttpServlet { + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String uri = req.getRequestURI(); + + uri = "nl/astraeus/jdbc/web" + uri; + InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(uri); + + if (in == null) { + resp.sendError(404, "Cannot find resource '" + uri + "'."); + } else { + try { + if (uri.endsWith("js")) { + resp.setContentType("text/javascript"); + } else if (uri.endsWith("css")) { + resp.setContentType("text/css"); + } else if (uri.endsWith("png")) { + resp.setContentType("image/png"); + } else if (uri.endsWith("jpg")) { + resp.setContentType("image/jpeg"); + } else if (uri.endsWith("gif")) { + resp.setContentType("image/gif"); + } + + IOUtils.copy(in, resp.getOutputStream()); + } finally { + in.close(); + } + } + } + +} diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f403193 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..73ff239 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..3b00020 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..275077f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/README b/README deleted file mode 100644 index 734abaf..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -This file was created by IntelliJ IDEA 11.1.1 for binding GitHub repository \ No newline at end of file diff --git a/Simple-jdbc-statistics.iml b/Simple-jdbc-statistics.iml new file mode 100644 index 0000000..ca90a9b --- /dev/null +++ b/Simple-jdbc-statistics.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/lib/h2-1.3.166.jar b/lib/h2-1.3.166.jar new file mode 100644 index 0000000..4985063 --- /dev/null +++ b/lib/h2-1.3.166.jar Binary files differ diff --git a/lib/servlet-api-2.5.jar b/lib/servlet-api-2.5.jar new file mode 100644 index 0000000..20b5755 --- /dev/null +++ b/lib/servlet-api-2.5.jar Binary files differ diff --git a/lib/slf4j-api-1.6.4.jar b/lib/slf4j-api-1.6.4.jar new file mode 100644 index 0000000..4d23f41 --- /dev/null +++ b/lib/slf4j-api-1.6.4.jar Binary files differ diff --git a/lib/slf4j-simple-1.6.4.jar b/lib/slf4j-simple-1.6.4.jar new file mode 100644 index 0000000..3d1b8d9 --- /dev/null +++ b/lib/slf4j-simple-1.6.4.jar Binary files differ diff --git a/lib/ssr-0.1.jar b/lib/ssr-0.1.jar new file mode 100644 index 0000000..65dfcf4 --- /dev/null +++ b/lib/ssr-0.1.jar Binary files differ diff --git a/lib/vst-0.4.jar b/lib/vst-0.4.jar new file mode 100644 index 0000000..db63792 --- /dev/null +++ b/lib/vst-0.4.jar Binary files differ diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..ac2dbe1 --- /dev/null +++ b/readme.md @@ -0,0 +1 @@ +A simple wrapper around jdbc drivers what will show current jdbc stats of the running queries on a simple web page on port 18080. \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/ConnectionLogger.java b/src/nl/astraeus/jdbc/ConnectionLogger.java new file mode 100644 index 0000000..c3e243f --- /dev/null +++ b/src/nl/astraeus/jdbc/ConnectionLogger.java @@ -0,0 +1,279 @@ +package nl.astraeus.jdbc; + +import java.sql.*; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Executor; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:12:34 PM + */ +public class ConnectionLogger implements Connection { + private Connection connection; + + private long milli; + private long nano; + private String lastSql; + + public ConnectionLogger(Connection connection) { + this.connection = connection; + this.lastSql = ""; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(QueryType.UNKNOWN, sql, m, n); + } + + public void commit() throws SQLException { + clearTime(); + + connection.commit(); + + log("commit"); + } + + public void rollback() throws SQLException { + clearTime(); + + connection.rollback(); + + log("rollback"); + } + + public void close() throws SQLException { + clearTime(); + + connection.close(); + + log("close"); + } + + public PreparedStatement prepareStatement(String sql) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, autoGeneratedKeys); + } + + public PreparedStatement prepareStatement(String sql, int columnIndexes[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnIndexes); + } + + public PreparedStatement prepareStatement(String sql, String columnNames[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnNames); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public Statement createStatement() throws SQLException { + return connection.createStatement(); + } + + public CallableStatement prepareCall(String sql) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql); + } + + public String nativeSQL(String sql) throws SQLException { + lastSql = sql; + return connection.nativeSQL(sql); + } + + public void setAutoCommit(boolean autoCommit) throws SQLException { + connection.setAutoCommit(autoCommit); + } + + public boolean getAutoCommit() throws SQLException { + return connection.getAutoCommit(); + } + + public boolean isClosed() throws SQLException { + return connection.isClosed(); + } + + public DatabaseMetaData getMetaData() throws SQLException { + return connection.getMetaData(); + } + + public void setReadOnly(boolean readOnly) throws SQLException { + connection.setReadOnly(readOnly); + } + + public boolean isReadOnly() throws SQLException { + return connection.isReadOnly(); + } + + public void setCatalog(String catalog) throws SQLException { + connection.setCatalog(catalog); + } + + public String getCatalog() throws SQLException { + return connection.getCatalog(); + } + + public void setTransactionIsolation(int level) throws SQLException { + connection.setTransactionIsolation(level); + } + + public int getTransactionIsolation() throws SQLException { + return connection.getTransactionIsolation(); + } + + public SQLWarning getWarnings() throws SQLException { + return connection.getWarnings(); + } + + public void clearWarnings() throws SQLException { + connection.clearWarnings(); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency); + } + + public Map> getTypeMap() throws SQLException { + return connection.getTypeMap(); + } + + public void setTypeMap(Map> map) throws SQLException { + connection.setTypeMap(map); + } + + public void setHoldability(int holdability) throws SQLException { + connection.setHoldability(holdability); + } + + public int getHoldability() throws SQLException { + return connection.getHoldability(); + } + + public Savepoint setSavepoint() throws SQLException { + return connection.setSavepoint(); + } + + public Savepoint setSavepoint(String name) throws SQLException { + return connection.setSavepoint(name); + } + + public void rollback(Savepoint savepoint) throws SQLException { + connection.rollback(); + } + + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + connection.releaseSavepoint(savepoint); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public Clob createClob() throws SQLException { + return connection.createClob(); + } + + public Blob createBlob() throws SQLException { + return connection.createBlob(); + } + + public NClob createNClob() throws SQLException { + return connection.createNClob(); + } + + public SQLXML createSQLXML() throws SQLException { + return connection.createSQLXML(); + } + + public boolean isValid(int timeout) throws SQLException { + return connection.isValid(timeout); + } + + public void setClientInfo(String name, String value) throws SQLClientInfoException { + connection.setClientInfo(name, value); + } + + public void setClientInfo(Properties properties) throws SQLClientInfoException { + connection.setClientInfo(properties); + } + + public String getClientInfo(String name) throws SQLException { + return connection.getClientInfo(name); + } + + public Properties getClientInfo() throws SQLException { + return connection.getClientInfo(); + } + + public Array createArrayOf(String typeName, Object[] elements) throws SQLException { + return connection.createArrayOf(typeName, elements); + } + + public Struct createStruct(String typeName, Object[] attributes) throws SQLException { + return connection.createStruct(typeName, attributes); + } + + @Override + public void setSchema(String schema) throws SQLException { + connection.setSchema(schema); + } + + @Override + public String getSchema() throws SQLException { + return connection.getSchema(); + } + + @Override + public void abort(Executor executor) throws SQLException { + connection.abort(executor); + } + + @Override + public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { + connection.setNetworkTimeout(executor, milliseconds); + } + + @Override + public int getNetworkTimeout() throws SQLException { + return connection.getNetworkTimeout(); + } + + public T unwrap(Class iface) throws SQLException { + return connection.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return connection.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/Driver.java b/src/nl/astraeus/jdbc/Driver.java new file mode 100644 index 0000000..8317172 --- /dev/null +++ b/src/nl/astraeus/jdbc/Driver.java @@ -0,0 +1,116 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.http.SimpleWebServer; +import nl.astraeus.jdbc.web.JdbcStatisticsServlet; +import nl.astraeus.jdbc.web.ResourceServlet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.*; +import java.util.Enumeration; +import java.util.Properties; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:54:37 PM + */ +public class Driver implements java.sql.Driver { + private final static Logger log = LoggerFactory.getLogger(Driver.class); + + final private static String URL_PREFIX = "jdbc:stat:"; + + private java.sql.Driver driver = null; + private String[] drivers = { + "org.postgresql.Driver", + "oracle.jdbc.driver.OracleDriver", + "com.sybase.jdbc2.jdbc.SybDriver", + "net.sourceforge.jtds.jdbc.Driver", + "com.microsoft.jdbc.sqlserver.SQLServerDriver", + "com.microsoft.sqlserver.jdbc.SQLServerDriver", + "weblogic.jdbc.sqlserver.SQLServerDriver", + "com.informix.jdbc.IfxDriver", + "org.apache.derby.jdbc.ClientDriver", + "org.apache.derby.jdbc.EmbeddedDriver", + "com.mysql.jdbc.Driver", + "org.hsqldb.jdbcDriver", + "org.h2.Driver" }; + + static { + log.debug("Loading driver class " + Driver.class.getName()); + + try { + DriverManager.registerDriver(new Driver()); + } catch (SQLException e) { + log.error("", e); + } + } + + public Driver() { + for (String dr : drivers) { + try { + Class.forName(dr); + } catch (Throwable e) { + log.debug("Can't instantiate driver: " + dr, e); + } + } + } + + private java.sql.Driver findDriver(String url) throws SQLException { + Enumeration e = DriverManager.getDrivers(); + + while (e.hasMoreElements()) { + java.sql.Driver d = (java.sql.Driver) e.nextElement(); + + if (d.acceptsURL(url)) { + return d; + } + } + + throw new SQLException("Driver not found: " + url); + } + + public Connection connect(String url, Properties info) throws SQLException { + url = url.substring(URL_PREFIX.length()); + + if (driver == null) { + driver = findDriver(url); + } + + if (driver != null) { + SimpleWebServer server = new SimpleWebServer(18080); + + server.addServlet(new JdbcStatisticsServlet(), "/"); + server.addServlet(new ResourceServlet(), "/resources/*"); + + server.start(); + } + + return new ConnectionLogger(driver.connect(url, info)); + } + + public boolean acceptsURL(String url) throws SQLException { + return (url != null && url.startsWith(URL_PREFIX)); + } + + public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { + return driver.getPropertyInfo(url, info); + } + + public int getMajorVersion() { + return driver.getMajorVersion(); + } + + public int getMinorVersion() { + return driver.getMinorVersion(); + } + + public boolean jdbcCompliant() { + return driver.jdbcCompliant(); + } + + @Override + public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException { + return driver.getParentLogger(); + } +} diff --git a/src/nl/astraeus/jdbc/JdbcLogger.java b/src/nl/astraeus/jdbc/JdbcLogger.java new file mode 100644 index 0000000..f4bc125 --- /dev/null +++ b/src/nl/astraeus/jdbc/JdbcLogger.java @@ -0,0 +1,113 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.jdbc.util.Util; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/** + * User: riennentjes + * Date: Jul 12, 2008 + * Time: 9:15:21 AM + */ +public class JdbcLogger { + private final static Logger logger = LoggerFactory.getLogger(JdbcLogger.class); + + private final static JdbcLogger instance = new JdbcLogger(); + + public static JdbcLogger get() { + return instance; + } + + public final static class LogEntry { + public QueryType type; + public String sql; + public long milli; + public long nano; + public int count; + public int hash; + + public LogEntry(int hash, QueryType type, String sql, long milli, long nano) { + this.hash = hash; + this.type = type; + this.sql = sql; + this.milli = milli; + this.nano = nano; + this.count = 1; + } + + public void addCount(long milli, long nano) { + synchronized (this) { + count++; + this.milli += milli; + this.nano += nano; + } + } + + public int getCount() { + return count; + } + + public String getMilli() { + return Util.formatNano(milli*1000000/count); + } + + public String getNano() { + return Util.formatNano(nano/count); + } + + public String getTotal() { + return Util.formatNano(nano); + } + + public String getSql() { + return sql; + } + } + + private Map queries; + + public JdbcLogger() { + queries = new ConcurrentHashMap(); + } + + public void logEntry(QueryType type, String sql, long milli, long nano) { + int hash = sql.hashCode(); + LogEntry entry = queries.get(hash); + + if (entry == null) { + entry = new LogEntry(hash, type, sql, milli, nano); + queries.put(hash, entry); + } else { + entry.addCount(milli, nano); + } + + if (queries.size() > 1000) { + List toRemove = new LinkedList(); + List values = new LinkedList(queries.values()); + + Collections.sort(values, new Comparator() { + @Override + public int compare(LogEntry o1, LogEntry o2) { + return o1.count - o2.count; + } + }); + + while (queries.size() > 900) { + queries.remove(values.remove(0).hash); + + } + } + } + + public static void log(QueryType type, String sql, long milli, long nano) { + instance.logEntry(type, sql, milli, nano); + } + + public Collection getEntries() { + return queries.values(); + } + +} diff --git a/src/nl/astraeus/jdbc/PreparedStatementLogger.java b/src/nl/astraeus/jdbc/PreparedStatementLogger.java new file mode 100644 index 0000000..98aefc7 --- /dev/null +++ b/src/nl/astraeus/jdbc/PreparedStatementLogger.java @@ -0,0 +1,577 @@ +package nl.astraeus.jdbc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.InputStream; +import java.io.Reader; +import java.math.BigDecimal; +import java.net.URL; +import java.sql.*; +import java.util.Calendar; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 7:47:57 PM + */ +public class PreparedStatementLogger implements PreparedStatement { + private final static Logger log = LoggerFactory.getLogger(PreparedStatementLogger.class); + + private PreparedStatement statement; + + private String sql; + private QueryType type; + private long milli; + private long nano; + + //private ArrayList parameters; + + public PreparedStatementLogger(PreparedStatement statement) { + this.statement = statement; + this.sql = ""; + this.type = QueryType.UNKNOWN; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(QueryType type, String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(type, sql, m, n); + } + + public PreparedStatementLogger(Connection connection, String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql); + } + + public PreparedStatementLogger(Connection connection, String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatementLogger(Connection connection, String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, autoGeneratedKeys); + } + + public PreparedStatementLogger(Connection connection, String sql, int[] columnIndexes) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnIndexes); + } + + public PreparedStatementLogger(Connection connection, String sql, String[] columnNames) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnNames); + } + + public boolean execute() throws SQLException { + clearTime(); + + boolean result = statement.execute(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery() throws SQLException { + clearTime(); + + ResultSet result = statement.executeQuery(); + + log(type, sql); + + return result; + } + + public int executeUpdate() throws SQLException { + clearTime(); + + int result = statement.executeUpdate(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + ResultSet result = statement.executeQuery(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnNames); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnNames); + + log(type, sql); + + return result; + } + + + public void setNull(int parameterIndex, int sqlType) throws SQLException { + statement.setNull(parameterIndex, sqlType); + } + + public void setBoolean(int parameterIndex, boolean x) throws SQLException { + statement.setBoolean(parameterIndex, x); + } + + public void setByte(int parameterIndex, byte x) throws SQLException { + statement.setByte(parameterIndex, x); + } + + public void setShort(int parameterIndex, short x) throws SQLException { + statement.setShort(parameterIndex, x); + } + + public void setInt(int parameterIndex, int x) throws SQLException { + statement.setInt(parameterIndex, x); + } + + public void setLong(int parameterIndex, long x) throws SQLException { + statement.setLong(parameterIndex, x); + } + + public void setFloat(int parameterIndex, float x) throws SQLException { + statement.setFloat(parameterIndex, x); + } + + public void setDouble(int parameterIndex, double x) throws SQLException { + statement.setDouble(parameterIndex, x); + } + + public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { + statement.setBigDecimal(parameterIndex, x); + } + + public void setString(int parameterIndex, String x) throws SQLException { + statement.setString(parameterIndex, x); + } + + public void setBytes(int parameterIndex, byte x[]) throws SQLException { + statement.setBytes(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x) throws SQLException { + statement.setDate(parameterIndex, x); + } + + public void setTime(int parameterIndex, Time x) throws SQLException { + statement.setTime(parameterIndex, x); + } + + public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { + statement.setTimestamp(parameterIndex, x); + } + + public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setUnicodeStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType); + } + + public void setObject(int parameterIndex, Object x) throws SQLException { + statement.setObject(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setRef(int parameterIndex, Ref x) throws SQLException { + statement.setRef(parameterIndex, x); + } + + public void setBlob(int parameterIndex, Blob x) throws SQLException { + statement.setBlob(parameterIndex, x); + } + + public void setClob(int parameterIndex, Clob x) throws SQLException { + statement.setClob(parameterIndex, x); + } + + public void setArray(int parameterIndex, Array x) throws SQLException { + statement.setArray(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { + statement.setDate(parameterIndex, x, cal); + } + + public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { + statement.setTime(parameterIndex, x, cal); + } + + public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { + statement.setTimestamp(parameterIndex, x, cal); + } + + public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException { + statement.setNull(parameterIndex, sqlType, typeName); + } + + public void setURL(int parameterIndex, URL x) throws SQLException { + statement.setURL(parameterIndex, x); + } + + public void setRowId(int parameterIndex, RowId x) throws SQLException { + statement.setRowId(parameterIndex, x); + } + + public void setNString(int parameterIndex, String value) throws SQLException { + statement.setNString(parameterIndex, value); + } + + public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException { + statement.setNCharacterStream(parameterIndex, value, length); + } + + public void setNClob(int parameterIndex, NClob value) throws SQLException { + statement.setNClob(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setClob(parameterIndex, reader, length); + } + + public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException { + statement.setBlob(parameterIndex, inputStream, length); + } + + public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setNClob(parameterIndex, reader, length); + } + + public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException { + statement.setSQLXML(parameterIndex, xmlObject); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType, scaleOrLength); + } + + public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException { + statement.setAsciiStream(parameterIndex, x); + } + + public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException { + statement.setBinaryStream(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException { + statement.setCharacterStream(parameterIndex, reader); + } + + public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException { + statement.setNCharacterStream(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader) throws SQLException { + statement.setClob(parameterIndex, reader); + } + + public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException { + statement.setBlob(parameterIndex, inputStream); + } + + public void setNClob(int parameterIndex, Reader reader) throws SQLException { + statement.setNClob(parameterIndex, reader); + } + + + public void close() throws SQLException { + sql = ""; + type = QueryType.UNKNOWN; + milli = 0; + nano = 0; + + statement.close(); + } + + public ResultSetMetaData getMetaData() throws SQLException { + return statement.getMetaData(); + } + + public void clearParameters() throws SQLException { + statement.clearParameters(); + } + + public ParameterMetaData getParameterMetaData() throws SQLException { + return statement.getParameterMetaData(); + } + + public void addBatch() throws SQLException { + statement.addBatch(); + } + + public int getMaxFieldSize() throws SQLException { + return statement.getMaxFieldSize(); + } + + public void setMaxFieldSize(int max) throws SQLException { + statement.setMaxFieldSize(max); + } + + public int getMaxRows() throws SQLException { + return statement.getMaxRows(); + } + + public void setMaxRows(int max) throws SQLException { + statement.setMaxRows(max); + } + + public void setEscapeProcessing(boolean enable) throws SQLException { + statement.setEscapeProcessing(enable); + } + + public int getQueryTimeout() throws SQLException { + return statement.getQueryTimeout(); + } + + public void setQueryTimeout(int seconds) throws SQLException { + statement.setQueryTimeout(seconds); + } + + public void cancel() throws SQLException { + statement.cancel(); + } + + public SQLWarning getWarnings() throws SQLException { + return statement.getWarnings(); + } + + public void clearWarnings() throws SQLException { + statement.clearWarnings(); + } + + public void setCursorName(String name) throws SQLException { + statement.setCursorName(name); + } + + public boolean execute(String sql) throws SQLException { + return statement.execute(sql); + } + + public ResultSet getResultSet() throws SQLException { + return statement.getResultSet(); + } + + public int getUpdateCount() throws SQLException { + return statement.getUpdateCount(); + } + + public boolean getMoreResults() throws SQLException { + return statement.getMoreResults(); + } + + public void setFetchDirection(int direction) throws SQLException { + statement.setFetchDirection(direction); + } + + public int getFetchDirection() throws SQLException { + return statement.getFetchDirection(); + } + + public void setFetchSize(int rows) throws SQLException { + statement.setFetchSize(rows); + } + + public int getFetchSize() throws SQLException { + return statement.getFetchSize(); + } + + public int getResultSetConcurrency() throws SQLException { + return statement.getResultSetConcurrency(); + } + + public int getResultSetType() throws SQLException { + return statement.getResultSetType(); + } + + public void addBatch(String sql) throws SQLException { + statement.addBatch(sql); + } + + public void clearBatch() throws SQLException { + statement.clearBatch(); + } + + public int[] executeBatch() throws SQLException { + return statement.executeBatch(); + } + + public Connection getConnection() throws SQLException { + return statement.getConnection(); + } + + public boolean getMoreResults(int current) throws SQLException { + return statement.getMoreResults(current); + } + + public ResultSet getGeneratedKeys() throws SQLException { + return statement.getGeneratedKeys(); + } + + public int getResultSetHoldability() throws SQLException { + return statement.getResultSetHoldability(); + } + + public boolean isClosed() throws SQLException { + return statement.isClosed(); + } + + public void setPoolable(boolean poolable) throws SQLException { + statement.setPoolable(poolable); + } + + public boolean isPoolable() throws SQLException { + return statement.isPoolable(); + } + + @Override + public void closeOnCompletion() throws SQLException { + statement.closeOnCompletion();; + } + + @Override + public boolean isCloseOnCompletion() throws SQLException { + return statement.isCloseOnCompletion(); + } + + public T unwrap(Class iface) throws SQLException { + return statement.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return statement.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/QueryType.java b/src/nl/astraeus/jdbc/QueryType.java new file mode 100644 index 0000000..744fbfc --- /dev/null +++ b/src/nl/astraeus/jdbc/QueryType.java @@ -0,0 +1,24 @@ +package nl.astraeus.jdbc; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:32:49 PM + */ +public enum QueryType { + PLAIN("plain"), + PREPARED("prepared"), + CALLABLE("callable"), + UNKNOWN("unknown"); + + private String description; + + QueryType(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } + +} diff --git a/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java new file mode 100644 index 0000000..07aac40 --- /dev/null +++ b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java @@ -0,0 +1,68 @@ +package nl.astraeus.jdbc.example; + +import java.sql.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 7:32 PM + */ +public class JdbcStatisticsExample { + + + public static void main(String [] args) throws Exception { + Class.forName("org.h2.Driver"); + Class.forName("nl.astraeus.jdbc.Driver"); + + new JdbcStatisticsExample(); + } + + public JdbcStatisticsExample() throws Exception { + Connection conn = DriverManager.getConnection("jdbc:stat:jdbc:h2:mem:test"); + + Statement statement = null; + + statement = conn.createStatement(); + statement.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + + boolean running = true; + int count = 1; + PreparedStatement ps = null; + + while (running) { + Thread.sleep(10); + + String TableName = "TEST"+(System.nanoTime() % 1000); + + try { + ps = conn.prepareStatement("SELECT COUNT(*) FROM "+TableName); + ResultSet rs = ps.executeQuery(); + } catch (SQLException e) { + statement = conn.createStatement(); + statement.execute("CREATE TABLE "+TableName+" (ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + } finally { + if (ps!=null) { + ps.close(); + } + } + + ps = conn.prepareStatement("INSERT INTO "+TableName+" VALUES (?, ?)"); + + ps.setInt(1, count++); + ps.setString(2, "String "+System.currentTimeMillis()); + + ps.execute(); + ps.close(); + + Thread.sleep(10); + + ps = conn.prepareStatement("SELECT * FROM "+TableName); + ResultSet rs = ps.executeQuery(); + statement.close(); + } + + conn.close(); + } +} diff --git a/src/nl/astraeus/jdbc/util/IOUtils.java b/src/nl/astraeus/jdbc/util/IOUtils.java new file mode 100644 index 0000000..ce95d9d --- /dev/null +++ b/src/nl/astraeus/jdbc/util/IOUtils.java @@ -0,0 +1,38 @@ +package nl.astraeus.jdbc.util; + +import java.io.*; + +/** + * User: rnentjes + * Date: 4/9/12 + * Time: 2:33 PM + */ +public class IOUtils { + + public static String toString(InputStream in) throws IOException { + assert in != null; + + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + StringBuilder buffer = new StringBuilder(); + + while(reader.ready()) { + buffer.append(reader.readLine()); + buffer.append("\n"); + } + + return buffer.toString(); + } finally { + in.close(); + } + } + + public static void copy(InputStream in, OutputStream out) throws IOException { + byte [] buffer = new byte[1<<16]; + int bytes; + + while((bytes = in.read(buffer)) > 0) { + out.write(buffer, 0, bytes); + } + } +} diff --git a/src/nl/astraeus/jdbc/util/Util.java b/src/nl/astraeus/jdbc/util/Util.java new file mode 100644 index 0000000..eaa853b --- /dev/null +++ b/src/nl/astraeus/jdbc/util/Util.java @@ -0,0 +1,25 @@ +package nl.astraeus.jdbc.util; + +import java.text.DecimalFormat; +import java.text.NumberFormat; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 12:28 PM + */ +public class Util { + // utility functions + public static String formatNano(long l) { + NumberFormat format = new DecimalFormat("###,##0.000000"); + + return format.format((double) l / 1000000.0); + } + + public static void printMemoryUsage() { + System.out.println("Used memory: "+((Runtime.getRuntime().totalMemory() / (1024*1024))-(Runtime.getRuntime().freeMemory() / (1024*1024)))); + System.out.println("Free memory: "+(Runtime.getRuntime().freeMemory() / (1024*1024))); + System.out.println("Total memory: "+(Runtime.getRuntime().totalMemory() / (1024*1024))); + System.out.println("Max memory: "+(Runtime.getRuntime().maxMemory() / (1024*1024))); + } +} diff --git a/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java b/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java new file mode 100644 index 0000000..a162d6f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java @@ -0,0 +1,90 @@ +package nl.astraeus.jdbc.web; + +import nl.astraeus.jdbc.util.IOUtils; +import nl.astraeus.jdbc.util.Util; +import nl.astraeus.jdbc.web.page.Menu; +import nl.astraeus.jdbc.web.page.Page; +import nl.astraeus.jdbc.web.page.QueryOverview; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import java.io.IOException; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:05 PM + */ +public class JdbcStatisticsServlet extends HttpServlet { + + private String head; + private String bottom; + + @Override + public void init() throws ServletException { + super.init(); + + try { + head = IOUtils.toString(getClass().getResourceAsStream("head.html")); + bottom = IOUtils.toString(getClass().getResourceAsStream("bottom.html")); + } catch (IOException e) { + throw new ServletException(e); + } + + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + doPost(req, resp); + } + + @Override + protected void doPost(final HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + long nano = System.nanoTime(); + + HttpSession session = req.getSession(); + boolean ajax = "true".equals(req.getParameter("ajax")); + + resp.setContentType("text/html"); + + Page page = (Page)session.getAttribute("page"); + Page menu = (Page)session.getAttribute("menu"); + + session.setMaxInactiveInterval(1800); + + if (menu == null) { + menu = new Menu(); + + session.setAttribute("menu", menu); + } + + if (page == null || "menumain".equals(req.getParameter("action"))) { + page = new QueryOverview(); + } else if ("diagnostics".equals(req.getParameter("action"))) { + //page = new Diagnostics(); + } else { + page = page .processRequest(req); + } + + menu.processRequest(req); + + session.setAttribute("page", page); + + if (!ajax) { + resp.getWriter().print(head); + } + + resp.getWriter().print(menu.render(req)); + resp.getWriter().print(page.render(req)); + + if (!ajax) { + resp.getWriter().print(bottom); + } + + System.out.println("Request ends, time="+ Util.formatNano(System.nanoTime() - nano) +", page="+page.getClass().getSimpleName()); + } + +} diff --git a/src/nl/astraeus/jdbc/web/ResourceServlet.java b/src/nl/astraeus/jdbc/web/ResourceServlet.java new file mode 100644 index 0000000..7abfe6f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/ResourceServlet.java @@ -0,0 +1,49 @@ +package nl.astraeus.jdbc.web; + +import nl.astraeus.jdbc.util.IOUtils; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.InputStream; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:05 PM + */ +public class ResourceServlet extends HttpServlet { + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String uri = req.getRequestURI(); + + uri = "nl/astraeus/jdbc/web" + uri; + InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(uri); + + if (in == null) { + resp.sendError(404, "Cannot find resource '" + uri + "'."); + } else { + try { + if (uri.endsWith("js")) { + resp.setContentType("text/javascript"); + } else if (uri.endsWith("css")) { + resp.setContentType("text/css"); + } else if (uri.endsWith("png")) { + resp.setContentType("image/png"); + } else if (uri.endsWith("jpg")) { + resp.setContentType("image/jpeg"); + } else if (uri.endsWith("gif")) { + resp.setContentType("image/gif"); + } + + IOUtils.copy(in, resp.getOutputStream()); + } finally { + in.close(); + } + } + } + +} diff --git a/src/nl/astraeus/jdbc/web/bottom.html b/src/nl/astraeus/jdbc/web/bottom.html new file mode 100644 index 0000000..1288de4 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/bottom.html @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f403193 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..73ff239 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..3b00020 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..275077f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/README b/README deleted file mode 100644 index 734abaf..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -This file was created by IntelliJ IDEA 11.1.1 for binding GitHub repository \ No newline at end of file diff --git a/Simple-jdbc-statistics.iml b/Simple-jdbc-statistics.iml new file mode 100644 index 0000000..ca90a9b --- /dev/null +++ b/Simple-jdbc-statistics.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/lib/h2-1.3.166.jar b/lib/h2-1.3.166.jar new file mode 100644 index 0000000..4985063 --- /dev/null +++ b/lib/h2-1.3.166.jar Binary files differ diff --git a/lib/servlet-api-2.5.jar b/lib/servlet-api-2.5.jar new file mode 100644 index 0000000..20b5755 --- /dev/null +++ b/lib/servlet-api-2.5.jar Binary files differ diff --git a/lib/slf4j-api-1.6.4.jar b/lib/slf4j-api-1.6.4.jar new file mode 100644 index 0000000..4d23f41 --- /dev/null +++ b/lib/slf4j-api-1.6.4.jar Binary files differ diff --git a/lib/slf4j-simple-1.6.4.jar b/lib/slf4j-simple-1.6.4.jar new file mode 100644 index 0000000..3d1b8d9 --- /dev/null +++ b/lib/slf4j-simple-1.6.4.jar Binary files differ diff --git a/lib/ssr-0.1.jar b/lib/ssr-0.1.jar new file mode 100644 index 0000000..65dfcf4 --- /dev/null +++ b/lib/ssr-0.1.jar Binary files differ diff --git a/lib/vst-0.4.jar b/lib/vst-0.4.jar new file mode 100644 index 0000000..db63792 --- /dev/null +++ b/lib/vst-0.4.jar Binary files differ diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..ac2dbe1 --- /dev/null +++ b/readme.md @@ -0,0 +1 @@ +A simple wrapper around jdbc drivers what will show current jdbc stats of the running queries on a simple web page on port 18080. \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/ConnectionLogger.java b/src/nl/astraeus/jdbc/ConnectionLogger.java new file mode 100644 index 0000000..c3e243f --- /dev/null +++ b/src/nl/astraeus/jdbc/ConnectionLogger.java @@ -0,0 +1,279 @@ +package nl.astraeus.jdbc; + +import java.sql.*; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Executor; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:12:34 PM + */ +public class ConnectionLogger implements Connection { + private Connection connection; + + private long milli; + private long nano; + private String lastSql; + + public ConnectionLogger(Connection connection) { + this.connection = connection; + this.lastSql = ""; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(QueryType.UNKNOWN, sql, m, n); + } + + public void commit() throws SQLException { + clearTime(); + + connection.commit(); + + log("commit"); + } + + public void rollback() throws SQLException { + clearTime(); + + connection.rollback(); + + log("rollback"); + } + + public void close() throws SQLException { + clearTime(); + + connection.close(); + + log("close"); + } + + public PreparedStatement prepareStatement(String sql) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, autoGeneratedKeys); + } + + public PreparedStatement prepareStatement(String sql, int columnIndexes[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnIndexes); + } + + public PreparedStatement prepareStatement(String sql, String columnNames[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnNames); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public Statement createStatement() throws SQLException { + return connection.createStatement(); + } + + public CallableStatement prepareCall(String sql) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql); + } + + public String nativeSQL(String sql) throws SQLException { + lastSql = sql; + return connection.nativeSQL(sql); + } + + public void setAutoCommit(boolean autoCommit) throws SQLException { + connection.setAutoCommit(autoCommit); + } + + public boolean getAutoCommit() throws SQLException { + return connection.getAutoCommit(); + } + + public boolean isClosed() throws SQLException { + return connection.isClosed(); + } + + public DatabaseMetaData getMetaData() throws SQLException { + return connection.getMetaData(); + } + + public void setReadOnly(boolean readOnly) throws SQLException { + connection.setReadOnly(readOnly); + } + + public boolean isReadOnly() throws SQLException { + return connection.isReadOnly(); + } + + public void setCatalog(String catalog) throws SQLException { + connection.setCatalog(catalog); + } + + public String getCatalog() throws SQLException { + return connection.getCatalog(); + } + + public void setTransactionIsolation(int level) throws SQLException { + connection.setTransactionIsolation(level); + } + + public int getTransactionIsolation() throws SQLException { + return connection.getTransactionIsolation(); + } + + public SQLWarning getWarnings() throws SQLException { + return connection.getWarnings(); + } + + public void clearWarnings() throws SQLException { + connection.clearWarnings(); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency); + } + + public Map> getTypeMap() throws SQLException { + return connection.getTypeMap(); + } + + public void setTypeMap(Map> map) throws SQLException { + connection.setTypeMap(map); + } + + public void setHoldability(int holdability) throws SQLException { + connection.setHoldability(holdability); + } + + public int getHoldability() throws SQLException { + return connection.getHoldability(); + } + + public Savepoint setSavepoint() throws SQLException { + return connection.setSavepoint(); + } + + public Savepoint setSavepoint(String name) throws SQLException { + return connection.setSavepoint(name); + } + + public void rollback(Savepoint savepoint) throws SQLException { + connection.rollback(); + } + + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + connection.releaseSavepoint(savepoint); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public Clob createClob() throws SQLException { + return connection.createClob(); + } + + public Blob createBlob() throws SQLException { + return connection.createBlob(); + } + + public NClob createNClob() throws SQLException { + return connection.createNClob(); + } + + public SQLXML createSQLXML() throws SQLException { + return connection.createSQLXML(); + } + + public boolean isValid(int timeout) throws SQLException { + return connection.isValid(timeout); + } + + public void setClientInfo(String name, String value) throws SQLClientInfoException { + connection.setClientInfo(name, value); + } + + public void setClientInfo(Properties properties) throws SQLClientInfoException { + connection.setClientInfo(properties); + } + + public String getClientInfo(String name) throws SQLException { + return connection.getClientInfo(name); + } + + public Properties getClientInfo() throws SQLException { + return connection.getClientInfo(); + } + + public Array createArrayOf(String typeName, Object[] elements) throws SQLException { + return connection.createArrayOf(typeName, elements); + } + + public Struct createStruct(String typeName, Object[] attributes) throws SQLException { + return connection.createStruct(typeName, attributes); + } + + @Override + public void setSchema(String schema) throws SQLException { + connection.setSchema(schema); + } + + @Override + public String getSchema() throws SQLException { + return connection.getSchema(); + } + + @Override + public void abort(Executor executor) throws SQLException { + connection.abort(executor); + } + + @Override + public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { + connection.setNetworkTimeout(executor, milliseconds); + } + + @Override + public int getNetworkTimeout() throws SQLException { + return connection.getNetworkTimeout(); + } + + public T unwrap(Class iface) throws SQLException { + return connection.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return connection.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/Driver.java b/src/nl/astraeus/jdbc/Driver.java new file mode 100644 index 0000000..8317172 --- /dev/null +++ b/src/nl/astraeus/jdbc/Driver.java @@ -0,0 +1,116 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.http.SimpleWebServer; +import nl.astraeus.jdbc.web.JdbcStatisticsServlet; +import nl.astraeus.jdbc.web.ResourceServlet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.*; +import java.util.Enumeration; +import java.util.Properties; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:54:37 PM + */ +public class Driver implements java.sql.Driver { + private final static Logger log = LoggerFactory.getLogger(Driver.class); + + final private static String URL_PREFIX = "jdbc:stat:"; + + private java.sql.Driver driver = null; + private String[] drivers = { + "org.postgresql.Driver", + "oracle.jdbc.driver.OracleDriver", + "com.sybase.jdbc2.jdbc.SybDriver", + "net.sourceforge.jtds.jdbc.Driver", + "com.microsoft.jdbc.sqlserver.SQLServerDriver", + "com.microsoft.sqlserver.jdbc.SQLServerDriver", + "weblogic.jdbc.sqlserver.SQLServerDriver", + "com.informix.jdbc.IfxDriver", + "org.apache.derby.jdbc.ClientDriver", + "org.apache.derby.jdbc.EmbeddedDriver", + "com.mysql.jdbc.Driver", + "org.hsqldb.jdbcDriver", + "org.h2.Driver" }; + + static { + log.debug("Loading driver class " + Driver.class.getName()); + + try { + DriverManager.registerDriver(new Driver()); + } catch (SQLException e) { + log.error("", e); + } + } + + public Driver() { + for (String dr : drivers) { + try { + Class.forName(dr); + } catch (Throwable e) { + log.debug("Can't instantiate driver: " + dr, e); + } + } + } + + private java.sql.Driver findDriver(String url) throws SQLException { + Enumeration e = DriverManager.getDrivers(); + + while (e.hasMoreElements()) { + java.sql.Driver d = (java.sql.Driver) e.nextElement(); + + if (d.acceptsURL(url)) { + return d; + } + } + + throw new SQLException("Driver not found: " + url); + } + + public Connection connect(String url, Properties info) throws SQLException { + url = url.substring(URL_PREFIX.length()); + + if (driver == null) { + driver = findDriver(url); + } + + if (driver != null) { + SimpleWebServer server = new SimpleWebServer(18080); + + server.addServlet(new JdbcStatisticsServlet(), "/"); + server.addServlet(new ResourceServlet(), "/resources/*"); + + server.start(); + } + + return new ConnectionLogger(driver.connect(url, info)); + } + + public boolean acceptsURL(String url) throws SQLException { + return (url != null && url.startsWith(URL_PREFIX)); + } + + public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { + return driver.getPropertyInfo(url, info); + } + + public int getMajorVersion() { + return driver.getMajorVersion(); + } + + public int getMinorVersion() { + return driver.getMinorVersion(); + } + + public boolean jdbcCompliant() { + return driver.jdbcCompliant(); + } + + @Override + public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException { + return driver.getParentLogger(); + } +} diff --git a/src/nl/astraeus/jdbc/JdbcLogger.java b/src/nl/astraeus/jdbc/JdbcLogger.java new file mode 100644 index 0000000..f4bc125 --- /dev/null +++ b/src/nl/astraeus/jdbc/JdbcLogger.java @@ -0,0 +1,113 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.jdbc.util.Util; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/** + * User: riennentjes + * Date: Jul 12, 2008 + * Time: 9:15:21 AM + */ +public class JdbcLogger { + private final static Logger logger = LoggerFactory.getLogger(JdbcLogger.class); + + private final static JdbcLogger instance = new JdbcLogger(); + + public static JdbcLogger get() { + return instance; + } + + public final static class LogEntry { + public QueryType type; + public String sql; + public long milli; + public long nano; + public int count; + public int hash; + + public LogEntry(int hash, QueryType type, String sql, long milli, long nano) { + this.hash = hash; + this.type = type; + this.sql = sql; + this.milli = milli; + this.nano = nano; + this.count = 1; + } + + public void addCount(long milli, long nano) { + synchronized (this) { + count++; + this.milli += milli; + this.nano += nano; + } + } + + public int getCount() { + return count; + } + + public String getMilli() { + return Util.formatNano(milli*1000000/count); + } + + public String getNano() { + return Util.formatNano(nano/count); + } + + public String getTotal() { + return Util.formatNano(nano); + } + + public String getSql() { + return sql; + } + } + + private Map queries; + + public JdbcLogger() { + queries = new ConcurrentHashMap(); + } + + public void logEntry(QueryType type, String sql, long milli, long nano) { + int hash = sql.hashCode(); + LogEntry entry = queries.get(hash); + + if (entry == null) { + entry = new LogEntry(hash, type, sql, milli, nano); + queries.put(hash, entry); + } else { + entry.addCount(milli, nano); + } + + if (queries.size() > 1000) { + List toRemove = new LinkedList(); + List values = new LinkedList(queries.values()); + + Collections.sort(values, new Comparator() { + @Override + public int compare(LogEntry o1, LogEntry o2) { + return o1.count - o2.count; + } + }); + + while (queries.size() > 900) { + queries.remove(values.remove(0).hash); + + } + } + } + + public static void log(QueryType type, String sql, long milli, long nano) { + instance.logEntry(type, sql, milli, nano); + } + + public Collection getEntries() { + return queries.values(); + } + +} diff --git a/src/nl/astraeus/jdbc/PreparedStatementLogger.java b/src/nl/astraeus/jdbc/PreparedStatementLogger.java new file mode 100644 index 0000000..98aefc7 --- /dev/null +++ b/src/nl/astraeus/jdbc/PreparedStatementLogger.java @@ -0,0 +1,577 @@ +package nl.astraeus.jdbc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.InputStream; +import java.io.Reader; +import java.math.BigDecimal; +import java.net.URL; +import java.sql.*; +import java.util.Calendar; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 7:47:57 PM + */ +public class PreparedStatementLogger implements PreparedStatement { + private final static Logger log = LoggerFactory.getLogger(PreparedStatementLogger.class); + + private PreparedStatement statement; + + private String sql; + private QueryType type; + private long milli; + private long nano; + + //private ArrayList parameters; + + public PreparedStatementLogger(PreparedStatement statement) { + this.statement = statement; + this.sql = ""; + this.type = QueryType.UNKNOWN; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(QueryType type, String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(type, sql, m, n); + } + + public PreparedStatementLogger(Connection connection, String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql); + } + + public PreparedStatementLogger(Connection connection, String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatementLogger(Connection connection, String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, autoGeneratedKeys); + } + + public PreparedStatementLogger(Connection connection, String sql, int[] columnIndexes) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnIndexes); + } + + public PreparedStatementLogger(Connection connection, String sql, String[] columnNames) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnNames); + } + + public boolean execute() throws SQLException { + clearTime(); + + boolean result = statement.execute(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery() throws SQLException { + clearTime(); + + ResultSet result = statement.executeQuery(); + + log(type, sql); + + return result; + } + + public int executeUpdate() throws SQLException { + clearTime(); + + int result = statement.executeUpdate(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + ResultSet result = statement.executeQuery(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnNames); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnNames); + + log(type, sql); + + return result; + } + + + public void setNull(int parameterIndex, int sqlType) throws SQLException { + statement.setNull(parameterIndex, sqlType); + } + + public void setBoolean(int parameterIndex, boolean x) throws SQLException { + statement.setBoolean(parameterIndex, x); + } + + public void setByte(int parameterIndex, byte x) throws SQLException { + statement.setByte(parameterIndex, x); + } + + public void setShort(int parameterIndex, short x) throws SQLException { + statement.setShort(parameterIndex, x); + } + + public void setInt(int parameterIndex, int x) throws SQLException { + statement.setInt(parameterIndex, x); + } + + public void setLong(int parameterIndex, long x) throws SQLException { + statement.setLong(parameterIndex, x); + } + + public void setFloat(int parameterIndex, float x) throws SQLException { + statement.setFloat(parameterIndex, x); + } + + public void setDouble(int parameterIndex, double x) throws SQLException { + statement.setDouble(parameterIndex, x); + } + + public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { + statement.setBigDecimal(parameterIndex, x); + } + + public void setString(int parameterIndex, String x) throws SQLException { + statement.setString(parameterIndex, x); + } + + public void setBytes(int parameterIndex, byte x[]) throws SQLException { + statement.setBytes(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x) throws SQLException { + statement.setDate(parameterIndex, x); + } + + public void setTime(int parameterIndex, Time x) throws SQLException { + statement.setTime(parameterIndex, x); + } + + public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { + statement.setTimestamp(parameterIndex, x); + } + + public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setUnicodeStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType); + } + + public void setObject(int parameterIndex, Object x) throws SQLException { + statement.setObject(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setRef(int parameterIndex, Ref x) throws SQLException { + statement.setRef(parameterIndex, x); + } + + public void setBlob(int parameterIndex, Blob x) throws SQLException { + statement.setBlob(parameterIndex, x); + } + + public void setClob(int parameterIndex, Clob x) throws SQLException { + statement.setClob(parameterIndex, x); + } + + public void setArray(int parameterIndex, Array x) throws SQLException { + statement.setArray(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { + statement.setDate(parameterIndex, x, cal); + } + + public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { + statement.setTime(parameterIndex, x, cal); + } + + public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { + statement.setTimestamp(parameterIndex, x, cal); + } + + public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException { + statement.setNull(parameterIndex, sqlType, typeName); + } + + public void setURL(int parameterIndex, URL x) throws SQLException { + statement.setURL(parameterIndex, x); + } + + public void setRowId(int parameterIndex, RowId x) throws SQLException { + statement.setRowId(parameterIndex, x); + } + + public void setNString(int parameterIndex, String value) throws SQLException { + statement.setNString(parameterIndex, value); + } + + public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException { + statement.setNCharacterStream(parameterIndex, value, length); + } + + public void setNClob(int parameterIndex, NClob value) throws SQLException { + statement.setNClob(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setClob(parameterIndex, reader, length); + } + + public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException { + statement.setBlob(parameterIndex, inputStream, length); + } + + public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setNClob(parameterIndex, reader, length); + } + + public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException { + statement.setSQLXML(parameterIndex, xmlObject); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType, scaleOrLength); + } + + public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException { + statement.setAsciiStream(parameterIndex, x); + } + + public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException { + statement.setBinaryStream(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException { + statement.setCharacterStream(parameterIndex, reader); + } + + public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException { + statement.setNCharacterStream(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader) throws SQLException { + statement.setClob(parameterIndex, reader); + } + + public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException { + statement.setBlob(parameterIndex, inputStream); + } + + public void setNClob(int parameterIndex, Reader reader) throws SQLException { + statement.setNClob(parameterIndex, reader); + } + + + public void close() throws SQLException { + sql = ""; + type = QueryType.UNKNOWN; + milli = 0; + nano = 0; + + statement.close(); + } + + public ResultSetMetaData getMetaData() throws SQLException { + return statement.getMetaData(); + } + + public void clearParameters() throws SQLException { + statement.clearParameters(); + } + + public ParameterMetaData getParameterMetaData() throws SQLException { + return statement.getParameterMetaData(); + } + + public void addBatch() throws SQLException { + statement.addBatch(); + } + + public int getMaxFieldSize() throws SQLException { + return statement.getMaxFieldSize(); + } + + public void setMaxFieldSize(int max) throws SQLException { + statement.setMaxFieldSize(max); + } + + public int getMaxRows() throws SQLException { + return statement.getMaxRows(); + } + + public void setMaxRows(int max) throws SQLException { + statement.setMaxRows(max); + } + + public void setEscapeProcessing(boolean enable) throws SQLException { + statement.setEscapeProcessing(enable); + } + + public int getQueryTimeout() throws SQLException { + return statement.getQueryTimeout(); + } + + public void setQueryTimeout(int seconds) throws SQLException { + statement.setQueryTimeout(seconds); + } + + public void cancel() throws SQLException { + statement.cancel(); + } + + public SQLWarning getWarnings() throws SQLException { + return statement.getWarnings(); + } + + public void clearWarnings() throws SQLException { + statement.clearWarnings(); + } + + public void setCursorName(String name) throws SQLException { + statement.setCursorName(name); + } + + public boolean execute(String sql) throws SQLException { + return statement.execute(sql); + } + + public ResultSet getResultSet() throws SQLException { + return statement.getResultSet(); + } + + public int getUpdateCount() throws SQLException { + return statement.getUpdateCount(); + } + + public boolean getMoreResults() throws SQLException { + return statement.getMoreResults(); + } + + public void setFetchDirection(int direction) throws SQLException { + statement.setFetchDirection(direction); + } + + public int getFetchDirection() throws SQLException { + return statement.getFetchDirection(); + } + + public void setFetchSize(int rows) throws SQLException { + statement.setFetchSize(rows); + } + + public int getFetchSize() throws SQLException { + return statement.getFetchSize(); + } + + public int getResultSetConcurrency() throws SQLException { + return statement.getResultSetConcurrency(); + } + + public int getResultSetType() throws SQLException { + return statement.getResultSetType(); + } + + public void addBatch(String sql) throws SQLException { + statement.addBatch(sql); + } + + public void clearBatch() throws SQLException { + statement.clearBatch(); + } + + public int[] executeBatch() throws SQLException { + return statement.executeBatch(); + } + + public Connection getConnection() throws SQLException { + return statement.getConnection(); + } + + public boolean getMoreResults(int current) throws SQLException { + return statement.getMoreResults(current); + } + + public ResultSet getGeneratedKeys() throws SQLException { + return statement.getGeneratedKeys(); + } + + public int getResultSetHoldability() throws SQLException { + return statement.getResultSetHoldability(); + } + + public boolean isClosed() throws SQLException { + return statement.isClosed(); + } + + public void setPoolable(boolean poolable) throws SQLException { + statement.setPoolable(poolable); + } + + public boolean isPoolable() throws SQLException { + return statement.isPoolable(); + } + + @Override + public void closeOnCompletion() throws SQLException { + statement.closeOnCompletion();; + } + + @Override + public boolean isCloseOnCompletion() throws SQLException { + return statement.isCloseOnCompletion(); + } + + public T unwrap(Class iface) throws SQLException { + return statement.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return statement.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/QueryType.java b/src/nl/astraeus/jdbc/QueryType.java new file mode 100644 index 0000000..744fbfc --- /dev/null +++ b/src/nl/astraeus/jdbc/QueryType.java @@ -0,0 +1,24 @@ +package nl.astraeus.jdbc; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:32:49 PM + */ +public enum QueryType { + PLAIN("plain"), + PREPARED("prepared"), + CALLABLE("callable"), + UNKNOWN("unknown"); + + private String description; + + QueryType(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } + +} diff --git a/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java new file mode 100644 index 0000000..07aac40 --- /dev/null +++ b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java @@ -0,0 +1,68 @@ +package nl.astraeus.jdbc.example; + +import java.sql.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 7:32 PM + */ +public class JdbcStatisticsExample { + + + public static void main(String [] args) throws Exception { + Class.forName("org.h2.Driver"); + Class.forName("nl.astraeus.jdbc.Driver"); + + new JdbcStatisticsExample(); + } + + public JdbcStatisticsExample() throws Exception { + Connection conn = DriverManager.getConnection("jdbc:stat:jdbc:h2:mem:test"); + + Statement statement = null; + + statement = conn.createStatement(); + statement.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + + boolean running = true; + int count = 1; + PreparedStatement ps = null; + + while (running) { + Thread.sleep(10); + + String TableName = "TEST"+(System.nanoTime() % 1000); + + try { + ps = conn.prepareStatement("SELECT COUNT(*) FROM "+TableName); + ResultSet rs = ps.executeQuery(); + } catch (SQLException e) { + statement = conn.createStatement(); + statement.execute("CREATE TABLE "+TableName+" (ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + } finally { + if (ps!=null) { + ps.close(); + } + } + + ps = conn.prepareStatement("INSERT INTO "+TableName+" VALUES (?, ?)"); + + ps.setInt(1, count++); + ps.setString(2, "String "+System.currentTimeMillis()); + + ps.execute(); + ps.close(); + + Thread.sleep(10); + + ps = conn.prepareStatement("SELECT * FROM "+TableName); + ResultSet rs = ps.executeQuery(); + statement.close(); + } + + conn.close(); + } +} diff --git a/src/nl/astraeus/jdbc/util/IOUtils.java b/src/nl/astraeus/jdbc/util/IOUtils.java new file mode 100644 index 0000000..ce95d9d --- /dev/null +++ b/src/nl/astraeus/jdbc/util/IOUtils.java @@ -0,0 +1,38 @@ +package nl.astraeus.jdbc.util; + +import java.io.*; + +/** + * User: rnentjes + * Date: 4/9/12 + * Time: 2:33 PM + */ +public class IOUtils { + + public static String toString(InputStream in) throws IOException { + assert in != null; + + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + StringBuilder buffer = new StringBuilder(); + + while(reader.ready()) { + buffer.append(reader.readLine()); + buffer.append("\n"); + } + + return buffer.toString(); + } finally { + in.close(); + } + } + + public static void copy(InputStream in, OutputStream out) throws IOException { + byte [] buffer = new byte[1<<16]; + int bytes; + + while((bytes = in.read(buffer)) > 0) { + out.write(buffer, 0, bytes); + } + } +} diff --git a/src/nl/astraeus/jdbc/util/Util.java b/src/nl/astraeus/jdbc/util/Util.java new file mode 100644 index 0000000..eaa853b --- /dev/null +++ b/src/nl/astraeus/jdbc/util/Util.java @@ -0,0 +1,25 @@ +package nl.astraeus.jdbc.util; + +import java.text.DecimalFormat; +import java.text.NumberFormat; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 12:28 PM + */ +public class Util { + // utility functions + public static String formatNano(long l) { + NumberFormat format = new DecimalFormat("###,##0.000000"); + + return format.format((double) l / 1000000.0); + } + + public static void printMemoryUsage() { + System.out.println("Used memory: "+((Runtime.getRuntime().totalMemory() / (1024*1024))-(Runtime.getRuntime().freeMemory() / (1024*1024)))); + System.out.println("Free memory: "+(Runtime.getRuntime().freeMemory() / (1024*1024))); + System.out.println("Total memory: "+(Runtime.getRuntime().totalMemory() / (1024*1024))); + System.out.println("Max memory: "+(Runtime.getRuntime().maxMemory() / (1024*1024))); + } +} diff --git a/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java b/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java new file mode 100644 index 0000000..a162d6f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java @@ -0,0 +1,90 @@ +package nl.astraeus.jdbc.web; + +import nl.astraeus.jdbc.util.IOUtils; +import nl.astraeus.jdbc.util.Util; +import nl.astraeus.jdbc.web.page.Menu; +import nl.astraeus.jdbc.web.page.Page; +import nl.astraeus.jdbc.web.page.QueryOverview; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import java.io.IOException; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:05 PM + */ +public class JdbcStatisticsServlet extends HttpServlet { + + private String head; + private String bottom; + + @Override + public void init() throws ServletException { + super.init(); + + try { + head = IOUtils.toString(getClass().getResourceAsStream("head.html")); + bottom = IOUtils.toString(getClass().getResourceAsStream("bottom.html")); + } catch (IOException e) { + throw new ServletException(e); + } + + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + doPost(req, resp); + } + + @Override + protected void doPost(final HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + long nano = System.nanoTime(); + + HttpSession session = req.getSession(); + boolean ajax = "true".equals(req.getParameter("ajax")); + + resp.setContentType("text/html"); + + Page page = (Page)session.getAttribute("page"); + Page menu = (Page)session.getAttribute("menu"); + + session.setMaxInactiveInterval(1800); + + if (menu == null) { + menu = new Menu(); + + session.setAttribute("menu", menu); + } + + if (page == null || "menumain".equals(req.getParameter("action"))) { + page = new QueryOverview(); + } else if ("diagnostics".equals(req.getParameter("action"))) { + //page = new Diagnostics(); + } else { + page = page .processRequest(req); + } + + menu.processRequest(req); + + session.setAttribute("page", page); + + if (!ajax) { + resp.getWriter().print(head); + } + + resp.getWriter().print(menu.render(req)); + resp.getWriter().print(page.render(req)); + + if (!ajax) { + resp.getWriter().print(bottom); + } + + System.out.println("Request ends, time="+ Util.formatNano(System.nanoTime() - nano) +", page="+page.getClass().getSimpleName()); + } + +} diff --git a/src/nl/astraeus/jdbc/web/ResourceServlet.java b/src/nl/astraeus/jdbc/web/ResourceServlet.java new file mode 100644 index 0000000..7abfe6f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/ResourceServlet.java @@ -0,0 +1,49 @@ +package nl.astraeus.jdbc.web; + +import nl.astraeus.jdbc.util.IOUtils; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.InputStream; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:05 PM + */ +public class ResourceServlet extends HttpServlet { + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String uri = req.getRequestURI(); + + uri = "nl/astraeus/jdbc/web" + uri; + InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(uri); + + if (in == null) { + resp.sendError(404, "Cannot find resource '" + uri + "'."); + } else { + try { + if (uri.endsWith("js")) { + resp.setContentType("text/javascript"); + } else if (uri.endsWith("css")) { + resp.setContentType("text/css"); + } else if (uri.endsWith("png")) { + resp.setContentType("image/png"); + } else if (uri.endsWith("jpg")) { + resp.setContentType("image/jpeg"); + } else if (uri.endsWith("gif")) { + resp.setContentType("image/gif"); + } + + IOUtils.copy(in, resp.getOutputStream()); + } finally { + in.close(); + } + } + } + +} diff --git a/src/nl/astraeus/jdbc/web/bottom.html b/src/nl/astraeus/jdbc/web/bottom.html new file mode 100644 index 0000000..1288de4 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/bottom.html @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/head.html b/src/nl/astraeus/jdbc/web/head.html new file mode 100644 index 0000000..0f8f6a3 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/head.html @@ -0,0 +1,96 @@ + + + + + + + Simple JDBC Statistics + + + + + + + + + + + + + + + + + + + +
+
+ +
+ diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f403193 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..73ff239 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..3b00020 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..275077f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/README b/README deleted file mode 100644 index 734abaf..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -This file was created by IntelliJ IDEA 11.1.1 for binding GitHub repository \ No newline at end of file diff --git a/Simple-jdbc-statistics.iml b/Simple-jdbc-statistics.iml new file mode 100644 index 0000000..ca90a9b --- /dev/null +++ b/Simple-jdbc-statistics.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/lib/h2-1.3.166.jar b/lib/h2-1.3.166.jar new file mode 100644 index 0000000..4985063 --- /dev/null +++ b/lib/h2-1.3.166.jar Binary files differ diff --git a/lib/servlet-api-2.5.jar b/lib/servlet-api-2.5.jar new file mode 100644 index 0000000..20b5755 --- /dev/null +++ b/lib/servlet-api-2.5.jar Binary files differ diff --git a/lib/slf4j-api-1.6.4.jar b/lib/slf4j-api-1.6.4.jar new file mode 100644 index 0000000..4d23f41 --- /dev/null +++ b/lib/slf4j-api-1.6.4.jar Binary files differ diff --git a/lib/slf4j-simple-1.6.4.jar b/lib/slf4j-simple-1.6.4.jar new file mode 100644 index 0000000..3d1b8d9 --- /dev/null +++ b/lib/slf4j-simple-1.6.4.jar Binary files differ diff --git a/lib/ssr-0.1.jar b/lib/ssr-0.1.jar new file mode 100644 index 0000000..65dfcf4 --- /dev/null +++ b/lib/ssr-0.1.jar Binary files differ diff --git a/lib/vst-0.4.jar b/lib/vst-0.4.jar new file mode 100644 index 0000000..db63792 --- /dev/null +++ b/lib/vst-0.4.jar Binary files differ diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..ac2dbe1 --- /dev/null +++ b/readme.md @@ -0,0 +1 @@ +A simple wrapper around jdbc drivers what will show current jdbc stats of the running queries on a simple web page on port 18080. \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/ConnectionLogger.java b/src/nl/astraeus/jdbc/ConnectionLogger.java new file mode 100644 index 0000000..c3e243f --- /dev/null +++ b/src/nl/astraeus/jdbc/ConnectionLogger.java @@ -0,0 +1,279 @@ +package nl.astraeus.jdbc; + +import java.sql.*; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Executor; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:12:34 PM + */ +public class ConnectionLogger implements Connection { + private Connection connection; + + private long milli; + private long nano; + private String lastSql; + + public ConnectionLogger(Connection connection) { + this.connection = connection; + this.lastSql = ""; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(QueryType.UNKNOWN, sql, m, n); + } + + public void commit() throws SQLException { + clearTime(); + + connection.commit(); + + log("commit"); + } + + public void rollback() throws SQLException { + clearTime(); + + connection.rollback(); + + log("rollback"); + } + + public void close() throws SQLException { + clearTime(); + + connection.close(); + + log("close"); + } + + public PreparedStatement prepareStatement(String sql) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, autoGeneratedKeys); + } + + public PreparedStatement prepareStatement(String sql, int columnIndexes[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnIndexes); + } + + public PreparedStatement prepareStatement(String sql, String columnNames[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnNames); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public Statement createStatement() throws SQLException { + return connection.createStatement(); + } + + public CallableStatement prepareCall(String sql) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql); + } + + public String nativeSQL(String sql) throws SQLException { + lastSql = sql; + return connection.nativeSQL(sql); + } + + public void setAutoCommit(boolean autoCommit) throws SQLException { + connection.setAutoCommit(autoCommit); + } + + public boolean getAutoCommit() throws SQLException { + return connection.getAutoCommit(); + } + + public boolean isClosed() throws SQLException { + return connection.isClosed(); + } + + public DatabaseMetaData getMetaData() throws SQLException { + return connection.getMetaData(); + } + + public void setReadOnly(boolean readOnly) throws SQLException { + connection.setReadOnly(readOnly); + } + + public boolean isReadOnly() throws SQLException { + return connection.isReadOnly(); + } + + public void setCatalog(String catalog) throws SQLException { + connection.setCatalog(catalog); + } + + public String getCatalog() throws SQLException { + return connection.getCatalog(); + } + + public void setTransactionIsolation(int level) throws SQLException { + connection.setTransactionIsolation(level); + } + + public int getTransactionIsolation() throws SQLException { + return connection.getTransactionIsolation(); + } + + public SQLWarning getWarnings() throws SQLException { + return connection.getWarnings(); + } + + public void clearWarnings() throws SQLException { + connection.clearWarnings(); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency); + } + + public Map> getTypeMap() throws SQLException { + return connection.getTypeMap(); + } + + public void setTypeMap(Map> map) throws SQLException { + connection.setTypeMap(map); + } + + public void setHoldability(int holdability) throws SQLException { + connection.setHoldability(holdability); + } + + public int getHoldability() throws SQLException { + return connection.getHoldability(); + } + + public Savepoint setSavepoint() throws SQLException { + return connection.setSavepoint(); + } + + public Savepoint setSavepoint(String name) throws SQLException { + return connection.setSavepoint(name); + } + + public void rollback(Savepoint savepoint) throws SQLException { + connection.rollback(); + } + + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + connection.releaseSavepoint(savepoint); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public Clob createClob() throws SQLException { + return connection.createClob(); + } + + public Blob createBlob() throws SQLException { + return connection.createBlob(); + } + + public NClob createNClob() throws SQLException { + return connection.createNClob(); + } + + public SQLXML createSQLXML() throws SQLException { + return connection.createSQLXML(); + } + + public boolean isValid(int timeout) throws SQLException { + return connection.isValid(timeout); + } + + public void setClientInfo(String name, String value) throws SQLClientInfoException { + connection.setClientInfo(name, value); + } + + public void setClientInfo(Properties properties) throws SQLClientInfoException { + connection.setClientInfo(properties); + } + + public String getClientInfo(String name) throws SQLException { + return connection.getClientInfo(name); + } + + public Properties getClientInfo() throws SQLException { + return connection.getClientInfo(); + } + + public Array createArrayOf(String typeName, Object[] elements) throws SQLException { + return connection.createArrayOf(typeName, elements); + } + + public Struct createStruct(String typeName, Object[] attributes) throws SQLException { + return connection.createStruct(typeName, attributes); + } + + @Override + public void setSchema(String schema) throws SQLException { + connection.setSchema(schema); + } + + @Override + public String getSchema() throws SQLException { + return connection.getSchema(); + } + + @Override + public void abort(Executor executor) throws SQLException { + connection.abort(executor); + } + + @Override + public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { + connection.setNetworkTimeout(executor, milliseconds); + } + + @Override + public int getNetworkTimeout() throws SQLException { + return connection.getNetworkTimeout(); + } + + public T unwrap(Class iface) throws SQLException { + return connection.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return connection.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/Driver.java b/src/nl/astraeus/jdbc/Driver.java new file mode 100644 index 0000000..8317172 --- /dev/null +++ b/src/nl/astraeus/jdbc/Driver.java @@ -0,0 +1,116 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.http.SimpleWebServer; +import nl.astraeus.jdbc.web.JdbcStatisticsServlet; +import nl.astraeus.jdbc.web.ResourceServlet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.*; +import java.util.Enumeration; +import java.util.Properties; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:54:37 PM + */ +public class Driver implements java.sql.Driver { + private final static Logger log = LoggerFactory.getLogger(Driver.class); + + final private static String URL_PREFIX = "jdbc:stat:"; + + private java.sql.Driver driver = null; + private String[] drivers = { + "org.postgresql.Driver", + "oracle.jdbc.driver.OracleDriver", + "com.sybase.jdbc2.jdbc.SybDriver", + "net.sourceforge.jtds.jdbc.Driver", + "com.microsoft.jdbc.sqlserver.SQLServerDriver", + "com.microsoft.sqlserver.jdbc.SQLServerDriver", + "weblogic.jdbc.sqlserver.SQLServerDriver", + "com.informix.jdbc.IfxDriver", + "org.apache.derby.jdbc.ClientDriver", + "org.apache.derby.jdbc.EmbeddedDriver", + "com.mysql.jdbc.Driver", + "org.hsqldb.jdbcDriver", + "org.h2.Driver" }; + + static { + log.debug("Loading driver class " + Driver.class.getName()); + + try { + DriverManager.registerDriver(new Driver()); + } catch (SQLException e) { + log.error("", e); + } + } + + public Driver() { + for (String dr : drivers) { + try { + Class.forName(dr); + } catch (Throwable e) { + log.debug("Can't instantiate driver: " + dr, e); + } + } + } + + private java.sql.Driver findDriver(String url) throws SQLException { + Enumeration e = DriverManager.getDrivers(); + + while (e.hasMoreElements()) { + java.sql.Driver d = (java.sql.Driver) e.nextElement(); + + if (d.acceptsURL(url)) { + return d; + } + } + + throw new SQLException("Driver not found: " + url); + } + + public Connection connect(String url, Properties info) throws SQLException { + url = url.substring(URL_PREFIX.length()); + + if (driver == null) { + driver = findDriver(url); + } + + if (driver != null) { + SimpleWebServer server = new SimpleWebServer(18080); + + server.addServlet(new JdbcStatisticsServlet(), "/"); + server.addServlet(new ResourceServlet(), "/resources/*"); + + server.start(); + } + + return new ConnectionLogger(driver.connect(url, info)); + } + + public boolean acceptsURL(String url) throws SQLException { + return (url != null && url.startsWith(URL_PREFIX)); + } + + public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { + return driver.getPropertyInfo(url, info); + } + + public int getMajorVersion() { + return driver.getMajorVersion(); + } + + public int getMinorVersion() { + return driver.getMinorVersion(); + } + + public boolean jdbcCompliant() { + return driver.jdbcCompliant(); + } + + @Override + public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException { + return driver.getParentLogger(); + } +} diff --git a/src/nl/astraeus/jdbc/JdbcLogger.java b/src/nl/astraeus/jdbc/JdbcLogger.java new file mode 100644 index 0000000..f4bc125 --- /dev/null +++ b/src/nl/astraeus/jdbc/JdbcLogger.java @@ -0,0 +1,113 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.jdbc.util.Util; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/** + * User: riennentjes + * Date: Jul 12, 2008 + * Time: 9:15:21 AM + */ +public class JdbcLogger { + private final static Logger logger = LoggerFactory.getLogger(JdbcLogger.class); + + private final static JdbcLogger instance = new JdbcLogger(); + + public static JdbcLogger get() { + return instance; + } + + public final static class LogEntry { + public QueryType type; + public String sql; + public long milli; + public long nano; + public int count; + public int hash; + + public LogEntry(int hash, QueryType type, String sql, long milli, long nano) { + this.hash = hash; + this.type = type; + this.sql = sql; + this.milli = milli; + this.nano = nano; + this.count = 1; + } + + public void addCount(long milli, long nano) { + synchronized (this) { + count++; + this.milli += milli; + this.nano += nano; + } + } + + public int getCount() { + return count; + } + + public String getMilli() { + return Util.formatNano(milli*1000000/count); + } + + public String getNano() { + return Util.formatNano(nano/count); + } + + public String getTotal() { + return Util.formatNano(nano); + } + + public String getSql() { + return sql; + } + } + + private Map queries; + + public JdbcLogger() { + queries = new ConcurrentHashMap(); + } + + public void logEntry(QueryType type, String sql, long milli, long nano) { + int hash = sql.hashCode(); + LogEntry entry = queries.get(hash); + + if (entry == null) { + entry = new LogEntry(hash, type, sql, milli, nano); + queries.put(hash, entry); + } else { + entry.addCount(milli, nano); + } + + if (queries.size() > 1000) { + List toRemove = new LinkedList(); + List values = new LinkedList(queries.values()); + + Collections.sort(values, new Comparator() { + @Override + public int compare(LogEntry o1, LogEntry o2) { + return o1.count - o2.count; + } + }); + + while (queries.size() > 900) { + queries.remove(values.remove(0).hash); + + } + } + } + + public static void log(QueryType type, String sql, long milli, long nano) { + instance.logEntry(type, sql, milli, nano); + } + + public Collection getEntries() { + return queries.values(); + } + +} diff --git a/src/nl/astraeus/jdbc/PreparedStatementLogger.java b/src/nl/astraeus/jdbc/PreparedStatementLogger.java new file mode 100644 index 0000000..98aefc7 --- /dev/null +++ b/src/nl/astraeus/jdbc/PreparedStatementLogger.java @@ -0,0 +1,577 @@ +package nl.astraeus.jdbc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.InputStream; +import java.io.Reader; +import java.math.BigDecimal; +import java.net.URL; +import java.sql.*; +import java.util.Calendar; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 7:47:57 PM + */ +public class PreparedStatementLogger implements PreparedStatement { + private final static Logger log = LoggerFactory.getLogger(PreparedStatementLogger.class); + + private PreparedStatement statement; + + private String sql; + private QueryType type; + private long milli; + private long nano; + + //private ArrayList parameters; + + public PreparedStatementLogger(PreparedStatement statement) { + this.statement = statement; + this.sql = ""; + this.type = QueryType.UNKNOWN; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(QueryType type, String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(type, sql, m, n); + } + + public PreparedStatementLogger(Connection connection, String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql); + } + + public PreparedStatementLogger(Connection connection, String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatementLogger(Connection connection, String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, autoGeneratedKeys); + } + + public PreparedStatementLogger(Connection connection, String sql, int[] columnIndexes) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnIndexes); + } + + public PreparedStatementLogger(Connection connection, String sql, String[] columnNames) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnNames); + } + + public boolean execute() throws SQLException { + clearTime(); + + boolean result = statement.execute(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery() throws SQLException { + clearTime(); + + ResultSet result = statement.executeQuery(); + + log(type, sql); + + return result; + } + + public int executeUpdate() throws SQLException { + clearTime(); + + int result = statement.executeUpdate(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + ResultSet result = statement.executeQuery(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnNames); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnNames); + + log(type, sql); + + return result; + } + + + public void setNull(int parameterIndex, int sqlType) throws SQLException { + statement.setNull(parameterIndex, sqlType); + } + + public void setBoolean(int parameterIndex, boolean x) throws SQLException { + statement.setBoolean(parameterIndex, x); + } + + public void setByte(int parameterIndex, byte x) throws SQLException { + statement.setByte(parameterIndex, x); + } + + public void setShort(int parameterIndex, short x) throws SQLException { + statement.setShort(parameterIndex, x); + } + + public void setInt(int parameterIndex, int x) throws SQLException { + statement.setInt(parameterIndex, x); + } + + public void setLong(int parameterIndex, long x) throws SQLException { + statement.setLong(parameterIndex, x); + } + + public void setFloat(int parameterIndex, float x) throws SQLException { + statement.setFloat(parameterIndex, x); + } + + public void setDouble(int parameterIndex, double x) throws SQLException { + statement.setDouble(parameterIndex, x); + } + + public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { + statement.setBigDecimal(parameterIndex, x); + } + + public void setString(int parameterIndex, String x) throws SQLException { + statement.setString(parameterIndex, x); + } + + public void setBytes(int parameterIndex, byte x[]) throws SQLException { + statement.setBytes(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x) throws SQLException { + statement.setDate(parameterIndex, x); + } + + public void setTime(int parameterIndex, Time x) throws SQLException { + statement.setTime(parameterIndex, x); + } + + public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { + statement.setTimestamp(parameterIndex, x); + } + + public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setUnicodeStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType); + } + + public void setObject(int parameterIndex, Object x) throws SQLException { + statement.setObject(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setRef(int parameterIndex, Ref x) throws SQLException { + statement.setRef(parameterIndex, x); + } + + public void setBlob(int parameterIndex, Blob x) throws SQLException { + statement.setBlob(parameterIndex, x); + } + + public void setClob(int parameterIndex, Clob x) throws SQLException { + statement.setClob(parameterIndex, x); + } + + public void setArray(int parameterIndex, Array x) throws SQLException { + statement.setArray(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { + statement.setDate(parameterIndex, x, cal); + } + + public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { + statement.setTime(parameterIndex, x, cal); + } + + public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { + statement.setTimestamp(parameterIndex, x, cal); + } + + public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException { + statement.setNull(parameterIndex, sqlType, typeName); + } + + public void setURL(int parameterIndex, URL x) throws SQLException { + statement.setURL(parameterIndex, x); + } + + public void setRowId(int parameterIndex, RowId x) throws SQLException { + statement.setRowId(parameterIndex, x); + } + + public void setNString(int parameterIndex, String value) throws SQLException { + statement.setNString(parameterIndex, value); + } + + public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException { + statement.setNCharacterStream(parameterIndex, value, length); + } + + public void setNClob(int parameterIndex, NClob value) throws SQLException { + statement.setNClob(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setClob(parameterIndex, reader, length); + } + + public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException { + statement.setBlob(parameterIndex, inputStream, length); + } + + public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setNClob(parameterIndex, reader, length); + } + + public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException { + statement.setSQLXML(parameterIndex, xmlObject); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType, scaleOrLength); + } + + public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException { + statement.setAsciiStream(parameterIndex, x); + } + + public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException { + statement.setBinaryStream(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException { + statement.setCharacterStream(parameterIndex, reader); + } + + public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException { + statement.setNCharacterStream(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader) throws SQLException { + statement.setClob(parameterIndex, reader); + } + + public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException { + statement.setBlob(parameterIndex, inputStream); + } + + public void setNClob(int parameterIndex, Reader reader) throws SQLException { + statement.setNClob(parameterIndex, reader); + } + + + public void close() throws SQLException { + sql = ""; + type = QueryType.UNKNOWN; + milli = 0; + nano = 0; + + statement.close(); + } + + public ResultSetMetaData getMetaData() throws SQLException { + return statement.getMetaData(); + } + + public void clearParameters() throws SQLException { + statement.clearParameters(); + } + + public ParameterMetaData getParameterMetaData() throws SQLException { + return statement.getParameterMetaData(); + } + + public void addBatch() throws SQLException { + statement.addBatch(); + } + + public int getMaxFieldSize() throws SQLException { + return statement.getMaxFieldSize(); + } + + public void setMaxFieldSize(int max) throws SQLException { + statement.setMaxFieldSize(max); + } + + public int getMaxRows() throws SQLException { + return statement.getMaxRows(); + } + + public void setMaxRows(int max) throws SQLException { + statement.setMaxRows(max); + } + + public void setEscapeProcessing(boolean enable) throws SQLException { + statement.setEscapeProcessing(enable); + } + + public int getQueryTimeout() throws SQLException { + return statement.getQueryTimeout(); + } + + public void setQueryTimeout(int seconds) throws SQLException { + statement.setQueryTimeout(seconds); + } + + public void cancel() throws SQLException { + statement.cancel(); + } + + public SQLWarning getWarnings() throws SQLException { + return statement.getWarnings(); + } + + public void clearWarnings() throws SQLException { + statement.clearWarnings(); + } + + public void setCursorName(String name) throws SQLException { + statement.setCursorName(name); + } + + public boolean execute(String sql) throws SQLException { + return statement.execute(sql); + } + + public ResultSet getResultSet() throws SQLException { + return statement.getResultSet(); + } + + public int getUpdateCount() throws SQLException { + return statement.getUpdateCount(); + } + + public boolean getMoreResults() throws SQLException { + return statement.getMoreResults(); + } + + public void setFetchDirection(int direction) throws SQLException { + statement.setFetchDirection(direction); + } + + public int getFetchDirection() throws SQLException { + return statement.getFetchDirection(); + } + + public void setFetchSize(int rows) throws SQLException { + statement.setFetchSize(rows); + } + + public int getFetchSize() throws SQLException { + return statement.getFetchSize(); + } + + public int getResultSetConcurrency() throws SQLException { + return statement.getResultSetConcurrency(); + } + + public int getResultSetType() throws SQLException { + return statement.getResultSetType(); + } + + public void addBatch(String sql) throws SQLException { + statement.addBatch(sql); + } + + public void clearBatch() throws SQLException { + statement.clearBatch(); + } + + public int[] executeBatch() throws SQLException { + return statement.executeBatch(); + } + + public Connection getConnection() throws SQLException { + return statement.getConnection(); + } + + public boolean getMoreResults(int current) throws SQLException { + return statement.getMoreResults(current); + } + + public ResultSet getGeneratedKeys() throws SQLException { + return statement.getGeneratedKeys(); + } + + public int getResultSetHoldability() throws SQLException { + return statement.getResultSetHoldability(); + } + + public boolean isClosed() throws SQLException { + return statement.isClosed(); + } + + public void setPoolable(boolean poolable) throws SQLException { + statement.setPoolable(poolable); + } + + public boolean isPoolable() throws SQLException { + return statement.isPoolable(); + } + + @Override + public void closeOnCompletion() throws SQLException { + statement.closeOnCompletion();; + } + + @Override + public boolean isCloseOnCompletion() throws SQLException { + return statement.isCloseOnCompletion(); + } + + public T unwrap(Class iface) throws SQLException { + return statement.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return statement.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/QueryType.java b/src/nl/astraeus/jdbc/QueryType.java new file mode 100644 index 0000000..744fbfc --- /dev/null +++ b/src/nl/astraeus/jdbc/QueryType.java @@ -0,0 +1,24 @@ +package nl.astraeus.jdbc; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:32:49 PM + */ +public enum QueryType { + PLAIN("plain"), + PREPARED("prepared"), + CALLABLE("callable"), + UNKNOWN("unknown"); + + private String description; + + QueryType(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } + +} diff --git a/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java new file mode 100644 index 0000000..07aac40 --- /dev/null +++ b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java @@ -0,0 +1,68 @@ +package nl.astraeus.jdbc.example; + +import java.sql.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 7:32 PM + */ +public class JdbcStatisticsExample { + + + public static void main(String [] args) throws Exception { + Class.forName("org.h2.Driver"); + Class.forName("nl.astraeus.jdbc.Driver"); + + new JdbcStatisticsExample(); + } + + public JdbcStatisticsExample() throws Exception { + Connection conn = DriverManager.getConnection("jdbc:stat:jdbc:h2:mem:test"); + + Statement statement = null; + + statement = conn.createStatement(); + statement.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + + boolean running = true; + int count = 1; + PreparedStatement ps = null; + + while (running) { + Thread.sleep(10); + + String TableName = "TEST"+(System.nanoTime() % 1000); + + try { + ps = conn.prepareStatement("SELECT COUNT(*) FROM "+TableName); + ResultSet rs = ps.executeQuery(); + } catch (SQLException e) { + statement = conn.createStatement(); + statement.execute("CREATE TABLE "+TableName+" (ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + } finally { + if (ps!=null) { + ps.close(); + } + } + + ps = conn.prepareStatement("INSERT INTO "+TableName+" VALUES (?, ?)"); + + ps.setInt(1, count++); + ps.setString(2, "String "+System.currentTimeMillis()); + + ps.execute(); + ps.close(); + + Thread.sleep(10); + + ps = conn.prepareStatement("SELECT * FROM "+TableName); + ResultSet rs = ps.executeQuery(); + statement.close(); + } + + conn.close(); + } +} diff --git a/src/nl/astraeus/jdbc/util/IOUtils.java b/src/nl/astraeus/jdbc/util/IOUtils.java new file mode 100644 index 0000000..ce95d9d --- /dev/null +++ b/src/nl/astraeus/jdbc/util/IOUtils.java @@ -0,0 +1,38 @@ +package nl.astraeus.jdbc.util; + +import java.io.*; + +/** + * User: rnentjes + * Date: 4/9/12 + * Time: 2:33 PM + */ +public class IOUtils { + + public static String toString(InputStream in) throws IOException { + assert in != null; + + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + StringBuilder buffer = new StringBuilder(); + + while(reader.ready()) { + buffer.append(reader.readLine()); + buffer.append("\n"); + } + + return buffer.toString(); + } finally { + in.close(); + } + } + + public static void copy(InputStream in, OutputStream out) throws IOException { + byte [] buffer = new byte[1<<16]; + int bytes; + + while((bytes = in.read(buffer)) > 0) { + out.write(buffer, 0, bytes); + } + } +} diff --git a/src/nl/astraeus/jdbc/util/Util.java b/src/nl/astraeus/jdbc/util/Util.java new file mode 100644 index 0000000..eaa853b --- /dev/null +++ b/src/nl/astraeus/jdbc/util/Util.java @@ -0,0 +1,25 @@ +package nl.astraeus.jdbc.util; + +import java.text.DecimalFormat; +import java.text.NumberFormat; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 12:28 PM + */ +public class Util { + // utility functions + public static String formatNano(long l) { + NumberFormat format = new DecimalFormat("###,##0.000000"); + + return format.format((double) l / 1000000.0); + } + + public static void printMemoryUsage() { + System.out.println("Used memory: "+((Runtime.getRuntime().totalMemory() / (1024*1024))-(Runtime.getRuntime().freeMemory() / (1024*1024)))); + System.out.println("Free memory: "+(Runtime.getRuntime().freeMemory() / (1024*1024))); + System.out.println("Total memory: "+(Runtime.getRuntime().totalMemory() / (1024*1024))); + System.out.println("Max memory: "+(Runtime.getRuntime().maxMemory() / (1024*1024))); + } +} diff --git a/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java b/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java new file mode 100644 index 0000000..a162d6f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java @@ -0,0 +1,90 @@ +package nl.astraeus.jdbc.web; + +import nl.astraeus.jdbc.util.IOUtils; +import nl.astraeus.jdbc.util.Util; +import nl.astraeus.jdbc.web.page.Menu; +import nl.astraeus.jdbc.web.page.Page; +import nl.astraeus.jdbc.web.page.QueryOverview; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import java.io.IOException; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:05 PM + */ +public class JdbcStatisticsServlet extends HttpServlet { + + private String head; + private String bottom; + + @Override + public void init() throws ServletException { + super.init(); + + try { + head = IOUtils.toString(getClass().getResourceAsStream("head.html")); + bottom = IOUtils.toString(getClass().getResourceAsStream("bottom.html")); + } catch (IOException e) { + throw new ServletException(e); + } + + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + doPost(req, resp); + } + + @Override + protected void doPost(final HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + long nano = System.nanoTime(); + + HttpSession session = req.getSession(); + boolean ajax = "true".equals(req.getParameter("ajax")); + + resp.setContentType("text/html"); + + Page page = (Page)session.getAttribute("page"); + Page menu = (Page)session.getAttribute("menu"); + + session.setMaxInactiveInterval(1800); + + if (menu == null) { + menu = new Menu(); + + session.setAttribute("menu", menu); + } + + if (page == null || "menumain".equals(req.getParameter("action"))) { + page = new QueryOverview(); + } else if ("diagnostics".equals(req.getParameter("action"))) { + //page = new Diagnostics(); + } else { + page = page .processRequest(req); + } + + menu.processRequest(req); + + session.setAttribute("page", page); + + if (!ajax) { + resp.getWriter().print(head); + } + + resp.getWriter().print(menu.render(req)); + resp.getWriter().print(page.render(req)); + + if (!ajax) { + resp.getWriter().print(bottom); + } + + System.out.println("Request ends, time="+ Util.formatNano(System.nanoTime() - nano) +", page="+page.getClass().getSimpleName()); + } + +} diff --git a/src/nl/astraeus/jdbc/web/ResourceServlet.java b/src/nl/astraeus/jdbc/web/ResourceServlet.java new file mode 100644 index 0000000..7abfe6f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/ResourceServlet.java @@ -0,0 +1,49 @@ +package nl.astraeus.jdbc.web; + +import nl.astraeus.jdbc.util.IOUtils; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.InputStream; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:05 PM + */ +public class ResourceServlet extends HttpServlet { + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String uri = req.getRequestURI(); + + uri = "nl/astraeus/jdbc/web" + uri; + InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(uri); + + if (in == null) { + resp.sendError(404, "Cannot find resource '" + uri + "'."); + } else { + try { + if (uri.endsWith("js")) { + resp.setContentType("text/javascript"); + } else if (uri.endsWith("css")) { + resp.setContentType("text/css"); + } else if (uri.endsWith("png")) { + resp.setContentType("image/png"); + } else if (uri.endsWith("jpg")) { + resp.setContentType("image/jpeg"); + } else if (uri.endsWith("gif")) { + resp.setContentType("image/gif"); + } + + IOUtils.copy(in, resp.getOutputStream()); + } finally { + in.close(); + } + } + } + +} diff --git a/src/nl/astraeus/jdbc/web/bottom.html b/src/nl/astraeus/jdbc/web/bottom.html new file mode 100644 index 0000000..1288de4 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/bottom.html @@ -0,0 +1,8 @@ + + +
+ + + + + \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/head.html b/src/nl/astraeus/jdbc/web/head.html new file mode 100644 index 0000000..0f8f6a3 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/head.html @@ -0,0 +1,96 @@ + + + + + + + Simple JDBC Statistics + + + + + + + + + + + + + + + + + + + +
+
+ +
+ diff --git a/src/nl/astraeus/jdbc/web/page/Menu.html b/src/nl/astraeus/jdbc/web/page/Menu.html new file mode 100644 index 0000000..505c7c2 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.html @@ -0,0 +1,42 @@ + diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f403193 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..73ff239 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..3b00020 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..275077f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/README b/README deleted file mode 100644 index 734abaf..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -This file was created by IntelliJ IDEA 11.1.1 for binding GitHub repository \ No newline at end of file diff --git a/Simple-jdbc-statistics.iml b/Simple-jdbc-statistics.iml new file mode 100644 index 0000000..ca90a9b --- /dev/null +++ b/Simple-jdbc-statistics.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/lib/h2-1.3.166.jar b/lib/h2-1.3.166.jar new file mode 100644 index 0000000..4985063 --- /dev/null +++ b/lib/h2-1.3.166.jar Binary files differ diff --git a/lib/servlet-api-2.5.jar b/lib/servlet-api-2.5.jar new file mode 100644 index 0000000..20b5755 --- /dev/null +++ b/lib/servlet-api-2.5.jar Binary files differ diff --git a/lib/slf4j-api-1.6.4.jar b/lib/slf4j-api-1.6.4.jar new file mode 100644 index 0000000..4d23f41 --- /dev/null +++ b/lib/slf4j-api-1.6.4.jar Binary files differ diff --git a/lib/slf4j-simple-1.6.4.jar b/lib/slf4j-simple-1.6.4.jar new file mode 100644 index 0000000..3d1b8d9 --- /dev/null +++ b/lib/slf4j-simple-1.6.4.jar Binary files differ diff --git a/lib/ssr-0.1.jar b/lib/ssr-0.1.jar new file mode 100644 index 0000000..65dfcf4 --- /dev/null +++ b/lib/ssr-0.1.jar Binary files differ diff --git a/lib/vst-0.4.jar b/lib/vst-0.4.jar new file mode 100644 index 0000000..db63792 --- /dev/null +++ b/lib/vst-0.4.jar Binary files differ diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..ac2dbe1 --- /dev/null +++ b/readme.md @@ -0,0 +1 @@ +A simple wrapper around jdbc drivers what will show current jdbc stats of the running queries on a simple web page on port 18080. \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/ConnectionLogger.java b/src/nl/astraeus/jdbc/ConnectionLogger.java new file mode 100644 index 0000000..c3e243f --- /dev/null +++ b/src/nl/astraeus/jdbc/ConnectionLogger.java @@ -0,0 +1,279 @@ +package nl.astraeus.jdbc; + +import java.sql.*; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Executor; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:12:34 PM + */ +public class ConnectionLogger implements Connection { + private Connection connection; + + private long milli; + private long nano; + private String lastSql; + + public ConnectionLogger(Connection connection) { + this.connection = connection; + this.lastSql = ""; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(QueryType.UNKNOWN, sql, m, n); + } + + public void commit() throws SQLException { + clearTime(); + + connection.commit(); + + log("commit"); + } + + public void rollback() throws SQLException { + clearTime(); + + connection.rollback(); + + log("rollback"); + } + + public void close() throws SQLException { + clearTime(); + + connection.close(); + + log("close"); + } + + public PreparedStatement prepareStatement(String sql) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, autoGeneratedKeys); + } + + public PreparedStatement prepareStatement(String sql, int columnIndexes[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnIndexes); + } + + public PreparedStatement prepareStatement(String sql, String columnNames[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnNames); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public Statement createStatement() throws SQLException { + return connection.createStatement(); + } + + public CallableStatement prepareCall(String sql) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql); + } + + public String nativeSQL(String sql) throws SQLException { + lastSql = sql; + return connection.nativeSQL(sql); + } + + public void setAutoCommit(boolean autoCommit) throws SQLException { + connection.setAutoCommit(autoCommit); + } + + public boolean getAutoCommit() throws SQLException { + return connection.getAutoCommit(); + } + + public boolean isClosed() throws SQLException { + return connection.isClosed(); + } + + public DatabaseMetaData getMetaData() throws SQLException { + return connection.getMetaData(); + } + + public void setReadOnly(boolean readOnly) throws SQLException { + connection.setReadOnly(readOnly); + } + + public boolean isReadOnly() throws SQLException { + return connection.isReadOnly(); + } + + public void setCatalog(String catalog) throws SQLException { + connection.setCatalog(catalog); + } + + public String getCatalog() throws SQLException { + return connection.getCatalog(); + } + + public void setTransactionIsolation(int level) throws SQLException { + connection.setTransactionIsolation(level); + } + + public int getTransactionIsolation() throws SQLException { + return connection.getTransactionIsolation(); + } + + public SQLWarning getWarnings() throws SQLException { + return connection.getWarnings(); + } + + public void clearWarnings() throws SQLException { + connection.clearWarnings(); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency); + } + + public Map> getTypeMap() throws SQLException { + return connection.getTypeMap(); + } + + public void setTypeMap(Map> map) throws SQLException { + connection.setTypeMap(map); + } + + public void setHoldability(int holdability) throws SQLException { + connection.setHoldability(holdability); + } + + public int getHoldability() throws SQLException { + return connection.getHoldability(); + } + + public Savepoint setSavepoint() throws SQLException { + return connection.setSavepoint(); + } + + public Savepoint setSavepoint(String name) throws SQLException { + return connection.setSavepoint(name); + } + + public void rollback(Savepoint savepoint) throws SQLException { + connection.rollback(); + } + + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + connection.releaseSavepoint(savepoint); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public Clob createClob() throws SQLException { + return connection.createClob(); + } + + public Blob createBlob() throws SQLException { + return connection.createBlob(); + } + + public NClob createNClob() throws SQLException { + return connection.createNClob(); + } + + public SQLXML createSQLXML() throws SQLException { + return connection.createSQLXML(); + } + + public boolean isValid(int timeout) throws SQLException { + return connection.isValid(timeout); + } + + public void setClientInfo(String name, String value) throws SQLClientInfoException { + connection.setClientInfo(name, value); + } + + public void setClientInfo(Properties properties) throws SQLClientInfoException { + connection.setClientInfo(properties); + } + + public String getClientInfo(String name) throws SQLException { + return connection.getClientInfo(name); + } + + public Properties getClientInfo() throws SQLException { + return connection.getClientInfo(); + } + + public Array createArrayOf(String typeName, Object[] elements) throws SQLException { + return connection.createArrayOf(typeName, elements); + } + + public Struct createStruct(String typeName, Object[] attributes) throws SQLException { + return connection.createStruct(typeName, attributes); + } + + @Override + public void setSchema(String schema) throws SQLException { + connection.setSchema(schema); + } + + @Override + public String getSchema() throws SQLException { + return connection.getSchema(); + } + + @Override + public void abort(Executor executor) throws SQLException { + connection.abort(executor); + } + + @Override + public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { + connection.setNetworkTimeout(executor, milliseconds); + } + + @Override + public int getNetworkTimeout() throws SQLException { + return connection.getNetworkTimeout(); + } + + public T unwrap(Class iface) throws SQLException { + return connection.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return connection.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/Driver.java b/src/nl/astraeus/jdbc/Driver.java new file mode 100644 index 0000000..8317172 --- /dev/null +++ b/src/nl/astraeus/jdbc/Driver.java @@ -0,0 +1,116 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.http.SimpleWebServer; +import nl.astraeus.jdbc.web.JdbcStatisticsServlet; +import nl.astraeus.jdbc.web.ResourceServlet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.*; +import java.util.Enumeration; +import java.util.Properties; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:54:37 PM + */ +public class Driver implements java.sql.Driver { + private final static Logger log = LoggerFactory.getLogger(Driver.class); + + final private static String URL_PREFIX = "jdbc:stat:"; + + private java.sql.Driver driver = null; + private String[] drivers = { + "org.postgresql.Driver", + "oracle.jdbc.driver.OracleDriver", + "com.sybase.jdbc2.jdbc.SybDriver", + "net.sourceforge.jtds.jdbc.Driver", + "com.microsoft.jdbc.sqlserver.SQLServerDriver", + "com.microsoft.sqlserver.jdbc.SQLServerDriver", + "weblogic.jdbc.sqlserver.SQLServerDriver", + "com.informix.jdbc.IfxDriver", + "org.apache.derby.jdbc.ClientDriver", + "org.apache.derby.jdbc.EmbeddedDriver", + "com.mysql.jdbc.Driver", + "org.hsqldb.jdbcDriver", + "org.h2.Driver" }; + + static { + log.debug("Loading driver class " + Driver.class.getName()); + + try { + DriverManager.registerDriver(new Driver()); + } catch (SQLException e) { + log.error("", e); + } + } + + public Driver() { + for (String dr : drivers) { + try { + Class.forName(dr); + } catch (Throwable e) { + log.debug("Can't instantiate driver: " + dr, e); + } + } + } + + private java.sql.Driver findDriver(String url) throws SQLException { + Enumeration e = DriverManager.getDrivers(); + + while (e.hasMoreElements()) { + java.sql.Driver d = (java.sql.Driver) e.nextElement(); + + if (d.acceptsURL(url)) { + return d; + } + } + + throw new SQLException("Driver not found: " + url); + } + + public Connection connect(String url, Properties info) throws SQLException { + url = url.substring(URL_PREFIX.length()); + + if (driver == null) { + driver = findDriver(url); + } + + if (driver != null) { + SimpleWebServer server = new SimpleWebServer(18080); + + server.addServlet(new JdbcStatisticsServlet(), "/"); + server.addServlet(new ResourceServlet(), "/resources/*"); + + server.start(); + } + + return new ConnectionLogger(driver.connect(url, info)); + } + + public boolean acceptsURL(String url) throws SQLException { + return (url != null && url.startsWith(URL_PREFIX)); + } + + public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { + return driver.getPropertyInfo(url, info); + } + + public int getMajorVersion() { + return driver.getMajorVersion(); + } + + public int getMinorVersion() { + return driver.getMinorVersion(); + } + + public boolean jdbcCompliant() { + return driver.jdbcCompliant(); + } + + @Override + public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException { + return driver.getParentLogger(); + } +} diff --git a/src/nl/astraeus/jdbc/JdbcLogger.java b/src/nl/astraeus/jdbc/JdbcLogger.java new file mode 100644 index 0000000..f4bc125 --- /dev/null +++ b/src/nl/astraeus/jdbc/JdbcLogger.java @@ -0,0 +1,113 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.jdbc.util.Util; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/** + * User: riennentjes + * Date: Jul 12, 2008 + * Time: 9:15:21 AM + */ +public class JdbcLogger { + private final static Logger logger = LoggerFactory.getLogger(JdbcLogger.class); + + private final static JdbcLogger instance = new JdbcLogger(); + + public static JdbcLogger get() { + return instance; + } + + public final static class LogEntry { + public QueryType type; + public String sql; + public long milli; + public long nano; + public int count; + public int hash; + + public LogEntry(int hash, QueryType type, String sql, long milli, long nano) { + this.hash = hash; + this.type = type; + this.sql = sql; + this.milli = milli; + this.nano = nano; + this.count = 1; + } + + public void addCount(long milli, long nano) { + synchronized (this) { + count++; + this.milli += milli; + this.nano += nano; + } + } + + public int getCount() { + return count; + } + + public String getMilli() { + return Util.formatNano(milli*1000000/count); + } + + public String getNano() { + return Util.formatNano(nano/count); + } + + public String getTotal() { + return Util.formatNano(nano); + } + + public String getSql() { + return sql; + } + } + + private Map queries; + + public JdbcLogger() { + queries = new ConcurrentHashMap(); + } + + public void logEntry(QueryType type, String sql, long milli, long nano) { + int hash = sql.hashCode(); + LogEntry entry = queries.get(hash); + + if (entry == null) { + entry = new LogEntry(hash, type, sql, milli, nano); + queries.put(hash, entry); + } else { + entry.addCount(milli, nano); + } + + if (queries.size() > 1000) { + List toRemove = new LinkedList(); + List values = new LinkedList(queries.values()); + + Collections.sort(values, new Comparator() { + @Override + public int compare(LogEntry o1, LogEntry o2) { + return o1.count - o2.count; + } + }); + + while (queries.size() > 900) { + queries.remove(values.remove(0).hash); + + } + } + } + + public static void log(QueryType type, String sql, long milli, long nano) { + instance.logEntry(type, sql, milli, nano); + } + + public Collection getEntries() { + return queries.values(); + } + +} diff --git a/src/nl/astraeus/jdbc/PreparedStatementLogger.java b/src/nl/astraeus/jdbc/PreparedStatementLogger.java new file mode 100644 index 0000000..98aefc7 --- /dev/null +++ b/src/nl/astraeus/jdbc/PreparedStatementLogger.java @@ -0,0 +1,577 @@ +package nl.astraeus.jdbc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.InputStream; +import java.io.Reader; +import java.math.BigDecimal; +import java.net.URL; +import java.sql.*; +import java.util.Calendar; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 7:47:57 PM + */ +public class PreparedStatementLogger implements PreparedStatement { + private final static Logger log = LoggerFactory.getLogger(PreparedStatementLogger.class); + + private PreparedStatement statement; + + private String sql; + private QueryType type; + private long milli; + private long nano; + + //private ArrayList parameters; + + public PreparedStatementLogger(PreparedStatement statement) { + this.statement = statement; + this.sql = ""; + this.type = QueryType.UNKNOWN; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(QueryType type, String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(type, sql, m, n); + } + + public PreparedStatementLogger(Connection connection, String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql); + } + + public PreparedStatementLogger(Connection connection, String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatementLogger(Connection connection, String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, autoGeneratedKeys); + } + + public PreparedStatementLogger(Connection connection, String sql, int[] columnIndexes) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnIndexes); + } + + public PreparedStatementLogger(Connection connection, String sql, String[] columnNames) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnNames); + } + + public boolean execute() throws SQLException { + clearTime(); + + boolean result = statement.execute(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery() throws SQLException { + clearTime(); + + ResultSet result = statement.executeQuery(); + + log(type, sql); + + return result; + } + + public int executeUpdate() throws SQLException { + clearTime(); + + int result = statement.executeUpdate(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + ResultSet result = statement.executeQuery(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnNames); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnNames); + + log(type, sql); + + return result; + } + + + public void setNull(int parameterIndex, int sqlType) throws SQLException { + statement.setNull(parameterIndex, sqlType); + } + + public void setBoolean(int parameterIndex, boolean x) throws SQLException { + statement.setBoolean(parameterIndex, x); + } + + public void setByte(int parameterIndex, byte x) throws SQLException { + statement.setByte(parameterIndex, x); + } + + public void setShort(int parameterIndex, short x) throws SQLException { + statement.setShort(parameterIndex, x); + } + + public void setInt(int parameterIndex, int x) throws SQLException { + statement.setInt(parameterIndex, x); + } + + public void setLong(int parameterIndex, long x) throws SQLException { + statement.setLong(parameterIndex, x); + } + + public void setFloat(int parameterIndex, float x) throws SQLException { + statement.setFloat(parameterIndex, x); + } + + public void setDouble(int parameterIndex, double x) throws SQLException { + statement.setDouble(parameterIndex, x); + } + + public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { + statement.setBigDecimal(parameterIndex, x); + } + + public void setString(int parameterIndex, String x) throws SQLException { + statement.setString(parameterIndex, x); + } + + public void setBytes(int parameterIndex, byte x[]) throws SQLException { + statement.setBytes(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x) throws SQLException { + statement.setDate(parameterIndex, x); + } + + public void setTime(int parameterIndex, Time x) throws SQLException { + statement.setTime(parameterIndex, x); + } + + public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { + statement.setTimestamp(parameterIndex, x); + } + + public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setUnicodeStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType); + } + + public void setObject(int parameterIndex, Object x) throws SQLException { + statement.setObject(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setRef(int parameterIndex, Ref x) throws SQLException { + statement.setRef(parameterIndex, x); + } + + public void setBlob(int parameterIndex, Blob x) throws SQLException { + statement.setBlob(parameterIndex, x); + } + + public void setClob(int parameterIndex, Clob x) throws SQLException { + statement.setClob(parameterIndex, x); + } + + public void setArray(int parameterIndex, Array x) throws SQLException { + statement.setArray(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { + statement.setDate(parameterIndex, x, cal); + } + + public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { + statement.setTime(parameterIndex, x, cal); + } + + public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { + statement.setTimestamp(parameterIndex, x, cal); + } + + public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException { + statement.setNull(parameterIndex, sqlType, typeName); + } + + public void setURL(int parameterIndex, URL x) throws SQLException { + statement.setURL(parameterIndex, x); + } + + public void setRowId(int parameterIndex, RowId x) throws SQLException { + statement.setRowId(parameterIndex, x); + } + + public void setNString(int parameterIndex, String value) throws SQLException { + statement.setNString(parameterIndex, value); + } + + public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException { + statement.setNCharacterStream(parameterIndex, value, length); + } + + public void setNClob(int parameterIndex, NClob value) throws SQLException { + statement.setNClob(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setClob(parameterIndex, reader, length); + } + + public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException { + statement.setBlob(parameterIndex, inputStream, length); + } + + public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setNClob(parameterIndex, reader, length); + } + + public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException { + statement.setSQLXML(parameterIndex, xmlObject); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType, scaleOrLength); + } + + public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException { + statement.setAsciiStream(parameterIndex, x); + } + + public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException { + statement.setBinaryStream(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException { + statement.setCharacterStream(parameterIndex, reader); + } + + public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException { + statement.setNCharacterStream(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader) throws SQLException { + statement.setClob(parameterIndex, reader); + } + + public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException { + statement.setBlob(parameterIndex, inputStream); + } + + public void setNClob(int parameterIndex, Reader reader) throws SQLException { + statement.setNClob(parameterIndex, reader); + } + + + public void close() throws SQLException { + sql = ""; + type = QueryType.UNKNOWN; + milli = 0; + nano = 0; + + statement.close(); + } + + public ResultSetMetaData getMetaData() throws SQLException { + return statement.getMetaData(); + } + + public void clearParameters() throws SQLException { + statement.clearParameters(); + } + + public ParameterMetaData getParameterMetaData() throws SQLException { + return statement.getParameterMetaData(); + } + + public void addBatch() throws SQLException { + statement.addBatch(); + } + + public int getMaxFieldSize() throws SQLException { + return statement.getMaxFieldSize(); + } + + public void setMaxFieldSize(int max) throws SQLException { + statement.setMaxFieldSize(max); + } + + public int getMaxRows() throws SQLException { + return statement.getMaxRows(); + } + + public void setMaxRows(int max) throws SQLException { + statement.setMaxRows(max); + } + + public void setEscapeProcessing(boolean enable) throws SQLException { + statement.setEscapeProcessing(enable); + } + + public int getQueryTimeout() throws SQLException { + return statement.getQueryTimeout(); + } + + public void setQueryTimeout(int seconds) throws SQLException { + statement.setQueryTimeout(seconds); + } + + public void cancel() throws SQLException { + statement.cancel(); + } + + public SQLWarning getWarnings() throws SQLException { + return statement.getWarnings(); + } + + public void clearWarnings() throws SQLException { + statement.clearWarnings(); + } + + public void setCursorName(String name) throws SQLException { + statement.setCursorName(name); + } + + public boolean execute(String sql) throws SQLException { + return statement.execute(sql); + } + + public ResultSet getResultSet() throws SQLException { + return statement.getResultSet(); + } + + public int getUpdateCount() throws SQLException { + return statement.getUpdateCount(); + } + + public boolean getMoreResults() throws SQLException { + return statement.getMoreResults(); + } + + public void setFetchDirection(int direction) throws SQLException { + statement.setFetchDirection(direction); + } + + public int getFetchDirection() throws SQLException { + return statement.getFetchDirection(); + } + + public void setFetchSize(int rows) throws SQLException { + statement.setFetchSize(rows); + } + + public int getFetchSize() throws SQLException { + return statement.getFetchSize(); + } + + public int getResultSetConcurrency() throws SQLException { + return statement.getResultSetConcurrency(); + } + + public int getResultSetType() throws SQLException { + return statement.getResultSetType(); + } + + public void addBatch(String sql) throws SQLException { + statement.addBatch(sql); + } + + public void clearBatch() throws SQLException { + statement.clearBatch(); + } + + public int[] executeBatch() throws SQLException { + return statement.executeBatch(); + } + + public Connection getConnection() throws SQLException { + return statement.getConnection(); + } + + public boolean getMoreResults(int current) throws SQLException { + return statement.getMoreResults(current); + } + + public ResultSet getGeneratedKeys() throws SQLException { + return statement.getGeneratedKeys(); + } + + public int getResultSetHoldability() throws SQLException { + return statement.getResultSetHoldability(); + } + + public boolean isClosed() throws SQLException { + return statement.isClosed(); + } + + public void setPoolable(boolean poolable) throws SQLException { + statement.setPoolable(poolable); + } + + public boolean isPoolable() throws SQLException { + return statement.isPoolable(); + } + + @Override + public void closeOnCompletion() throws SQLException { + statement.closeOnCompletion();; + } + + @Override + public boolean isCloseOnCompletion() throws SQLException { + return statement.isCloseOnCompletion(); + } + + public T unwrap(Class iface) throws SQLException { + return statement.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return statement.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/QueryType.java b/src/nl/astraeus/jdbc/QueryType.java new file mode 100644 index 0000000..744fbfc --- /dev/null +++ b/src/nl/astraeus/jdbc/QueryType.java @@ -0,0 +1,24 @@ +package nl.astraeus.jdbc; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:32:49 PM + */ +public enum QueryType { + PLAIN("plain"), + PREPARED("prepared"), + CALLABLE("callable"), + UNKNOWN("unknown"); + + private String description; + + QueryType(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } + +} diff --git a/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java new file mode 100644 index 0000000..07aac40 --- /dev/null +++ b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java @@ -0,0 +1,68 @@ +package nl.astraeus.jdbc.example; + +import java.sql.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 7:32 PM + */ +public class JdbcStatisticsExample { + + + public static void main(String [] args) throws Exception { + Class.forName("org.h2.Driver"); + Class.forName("nl.astraeus.jdbc.Driver"); + + new JdbcStatisticsExample(); + } + + public JdbcStatisticsExample() throws Exception { + Connection conn = DriverManager.getConnection("jdbc:stat:jdbc:h2:mem:test"); + + Statement statement = null; + + statement = conn.createStatement(); + statement.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + + boolean running = true; + int count = 1; + PreparedStatement ps = null; + + while (running) { + Thread.sleep(10); + + String TableName = "TEST"+(System.nanoTime() % 1000); + + try { + ps = conn.prepareStatement("SELECT COUNT(*) FROM "+TableName); + ResultSet rs = ps.executeQuery(); + } catch (SQLException e) { + statement = conn.createStatement(); + statement.execute("CREATE TABLE "+TableName+" (ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + } finally { + if (ps!=null) { + ps.close(); + } + } + + ps = conn.prepareStatement("INSERT INTO "+TableName+" VALUES (?, ?)"); + + ps.setInt(1, count++); + ps.setString(2, "String "+System.currentTimeMillis()); + + ps.execute(); + ps.close(); + + Thread.sleep(10); + + ps = conn.prepareStatement("SELECT * FROM "+TableName); + ResultSet rs = ps.executeQuery(); + statement.close(); + } + + conn.close(); + } +} diff --git a/src/nl/astraeus/jdbc/util/IOUtils.java b/src/nl/astraeus/jdbc/util/IOUtils.java new file mode 100644 index 0000000..ce95d9d --- /dev/null +++ b/src/nl/astraeus/jdbc/util/IOUtils.java @@ -0,0 +1,38 @@ +package nl.astraeus.jdbc.util; + +import java.io.*; + +/** + * User: rnentjes + * Date: 4/9/12 + * Time: 2:33 PM + */ +public class IOUtils { + + public static String toString(InputStream in) throws IOException { + assert in != null; + + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + StringBuilder buffer = new StringBuilder(); + + while(reader.ready()) { + buffer.append(reader.readLine()); + buffer.append("\n"); + } + + return buffer.toString(); + } finally { + in.close(); + } + } + + public static void copy(InputStream in, OutputStream out) throws IOException { + byte [] buffer = new byte[1<<16]; + int bytes; + + while((bytes = in.read(buffer)) > 0) { + out.write(buffer, 0, bytes); + } + } +} diff --git a/src/nl/astraeus/jdbc/util/Util.java b/src/nl/astraeus/jdbc/util/Util.java new file mode 100644 index 0000000..eaa853b --- /dev/null +++ b/src/nl/astraeus/jdbc/util/Util.java @@ -0,0 +1,25 @@ +package nl.astraeus.jdbc.util; + +import java.text.DecimalFormat; +import java.text.NumberFormat; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 12:28 PM + */ +public class Util { + // utility functions + public static String formatNano(long l) { + NumberFormat format = new DecimalFormat("###,##0.000000"); + + return format.format((double) l / 1000000.0); + } + + public static void printMemoryUsage() { + System.out.println("Used memory: "+((Runtime.getRuntime().totalMemory() / (1024*1024))-(Runtime.getRuntime().freeMemory() / (1024*1024)))); + System.out.println("Free memory: "+(Runtime.getRuntime().freeMemory() / (1024*1024))); + System.out.println("Total memory: "+(Runtime.getRuntime().totalMemory() / (1024*1024))); + System.out.println("Max memory: "+(Runtime.getRuntime().maxMemory() / (1024*1024))); + } +} diff --git a/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java b/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java new file mode 100644 index 0000000..a162d6f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java @@ -0,0 +1,90 @@ +package nl.astraeus.jdbc.web; + +import nl.astraeus.jdbc.util.IOUtils; +import nl.astraeus.jdbc.util.Util; +import nl.astraeus.jdbc.web.page.Menu; +import nl.astraeus.jdbc.web.page.Page; +import nl.astraeus.jdbc.web.page.QueryOverview; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import java.io.IOException; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:05 PM + */ +public class JdbcStatisticsServlet extends HttpServlet { + + private String head; + private String bottom; + + @Override + public void init() throws ServletException { + super.init(); + + try { + head = IOUtils.toString(getClass().getResourceAsStream("head.html")); + bottom = IOUtils.toString(getClass().getResourceAsStream("bottom.html")); + } catch (IOException e) { + throw new ServletException(e); + } + + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + doPost(req, resp); + } + + @Override + protected void doPost(final HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + long nano = System.nanoTime(); + + HttpSession session = req.getSession(); + boolean ajax = "true".equals(req.getParameter("ajax")); + + resp.setContentType("text/html"); + + Page page = (Page)session.getAttribute("page"); + Page menu = (Page)session.getAttribute("menu"); + + session.setMaxInactiveInterval(1800); + + if (menu == null) { + menu = new Menu(); + + session.setAttribute("menu", menu); + } + + if (page == null || "menumain".equals(req.getParameter("action"))) { + page = new QueryOverview(); + } else if ("diagnostics".equals(req.getParameter("action"))) { + //page = new Diagnostics(); + } else { + page = page .processRequest(req); + } + + menu.processRequest(req); + + session.setAttribute("page", page); + + if (!ajax) { + resp.getWriter().print(head); + } + + resp.getWriter().print(menu.render(req)); + resp.getWriter().print(page.render(req)); + + if (!ajax) { + resp.getWriter().print(bottom); + } + + System.out.println("Request ends, time="+ Util.formatNano(System.nanoTime() - nano) +", page="+page.getClass().getSimpleName()); + } + +} diff --git a/src/nl/astraeus/jdbc/web/ResourceServlet.java b/src/nl/astraeus/jdbc/web/ResourceServlet.java new file mode 100644 index 0000000..7abfe6f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/ResourceServlet.java @@ -0,0 +1,49 @@ +package nl.astraeus.jdbc.web; + +import nl.astraeus.jdbc.util.IOUtils; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.InputStream; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:05 PM + */ +public class ResourceServlet extends HttpServlet { + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String uri = req.getRequestURI(); + + uri = "nl/astraeus/jdbc/web" + uri; + InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(uri); + + if (in == null) { + resp.sendError(404, "Cannot find resource '" + uri + "'."); + } else { + try { + if (uri.endsWith("js")) { + resp.setContentType("text/javascript"); + } else if (uri.endsWith("css")) { + resp.setContentType("text/css"); + } else if (uri.endsWith("png")) { + resp.setContentType("image/png"); + } else if (uri.endsWith("jpg")) { + resp.setContentType("image/jpeg"); + } else if (uri.endsWith("gif")) { + resp.setContentType("image/gif"); + } + + IOUtils.copy(in, resp.getOutputStream()); + } finally { + in.close(); + } + } + } + +} diff --git a/src/nl/astraeus/jdbc/web/bottom.html b/src/nl/astraeus/jdbc/web/bottom.html new file mode 100644 index 0000000..1288de4 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/bottom.html @@ -0,0 +1,8 @@ + + +
+ + + + + \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/head.html b/src/nl/astraeus/jdbc/web/head.html new file mode 100644 index 0000000..0f8f6a3 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/head.html @@ -0,0 +1,96 @@ + + + + + + + Simple JDBC Statistics + + + + + + + + + + + + + + + + + + + +
+
+ +
+ diff --git a/src/nl/astraeus/jdbc/web/page/Menu.html b/src/nl/astraeus/jdbc/web/page/Menu.html new file mode 100644 index 0000000..505c7c2 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.html @@ -0,0 +1,42 @@ + diff --git a/src/nl/astraeus/jdbc/web/page/Menu.java b/src/nl/astraeus/jdbc/web/page/Menu.java new file mode 100644 index 0000000..f0a349a --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.java @@ -0,0 +1,27 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 9:07 PM + */ +public class Menu extends TemplatePage { + + @Override + public Page processRequest(HttpServletRequest request) { + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + result.put("user", request.getSession().getAttribute("user")); + + return result; + } +} diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f403193 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..73ff239 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..3b00020 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..275077f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/README b/README deleted file mode 100644 index 734abaf..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -This file was created by IntelliJ IDEA 11.1.1 for binding GitHub repository \ No newline at end of file diff --git a/Simple-jdbc-statistics.iml b/Simple-jdbc-statistics.iml new file mode 100644 index 0000000..ca90a9b --- /dev/null +++ b/Simple-jdbc-statistics.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/lib/h2-1.3.166.jar b/lib/h2-1.3.166.jar new file mode 100644 index 0000000..4985063 --- /dev/null +++ b/lib/h2-1.3.166.jar Binary files differ diff --git a/lib/servlet-api-2.5.jar b/lib/servlet-api-2.5.jar new file mode 100644 index 0000000..20b5755 --- /dev/null +++ b/lib/servlet-api-2.5.jar Binary files differ diff --git a/lib/slf4j-api-1.6.4.jar b/lib/slf4j-api-1.6.4.jar new file mode 100644 index 0000000..4d23f41 --- /dev/null +++ b/lib/slf4j-api-1.6.4.jar Binary files differ diff --git a/lib/slf4j-simple-1.6.4.jar b/lib/slf4j-simple-1.6.4.jar new file mode 100644 index 0000000..3d1b8d9 --- /dev/null +++ b/lib/slf4j-simple-1.6.4.jar Binary files differ diff --git a/lib/ssr-0.1.jar b/lib/ssr-0.1.jar new file mode 100644 index 0000000..65dfcf4 --- /dev/null +++ b/lib/ssr-0.1.jar Binary files differ diff --git a/lib/vst-0.4.jar b/lib/vst-0.4.jar new file mode 100644 index 0000000..db63792 --- /dev/null +++ b/lib/vst-0.4.jar Binary files differ diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..ac2dbe1 --- /dev/null +++ b/readme.md @@ -0,0 +1 @@ +A simple wrapper around jdbc drivers what will show current jdbc stats of the running queries on a simple web page on port 18080. \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/ConnectionLogger.java b/src/nl/astraeus/jdbc/ConnectionLogger.java new file mode 100644 index 0000000..c3e243f --- /dev/null +++ b/src/nl/astraeus/jdbc/ConnectionLogger.java @@ -0,0 +1,279 @@ +package nl.astraeus.jdbc; + +import java.sql.*; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Executor; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:12:34 PM + */ +public class ConnectionLogger implements Connection { + private Connection connection; + + private long milli; + private long nano; + private String lastSql; + + public ConnectionLogger(Connection connection) { + this.connection = connection; + this.lastSql = ""; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(QueryType.UNKNOWN, sql, m, n); + } + + public void commit() throws SQLException { + clearTime(); + + connection.commit(); + + log("commit"); + } + + public void rollback() throws SQLException { + clearTime(); + + connection.rollback(); + + log("rollback"); + } + + public void close() throws SQLException { + clearTime(); + + connection.close(); + + log("close"); + } + + public PreparedStatement prepareStatement(String sql) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, autoGeneratedKeys); + } + + public PreparedStatement prepareStatement(String sql, int columnIndexes[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnIndexes); + } + + public PreparedStatement prepareStatement(String sql, String columnNames[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnNames); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public Statement createStatement() throws SQLException { + return connection.createStatement(); + } + + public CallableStatement prepareCall(String sql) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql); + } + + public String nativeSQL(String sql) throws SQLException { + lastSql = sql; + return connection.nativeSQL(sql); + } + + public void setAutoCommit(boolean autoCommit) throws SQLException { + connection.setAutoCommit(autoCommit); + } + + public boolean getAutoCommit() throws SQLException { + return connection.getAutoCommit(); + } + + public boolean isClosed() throws SQLException { + return connection.isClosed(); + } + + public DatabaseMetaData getMetaData() throws SQLException { + return connection.getMetaData(); + } + + public void setReadOnly(boolean readOnly) throws SQLException { + connection.setReadOnly(readOnly); + } + + public boolean isReadOnly() throws SQLException { + return connection.isReadOnly(); + } + + public void setCatalog(String catalog) throws SQLException { + connection.setCatalog(catalog); + } + + public String getCatalog() throws SQLException { + return connection.getCatalog(); + } + + public void setTransactionIsolation(int level) throws SQLException { + connection.setTransactionIsolation(level); + } + + public int getTransactionIsolation() throws SQLException { + return connection.getTransactionIsolation(); + } + + public SQLWarning getWarnings() throws SQLException { + return connection.getWarnings(); + } + + public void clearWarnings() throws SQLException { + connection.clearWarnings(); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency); + } + + public Map> getTypeMap() throws SQLException { + return connection.getTypeMap(); + } + + public void setTypeMap(Map> map) throws SQLException { + connection.setTypeMap(map); + } + + public void setHoldability(int holdability) throws SQLException { + connection.setHoldability(holdability); + } + + public int getHoldability() throws SQLException { + return connection.getHoldability(); + } + + public Savepoint setSavepoint() throws SQLException { + return connection.setSavepoint(); + } + + public Savepoint setSavepoint(String name) throws SQLException { + return connection.setSavepoint(name); + } + + public void rollback(Savepoint savepoint) throws SQLException { + connection.rollback(); + } + + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + connection.releaseSavepoint(savepoint); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public Clob createClob() throws SQLException { + return connection.createClob(); + } + + public Blob createBlob() throws SQLException { + return connection.createBlob(); + } + + public NClob createNClob() throws SQLException { + return connection.createNClob(); + } + + public SQLXML createSQLXML() throws SQLException { + return connection.createSQLXML(); + } + + public boolean isValid(int timeout) throws SQLException { + return connection.isValid(timeout); + } + + public void setClientInfo(String name, String value) throws SQLClientInfoException { + connection.setClientInfo(name, value); + } + + public void setClientInfo(Properties properties) throws SQLClientInfoException { + connection.setClientInfo(properties); + } + + public String getClientInfo(String name) throws SQLException { + return connection.getClientInfo(name); + } + + public Properties getClientInfo() throws SQLException { + return connection.getClientInfo(); + } + + public Array createArrayOf(String typeName, Object[] elements) throws SQLException { + return connection.createArrayOf(typeName, elements); + } + + public Struct createStruct(String typeName, Object[] attributes) throws SQLException { + return connection.createStruct(typeName, attributes); + } + + @Override + public void setSchema(String schema) throws SQLException { + connection.setSchema(schema); + } + + @Override + public String getSchema() throws SQLException { + return connection.getSchema(); + } + + @Override + public void abort(Executor executor) throws SQLException { + connection.abort(executor); + } + + @Override + public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { + connection.setNetworkTimeout(executor, milliseconds); + } + + @Override + public int getNetworkTimeout() throws SQLException { + return connection.getNetworkTimeout(); + } + + public T unwrap(Class iface) throws SQLException { + return connection.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return connection.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/Driver.java b/src/nl/astraeus/jdbc/Driver.java new file mode 100644 index 0000000..8317172 --- /dev/null +++ b/src/nl/astraeus/jdbc/Driver.java @@ -0,0 +1,116 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.http.SimpleWebServer; +import nl.astraeus.jdbc.web.JdbcStatisticsServlet; +import nl.astraeus.jdbc.web.ResourceServlet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.*; +import java.util.Enumeration; +import java.util.Properties; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:54:37 PM + */ +public class Driver implements java.sql.Driver { + private final static Logger log = LoggerFactory.getLogger(Driver.class); + + final private static String URL_PREFIX = "jdbc:stat:"; + + private java.sql.Driver driver = null; + private String[] drivers = { + "org.postgresql.Driver", + "oracle.jdbc.driver.OracleDriver", + "com.sybase.jdbc2.jdbc.SybDriver", + "net.sourceforge.jtds.jdbc.Driver", + "com.microsoft.jdbc.sqlserver.SQLServerDriver", + "com.microsoft.sqlserver.jdbc.SQLServerDriver", + "weblogic.jdbc.sqlserver.SQLServerDriver", + "com.informix.jdbc.IfxDriver", + "org.apache.derby.jdbc.ClientDriver", + "org.apache.derby.jdbc.EmbeddedDriver", + "com.mysql.jdbc.Driver", + "org.hsqldb.jdbcDriver", + "org.h2.Driver" }; + + static { + log.debug("Loading driver class " + Driver.class.getName()); + + try { + DriverManager.registerDriver(new Driver()); + } catch (SQLException e) { + log.error("", e); + } + } + + public Driver() { + for (String dr : drivers) { + try { + Class.forName(dr); + } catch (Throwable e) { + log.debug("Can't instantiate driver: " + dr, e); + } + } + } + + private java.sql.Driver findDriver(String url) throws SQLException { + Enumeration e = DriverManager.getDrivers(); + + while (e.hasMoreElements()) { + java.sql.Driver d = (java.sql.Driver) e.nextElement(); + + if (d.acceptsURL(url)) { + return d; + } + } + + throw new SQLException("Driver not found: " + url); + } + + public Connection connect(String url, Properties info) throws SQLException { + url = url.substring(URL_PREFIX.length()); + + if (driver == null) { + driver = findDriver(url); + } + + if (driver != null) { + SimpleWebServer server = new SimpleWebServer(18080); + + server.addServlet(new JdbcStatisticsServlet(), "/"); + server.addServlet(new ResourceServlet(), "/resources/*"); + + server.start(); + } + + return new ConnectionLogger(driver.connect(url, info)); + } + + public boolean acceptsURL(String url) throws SQLException { + return (url != null && url.startsWith(URL_PREFIX)); + } + + public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { + return driver.getPropertyInfo(url, info); + } + + public int getMajorVersion() { + return driver.getMajorVersion(); + } + + public int getMinorVersion() { + return driver.getMinorVersion(); + } + + public boolean jdbcCompliant() { + return driver.jdbcCompliant(); + } + + @Override + public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException { + return driver.getParentLogger(); + } +} diff --git a/src/nl/astraeus/jdbc/JdbcLogger.java b/src/nl/astraeus/jdbc/JdbcLogger.java new file mode 100644 index 0000000..f4bc125 --- /dev/null +++ b/src/nl/astraeus/jdbc/JdbcLogger.java @@ -0,0 +1,113 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.jdbc.util.Util; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/** + * User: riennentjes + * Date: Jul 12, 2008 + * Time: 9:15:21 AM + */ +public class JdbcLogger { + private final static Logger logger = LoggerFactory.getLogger(JdbcLogger.class); + + private final static JdbcLogger instance = new JdbcLogger(); + + public static JdbcLogger get() { + return instance; + } + + public final static class LogEntry { + public QueryType type; + public String sql; + public long milli; + public long nano; + public int count; + public int hash; + + public LogEntry(int hash, QueryType type, String sql, long milli, long nano) { + this.hash = hash; + this.type = type; + this.sql = sql; + this.milli = milli; + this.nano = nano; + this.count = 1; + } + + public void addCount(long milli, long nano) { + synchronized (this) { + count++; + this.milli += milli; + this.nano += nano; + } + } + + public int getCount() { + return count; + } + + public String getMilli() { + return Util.formatNano(milli*1000000/count); + } + + public String getNano() { + return Util.formatNano(nano/count); + } + + public String getTotal() { + return Util.formatNano(nano); + } + + public String getSql() { + return sql; + } + } + + private Map queries; + + public JdbcLogger() { + queries = new ConcurrentHashMap(); + } + + public void logEntry(QueryType type, String sql, long milli, long nano) { + int hash = sql.hashCode(); + LogEntry entry = queries.get(hash); + + if (entry == null) { + entry = new LogEntry(hash, type, sql, milli, nano); + queries.put(hash, entry); + } else { + entry.addCount(milli, nano); + } + + if (queries.size() > 1000) { + List toRemove = new LinkedList(); + List values = new LinkedList(queries.values()); + + Collections.sort(values, new Comparator() { + @Override + public int compare(LogEntry o1, LogEntry o2) { + return o1.count - o2.count; + } + }); + + while (queries.size() > 900) { + queries.remove(values.remove(0).hash); + + } + } + } + + public static void log(QueryType type, String sql, long milli, long nano) { + instance.logEntry(type, sql, milli, nano); + } + + public Collection getEntries() { + return queries.values(); + } + +} diff --git a/src/nl/astraeus/jdbc/PreparedStatementLogger.java b/src/nl/astraeus/jdbc/PreparedStatementLogger.java new file mode 100644 index 0000000..98aefc7 --- /dev/null +++ b/src/nl/astraeus/jdbc/PreparedStatementLogger.java @@ -0,0 +1,577 @@ +package nl.astraeus.jdbc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.InputStream; +import java.io.Reader; +import java.math.BigDecimal; +import java.net.URL; +import java.sql.*; +import java.util.Calendar; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 7:47:57 PM + */ +public class PreparedStatementLogger implements PreparedStatement { + private final static Logger log = LoggerFactory.getLogger(PreparedStatementLogger.class); + + private PreparedStatement statement; + + private String sql; + private QueryType type; + private long milli; + private long nano; + + //private ArrayList parameters; + + public PreparedStatementLogger(PreparedStatement statement) { + this.statement = statement; + this.sql = ""; + this.type = QueryType.UNKNOWN; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(QueryType type, String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(type, sql, m, n); + } + + public PreparedStatementLogger(Connection connection, String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql); + } + + public PreparedStatementLogger(Connection connection, String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatementLogger(Connection connection, String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, autoGeneratedKeys); + } + + public PreparedStatementLogger(Connection connection, String sql, int[] columnIndexes) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnIndexes); + } + + public PreparedStatementLogger(Connection connection, String sql, String[] columnNames) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnNames); + } + + public boolean execute() throws SQLException { + clearTime(); + + boolean result = statement.execute(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery() throws SQLException { + clearTime(); + + ResultSet result = statement.executeQuery(); + + log(type, sql); + + return result; + } + + public int executeUpdate() throws SQLException { + clearTime(); + + int result = statement.executeUpdate(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + ResultSet result = statement.executeQuery(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnNames); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnNames); + + log(type, sql); + + return result; + } + + + public void setNull(int parameterIndex, int sqlType) throws SQLException { + statement.setNull(parameterIndex, sqlType); + } + + public void setBoolean(int parameterIndex, boolean x) throws SQLException { + statement.setBoolean(parameterIndex, x); + } + + public void setByte(int parameterIndex, byte x) throws SQLException { + statement.setByte(parameterIndex, x); + } + + public void setShort(int parameterIndex, short x) throws SQLException { + statement.setShort(parameterIndex, x); + } + + public void setInt(int parameterIndex, int x) throws SQLException { + statement.setInt(parameterIndex, x); + } + + public void setLong(int parameterIndex, long x) throws SQLException { + statement.setLong(parameterIndex, x); + } + + public void setFloat(int parameterIndex, float x) throws SQLException { + statement.setFloat(parameterIndex, x); + } + + public void setDouble(int parameterIndex, double x) throws SQLException { + statement.setDouble(parameterIndex, x); + } + + public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { + statement.setBigDecimal(parameterIndex, x); + } + + public void setString(int parameterIndex, String x) throws SQLException { + statement.setString(parameterIndex, x); + } + + public void setBytes(int parameterIndex, byte x[]) throws SQLException { + statement.setBytes(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x) throws SQLException { + statement.setDate(parameterIndex, x); + } + + public void setTime(int parameterIndex, Time x) throws SQLException { + statement.setTime(parameterIndex, x); + } + + public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { + statement.setTimestamp(parameterIndex, x); + } + + public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setUnicodeStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType); + } + + public void setObject(int parameterIndex, Object x) throws SQLException { + statement.setObject(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setRef(int parameterIndex, Ref x) throws SQLException { + statement.setRef(parameterIndex, x); + } + + public void setBlob(int parameterIndex, Blob x) throws SQLException { + statement.setBlob(parameterIndex, x); + } + + public void setClob(int parameterIndex, Clob x) throws SQLException { + statement.setClob(parameterIndex, x); + } + + public void setArray(int parameterIndex, Array x) throws SQLException { + statement.setArray(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { + statement.setDate(parameterIndex, x, cal); + } + + public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { + statement.setTime(parameterIndex, x, cal); + } + + public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { + statement.setTimestamp(parameterIndex, x, cal); + } + + public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException { + statement.setNull(parameterIndex, sqlType, typeName); + } + + public void setURL(int parameterIndex, URL x) throws SQLException { + statement.setURL(parameterIndex, x); + } + + public void setRowId(int parameterIndex, RowId x) throws SQLException { + statement.setRowId(parameterIndex, x); + } + + public void setNString(int parameterIndex, String value) throws SQLException { + statement.setNString(parameterIndex, value); + } + + public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException { + statement.setNCharacterStream(parameterIndex, value, length); + } + + public void setNClob(int parameterIndex, NClob value) throws SQLException { + statement.setNClob(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setClob(parameterIndex, reader, length); + } + + public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException { + statement.setBlob(parameterIndex, inputStream, length); + } + + public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setNClob(parameterIndex, reader, length); + } + + public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException { + statement.setSQLXML(parameterIndex, xmlObject); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType, scaleOrLength); + } + + public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException { + statement.setAsciiStream(parameterIndex, x); + } + + public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException { + statement.setBinaryStream(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException { + statement.setCharacterStream(parameterIndex, reader); + } + + public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException { + statement.setNCharacterStream(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader) throws SQLException { + statement.setClob(parameterIndex, reader); + } + + public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException { + statement.setBlob(parameterIndex, inputStream); + } + + public void setNClob(int parameterIndex, Reader reader) throws SQLException { + statement.setNClob(parameterIndex, reader); + } + + + public void close() throws SQLException { + sql = ""; + type = QueryType.UNKNOWN; + milli = 0; + nano = 0; + + statement.close(); + } + + public ResultSetMetaData getMetaData() throws SQLException { + return statement.getMetaData(); + } + + public void clearParameters() throws SQLException { + statement.clearParameters(); + } + + public ParameterMetaData getParameterMetaData() throws SQLException { + return statement.getParameterMetaData(); + } + + public void addBatch() throws SQLException { + statement.addBatch(); + } + + public int getMaxFieldSize() throws SQLException { + return statement.getMaxFieldSize(); + } + + public void setMaxFieldSize(int max) throws SQLException { + statement.setMaxFieldSize(max); + } + + public int getMaxRows() throws SQLException { + return statement.getMaxRows(); + } + + public void setMaxRows(int max) throws SQLException { + statement.setMaxRows(max); + } + + public void setEscapeProcessing(boolean enable) throws SQLException { + statement.setEscapeProcessing(enable); + } + + public int getQueryTimeout() throws SQLException { + return statement.getQueryTimeout(); + } + + public void setQueryTimeout(int seconds) throws SQLException { + statement.setQueryTimeout(seconds); + } + + public void cancel() throws SQLException { + statement.cancel(); + } + + public SQLWarning getWarnings() throws SQLException { + return statement.getWarnings(); + } + + public void clearWarnings() throws SQLException { + statement.clearWarnings(); + } + + public void setCursorName(String name) throws SQLException { + statement.setCursorName(name); + } + + public boolean execute(String sql) throws SQLException { + return statement.execute(sql); + } + + public ResultSet getResultSet() throws SQLException { + return statement.getResultSet(); + } + + public int getUpdateCount() throws SQLException { + return statement.getUpdateCount(); + } + + public boolean getMoreResults() throws SQLException { + return statement.getMoreResults(); + } + + public void setFetchDirection(int direction) throws SQLException { + statement.setFetchDirection(direction); + } + + public int getFetchDirection() throws SQLException { + return statement.getFetchDirection(); + } + + public void setFetchSize(int rows) throws SQLException { + statement.setFetchSize(rows); + } + + public int getFetchSize() throws SQLException { + return statement.getFetchSize(); + } + + public int getResultSetConcurrency() throws SQLException { + return statement.getResultSetConcurrency(); + } + + public int getResultSetType() throws SQLException { + return statement.getResultSetType(); + } + + public void addBatch(String sql) throws SQLException { + statement.addBatch(sql); + } + + public void clearBatch() throws SQLException { + statement.clearBatch(); + } + + public int[] executeBatch() throws SQLException { + return statement.executeBatch(); + } + + public Connection getConnection() throws SQLException { + return statement.getConnection(); + } + + public boolean getMoreResults(int current) throws SQLException { + return statement.getMoreResults(current); + } + + public ResultSet getGeneratedKeys() throws SQLException { + return statement.getGeneratedKeys(); + } + + public int getResultSetHoldability() throws SQLException { + return statement.getResultSetHoldability(); + } + + public boolean isClosed() throws SQLException { + return statement.isClosed(); + } + + public void setPoolable(boolean poolable) throws SQLException { + statement.setPoolable(poolable); + } + + public boolean isPoolable() throws SQLException { + return statement.isPoolable(); + } + + @Override + public void closeOnCompletion() throws SQLException { + statement.closeOnCompletion();; + } + + @Override + public boolean isCloseOnCompletion() throws SQLException { + return statement.isCloseOnCompletion(); + } + + public T unwrap(Class iface) throws SQLException { + return statement.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return statement.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/QueryType.java b/src/nl/astraeus/jdbc/QueryType.java new file mode 100644 index 0000000..744fbfc --- /dev/null +++ b/src/nl/astraeus/jdbc/QueryType.java @@ -0,0 +1,24 @@ +package nl.astraeus.jdbc; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:32:49 PM + */ +public enum QueryType { + PLAIN("plain"), + PREPARED("prepared"), + CALLABLE("callable"), + UNKNOWN("unknown"); + + private String description; + + QueryType(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } + +} diff --git a/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java new file mode 100644 index 0000000..07aac40 --- /dev/null +++ b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java @@ -0,0 +1,68 @@ +package nl.astraeus.jdbc.example; + +import java.sql.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 7:32 PM + */ +public class JdbcStatisticsExample { + + + public static void main(String [] args) throws Exception { + Class.forName("org.h2.Driver"); + Class.forName("nl.astraeus.jdbc.Driver"); + + new JdbcStatisticsExample(); + } + + public JdbcStatisticsExample() throws Exception { + Connection conn = DriverManager.getConnection("jdbc:stat:jdbc:h2:mem:test"); + + Statement statement = null; + + statement = conn.createStatement(); + statement.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + + boolean running = true; + int count = 1; + PreparedStatement ps = null; + + while (running) { + Thread.sleep(10); + + String TableName = "TEST"+(System.nanoTime() % 1000); + + try { + ps = conn.prepareStatement("SELECT COUNT(*) FROM "+TableName); + ResultSet rs = ps.executeQuery(); + } catch (SQLException e) { + statement = conn.createStatement(); + statement.execute("CREATE TABLE "+TableName+" (ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + } finally { + if (ps!=null) { + ps.close(); + } + } + + ps = conn.prepareStatement("INSERT INTO "+TableName+" VALUES (?, ?)"); + + ps.setInt(1, count++); + ps.setString(2, "String "+System.currentTimeMillis()); + + ps.execute(); + ps.close(); + + Thread.sleep(10); + + ps = conn.prepareStatement("SELECT * FROM "+TableName); + ResultSet rs = ps.executeQuery(); + statement.close(); + } + + conn.close(); + } +} diff --git a/src/nl/astraeus/jdbc/util/IOUtils.java b/src/nl/astraeus/jdbc/util/IOUtils.java new file mode 100644 index 0000000..ce95d9d --- /dev/null +++ b/src/nl/astraeus/jdbc/util/IOUtils.java @@ -0,0 +1,38 @@ +package nl.astraeus.jdbc.util; + +import java.io.*; + +/** + * User: rnentjes + * Date: 4/9/12 + * Time: 2:33 PM + */ +public class IOUtils { + + public static String toString(InputStream in) throws IOException { + assert in != null; + + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + StringBuilder buffer = new StringBuilder(); + + while(reader.ready()) { + buffer.append(reader.readLine()); + buffer.append("\n"); + } + + return buffer.toString(); + } finally { + in.close(); + } + } + + public static void copy(InputStream in, OutputStream out) throws IOException { + byte [] buffer = new byte[1<<16]; + int bytes; + + while((bytes = in.read(buffer)) > 0) { + out.write(buffer, 0, bytes); + } + } +} diff --git a/src/nl/astraeus/jdbc/util/Util.java b/src/nl/astraeus/jdbc/util/Util.java new file mode 100644 index 0000000..eaa853b --- /dev/null +++ b/src/nl/astraeus/jdbc/util/Util.java @@ -0,0 +1,25 @@ +package nl.astraeus.jdbc.util; + +import java.text.DecimalFormat; +import java.text.NumberFormat; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 12:28 PM + */ +public class Util { + // utility functions + public static String formatNano(long l) { + NumberFormat format = new DecimalFormat("###,##0.000000"); + + return format.format((double) l / 1000000.0); + } + + public static void printMemoryUsage() { + System.out.println("Used memory: "+((Runtime.getRuntime().totalMemory() / (1024*1024))-(Runtime.getRuntime().freeMemory() / (1024*1024)))); + System.out.println("Free memory: "+(Runtime.getRuntime().freeMemory() / (1024*1024))); + System.out.println("Total memory: "+(Runtime.getRuntime().totalMemory() / (1024*1024))); + System.out.println("Max memory: "+(Runtime.getRuntime().maxMemory() / (1024*1024))); + } +} diff --git a/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java b/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java new file mode 100644 index 0000000..a162d6f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java @@ -0,0 +1,90 @@ +package nl.astraeus.jdbc.web; + +import nl.astraeus.jdbc.util.IOUtils; +import nl.astraeus.jdbc.util.Util; +import nl.astraeus.jdbc.web.page.Menu; +import nl.astraeus.jdbc.web.page.Page; +import nl.astraeus.jdbc.web.page.QueryOverview; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import java.io.IOException; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:05 PM + */ +public class JdbcStatisticsServlet extends HttpServlet { + + private String head; + private String bottom; + + @Override + public void init() throws ServletException { + super.init(); + + try { + head = IOUtils.toString(getClass().getResourceAsStream("head.html")); + bottom = IOUtils.toString(getClass().getResourceAsStream("bottom.html")); + } catch (IOException e) { + throw new ServletException(e); + } + + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + doPost(req, resp); + } + + @Override + protected void doPost(final HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + long nano = System.nanoTime(); + + HttpSession session = req.getSession(); + boolean ajax = "true".equals(req.getParameter("ajax")); + + resp.setContentType("text/html"); + + Page page = (Page)session.getAttribute("page"); + Page menu = (Page)session.getAttribute("menu"); + + session.setMaxInactiveInterval(1800); + + if (menu == null) { + menu = new Menu(); + + session.setAttribute("menu", menu); + } + + if (page == null || "menumain".equals(req.getParameter("action"))) { + page = new QueryOverview(); + } else if ("diagnostics".equals(req.getParameter("action"))) { + //page = new Diagnostics(); + } else { + page = page .processRequest(req); + } + + menu.processRequest(req); + + session.setAttribute("page", page); + + if (!ajax) { + resp.getWriter().print(head); + } + + resp.getWriter().print(menu.render(req)); + resp.getWriter().print(page.render(req)); + + if (!ajax) { + resp.getWriter().print(bottom); + } + + System.out.println("Request ends, time="+ Util.formatNano(System.nanoTime() - nano) +", page="+page.getClass().getSimpleName()); + } + +} diff --git a/src/nl/astraeus/jdbc/web/ResourceServlet.java b/src/nl/astraeus/jdbc/web/ResourceServlet.java new file mode 100644 index 0000000..7abfe6f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/ResourceServlet.java @@ -0,0 +1,49 @@ +package nl.astraeus.jdbc.web; + +import nl.astraeus.jdbc.util.IOUtils; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.InputStream; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:05 PM + */ +public class ResourceServlet extends HttpServlet { + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String uri = req.getRequestURI(); + + uri = "nl/astraeus/jdbc/web" + uri; + InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(uri); + + if (in == null) { + resp.sendError(404, "Cannot find resource '" + uri + "'."); + } else { + try { + if (uri.endsWith("js")) { + resp.setContentType("text/javascript"); + } else if (uri.endsWith("css")) { + resp.setContentType("text/css"); + } else if (uri.endsWith("png")) { + resp.setContentType("image/png"); + } else if (uri.endsWith("jpg")) { + resp.setContentType("image/jpeg"); + } else if (uri.endsWith("gif")) { + resp.setContentType("image/gif"); + } + + IOUtils.copy(in, resp.getOutputStream()); + } finally { + in.close(); + } + } + } + +} diff --git a/src/nl/astraeus/jdbc/web/bottom.html b/src/nl/astraeus/jdbc/web/bottom.html new file mode 100644 index 0000000..1288de4 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/bottom.html @@ -0,0 +1,8 @@ + + +
+ + + + + \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/head.html b/src/nl/astraeus/jdbc/web/head.html new file mode 100644 index 0000000..0f8f6a3 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/head.html @@ -0,0 +1,96 @@ + + + + + + + Simple JDBC Statistics + + + + + + + + + + + + + + + + + + + +
+
+ +
+ diff --git a/src/nl/astraeus/jdbc/web/page/Menu.html b/src/nl/astraeus/jdbc/web/page/Menu.html new file mode 100644 index 0000000..505c7c2 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.html @@ -0,0 +1,42 @@ + diff --git a/src/nl/astraeus/jdbc/web/page/Menu.java b/src/nl/astraeus/jdbc/web/page/Menu.java new file mode 100644 index 0000000..f0a349a --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.java @@ -0,0 +1,27 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 9:07 PM + */ +public class Menu extends TemplatePage { + + @Override + public Page processRequest(HttpServletRequest request) { + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + result.put("user", request.getSession().getAttribute("user")); + + return result; + } +} diff --git a/src/nl/astraeus/jdbc/web/page/Page.java b/src/nl/astraeus/jdbc/web/page/Page.java new file mode 100644 index 0000000..9d526d6 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Page.java @@ -0,0 +1,17 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:20 PM + */ +public abstract class Page { + + public abstract Page processRequest(HttpServletRequest request); + public abstract Map defineModel(HttpServletRequest request); + public abstract String render(HttpServletRequest request); + +} diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f403193 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..73ff239 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..3b00020 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..275077f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/README b/README deleted file mode 100644 index 734abaf..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -This file was created by IntelliJ IDEA 11.1.1 for binding GitHub repository \ No newline at end of file diff --git a/Simple-jdbc-statistics.iml b/Simple-jdbc-statistics.iml new file mode 100644 index 0000000..ca90a9b --- /dev/null +++ b/Simple-jdbc-statistics.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/lib/h2-1.3.166.jar b/lib/h2-1.3.166.jar new file mode 100644 index 0000000..4985063 --- /dev/null +++ b/lib/h2-1.3.166.jar Binary files differ diff --git a/lib/servlet-api-2.5.jar b/lib/servlet-api-2.5.jar new file mode 100644 index 0000000..20b5755 --- /dev/null +++ b/lib/servlet-api-2.5.jar Binary files differ diff --git a/lib/slf4j-api-1.6.4.jar b/lib/slf4j-api-1.6.4.jar new file mode 100644 index 0000000..4d23f41 --- /dev/null +++ b/lib/slf4j-api-1.6.4.jar Binary files differ diff --git a/lib/slf4j-simple-1.6.4.jar b/lib/slf4j-simple-1.6.4.jar new file mode 100644 index 0000000..3d1b8d9 --- /dev/null +++ b/lib/slf4j-simple-1.6.4.jar Binary files differ diff --git a/lib/ssr-0.1.jar b/lib/ssr-0.1.jar new file mode 100644 index 0000000..65dfcf4 --- /dev/null +++ b/lib/ssr-0.1.jar Binary files differ diff --git a/lib/vst-0.4.jar b/lib/vst-0.4.jar new file mode 100644 index 0000000..db63792 --- /dev/null +++ b/lib/vst-0.4.jar Binary files differ diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..ac2dbe1 --- /dev/null +++ b/readme.md @@ -0,0 +1 @@ +A simple wrapper around jdbc drivers what will show current jdbc stats of the running queries on a simple web page on port 18080. \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/ConnectionLogger.java b/src/nl/astraeus/jdbc/ConnectionLogger.java new file mode 100644 index 0000000..c3e243f --- /dev/null +++ b/src/nl/astraeus/jdbc/ConnectionLogger.java @@ -0,0 +1,279 @@ +package nl.astraeus.jdbc; + +import java.sql.*; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Executor; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:12:34 PM + */ +public class ConnectionLogger implements Connection { + private Connection connection; + + private long milli; + private long nano; + private String lastSql; + + public ConnectionLogger(Connection connection) { + this.connection = connection; + this.lastSql = ""; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(QueryType.UNKNOWN, sql, m, n); + } + + public void commit() throws SQLException { + clearTime(); + + connection.commit(); + + log("commit"); + } + + public void rollback() throws SQLException { + clearTime(); + + connection.rollback(); + + log("rollback"); + } + + public void close() throws SQLException { + clearTime(); + + connection.close(); + + log("close"); + } + + public PreparedStatement prepareStatement(String sql) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, autoGeneratedKeys); + } + + public PreparedStatement prepareStatement(String sql, int columnIndexes[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnIndexes); + } + + public PreparedStatement prepareStatement(String sql, String columnNames[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnNames); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public Statement createStatement() throws SQLException { + return connection.createStatement(); + } + + public CallableStatement prepareCall(String sql) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql); + } + + public String nativeSQL(String sql) throws SQLException { + lastSql = sql; + return connection.nativeSQL(sql); + } + + public void setAutoCommit(boolean autoCommit) throws SQLException { + connection.setAutoCommit(autoCommit); + } + + public boolean getAutoCommit() throws SQLException { + return connection.getAutoCommit(); + } + + public boolean isClosed() throws SQLException { + return connection.isClosed(); + } + + public DatabaseMetaData getMetaData() throws SQLException { + return connection.getMetaData(); + } + + public void setReadOnly(boolean readOnly) throws SQLException { + connection.setReadOnly(readOnly); + } + + public boolean isReadOnly() throws SQLException { + return connection.isReadOnly(); + } + + public void setCatalog(String catalog) throws SQLException { + connection.setCatalog(catalog); + } + + public String getCatalog() throws SQLException { + return connection.getCatalog(); + } + + public void setTransactionIsolation(int level) throws SQLException { + connection.setTransactionIsolation(level); + } + + public int getTransactionIsolation() throws SQLException { + return connection.getTransactionIsolation(); + } + + public SQLWarning getWarnings() throws SQLException { + return connection.getWarnings(); + } + + public void clearWarnings() throws SQLException { + connection.clearWarnings(); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency); + } + + public Map> getTypeMap() throws SQLException { + return connection.getTypeMap(); + } + + public void setTypeMap(Map> map) throws SQLException { + connection.setTypeMap(map); + } + + public void setHoldability(int holdability) throws SQLException { + connection.setHoldability(holdability); + } + + public int getHoldability() throws SQLException { + return connection.getHoldability(); + } + + public Savepoint setSavepoint() throws SQLException { + return connection.setSavepoint(); + } + + public Savepoint setSavepoint(String name) throws SQLException { + return connection.setSavepoint(name); + } + + public void rollback(Savepoint savepoint) throws SQLException { + connection.rollback(); + } + + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + connection.releaseSavepoint(savepoint); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public Clob createClob() throws SQLException { + return connection.createClob(); + } + + public Blob createBlob() throws SQLException { + return connection.createBlob(); + } + + public NClob createNClob() throws SQLException { + return connection.createNClob(); + } + + public SQLXML createSQLXML() throws SQLException { + return connection.createSQLXML(); + } + + public boolean isValid(int timeout) throws SQLException { + return connection.isValid(timeout); + } + + public void setClientInfo(String name, String value) throws SQLClientInfoException { + connection.setClientInfo(name, value); + } + + public void setClientInfo(Properties properties) throws SQLClientInfoException { + connection.setClientInfo(properties); + } + + public String getClientInfo(String name) throws SQLException { + return connection.getClientInfo(name); + } + + public Properties getClientInfo() throws SQLException { + return connection.getClientInfo(); + } + + public Array createArrayOf(String typeName, Object[] elements) throws SQLException { + return connection.createArrayOf(typeName, elements); + } + + public Struct createStruct(String typeName, Object[] attributes) throws SQLException { + return connection.createStruct(typeName, attributes); + } + + @Override + public void setSchema(String schema) throws SQLException { + connection.setSchema(schema); + } + + @Override + public String getSchema() throws SQLException { + return connection.getSchema(); + } + + @Override + public void abort(Executor executor) throws SQLException { + connection.abort(executor); + } + + @Override + public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { + connection.setNetworkTimeout(executor, milliseconds); + } + + @Override + public int getNetworkTimeout() throws SQLException { + return connection.getNetworkTimeout(); + } + + public T unwrap(Class iface) throws SQLException { + return connection.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return connection.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/Driver.java b/src/nl/astraeus/jdbc/Driver.java new file mode 100644 index 0000000..8317172 --- /dev/null +++ b/src/nl/astraeus/jdbc/Driver.java @@ -0,0 +1,116 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.http.SimpleWebServer; +import nl.astraeus.jdbc.web.JdbcStatisticsServlet; +import nl.astraeus.jdbc.web.ResourceServlet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.*; +import java.util.Enumeration; +import java.util.Properties; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:54:37 PM + */ +public class Driver implements java.sql.Driver { + private final static Logger log = LoggerFactory.getLogger(Driver.class); + + final private static String URL_PREFIX = "jdbc:stat:"; + + private java.sql.Driver driver = null; + private String[] drivers = { + "org.postgresql.Driver", + "oracle.jdbc.driver.OracleDriver", + "com.sybase.jdbc2.jdbc.SybDriver", + "net.sourceforge.jtds.jdbc.Driver", + "com.microsoft.jdbc.sqlserver.SQLServerDriver", + "com.microsoft.sqlserver.jdbc.SQLServerDriver", + "weblogic.jdbc.sqlserver.SQLServerDriver", + "com.informix.jdbc.IfxDriver", + "org.apache.derby.jdbc.ClientDriver", + "org.apache.derby.jdbc.EmbeddedDriver", + "com.mysql.jdbc.Driver", + "org.hsqldb.jdbcDriver", + "org.h2.Driver" }; + + static { + log.debug("Loading driver class " + Driver.class.getName()); + + try { + DriverManager.registerDriver(new Driver()); + } catch (SQLException e) { + log.error("", e); + } + } + + public Driver() { + for (String dr : drivers) { + try { + Class.forName(dr); + } catch (Throwable e) { + log.debug("Can't instantiate driver: " + dr, e); + } + } + } + + private java.sql.Driver findDriver(String url) throws SQLException { + Enumeration e = DriverManager.getDrivers(); + + while (e.hasMoreElements()) { + java.sql.Driver d = (java.sql.Driver) e.nextElement(); + + if (d.acceptsURL(url)) { + return d; + } + } + + throw new SQLException("Driver not found: " + url); + } + + public Connection connect(String url, Properties info) throws SQLException { + url = url.substring(URL_PREFIX.length()); + + if (driver == null) { + driver = findDriver(url); + } + + if (driver != null) { + SimpleWebServer server = new SimpleWebServer(18080); + + server.addServlet(new JdbcStatisticsServlet(), "/"); + server.addServlet(new ResourceServlet(), "/resources/*"); + + server.start(); + } + + return new ConnectionLogger(driver.connect(url, info)); + } + + public boolean acceptsURL(String url) throws SQLException { + return (url != null && url.startsWith(URL_PREFIX)); + } + + public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { + return driver.getPropertyInfo(url, info); + } + + public int getMajorVersion() { + return driver.getMajorVersion(); + } + + public int getMinorVersion() { + return driver.getMinorVersion(); + } + + public boolean jdbcCompliant() { + return driver.jdbcCompliant(); + } + + @Override + public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException { + return driver.getParentLogger(); + } +} diff --git a/src/nl/astraeus/jdbc/JdbcLogger.java b/src/nl/astraeus/jdbc/JdbcLogger.java new file mode 100644 index 0000000..f4bc125 --- /dev/null +++ b/src/nl/astraeus/jdbc/JdbcLogger.java @@ -0,0 +1,113 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.jdbc.util.Util; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/** + * User: riennentjes + * Date: Jul 12, 2008 + * Time: 9:15:21 AM + */ +public class JdbcLogger { + private final static Logger logger = LoggerFactory.getLogger(JdbcLogger.class); + + private final static JdbcLogger instance = new JdbcLogger(); + + public static JdbcLogger get() { + return instance; + } + + public final static class LogEntry { + public QueryType type; + public String sql; + public long milli; + public long nano; + public int count; + public int hash; + + public LogEntry(int hash, QueryType type, String sql, long milli, long nano) { + this.hash = hash; + this.type = type; + this.sql = sql; + this.milli = milli; + this.nano = nano; + this.count = 1; + } + + public void addCount(long milli, long nano) { + synchronized (this) { + count++; + this.milli += milli; + this.nano += nano; + } + } + + public int getCount() { + return count; + } + + public String getMilli() { + return Util.formatNano(milli*1000000/count); + } + + public String getNano() { + return Util.formatNano(nano/count); + } + + public String getTotal() { + return Util.formatNano(nano); + } + + public String getSql() { + return sql; + } + } + + private Map queries; + + public JdbcLogger() { + queries = new ConcurrentHashMap(); + } + + public void logEntry(QueryType type, String sql, long milli, long nano) { + int hash = sql.hashCode(); + LogEntry entry = queries.get(hash); + + if (entry == null) { + entry = new LogEntry(hash, type, sql, milli, nano); + queries.put(hash, entry); + } else { + entry.addCount(milli, nano); + } + + if (queries.size() > 1000) { + List toRemove = new LinkedList(); + List values = new LinkedList(queries.values()); + + Collections.sort(values, new Comparator() { + @Override + public int compare(LogEntry o1, LogEntry o2) { + return o1.count - o2.count; + } + }); + + while (queries.size() > 900) { + queries.remove(values.remove(0).hash); + + } + } + } + + public static void log(QueryType type, String sql, long milli, long nano) { + instance.logEntry(type, sql, milli, nano); + } + + public Collection getEntries() { + return queries.values(); + } + +} diff --git a/src/nl/astraeus/jdbc/PreparedStatementLogger.java b/src/nl/astraeus/jdbc/PreparedStatementLogger.java new file mode 100644 index 0000000..98aefc7 --- /dev/null +++ b/src/nl/astraeus/jdbc/PreparedStatementLogger.java @@ -0,0 +1,577 @@ +package nl.astraeus.jdbc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.InputStream; +import java.io.Reader; +import java.math.BigDecimal; +import java.net.URL; +import java.sql.*; +import java.util.Calendar; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 7:47:57 PM + */ +public class PreparedStatementLogger implements PreparedStatement { + private final static Logger log = LoggerFactory.getLogger(PreparedStatementLogger.class); + + private PreparedStatement statement; + + private String sql; + private QueryType type; + private long milli; + private long nano; + + //private ArrayList parameters; + + public PreparedStatementLogger(PreparedStatement statement) { + this.statement = statement; + this.sql = ""; + this.type = QueryType.UNKNOWN; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(QueryType type, String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(type, sql, m, n); + } + + public PreparedStatementLogger(Connection connection, String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql); + } + + public PreparedStatementLogger(Connection connection, String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatementLogger(Connection connection, String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, autoGeneratedKeys); + } + + public PreparedStatementLogger(Connection connection, String sql, int[] columnIndexes) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnIndexes); + } + + public PreparedStatementLogger(Connection connection, String sql, String[] columnNames) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnNames); + } + + public boolean execute() throws SQLException { + clearTime(); + + boolean result = statement.execute(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery() throws SQLException { + clearTime(); + + ResultSet result = statement.executeQuery(); + + log(type, sql); + + return result; + } + + public int executeUpdate() throws SQLException { + clearTime(); + + int result = statement.executeUpdate(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + ResultSet result = statement.executeQuery(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnNames); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnNames); + + log(type, sql); + + return result; + } + + + public void setNull(int parameterIndex, int sqlType) throws SQLException { + statement.setNull(parameterIndex, sqlType); + } + + public void setBoolean(int parameterIndex, boolean x) throws SQLException { + statement.setBoolean(parameterIndex, x); + } + + public void setByte(int parameterIndex, byte x) throws SQLException { + statement.setByte(parameterIndex, x); + } + + public void setShort(int parameterIndex, short x) throws SQLException { + statement.setShort(parameterIndex, x); + } + + public void setInt(int parameterIndex, int x) throws SQLException { + statement.setInt(parameterIndex, x); + } + + public void setLong(int parameterIndex, long x) throws SQLException { + statement.setLong(parameterIndex, x); + } + + public void setFloat(int parameterIndex, float x) throws SQLException { + statement.setFloat(parameterIndex, x); + } + + public void setDouble(int parameterIndex, double x) throws SQLException { + statement.setDouble(parameterIndex, x); + } + + public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { + statement.setBigDecimal(parameterIndex, x); + } + + public void setString(int parameterIndex, String x) throws SQLException { + statement.setString(parameterIndex, x); + } + + public void setBytes(int parameterIndex, byte x[]) throws SQLException { + statement.setBytes(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x) throws SQLException { + statement.setDate(parameterIndex, x); + } + + public void setTime(int parameterIndex, Time x) throws SQLException { + statement.setTime(parameterIndex, x); + } + + public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { + statement.setTimestamp(parameterIndex, x); + } + + public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setUnicodeStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType); + } + + public void setObject(int parameterIndex, Object x) throws SQLException { + statement.setObject(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setRef(int parameterIndex, Ref x) throws SQLException { + statement.setRef(parameterIndex, x); + } + + public void setBlob(int parameterIndex, Blob x) throws SQLException { + statement.setBlob(parameterIndex, x); + } + + public void setClob(int parameterIndex, Clob x) throws SQLException { + statement.setClob(parameterIndex, x); + } + + public void setArray(int parameterIndex, Array x) throws SQLException { + statement.setArray(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { + statement.setDate(parameterIndex, x, cal); + } + + public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { + statement.setTime(parameterIndex, x, cal); + } + + public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { + statement.setTimestamp(parameterIndex, x, cal); + } + + public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException { + statement.setNull(parameterIndex, sqlType, typeName); + } + + public void setURL(int parameterIndex, URL x) throws SQLException { + statement.setURL(parameterIndex, x); + } + + public void setRowId(int parameterIndex, RowId x) throws SQLException { + statement.setRowId(parameterIndex, x); + } + + public void setNString(int parameterIndex, String value) throws SQLException { + statement.setNString(parameterIndex, value); + } + + public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException { + statement.setNCharacterStream(parameterIndex, value, length); + } + + public void setNClob(int parameterIndex, NClob value) throws SQLException { + statement.setNClob(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setClob(parameterIndex, reader, length); + } + + public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException { + statement.setBlob(parameterIndex, inputStream, length); + } + + public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setNClob(parameterIndex, reader, length); + } + + public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException { + statement.setSQLXML(parameterIndex, xmlObject); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType, scaleOrLength); + } + + public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException { + statement.setAsciiStream(parameterIndex, x); + } + + public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException { + statement.setBinaryStream(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException { + statement.setCharacterStream(parameterIndex, reader); + } + + public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException { + statement.setNCharacterStream(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader) throws SQLException { + statement.setClob(parameterIndex, reader); + } + + public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException { + statement.setBlob(parameterIndex, inputStream); + } + + public void setNClob(int parameterIndex, Reader reader) throws SQLException { + statement.setNClob(parameterIndex, reader); + } + + + public void close() throws SQLException { + sql = ""; + type = QueryType.UNKNOWN; + milli = 0; + nano = 0; + + statement.close(); + } + + public ResultSetMetaData getMetaData() throws SQLException { + return statement.getMetaData(); + } + + public void clearParameters() throws SQLException { + statement.clearParameters(); + } + + public ParameterMetaData getParameterMetaData() throws SQLException { + return statement.getParameterMetaData(); + } + + public void addBatch() throws SQLException { + statement.addBatch(); + } + + public int getMaxFieldSize() throws SQLException { + return statement.getMaxFieldSize(); + } + + public void setMaxFieldSize(int max) throws SQLException { + statement.setMaxFieldSize(max); + } + + public int getMaxRows() throws SQLException { + return statement.getMaxRows(); + } + + public void setMaxRows(int max) throws SQLException { + statement.setMaxRows(max); + } + + public void setEscapeProcessing(boolean enable) throws SQLException { + statement.setEscapeProcessing(enable); + } + + public int getQueryTimeout() throws SQLException { + return statement.getQueryTimeout(); + } + + public void setQueryTimeout(int seconds) throws SQLException { + statement.setQueryTimeout(seconds); + } + + public void cancel() throws SQLException { + statement.cancel(); + } + + public SQLWarning getWarnings() throws SQLException { + return statement.getWarnings(); + } + + public void clearWarnings() throws SQLException { + statement.clearWarnings(); + } + + public void setCursorName(String name) throws SQLException { + statement.setCursorName(name); + } + + public boolean execute(String sql) throws SQLException { + return statement.execute(sql); + } + + public ResultSet getResultSet() throws SQLException { + return statement.getResultSet(); + } + + public int getUpdateCount() throws SQLException { + return statement.getUpdateCount(); + } + + public boolean getMoreResults() throws SQLException { + return statement.getMoreResults(); + } + + public void setFetchDirection(int direction) throws SQLException { + statement.setFetchDirection(direction); + } + + public int getFetchDirection() throws SQLException { + return statement.getFetchDirection(); + } + + public void setFetchSize(int rows) throws SQLException { + statement.setFetchSize(rows); + } + + public int getFetchSize() throws SQLException { + return statement.getFetchSize(); + } + + public int getResultSetConcurrency() throws SQLException { + return statement.getResultSetConcurrency(); + } + + public int getResultSetType() throws SQLException { + return statement.getResultSetType(); + } + + public void addBatch(String sql) throws SQLException { + statement.addBatch(sql); + } + + public void clearBatch() throws SQLException { + statement.clearBatch(); + } + + public int[] executeBatch() throws SQLException { + return statement.executeBatch(); + } + + public Connection getConnection() throws SQLException { + return statement.getConnection(); + } + + public boolean getMoreResults(int current) throws SQLException { + return statement.getMoreResults(current); + } + + public ResultSet getGeneratedKeys() throws SQLException { + return statement.getGeneratedKeys(); + } + + public int getResultSetHoldability() throws SQLException { + return statement.getResultSetHoldability(); + } + + public boolean isClosed() throws SQLException { + return statement.isClosed(); + } + + public void setPoolable(boolean poolable) throws SQLException { + statement.setPoolable(poolable); + } + + public boolean isPoolable() throws SQLException { + return statement.isPoolable(); + } + + @Override + public void closeOnCompletion() throws SQLException { + statement.closeOnCompletion();; + } + + @Override + public boolean isCloseOnCompletion() throws SQLException { + return statement.isCloseOnCompletion(); + } + + public T unwrap(Class iface) throws SQLException { + return statement.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return statement.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/QueryType.java b/src/nl/astraeus/jdbc/QueryType.java new file mode 100644 index 0000000..744fbfc --- /dev/null +++ b/src/nl/astraeus/jdbc/QueryType.java @@ -0,0 +1,24 @@ +package nl.astraeus.jdbc; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:32:49 PM + */ +public enum QueryType { + PLAIN("plain"), + PREPARED("prepared"), + CALLABLE("callable"), + UNKNOWN("unknown"); + + private String description; + + QueryType(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } + +} diff --git a/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java new file mode 100644 index 0000000..07aac40 --- /dev/null +++ b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java @@ -0,0 +1,68 @@ +package nl.astraeus.jdbc.example; + +import java.sql.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 7:32 PM + */ +public class JdbcStatisticsExample { + + + public static void main(String [] args) throws Exception { + Class.forName("org.h2.Driver"); + Class.forName("nl.astraeus.jdbc.Driver"); + + new JdbcStatisticsExample(); + } + + public JdbcStatisticsExample() throws Exception { + Connection conn = DriverManager.getConnection("jdbc:stat:jdbc:h2:mem:test"); + + Statement statement = null; + + statement = conn.createStatement(); + statement.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + + boolean running = true; + int count = 1; + PreparedStatement ps = null; + + while (running) { + Thread.sleep(10); + + String TableName = "TEST"+(System.nanoTime() % 1000); + + try { + ps = conn.prepareStatement("SELECT COUNT(*) FROM "+TableName); + ResultSet rs = ps.executeQuery(); + } catch (SQLException e) { + statement = conn.createStatement(); + statement.execute("CREATE TABLE "+TableName+" (ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + } finally { + if (ps!=null) { + ps.close(); + } + } + + ps = conn.prepareStatement("INSERT INTO "+TableName+" VALUES (?, ?)"); + + ps.setInt(1, count++); + ps.setString(2, "String "+System.currentTimeMillis()); + + ps.execute(); + ps.close(); + + Thread.sleep(10); + + ps = conn.prepareStatement("SELECT * FROM "+TableName); + ResultSet rs = ps.executeQuery(); + statement.close(); + } + + conn.close(); + } +} diff --git a/src/nl/astraeus/jdbc/util/IOUtils.java b/src/nl/astraeus/jdbc/util/IOUtils.java new file mode 100644 index 0000000..ce95d9d --- /dev/null +++ b/src/nl/astraeus/jdbc/util/IOUtils.java @@ -0,0 +1,38 @@ +package nl.astraeus.jdbc.util; + +import java.io.*; + +/** + * User: rnentjes + * Date: 4/9/12 + * Time: 2:33 PM + */ +public class IOUtils { + + public static String toString(InputStream in) throws IOException { + assert in != null; + + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + StringBuilder buffer = new StringBuilder(); + + while(reader.ready()) { + buffer.append(reader.readLine()); + buffer.append("\n"); + } + + return buffer.toString(); + } finally { + in.close(); + } + } + + public static void copy(InputStream in, OutputStream out) throws IOException { + byte [] buffer = new byte[1<<16]; + int bytes; + + while((bytes = in.read(buffer)) > 0) { + out.write(buffer, 0, bytes); + } + } +} diff --git a/src/nl/astraeus/jdbc/util/Util.java b/src/nl/astraeus/jdbc/util/Util.java new file mode 100644 index 0000000..eaa853b --- /dev/null +++ b/src/nl/astraeus/jdbc/util/Util.java @@ -0,0 +1,25 @@ +package nl.astraeus.jdbc.util; + +import java.text.DecimalFormat; +import java.text.NumberFormat; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 12:28 PM + */ +public class Util { + // utility functions + public static String formatNano(long l) { + NumberFormat format = new DecimalFormat("###,##0.000000"); + + return format.format((double) l / 1000000.0); + } + + public static void printMemoryUsage() { + System.out.println("Used memory: "+((Runtime.getRuntime().totalMemory() / (1024*1024))-(Runtime.getRuntime().freeMemory() / (1024*1024)))); + System.out.println("Free memory: "+(Runtime.getRuntime().freeMemory() / (1024*1024))); + System.out.println("Total memory: "+(Runtime.getRuntime().totalMemory() / (1024*1024))); + System.out.println("Max memory: "+(Runtime.getRuntime().maxMemory() / (1024*1024))); + } +} diff --git a/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java b/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java new file mode 100644 index 0000000..a162d6f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java @@ -0,0 +1,90 @@ +package nl.astraeus.jdbc.web; + +import nl.astraeus.jdbc.util.IOUtils; +import nl.astraeus.jdbc.util.Util; +import nl.astraeus.jdbc.web.page.Menu; +import nl.astraeus.jdbc.web.page.Page; +import nl.astraeus.jdbc.web.page.QueryOverview; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import java.io.IOException; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:05 PM + */ +public class JdbcStatisticsServlet extends HttpServlet { + + private String head; + private String bottom; + + @Override + public void init() throws ServletException { + super.init(); + + try { + head = IOUtils.toString(getClass().getResourceAsStream("head.html")); + bottom = IOUtils.toString(getClass().getResourceAsStream("bottom.html")); + } catch (IOException e) { + throw new ServletException(e); + } + + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + doPost(req, resp); + } + + @Override + protected void doPost(final HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + long nano = System.nanoTime(); + + HttpSession session = req.getSession(); + boolean ajax = "true".equals(req.getParameter("ajax")); + + resp.setContentType("text/html"); + + Page page = (Page)session.getAttribute("page"); + Page menu = (Page)session.getAttribute("menu"); + + session.setMaxInactiveInterval(1800); + + if (menu == null) { + menu = new Menu(); + + session.setAttribute("menu", menu); + } + + if (page == null || "menumain".equals(req.getParameter("action"))) { + page = new QueryOverview(); + } else if ("diagnostics".equals(req.getParameter("action"))) { + //page = new Diagnostics(); + } else { + page = page .processRequest(req); + } + + menu.processRequest(req); + + session.setAttribute("page", page); + + if (!ajax) { + resp.getWriter().print(head); + } + + resp.getWriter().print(menu.render(req)); + resp.getWriter().print(page.render(req)); + + if (!ajax) { + resp.getWriter().print(bottom); + } + + System.out.println("Request ends, time="+ Util.formatNano(System.nanoTime() - nano) +", page="+page.getClass().getSimpleName()); + } + +} diff --git a/src/nl/astraeus/jdbc/web/ResourceServlet.java b/src/nl/astraeus/jdbc/web/ResourceServlet.java new file mode 100644 index 0000000..7abfe6f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/ResourceServlet.java @@ -0,0 +1,49 @@ +package nl.astraeus.jdbc.web; + +import nl.astraeus.jdbc.util.IOUtils; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.InputStream; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:05 PM + */ +public class ResourceServlet extends HttpServlet { + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String uri = req.getRequestURI(); + + uri = "nl/astraeus/jdbc/web" + uri; + InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(uri); + + if (in == null) { + resp.sendError(404, "Cannot find resource '" + uri + "'."); + } else { + try { + if (uri.endsWith("js")) { + resp.setContentType("text/javascript"); + } else if (uri.endsWith("css")) { + resp.setContentType("text/css"); + } else if (uri.endsWith("png")) { + resp.setContentType("image/png"); + } else if (uri.endsWith("jpg")) { + resp.setContentType("image/jpeg"); + } else if (uri.endsWith("gif")) { + resp.setContentType("image/gif"); + } + + IOUtils.copy(in, resp.getOutputStream()); + } finally { + in.close(); + } + } + } + +} diff --git a/src/nl/astraeus/jdbc/web/bottom.html b/src/nl/astraeus/jdbc/web/bottom.html new file mode 100644 index 0000000..1288de4 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/bottom.html @@ -0,0 +1,8 @@ + + +
+ + + + + \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/head.html b/src/nl/astraeus/jdbc/web/head.html new file mode 100644 index 0000000..0f8f6a3 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/head.html @@ -0,0 +1,96 @@ + + + + + + + Simple JDBC Statistics + + + + + + + + + + + + + + + + + + + +
+
+ +
+ diff --git a/src/nl/astraeus/jdbc/web/page/Menu.html b/src/nl/astraeus/jdbc/web/page/Menu.html new file mode 100644 index 0000000..505c7c2 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.html @@ -0,0 +1,42 @@ + diff --git a/src/nl/astraeus/jdbc/web/page/Menu.java b/src/nl/astraeus/jdbc/web/page/Menu.java new file mode 100644 index 0000000..f0a349a --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.java @@ -0,0 +1,27 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 9:07 PM + */ +public class Menu extends TemplatePage { + + @Override + public Page processRequest(HttpServletRequest request) { + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + result.put("user", request.getSession().getAttribute("user")); + + return result; + } +} diff --git a/src/nl/astraeus/jdbc/web/page/Page.java b/src/nl/astraeus/jdbc/web/page/Page.java new file mode 100644 index 0000000..9d526d6 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Page.java @@ -0,0 +1,17 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:20 PM + */ +public abstract class Page { + + public abstract Page processRequest(HttpServletRequest request); + public abstract Map defineModel(HttpServletRequest request); + public abstract String render(HttpServletRequest request); + +} diff --git a/src/nl/astraeus/jdbc/web/page/QueryOverview.html b/src/nl/astraeus/jdbc/web/page/QueryOverview.html new file mode 100644 index 0000000..64a88fb --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/QueryOverview.html @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + {foreach(queries as q)} + + + + + + + {eachend} + +
Total timeAvg. time# CallsSql
{q.total}{q.nano}{q.count}{q.sql}
diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f403193 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..73ff239 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..3b00020 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..275077f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/README b/README deleted file mode 100644 index 734abaf..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -This file was created by IntelliJ IDEA 11.1.1 for binding GitHub repository \ No newline at end of file diff --git a/Simple-jdbc-statistics.iml b/Simple-jdbc-statistics.iml new file mode 100644 index 0000000..ca90a9b --- /dev/null +++ b/Simple-jdbc-statistics.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/lib/h2-1.3.166.jar b/lib/h2-1.3.166.jar new file mode 100644 index 0000000..4985063 --- /dev/null +++ b/lib/h2-1.3.166.jar Binary files differ diff --git a/lib/servlet-api-2.5.jar b/lib/servlet-api-2.5.jar new file mode 100644 index 0000000..20b5755 --- /dev/null +++ b/lib/servlet-api-2.5.jar Binary files differ diff --git a/lib/slf4j-api-1.6.4.jar b/lib/slf4j-api-1.6.4.jar new file mode 100644 index 0000000..4d23f41 --- /dev/null +++ b/lib/slf4j-api-1.6.4.jar Binary files differ diff --git a/lib/slf4j-simple-1.6.4.jar b/lib/slf4j-simple-1.6.4.jar new file mode 100644 index 0000000..3d1b8d9 --- /dev/null +++ b/lib/slf4j-simple-1.6.4.jar Binary files differ diff --git a/lib/ssr-0.1.jar b/lib/ssr-0.1.jar new file mode 100644 index 0000000..65dfcf4 --- /dev/null +++ b/lib/ssr-0.1.jar Binary files differ diff --git a/lib/vst-0.4.jar b/lib/vst-0.4.jar new file mode 100644 index 0000000..db63792 --- /dev/null +++ b/lib/vst-0.4.jar Binary files differ diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..ac2dbe1 --- /dev/null +++ b/readme.md @@ -0,0 +1 @@ +A simple wrapper around jdbc drivers what will show current jdbc stats of the running queries on a simple web page on port 18080. \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/ConnectionLogger.java b/src/nl/astraeus/jdbc/ConnectionLogger.java new file mode 100644 index 0000000..c3e243f --- /dev/null +++ b/src/nl/astraeus/jdbc/ConnectionLogger.java @@ -0,0 +1,279 @@ +package nl.astraeus.jdbc; + +import java.sql.*; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Executor; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:12:34 PM + */ +public class ConnectionLogger implements Connection { + private Connection connection; + + private long milli; + private long nano; + private String lastSql; + + public ConnectionLogger(Connection connection) { + this.connection = connection; + this.lastSql = ""; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(QueryType.UNKNOWN, sql, m, n); + } + + public void commit() throws SQLException { + clearTime(); + + connection.commit(); + + log("commit"); + } + + public void rollback() throws SQLException { + clearTime(); + + connection.rollback(); + + log("rollback"); + } + + public void close() throws SQLException { + clearTime(); + + connection.close(); + + log("close"); + } + + public PreparedStatement prepareStatement(String sql) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, autoGeneratedKeys); + } + + public PreparedStatement prepareStatement(String sql, int columnIndexes[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnIndexes); + } + + public PreparedStatement prepareStatement(String sql, String columnNames[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnNames); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public Statement createStatement() throws SQLException { + return connection.createStatement(); + } + + public CallableStatement prepareCall(String sql) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql); + } + + public String nativeSQL(String sql) throws SQLException { + lastSql = sql; + return connection.nativeSQL(sql); + } + + public void setAutoCommit(boolean autoCommit) throws SQLException { + connection.setAutoCommit(autoCommit); + } + + public boolean getAutoCommit() throws SQLException { + return connection.getAutoCommit(); + } + + public boolean isClosed() throws SQLException { + return connection.isClosed(); + } + + public DatabaseMetaData getMetaData() throws SQLException { + return connection.getMetaData(); + } + + public void setReadOnly(boolean readOnly) throws SQLException { + connection.setReadOnly(readOnly); + } + + public boolean isReadOnly() throws SQLException { + return connection.isReadOnly(); + } + + public void setCatalog(String catalog) throws SQLException { + connection.setCatalog(catalog); + } + + public String getCatalog() throws SQLException { + return connection.getCatalog(); + } + + public void setTransactionIsolation(int level) throws SQLException { + connection.setTransactionIsolation(level); + } + + public int getTransactionIsolation() throws SQLException { + return connection.getTransactionIsolation(); + } + + public SQLWarning getWarnings() throws SQLException { + return connection.getWarnings(); + } + + public void clearWarnings() throws SQLException { + connection.clearWarnings(); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency); + } + + public Map> getTypeMap() throws SQLException { + return connection.getTypeMap(); + } + + public void setTypeMap(Map> map) throws SQLException { + connection.setTypeMap(map); + } + + public void setHoldability(int holdability) throws SQLException { + connection.setHoldability(holdability); + } + + public int getHoldability() throws SQLException { + return connection.getHoldability(); + } + + public Savepoint setSavepoint() throws SQLException { + return connection.setSavepoint(); + } + + public Savepoint setSavepoint(String name) throws SQLException { + return connection.setSavepoint(name); + } + + public void rollback(Savepoint savepoint) throws SQLException { + connection.rollback(); + } + + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + connection.releaseSavepoint(savepoint); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public Clob createClob() throws SQLException { + return connection.createClob(); + } + + public Blob createBlob() throws SQLException { + return connection.createBlob(); + } + + public NClob createNClob() throws SQLException { + return connection.createNClob(); + } + + public SQLXML createSQLXML() throws SQLException { + return connection.createSQLXML(); + } + + public boolean isValid(int timeout) throws SQLException { + return connection.isValid(timeout); + } + + public void setClientInfo(String name, String value) throws SQLClientInfoException { + connection.setClientInfo(name, value); + } + + public void setClientInfo(Properties properties) throws SQLClientInfoException { + connection.setClientInfo(properties); + } + + public String getClientInfo(String name) throws SQLException { + return connection.getClientInfo(name); + } + + public Properties getClientInfo() throws SQLException { + return connection.getClientInfo(); + } + + public Array createArrayOf(String typeName, Object[] elements) throws SQLException { + return connection.createArrayOf(typeName, elements); + } + + public Struct createStruct(String typeName, Object[] attributes) throws SQLException { + return connection.createStruct(typeName, attributes); + } + + @Override + public void setSchema(String schema) throws SQLException { + connection.setSchema(schema); + } + + @Override + public String getSchema() throws SQLException { + return connection.getSchema(); + } + + @Override + public void abort(Executor executor) throws SQLException { + connection.abort(executor); + } + + @Override + public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { + connection.setNetworkTimeout(executor, milliseconds); + } + + @Override + public int getNetworkTimeout() throws SQLException { + return connection.getNetworkTimeout(); + } + + public T unwrap(Class iface) throws SQLException { + return connection.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return connection.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/Driver.java b/src/nl/astraeus/jdbc/Driver.java new file mode 100644 index 0000000..8317172 --- /dev/null +++ b/src/nl/astraeus/jdbc/Driver.java @@ -0,0 +1,116 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.http.SimpleWebServer; +import nl.astraeus.jdbc.web.JdbcStatisticsServlet; +import nl.astraeus.jdbc.web.ResourceServlet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.*; +import java.util.Enumeration; +import java.util.Properties; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:54:37 PM + */ +public class Driver implements java.sql.Driver { + private final static Logger log = LoggerFactory.getLogger(Driver.class); + + final private static String URL_PREFIX = "jdbc:stat:"; + + private java.sql.Driver driver = null; + private String[] drivers = { + "org.postgresql.Driver", + "oracle.jdbc.driver.OracleDriver", + "com.sybase.jdbc2.jdbc.SybDriver", + "net.sourceforge.jtds.jdbc.Driver", + "com.microsoft.jdbc.sqlserver.SQLServerDriver", + "com.microsoft.sqlserver.jdbc.SQLServerDriver", + "weblogic.jdbc.sqlserver.SQLServerDriver", + "com.informix.jdbc.IfxDriver", + "org.apache.derby.jdbc.ClientDriver", + "org.apache.derby.jdbc.EmbeddedDriver", + "com.mysql.jdbc.Driver", + "org.hsqldb.jdbcDriver", + "org.h2.Driver" }; + + static { + log.debug("Loading driver class " + Driver.class.getName()); + + try { + DriverManager.registerDriver(new Driver()); + } catch (SQLException e) { + log.error("", e); + } + } + + public Driver() { + for (String dr : drivers) { + try { + Class.forName(dr); + } catch (Throwable e) { + log.debug("Can't instantiate driver: " + dr, e); + } + } + } + + private java.sql.Driver findDriver(String url) throws SQLException { + Enumeration e = DriverManager.getDrivers(); + + while (e.hasMoreElements()) { + java.sql.Driver d = (java.sql.Driver) e.nextElement(); + + if (d.acceptsURL(url)) { + return d; + } + } + + throw new SQLException("Driver not found: " + url); + } + + public Connection connect(String url, Properties info) throws SQLException { + url = url.substring(URL_PREFIX.length()); + + if (driver == null) { + driver = findDriver(url); + } + + if (driver != null) { + SimpleWebServer server = new SimpleWebServer(18080); + + server.addServlet(new JdbcStatisticsServlet(), "/"); + server.addServlet(new ResourceServlet(), "/resources/*"); + + server.start(); + } + + return new ConnectionLogger(driver.connect(url, info)); + } + + public boolean acceptsURL(String url) throws SQLException { + return (url != null && url.startsWith(URL_PREFIX)); + } + + public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { + return driver.getPropertyInfo(url, info); + } + + public int getMajorVersion() { + return driver.getMajorVersion(); + } + + public int getMinorVersion() { + return driver.getMinorVersion(); + } + + public boolean jdbcCompliant() { + return driver.jdbcCompliant(); + } + + @Override + public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException { + return driver.getParentLogger(); + } +} diff --git a/src/nl/astraeus/jdbc/JdbcLogger.java b/src/nl/astraeus/jdbc/JdbcLogger.java new file mode 100644 index 0000000..f4bc125 --- /dev/null +++ b/src/nl/astraeus/jdbc/JdbcLogger.java @@ -0,0 +1,113 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.jdbc.util.Util; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/** + * User: riennentjes + * Date: Jul 12, 2008 + * Time: 9:15:21 AM + */ +public class JdbcLogger { + private final static Logger logger = LoggerFactory.getLogger(JdbcLogger.class); + + private final static JdbcLogger instance = new JdbcLogger(); + + public static JdbcLogger get() { + return instance; + } + + public final static class LogEntry { + public QueryType type; + public String sql; + public long milli; + public long nano; + public int count; + public int hash; + + public LogEntry(int hash, QueryType type, String sql, long milli, long nano) { + this.hash = hash; + this.type = type; + this.sql = sql; + this.milli = milli; + this.nano = nano; + this.count = 1; + } + + public void addCount(long milli, long nano) { + synchronized (this) { + count++; + this.milli += milli; + this.nano += nano; + } + } + + public int getCount() { + return count; + } + + public String getMilli() { + return Util.formatNano(milli*1000000/count); + } + + public String getNano() { + return Util.formatNano(nano/count); + } + + public String getTotal() { + return Util.formatNano(nano); + } + + public String getSql() { + return sql; + } + } + + private Map queries; + + public JdbcLogger() { + queries = new ConcurrentHashMap(); + } + + public void logEntry(QueryType type, String sql, long milli, long nano) { + int hash = sql.hashCode(); + LogEntry entry = queries.get(hash); + + if (entry == null) { + entry = new LogEntry(hash, type, sql, milli, nano); + queries.put(hash, entry); + } else { + entry.addCount(milli, nano); + } + + if (queries.size() > 1000) { + List toRemove = new LinkedList(); + List values = new LinkedList(queries.values()); + + Collections.sort(values, new Comparator() { + @Override + public int compare(LogEntry o1, LogEntry o2) { + return o1.count - o2.count; + } + }); + + while (queries.size() > 900) { + queries.remove(values.remove(0).hash); + + } + } + } + + public static void log(QueryType type, String sql, long milli, long nano) { + instance.logEntry(type, sql, milli, nano); + } + + public Collection getEntries() { + return queries.values(); + } + +} diff --git a/src/nl/astraeus/jdbc/PreparedStatementLogger.java b/src/nl/astraeus/jdbc/PreparedStatementLogger.java new file mode 100644 index 0000000..98aefc7 --- /dev/null +++ b/src/nl/astraeus/jdbc/PreparedStatementLogger.java @@ -0,0 +1,577 @@ +package nl.astraeus.jdbc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.InputStream; +import java.io.Reader; +import java.math.BigDecimal; +import java.net.URL; +import java.sql.*; +import java.util.Calendar; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 7:47:57 PM + */ +public class PreparedStatementLogger implements PreparedStatement { + private final static Logger log = LoggerFactory.getLogger(PreparedStatementLogger.class); + + private PreparedStatement statement; + + private String sql; + private QueryType type; + private long milli; + private long nano; + + //private ArrayList parameters; + + public PreparedStatementLogger(PreparedStatement statement) { + this.statement = statement; + this.sql = ""; + this.type = QueryType.UNKNOWN; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(QueryType type, String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(type, sql, m, n); + } + + public PreparedStatementLogger(Connection connection, String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql); + } + + public PreparedStatementLogger(Connection connection, String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatementLogger(Connection connection, String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, autoGeneratedKeys); + } + + public PreparedStatementLogger(Connection connection, String sql, int[] columnIndexes) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnIndexes); + } + + public PreparedStatementLogger(Connection connection, String sql, String[] columnNames) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnNames); + } + + public boolean execute() throws SQLException { + clearTime(); + + boolean result = statement.execute(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery() throws SQLException { + clearTime(); + + ResultSet result = statement.executeQuery(); + + log(type, sql); + + return result; + } + + public int executeUpdate() throws SQLException { + clearTime(); + + int result = statement.executeUpdate(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + ResultSet result = statement.executeQuery(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnNames); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnNames); + + log(type, sql); + + return result; + } + + + public void setNull(int parameterIndex, int sqlType) throws SQLException { + statement.setNull(parameterIndex, sqlType); + } + + public void setBoolean(int parameterIndex, boolean x) throws SQLException { + statement.setBoolean(parameterIndex, x); + } + + public void setByte(int parameterIndex, byte x) throws SQLException { + statement.setByte(parameterIndex, x); + } + + public void setShort(int parameterIndex, short x) throws SQLException { + statement.setShort(parameterIndex, x); + } + + public void setInt(int parameterIndex, int x) throws SQLException { + statement.setInt(parameterIndex, x); + } + + public void setLong(int parameterIndex, long x) throws SQLException { + statement.setLong(parameterIndex, x); + } + + public void setFloat(int parameterIndex, float x) throws SQLException { + statement.setFloat(parameterIndex, x); + } + + public void setDouble(int parameterIndex, double x) throws SQLException { + statement.setDouble(parameterIndex, x); + } + + public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { + statement.setBigDecimal(parameterIndex, x); + } + + public void setString(int parameterIndex, String x) throws SQLException { + statement.setString(parameterIndex, x); + } + + public void setBytes(int parameterIndex, byte x[]) throws SQLException { + statement.setBytes(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x) throws SQLException { + statement.setDate(parameterIndex, x); + } + + public void setTime(int parameterIndex, Time x) throws SQLException { + statement.setTime(parameterIndex, x); + } + + public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { + statement.setTimestamp(parameterIndex, x); + } + + public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setUnicodeStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType); + } + + public void setObject(int parameterIndex, Object x) throws SQLException { + statement.setObject(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setRef(int parameterIndex, Ref x) throws SQLException { + statement.setRef(parameterIndex, x); + } + + public void setBlob(int parameterIndex, Blob x) throws SQLException { + statement.setBlob(parameterIndex, x); + } + + public void setClob(int parameterIndex, Clob x) throws SQLException { + statement.setClob(parameterIndex, x); + } + + public void setArray(int parameterIndex, Array x) throws SQLException { + statement.setArray(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { + statement.setDate(parameterIndex, x, cal); + } + + public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { + statement.setTime(parameterIndex, x, cal); + } + + public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { + statement.setTimestamp(parameterIndex, x, cal); + } + + public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException { + statement.setNull(parameterIndex, sqlType, typeName); + } + + public void setURL(int parameterIndex, URL x) throws SQLException { + statement.setURL(parameterIndex, x); + } + + public void setRowId(int parameterIndex, RowId x) throws SQLException { + statement.setRowId(parameterIndex, x); + } + + public void setNString(int parameterIndex, String value) throws SQLException { + statement.setNString(parameterIndex, value); + } + + public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException { + statement.setNCharacterStream(parameterIndex, value, length); + } + + public void setNClob(int parameterIndex, NClob value) throws SQLException { + statement.setNClob(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setClob(parameterIndex, reader, length); + } + + public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException { + statement.setBlob(parameterIndex, inputStream, length); + } + + public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setNClob(parameterIndex, reader, length); + } + + public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException { + statement.setSQLXML(parameterIndex, xmlObject); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType, scaleOrLength); + } + + public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException { + statement.setAsciiStream(parameterIndex, x); + } + + public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException { + statement.setBinaryStream(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException { + statement.setCharacterStream(parameterIndex, reader); + } + + public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException { + statement.setNCharacterStream(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader) throws SQLException { + statement.setClob(parameterIndex, reader); + } + + public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException { + statement.setBlob(parameterIndex, inputStream); + } + + public void setNClob(int parameterIndex, Reader reader) throws SQLException { + statement.setNClob(parameterIndex, reader); + } + + + public void close() throws SQLException { + sql = ""; + type = QueryType.UNKNOWN; + milli = 0; + nano = 0; + + statement.close(); + } + + public ResultSetMetaData getMetaData() throws SQLException { + return statement.getMetaData(); + } + + public void clearParameters() throws SQLException { + statement.clearParameters(); + } + + public ParameterMetaData getParameterMetaData() throws SQLException { + return statement.getParameterMetaData(); + } + + public void addBatch() throws SQLException { + statement.addBatch(); + } + + public int getMaxFieldSize() throws SQLException { + return statement.getMaxFieldSize(); + } + + public void setMaxFieldSize(int max) throws SQLException { + statement.setMaxFieldSize(max); + } + + public int getMaxRows() throws SQLException { + return statement.getMaxRows(); + } + + public void setMaxRows(int max) throws SQLException { + statement.setMaxRows(max); + } + + public void setEscapeProcessing(boolean enable) throws SQLException { + statement.setEscapeProcessing(enable); + } + + public int getQueryTimeout() throws SQLException { + return statement.getQueryTimeout(); + } + + public void setQueryTimeout(int seconds) throws SQLException { + statement.setQueryTimeout(seconds); + } + + public void cancel() throws SQLException { + statement.cancel(); + } + + public SQLWarning getWarnings() throws SQLException { + return statement.getWarnings(); + } + + public void clearWarnings() throws SQLException { + statement.clearWarnings(); + } + + public void setCursorName(String name) throws SQLException { + statement.setCursorName(name); + } + + public boolean execute(String sql) throws SQLException { + return statement.execute(sql); + } + + public ResultSet getResultSet() throws SQLException { + return statement.getResultSet(); + } + + public int getUpdateCount() throws SQLException { + return statement.getUpdateCount(); + } + + public boolean getMoreResults() throws SQLException { + return statement.getMoreResults(); + } + + public void setFetchDirection(int direction) throws SQLException { + statement.setFetchDirection(direction); + } + + public int getFetchDirection() throws SQLException { + return statement.getFetchDirection(); + } + + public void setFetchSize(int rows) throws SQLException { + statement.setFetchSize(rows); + } + + public int getFetchSize() throws SQLException { + return statement.getFetchSize(); + } + + public int getResultSetConcurrency() throws SQLException { + return statement.getResultSetConcurrency(); + } + + public int getResultSetType() throws SQLException { + return statement.getResultSetType(); + } + + public void addBatch(String sql) throws SQLException { + statement.addBatch(sql); + } + + public void clearBatch() throws SQLException { + statement.clearBatch(); + } + + public int[] executeBatch() throws SQLException { + return statement.executeBatch(); + } + + public Connection getConnection() throws SQLException { + return statement.getConnection(); + } + + public boolean getMoreResults(int current) throws SQLException { + return statement.getMoreResults(current); + } + + public ResultSet getGeneratedKeys() throws SQLException { + return statement.getGeneratedKeys(); + } + + public int getResultSetHoldability() throws SQLException { + return statement.getResultSetHoldability(); + } + + public boolean isClosed() throws SQLException { + return statement.isClosed(); + } + + public void setPoolable(boolean poolable) throws SQLException { + statement.setPoolable(poolable); + } + + public boolean isPoolable() throws SQLException { + return statement.isPoolable(); + } + + @Override + public void closeOnCompletion() throws SQLException { + statement.closeOnCompletion();; + } + + @Override + public boolean isCloseOnCompletion() throws SQLException { + return statement.isCloseOnCompletion(); + } + + public T unwrap(Class iface) throws SQLException { + return statement.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return statement.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/QueryType.java b/src/nl/astraeus/jdbc/QueryType.java new file mode 100644 index 0000000..744fbfc --- /dev/null +++ b/src/nl/astraeus/jdbc/QueryType.java @@ -0,0 +1,24 @@ +package nl.astraeus.jdbc; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:32:49 PM + */ +public enum QueryType { + PLAIN("plain"), + PREPARED("prepared"), + CALLABLE("callable"), + UNKNOWN("unknown"); + + private String description; + + QueryType(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } + +} diff --git a/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java new file mode 100644 index 0000000..07aac40 --- /dev/null +++ b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java @@ -0,0 +1,68 @@ +package nl.astraeus.jdbc.example; + +import java.sql.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 7:32 PM + */ +public class JdbcStatisticsExample { + + + public static void main(String [] args) throws Exception { + Class.forName("org.h2.Driver"); + Class.forName("nl.astraeus.jdbc.Driver"); + + new JdbcStatisticsExample(); + } + + public JdbcStatisticsExample() throws Exception { + Connection conn = DriverManager.getConnection("jdbc:stat:jdbc:h2:mem:test"); + + Statement statement = null; + + statement = conn.createStatement(); + statement.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + + boolean running = true; + int count = 1; + PreparedStatement ps = null; + + while (running) { + Thread.sleep(10); + + String TableName = "TEST"+(System.nanoTime() % 1000); + + try { + ps = conn.prepareStatement("SELECT COUNT(*) FROM "+TableName); + ResultSet rs = ps.executeQuery(); + } catch (SQLException e) { + statement = conn.createStatement(); + statement.execute("CREATE TABLE "+TableName+" (ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + } finally { + if (ps!=null) { + ps.close(); + } + } + + ps = conn.prepareStatement("INSERT INTO "+TableName+" VALUES (?, ?)"); + + ps.setInt(1, count++); + ps.setString(2, "String "+System.currentTimeMillis()); + + ps.execute(); + ps.close(); + + Thread.sleep(10); + + ps = conn.prepareStatement("SELECT * FROM "+TableName); + ResultSet rs = ps.executeQuery(); + statement.close(); + } + + conn.close(); + } +} diff --git a/src/nl/astraeus/jdbc/util/IOUtils.java b/src/nl/astraeus/jdbc/util/IOUtils.java new file mode 100644 index 0000000..ce95d9d --- /dev/null +++ b/src/nl/astraeus/jdbc/util/IOUtils.java @@ -0,0 +1,38 @@ +package nl.astraeus.jdbc.util; + +import java.io.*; + +/** + * User: rnentjes + * Date: 4/9/12 + * Time: 2:33 PM + */ +public class IOUtils { + + public static String toString(InputStream in) throws IOException { + assert in != null; + + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + StringBuilder buffer = new StringBuilder(); + + while(reader.ready()) { + buffer.append(reader.readLine()); + buffer.append("\n"); + } + + return buffer.toString(); + } finally { + in.close(); + } + } + + public static void copy(InputStream in, OutputStream out) throws IOException { + byte [] buffer = new byte[1<<16]; + int bytes; + + while((bytes = in.read(buffer)) > 0) { + out.write(buffer, 0, bytes); + } + } +} diff --git a/src/nl/astraeus/jdbc/util/Util.java b/src/nl/astraeus/jdbc/util/Util.java new file mode 100644 index 0000000..eaa853b --- /dev/null +++ b/src/nl/astraeus/jdbc/util/Util.java @@ -0,0 +1,25 @@ +package nl.astraeus.jdbc.util; + +import java.text.DecimalFormat; +import java.text.NumberFormat; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 12:28 PM + */ +public class Util { + // utility functions + public static String formatNano(long l) { + NumberFormat format = new DecimalFormat("###,##0.000000"); + + return format.format((double) l / 1000000.0); + } + + public static void printMemoryUsage() { + System.out.println("Used memory: "+((Runtime.getRuntime().totalMemory() / (1024*1024))-(Runtime.getRuntime().freeMemory() / (1024*1024)))); + System.out.println("Free memory: "+(Runtime.getRuntime().freeMemory() / (1024*1024))); + System.out.println("Total memory: "+(Runtime.getRuntime().totalMemory() / (1024*1024))); + System.out.println("Max memory: "+(Runtime.getRuntime().maxMemory() / (1024*1024))); + } +} diff --git a/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java b/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java new file mode 100644 index 0000000..a162d6f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java @@ -0,0 +1,90 @@ +package nl.astraeus.jdbc.web; + +import nl.astraeus.jdbc.util.IOUtils; +import nl.astraeus.jdbc.util.Util; +import nl.astraeus.jdbc.web.page.Menu; +import nl.astraeus.jdbc.web.page.Page; +import nl.astraeus.jdbc.web.page.QueryOverview; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import java.io.IOException; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:05 PM + */ +public class JdbcStatisticsServlet extends HttpServlet { + + private String head; + private String bottom; + + @Override + public void init() throws ServletException { + super.init(); + + try { + head = IOUtils.toString(getClass().getResourceAsStream("head.html")); + bottom = IOUtils.toString(getClass().getResourceAsStream("bottom.html")); + } catch (IOException e) { + throw new ServletException(e); + } + + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + doPost(req, resp); + } + + @Override + protected void doPost(final HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + long nano = System.nanoTime(); + + HttpSession session = req.getSession(); + boolean ajax = "true".equals(req.getParameter("ajax")); + + resp.setContentType("text/html"); + + Page page = (Page)session.getAttribute("page"); + Page menu = (Page)session.getAttribute("menu"); + + session.setMaxInactiveInterval(1800); + + if (menu == null) { + menu = new Menu(); + + session.setAttribute("menu", menu); + } + + if (page == null || "menumain".equals(req.getParameter("action"))) { + page = new QueryOverview(); + } else if ("diagnostics".equals(req.getParameter("action"))) { + //page = new Diagnostics(); + } else { + page = page .processRequest(req); + } + + menu.processRequest(req); + + session.setAttribute("page", page); + + if (!ajax) { + resp.getWriter().print(head); + } + + resp.getWriter().print(menu.render(req)); + resp.getWriter().print(page.render(req)); + + if (!ajax) { + resp.getWriter().print(bottom); + } + + System.out.println("Request ends, time="+ Util.formatNano(System.nanoTime() - nano) +", page="+page.getClass().getSimpleName()); + } + +} diff --git a/src/nl/astraeus/jdbc/web/ResourceServlet.java b/src/nl/astraeus/jdbc/web/ResourceServlet.java new file mode 100644 index 0000000..7abfe6f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/ResourceServlet.java @@ -0,0 +1,49 @@ +package nl.astraeus.jdbc.web; + +import nl.astraeus.jdbc.util.IOUtils; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.InputStream; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:05 PM + */ +public class ResourceServlet extends HttpServlet { + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String uri = req.getRequestURI(); + + uri = "nl/astraeus/jdbc/web" + uri; + InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(uri); + + if (in == null) { + resp.sendError(404, "Cannot find resource '" + uri + "'."); + } else { + try { + if (uri.endsWith("js")) { + resp.setContentType("text/javascript"); + } else if (uri.endsWith("css")) { + resp.setContentType("text/css"); + } else if (uri.endsWith("png")) { + resp.setContentType("image/png"); + } else if (uri.endsWith("jpg")) { + resp.setContentType("image/jpeg"); + } else if (uri.endsWith("gif")) { + resp.setContentType("image/gif"); + } + + IOUtils.copy(in, resp.getOutputStream()); + } finally { + in.close(); + } + } + } + +} diff --git a/src/nl/astraeus/jdbc/web/bottom.html b/src/nl/astraeus/jdbc/web/bottom.html new file mode 100644 index 0000000..1288de4 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/bottom.html @@ -0,0 +1,8 @@ + + +
+ + + + + \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/head.html b/src/nl/astraeus/jdbc/web/head.html new file mode 100644 index 0000000..0f8f6a3 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/head.html @@ -0,0 +1,96 @@ + + + + + + + Simple JDBC Statistics + + + + + + + + + + + + + + + + + + + +
+
+ +
+ diff --git a/src/nl/astraeus/jdbc/web/page/Menu.html b/src/nl/astraeus/jdbc/web/page/Menu.html new file mode 100644 index 0000000..505c7c2 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.html @@ -0,0 +1,42 @@ + diff --git a/src/nl/astraeus/jdbc/web/page/Menu.java b/src/nl/astraeus/jdbc/web/page/Menu.java new file mode 100644 index 0000000..f0a349a --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.java @@ -0,0 +1,27 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 9:07 PM + */ +public class Menu extends TemplatePage { + + @Override + public Page processRequest(HttpServletRequest request) { + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + result.put("user", request.getSession().getAttribute("user")); + + return result; + } +} diff --git a/src/nl/astraeus/jdbc/web/page/Page.java b/src/nl/astraeus/jdbc/web/page/Page.java new file mode 100644 index 0000000..9d526d6 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Page.java @@ -0,0 +1,17 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:20 PM + */ +public abstract class Page { + + public abstract Page processRequest(HttpServletRequest request); + public abstract Map defineModel(HttpServletRequest request); + public abstract String render(HttpServletRequest request); + +} diff --git a/src/nl/astraeus/jdbc/web/page/QueryOverview.html b/src/nl/astraeus/jdbc/web/page/QueryOverview.html new file mode 100644 index 0000000..64a88fb --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/QueryOverview.html @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + {foreach(queries as q)} + + + + + + + {eachend} + +
Total timeAvg. time# CallsSql
{q.total}{q.nano}{q.count}{q.sql}
diff --git a/src/nl/astraeus/jdbc/web/page/QueryOverview.java b/src/nl/astraeus/jdbc/web/page/QueryOverview.java new file mode 100644 index 0000000..02982f1 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/QueryOverview.java @@ -0,0 +1,92 @@ +package nl.astraeus.jdbc.web.page; + +import nl.astraeus.jdbc.JdbcLogger; + +import javax.servlet.http.HttpServletRequest; +import java.util.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 9:16 PM + */ +public class QueryOverview extends TemplatePage { + + boolean sortTotalCalls = true; + boolean sortAvgTime = false; + boolean sortTotalTime = false; + + @Override + public Page processRequest(HttpServletRequest request) { + if ("sortTotalCalls".equals(request.getParameter("action"))) { + sortTotalCalls = true; + sortAvgTime = false; + sortTotalTime = false; + } else if ("sortAvgTime".equals(request.getParameter("action"))) { + sortTotalCalls = false; + sortAvgTime = true; + sortTotalTime = false; + } else if ("sortTotalTime".equals(request.getParameter("action"))) { + sortTotalCalls = false; + sortAvgTime = false; + sortTotalTime = true; + } + + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + List entries = new ArrayList(JdbcLogger.get().getEntries()); + + if (sortTotalCalls) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + return o2.count - o1.count; + } + }); + } else if (sortAvgTime) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + long n1 = o1.nano / o1.count; + long n2 = o2.nano / o2.count; + + if (n2 > n1) { + return 1; + } else if (n2 < n1) { + return -1; + } else { + return 0; + } + } + }); + } else if (sortTotalTime) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + if (o2.nano > o1.nano) { + return 1; + } else if (o2.nano < o1.nano) { + return -1; + } else { + return 0; + } + } + }); + } + + result.put("queries", entries); + result.put("count", entries.size()); + + result.put("sortTotalCalls", sortTotalCalls); + result.put("sortAvgTime", sortAvgTime); + result.put("sortTotalTime", sortTotalTime); + + return result; + } + +} diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f403193 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..73ff239 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..3b00020 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..275077f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/README b/README deleted file mode 100644 index 734abaf..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -This file was created by IntelliJ IDEA 11.1.1 for binding GitHub repository \ No newline at end of file diff --git a/Simple-jdbc-statistics.iml b/Simple-jdbc-statistics.iml new file mode 100644 index 0000000..ca90a9b --- /dev/null +++ b/Simple-jdbc-statistics.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/lib/h2-1.3.166.jar b/lib/h2-1.3.166.jar new file mode 100644 index 0000000..4985063 --- /dev/null +++ b/lib/h2-1.3.166.jar Binary files differ diff --git a/lib/servlet-api-2.5.jar b/lib/servlet-api-2.5.jar new file mode 100644 index 0000000..20b5755 --- /dev/null +++ b/lib/servlet-api-2.5.jar Binary files differ diff --git a/lib/slf4j-api-1.6.4.jar b/lib/slf4j-api-1.6.4.jar new file mode 100644 index 0000000..4d23f41 --- /dev/null +++ b/lib/slf4j-api-1.6.4.jar Binary files differ diff --git a/lib/slf4j-simple-1.6.4.jar b/lib/slf4j-simple-1.6.4.jar new file mode 100644 index 0000000..3d1b8d9 --- /dev/null +++ b/lib/slf4j-simple-1.6.4.jar Binary files differ diff --git a/lib/ssr-0.1.jar b/lib/ssr-0.1.jar new file mode 100644 index 0000000..65dfcf4 --- /dev/null +++ b/lib/ssr-0.1.jar Binary files differ diff --git a/lib/vst-0.4.jar b/lib/vst-0.4.jar new file mode 100644 index 0000000..db63792 --- /dev/null +++ b/lib/vst-0.4.jar Binary files differ diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..ac2dbe1 --- /dev/null +++ b/readme.md @@ -0,0 +1 @@ +A simple wrapper around jdbc drivers what will show current jdbc stats of the running queries on a simple web page on port 18080. \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/ConnectionLogger.java b/src/nl/astraeus/jdbc/ConnectionLogger.java new file mode 100644 index 0000000..c3e243f --- /dev/null +++ b/src/nl/astraeus/jdbc/ConnectionLogger.java @@ -0,0 +1,279 @@ +package nl.astraeus.jdbc; + +import java.sql.*; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Executor; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:12:34 PM + */ +public class ConnectionLogger implements Connection { + private Connection connection; + + private long milli; + private long nano; + private String lastSql; + + public ConnectionLogger(Connection connection) { + this.connection = connection; + this.lastSql = ""; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(QueryType.UNKNOWN, sql, m, n); + } + + public void commit() throws SQLException { + clearTime(); + + connection.commit(); + + log("commit"); + } + + public void rollback() throws SQLException { + clearTime(); + + connection.rollback(); + + log("rollback"); + } + + public void close() throws SQLException { + clearTime(); + + connection.close(); + + log("close"); + } + + public PreparedStatement prepareStatement(String sql) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, autoGeneratedKeys); + } + + public PreparedStatement prepareStatement(String sql, int columnIndexes[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnIndexes); + } + + public PreparedStatement prepareStatement(String sql, String columnNames[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnNames); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public Statement createStatement() throws SQLException { + return connection.createStatement(); + } + + public CallableStatement prepareCall(String sql) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql); + } + + public String nativeSQL(String sql) throws SQLException { + lastSql = sql; + return connection.nativeSQL(sql); + } + + public void setAutoCommit(boolean autoCommit) throws SQLException { + connection.setAutoCommit(autoCommit); + } + + public boolean getAutoCommit() throws SQLException { + return connection.getAutoCommit(); + } + + public boolean isClosed() throws SQLException { + return connection.isClosed(); + } + + public DatabaseMetaData getMetaData() throws SQLException { + return connection.getMetaData(); + } + + public void setReadOnly(boolean readOnly) throws SQLException { + connection.setReadOnly(readOnly); + } + + public boolean isReadOnly() throws SQLException { + return connection.isReadOnly(); + } + + public void setCatalog(String catalog) throws SQLException { + connection.setCatalog(catalog); + } + + public String getCatalog() throws SQLException { + return connection.getCatalog(); + } + + public void setTransactionIsolation(int level) throws SQLException { + connection.setTransactionIsolation(level); + } + + public int getTransactionIsolation() throws SQLException { + return connection.getTransactionIsolation(); + } + + public SQLWarning getWarnings() throws SQLException { + return connection.getWarnings(); + } + + public void clearWarnings() throws SQLException { + connection.clearWarnings(); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency); + } + + public Map> getTypeMap() throws SQLException { + return connection.getTypeMap(); + } + + public void setTypeMap(Map> map) throws SQLException { + connection.setTypeMap(map); + } + + public void setHoldability(int holdability) throws SQLException { + connection.setHoldability(holdability); + } + + public int getHoldability() throws SQLException { + return connection.getHoldability(); + } + + public Savepoint setSavepoint() throws SQLException { + return connection.setSavepoint(); + } + + public Savepoint setSavepoint(String name) throws SQLException { + return connection.setSavepoint(name); + } + + public void rollback(Savepoint savepoint) throws SQLException { + connection.rollback(); + } + + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + connection.releaseSavepoint(savepoint); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public Clob createClob() throws SQLException { + return connection.createClob(); + } + + public Blob createBlob() throws SQLException { + return connection.createBlob(); + } + + public NClob createNClob() throws SQLException { + return connection.createNClob(); + } + + public SQLXML createSQLXML() throws SQLException { + return connection.createSQLXML(); + } + + public boolean isValid(int timeout) throws SQLException { + return connection.isValid(timeout); + } + + public void setClientInfo(String name, String value) throws SQLClientInfoException { + connection.setClientInfo(name, value); + } + + public void setClientInfo(Properties properties) throws SQLClientInfoException { + connection.setClientInfo(properties); + } + + public String getClientInfo(String name) throws SQLException { + return connection.getClientInfo(name); + } + + public Properties getClientInfo() throws SQLException { + return connection.getClientInfo(); + } + + public Array createArrayOf(String typeName, Object[] elements) throws SQLException { + return connection.createArrayOf(typeName, elements); + } + + public Struct createStruct(String typeName, Object[] attributes) throws SQLException { + return connection.createStruct(typeName, attributes); + } + + @Override + public void setSchema(String schema) throws SQLException { + connection.setSchema(schema); + } + + @Override + public String getSchema() throws SQLException { + return connection.getSchema(); + } + + @Override + public void abort(Executor executor) throws SQLException { + connection.abort(executor); + } + + @Override + public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { + connection.setNetworkTimeout(executor, milliseconds); + } + + @Override + public int getNetworkTimeout() throws SQLException { + return connection.getNetworkTimeout(); + } + + public T unwrap(Class iface) throws SQLException { + return connection.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return connection.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/Driver.java b/src/nl/astraeus/jdbc/Driver.java new file mode 100644 index 0000000..8317172 --- /dev/null +++ b/src/nl/astraeus/jdbc/Driver.java @@ -0,0 +1,116 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.http.SimpleWebServer; +import nl.astraeus.jdbc.web.JdbcStatisticsServlet; +import nl.astraeus.jdbc.web.ResourceServlet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.*; +import java.util.Enumeration; +import java.util.Properties; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:54:37 PM + */ +public class Driver implements java.sql.Driver { + private final static Logger log = LoggerFactory.getLogger(Driver.class); + + final private static String URL_PREFIX = "jdbc:stat:"; + + private java.sql.Driver driver = null; + private String[] drivers = { + "org.postgresql.Driver", + "oracle.jdbc.driver.OracleDriver", + "com.sybase.jdbc2.jdbc.SybDriver", + "net.sourceforge.jtds.jdbc.Driver", + "com.microsoft.jdbc.sqlserver.SQLServerDriver", + "com.microsoft.sqlserver.jdbc.SQLServerDriver", + "weblogic.jdbc.sqlserver.SQLServerDriver", + "com.informix.jdbc.IfxDriver", + "org.apache.derby.jdbc.ClientDriver", + "org.apache.derby.jdbc.EmbeddedDriver", + "com.mysql.jdbc.Driver", + "org.hsqldb.jdbcDriver", + "org.h2.Driver" }; + + static { + log.debug("Loading driver class " + Driver.class.getName()); + + try { + DriverManager.registerDriver(new Driver()); + } catch (SQLException e) { + log.error("", e); + } + } + + public Driver() { + for (String dr : drivers) { + try { + Class.forName(dr); + } catch (Throwable e) { + log.debug("Can't instantiate driver: " + dr, e); + } + } + } + + private java.sql.Driver findDriver(String url) throws SQLException { + Enumeration e = DriverManager.getDrivers(); + + while (e.hasMoreElements()) { + java.sql.Driver d = (java.sql.Driver) e.nextElement(); + + if (d.acceptsURL(url)) { + return d; + } + } + + throw new SQLException("Driver not found: " + url); + } + + public Connection connect(String url, Properties info) throws SQLException { + url = url.substring(URL_PREFIX.length()); + + if (driver == null) { + driver = findDriver(url); + } + + if (driver != null) { + SimpleWebServer server = new SimpleWebServer(18080); + + server.addServlet(new JdbcStatisticsServlet(), "/"); + server.addServlet(new ResourceServlet(), "/resources/*"); + + server.start(); + } + + return new ConnectionLogger(driver.connect(url, info)); + } + + public boolean acceptsURL(String url) throws SQLException { + return (url != null && url.startsWith(URL_PREFIX)); + } + + public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { + return driver.getPropertyInfo(url, info); + } + + public int getMajorVersion() { + return driver.getMajorVersion(); + } + + public int getMinorVersion() { + return driver.getMinorVersion(); + } + + public boolean jdbcCompliant() { + return driver.jdbcCompliant(); + } + + @Override + public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException { + return driver.getParentLogger(); + } +} diff --git a/src/nl/astraeus/jdbc/JdbcLogger.java b/src/nl/astraeus/jdbc/JdbcLogger.java new file mode 100644 index 0000000..f4bc125 --- /dev/null +++ b/src/nl/astraeus/jdbc/JdbcLogger.java @@ -0,0 +1,113 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.jdbc.util.Util; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/** + * User: riennentjes + * Date: Jul 12, 2008 + * Time: 9:15:21 AM + */ +public class JdbcLogger { + private final static Logger logger = LoggerFactory.getLogger(JdbcLogger.class); + + private final static JdbcLogger instance = new JdbcLogger(); + + public static JdbcLogger get() { + return instance; + } + + public final static class LogEntry { + public QueryType type; + public String sql; + public long milli; + public long nano; + public int count; + public int hash; + + public LogEntry(int hash, QueryType type, String sql, long milli, long nano) { + this.hash = hash; + this.type = type; + this.sql = sql; + this.milli = milli; + this.nano = nano; + this.count = 1; + } + + public void addCount(long milli, long nano) { + synchronized (this) { + count++; + this.milli += milli; + this.nano += nano; + } + } + + public int getCount() { + return count; + } + + public String getMilli() { + return Util.formatNano(milli*1000000/count); + } + + public String getNano() { + return Util.formatNano(nano/count); + } + + public String getTotal() { + return Util.formatNano(nano); + } + + public String getSql() { + return sql; + } + } + + private Map queries; + + public JdbcLogger() { + queries = new ConcurrentHashMap(); + } + + public void logEntry(QueryType type, String sql, long milli, long nano) { + int hash = sql.hashCode(); + LogEntry entry = queries.get(hash); + + if (entry == null) { + entry = new LogEntry(hash, type, sql, milli, nano); + queries.put(hash, entry); + } else { + entry.addCount(milli, nano); + } + + if (queries.size() > 1000) { + List toRemove = new LinkedList(); + List values = new LinkedList(queries.values()); + + Collections.sort(values, new Comparator() { + @Override + public int compare(LogEntry o1, LogEntry o2) { + return o1.count - o2.count; + } + }); + + while (queries.size() > 900) { + queries.remove(values.remove(0).hash); + + } + } + } + + public static void log(QueryType type, String sql, long milli, long nano) { + instance.logEntry(type, sql, milli, nano); + } + + public Collection getEntries() { + return queries.values(); + } + +} diff --git a/src/nl/astraeus/jdbc/PreparedStatementLogger.java b/src/nl/astraeus/jdbc/PreparedStatementLogger.java new file mode 100644 index 0000000..98aefc7 --- /dev/null +++ b/src/nl/astraeus/jdbc/PreparedStatementLogger.java @@ -0,0 +1,577 @@ +package nl.astraeus.jdbc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.InputStream; +import java.io.Reader; +import java.math.BigDecimal; +import java.net.URL; +import java.sql.*; +import java.util.Calendar; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 7:47:57 PM + */ +public class PreparedStatementLogger implements PreparedStatement { + private final static Logger log = LoggerFactory.getLogger(PreparedStatementLogger.class); + + private PreparedStatement statement; + + private String sql; + private QueryType type; + private long milli; + private long nano; + + //private ArrayList parameters; + + public PreparedStatementLogger(PreparedStatement statement) { + this.statement = statement; + this.sql = ""; + this.type = QueryType.UNKNOWN; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(QueryType type, String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(type, sql, m, n); + } + + public PreparedStatementLogger(Connection connection, String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql); + } + + public PreparedStatementLogger(Connection connection, String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatementLogger(Connection connection, String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, autoGeneratedKeys); + } + + public PreparedStatementLogger(Connection connection, String sql, int[] columnIndexes) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnIndexes); + } + + public PreparedStatementLogger(Connection connection, String sql, String[] columnNames) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnNames); + } + + public boolean execute() throws SQLException { + clearTime(); + + boolean result = statement.execute(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery() throws SQLException { + clearTime(); + + ResultSet result = statement.executeQuery(); + + log(type, sql); + + return result; + } + + public int executeUpdate() throws SQLException { + clearTime(); + + int result = statement.executeUpdate(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + ResultSet result = statement.executeQuery(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnNames); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnNames); + + log(type, sql); + + return result; + } + + + public void setNull(int parameterIndex, int sqlType) throws SQLException { + statement.setNull(parameterIndex, sqlType); + } + + public void setBoolean(int parameterIndex, boolean x) throws SQLException { + statement.setBoolean(parameterIndex, x); + } + + public void setByte(int parameterIndex, byte x) throws SQLException { + statement.setByte(parameterIndex, x); + } + + public void setShort(int parameterIndex, short x) throws SQLException { + statement.setShort(parameterIndex, x); + } + + public void setInt(int parameterIndex, int x) throws SQLException { + statement.setInt(parameterIndex, x); + } + + public void setLong(int parameterIndex, long x) throws SQLException { + statement.setLong(parameterIndex, x); + } + + public void setFloat(int parameterIndex, float x) throws SQLException { + statement.setFloat(parameterIndex, x); + } + + public void setDouble(int parameterIndex, double x) throws SQLException { + statement.setDouble(parameterIndex, x); + } + + public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { + statement.setBigDecimal(parameterIndex, x); + } + + public void setString(int parameterIndex, String x) throws SQLException { + statement.setString(parameterIndex, x); + } + + public void setBytes(int parameterIndex, byte x[]) throws SQLException { + statement.setBytes(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x) throws SQLException { + statement.setDate(parameterIndex, x); + } + + public void setTime(int parameterIndex, Time x) throws SQLException { + statement.setTime(parameterIndex, x); + } + + public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { + statement.setTimestamp(parameterIndex, x); + } + + public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setUnicodeStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType); + } + + public void setObject(int parameterIndex, Object x) throws SQLException { + statement.setObject(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setRef(int parameterIndex, Ref x) throws SQLException { + statement.setRef(parameterIndex, x); + } + + public void setBlob(int parameterIndex, Blob x) throws SQLException { + statement.setBlob(parameterIndex, x); + } + + public void setClob(int parameterIndex, Clob x) throws SQLException { + statement.setClob(parameterIndex, x); + } + + public void setArray(int parameterIndex, Array x) throws SQLException { + statement.setArray(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { + statement.setDate(parameterIndex, x, cal); + } + + public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { + statement.setTime(parameterIndex, x, cal); + } + + public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { + statement.setTimestamp(parameterIndex, x, cal); + } + + public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException { + statement.setNull(parameterIndex, sqlType, typeName); + } + + public void setURL(int parameterIndex, URL x) throws SQLException { + statement.setURL(parameterIndex, x); + } + + public void setRowId(int parameterIndex, RowId x) throws SQLException { + statement.setRowId(parameterIndex, x); + } + + public void setNString(int parameterIndex, String value) throws SQLException { + statement.setNString(parameterIndex, value); + } + + public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException { + statement.setNCharacterStream(parameterIndex, value, length); + } + + public void setNClob(int parameterIndex, NClob value) throws SQLException { + statement.setNClob(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setClob(parameterIndex, reader, length); + } + + public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException { + statement.setBlob(parameterIndex, inputStream, length); + } + + public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setNClob(parameterIndex, reader, length); + } + + public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException { + statement.setSQLXML(parameterIndex, xmlObject); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType, scaleOrLength); + } + + public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException { + statement.setAsciiStream(parameterIndex, x); + } + + public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException { + statement.setBinaryStream(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException { + statement.setCharacterStream(parameterIndex, reader); + } + + public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException { + statement.setNCharacterStream(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader) throws SQLException { + statement.setClob(parameterIndex, reader); + } + + public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException { + statement.setBlob(parameterIndex, inputStream); + } + + public void setNClob(int parameterIndex, Reader reader) throws SQLException { + statement.setNClob(parameterIndex, reader); + } + + + public void close() throws SQLException { + sql = ""; + type = QueryType.UNKNOWN; + milli = 0; + nano = 0; + + statement.close(); + } + + public ResultSetMetaData getMetaData() throws SQLException { + return statement.getMetaData(); + } + + public void clearParameters() throws SQLException { + statement.clearParameters(); + } + + public ParameterMetaData getParameterMetaData() throws SQLException { + return statement.getParameterMetaData(); + } + + public void addBatch() throws SQLException { + statement.addBatch(); + } + + public int getMaxFieldSize() throws SQLException { + return statement.getMaxFieldSize(); + } + + public void setMaxFieldSize(int max) throws SQLException { + statement.setMaxFieldSize(max); + } + + public int getMaxRows() throws SQLException { + return statement.getMaxRows(); + } + + public void setMaxRows(int max) throws SQLException { + statement.setMaxRows(max); + } + + public void setEscapeProcessing(boolean enable) throws SQLException { + statement.setEscapeProcessing(enable); + } + + public int getQueryTimeout() throws SQLException { + return statement.getQueryTimeout(); + } + + public void setQueryTimeout(int seconds) throws SQLException { + statement.setQueryTimeout(seconds); + } + + public void cancel() throws SQLException { + statement.cancel(); + } + + public SQLWarning getWarnings() throws SQLException { + return statement.getWarnings(); + } + + public void clearWarnings() throws SQLException { + statement.clearWarnings(); + } + + public void setCursorName(String name) throws SQLException { + statement.setCursorName(name); + } + + public boolean execute(String sql) throws SQLException { + return statement.execute(sql); + } + + public ResultSet getResultSet() throws SQLException { + return statement.getResultSet(); + } + + public int getUpdateCount() throws SQLException { + return statement.getUpdateCount(); + } + + public boolean getMoreResults() throws SQLException { + return statement.getMoreResults(); + } + + public void setFetchDirection(int direction) throws SQLException { + statement.setFetchDirection(direction); + } + + public int getFetchDirection() throws SQLException { + return statement.getFetchDirection(); + } + + public void setFetchSize(int rows) throws SQLException { + statement.setFetchSize(rows); + } + + public int getFetchSize() throws SQLException { + return statement.getFetchSize(); + } + + public int getResultSetConcurrency() throws SQLException { + return statement.getResultSetConcurrency(); + } + + public int getResultSetType() throws SQLException { + return statement.getResultSetType(); + } + + public void addBatch(String sql) throws SQLException { + statement.addBatch(sql); + } + + public void clearBatch() throws SQLException { + statement.clearBatch(); + } + + public int[] executeBatch() throws SQLException { + return statement.executeBatch(); + } + + public Connection getConnection() throws SQLException { + return statement.getConnection(); + } + + public boolean getMoreResults(int current) throws SQLException { + return statement.getMoreResults(current); + } + + public ResultSet getGeneratedKeys() throws SQLException { + return statement.getGeneratedKeys(); + } + + public int getResultSetHoldability() throws SQLException { + return statement.getResultSetHoldability(); + } + + public boolean isClosed() throws SQLException { + return statement.isClosed(); + } + + public void setPoolable(boolean poolable) throws SQLException { + statement.setPoolable(poolable); + } + + public boolean isPoolable() throws SQLException { + return statement.isPoolable(); + } + + @Override + public void closeOnCompletion() throws SQLException { + statement.closeOnCompletion();; + } + + @Override + public boolean isCloseOnCompletion() throws SQLException { + return statement.isCloseOnCompletion(); + } + + public T unwrap(Class iface) throws SQLException { + return statement.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return statement.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/QueryType.java b/src/nl/astraeus/jdbc/QueryType.java new file mode 100644 index 0000000..744fbfc --- /dev/null +++ b/src/nl/astraeus/jdbc/QueryType.java @@ -0,0 +1,24 @@ +package nl.astraeus.jdbc; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:32:49 PM + */ +public enum QueryType { + PLAIN("plain"), + PREPARED("prepared"), + CALLABLE("callable"), + UNKNOWN("unknown"); + + private String description; + + QueryType(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } + +} diff --git a/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java new file mode 100644 index 0000000..07aac40 --- /dev/null +++ b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java @@ -0,0 +1,68 @@ +package nl.astraeus.jdbc.example; + +import java.sql.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 7:32 PM + */ +public class JdbcStatisticsExample { + + + public static void main(String [] args) throws Exception { + Class.forName("org.h2.Driver"); + Class.forName("nl.astraeus.jdbc.Driver"); + + new JdbcStatisticsExample(); + } + + public JdbcStatisticsExample() throws Exception { + Connection conn = DriverManager.getConnection("jdbc:stat:jdbc:h2:mem:test"); + + Statement statement = null; + + statement = conn.createStatement(); + statement.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + + boolean running = true; + int count = 1; + PreparedStatement ps = null; + + while (running) { + Thread.sleep(10); + + String TableName = "TEST"+(System.nanoTime() % 1000); + + try { + ps = conn.prepareStatement("SELECT COUNT(*) FROM "+TableName); + ResultSet rs = ps.executeQuery(); + } catch (SQLException e) { + statement = conn.createStatement(); + statement.execute("CREATE TABLE "+TableName+" (ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + } finally { + if (ps!=null) { + ps.close(); + } + } + + ps = conn.prepareStatement("INSERT INTO "+TableName+" VALUES (?, ?)"); + + ps.setInt(1, count++); + ps.setString(2, "String "+System.currentTimeMillis()); + + ps.execute(); + ps.close(); + + Thread.sleep(10); + + ps = conn.prepareStatement("SELECT * FROM "+TableName); + ResultSet rs = ps.executeQuery(); + statement.close(); + } + + conn.close(); + } +} diff --git a/src/nl/astraeus/jdbc/util/IOUtils.java b/src/nl/astraeus/jdbc/util/IOUtils.java new file mode 100644 index 0000000..ce95d9d --- /dev/null +++ b/src/nl/astraeus/jdbc/util/IOUtils.java @@ -0,0 +1,38 @@ +package nl.astraeus.jdbc.util; + +import java.io.*; + +/** + * User: rnentjes + * Date: 4/9/12 + * Time: 2:33 PM + */ +public class IOUtils { + + public static String toString(InputStream in) throws IOException { + assert in != null; + + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + StringBuilder buffer = new StringBuilder(); + + while(reader.ready()) { + buffer.append(reader.readLine()); + buffer.append("\n"); + } + + return buffer.toString(); + } finally { + in.close(); + } + } + + public static void copy(InputStream in, OutputStream out) throws IOException { + byte [] buffer = new byte[1<<16]; + int bytes; + + while((bytes = in.read(buffer)) > 0) { + out.write(buffer, 0, bytes); + } + } +} diff --git a/src/nl/astraeus/jdbc/util/Util.java b/src/nl/astraeus/jdbc/util/Util.java new file mode 100644 index 0000000..eaa853b --- /dev/null +++ b/src/nl/astraeus/jdbc/util/Util.java @@ -0,0 +1,25 @@ +package nl.astraeus.jdbc.util; + +import java.text.DecimalFormat; +import java.text.NumberFormat; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 12:28 PM + */ +public class Util { + // utility functions + public static String formatNano(long l) { + NumberFormat format = new DecimalFormat("###,##0.000000"); + + return format.format((double) l / 1000000.0); + } + + public static void printMemoryUsage() { + System.out.println("Used memory: "+((Runtime.getRuntime().totalMemory() / (1024*1024))-(Runtime.getRuntime().freeMemory() / (1024*1024)))); + System.out.println("Free memory: "+(Runtime.getRuntime().freeMemory() / (1024*1024))); + System.out.println("Total memory: "+(Runtime.getRuntime().totalMemory() / (1024*1024))); + System.out.println("Max memory: "+(Runtime.getRuntime().maxMemory() / (1024*1024))); + } +} diff --git a/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java b/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java new file mode 100644 index 0000000..a162d6f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java @@ -0,0 +1,90 @@ +package nl.astraeus.jdbc.web; + +import nl.astraeus.jdbc.util.IOUtils; +import nl.astraeus.jdbc.util.Util; +import nl.astraeus.jdbc.web.page.Menu; +import nl.astraeus.jdbc.web.page.Page; +import nl.astraeus.jdbc.web.page.QueryOverview; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import java.io.IOException; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:05 PM + */ +public class JdbcStatisticsServlet extends HttpServlet { + + private String head; + private String bottom; + + @Override + public void init() throws ServletException { + super.init(); + + try { + head = IOUtils.toString(getClass().getResourceAsStream("head.html")); + bottom = IOUtils.toString(getClass().getResourceAsStream("bottom.html")); + } catch (IOException e) { + throw new ServletException(e); + } + + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + doPost(req, resp); + } + + @Override + protected void doPost(final HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + long nano = System.nanoTime(); + + HttpSession session = req.getSession(); + boolean ajax = "true".equals(req.getParameter("ajax")); + + resp.setContentType("text/html"); + + Page page = (Page)session.getAttribute("page"); + Page menu = (Page)session.getAttribute("menu"); + + session.setMaxInactiveInterval(1800); + + if (menu == null) { + menu = new Menu(); + + session.setAttribute("menu", menu); + } + + if (page == null || "menumain".equals(req.getParameter("action"))) { + page = new QueryOverview(); + } else if ("diagnostics".equals(req.getParameter("action"))) { + //page = new Diagnostics(); + } else { + page = page .processRequest(req); + } + + menu.processRequest(req); + + session.setAttribute("page", page); + + if (!ajax) { + resp.getWriter().print(head); + } + + resp.getWriter().print(menu.render(req)); + resp.getWriter().print(page.render(req)); + + if (!ajax) { + resp.getWriter().print(bottom); + } + + System.out.println("Request ends, time="+ Util.formatNano(System.nanoTime() - nano) +", page="+page.getClass().getSimpleName()); + } + +} diff --git a/src/nl/astraeus/jdbc/web/ResourceServlet.java b/src/nl/astraeus/jdbc/web/ResourceServlet.java new file mode 100644 index 0000000..7abfe6f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/ResourceServlet.java @@ -0,0 +1,49 @@ +package nl.astraeus.jdbc.web; + +import nl.astraeus.jdbc.util.IOUtils; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.InputStream; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:05 PM + */ +public class ResourceServlet extends HttpServlet { + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String uri = req.getRequestURI(); + + uri = "nl/astraeus/jdbc/web" + uri; + InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(uri); + + if (in == null) { + resp.sendError(404, "Cannot find resource '" + uri + "'."); + } else { + try { + if (uri.endsWith("js")) { + resp.setContentType("text/javascript"); + } else if (uri.endsWith("css")) { + resp.setContentType("text/css"); + } else if (uri.endsWith("png")) { + resp.setContentType("image/png"); + } else if (uri.endsWith("jpg")) { + resp.setContentType("image/jpeg"); + } else if (uri.endsWith("gif")) { + resp.setContentType("image/gif"); + } + + IOUtils.copy(in, resp.getOutputStream()); + } finally { + in.close(); + } + } + } + +} diff --git a/src/nl/astraeus/jdbc/web/bottom.html b/src/nl/astraeus/jdbc/web/bottom.html new file mode 100644 index 0000000..1288de4 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/bottom.html @@ -0,0 +1,8 @@ + + +
+ + + + + \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/head.html b/src/nl/astraeus/jdbc/web/head.html new file mode 100644 index 0000000..0f8f6a3 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/head.html @@ -0,0 +1,96 @@ + + + + + + + Simple JDBC Statistics + + + + + + + + + + + + + + + + + + + +
+
+ +
+ diff --git a/src/nl/astraeus/jdbc/web/page/Menu.html b/src/nl/astraeus/jdbc/web/page/Menu.html new file mode 100644 index 0000000..505c7c2 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.html @@ -0,0 +1,42 @@ + diff --git a/src/nl/astraeus/jdbc/web/page/Menu.java b/src/nl/astraeus/jdbc/web/page/Menu.java new file mode 100644 index 0000000..f0a349a --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.java @@ -0,0 +1,27 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 9:07 PM + */ +public class Menu extends TemplatePage { + + @Override + public Page processRequest(HttpServletRequest request) { + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + result.put("user", request.getSession().getAttribute("user")); + + return result; + } +} diff --git a/src/nl/astraeus/jdbc/web/page/Page.java b/src/nl/astraeus/jdbc/web/page/Page.java new file mode 100644 index 0000000..9d526d6 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Page.java @@ -0,0 +1,17 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:20 PM + */ +public abstract class Page { + + public abstract Page processRequest(HttpServletRequest request); + public abstract Map defineModel(HttpServletRequest request); + public abstract String render(HttpServletRequest request); + +} diff --git a/src/nl/astraeus/jdbc/web/page/QueryOverview.html b/src/nl/astraeus/jdbc/web/page/QueryOverview.html new file mode 100644 index 0000000..64a88fb --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/QueryOverview.html @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + {foreach(queries as q)} + + + + + + + {eachend} + +
Total timeAvg. time# CallsSql
{q.total}{q.nano}{q.count}{q.sql}
diff --git a/src/nl/astraeus/jdbc/web/page/QueryOverview.java b/src/nl/astraeus/jdbc/web/page/QueryOverview.java new file mode 100644 index 0000000..02982f1 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/QueryOverview.java @@ -0,0 +1,92 @@ +package nl.astraeus.jdbc.web.page; + +import nl.astraeus.jdbc.JdbcLogger; + +import javax.servlet.http.HttpServletRequest; +import java.util.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 9:16 PM + */ +public class QueryOverview extends TemplatePage { + + boolean sortTotalCalls = true; + boolean sortAvgTime = false; + boolean sortTotalTime = false; + + @Override + public Page processRequest(HttpServletRequest request) { + if ("sortTotalCalls".equals(request.getParameter("action"))) { + sortTotalCalls = true; + sortAvgTime = false; + sortTotalTime = false; + } else if ("sortAvgTime".equals(request.getParameter("action"))) { + sortTotalCalls = false; + sortAvgTime = true; + sortTotalTime = false; + } else if ("sortTotalTime".equals(request.getParameter("action"))) { + sortTotalCalls = false; + sortAvgTime = false; + sortTotalTime = true; + } + + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + List entries = new ArrayList(JdbcLogger.get().getEntries()); + + if (sortTotalCalls) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + return o2.count - o1.count; + } + }); + } else if (sortAvgTime) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + long n1 = o1.nano / o1.count; + long n2 = o2.nano / o2.count; + + if (n2 > n1) { + return 1; + } else if (n2 < n1) { + return -1; + } else { + return 0; + } + } + }); + } else if (sortTotalTime) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + if (o2.nano > o1.nano) { + return 1; + } else if (o2.nano < o1.nano) { + return -1; + } else { + return 0; + } + } + }); + } + + result.put("queries", entries); + result.put("count", entries.size()); + + result.put("sortTotalCalls", sortTotalCalls); + result.put("sortAvgTime", sortAvgTime); + result.put("sortTotalTime", sortTotalTime); + + return result; + } + +} diff --git a/src/nl/astraeus/jdbc/web/page/TemplatePage.java b/src/nl/astraeus/jdbc/web/page/TemplatePage.java new file mode 100644 index 0000000..33e2641 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/TemplatePage.java @@ -0,0 +1,58 @@ +package nl.astraeus.jdbc.web.page; + +import nl.astraeus.template.EscapeMode; +import nl.astraeus.template.SimpleTemplate; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:20 PM + */ +public abstract class TemplatePage extends Page { + + private SimpleTemplate template; + + protected TemplatePage() { + template = getSimpleTemplate(this.getClass()); + } + + public String render(HttpServletRequest request) { + return template.render(defineModel(request)); + } + + private static Map templateCache = new HashMap(); + + public synchronized static SimpleTemplate getSimpleTemplate(Class cls) { + SimpleTemplate result = templateCache.get(cls); + + if (result == null) { + InputStream in = null; + + try { + in = cls.getResourceAsStream(cls.getSimpleName() + ".html"); + + result = SimpleTemplate.readTemplate('{','}', EscapeMode.HTML, in); + + templateCache.put(cls, result); + } catch (IOException e) { + throw new IllegalStateException(e); + } finally { + if (in != null) { + try { + in.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + + return result; + } +} diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f403193 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..73ff239 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..3b00020 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..275077f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/README b/README deleted file mode 100644 index 734abaf..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -This file was created by IntelliJ IDEA 11.1.1 for binding GitHub repository \ No newline at end of file diff --git a/Simple-jdbc-statistics.iml b/Simple-jdbc-statistics.iml new file mode 100644 index 0000000..ca90a9b --- /dev/null +++ b/Simple-jdbc-statistics.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/lib/h2-1.3.166.jar b/lib/h2-1.3.166.jar new file mode 100644 index 0000000..4985063 --- /dev/null +++ b/lib/h2-1.3.166.jar Binary files differ diff --git a/lib/servlet-api-2.5.jar b/lib/servlet-api-2.5.jar new file mode 100644 index 0000000..20b5755 --- /dev/null +++ b/lib/servlet-api-2.5.jar Binary files differ diff --git a/lib/slf4j-api-1.6.4.jar b/lib/slf4j-api-1.6.4.jar new file mode 100644 index 0000000..4d23f41 --- /dev/null +++ b/lib/slf4j-api-1.6.4.jar Binary files differ diff --git a/lib/slf4j-simple-1.6.4.jar b/lib/slf4j-simple-1.6.4.jar new file mode 100644 index 0000000..3d1b8d9 --- /dev/null +++ b/lib/slf4j-simple-1.6.4.jar Binary files differ diff --git a/lib/ssr-0.1.jar b/lib/ssr-0.1.jar new file mode 100644 index 0000000..65dfcf4 --- /dev/null +++ b/lib/ssr-0.1.jar Binary files differ diff --git a/lib/vst-0.4.jar b/lib/vst-0.4.jar new file mode 100644 index 0000000..db63792 --- /dev/null +++ b/lib/vst-0.4.jar Binary files differ diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..ac2dbe1 --- /dev/null +++ b/readme.md @@ -0,0 +1 @@ +A simple wrapper around jdbc drivers what will show current jdbc stats of the running queries on a simple web page on port 18080. \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/ConnectionLogger.java b/src/nl/astraeus/jdbc/ConnectionLogger.java new file mode 100644 index 0000000..c3e243f --- /dev/null +++ b/src/nl/astraeus/jdbc/ConnectionLogger.java @@ -0,0 +1,279 @@ +package nl.astraeus.jdbc; + +import java.sql.*; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Executor; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:12:34 PM + */ +public class ConnectionLogger implements Connection { + private Connection connection; + + private long milli; + private long nano; + private String lastSql; + + public ConnectionLogger(Connection connection) { + this.connection = connection; + this.lastSql = ""; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(QueryType.UNKNOWN, sql, m, n); + } + + public void commit() throws SQLException { + clearTime(); + + connection.commit(); + + log("commit"); + } + + public void rollback() throws SQLException { + clearTime(); + + connection.rollback(); + + log("rollback"); + } + + public void close() throws SQLException { + clearTime(); + + connection.close(); + + log("close"); + } + + public PreparedStatement prepareStatement(String sql) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, autoGeneratedKeys); + } + + public PreparedStatement prepareStatement(String sql, int columnIndexes[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnIndexes); + } + + public PreparedStatement prepareStatement(String sql, String columnNames[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnNames); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public Statement createStatement() throws SQLException { + return connection.createStatement(); + } + + public CallableStatement prepareCall(String sql) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql); + } + + public String nativeSQL(String sql) throws SQLException { + lastSql = sql; + return connection.nativeSQL(sql); + } + + public void setAutoCommit(boolean autoCommit) throws SQLException { + connection.setAutoCommit(autoCommit); + } + + public boolean getAutoCommit() throws SQLException { + return connection.getAutoCommit(); + } + + public boolean isClosed() throws SQLException { + return connection.isClosed(); + } + + public DatabaseMetaData getMetaData() throws SQLException { + return connection.getMetaData(); + } + + public void setReadOnly(boolean readOnly) throws SQLException { + connection.setReadOnly(readOnly); + } + + public boolean isReadOnly() throws SQLException { + return connection.isReadOnly(); + } + + public void setCatalog(String catalog) throws SQLException { + connection.setCatalog(catalog); + } + + public String getCatalog() throws SQLException { + return connection.getCatalog(); + } + + public void setTransactionIsolation(int level) throws SQLException { + connection.setTransactionIsolation(level); + } + + public int getTransactionIsolation() throws SQLException { + return connection.getTransactionIsolation(); + } + + public SQLWarning getWarnings() throws SQLException { + return connection.getWarnings(); + } + + public void clearWarnings() throws SQLException { + connection.clearWarnings(); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency); + } + + public Map> getTypeMap() throws SQLException { + return connection.getTypeMap(); + } + + public void setTypeMap(Map> map) throws SQLException { + connection.setTypeMap(map); + } + + public void setHoldability(int holdability) throws SQLException { + connection.setHoldability(holdability); + } + + public int getHoldability() throws SQLException { + return connection.getHoldability(); + } + + public Savepoint setSavepoint() throws SQLException { + return connection.setSavepoint(); + } + + public Savepoint setSavepoint(String name) throws SQLException { + return connection.setSavepoint(name); + } + + public void rollback(Savepoint savepoint) throws SQLException { + connection.rollback(); + } + + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + connection.releaseSavepoint(savepoint); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public Clob createClob() throws SQLException { + return connection.createClob(); + } + + public Blob createBlob() throws SQLException { + return connection.createBlob(); + } + + public NClob createNClob() throws SQLException { + return connection.createNClob(); + } + + public SQLXML createSQLXML() throws SQLException { + return connection.createSQLXML(); + } + + public boolean isValid(int timeout) throws SQLException { + return connection.isValid(timeout); + } + + public void setClientInfo(String name, String value) throws SQLClientInfoException { + connection.setClientInfo(name, value); + } + + public void setClientInfo(Properties properties) throws SQLClientInfoException { + connection.setClientInfo(properties); + } + + public String getClientInfo(String name) throws SQLException { + return connection.getClientInfo(name); + } + + public Properties getClientInfo() throws SQLException { + return connection.getClientInfo(); + } + + public Array createArrayOf(String typeName, Object[] elements) throws SQLException { + return connection.createArrayOf(typeName, elements); + } + + public Struct createStruct(String typeName, Object[] attributes) throws SQLException { + return connection.createStruct(typeName, attributes); + } + + @Override + public void setSchema(String schema) throws SQLException { + connection.setSchema(schema); + } + + @Override + public String getSchema() throws SQLException { + return connection.getSchema(); + } + + @Override + public void abort(Executor executor) throws SQLException { + connection.abort(executor); + } + + @Override + public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { + connection.setNetworkTimeout(executor, milliseconds); + } + + @Override + public int getNetworkTimeout() throws SQLException { + return connection.getNetworkTimeout(); + } + + public T unwrap(Class iface) throws SQLException { + return connection.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return connection.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/Driver.java b/src/nl/astraeus/jdbc/Driver.java new file mode 100644 index 0000000..8317172 --- /dev/null +++ b/src/nl/astraeus/jdbc/Driver.java @@ -0,0 +1,116 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.http.SimpleWebServer; +import nl.astraeus.jdbc.web.JdbcStatisticsServlet; +import nl.astraeus.jdbc.web.ResourceServlet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.*; +import java.util.Enumeration; +import java.util.Properties; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:54:37 PM + */ +public class Driver implements java.sql.Driver { + private final static Logger log = LoggerFactory.getLogger(Driver.class); + + final private static String URL_PREFIX = "jdbc:stat:"; + + private java.sql.Driver driver = null; + private String[] drivers = { + "org.postgresql.Driver", + "oracle.jdbc.driver.OracleDriver", + "com.sybase.jdbc2.jdbc.SybDriver", + "net.sourceforge.jtds.jdbc.Driver", + "com.microsoft.jdbc.sqlserver.SQLServerDriver", + "com.microsoft.sqlserver.jdbc.SQLServerDriver", + "weblogic.jdbc.sqlserver.SQLServerDriver", + "com.informix.jdbc.IfxDriver", + "org.apache.derby.jdbc.ClientDriver", + "org.apache.derby.jdbc.EmbeddedDriver", + "com.mysql.jdbc.Driver", + "org.hsqldb.jdbcDriver", + "org.h2.Driver" }; + + static { + log.debug("Loading driver class " + Driver.class.getName()); + + try { + DriverManager.registerDriver(new Driver()); + } catch (SQLException e) { + log.error("", e); + } + } + + public Driver() { + for (String dr : drivers) { + try { + Class.forName(dr); + } catch (Throwable e) { + log.debug("Can't instantiate driver: " + dr, e); + } + } + } + + private java.sql.Driver findDriver(String url) throws SQLException { + Enumeration e = DriverManager.getDrivers(); + + while (e.hasMoreElements()) { + java.sql.Driver d = (java.sql.Driver) e.nextElement(); + + if (d.acceptsURL(url)) { + return d; + } + } + + throw new SQLException("Driver not found: " + url); + } + + public Connection connect(String url, Properties info) throws SQLException { + url = url.substring(URL_PREFIX.length()); + + if (driver == null) { + driver = findDriver(url); + } + + if (driver != null) { + SimpleWebServer server = new SimpleWebServer(18080); + + server.addServlet(new JdbcStatisticsServlet(), "/"); + server.addServlet(new ResourceServlet(), "/resources/*"); + + server.start(); + } + + return new ConnectionLogger(driver.connect(url, info)); + } + + public boolean acceptsURL(String url) throws SQLException { + return (url != null && url.startsWith(URL_PREFIX)); + } + + public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { + return driver.getPropertyInfo(url, info); + } + + public int getMajorVersion() { + return driver.getMajorVersion(); + } + + public int getMinorVersion() { + return driver.getMinorVersion(); + } + + public boolean jdbcCompliant() { + return driver.jdbcCompliant(); + } + + @Override + public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException { + return driver.getParentLogger(); + } +} diff --git a/src/nl/astraeus/jdbc/JdbcLogger.java b/src/nl/astraeus/jdbc/JdbcLogger.java new file mode 100644 index 0000000..f4bc125 --- /dev/null +++ b/src/nl/astraeus/jdbc/JdbcLogger.java @@ -0,0 +1,113 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.jdbc.util.Util; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/** + * User: riennentjes + * Date: Jul 12, 2008 + * Time: 9:15:21 AM + */ +public class JdbcLogger { + private final static Logger logger = LoggerFactory.getLogger(JdbcLogger.class); + + private final static JdbcLogger instance = new JdbcLogger(); + + public static JdbcLogger get() { + return instance; + } + + public final static class LogEntry { + public QueryType type; + public String sql; + public long milli; + public long nano; + public int count; + public int hash; + + public LogEntry(int hash, QueryType type, String sql, long milli, long nano) { + this.hash = hash; + this.type = type; + this.sql = sql; + this.milli = milli; + this.nano = nano; + this.count = 1; + } + + public void addCount(long milli, long nano) { + synchronized (this) { + count++; + this.milli += milli; + this.nano += nano; + } + } + + public int getCount() { + return count; + } + + public String getMilli() { + return Util.formatNano(milli*1000000/count); + } + + public String getNano() { + return Util.formatNano(nano/count); + } + + public String getTotal() { + return Util.formatNano(nano); + } + + public String getSql() { + return sql; + } + } + + private Map queries; + + public JdbcLogger() { + queries = new ConcurrentHashMap(); + } + + public void logEntry(QueryType type, String sql, long milli, long nano) { + int hash = sql.hashCode(); + LogEntry entry = queries.get(hash); + + if (entry == null) { + entry = new LogEntry(hash, type, sql, milli, nano); + queries.put(hash, entry); + } else { + entry.addCount(milli, nano); + } + + if (queries.size() > 1000) { + List toRemove = new LinkedList(); + List values = new LinkedList(queries.values()); + + Collections.sort(values, new Comparator() { + @Override + public int compare(LogEntry o1, LogEntry o2) { + return o1.count - o2.count; + } + }); + + while (queries.size() > 900) { + queries.remove(values.remove(0).hash); + + } + } + } + + public static void log(QueryType type, String sql, long milli, long nano) { + instance.logEntry(type, sql, milli, nano); + } + + public Collection getEntries() { + return queries.values(); + } + +} diff --git a/src/nl/astraeus/jdbc/PreparedStatementLogger.java b/src/nl/astraeus/jdbc/PreparedStatementLogger.java new file mode 100644 index 0000000..98aefc7 --- /dev/null +++ b/src/nl/astraeus/jdbc/PreparedStatementLogger.java @@ -0,0 +1,577 @@ +package nl.astraeus.jdbc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.InputStream; +import java.io.Reader; +import java.math.BigDecimal; +import java.net.URL; +import java.sql.*; +import java.util.Calendar; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 7:47:57 PM + */ +public class PreparedStatementLogger implements PreparedStatement { + private final static Logger log = LoggerFactory.getLogger(PreparedStatementLogger.class); + + private PreparedStatement statement; + + private String sql; + private QueryType type; + private long milli; + private long nano; + + //private ArrayList parameters; + + public PreparedStatementLogger(PreparedStatement statement) { + this.statement = statement; + this.sql = ""; + this.type = QueryType.UNKNOWN; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(QueryType type, String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(type, sql, m, n); + } + + public PreparedStatementLogger(Connection connection, String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql); + } + + public PreparedStatementLogger(Connection connection, String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatementLogger(Connection connection, String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, autoGeneratedKeys); + } + + public PreparedStatementLogger(Connection connection, String sql, int[] columnIndexes) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnIndexes); + } + + public PreparedStatementLogger(Connection connection, String sql, String[] columnNames) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnNames); + } + + public boolean execute() throws SQLException { + clearTime(); + + boolean result = statement.execute(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery() throws SQLException { + clearTime(); + + ResultSet result = statement.executeQuery(); + + log(type, sql); + + return result; + } + + public int executeUpdate() throws SQLException { + clearTime(); + + int result = statement.executeUpdate(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + ResultSet result = statement.executeQuery(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnNames); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnNames); + + log(type, sql); + + return result; + } + + + public void setNull(int parameterIndex, int sqlType) throws SQLException { + statement.setNull(parameterIndex, sqlType); + } + + public void setBoolean(int parameterIndex, boolean x) throws SQLException { + statement.setBoolean(parameterIndex, x); + } + + public void setByte(int parameterIndex, byte x) throws SQLException { + statement.setByte(parameterIndex, x); + } + + public void setShort(int parameterIndex, short x) throws SQLException { + statement.setShort(parameterIndex, x); + } + + public void setInt(int parameterIndex, int x) throws SQLException { + statement.setInt(parameterIndex, x); + } + + public void setLong(int parameterIndex, long x) throws SQLException { + statement.setLong(parameterIndex, x); + } + + public void setFloat(int parameterIndex, float x) throws SQLException { + statement.setFloat(parameterIndex, x); + } + + public void setDouble(int parameterIndex, double x) throws SQLException { + statement.setDouble(parameterIndex, x); + } + + public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { + statement.setBigDecimal(parameterIndex, x); + } + + public void setString(int parameterIndex, String x) throws SQLException { + statement.setString(parameterIndex, x); + } + + public void setBytes(int parameterIndex, byte x[]) throws SQLException { + statement.setBytes(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x) throws SQLException { + statement.setDate(parameterIndex, x); + } + + public void setTime(int parameterIndex, Time x) throws SQLException { + statement.setTime(parameterIndex, x); + } + + public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { + statement.setTimestamp(parameterIndex, x); + } + + public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setUnicodeStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType); + } + + public void setObject(int parameterIndex, Object x) throws SQLException { + statement.setObject(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setRef(int parameterIndex, Ref x) throws SQLException { + statement.setRef(parameterIndex, x); + } + + public void setBlob(int parameterIndex, Blob x) throws SQLException { + statement.setBlob(parameterIndex, x); + } + + public void setClob(int parameterIndex, Clob x) throws SQLException { + statement.setClob(parameterIndex, x); + } + + public void setArray(int parameterIndex, Array x) throws SQLException { + statement.setArray(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { + statement.setDate(parameterIndex, x, cal); + } + + public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { + statement.setTime(parameterIndex, x, cal); + } + + public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { + statement.setTimestamp(parameterIndex, x, cal); + } + + public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException { + statement.setNull(parameterIndex, sqlType, typeName); + } + + public void setURL(int parameterIndex, URL x) throws SQLException { + statement.setURL(parameterIndex, x); + } + + public void setRowId(int parameterIndex, RowId x) throws SQLException { + statement.setRowId(parameterIndex, x); + } + + public void setNString(int parameterIndex, String value) throws SQLException { + statement.setNString(parameterIndex, value); + } + + public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException { + statement.setNCharacterStream(parameterIndex, value, length); + } + + public void setNClob(int parameterIndex, NClob value) throws SQLException { + statement.setNClob(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setClob(parameterIndex, reader, length); + } + + public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException { + statement.setBlob(parameterIndex, inputStream, length); + } + + public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setNClob(parameterIndex, reader, length); + } + + public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException { + statement.setSQLXML(parameterIndex, xmlObject); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType, scaleOrLength); + } + + public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException { + statement.setAsciiStream(parameterIndex, x); + } + + public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException { + statement.setBinaryStream(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException { + statement.setCharacterStream(parameterIndex, reader); + } + + public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException { + statement.setNCharacterStream(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader) throws SQLException { + statement.setClob(parameterIndex, reader); + } + + public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException { + statement.setBlob(parameterIndex, inputStream); + } + + public void setNClob(int parameterIndex, Reader reader) throws SQLException { + statement.setNClob(parameterIndex, reader); + } + + + public void close() throws SQLException { + sql = ""; + type = QueryType.UNKNOWN; + milli = 0; + nano = 0; + + statement.close(); + } + + public ResultSetMetaData getMetaData() throws SQLException { + return statement.getMetaData(); + } + + public void clearParameters() throws SQLException { + statement.clearParameters(); + } + + public ParameterMetaData getParameterMetaData() throws SQLException { + return statement.getParameterMetaData(); + } + + public void addBatch() throws SQLException { + statement.addBatch(); + } + + public int getMaxFieldSize() throws SQLException { + return statement.getMaxFieldSize(); + } + + public void setMaxFieldSize(int max) throws SQLException { + statement.setMaxFieldSize(max); + } + + public int getMaxRows() throws SQLException { + return statement.getMaxRows(); + } + + public void setMaxRows(int max) throws SQLException { + statement.setMaxRows(max); + } + + public void setEscapeProcessing(boolean enable) throws SQLException { + statement.setEscapeProcessing(enable); + } + + public int getQueryTimeout() throws SQLException { + return statement.getQueryTimeout(); + } + + public void setQueryTimeout(int seconds) throws SQLException { + statement.setQueryTimeout(seconds); + } + + public void cancel() throws SQLException { + statement.cancel(); + } + + public SQLWarning getWarnings() throws SQLException { + return statement.getWarnings(); + } + + public void clearWarnings() throws SQLException { + statement.clearWarnings(); + } + + public void setCursorName(String name) throws SQLException { + statement.setCursorName(name); + } + + public boolean execute(String sql) throws SQLException { + return statement.execute(sql); + } + + public ResultSet getResultSet() throws SQLException { + return statement.getResultSet(); + } + + public int getUpdateCount() throws SQLException { + return statement.getUpdateCount(); + } + + public boolean getMoreResults() throws SQLException { + return statement.getMoreResults(); + } + + public void setFetchDirection(int direction) throws SQLException { + statement.setFetchDirection(direction); + } + + public int getFetchDirection() throws SQLException { + return statement.getFetchDirection(); + } + + public void setFetchSize(int rows) throws SQLException { + statement.setFetchSize(rows); + } + + public int getFetchSize() throws SQLException { + return statement.getFetchSize(); + } + + public int getResultSetConcurrency() throws SQLException { + return statement.getResultSetConcurrency(); + } + + public int getResultSetType() throws SQLException { + return statement.getResultSetType(); + } + + public void addBatch(String sql) throws SQLException { + statement.addBatch(sql); + } + + public void clearBatch() throws SQLException { + statement.clearBatch(); + } + + public int[] executeBatch() throws SQLException { + return statement.executeBatch(); + } + + public Connection getConnection() throws SQLException { + return statement.getConnection(); + } + + public boolean getMoreResults(int current) throws SQLException { + return statement.getMoreResults(current); + } + + public ResultSet getGeneratedKeys() throws SQLException { + return statement.getGeneratedKeys(); + } + + public int getResultSetHoldability() throws SQLException { + return statement.getResultSetHoldability(); + } + + public boolean isClosed() throws SQLException { + return statement.isClosed(); + } + + public void setPoolable(boolean poolable) throws SQLException { + statement.setPoolable(poolable); + } + + public boolean isPoolable() throws SQLException { + return statement.isPoolable(); + } + + @Override + public void closeOnCompletion() throws SQLException { + statement.closeOnCompletion();; + } + + @Override + public boolean isCloseOnCompletion() throws SQLException { + return statement.isCloseOnCompletion(); + } + + public T unwrap(Class iface) throws SQLException { + return statement.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return statement.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/QueryType.java b/src/nl/astraeus/jdbc/QueryType.java new file mode 100644 index 0000000..744fbfc --- /dev/null +++ b/src/nl/astraeus/jdbc/QueryType.java @@ -0,0 +1,24 @@ +package nl.astraeus.jdbc; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:32:49 PM + */ +public enum QueryType { + PLAIN("plain"), + PREPARED("prepared"), + CALLABLE("callable"), + UNKNOWN("unknown"); + + private String description; + + QueryType(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } + +} diff --git a/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java new file mode 100644 index 0000000..07aac40 --- /dev/null +++ b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java @@ -0,0 +1,68 @@ +package nl.astraeus.jdbc.example; + +import java.sql.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 7:32 PM + */ +public class JdbcStatisticsExample { + + + public static void main(String [] args) throws Exception { + Class.forName("org.h2.Driver"); + Class.forName("nl.astraeus.jdbc.Driver"); + + new JdbcStatisticsExample(); + } + + public JdbcStatisticsExample() throws Exception { + Connection conn = DriverManager.getConnection("jdbc:stat:jdbc:h2:mem:test"); + + Statement statement = null; + + statement = conn.createStatement(); + statement.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + + boolean running = true; + int count = 1; + PreparedStatement ps = null; + + while (running) { + Thread.sleep(10); + + String TableName = "TEST"+(System.nanoTime() % 1000); + + try { + ps = conn.prepareStatement("SELECT COUNT(*) FROM "+TableName); + ResultSet rs = ps.executeQuery(); + } catch (SQLException e) { + statement = conn.createStatement(); + statement.execute("CREATE TABLE "+TableName+" (ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + } finally { + if (ps!=null) { + ps.close(); + } + } + + ps = conn.prepareStatement("INSERT INTO "+TableName+" VALUES (?, ?)"); + + ps.setInt(1, count++); + ps.setString(2, "String "+System.currentTimeMillis()); + + ps.execute(); + ps.close(); + + Thread.sleep(10); + + ps = conn.prepareStatement("SELECT * FROM "+TableName); + ResultSet rs = ps.executeQuery(); + statement.close(); + } + + conn.close(); + } +} diff --git a/src/nl/astraeus/jdbc/util/IOUtils.java b/src/nl/astraeus/jdbc/util/IOUtils.java new file mode 100644 index 0000000..ce95d9d --- /dev/null +++ b/src/nl/astraeus/jdbc/util/IOUtils.java @@ -0,0 +1,38 @@ +package nl.astraeus.jdbc.util; + +import java.io.*; + +/** + * User: rnentjes + * Date: 4/9/12 + * Time: 2:33 PM + */ +public class IOUtils { + + public static String toString(InputStream in) throws IOException { + assert in != null; + + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + StringBuilder buffer = new StringBuilder(); + + while(reader.ready()) { + buffer.append(reader.readLine()); + buffer.append("\n"); + } + + return buffer.toString(); + } finally { + in.close(); + } + } + + public static void copy(InputStream in, OutputStream out) throws IOException { + byte [] buffer = new byte[1<<16]; + int bytes; + + while((bytes = in.read(buffer)) > 0) { + out.write(buffer, 0, bytes); + } + } +} diff --git a/src/nl/astraeus/jdbc/util/Util.java b/src/nl/astraeus/jdbc/util/Util.java new file mode 100644 index 0000000..eaa853b --- /dev/null +++ b/src/nl/astraeus/jdbc/util/Util.java @@ -0,0 +1,25 @@ +package nl.astraeus.jdbc.util; + +import java.text.DecimalFormat; +import java.text.NumberFormat; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 12:28 PM + */ +public class Util { + // utility functions + public static String formatNano(long l) { + NumberFormat format = new DecimalFormat("###,##0.000000"); + + return format.format((double) l / 1000000.0); + } + + public static void printMemoryUsage() { + System.out.println("Used memory: "+((Runtime.getRuntime().totalMemory() / (1024*1024))-(Runtime.getRuntime().freeMemory() / (1024*1024)))); + System.out.println("Free memory: "+(Runtime.getRuntime().freeMemory() / (1024*1024))); + System.out.println("Total memory: "+(Runtime.getRuntime().totalMemory() / (1024*1024))); + System.out.println("Max memory: "+(Runtime.getRuntime().maxMemory() / (1024*1024))); + } +} diff --git a/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java b/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java new file mode 100644 index 0000000..a162d6f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java @@ -0,0 +1,90 @@ +package nl.astraeus.jdbc.web; + +import nl.astraeus.jdbc.util.IOUtils; +import nl.astraeus.jdbc.util.Util; +import nl.astraeus.jdbc.web.page.Menu; +import nl.astraeus.jdbc.web.page.Page; +import nl.astraeus.jdbc.web.page.QueryOverview; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import java.io.IOException; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:05 PM + */ +public class JdbcStatisticsServlet extends HttpServlet { + + private String head; + private String bottom; + + @Override + public void init() throws ServletException { + super.init(); + + try { + head = IOUtils.toString(getClass().getResourceAsStream("head.html")); + bottom = IOUtils.toString(getClass().getResourceAsStream("bottom.html")); + } catch (IOException e) { + throw new ServletException(e); + } + + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + doPost(req, resp); + } + + @Override + protected void doPost(final HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + long nano = System.nanoTime(); + + HttpSession session = req.getSession(); + boolean ajax = "true".equals(req.getParameter("ajax")); + + resp.setContentType("text/html"); + + Page page = (Page)session.getAttribute("page"); + Page menu = (Page)session.getAttribute("menu"); + + session.setMaxInactiveInterval(1800); + + if (menu == null) { + menu = new Menu(); + + session.setAttribute("menu", menu); + } + + if (page == null || "menumain".equals(req.getParameter("action"))) { + page = new QueryOverview(); + } else if ("diagnostics".equals(req.getParameter("action"))) { + //page = new Diagnostics(); + } else { + page = page .processRequest(req); + } + + menu.processRequest(req); + + session.setAttribute("page", page); + + if (!ajax) { + resp.getWriter().print(head); + } + + resp.getWriter().print(menu.render(req)); + resp.getWriter().print(page.render(req)); + + if (!ajax) { + resp.getWriter().print(bottom); + } + + System.out.println("Request ends, time="+ Util.formatNano(System.nanoTime() - nano) +", page="+page.getClass().getSimpleName()); + } + +} diff --git a/src/nl/astraeus/jdbc/web/ResourceServlet.java b/src/nl/astraeus/jdbc/web/ResourceServlet.java new file mode 100644 index 0000000..7abfe6f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/ResourceServlet.java @@ -0,0 +1,49 @@ +package nl.astraeus.jdbc.web; + +import nl.astraeus.jdbc.util.IOUtils; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.InputStream; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:05 PM + */ +public class ResourceServlet extends HttpServlet { + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String uri = req.getRequestURI(); + + uri = "nl/astraeus/jdbc/web" + uri; + InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(uri); + + if (in == null) { + resp.sendError(404, "Cannot find resource '" + uri + "'."); + } else { + try { + if (uri.endsWith("js")) { + resp.setContentType("text/javascript"); + } else if (uri.endsWith("css")) { + resp.setContentType("text/css"); + } else if (uri.endsWith("png")) { + resp.setContentType("image/png"); + } else if (uri.endsWith("jpg")) { + resp.setContentType("image/jpeg"); + } else if (uri.endsWith("gif")) { + resp.setContentType("image/gif"); + } + + IOUtils.copy(in, resp.getOutputStream()); + } finally { + in.close(); + } + } + } + +} diff --git a/src/nl/astraeus/jdbc/web/bottom.html b/src/nl/astraeus/jdbc/web/bottom.html new file mode 100644 index 0000000..1288de4 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/bottom.html @@ -0,0 +1,8 @@ + + +
+ + + + + \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/head.html b/src/nl/astraeus/jdbc/web/head.html new file mode 100644 index 0000000..0f8f6a3 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/head.html @@ -0,0 +1,96 @@ + + + + + + + Simple JDBC Statistics + + + + + + + + + + + + + + + + + + + +
+
+ +
+ diff --git a/src/nl/astraeus/jdbc/web/page/Menu.html b/src/nl/astraeus/jdbc/web/page/Menu.html new file mode 100644 index 0000000..505c7c2 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.html @@ -0,0 +1,42 @@ + diff --git a/src/nl/astraeus/jdbc/web/page/Menu.java b/src/nl/astraeus/jdbc/web/page/Menu.java new file mode 100644 index 0000000..f0a349a --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.java @@ -0,0 +1,27 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 9:07 PM + */ +public class Menu extends TemplatePage { + + @Override + public Page processRequest(HttpServletRequest request) { + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + result.put("user", request.getSession().getAttribute("user")); + + return result; + } +} diff --git a/src/nl/astraeus/jdbc/web/page/Page.java b/src/nl/astraeus/jdbc/web/page/Page.java new file mode 100644 index 0000000..9d526d6 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Page.java @@ -0,0 +1,17 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:20 PM + */ +public abstract class Page { + + public abstract Page processRequest(HttpServletRequest request); + public abstract Map defineModel(HttpServletRequest request); + public abstract String render(HttpServletRequest request); + +} diff --git a/src/nl/astraeus/jdbc/web/page/QueryOverview.html b/src/nl/astraeus/jdbc/web/page/QueryOverview.html new file mode 100644 index 0000000..64a88fb --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/QueryOverview.html @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + {foreach(queries as q)} + + + + + + + {eachend} + +
Total timeAvg. time# CallsSql
{q.total}{q.nano}{q.count}{q.sql}
diff --git a/src/nl/astraeus/jdbc/web/page/QueryOverview.java b/src/nl/astraeus/jdbc/web/page/QueryOverview.java new file mode 100644 index 0000000..02982f1 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/QueryOverview.java @@ -0,0 +1,92 @@ +package nl.astraeus.jdbc.web.page; + +import nl.astraeus.jdbc.JdbcLogger; + +import javax.servlet.http.HttpServletRequest; +import java.util.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 9:16 PM + */ +public class QueryOverview extends TemplatePage { + + boolean sortTotalCalls = true; + boolean sortAvgTime = false; + boolean sortTotalTime = false; + + @Override + public Page processRequest(HttpServletRequest request) { + if ("sortTotalCalls".equals(request.getParameter("action"))) { + sortTotalCalls = true; + sortAvgTime = false; + sortTotalTime = false; + } else if ("sortAvgTime".equals(request.getParameter("action"))) { + sortTotalCalls = false; + sortAvgTime = true; + sortTotalTime = false; + } else if ("sortTotalTime".equals(request.getParameter("action"))) { + sortTotalCalls = false; + sortAvgTime = false; + sortTotalTime = true; + } + + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + List entries = new ArrayList(JdbcLogger.get().getEntries()); + + if (sortTotalCalls) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + return o2.count - o1.count; + } + }); + } else if (sortAvgTime) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + long n1 = o1.nano / o1.count; + long n2 = o2.nano / o2.count; + + if (n2 > n1) { + return 1; + } else if (n2 < n1) { + return -1; + } else { + return 0; + } + } + }); + } else if (sortTotalTime) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + if (o2.nano > o1.nano) { + return 1; + } else if (o2.nano < o1.nano) { + return -1; + } else { + return 0; + } + } + }); + } + + result.put("queries", entries); + result.put("count", entries.size()); + + result.put("sortTotalCalls", sortTotalCalls); + result.put("sortAvgTime", sortAvgTime); + result.put("sortTotalTime", sortTotalTime); + + return result; + } + +} diff --git a/src/nl/astraeus/jdbc/web/page/TemplatePage.java b/src/nl/astraeus/jdbc/web/page/TemplatePage.java new file mode 100644 index 0000000..33e2641 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/TemplatePage.java @@ -0,0 +1,58 @@ +package nl.astraeus.jdbc.web.page; + +import nl.astraeus.template.EscapeMode; +import nl.astraeus.template.SimpleTemplate; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:20 PM + */ +public abstract class TemplatePage extends Page { + + private SimpleTemplate template; + + protected TemplatePage() { + template = getSimpleTemplate(this.getClass()); + } + + public String render(HttpServletRequest request) { + return template.render(defineModel(request)); + } + + private static Map templateCache = new HashMap(); + + public synchronized static SimpleTemplate getSimpleTemplate(Class cls) { + SimpleTemplate result = templateCache.get(cls); + + if (result == null) { + InputStream in = null; + + try { + in = cls.getResourceAsStream(cls.getSimpleName() + ".html"); + + result = SimpleTemplate.readTemplate('{','}', EscapeMode.HTML, in); + + templateCache.put(cls, result); + } catch (IOException e) { + throw new IllegalStateException(e); + } finally { + if (in != null) { + try { + in.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + + return result; + } +} diff --git a/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css b/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css new file mode 100644 index 0000000..0e0056f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css @@ -0,0 +1,581 @@ +/*! + * Bootstrap Responsive v2.0.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ +.clearfix { + *zoom: 1; +} +.clearfix:before, .clearfix:after { + display: table; + content: ""; +} +.clearfix:after { + clear: both; +} +.hidden { + display: none; + visibility: hidden; +} +@media (max-width: 480px) { + .nav-collapse { + -webkit-transform: translate3d(0, 0, 0); + } + .page-header h1 small { + display: block; + line-height: 18px; + } + input[class*="span"], + select[class*="span"], + textarea[class*="span"], + .uneditable-input { + display: block; + width: 100%; + min-height: 28px; + /* Make inputs at least the height of their button counterpart */ + + /* Makes inputs behave like true block-level elements */ + + -webkit-box-sizing: border-box; + /* Older Webkit */ + + -moz-box-sizing: border-box; + /* Older FF */ + + -ms-box-sizing: border-box; + /* IE8 */ + + box-sizing: border-box; + /* CSS3 spec*/ + + } + .input-prepend input[class*="span"], .input-append input[class*="span"] { + width: auto; + } + input[type="checkbox"], input[type="radio"] { + border: 1px solid #ccc; + } + .form-horizontal .control-group > label { + float: none; + width: auto; + padding-top: 0; + text-align: left; + } + .form-horizontal .controls { + margin-left: 0; + } + .form-horizontal .control-list { + padding-top: 0; + } + .form-horizontal .form-actions { + padding-left: 10px; + padding-right: 10px; + } + .modal { + position: absolute; + top: 10px; + left: 10px; + right: 10px; + width: auto; + margin: 0; + } + .modal.fade.in { + top: auto; + } + .modal-header .close { + padding: 10px; + margin: -10px; + } + .carousel-caption { + position: static; + } +} +@media (max-width: 767px) { + .container { + width: auto; + padding: 0 20px; + } + .row-fluid { + width: 100%; + } + .row { + margin-left: 0; + } + .row > [class*="span"], .row-fluid > [class*="span"] { + float: none; + display: block; + width: auto; + margin: 0; + } +} +@media (min-width: 768px) and (max-width: 979px) { + .row { + margin-left: -20px; + *zoom: 1; + } + .row:before, .row:after { + display: table; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + margin-left: 20px; + } + .span1 { + width: 42px; + } + .span2 { + width: 104px; + } + .span3 { + width: 166px; + } + .span4 { + width: 228px; + } + .span5 { + width: 290px; + } + .span6 { + width: 352px; + } + .span7 { + width: 414px; + } + .span8 { + width: 476px; + } + .span9 { + width: 538px; + } + .span10 { + width: 600px; + } + .span11 { + width: 662px; + } + .span12, .container { + width: 724px; + } + .offset1 { + margin-left: 82px; + } + .offset2 { + margin-left: 144px; + } + .offset3 { + margin-left: 206px; + } + .offset4 { + margin-left: 268px; + } + .offset5 { + margin-left: 330px; + } + .offset6 { + margin-left: 392px; + } + .offset7 { + margin-left: 454px; + } + .offset8 { + margin-left: 516px; + } + .offset9 { + margin-left: 578px; + } + .offset10 { + margin-left: 640px; + } + .offset11 { + margin-left: 702px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, .row-fluid:after { + display: table; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid > [class*="span"] { + float: left; + margin-left: 2.762430939%; + } + .row-fluid > [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid > .span1 { + width: 5.801104972%; + } + .row-fluid > .span2 { + width: 14.364640883%; + } + .row-fluid > .span3 { + width: 22.928176794%; + } + .row-fluid > .span4 { + width: 31.491712705%; + } + .row-fluid > .span5 { + width: 40.055248616%; + } + .row-fluid > .span6 { + width: 48.618784527%; + } + .row-fluid > .span7 { + width: 57.182320438000005%; + } + .row-fluid > .span8 { + width: 65.74585634900001%; + } + .row-fluid > .span9 { + width: 74.30939226%; + } + .row-fluid > .span10 { + width: 82.87292817100001%; + } + .row-fluid > .span11 { + width: 91.436464082%; + } + .row-fluid > .span12 { + width: 99.999999993%; + } + input.span1, textarea.span1, .uneditable-input.span1 { + width: 32px; + } + input.span2, textarea.span2, .uneditable-input.span2 { + width: 94px; + } + input.span3, textarea.span3, .uneditable-input.span3 { + width: 156px; + } + input.span4, textarea.span4, .uneditable-input.span4 { + width: 218px; + } + input.span5, textarea.span5, .uneditable-input.span5 { + width: 280px; + } + input.span6, textarea.span6, .uneditable-input.span6 { + width: 342px; + } + input.span7, textarea.span7, .uneditable-input.span7 { + width: 404px; + } + input.span8, textarea.span8, .uneditable-input.span8 { + width: 466px; + } + input.span9, textarea.span9, .uneditable-input.span9 { + width: 528px; + } + input.span10, textarea.span10, .uneditable-input.span10 { + width: 590px; + } + input.span11, textarea.span11, .uneditable-input.span11 { + width: 652px; + } + input.span12, textarea.span12, .uneditable-input.span12 { + width: 714px; + } +} +@media (max-width: 979px) { + body { + padding-top: 0; + } + .navbar-fixed-top { + position: static; + margin-bottom: 18px; + } + .navbar-fixed-top .navbar-inner { + padding: 5px; + } + .navbar .container { + width: auto; + padding: 0; + } + .navbar .brand { + padding-left: 10px; + padding-right: 10px; + margin: 0 0 0 -5px; + } + .navbar .nav-collapse { + clear: left; + } + .navbar .nav { + float: none; + margin: 0 0 9px; + } + .navbar .nav > li { + float: none; + } + .navbar .nav > li > a { + margin-bottom: 2px; + } + .navbar .nav > .divider-vertical { + display: none; + } + .navbar .nav .nav-header { + color: #999999; + text-shadow: none; + } + .navbar .nav > li > a, .navbar .dropdown-menu a { + padding: 6px 15px; + font-weight: bold; + color: #999999; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + } + .navbar .dropdown-menu li + li a { + margin-bottom: 2px; + } + .navbar .nav > li > a:hover, .navbar .dropdown-menu a:hover { + background-color: #222222; + } + .navbar .dropdown-menu { + position: static; + top: auto; + left: auto; + float: none; + display: block; + max-width: none; + margin: 0 15px; + padding: 0; + background-color: transparent; + border: none; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + } + .navbar .dropdown-menu:before, .navbar .dropdown-menu:after { + display: none; + } + .navbar .dropdown-menu .divider { + display: none; + } + .navbar-form, .navbar-search { + float: none; + padding: 9px 15px; + margin: 9px 0; + border-top: 1px solid #222222; + border-bottom: 1px solid #222222; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + } + .navbar .nav.pull-right { + float: none; + margin-left: 0; + } + .navbar-static .navbar-inner { + padding-left: 10px; + padding-right: 10px; + } + .btn-navbar { + display: block; + } + .nav-collapse { + overflow: hidden; + height: 0; + } +} +@media (min-width: 980px) { + .nav-collapse.collapse { + height: auto !important; + } +} +@media (min-width: 1200px) { + .row { + margin-left: -30px; + *zoom: 1; + } + .row:before, .row:after { + display: table; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + margin-left: 30px; + } + .span1 { + width: 70px; + } + .span2 { + width: 170px; + } + .span3 { + width: 270px; + } + .span4 { + width: 370px; + } + .span5 { + width: 470px; + } + .span6 { + width: 570px; + } + .span7 { + width: 670px; + } + .span8 { + width: 770px; + } + .span9 { + width: 870px; + } + .span10 { + width: 970px; + } + .span11 { + width: 1070px; + } + .span12, .container { + width: 1170px; + } + .offset1 { + margin-left: 130px; + } + .offset2 { + margin-left: 230px; + } + .offset3 { + margin-left: 330px; + } + .offset4 { + margin-left: 430px; + } + .offset5 { + margin-left: 530px; + } + .offset6 { + margin-left: 630px; + } + .offset7 { + margin-left: 730px; + } + .offset8 { + margin-left: 830px; + } + .offset9 { + margin-left: 930px; + } + .offset10 { + margin-left: 1030px; + } + .offset11 { + margin-left: 1130px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, .row-fluid:after { + display: table; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid > [class*="span"] { + float: left; + margin-left: 2.564102564%; + } + .row-fluid > [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid > .span1 { + width: 5.982905983%; + } + .row-fluid > .span2 { + width: 14.529914530000001%; + } + .row-fluid > .span3 { + width: 23.076923077%; + } + .row-fluid > .span4 { + width: 31.623931624%; + } + .row-fluid > .span5 { + width: 40.170940171000005%; + } + .row-fluid > .span6 { + width: 48.717948718%; + } + .row-fluid > .span7 { + width: 57.264957265%; + } + .row-fluid > .span8 { + width: 65.81196581200001%; + } + .row-fluid > .span9 { + width: 74.358974359%; + } + .row-fluid > .span10 { + width: 82.905982906%; + } + .row-fluid > .span11 { + width: 91.45299145300001%; + } + .row-fluid > .span12 { + width: 100%; + } + input.span1, textarea.span1, .uneditable-input.span1 { + width: 60px; + } + input.span2, textarea.span2, .uneditable-input.span2 { + width: 160px; + } + input.span3, textarea.span3, .uneditable-input.span3 { + width: 260px; + } + input.span4, textarea.span4, .uneditable-input.span4 { + width: 360px; + } + input.span5, textarea.span5, .uneditable-input.span5 { + width: 460px; + } + input.span6, textarea.span6, .uneditable-input.span6 { + width: 560px; + } + input.span7, textarea.span7, .uneditable-input.span7 { + width: 660px; + } + input.span8, textarea.span8, .uneditable-input.span8 { + width: 760px; + } + input.span9, textarea.span9, .uneditable-input.span9 { + width: 860px; + } + input.span10, textarea.span10, .uneditable-input.span10 { + width: 960px; + } + input.span11, textarea.span11, .uneditable-input.span11 { + width: 1060px; + } + input.span12, textarea.span12, .uneditable-input.span12 { + width: 1160px; + } + .thumbnails { + margin-left: -30px; + } + .thumbnails > li { + margin-left: 30px; + } +} diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f403193 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..73ff239 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..3b00020 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..275077f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/README b/README deleted file mode 100644 index 734abaf..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -This file was created by IntelliJ IDEA 11.1.1 for binding GitHub repository \ No newline at end of file diff --git a/Simple-jdbc-statistics.iml b/Simple-jdbc-statistics.iml new file mode 100644 index 0000000..ca90a9b --- /dev/null +++ b/Simple-jdbc-statistics.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/lib/h2-1.3.166.jar b/lib/h2-1.3.166.jar new file mode 100644 index 0000000..4985063 --- /dev/null +++ b/lib/h2-1.3.166.jar Binary files differ diff --git a/lib/servlet-api-2.5.jar b/lib/servlet-api-2.5.jar new file mode 100644 index 0000000..20b5755 --- /dev/null +++ b/lib/servlet-api-2.5.jar Binary files differ diff --git a/lib/slf4j-api-1.6.4.jar b/lib/slf4j-api-1.6.4.jar new file mode 100644 index 0000000..4d23f41 --- /dev/null +++ b/lib/slf4j-api-1.6.4.jar Binary files differ diff --git a/lib/slf4j-simple-1.6.4.jar b/lib/slf4j-simple-1.6.4.jar new file mode 100644 index 0000000..3d1b8d9 --- /dev/null +++ b/lib/slf4j-simple-1.6.4.jar Binary files differ diff --git a/lib/ssr-0.1.jar b/lib/ssr-0.1.jar new file mode 100644 index 0000000..65dfcf4 --- /dev/null +++ b/lib/ssr-0.1.jar Binary files differ diff --git a/lib/vst-0.4.jar b/lib/vst-0.4.jar new file mode 100644 index 0000000..db63792 --- /dev/null +++ b/lib/vst-0.4.jar Binary files differ diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..ac2dbe1 --- /dev/null +++ b/readme.md @@ -0,0 +1 @@ +A simple wrapper around jdbc drivers what will show current jdbc stats of the running queries on a simple web page on port 18080. \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/ConnectionLogger.java b/src/nl/astraeus/jdbc/ConnectionLogger.java new file mode 100644 index 0000000..c3e243f --- /dev/null +++ b/src/nl/astraeus/jdbc/ConnectionLogger.java @@ -0,0 +1,279 @@ +package nl.astraeus.jdbc; + +import java.sql.*; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Executor; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:12:34 PM + */ +public class ConnectionLogger implements Connection { + private Connection connection; + + private long milli; + private long nano; + private String lastSql; + + public ConnectionLogger(Connection connection) { + this.connection = connection; + this.lastSql = ""; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(QueryType.UNKNOWN, sql, m, n); + } + + public void commit() throws SQLException { + clearTime(); + + connection.commit(); + + log("commit"); + } + + public void rollback() throws SQLException { + clearTime(); + + connection.rollback(); + + log("rollback"); + } + + public void close() throws SQLException { + clearTime(); + + connection.close(); + + log("close"); + } + + public PreparedStatement prepareStatement(String sql) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, autoGeneratedKeys); + } + + public PreparedStatement prepareStatement(String sql, int columnIndexes[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnIndexes); + } + + public PreparedStatement prepareStatement(String sql, String columnNames[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnNames); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public Statement createStatement() throws SQLException { + return connection.createStatement(); + } + + public CallableStatement prepareCall(String sql) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql); + } + + public String nativeSQL(String sql) throws SQLException { + lastSql = sql; + return connection.nativeSQL(sql); + } + + public void setAutoCommit(boolean autoCommit) throws SQLException { + connection.setAutoCommit(autoCommit); + } + + public boolean getAutoCommit() throws SQLException { + return connection.getAutoCommit(); + } + + public boolean isClosed() throws SQLException { + return connection.isClosed(); + } + + public DatabaseMetaData getMetaData() throws SQLException { + return connection.getMetaData(); + } + + public void setReadOnly(boolean readOnly) throws SQLException { + connection.setReadOnly(readOnly); + } + + public boolean isReadOnly() throws SQLException { + return connection.isReadOnly(); + } + + public void setCatalog(String catalog) throws SQLException { + connection.setCatalog(catalog); + } + + public String getCatalog() throws SQLException { + return connection.getCatalog(); + } + + public void setTransactionIsolation(int level) throws SQLException { + connection.setTransactionIsolation(level); + } + + public int getTransactionIsolation() throws SQLException { + return connection.getTransactionIsolation(); + } + + public SQLWarning getWarnings() throws SQLException { + return connection.getWarnings(); + } + + public void clearWarnings() throws SQLException { + connection.clearWarnings(); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency); + } + + public Map> getTypeMap() throws SQLException { + return connection.getTypeMap(); + } + + public void setTypeMap(Map> map) throws SQLException { + connection.setTypeMap(map); + } + + public void setHoldability(int holdability) throws SQLException { + connection.setHoldability(holdability); + } + + public int getHoldability() throws SQLException { + return connection.getHoldability(); + } + + public Savepoint setSavepoint() throws SQLException { + return connection.setSavepoint(); + } + + public Savepoint setSavepoint(String name) throws SQLException { + return connection.setSavepoint(name); + } + + public void rollback(Savepoint savepoint) throws SQLException { + connection.rollback(); + } + + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + connection.releaseSavepoint(savepoint); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public Clob createClob() throws SQLException { + return connection.createClob(); + } + + public Blob createBlob() throws SQLException { + return connection.createBlob(); + } + + public NClob createNClob() throws SQLException { + return connection.createNClob(); + } + + public SQLXML createSQLXML() throws SQLException { + return connection.createSQLXML(); + } + + public boolean isValid(int timeout) throws SQLException { + return connection.isValid(timeout); + } + + public void setClientInfo(String name, String value) throws SQLClientInfoException { + connection.setClientInfo(name, value); + } + + public void setClientInfo(Properties properties) throws SQLClientInfoException { + connection.setClientInfo(properties); + } + + public String getClientInfo(String name) throws SQLException { + return connection.getClientInfo(name); + } + + public Properties getClientInfo() throws SQLException { + return connection.getClientInfo(); + } + + public Array createArrayOf(String typeName, Object[] elements) throws SQLException { + return connection.createArrayOf(typeName, elements); + } + + public Struct createStruct(String typeName, Object[] attributes) throws SQLException { + return connection.createStruct(typeName, attributes); + } + + @Override + public void setSchema(String schema) throws SQLException { + connection.setSchema(schema); + } + + @Override + public String getSchema() throws SQLException { + return connection.getSchema(); + } + + @Override + public void abort(Executor executor) throws SQLException { + connection.abort(executor); + } + + @Override + public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { + connection.setNetworkTimeout(executor, milliseconds); + } + + @Override + public int getNetworkTimeout() throws SQLException { + return connection.getNetworkTimeout(); + } + + public T unwrap(Class iface) throws SQLException { + return connection.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return connection.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/Driver.java b/src/nl/astraeus/jdbc/Driver.java new file mode 100644 index 0000000..8317172 --- /dev/null +++ b/src/nl/astraeus/jdbc/Driver.java @@ -0,0 +1,116 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.http.SimpleWebServer; +import nl.astraeus.jdbc.web.JdbcStatisticsServlet; +import nl.astraeus.jdbc.web.ResourceServlet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.*; +import java.util.Enumeration; +import java.util.Properties; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:54:37 PM + */ +public class Driver implements java.sql.Driver { + private final static Logger log = LoggerFactory.getLogger(Driver.class); + + final private static String URL_PREFIX = "jdbc:stat:"; + + private java.sql.Driver driver = null; + private String[] drivers = { + "org.postgresql.Driver", + "oracle.jdbc.driver.OracleDriver", + "com.sybase.jdbc2.jdbc.SybDriver", + "net.sourceforge.jtds.jdbc.Driver", + "com.microsoft.jdbc.sqlserver.SQLServerDriver", + "com.microsoft.sqlserver.jdbc.SQLServerDriver", + "weblogic.jdbc.sqlserver.SQLServerDriver", + "com.informix.jdbc.IfxDriver", + "org.apache.derby.jdbc.ClientDriver", + "org.apache.derby.jdbc.EmbeddedDriver", + "com.mysql.jdbc.Driver", + "org.hsqldb.jdbcDriver", + "org.h2.Driver" }; + + static { + log.debug("Loading driver class " + Driver.class.getName()); + + try { + DriverManager.registerDriver(new Driver()); + } catch (SQLException e) { + log.error("", e); + } + } + + public Driver() { + for (String dr : drivers) { + try { + Class.forName(dr); + } catch (Throwable e) { + log.debug("Can't instantiate driver: " + dr, e); + } + } + } + + private java.sql.Driver findDriver(String url) throws SQLException { + Enumeration e = DriverManager.getDrivers(); + + while (e.hasMoreElements()) { + java.sql.Driver d = (java.sql.Driver) e.nextElement(); + + if (d.acceptsURL(url)) { + return d; + } + } + + throw new SQLException("Driver not found: " + url); + } + + public Connection connect(String url, Properties info) throws SQLException { + url = url.substring(URL_PREFIX.length()); + + if (driver == null) { + driver = findDriver(url); + } + + if (driver != null) { + SimpleWebServer server = new SimpleWebServer(18080); + + server.addServlet(new JdbcStatisticsServlet(), "/"); + server.addServlet(new ResourceServlet(), "/resources/*"); + + server.start(); + } + + return new ConnectionLogger(driver.connect(url, info)); + } + + public boolean acceptsURL(String url) throws SQLException { + return (url != null && url.startsWith(URL_PREFIX)); + } + + public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { + return driver.getPropertyInfo(url, info); + } + + public int getMajorVersion() { + return driver.getMajorVersion(); + } + + public int getMinorVersion() { + return driver.getMinorVersion(); + } + + public boolean jdbcCompliant() { + return driver.jdbcCompliant(); + } + + @Override + public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException { + return driver.getParentLogger(); + } +} diff --git a/src/nl/astraeus/jdbc/JdbcLogger.java b/src/nl/astraeus/jdbc/JdbcLogger.java new file mode 100644 index 0000000..f4bc125 --- /dev/null +++ b/src/nl/astraeus/jdbc/JdbcLogger.java @@ -0,0 +1,113 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.jdbc.util.Util; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/** + * User: riennentjes + * Date: Jul 12, 2008 + * Time: 9:15:21 AM + */ +public class JdbcLogger { + private final static Logger logger = LoggerFactory.getLogger(JdbcLogger.class); + + private final static JdbcLogger instance = new JdbcLogger(); + + public static JdbcLogger get() { + return instance; + } + + public final static class LogEntry { + public QueryType type; + public String sql; + public long milli; + public long nano; + public int count; + public int hash; + + public LogEntry(int hash, QueryType type, String sql, long milli, long nano) { + this.hash = hash; + this.type = type; + this.sql = sql; + this.milli = milli; + this.nano = nano; + this.count = 1; + } + + public void addCount(long milli, long nano) { + synchronized (this) { + count++; + this.milli += milli; + this.nano += nano; + } + } + + public int getCount() { + return count; + } + + public String getMilli() { + return Util.formatNano(milli*1000000/count); + } + + public String getNano() { + return Util.formatNano(nano/count); + } + + public String getTotal() { + return Util.formatNano(nano); + } + + public String getSql() { + return sql; + } + } + + private Map queries; + + public JdbcLogger() { + queries = new ConcurrentHashMap(); + } + + public void logEntry(QueryType type, String sql, long milli, long nano) { + int hash = sql.hashCode(); + LogEntry entry = queries.get(hash); + + if (entry == null) { + entry = new LogEntry(hash, type, sql, milli, nano); + queries.put(hash, entry); + } else { + entry.addCount(milli, nano); + } + + if (queries.size() > 1000) { + List toRemove = new LinkedList(); + List values = new LinkedList(queries.values()); + + Collections.sort(values, new Comparator() { + @Override + public int compare(LogEntry o1, LogEntry o2) { + return o1.count - o2.count; + } + }); + + while (queries.size() > 900) { + queries.remove(values.remove(0).hash); + + } + } + } + + public static void log(QueryType type, String sql, long milli, long nano) { + instance.logEntry(type, sql, milli, nano); + } + + public Collection getEntries() { + return queries.values(); + } + +} diff --git a/src/nl/astraeus/jdbc/PreparedStatementLogger.java b/src/nl/astraeus/jdbc/PreparedStatementLogger.java new file mode 100644 index 0000000..98aefc7 --- /dev/null +++ b/src/nl/astraeus/jdbc/PreparedStatementLogger.java @@ -0,0 +1,577 @@ +package nl.astraeus.jdbc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.InputStream; +import java.io.Reader; +import java.math.BigDecimal; +import java.net.URL; +import java.sql.*; +import java.util.Calendar; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 7:47:57 PM + */ +public class PreparedStatementLogger implements PreparedStatement { + private final static Logger log = LoggerFactory.getLogger(PreparedStatementLogger.class); + + private PreparedStatement statement; + + private String sql; + private QueryType type; + private long milli; + private long nano; + + //private ArrayList parameters; + + public PreparedStatementLogger(PreparedStatement statement) { + this.statement = statement; + this.sql = ""; + this.type = QueryType.UNKNOWN; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(QueryType type, String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(type, sql, m, n); + } + + public PreparedStatementLogger(Connection connection, String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql); + } + + public PreparedStatementLogger(Connection connection, String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatementLogger(Connection connection, String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, autoGeneratedKeys); + } + + public PreparedStatementLogger(Connection connection, String sql, int[] columnIndexes) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnIndexes); + } + + public PreparedStatementLogger(Connection connection, String sql, String[] columnNames) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnNames); + } + + public boolean execute() throws SQLException { + clearTime(); + + boolean result = statement.execute(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery() throws SQLException { + clearTime(); + + ResultSet result = statement.executeQuery(); + + log(type, sql); + + return result; + } + + public int executeUpdate() throws SQLException { + clearTime(); + + int result = statement.executeUpdate(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + ResultSet result = statement.executeQuery(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnNames); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnNames); + + log(type, sql); + + return result; + } + + + public void setNull(int parameterIndex, int sqlType) throws SQLException { + statement.setNull(parameterIndex, sqlType); + } + + public void setBoolean(int parameterIndex, boolean x) throws SQLException { + statement.setBoolean(parameterIndex, x); + } + + public void setByte(int parameterIndex, byte x) throws SQLException { + statement.setByte(parameterIndex, x); + } + + public void setShort(int parameterIndex, short x) throws SQLException { + statement.setShort(parameterIndex, x); + } + + public void setInt(int parameterIndex, int x) throws SQLException { + statement.setInt(parameterIndex, x); + } + + public void setLong(int parameterIndex, long x) throws SQLException { + statement.setLong(parameterIndex, x); + } + + public void setFloat(int parameterIndex, float x) throws SQLException { + statement.setFloat(parameterIndex, x); + } + + public void setDouble(int parameterIndex, double x) throws SQLException { + statement.setDouble(parameterIndex, x); + } + + public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { + statement.setBigDecimal(parameterIndex, x); + } + + public void setString(int parameterIndex, String x) throws SQLException { + statement.setString(parameterIndex, x); + } + + public void setBytes(int parameterIndex, byte x[]) throws SQLException { + statement.setBytes(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x) throws SQLException { + statement.setDate(parameterIndex, x); + } + + public void setTime(int parameterIndex, Time x) throws SQLException { + statement.setTime(parameterIndex, x); + } + + public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { + statement.setTimestamp(parameterIndex, x); + } + + public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setUnicodeStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType); + } + + public void setObject(int parameterIndex, Object x) throws SQLException { + statement.setObject(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setRef(int parameterIndex, Ref x) throws SQLException { + statement.setRef(parameterIndex, x); + } + + public void setBlob(int parameterIndex, Blob x) throws SQLException { + statement.setBlob(parameterIndex, x); + } + + public void setClob(int parameterIndex, Clob x) throws SQLException { + statement.setClob(parameterIndex, x); + } + + public void setArray(int parameterIndex, Array x) throws SQLException { + statement.setArray(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { + statement.setDate(parameterIndex, x, cal); + } + + public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { + statement.setTime(parameterIndex, x, cal); + } + + public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { + statement.setTimestamp(parameterIndex, x, cal); + } + + public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException { + statement.setNull(parameterIndex, sqlType, typeName); + } + + public void setURL(int parameterIndex, URL x) throws SQLException { + statement.setURL(parameterIndex, x); + } + + public void setRowId(int parameterIndex, RowId x) throws SQLException { + statement.setRowId(parameterIndex, x); + } + + public void setNString(int parameterIndex, String value) throws SQLException { + statement.setNString(parameterIndex, value); + } + + public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException { + statement.setNCharacterStream(parameterIndex, value, length); + } + + public void setNClob(int parameterIndex, NClob value) throws SQLException { + statement.setNClob(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setClob(parameterIndex, reader, length); + } + + public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException { + statement.setBlob(parameterIndex, inputStream, length); + } + + public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setNClob(parameterIndex, reader, length); + } + + public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException { + statement.setSQLXML(parameterIndex, xmlObject); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType, scaleOrLength); + } + + public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException { + statement.setAsciiStream(parameterIndex, x); + } + + public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException { + statement.setBinaryStream(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException { + statement.setCharacterStream(parameterIndex, reader); + } + + public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException { + statement.setNCharacterStream(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader) throws SQLException { + statement.setClob(parameterIndex, reader); + } + + public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException { + statement.setBlob(parameterIndex, inputStream); + } + + public void setNClob(int parameterIndex, Reader reader) throws SQLException { + statement.setNClob(parameterIndex, reader); + } + + + public void close() throws SQLException { + sql = ""; + type = QueryType.UNKNOWN; + milli = 0; + nano = 0; + + statement.close(); + } + + public ResultSetMetaData getMetaData() throws SQLException { + return statement.getMetaData(); + } + + public void clearParameters() throws SQLException { + statement.clearParameters(); + } + + public ParameterMetaData getParameterMetaData() throws SQLException { + return statement.getParameterMetaData(); + } + + public void addBatch() throws SQLException { + statement.addBatch(); + } + + public int getMaxFieldSize() throws SQLException { + return statement.getMaxFieldSize(); + } + + public void setMaxFieldSize(int max) throws SQLException { + statement.setMaxFieldSize(max); + } + + public int getMaxRows() throws SQLException { + return statement.getMaxRows(); + } + + public void setMaxRows(int max) throws SQLException { + statement.setMaxRows(max); + } + + public void setEscapeProcessing(boolean enable) throws SQLException { + statement.setEscapeProcessing(enable); + } + + public int getQueryTimeout() throws SQLException { + return statement.getQueryTimeout(); + } + + public void setQueryTimeout(int seconds) throws SQLException { + statement.setQueryTimeout(seconds); + } + + public void cancel() throws SQLException { + statement.cancel(); + } + + public SQLWarning getWarnings() throws SQLException { + return statement.getWarnings(); + } + + public void clearWarnings() throws SQLException { + statement.clearWarnings(); + } + + public void setCursorName(String name) throws SQLException { + statement.setCursorName(name); + } + + public boolean execute(String sql) throws SQLException { + return statement.execute(sql); + } + + public ResultSet getResultSet() throws SQLException { + return statement.getResultSet(); + } + + public int getUpdateCount() throws SQLException { + return statement.getUpdateCount(); + } + + public boolean getMoreResults() throws SQLException { + return statement.getMoreResults(); + } + + public void setFetchDirection(int direction) throws SQLException { + statement.setFetchDirection(direction); + } + + public int getFetchDirection() throws SQLException { + return statement.getFetchDirection(); + } + + public void setFetchSize(int rows) throws SQLException { + statement.setFetchSize(rows); + } + + public int getFetchSize() throws SQLException { + return statement.getFetchSize(); + } + + public int getResultSetConcurrency() throws SQLException { + return statement.getResultSetConcurrency(); + } + + public int getResultSetType() throws SQLException { + return statement.getResultSetType(); + } + + public void addBatch(String sql) throws SQLException { + statement.addBatch(sql); + } + + public void clearBatch() throws SQLException { + statement.clearBatch(); + } + + public int[] executeBatch() throws SQLException { + return statement.executeBatch(); + } + + public Connection getConnection() throws SQLException { + return statement.getConnection(); + } + + public boolean getMoreResults(int current) throws SQLException { + return statement.getMoreResults(current); + } + + public ResultSet getGeneratedKeys() throws SQLException { + return statement.getGeneratedKeys(); + } + + public int getResultSetHoldability() throws SQLException { + return statement.getResultSetHoldability(); + } + + public boolean isClosed() throws SQLException { + return statement.isClosed(); + } + + public void setPoolable(boolean poolable) throws SQLException { + statement.setPoolable(poolable); + } + + public boolean isPoolable() throws SQLException { + return statement.isPoolable(); + } + + @Override + public void closeOnCompletion() throws SQLException { + statement.closeOnCompletion();; + } + + @Override + public boolean isCloseOnCompletion() throws SQLException { + return statement.isCloseOnCompletion(); + } + + public T unwrap(Class iface) throws SQLException { + return statement.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return statement.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/QueryType.java b/src/nl/astraeus/jdbc/QueryType.java new file mode 100644 index 0000000..744fbfc --- /dev/null +++ b/src/nl/astraeus/jdbc/QueryType.java @@ -0,0 +1,24 @@ +package nl.astraeus.jdbc; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:32:49 PM + */ +public enum QueryType { + PLAIN("plain"), + PREPARED("prepared"), + CALLABLE("callable"), + UNKNOWN("unknown"); + + private String description; + + QueryType(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } + +} diff --git a/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java new file mode 100644 index 0000000..07aac40 --- /dev/null +++ b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java @@ -0,0 +1,68 @@ +package nl.astraeus.jdbc.example; + +import java.sql.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 7:32 PM + */ +public class JdbcStatisticsExample { + + + public static void main(String [] args) throws Exception { + Class.forName("org.h2.Driver"); + Class.forName("nl.astraeus.jdbc.Driver"); + + new JdbcStatisticsExample(); + } + + public JdbcStatisticsExample() throws Exception { + Connection conn = DriverManager.getConnection("jdbc:stat:jdbc:h2:mem:test"); + + Statement statement = null; + + statement = conn.createStatement(); + statement.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + + boolean running = true; + int count = 1; + PreparedStatement ps = null; + + while (running) { + Thread.sleep(10); + + String TableName = "TEST"+(System.nanoTime() % 1000); + + try { + ps = conn.prepareStatement("SELECT COUNT(*) FROM "+TableName); + ResultSet rs = ps.executeQuery(); + } catch (SQLException e) { + statement = conn.createStatement(); + statement.execute("CREATE TABLE "+TableName+" (ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + } finally { + if (ps!=null) { + ps.close(); + } + } + + ps = conn.prepareStatement("INSERT INTO "+TableName+" VALUES (?, ?)"); + + ps.setInt(1, count++); + ps.setString(2, "String "+System.currentTimeMillis()); + + ps.execute(); + ps.close(); + + Thread.sleep(10); + + ps = conn.prepareStatement("SELECT * FROM "+TableName); + ResultSet rs = ps.executeQuery(); + statement.close(); + } + + conn.close(); + } +} diff --git a/src/nl/astraeus/jdbc/util/IOUtils.java b/src/nl/astraeus/jdbc/util/IOUtils.java new file mode 100644 index 0000000..ce95d9d --- /dev/null +++ b/src/nl/astraeus/jdbc/util/IOUtils.java @@ -0,0 +1,38 @@ +package nl.astraeus.jdbc.util; + +import java.io.*; + +/** + * User: rnentjes + * Date: 4/9/12 + * Time: 2:33 PM + */ +public class IOUtils { + + public static String toString(InputStream in) throws IOException { + assert in != null; + + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + StringBuilder buffer = new StringBuilder(); + + while(reader.ready()) { + buffer.append(reader.readLine()); + buffer.append("\n"); + } + + return buffer.toString(); + } finally { + in.close(); + } + } + + public static void copy(InputStream in, OutputStream out) throws IOException { + byte [] buffer = new byte[1<<16]; + int bytes; + + while((bytes = in.read(buffer)) > 0) { + out.write(buffer, 0, bytes); + } + } +} diff --git a/src/nl/astraeus/jdbc/util/Util.java b/src/nl/astraeus/jdbc/util/Util.java new file mode 100644 index 0000000..eaa853b --- /dev/null +++ b/src/nl/astraeus/jdbc/util/Util.java @@ -0,0 +1,25 @@ +package nl.astraeus.jdbc.util; + +import java.text.DecimalFormat; +import java.text.NumberFormat; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 12:28 PM + */ +public class Util { + // utility functions + public static String formatNano(long l) { + NumberFormat format = new DecimalFormat("###,##0.000000"); + + return format.format((double) l / 1000000.0); + } + + public static void printMemoryUsage() { + System.out.println("Used memory: "+((Runtime.getRuntime().totalMemory() / (1024*1024))-(Runtime.getRuntime().freeMemory() / (1024*1024)))); + System.out.println("Free memory: "+(Runtime.getRuntime().freeMemory() / (1024*1024))); + System.out.println("Total memory: "+(Runtime.getRuntime().totalMemory() / (1024*1024))); + System.out.println("Max memory: "+(Runtime.getRuntime().maxMemory() / (1024*1024))); + } +} diff --git a/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java b/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java new file mode 100644 index 0000000..a162d6f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java @@ -0,0 +1,90 @@ +package nl.astraeus.jdbc.web; + +import nl.astraeus.jdbc.util.IOUtils; +import nl.astraeus.jdbc.util.Util; +import nl.astraeus.jdbc.web.page.Menu; +import nl.astraeus.jdbc.web.page.Page; +import nl.astraeus.jdbc.web.page.QueryOverview; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import java.io.IOException; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:05 PM + */ +public class JdbcStatisticsServlet extends HttpServlet { + + private String head; + private String bottom; + + @Override + public void init() throws ServletException { + super.init(); + + try { + head = IOUtils.toString(getClass().getResourceAsStream("head.html")); + bottom = IOUtils.toString(getClass().getResourceAsStream("bottom.html")); + } catch (IOException e) { + throw new ServletException(e); + } + + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + doPost(req, resp); + } + + @Override + protected void doPost(final HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + long nano = System.nanoTime(); + + HttpSession session = req.getSession(); + boolean ajax = "true".equals(req.getParameter("ajax")); + + resp.setContentType("text/html"); + + Page page = (Page)session.getAttribute("page"); + Page menu = (Page)session.getAttribute("menu"); + + session.setMaxInactiveInterval(1800); + + if (menu == null) { + menu = new Menu(); + + session.setAttribute("menu", menu); + } + + if (page == null || "menumain".equals(req.getParameter("action"))) { + page = new QueryOverview(); + } else if ("diagnostics".equals(req.getParameter("action"))) { + //page = new Diagnostics(); + } else { + page = page .processRequest(req); + } + + menu.processRequest(req); + + session.setAttribute("page", page); + + if (!ajax) { + resp.getWriter().print(head); + } + + resp.getWriter().print(menu.render(req)); + resp.getWriter().print(page.render(req)); + + if (!ajax) { + resp.getWriter().print(bottom); + } + + System.out.println("Request ends, time="+ Util.formatNano(System.nanoTime() - nano) +", page="+page.getClass().getSimpleName()); + } + +} diff --git a/src/nl/astraeus/jdbc/web/ResourceServlet.java b/src/nl/astraeus/jdbc/web/ResourceServlet.java new file mode 100644 index 0000000..7abfe6f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/ResourceServlet.java @@ -0,0 +1,49 @@ +package nl.astraeus.jdbc.web; + +import nl.astraeus.jdbc.util.IOUtils; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.InputStream; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:05 PM + */ +public class ResourceServlet extends HttpServlet { + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String uri = req.getRequestURI(); + + uri = "nl/astraeus/jdbc/web" + uri; + InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(uri); + + if (in == null) { + resp.sendError(404, "Cannot find resource '" + uri + "'."); + } else { + try { + if (uri.endsWith("js")) { + resp.setContentType("text/javascript"); + } else if (uri.endsWith("css")) { + resp.setContentType("text/css"); + } else if (uri.endsWith("png")) { + resp.setContentType("image/png"); + } else if (uri.endsWith("jpg")) { + resp.setContentType("image/jpeg"); + } else if (uri.endsWith("gif")) { + resp.setContentType("image/gif"); + } + + IOUtils.copy(in, resp.getOutputStream()); + } finally { + in.close(); + } + } + } + +} diff --git a/src/nl/astraeus/jdbc/web/bottom.html b/src/nl/astraeus/jdbc/web/bottom.html new file mode 100644 index 0000000..1288de4 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/bottom.html @@ -0,0 +1,8 @@ + + +
+ + + + + \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/head.html b/src/nl/astraeus/jdbc/web/head.html new file mode 100644 index 0000000..0f8f6a3 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/head.html @@ -0,0 +1,96 @@ + + + + + + + Simple JDBC Statistics + + + + + + + + + + + + + + + + + + + +
+
+ +
+ diff --git a/src/nl/astraeus/jdbc/web/page/Menu.html b/src/nl/astraeus/jdbc/web/page/Menu.html new file mode 100644 index 0000000..505c7c2 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.html @@ -0,0 +1,42 @@ + diff --git a/src/nl/astraeus/jdbc/web/page/Menu.java b/src/nl/astraeus/jdbc/web/page/Menu.java new file mode 100644 index 0000000..f0a349a --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.java @@ -0,0 +1,27 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 9:07 PM + */ +public class Menu extends TemplatePage { + + @Override + public Page processRequest(HttpServletRequest request) { + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + result.put("user", request.getSession().getAttribute("user")); + + return result; + } +} diff --git a/src/nl/astraeus/jdbc/web/page/Page.java b/src/nl/astraeus/jdbc/web/page/Page.java new file mode 100644 index 0000000..9d526d6 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Page.java @@ -0,0 +1,17 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:20 PM + */ +public abstract class Page { + + public abstract Page processRequest(HttpServletRequest request); + public abstract Map defineModel(HttpServletRequest request); + public abstract String render(HttpServletRequest request); + +} diff --git a/src/nl/astraeus/jdbc/web/page/QueryOverview.html b/src/nl/astraeus/jdbc/web/page/QueryOverview.html new file mode 100644 index 0000000..64a88fb --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/QueryOverview.html @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + {foreach(queries as q)} + + + + + + + {eachend} + +
Total timeAvg. time# CallsSql
{q.total}{q.nano}{q.count}{q.sql}
diff --git a/src/nl/astraeus/jdbc/web/page/QueryOverview.java b/src/nl/astraeus/jdbc/web/page/QueryOverview.java new file mode 100644 index 0000000..02982f1 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/QueryOverview.java @@ -0,0 +1,92 @@ +package nl.astraeus.jdbc.web.page; + +import nl.astraeus.jdbc.JdbcLogger; + +import javax.servlet.http.HttpServletRequest; +import java.util.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 9:16 PM + */ +public class QueryOverview extends TemplatePage { + + boolean sortTotalCalls = true; + boolean sortAvgTime = false; + boolean sortTotalTime = false; + + @Override + public Page processRequest(HttpServletRequest request) { + if ("sortTotalCalls".equals(request.getParameter("action"))) { + sortTotalCalls = true; + sortAvgTime = false; + sortTotalTime = false; + } else if ("sortAvgTime".equals(request.getParameter("action"))) { + sortTotalCalls = false; + sortAvgTime = true; + sortTotalTime = false; + } else if ("sortTotalTime".equals(request.getParameter("action"))) { + sortTotalCalls = false; + sortAvgTime = false; + sortTotalTime = true; + } + + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + List entries = new ArrayList(JdbcLogger.get().getEntries()); + + if (sortTotalCalls) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + return o2.count - o1.count; + } + }); + } else if (sortAvgTime) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + long n1 = o1.nano / o1.count; + long n2 = o2.nano / o2.count; + + if (n2 > n1) { + return 1; + } else if (n2 < n1) { + return -1; + } else { + return 0; + } + } + }); + } else if (sortTotalTime) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + if (o2.nano > o1.nano) { + return 1; + } else if (o2.nano < o1.nano) { + return -1; + } else { + return 0; + } + } + }); + } + + result.put("queries", entries); + result.put("count", entries.size()); + + result.put("sortTotalCalls", sortTotalCalls); + result.put("sortAvgTime", sortAvgTime); + result.put("sortTotalTime", sortTotalTime); + + return result; + } + +} diff --git a/src/nl/astraeus/jdbc/web/page/TemplatePage.java b/src/nl/astraeus/jdbc/web/page/TemplatePage.java new file mode 100644 index 0000000..33e2641 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/TemplatePage.java @@ -0,0 +1,58 @@ +package nl.astraeus.jdbc.web.page; + +import nl.astraeus.template.EscapeMode; +import nl.astraeus.template.SimpleTemplate; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:20 PM + */ +public abstract class TemplatePage extends Page { + + private SimpleTemplate template; + + protected TemplatePage() { + template = getSimpleTemplate(this.getClass()); + } + + public String render(HttpServletRequest request) { + return template.render(defineModel(request)); + } + + private static Map templateCache = new HashMap(); + + public synchronized static SimpleTemplate getSimpleTemplate(Class cls) { + SimpleTemplate result = templateCache.get(cls); + + if (result == null) { + InputStream in = null; + + try { + in = cls.getResourceAsStream(cls.getSimpleName() + ".html"); + + result = SimpleTemplate.readTemplate('{','}', EscapeMode.HTML, in); + + templateCache.put(cls, result); + } catch (IOException e) { + throw new IllegalStateException(e); + } finally { + if (in != null) { + try { + in.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + + return result; + } +} diff --git a/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css b/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css new file mode 100644 index 0000000..0e0056f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css @@ -0,0 +1,581 @@ +/*! + * Bootstrap Responsive v2.0.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ +.clearfix { + *zoom: 1; +} +.clearfix:before, .clearfix:after { + display: table; + content: ""; +} +.clearfix:after { + clear: both; +} +.hidden { + display: none; + visibility: hidden; +} +@media (max-width: 480px) { + .nav-collapse { + -webkit-transform: translate3d(0, 0, 0); + } + .page-header h1 small { + display: block; + line-height: 18px; + } + input[class*="span"], + select[class*="span"], + textarea[class*="span"], + .uneditable-input { + display: block; + width: 100%; + min-height: 28px; + /* Make inputs at least the height of their button counterpart */ + + /* Makes inputs behave like true block-level elements */ + + -webkit-box-sizing: border-box; + /* Older Webkit */ + + -moz-box-sizing: border-box; + /* Older FF */ + + -ms-box-sizing: border-box; + /* IE8 */ + + box-sizing: border-box; + /* CSS3 spec*/ + + } + .input-prepend input[class*="span"], .input-append input[class*="span"] { + width: auto; + } + input[type="checkbox"], input[type="radio"] { + border: 1px solid #ccc; + } + .form-horizontal .control-group > label { + float: none; + width: auto; + padding-top: 0; + text-align: left; + } + .form-horizontal .controls { + margin-left: 0; + } + .form-horizontal .control-list { + padding-top: 0; + } + .form-horizontal .form-actions { + padding-left: 10px; + padding-right: 10px; + } + .modal { + position: absolute; + top: 10px; + left: 10px; + right: 10px; + width: auto; + margin: 0; + } + .modal.fade.in { + top: auto; + } + .modal-header .close { + padding: 10px; + margin: -10px; + } + .carousel-caption { + position: static; + } +} +@media (max-width: 767px) { + .container { + width: auto; + padding: 0 20px; + } + .row-fluid { + width: 100%; + } + .row { + margin-left: 0; + } + .row > [class*="span"], .row-fluid > [class*="span"] { + float: none; + display: block; + width: auto; + margin: 0; + } +} +@media (min-width: 768px) and (max-width: 979px) { + .row { + margin-left: -20px; + *zoom: 1; + } + .row:before, .row:after { + display: table; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + margin-left: 20px; + } + .span1 { + width: 42px; + } + .span2 { + width: 104px; + } + .span3 { + width: 166px; + } + .span4 { + width: 228px; + } + .span5 { + width: 290px; + } + .span6 { + width: 352px; + } + .span7 { + width: 414px; + } + .span8 { + width: 476px; + } + .span9 { + width: 538px; + } + .span10 { + width: 600px; + } + .span11 { + width: 662px; + } + .span12, .container { + width: 724px; + } + .offset1 { + margin-left: 82px; + } + .offset2 { + margin-left: 144px; + } + .offset3 { + margin-left: 206px; + } + .offset4 { + margin-left: 268px; + } + .offset5 { + margin-left: 330px; + } + .offset6 { + margin-left: 392px; + } + .offset7 { + margin-left: 454px; + } + .offset8 { + margin-left: 516px; + } + .offset9 { + margin-left: 578px; + } + .offset10 { + margin-left: 640px; + } + .offset11 { + margin-left: 702px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, .row-fluid:after { + display: table; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid > [class*="span"] { + float: left; + margin-left: 2.762430939%; + } + .row-fluid > [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid > .span1 { + width: 5.801104972%; + } + .row-fluid > .span2 { + width: 14.364640883%; + } + .row-fluid > .span3 { + width: 22.928176794%; + } + .row-fluid > .span4 { + width: 31.491712705%; + } + .row-fluid > .span5 { + width: 40.055248616%; + } + .row-fluid > .span6 { + width: 48.618784527%; + } + .row-fluid > .span7 { + width: 57.182320438000005%; + } + .row-fluid > .span8 { + width: 65.74585634900001%; + } + .row-fluid > .span9 { + width: 74.30939226%; + } + .row-fluid > .span10 { + width: 82.87292817100001%; + } + .row-fluid > .span11 { + width: 91.436464082%; + } + .row-fluid > .span12 { + width: 99.999999993%; + } + input.span1, textarea.span1, .uneditable-input.span1 { + width: 32px; + } + input.span2, textarea.span2, .uneditable-input.span2 { + width: 94px; + } + input.span3, textarea.span3, .uneditable-input.span3 { + width: 156px; + } + input.span4, textarea.span4, .uneditable-input.span4 { + width: 218px; + } + input.span5, textarea.span5, .uneditable-input.span5 { + width: 280px; + } + input.span6, textarea.span6, .uneditable-input.span6 { + width: 342px; + } + input.span7, textarea.span7, .uneditable-input.span7 { + width: 404px; + } + input.span8, textarea.span8, .uneditable-input.span8 { + width: 466px; + } + input.span9, textarea.span9, .uneditable-input.span9 { + width: 528px; + } + input.span10, textarea.span10, .uneditable-input.span10 { + width: 590px; + } + input.span11, textarea.span11, .uneditable-input.span11 { + width: 652px; + } + input.span12, textarea.span12, .uneditable-input.span12 { + width: 714px; + } +} +@media (max-width: 979px) { + body { + padding-top: 0; + } + .navbar-fixed-top { + position: static; + margin-bottom: 18px; + } + .navbar-fixed-top .navbar-inner { + padding: 5px; + } + .navbar .container { + width: auto; + padding: 0; + } + .navbar .brand { + padding-left: 10px; + padding-right: 10px; + margin: 0 0 0 -5px; + } + .navbar .nav-collapse { + clear: left; + } + .navbar .nav { + float: none; + margin: 0 0 9px; + } + .navbar .nav > li { + float: none; + } + .navbar .nav > li > a { + margin-bottom: 2px; + } + .navbar .nav > .divider-vertical { + display: none; + } + .navbar .nav .nav-header { + color: #999999; + text-shadow: none; + } + .navbar .nav > li > a, .navbar .dropdown-menu a { + padding: 6px 15px; + font-weight: bold; + color: #999999; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + } + .navbar .dropdown-menu li + li a { + margin-bottom: 2px; + } + .navbar .nav > li > a:hover, .navbar .dropdown-menu a:hover { + background-color: #222222; + } + .navbar .dropdown-menu { + position: static; + top: auto; + left: auto; + float: none; + display: block; + max-width: none; + margin: 0 15px; + padding: 0; + background-color: transparent; + border: none; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + } + .navbar .dropdown-menu:before, .navbar .dropdown-menu:after { + display: none; + } + .navbar .dropdown-menu .divider { + display: none; + } + .navbar-form, .navbar-search { + float: none; + padding: 9px 15px; + margin: 9px 0; + border-top: 1px solid #222222; + border-bottom: 1px solid #222222; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + } + .navbar .nav.pull-right { + float: none; + margin-left: 0; + } + .navbar-static .navbar-inner { + padding-left: 10px; + padding-right: 10px; + } + .btn-navbar { + display: block; + } + .nav-collapse { + overflow: hidden; + height: 0; + } +} +@media (min-width: 980px) { + .nav-collapse.collapse { + height: auto !important; + } +} +@media (min-width: 1200px) { + .row { + margin-left: -30px; + *zoom: 1; + } + .row:before, .row:after { + display: table; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + margin-left: 30px; + } + .span1 { + width: 70px; + } + .span2 { + width: 170px; + } + .span3 { + width: 270px; + } + .span4 { + width: 370px; + } + .span5 { + width: 470px; + } + .span6 { + width: 570px; + } + .span7 { + width: 670px; + } + .span8 { + width: 770px; + } + .span9 { + width: 870px; + } + .span10 { + width: 970px; + } + .span11 { + width: 1070px; + } + .span12, .container { + width: 1170px; + } + .offset1 { + margin-left: 130px; + } + .offset2 { + margin-left: 230px; + } + .offset3 { + margin-left: 330px; + } + .offset4 { + margin-left: 430px; + } + .offset5 { + margin-left: 530px; + } + .offset6 { + margin-left: 630px; + } + .offset7 { + margin-left: 730px; + } + .offset8 { + margin-left: 830px; + } + .offset9 { + margin-left: 930px; + } + .offset10 { + margin-left: 1030px; + } + .offset11 { + margin-left: 1130px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, .row-fluid:after { + display: table; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid > [class*="span"] { + float: left; + margin-left: 2.564102564%; + } + .row-fluid > [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid > .span1 { + width: 5.982905983%; + } + .row-fluid > .span2 { + width: 14.529914530000001%; + } + .row-fluid > .span3 { + width: 23.076923077%; + } + .row-fluid > .span4 { + width: 31.623931624%; + } + .row-fluid > .span5 { + width: 40.170940171000005%; + } + .row-fluid > .span6 { + width: 48.717948718%; + } + .row-fluid > .span7 { + width: 57.264957265%; + } + .row-fluid > .span8 { + width: 65.81196581200001%; + } + .row-fluid > .span9 { + width: 74.358974359%; + } + .row-fluid > .span10 { + width: 82.905982906%; + } + .row-fluid > .span11 { + width: 91.45299145300001%; + } + .row-fluid > .span12 { + width: 100%; + } + input.span1, textarea.span1, .uneditable-input.span1 { + width: 60px; + } + input.span2, textarea.span2, .uneditable-input.span2 { + width: 160px; + } + input.span3, textarea.span3, .uneditable-input.span3 { + width: 260px; + } + input.span4, textarea.span4, .uneditable-input.span4 { + width: 360px; + } + input.span5, textarea.span5, .uneditable-input.span5 { + width: 460px; + } + input.span6, textarea.span6, .uneditable-input.span6 { + width: 560px; + } + input.span7, textarea.span7, .uneditable-input.span7 { + width: 660px; + } + input.span8, textarea.span8, .uneditable-input.span8 { + width: 760px; + } + input.span9, textarea.span9, .uneditable-input.span9 { + width: 860px; + } + input.span10, textarea.span10, .uneditable-input.span10 { + width: 960px; + } + input.span11, textarea.span11, .uneditable-input.span11 { + width: 1060px; + } + input.span12, textarea.span12, .uneditable-input.span12 { + width: 1160px; + } + .thumbnails { + margin-left: -30px; + } + .thumbnails > li { + margin-left: 30px; + } +} diff --git a/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css b/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css new file mode 100644 index 0000000..6229c12 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css @@ -0,0 +1,3521 @@ +/*! + * Bootstrap v2.0.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +nav, +section { + display: block; +} +audio, canvas, video { + display: inline-block; + *display: inline; + *zoom: 1; +} +audio:not([controls]) { + display: none; +} +html { + font-size: 100%; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} +a:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +a:hover, a:active { + outline: 0; +} +sub, sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} +sup { + top: -0.5em; +} +sub { + bottom: -0.25em; +} +img { + max-width: 100%; + height: auto; + border: 0; + -ms-interpolation-mode: bicubic; +} +button, +input, +select, +textarea { + margin: 0; + font-size: 100%; + vertical-align: middle; +} +button, input { + *overflow: visible; + line-height: normal; +} +button::-moz-focus-inner, input::-moz-focus-inner { + padding: 0; + border: 0; +} +button, +input[type="button"], +input[type="reset"], +input[type="submit"] { + cursor: pointer; + -webkit-appearance: button; +} +input[type="search"] { + -webkit-appearance: textfield; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +input[type="search"]::-webkit-search-decoration, input[type="search"]::-webkit-search-cancel-button { + -webkit-appearance: none; +} +textarea { + overflow: auto; + vertical-align: top; +} +.clearfix { + *zoom: 1; +} +.clearfix:before, .clearfix:after { + display: table; + content: ""; +} +.clearfix:after { + clear: both; +} +body { + margin: 0; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 18px; + color: #333333; + background-color: #ffffff; +} +a { + color: #0088cc; + text-decoration: none; +} +a:hover { + color: #005580; + text-decoration: underline; +} +.row { + margin-left: -20px; + *zoom: 1; +} +.row:before, .row:after { + display: table; + content: ""; +} +.row:after { + clear: both; +} +[class*="span"] { + float: left; + margin-left: 20px; +} +.span1 { + width: 60px; +} +.span2 { + width: 140px; +} +.span3 { + width: 220px; +} +.span4 { + width: 300px; +} +.span5 { + width: 380px; +} +.span6 { + width: 460px; +} +.span7 { + width: 540px; +} +.span8 { + width: 620px; +} +.span9 { + width: 700px; +} +.span10 { + width: 780px; +} +.span11 { + width: 860px; +} +.span12, .container { + width: 940px; +} +.offset1 { + margin-left: 100px; +} +.offset2 { + margin-left: 180px; +} +.offset3 { + margin-left: 260px; +} +.offset4 { + margin-left: 340px; +} +.offset5 { + margin-left: 420px; +} +.offset6 { + margin-left: 500px; +} +.offset7 { + margin-left: 580px; +} +.offset8 { + margin-left: 660px; +} +.offset9 { + margin-left: 740px; +} +.offset10 { + margin-left: 820px; +} +.offset11 { + margin-left: 900px; +} +.row-fluid { + width: 100%; + *zoom: 1; +} +.row-fluid:before, .row-fluid:after { + display: table; + content: ""; +} +.row-fluid:after { + clear: both; +} +.row-fluid > [class*="span"] { + float: left; + margin-left: 2.127659574%; +} +.row-fluid > [class*="span"]:first-child { + margin-left: 0; +} +.row-fluid > .span1 { + width: 6.382978723%; +} +.row-fluid > .span2 { + width: 14.89361702%; +} +.row-fluid > .span3 { + width: 23.404255317%; +} +.row-fluid > .span4 { + width: 31.914893614%; +} +.row-fluid > .span5 { + width: 40.425531911%; +} +.row-fluid > .span6 { + width: 48.93617020799999%; +} +.row-fluid > .span7 { + width: 57.446808505%; +} +.row-fluid > .span8 { + width: 65.95744680199999%; +} +.row-fluid > .span9 { + width: 74.468085099%; +} +.row-fluid > .span10 { + width: 82.97872339599999%; +} +.row-fluid > .span11 { + width: 91.489361693%; +} +.row-fluid > .span12 { + width: 99.99999998999999%; +} +.container { + width: 940px; + margin-left: auto; + margin-right: auto; + *zoom: 1; +} +.container:before, .container:after { + display: table; + content: ""; +} +.container:after { + clear: both; +} +.container-fluid { + padding-left: 20px; + padding-right: 20px; + *zoom: 1; +} +.container-fluid:before, .container-fluid:after { + display: table; + content: ""; +} +.container-fluid:after { + clear: both; +} +p { + margin: 0 0 9px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 18px; +} +p small { + font-size: 11px; + color: #999999; +} +.lead { + margin-bottom: 18px; + font-size: 20px; + font-weight: 200; + line-height: 27px; +} +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 0; + font-weight: bold; + color: #333333; + text-rendering: optimizelegibility; +} +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small { + font-weight: normal; + color: #999999; +} +h1 { + font-size: 30px; + line-height: 36px; +} +h1 small { + font-size: 18px; +} +h2 { + font-size: 24px; + line-height: 36px; +} +h2 small { + font-size: 18px; +} +h3 { + line-height: 27px; + font-size: 18px; +} +h3 small { + font-size: 14px; +} +h4, h5, h6 { + line-height: 18px; +} +h4 { + font-size: 14px; +} +h4 small { + font-size: 12px; +} +h5 { + font-size: 12px; +} +h6 { + font-size: 11px; + color: #999999; + text-transform: uppercase; +} +.page-header { + padding-bottom: 17px; + margin: 18px 0; + border-bottom: 1px solid #eeeeee; +} +.page-header h1 { + line-height: 1; +} +ul, ol { + padding: 0; + margin: 0 0 9px 25px; +} +ul ul, +ul ol, +ol ol, +ol ul { + margin-bottom: 0; +} +ul { + list-style: disc; +} +ol { + list-style: decimal; +} +li { + line-height: 18px; +} +ul.unstyled, ol.unstyled { + margin-left: 0; + list-style: none; +} +dl { + margin-bottom: 18px; +} +dt, dd { + line-height: 18px; +} +dt { + font-weight: bold; +} +dd { + margin-left: 9px; +} +hr { + margin: 18px 0; + border: 0; + border-top: 1px solid #eeeeee; + border-bottom: 1px solid #ffffff; +} +strong { + font-weight: bold; +} +em { + font-style: italic; +} +.muted { + color: #999999; +} +abbr { + font-size: 90%; + text-transform: uppercase; + border-bottom: 1px dotted #ddd; + cursor: help; +} +blockquote { + padding: 0 0 0 15px; + margin: 0 0 18px; + border-left: 5px solid #eeeeee; +} +blockquote p { + margin-bottom: 0; + font-size: 16px; + font-weight: 300; + line-height: 22.5px; +} +blockquote small { + display: block; + line-height: 18px; + color: #999999; +} +blockquote small:before { + content: '\2014 \00A0'; +} +blockquote.pull-right { + float: right; + padding-left: 0; + padding-right: 15px; + border-left: 0; + border-right: 5px solid #eeeeee; +} +blockquote.pull-right p, blockquote.pull-right small { + text-align: right; +} +q:before, +q:after, +blockquote:before, +blockquote:after { + content: ""; +} +address { + display: block; + margin-bottom: 18px; + line-height: 18px; + font-style: normal; +} +small { + font-size: 100%; +} +cite { + font-style: normal; +} +code, pre { + padding: 0 3px 2px; + font-family: Menlo, Monaco, "Courier New", monospace; + font-size: 12px; + color: #333333; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +code { + padding: 3px 4px; + color: #d14; + background-color: #f7f7f9; + border: 1px solid #e1e1e8; +} +pre { + display: block; + padding: 8.5px; + margin: 0 0 9px; + font-size: 12px; + line-height: 18px; + background-color: #f5f5f5; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.15); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + white-space: pre; + white-space: pre-wrap; + word-break: break-all; + word-wrap: break-word; +} +pre.prettyprint { + margin-bottom: 18px; +} +pre code { + padding: 0; + color: inherit; + background-color: transparent; + border: 0; +} +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} +form { + margin: 0 0 18px; +} +fieldset { + padding: 0; + margin: 0; + border: 0; +} +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 27px; + font-size: 19.5px; + line-height: 36px; + color: #333333; + border: 0; + border-bottom: 1px solid #eee; +} +legend small { + font-size: 13.5px; + color: #999999; +} +label, +input, +button, +select, +textarea { + font-size: 13px; + font-weight: normal; + line-height: 18px; +} +input, +button, +select, +textarea { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; +} +label { + display: block; + margin-bottom: 5px; + color: #333333; +} +input, +textarea, +select, +.uneditable-input { + display: inline-block; + width: 210px; + height: 18px; + padding: 4px; + margin-bottom: 9px; + font-size: 13px; + line-height: 18px; + color: #555555; + border: 1px solid #ccc; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.uneditable-textarea { + width: auto; + height: auto; +} +label input, label textarea, label select { + display: block; +} +input[type="image"], input[type="checkbox"], input[type="radio"] { + width: auto; + height: auto; + padding: 0; + margin: 3px 0; + *margin-top: 0; + /* IE7 */ + + line-height: normal; + cursor: pointer; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + border: 0 \9; + /* IE9 and down */ + +} +input[type="image"] { + border: 0; +} +input[type="file"] { + width: auto; + padding: initial; + line-height: initial; + border: initial; + background-color: #ffffff; + background-color: initial; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +input[type="button"], input[type="reset"], input[type="submit"] { + width: auto; + height: auto; +} +select, input[type="file"] { + height: 28px; + /* In IE7, the height of the select element cannot be changed by height, only font-size */ + + *margin-top: 4px; + /* For IE7, add top margin to align select with labels */ + + line-height: 28px; +} +input[type="file"] { + line-height: 18px \9; +} +select { + width: 220px; + background-color: #ffffff; +} +select[multiple], select[size] { + height: auto; +} +input[type="image"] { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +textarea { + height: auto; +} +input[type="hidden"] { + display: none; +} +.radio, .checkbox { + padding-left: 18px; +} +.radio input[type="radio"], .checkbox input[type="checkbox"] { + float: left; + margin-left: -18px; +} +.controls > .radio:first-child, .controls > .checkbox:first-child { + padding-top: 5px; +} +.radio.inline, .checkbox.inline { + display: inline-block; + padding-top: 5px; + margin-bottom: 0; + vertical-align: middle; +} +.radio.inline + .radio.inline, .checkbox.inline + .checkbox.inline { + margin-left: 10px; +} +input, textarea { + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; + -moz-transition: border linear 0.2s, box-shadow linear 0.2s; + -ms-transition: border linear 0.2s, box-shadow linear 0.2s; + -o-transition: border linear 0.2s, box-shadow linear 0.2s; + transition: border linear 0.2s, box-shadow linear 0.2s; +} +input:focus, textarea:focus { + border-color: rgba(82, 168, 236, 0.8); + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + outline: 0; + outline: thin dotted \9; + /* IE6-9 */ + +} +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus, +select:focus { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.input-mini { + width: 60px; +} +.input-small { + width: 90px; +} +.input-medium { + width: 150px; +} +.input-large { + width: 210px; +} +.input-xlarge { + width: 270px; +} +.input-xxlarge { + width: 530px; +} +input[class*="span"], +select[class*="span"], +textarea[class*="span"], +.uneditable-input { + float: none; + margin-left: 0; +} +input.span1, textarea.span1, .uneditable-input.span1 { + width: 50px; +} +input.span2, textarea.span2, .uneditable-input.span2 { + width: 130px; +} +input.span3, textarea.span3, .uneditable-input.span3 { + width: 210px; +} +input.span4, textarea.span4, .uneditable-input.span4 { + width: 290px; +} +input.span5, textarea.span5, .uneditable-input.span5 { + width: 370px; +} +input.span6, textarea.span6, .uneditable-input.span6 { + width: 450px; +} +input.span7, textarea.span7, .uneditable-input.span7 { + width: 530px; +} +input.span8, textarea.span8, .uneditable-input.span8 { + width: 610px; +} +input.span9, textarea.span9, .uneditable-input.span9 { + width: 690px; +} +input.span10, textarea.span10, .uneditable-input.span10 { + width: 770px; +} +input.span11, textarea.span11, .uneditable-input.span11 { + width: 850px; +} +input.span12, textarea.span12, .uneditable-input.span12 { + width: 930px; +} +input[disabled], +select[disabled], +textarea[disabled], +input[readonly], +select[readonly], +textarea[readonly] { + background-color: #f5f5f5; + border-color: #ddd; + cursor: not-allowed; +} +.control-group.warning > label, .control-group.warning .help-block, .control-group.warning .help-inline { + color: #c09853; +} +.control-group.warning input, .control-group.warning select, .control-group.warning textarea { + color: #c09853; + border-color: #c09853; +} +.control-group.warning input:focus, .control-group.warning select:focus, .control-group.warning textarea:focus { + border-color: #a47e3c; + -webkit-box-shadow: 0 0 6px #dbc59e; + -moz-box-shadow: 0 0 6px #dbc59e; + box-shadow: 0 0 6px #dbc59e; +} +.control-group.warning .input-prepend .add-on, .control-group.warning .input-append .add-on { + color: #c09853; + background-color: #fcf8e3; + border-color: #c09853; +} +.control-group.error > label, .control-group.error .help-block, .control-group.error .help-inline { + color: #b94a48; +} +.control-group.error input, .control-group.error select, .control-group.error textarea { + color: #b94a48; + border-color: #b94a48; +} +.control-group.error input:focus, .control-group.error select:focus, .control-group.error textarea:focus { + border-color: #953b39; + -webkit-box-shadow: 0 0 6px #d59392; + -moz-box-shadow: 0 0 6px #d59392; + box-shadow: 0 0 6px #d59392; +} +.control-group.error .input-prepend .add-on, .control-group.error .input-append .add-on { + color: #b94a48; + background-color: #f2dede; + border-color: #b94a48; +} +.control-group.success > label, .control-group.success .help-block, .control-group.success .help-inline { + color: #468847; +} +.control-group.success input, .control-group.success select, .control-group.success textarea { + color: #468847; + border-color: #468847; +} +.control-group.success input:focus, .control-group.success select:focus, .control-group.success textarea:focus { + border-color: #356635; + -webkit-box-shadow: 0 0 6px #7aba7b; + -moz-box-shadow: 0 0 6px #7aba7b; + box-shadow: 0 0 6px #7aba7b; +} +.control-group.success .input-prepend .add-on, .control-group.success .input-append .add-on { + color: #468847; + background-color: #dff0d8; + border-color: #468847; +} +input:focus:required:invalid, textarea:focus:required:invalid, select:focus:required:invalid { + color: #b94a48; + border-color: #ee5f5b; +} +input:focus:required:invalid:focus, textarea:focus:required:invalid:focus, select:focus:required:invalid:focus { + border-color: #e9322d; + -webkit-box-shadow: 0 0 6px #f8b9b7; + -moz-box-shadow: 0 0 6px #f8b9b7; + box-shadow: 0 0 6px #f8b9b7; +} +.form-actions { + padding: 17px 20px 18px; + margin-top: 18px; + margin-bottom: 18px; + background-color: #f5f5f5; + border-top: 1px solid #ddd; +} +.uneditable-input { + display: block; + background-color: #ffffff; + border-color: #eee; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + cursor: not-allowed; +} +:-moz-placeholder { + color: #999999; +} +::-webkit-input-placeholder { + color: #999999; +} +.help-block { + display: block; + margin-top: 5px; + margin-bottom: 0; + color: #999999; +} +.help-inline { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; + margin-bottom: 9px; + vertical-align: middle; + padding-left: 5px; +} +.input-prepend, .input-append { + margin-bottom: 5px; + *zoom: 1; +} +.input-prepend:before, +.input-append:before, +.input-prepend:after, +.input-append:after { + display: table; + content: ""; +} +.input-prepend:after, .input-append:after { + clear: both; +} +.input-prepend input, +.input-append input, +.input-prepend .uneditable-input, +.input-append .uneditable-input { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.input-prepend input:focus, +.input-append input:focus, +.input-prepend .uneditable-input:focus, +.input-append .uneditable-input:focus { + position: relative; + z-index: 2; +} +.input-prepend .uneditable-input, .input-append .uneditable-input { + border-left-color: #ccc; +} +.input-prepend .add-on, .input-append .add-on { + float: left; + display: block; + width: auto; + min-width: 16px; + height: 18px; + margin-right: -1px; + padding: 4px 5px; + font-weight: normal; + line-height: 18px; + color: #999999; + text-align: center; + text-shadow: 0 1px 0 #ffffff; + background-color: #f5f5f5; + border: 1px solid #ccc; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.input-prepend .active, .input-append .active { + background-color: #a9dba9; + border-color: #46a546; +} +.input-prepend .add-on { + *margin-top: 1px; + /* IE6-7 */ + +} +.input-append input, .input-append .uneditable-input { + float: left; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.input-append .uneditable-input { + border-left-color: #eee; + border-right-color: #ccc; +} +.input-append .add-on { + margin-right: 0; + margin-left: -1px; + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.input-append input:first-child { + *margin-left: -160px; +} +.input-append input:first-child + .add-on { + *margin-left: -21px; +} +.search-query { + padding-left: 14px; + padding-right: 14px; + margin-bottom: 0; + -webkit-border-radius: 14px; + -moz-border-radius: 14px; + border-radius: 14px; +} +.form-search input, +.form-inline input, +.form-horizontal input, +.form-search textarea, +.form-inline textarea, +.form-horizontal textarea, +.form-search select, +.form-inline select, +.form-horizontal select, +.form-search .help-inline, +.form-inline .help-inline, +.form-horizontal .help-inline, +.form-search .uneditable-input, +.form-inline .uneditable-input, +.form-horizontal .uneditable-input { + display: inline-block; + margin-bottom: 0; +} +.form-search .hide, .form-inline .hide, .form-horizontal .hide { + display: none; +} +.form-search label, +.form-inline label, +.form-search .input-append, +.form-inline .input-append, +.form-search .input-prepend, +.form-inline .input-prepend { + display: inline-block; +} +.form-search .input-append .add-on, +.form-inline .input-prepend .add-on, +.form-search .input-append .add-on, +.form-inline .input-prepend .add-on { + vertical-align: middle; +} +.form-search .radio, +.form-inline .radio, +.form-search .checkbox, +.form-inline .checkbox { + margin-bottom: 0; + vertical-align: middle; +} +.control-group { + margin-bottom: 9px; +} +legend + .control-group { + margin-top: 18px; + -webkit-margin-top-collapse: separate; +} +.form-horizontal .control-group { + margin-bottom: 18px; + *zoom: 1; +} +.form-horizontal .control-group:before, .form-horizontal .control-group:after { + display: table; + content: ""; +} +.form-horizontal .control-group:after { + clear: both; +} +.form-horizontal .control-label { + float: left; + width: 140px; + padding-top: 5px; + text-align: right; +} +.form-horizontal .controls { + margin-left: 160px; +} +.form-horizontal .form-actions { + padding-left: 160px; +} +table { + max-width: 100%; + border-collapse: collapse; + border-spacing: 0; +} +.table { + width: 100%; + margin-bottom: 18px; +} +.table th, .table td { + padding: 8px; + line-height: 18px; + text-align: left; + vertical-align: top; + border-top: 1px solid #ddd; +} +.table th { + font-weight: bold; +} +.table thead th { + vertical-align: bottom; +} +.table thead:first-child tr th, .table thead:first-child tr td { + border-top: 0; +} +.table tbody + tbody { + border-top: 2px solid #ddd; +} +.table-condensed th, .table-condensed td { + padding: 4px 5px; +} +.table-bordered { + border: 1px solid #ddd; + border-collapse: separate; + *border-collapse: collapsed; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.table-bordered th + th, +.table-bordered td + td, +.table-bordered th + td, +.table-bordered td + th { + border-left: 1px solid #ddd; +} +.table-bordered thead:first-child tr:first-child th, .table-bordered tbody:first-child tr:first-child th, .table-bordered tbody:first-child tr:first-child td { + border-top: 0; +} +.table-bordered thead:first-child tr:first-child th:first-child, .table-bordered tbody:first-child tr:first-child td:first-child { + -webkit-border-radius: 4px 0 0 0; + -moz-border-radius: 4px 0 0 0; + border-radius: 4px 0 0 0; +} +.table-bordered thead:first-child tr:first-child th:last-child, .table-bordered tbody:first-child tr:first-child td:last-child { + -webkit-border-radius: 0 4px 0 0; + -moz-border-radius: 0 4px 0 0; + border-radius: 0 4px 0 0; +} +.table-bordered thead:last-child tr:last-child th:first-child, .table-bordered tbody:last-child tr:last-child td:first-child { + -webkit-border-radius: 0 0 0 4px; + -moz-border-radius: 0 0 0 4px; + border-radius: 0 0 0 4px; +} +.table-bordered thead:last-child tr:last-child th:last-child, .table-bordered tbody:last-child tr:last-child td:last-child { + -webkit-border-radius: 0 0 4px 0; + -moz-border-radius: 0 0 4px 0; + border-radius: 0 0 4px 0; +} +.table-striped tbody tr:nth-child(odd) td, .table-striped tbody tr:nth-child(odd) th { + background-color: #f9f9f9; +} +.table tbody tr:hover td, .table tbody tr:hover th { + background-color: #f5f5f5; +} +table .span1 { + float: none; + width: 44px; + margin-left: 0; +} +table .span2 { + float: none; + width: 124px; + margin-left: 0; +} +table .span3 { + float: none; + width: 204px; + margin-left: 0; +} +table .span4 { + float: none; + width: 284px; + margin-left: 0; +} +table .span5 { + float: none; + width: 364px; + margin-left: 0; +} +table .span6 { + float: none; + width: 444px; + margin-left: 0; +} +table .span7 { + float: none; + width: 524px; + margin-left: 0; +} +table .span8 { + float: none; + width: 604px; + margin-left: 0; +} +table .span9 { + float: none; + width: 684px; + margin-left: 0; +} +table .span10 { + float: none; + width: 764px; + margin-left: 0; +} +table .span11 { + float: none; + width: 844px; + margin-left: 0; +} +table .span12 { + float: none; + width: 924px; + margin-left: 0; +} +[class^="icon-"], [class*=" icon-"] { + display: inline-block; + width: 14px; + height: 14px; + line-height: 14px; + vertical-align: text-top; + background-image: url("../img/glyphicons-halflings.png"); + background-position: 14px 14px; + background-repeat: no-repeat; + *margin-right: .3em; +} +[class^="icon-"]:last-child, [class*=" icon-"]:last-child { + *margin-left: 0; +} +.icon-white { + background-image: url("../img/glyphicons-halflings-white.png"); +} +.icon-glass { + background-position: 0 0; +} +.icon-music { + background-position: -24px 0; +} +.icon-search { + background-position: -48px 0; +} +.icon-envelope { + background-position: -72px 0; +} +.icon-heart { + background-position: -96px 0; +} +.icon-star { + background-position: -120px 0; +} +.icon-star-empty { + background-position: -144px 0; +} +.icon-user { + background-position: -168px 0; +} +.icon-film { + background-position: -192px 0; +} +.icon-th-large { + background-position: -216px 0; +} +.icon-th { + background-position: -240px 0; +} +.icon-th-list { + background-position: -264px 0; +} +.icon-ok { + background-position: -288px 0; +} +.icon-remove { + background-position: -312px 0; +} +.icon-zoom-in { + background-position: -336px 0; +} +.icon-zoom-out { + background-position: -360px 0; +} +.icon-off { + background-position: -384px 0; +} +.icon-signal { + background-position: -408px 0; +} +.icon-cog { + background-position: -432px 0; +} +.icon-trash { + background-position: -456px 0; +} +.icon-home { + background-position: 0 -24px; +} +.icon-file { + background-position: -24px -24px; +} +.icon-time { + background-position: -48px -24px; +} +.icon-road { + background-position: -72px -24px; +} +.icon-download-alt { + background-position: -96px -24px; +} +.icon-download { + background-position: -120px -24px; +} +.icon-upload { + background-position: -144px -24px; +} +.icon-inbox { + background-position: -168px -24px; +} +.icon-play-circle { + background-position: -192px -24px; +} +.icon-repeat { + background-position: -216px -24px; +} +.icon-refresh { + background-position: -240px -24px; +} +.icon-list-alt { + background-position: -264px -24px; +} +.icon-lock { + background-position: -287px -24px; +} +.icon-flag { + background-position: -312px -24px; +} +.icon-headphones { + background-position: -336px -24px; +} +.icon-volume-off { + background-position: -360px -24px; +} +.icon-volume-down { + background-position: -384px -24px; +} +.icon-volume-up { + background-position: -408px -24px; +} +.icon-qrcode { + background-position: -432px -24px; +} +.icon-barcode { + background-position: -456px -24px; +} +.icon-tag { + background-position: 0 -48px; +} +.icon-tags { + background-position: -25px -48px; +} +.icon-book { + background-position: -48px -48px; +} +.icon-bookmark { + background-position: -72px -48px; +} +.icon-print { + background-position: -96px -48px; +} +.icon-camera { + background-position: -120px -48px; +} +.icon-font { + background-position: -144px -48px; +} +.icon-bold { + background-position: -167px -48px; +} +.icon-italic { + background-position: -192px -48px; +} +.icon-text-height { + background-position: -216px -48px; +} +.icon-text-width { + background-position: -240px -48px; +} +.icon-align-left { + background-position: -264px -48px; +} +.icon-align-center { + background-position: -288px -48px; +} +.icon-align-right { + background-position: -312px -48px; +} +.icon-align-justify { + background-position: -336px -48px; +} +.icon-list { + background-position: -360px -48px; +} +.icon-indent-left { + background-position: -384px -48px; +} +.icon-indent-right { + background-position: -408px -48px; +} +.icon-facetime-video { + background-position: -432px -48px; +} +.icon-picture { + background-position: -456px -48px; +} +.icon-pencil { + background-position: 0 -72px; +} +.icon-map-marker { + background-position: -24px -72px; +} +.icon-adjust { + background-position: -48px -72px; +} +.icon-tint { + background-position: -72px -72px; +} +.icon-edit { + background-position: -96px -72px; +} +.icon-share { + background-position: -120px -72px; +} +.icon-check { + background-position: -144px -72px; +} +.icon-move { + background-position: -168px -72px; +} +.icon-step-backward { + background-position: -192px -72px; +} +.icon-fast-backward { + background-position: -216px -72px; +} +.icon-backward { + background-position: -240px -72px; +} +.icon-play { + background-position: -264px -72px; +} +.icon-pause { + background-position: -288px -72px; +} +.icon-stop { + background-position: -312px -72px; +} +.icon-forward { + background-position: -336px -72px; +} +.icon-fast-forward { + background-position: -360px -72px; +} +.icon-step-forward { + background-position: -384px -72px; +} +.icon-eject { + background-position: -408px -72px; +} +.icon-chevron-left { + background-position: -432px -72px; +} +.icon-chevron-right { + background-position: -456px -72px; +} +.icon-plus-sign { + background-position: 0 -96px; +} +.icon-minus-sign { + background-position: -24px -96px; +} +.icon-remove-sign { + background-position: -48px -96px; +} +.icon-ok-sign { + background-position: -72px -96px; +} +.icon-question-sign { + background-position: -96px -96px; +} +.icon-info-sign { + background-position: -120px -96px; +} +.icon-screenshot { + background-position: -144px -96px; +} +.icon-remove-circle { + background-position: -168px -96px; +} +.icon-ok-circle { + background-position: -192px -96px; +} +.icon-ban-circle { + background-position: -216px -96px; +} +.icon-arrow-left { + background-position: -240px -96px; +} +.icon-arrow-right { + background-position: -264px -96px; +} +.icon-arrow-up { + background-position: -289px -96px; +} +.icon-arrow-down { + background-position: -312px -96px; +} +.icon-share-alt { + background-position: -336px -96px; +} +.icon-resize-full { + background-position: -360px -96px; +} +.icon-resize-small { + background-position: -384px -96px; +} +.icon-plus { + background-position: -408px -96px; +} +.icon-minus { + background-position: -433px -96px; +} +.icon-asterisk { + background-position: -456px -96px; +} +.icon-exclamation-sign { + background-position: 0 -120px; +} +.icon-gift { + background-position: -24px -120px; +} +.icon-leaf { + background-position: -48px -120px; +} +.icon-fire { + background-position: -72px -120px; +} +.icon-eye-open { + background-position: -96px -120px; +} +.icon-eye-close { + background-position: -120px -120px; +} +.icon-warning-sign { + background-position: -144px -120px; +} +.icon-plane { + background-position: -168px -120px; +} +.icon-calendar { + background-position: -192px -120px; +} +.icon-random { + background-position: -216px -120px; +} +.icon-comment { + background-position: -240px -120px; +} +.icon-magnet { + background-position: -264px -120px; +} +.icon-chevron-up { + background-position: -288px -120px; +} +.icon-chevron-down { + background-position: -313px -119px; +} +.icon-retweet { + background-position: -336px -120px; +} +.icon-shopping-cart { + background-position: -360px -120px; +} +.icon-folder-close { + background-position: -384px -120px; +} +.icon-folder-open { + background-position: -408px -120px; +} +.icon-resize-vertical { + background-position: -432px -119px; +} +.icon-resize-horizontal { + background-position: -456px -118px; +} +.dropdown { + position: relative; +} +.dropdown-toggle { + *margin-bottom: -3px; +} +.dropdown-toggle:active, .open .dropdown-toggle { + outline: 0; +} +.caret { + display: inline-block; + width: 0; + height: 0; + text-indent: -99999px; + *text-indent: 0; + vertical-align: top; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 4px solid #000000; + opacity: 0.3; + filter: alpha(opacity=30); + content: "\2193"; +} +.dropdown .caret { + margin-top: 8px; + margin-left: 2px; +} +.dropdown:hover .caret, .open.dropdown .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + float: left; + display: none; + min-width: 160px; + _width: 160px; + padding: 4px 0; + margin: 0; + list-style: none; + background-color: #ffffff; + border-color: #ccc; + border-color: rgba(0, 0, 0, 0.2); + border-style: solid; + border-width: 1px; + -webkit-border-radius: 0 0 5px 5px; + -moz-border-radius: 0 0 5px 5px; + border-radius: 0 0 5px 5px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; + *border-right-width: 2px; + *border-bottom-width: 2px; +} +.dropdown-menu.bottom-up { + top: auto; + bottom: 100%; + margin-bottom: 2px; +} +.dropdown-menu .divider { + height: 1px; + margin: 5px 1px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #ffffff; + *width: 100%; + *margin: -5px 0 5px; +} +.dropdown-menu a { + display: block; + padding: 3px 15px; + clear: both; + font-weight: normal; + line-height: 18px; + color: #555555; + white-space: nowrap; +} +.dropdown-menu li > a:hover, .dropdown-menu .active > a, .dropdown-menu .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #0088cc; +} +.dropdown.open { + *z-index: 1000; +} +.dropdown.open .dropdown-toggle { + color: #ffffff; + background: #ccc; + background: rgba(0, 0, 0, 0.3); +} +.dropdown.open .dropdown-menu { + display: block; +} +.typeahead { + margin-top: 2px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #f5f5f5; + border: 1px solid #eee; + border: 1px solid rgba(0, 0, 0, 0.05); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 0, 0, 0.15); +} +.fade { + -webkit-transition: opacity 0.15s linear; + -moz-transition: opacity 0.15s linear; + -ms-transition: opacity 0.15s linear; + -o-transition: opacity 0.15s linear; + transition: opacity 0.15s linear; + opacity: 0; +} +.fade.in { + opacity: 1; +} +.collapse { + -webkit-transition: height 0.35s ease; + -moz-transition: height 0.35s ease; + -ms-transition: height 0.35s ease; + -o-transition: height 0.35s ease; + transition: height 0.35s ease; + position: relative; + overflow: hidden; + height: 0; +} +.collapse.in { + height: auto; +} +.close { + float: right; + font-size: 20px; + font-weight: bold; + line-height: 18px; + color: #000000; + text-shadow: 0 1px 0 #ffffff; + opacity: 0.2; + filter: alpha(opacity=20); +} +.close:hover { + color: #000000; + text-decoration: none; + opacity: 0.4; + filter: alpha(opacity=40); + cursor: pointer; +} +.btn { + display: inline-block; + padding: 4px 10px 4px; + margin-bottom: 0; + font-size: 13px; + line-height: 18px; + color: #333333; + text-align: center; + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); + vertical-align: middle; + background-color: #f5f5f5; + background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); + background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); + background-image: linear-gradient(top, #ffffff, #e6e6e6); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0); + border-color: #e6e6e6 #e6e6e6 #bfbfbf; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + border: 1px solid #ccc; + border-bottom-color: #bbb; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + cursor: pointer; + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + *margin-left: .3em; +} +.btn:hover, +.btn:active, +.btn.active, +.btn.disabled, +.btn[disabled] { + background-color: #e6e6e6; +} +.btn:active, .btn.active { + background-color: #cccccc \9; +} +.btn:first-child { + *margin-left: 0; +} +.btn:hover { + color: #333333; + text-decoration: none; + background-color: #e6e6e6; + background-position: 0 -15px; + -webkit-transition: background-position 0.1s linear; + -moz-transition: background-position 0.1s linear; + -ms-transition: background-position 0.1s linear; + -o-transition: background-position 0.1s linear; + transition: background-position 0.1s linear; +} +.btn:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.btn.active, .btn:active { + background-image: none; + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + background-color: #e6e6e6; + background-color: #d9d9d9 \9; + outline: 0; +} +.btn.disabled, .btn[disabled] { + cursor: default; + background-image: none; + background-color: #e6e6e6; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +.btn-large { + padding: 9px 14px; + font-size: 15px; + line-height: normal; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.btn-large [class^="icon-"] { + margin-top: 1px; +} +.btn-small { + padding: 5px 9px; + font-size: 11px; + line-height: 16px; +} +.btn-small [class^="icon-"] { + margin-top: -1px; +} +.btn-mini { + padding: 2px 6px; + font-size: 11px; + line-height: 14px; +} +.btn-primary, +.btn-primary:hover, +.btn-warning, +.btn-warning:hover, +.btn-danger, +.btn-danger:hover, +.btn-success, +.btn-success:hover, +.btn-info, +.btn-info:hover, +.btn-inverse, +.btn-inverse:hover { + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + color: #ffffff; +} +.btn-primary.active, +.btn-warning.active, +.btn-danger.active, +.btn-success.active, +.btn-info.active, +.btn-dark.active { + color: rgba(255, 255, 255, 0.75); +} +.btn-primary { + background-color: #006dcc; + background-image: -moz-linear-gradient(top, #0088cc, #0044cc); + background-image: -ms-linear-gradient(top, #0088cc, #0044cc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); + background-image: -o-linear-gradient(top, #0088cc, #0044cc); + background-image: linear-gradient(top, #0088cc, #0044cc); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); + border-color: #0044cc #0044cc #002a80; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-primary:hover, +.btn-primary:active, +.btn-primary.active, +.btn-primary.disabled, +.btn-primary[disabled] { + background-color: #0044cc; +} +.btn-primary:active, .btn-primary.active { + background-color: #003399 \9; +} +.btn-warning { + background-color: #faa732; + background-image: -moz-linear-gradient(top, #fbb450, #f89406); + background-image: -ms-linear-gradient(top, #fbb450, #f89406); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); + background-image: -webkit-linear-gradient(top, #fbb450, #f89406); + background-image: -o-linear-gradient(top, #fbb450, #f89406); + background-image: linear-gradient(top, #fbb450, #f89406); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0); + border-color: #f89406 #f89406 #ad6704; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-warning:hover, +.btn-warning:active, +.btn-warning.active, +.btn-warning.disabled, +.btn-warning[disabled] { + background-color: #f89406; +} +.btn-warning:active, .btn-warning.active { + background-color: #c67605 \9; +} +.btn-danger { + background-color: #da4f49; + background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -ms-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -o-linear-gradient(top, #ee5f5b, #bd362f); + background-image: linear-gradient(top, #ee5f5b, #bd362f); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0); + border-color: #bd362f #bd362f #802420; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-danger:hover, +.btn-danger:active, +.btn-danger.active, +.btn-danger.disabled, +.btn-danger[disabled] { + background-color: #bd362f; +} +.btn-danger:active, .btn-danger.active { + background-color: #942a25 \9; +} +.btn-success { + background-color: #5bb75b; + background-image: -moz-linear-gradient(top, #62c462, #51a351); + background-image: -ms-linear-gradient(top, #62c462, #51a351); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351)); + background-image: -webkit-linear-gradient(top, #62c462, #51a351); + background-image: -o-linear-gradient(top, #62c462, #51a351); + background-image: linear-gradient(top, #62c462, #51a351); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0); + border-color: #51a351 #51a351 #387038; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-success:hover, +.btn-success:active, +.btn-success.active, +.btn-success.disabled, +.btn-success[disabled] { + background-color: #51a351; +} +.btn-success:active, .btn-success.active { + background-color: #408140 \9; +} +.btn-info { + background-color: #49afcd; + background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -ms-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4)); + background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -o-linear-gradient(top, #5bc0de, #2f96b4); + background-image: linear-gradient(top, #5bc0de, #2f96b4); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0); + border-color: #2f96b4 #2f96b4 #1f6377; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-info:hover, +.btn-info:active, +.btn-info.active, +.btn-info.disabled, +.btn-info[disabled] { + background-color: #2f96b4; +} +.btn-info:active, .btn-info.active { + background-color: #24748c \9; +} +.btn-inverse { + background-color: #393939; + background-image: -moz-linear-gradient(top, #454545, #262626); + background-image: -ms-linear-gradient(top, #454545, #262626); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#454545), to(#262626)); + background-image: -webkit-linear-gradient(top, #454545, #262626); + background-image: -o-linear-gradient(top, #454545, #262626); + background-image: linear-gradient(top, #454545, #262626); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#454545', endColorstr='#262626', GradientType=0); + border-color: #262626 #262626 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-inverse:hover, +.btn-inverse:active, +.btn-inverse.active, +.btn-inverse.disabled, +.btn-inverse[disabled] { + background-color: #262626; +} +.btn-inverse:active, .btn-inverse.active { + background-color: #0c0c0c \9; +} +button.btn, input[type="submit"].btn { + *padding-top: 2px; + *padding-bottom: 2px; +} +button.btn::-moz-focus-inner, input[type="submit"].btn::-moz-focus-inner { + padding: 0; + border: 0; +} +button.btn.large, input[type="submit"].btn.large { + *padding-top: 7px; + *padding-bottom: 7px; +} +button.btn.small, input[type="submit"].btn.small { + *padding-top: 3px; + *padding-bottom: 3px; +} +.btn-group { + position: relative; + *zoom: 1; + *margin-left: .3em; +} +.btn-group:before, .btn-group:after { + display: table; + content: ""; +} +.btn-group:after { + clear: both; +} +.btn-group:first-child { + *margin-left: 0; +} +.btn-group + .btn-group { + margin-left: 5px; +} +.btn-toolbar { + margin-top: 9px; + margin-bottom: 9px; +} +.btn-toolbar .btn-group { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; +} +.btn-group .btn { + position: relative; + float: left; + margin-left: -1px; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.btn-group .btn:first-child { + margin-left: 0; + -webkit-border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; + border-top-left-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + border-bottom-left-radius: 4px; +} +.btn-group .btn:last-child, .btn-group .dropdown-toggle { + -webkit-border-top-right-radius: 4px; + -moz-border-radius-topright: 4px; + border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -moz-border-radius-bottomright: 4px; + border-bottom-right-radius: 4px; +} +.btn-group .btn.large:first-child { + margin-left: 0; + -webkit-border-top-left-radius: 6px; + -moz-border-radius-topleft: 6px; + border-top-left-radius: 6px; + -webkit-border-bottom-left-radius: 6px; + -moz-border-radius-bottomleft: 6px; + border-bottom-left-radius: 6px; +} +.btn-group .btn.large:last-child, .btn-group .large.dropdown-toggle { + -webkit-border-top-right-radius: 6px; + -moz-border-radius-topright: 6px; + border-top-right-radius: 6px; + -webkit-border-bottom-right-radius: 6px; + -moz-border-radius-bottomright: 6px; + border-bottom-right-radius: 6px; +} +.btn-group .btn:hover, +.btn-group .btn:focus, +.btn-group .btn:active, +.btn-group .btn.active { + z-index: 2; +} +.btn-group .dropdown-toggle:active, .btn-group.open .dropdown-toggle { + outline: 0; +} +.btn-group .dropdown-toggle { + padding-left: 8px; + padding-right: 8px; + -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + *padding-top: 5px; + *padding-bottom: 5px; +} +.btn-group.open { + *z-index: 1000; +} +.btn-group.open .dropdown-menu { + display: block; + margin-top: 1px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.btn-group.open .dropdown-toggle { + background-image: none; + -webkit-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); +} +.btn .caret { + margin-top: 7px; + margin-left: 0; +} +.btn:hover .caret, .open.btn-group .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.btn-primary .caret, +.btn-danger .caret, +.btn-info .caret, +.btn-success .caret, +.btn-inverse .caret { + border-top-color: #ffffff; + opacity: 0.75; + filter: alpha(opacity=75); +} +.btn-small .caret { + margin-top: 4px; +} +.alert { + padding: 8px 35px 8px 14px; + margin-bottom: 18px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + background-color: #fcf8e3; + border: 1px solid #fbeed5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.alert, .alert-heading { + color: #c09853; +} +.alert .close { + position: relative; + top: -2px; + right: -21px; + line-height: 18px; +} +.alert-success { + background-color: #dff0d8; + border-color: #d6e9c6; +} +.alert-success, .alert-success .alert-heading { + color: #468847; +} +.alert-danger, .alert-error { + background-color: #f2dede; + border-color: #eed3d7; +} +.alert-danger, +.alert-error, +.alert-danger .alert-heading, +.alert-error .alert-heading { + color: #b94a48; +} +.alert-info { + background-color: #d9edf7; + border-color: #bce8f1; +} +.alert-info, .alert-info .alert-heading { + color: #3a87ad; +} +.alert-block { + padding-top: 14px; + padding-bottom: 14px; +} +.alert-block > p, .alert-block > ul { + margin-bottom: 0; +} +.alert-block p + p { + margin-top: 5px; +} +.nav { + margin-left: 0; + margin-bottom: 18px; + list-style: none; +} +.nav > li > a { + display: block; +} +.nav > li > a:hover { + text-decoration: none; + background-color: #eeeeee; +} +.nav .nav-header { + display: block; + padding: 3px 15px; + font-size: 11px; + font-weight: bold; + line-height: 18px; + color: #999999; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + text-transform: uppercase; +} +.nav li + .nav-header { + margin-top: 9px; +} +.nav-list { + padding-left: 14px; + padding-right: 14px; + margin-bottom: 0; +} +.nav-list > li > a, .nav-list .nav-header { + margin-left: -15px; + margin-right: -15px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); +} +.nav-list > li > a { + padding: 3px 15px; +} +.nav-list .active > a, .nav-list .active > a:hover { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); + background-color: #0088cc; +} +.nav-list [class^="icon-"] { + margin-right: 2px; +} +.nav-tabs, .nav-pills { + *zoom: 1; +} +.nav-tabs:before, +.nav-pills:before, +.nav-tabs:after, +.nav-pills:after { + display: table; + content: ""; +} +.nav-tabs:after, .nav-pills:after { + clear: both; +} +.nav-tabs > li, .nav-pills > li { + float: left; +} +.nav-tabs > li > a, .nav-pills > li > a { + padding-right: 12px; + padding-left: 12px; + margin-right: 2px; + line-height: 14px; +} +.nav-tabs { + border-bottom: 1px solid #ddd; +} +.nav-tabs > li { + margin-bottom: -1px; +} +.nav-tabs > li > a { + padding-top: 9px; + padding-bottom: 9px; + border: 1px solid transparent; + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} +.nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #dddddd; +} +.nav-tabs > .active > a, .nav-tabs > .active > a:hover { + color: #555555; + background-color: #ffffff; + border: 1px solid #ddd; + border-bottom-color: transparent; + cursor: default; +} +.nav-pills > li > a { + padding-top: 8px; + padding-bottom: 8px; + margin-top: 2px; + margin-bottom: 2px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.nav-pills .active > a, .nav-pills .active > a:hover { + color: #ffffff; + background-color: #0088cc; +} +.nav-stacked > li { + float: none; +} +.nav-stacked > li > a { + margin-right: 0; +} +.nav-tabs.nav-stacked { + border-bottom: 0; +} +.nav-tabs.nav-stacked > li > a { + border: 1px solid #ddd; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.nav-tabs.nav-stacked > li:first-child > a { + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} +.nav-tabs.nav-stacked > li:last-child > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} +.nav-tabs.nav-stacked > li > a:hover { + border-color: #ddd; + z-index: 2; +} +.nav-pills.nav-stacked > li > a { + margin-bottom: 3px; +} +.nav-pills.nav-stacked > li:last-child > a { + margin-bottom: 1px; +} +.nav-tabs .dropdown-menu, .nav-pills .dropdown-menu { + margin-top: 1px; + border-width: 1px; +} +.nav-pills .dropdown-menu { + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.nav-tabs .dropdown-toggle .caret, .nav-pills .dropdown-toggle .caret { + border-top-color: #0088cc; + margin-top: 6px; +} +.nav-tabs .dropdown-toggle:hover .caret, .nav-pills .dropdown-toggle:hover .caret { + border-top-color: #005580; +} +.nav-tabs .active .dropdown-toggle .caret, .nav-pills .active .dropdown-toggle .caret { + border-top-color: #333333; +} +.nav > .dropdown.active > a:hover { + color: #000000; + cursor: pointer; +} +.nav-tabs .open .dropdown-toggle, .nav-pills .open .dropdown-toggle, .nav > .open.active > a:hover { + color: #ffffff; + background-color: #999999; + border-color: #999999; +} +.nav .open .caret, .nav .open.active .caret, .nav .open a:hover .caret { + border-top-color: #ffffff; + opacity: 1; + filter: alpha(opacity=100); +} +.tabs-stacked .open > a:hover { + border-color: #999999; +} +.tabbable { + *zoom: 1; +} +.tabbable:before, .tabbable:after { + display: table; + content: ""; +} +.tabbable:after { + clear: both; +} +.tab-content { + overflow: hidden; +} +.tabs-below .nav-tabs, .tabs-right .nav-tabs, .tabs-left .nav-tabs { + border-bottom: 0; +} +.tab-content > .tab-pane, .pill-content > .pill-pane { + display: none; +} +.tab-content > .active, .pill-content > .active { + display: block; +} +.tabs-below .nav-tabs { + border-top: 1px solid #ddd; +} +.tabs-below .nav-tabs > li { + margin-top: -1px; + margin-bottom: 0; +} +.tabs-below .nav-tabs > li > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} +.tabs-below .nav-tabs > li > a:hover { + border-bottom-color: transparent; + border-top-color: #ddd; +} +.tabs-below .nav-tabs .active > a, .tabs-below .nav-tabs .active > a:hover { + border-color: transparent #ddd #ddd #ddd; +} +.tabs-left .nav-tabs > li, .tabs-right .nav-tabs > li { + float: none; +} +.tabs-left .nav-tabs > li > a, .tabs-right .nav-tabs > li > a { + min-width: 74px; + margin-right: 0; + margin-bottom: 3px; +} +.tabs-left .nav-tabs { + float: left; + margin-right: 19px; + border-right: 1px solid #ddd; +} +.tabs-left .nav-tabs > li > a { + margin-right: -1px; + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} +.tabs-left .nav-tabs > li > a:hover { + border-color: #eeeeee #dddddd #eeeeee #eeeeee; +} +.tabs-left .nav-tabs .active > a, .tabs-left .nav-tabs .active > a:hover { + border-color: #ddd transparent #ddd #ddd; + *border-right-color: #ffffff; +} +.tabs-right .nav-tabs { + float: right; + margin-left: 19px; + border-left: 1px solid #ddd; +} +.tabs-right .nav-tabs > li > a { + margin-left: -1px; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} +.tabs-right .nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #eeeeee #dddddd; +} +.tabs-right .nav-tabs .active > a, .tabs-right .nav-tabs .active > a:hover { + border-color: #ddd #ddd #ddd transparent; + *border-left-color: #ffffff; +} +.navbar { + overflow: visible; + margin-bottom: 18px; +} +.navbar-inner { + padding-left: 20px; + padding-right: 20px; + background-color: #2c2c2c; + background-image: -moz-linear-gradient(top, #333333, #222222); + background-image: -ms-linear-gradient(top, #333333, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); + background-image: -webkit-linear-gradient(top, #333333, #222222); + background-image: -o-linear-gradient(top, #333333, #222222); + background-image: linear-gradient(top, #333333, #222222); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); +} +.btn-navbar { + display: none; + float: right; + padding: 7px 10px; + margin-left: 5px; + margin-right: 5px; + background-color: #2c2c2c; + background-image: -moz-linear-gradient(top, #333333, #222222); + background-image: -ms-linear-gradient(top, #333333, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); + background-image: -webkit-linear-gradient(top, #333333, #222222); + background-image: -o-linear-gradient(top, #333333, #222222); + background-image: linear-gradient(top, #333333, #222222); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); + border-color: #222222 #222222 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); +} +.btn-navbar:hover, +.btn-navbar:active, +.btn-navbar.active, +.btn-navbar.disabled, +.btn-navbar[disabled] { + background-color: #222222; +} +.btn-navbar:active, .btn-navbar.active { + background-color: #080808 \9; +} +.btn-navbar .icon-bar { + display: block; + width: 18px; + height: 2px; + background-color: #f5f5f5; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; + -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); +} +.btn-navbar .icon-bar + .icon-bar { + margin-top: 3px; +} +.nav-collapse.collapse { + height: auto; +} +.navbar .brand:hover { + text-decoration: none; +} +.navbar .brand { + float: left; + display: block; + padding: 8px 20px 12px; + margin-left: -20px; + font-size: 20px; + font-weight: 200; + line-height: 1; + color: #ffffff; +} +.navbar .navbar-text { + margin-bottom: 0; + line-height: 40px; + color: #999999; +} +.navbar .navbar-text a:hover { + color: #ffffff; + background-color: transparent; +} +.navbar .btn, .navbar .btn-group { + margin-top: 5px; +} +.navbar .btn-group .btn { + margin-top: 0; +} +.navbar-form { + margin-bottom: 0; + *zoom: 1; +} +.navbar-form:before, .navbar-form:after { + display: table; + content: ""; +} +.navbar-form:after { + clear: both; +} +.navbar-form input, .navbar-form select { + display: inline-block; + margin-top: 5px; + margin-bottom: 0; +} +.navbar-form .radio, .navbar-form .checkbox { + margin-top: 5px; +} +.navbar-form input[type="image"], .navbar-form input[type="checkbox"], .navbar-form input[type="radio"] { + margin-top: 3px; +} +.navbar-form .input-append, .navbar-form .input-prepend { + margin-top: 6px; + white-space: nowrap; +} +.navbar-form .input-append input, .navbar-form .input-prepend input { + margin-top: 0; +} +.navbar-search { + position: relative; + float: left; + margin-top: 6px; + margin-bottom: 0; +} +.navbar-search .search-query { + padding: 4px 9px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + font-weight: normal; + line-height: 1; + color: #ffffff; + color: rgba(255, 255, 255, 0.75); + background: #666; + background: rgba(255, 255, 255, 0.3); + border: 1px solid #111; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + -webkit-transition: none; + -moz-transition: none; + -ms-transition: none; + -o-transition: none; + transition: none; +} +.navbar-search .search-query :-moz-placeholder { + color: #eeeeee; +} +.navbar-search .search-query::-webkit-input-placeholder { + color: #eeeeee; +} +.navbar-search .search-query:hover { + color: #ffffff; + background-color: #999999; + background-color: rgba(255, 255, 255, 0.5); +} +.navbar-search .search-query:focus, .navbar-search .search-query.focused { + padding: 5px 10px; + color: #333333; + text-shadow: 0 1px 0 #ffffff; + background-color: #ffffff; + border: 0; + -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + outline: 0; +} +.navbar-fixed-top { + position: fixed; + top: 0; + right: 0; + left: 0; + z-index: 1030; +} +.navbar-fixed-top .navbar-inner { + padding-left: 0; + padding-right: 0; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.navbar .nav { + position: relative; + left: 0; + display: block; + float: left; + margin: 0 10px 0 0; +} +.navbar .nav.pull-right { + float: right; +} +.navbar .nav > li { + display: block; + float: left; +} +.navbar .nav > li > a { + float: none; + padding: 10px 10px 11px; + line-height: 19px; + color: #999999; + text-decoration: none; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.navbar .nav > li > a:hover { + background-color: transparent; + color: #ffffff; + text-decoration: none; +} +.navbar .nav .active > a, .navbar .nav .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #222222; +} +.navbar .divider-vertical { + height: 40px; + width: 1px; + margin: 0 9px; + overflow: hidden; + background-color: #222222; + border-right: 1px solid #333333; +} +.navbar .nav.pull-right { + margin-left: 10px; + margin-right: 0; +} +.navbar .dropdown-menu { + margin-top: 1px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.navbar .dropdown-menu:before { + content: ''; + display: inline-block; + border-left: 7px solid transparent; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-bottom-color: rgba(0, 0, 0, 0.2); + position: absolute; + top: -7px; + left: 9px; +} +.navbar .dropdown-menu:after { + content: ''; + display: inline-block; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid #ffffff; + position: absolute; + top: -6px; + left: 10px; +} +.navbar .nav .dropdown-toggle .caret, .navbar .nav .open.dropdown .caret { + border-top-color: #ffffff; +} +.navbar .nav .active .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.navbar .nav .open > .dropdown-toggle, .navbar .nav .active > .dropdown-toggle, .navbar .nav .open.active > .dropdown-toggle { + background-color: transparent; +} +.navbar .nav .active > .dropdown-toggle:hover { + color: #ffffff; +} +.navbar .nav.pull-right .dropdown-menu { + left: auto; + right: 0; +} +.navbar .nav.pull-right .dropdown-menu:before { + left: auto; + right: 12px; +} +.navbar .nav.pull-right .dropdown-menu:after { + left: auto; + right: 13px; +} +.breadcrumb { + padding: 7px 14px; + margin: 0 0 18px; + background-color: #fbfbfb; + background-image: -moz-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -ms-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5)); + background-image: -webkit-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -o-linear-gradient(top, #ffffff, #f5f5f5); + background-image: linear-gradient(top, #ffffff, #f5f5f5); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0); + border: 1px solid #ddd; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; +} +.breadcrumb li { + display: inline-block; + text-shadow: 0 1px 0 #ffffff; +} +.breadcrumb .divider { + padding: 0 5px; + color: #999999; +} +.breadcrumb .active a { + color: #333333; +} +.pagination { + height: 36px; + margin: 18px 0; +} +.pagination ul { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; + margin-left: 0; + margin-bottom: 0; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); +} +.pagination li { + display: inline; +} +.pagination a { + float: left; + padding: 0 14px; + line-height: 34px; + text-decoration: none; + border: 1px solid #ddd; + border-left-width: 0; +} +.pagination a:hover, .pagination .active a { + background-color: #f5f5f5; +} +.pagination .active a { + color: #999999; + cursor: default; +} +.pagination .disabled a, .pagination .disabled a:hover { + color: #999999; + background-color: transparent; + cursor: default; +} +.pagination li:first-child a { + border-left-width: 1px; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.pagination li:last-child a { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.pagination-centered { + text-align: center; +} +.pagination-right { + text-align: right; +} +.pager { + margin-left: 0; + margin-bottom: 18px; + list-style: none; + text-align: center; + *zoom: 1; +} +.pager:before, .pager:after { + display: table; + content: ""; +} +.pager:after { + clear: both; +} +.pager li { + display: inline; +} +.pager a { + display: inline-block; + padding: 5px 14px; + background-color: #fff; + border: 1px solid #ddd; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} +.pager a:hover { + text-decoration: none; + background-color: #f5f5f5; +} +.pager .next a { + float: right; +} +.pager .previous a { + float: left; +} +.modal-open .dropdown-menu { + z-index: 2050; +} +.modal-open .dropdown.open { + *z-index: 2050; +} +.modal-open .popover { + z-index: 2060; +} +.modal-open .tooltip { + z-index: 2070; +} +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + background-color: #000000; +} +.modal-backdrop.fade { + opacity: 0; +} +.modal-backdrop, .modal-backdrop.fade.in { + opacity: 0.8; + filter: alpha(opacity=80); +} +.modal { + position: fixed; + top: 50%; + left: 50%; + z-index: 1050; + max-height: 500px; + overflow: auto; + width: 560px; + margin: -250px 0 0 -280px; + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + /* IE6-7 */ + + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.wide-modal { + position: fixed; + top: 5%; + left: 5%; + z-index: 1050; + max-height: 90%; + overflow: auto; + width: 90%; + /*margin: -50px 0 0 -80px;*/ + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + /* IE6-7 */ + + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.modal.fade { + -webkit-transition: opacity .3s linear, top .3s ease-out; + -moz-transition: opacity .3s linear, top .3s ease-out; + -ms-transition: opacity .3s linear, top .3s ease-out; + -o-transition: opacity .3s linear, top .3s ease-out; + transition: opacity .3s linear, top .3s ease-out; + top: -25%; +} +.modal.fade.in { + top: 50%; +} +.modal-header { + padding: 9px 15px; + border-bottom: 1px solid #eee; +} +.modal-header .close { + margin-top: 2px; +} +.modal-body { + padding: 15px; +} +.modal-body .modal-form { + margin-bottom: 0; +} +.modal-footer { + padding: 14px 15px 15px; + margin-bottom: 0; + background-color: #f5f5f5; + border-top: 1px solid #ddd; + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; + *zoom: 1; +} +.modal-footer:before, .modal-footer:after { + display: table; + content: ""; +} +.modal-footer:after { + clear: both; +} +.modal-footer .btn { + float: right; + margin-left: 5px; + margin-bottom: 0; +} +.tooltip { + position: absolute; + z-index: 1020; + display: block; + visibility: visible; + padding: 5px; + font-size: 11px; + opacity: 0; + filter: alpha(opacity=0); +} +.tooltip.in { + opacity: 0.8; + filter: alpha(opacity=80); +} +.tooltip.top { + margin-top: -2px; +} +.tooltip.right { + margin-left: 2px; +} +.tooltip.bottom { + margin-top: 2px; +} +.tooltip.left { + margin-left: -2px; +} +.tooltip.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid #000000; +} +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #000000; +} +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-bottom: 5px solid #000000; +} +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-right: 5px solid #000000; +} +.tooltip-inner { + max-width: 200px; + padding: 3px 8px; + color: #ffffff; + text-align: center; + text-decoration: none; + background-color: #000000; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; +} +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1010; + display: none; + padding: 5px; +} +.popover.top { + margin-top: -5px; +} +.popover.right { + margin-left: 5px; +} +.popover.bottom { + margin-top: 5px; +} +.popover.left { + margin-left: -5px; +} +.popover.top .arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid #000000; +} +.popover.right .arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-right: 5px solid #000000; +} +.popover.bottom .arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-bottom: 5px solid #000000; +} +.popover.left .arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #000000; +} +.popover .arrow { + position: absolute; + width: 0; + height: 0; +} +.popover-inner { + padding: 3px; + width: 280px; + overflow: hidden; + background: #000000; + background: rgba(0, 0, 0, 0.8); + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); +} +.popover-title { + padding: 9px 15px; + line-height: 1; + background-color: #f5f5f5; + border-bottom: 1px solid #eee; + -webkit-border-radius: 3px 3px 0 0; + -moz-border-radius: 3px 3px 0 0; + border-radius: 3px 3px 0 0; +} +.popover-content { + padding: 14px; + background-color: #ffffff; + -webkit-border-radius: 0 0 3px 3px; + -moz-border-radius: 0 0 3px 3px; + border-radius: 0 0 3px 3px; + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.popover-content p, .popover-content ul, .popover-content ol { + margin-bottom: 0; +} +.thumbnails { + margin-left: -20px; + list-style: none; + *zoom: 1; +} +.thumbnails:before, .thumbnails:after { + display: table; + content: ""; +} +.thumbnails:after { + clear: both; +} +.thumbnails > li { + float: left; + margin: 0 0 18px 20px; +} +.thumbnail { + display: block; + padding: 4px; + line-height: 1; + border: 1px solid #ddd; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); +} +a.thumbnail:hover { + border-color: #0088cc; + -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); +} +.thumbnail > img { + display: block; + max-width: 100%; + margin-left: auto; + margin-right: auto; +} +.thumbnail .caption { + padding: 9px; +} +.label { + padding: 2px 4px 3px; + font-size: 11.049999999999999px; + font-weight: bold; + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #999999; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.label:hover { + color: #ffffff; + text-decoration: none; +} +.label-important { + background-color: #b94a48; +} +.label-important:hover { + background-color: #953b39; +} +.label-warning { + background-color: #f89406; +} +.label-warning:hover { + background-color: #c67605; +} +.label-success { + background-color: #468847; +} +.label-success:hover { + background-color: #356635; +} +.label-info { + background-color: #3a87ad; +} +.label-info:hover { + background-color: #2d6987; +} +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +@-moz-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +@keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +.progress { + overflow: hidden; + height: 18px; + margin-bottom: 18px; + background-color: #f7f7f7; + background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -ms-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9)); + background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: linear-gradient(top, #f5f5f5, #f9f9f9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0); + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.progress .bar { + width: 0%; + height: 18px; + color: #ffffff; + font-size: 12px; + text-align: center; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #0e90d2; + background-image: -moz-linear-gradient(top, #149bdf, #0480be); + background-image: -ms-linear-gradient(top, #149bdf, #0480be); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be)); + background-image: -webkit-linear-gradient(top, #149bdf, #0480be); + background-image: -o-linear-gradient(top, #149bdf, #0480be); + background-image: linear-gradient(top, #149bdf, #0480be); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0); + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition: width 0.6s ease; + -moz-transition: width 0.6s ease; + -ms-transition: width 0.6s ease; + -o-transition: width 0.6s ease; + transition: width 0.6s ease; +} +.progress-striped .bar { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + -webkit-background-size: 40px 40px; + -moz-background-size: 40px 40px; + -o-background-size: 40px 40px; + background-size: 40px 40px; +} +.progress.active .bar { + -webkit-animation: progress-bar-stripes 2s linear infinite; + -moz-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} +.progress-danger .bar { + background-color: #dd514c; + background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -o-linear-gradient(top, #ee5f5b, #c43c35); + background-image: linear-gradient(top, #ee5f5b, #c43c35); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0); +} +.progress-danger.progress-striped .bar { + background-color: #ee5f5b; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-success .bar { + background-color: #5eb95e; + background-image: -moz-linear-gradient(top, #62c462, #57a957); + background-image: -ms-linear-gradient(top, #62c462, #57a957); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957)); + background-image: -webkit-linear-gradient(top, #62c462, #57a957); + background-image: -o-linear-gradient(top, #62c462, #57a957); + background-image: linear-gradient(top, #62c462, #57a957); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0); +} +.progress-success.progress-striped .bar { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-info .bar { + background-color: #4bb1cf; + background-image: -moz-linear-gradient(top, #5bc0de, #339bb9); + background-image: -ms-linear-gradient(top, #5bc0de, #339bb9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9)); + background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9); + background-image: -o-linear-gradient(top, #5bc0de, #339bb9); + background-image: linear-gradient(top, #5bc0de, #339bb9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0); +} +.progress-info.progress-striped .bar { + background-color: #5bc0de; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.accordion { + margin-bottom: 18px; +} +.accordion-group { + margin-bottom: 2px; + border: 1px solid #e5e5e5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.accordion-heading { + border-bottom: 0; +} +.accordion-heading .accordion-toggle { + display: block; + padding: 8px 15px; +} +.accordion-inner { + padding: 9px 15px; + border-top: 1px solid #e5e5e5; +} +.carousel { + position: relative; + margin-bottom: 18px; + line-height: 1; +} +.carousel-inner { + overflow: hidden; + width: 100%; + position: relative; +} +.carousel .item { + display: none; + position: relative; + -webkit-transition: 0.6s ease-in-out left; + -moz-transition: 0.6s ease-in-out left; + -ms-transition: 0.6s ease-in-out left; + -o-transition: 0.6s ease-in-out left; + transition: 0.6s ease-in-out left; +} +.carousel .item > img { + display: block; + line-height: 1; +} +.carousel .active, .carousel .next, .carousel .prev { + display: block; +} +.carousel .active { + left: 0; +} +.carousel .next, .carousel .prev { + position: absolute; + top: 0; + width: 100%; +} +.carousel .next { + left: 100%; +} +.carousel .prev { + left: -100%; +} +.carousel .next.left, .carousel .prev.right { + left: 0; +} +.carousel .active.left { + left: -100%; +} +.carousel .active.right { + left: 100%; +} +.carousel-control { + position: absolute; + top: 40%; + left: 15px; + width: 40px; + height: 40px; + margin-top: -20px; + font-size: 60px; + font-weight: 100; + line-height: 30px; + color: #ffffff; + text-align: center; + background: #222222; + border: 3px solid #ffffff; + -webkit-border-radius: 23px; + -moz-border-radius: 23px; + border-radius: 23px; + opacity: 0.5; + filter: alpha(opacity=50); +} +.carousel-control.right { + left: auto; + right: 15px; +} +.carousel-control:hover { + color: #ffffff; + text-decoration: none; + opacity: 0.9; + filter: alpha(opacity=90); +} +.carousel-caption { + position: absolute; + left: 0; + right: 0; + bottom: 0; + padding: 10px 15px 5px; + background: #333333; + background: rgba(0, 0, 0, 0.75); +} +.carousel-caption h4, .carousel-caption p { + color: #ffffff; +} +.hero-unit { + padding: 60px; + margin-bottom: 30px; + background-color: #f5f5f5; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} +.hero-unit h1 { + margin-bottom: 0; + font-size: 60px; + line-height: 1; + letter-spacing: -1px; +} +.hero-unit p { + font-size: 18px; + font-weight: 200; + line-height: 27px; +} +.pull-right { + float: right; +} +.pull-left { + float: left; +} +.hide { + display: none; +} +.show { + display: block; +} +.invisible { + visibility: hidden; +} diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f403193 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..73ff239 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..3b00020 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..275077f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/README b/README deleted file mode 100644 index 734abaf..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -This file was created by IntelliJ IDEA 11.1.1 for binding GitHub repository \ No newline at end of file diff --git a/Simple-jdbc-statistics.iml b/Simple-jdbc-statistics.iml new file mode 100644 index 0000000..ca90a9b --- /dev/null +++ b/Simple-jdbc-statistics.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/lib/h2-1.3.166.jar b/lib/h2-1.3.166.jar new file mode 100644 index 0000000..4985063 --- /dev/null +++ b/lib/h2-1.3.166.jar Binary files differ diff --git a/lib/servlet-api-2.5.jar b/lib/servlet-api-2.5.jar new file mode 100644 index 0000000..20b5755 --- /dev/null +++ b/lib/servlet-api-2.5.jar Binary files differ diff --git a/lib/slf4j-api-1.6.4.jar b/lib/slf4j-api-1.6.4.jar new file mode 100644 index 0000000..4d23f41 --- /dev/null +++ b/lib/slf4j-api-1.6.4.jar Binary files differ diff --git a/lib/slf4j-simple-1.6.4.jar b/lib/slf4j-simple-1.6.4.jar new file mode 100644 index 0000000..3d1b8d9 --- /dev/null +++ b/lib/slf4j-simple-1.6.4.jar Binary files differ diff --git a/lib/ssr-0.1.jar b/lib/ssr-0.1.jar new file mode 100644 index 0000000..65dfcf4 --- /dev/null +++ b/lib/ssr-0.1.jar Binary files differ diff --git a/lib/vst-0.4.jar b/lib/vst-0.4.jar new file mode 100644 index 0000000..db63792 --- /dev/null +++ b/lib/vst-0.4.jar Binary files differ diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..ac2dbe1 --- /dev/null +++ b/readme.md @@ -0,0 +1 @@ +A simple wrapper around jdbc drivers what will show current jdbc stats of the running queries on a simple web page on port 18080. \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/ConnectionLogger.java b/src/nl/astraeus/jdbc/ConnectionLogger.java new file mode 100644 index 0000000..c3e243f --- /dev/null +++ b/src/nl/astraeus/jdbc/ConnectionLogger.java @@ -0,0 +1,279 @@ +package nl.astraeus.jdbc; + +import java.sql.*; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Executor; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:12:34 PM + */ +public class ConnectionLogger implements Connection { + private Connection connection; + + private long milli; + private long nano; + private String lastSql; + + public ConnectionLogger(Connection connection) { + this.connection = connection; + this.lastSql = ""; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(QueryType.UNKNOWN, sql, m, n); + } + + public void commit() throws SQLException { + clearTime(); + + connection.commit(); + + log("commit"); + } + + public void rollback() throws SQLException { + clearTime(); + + connection.rollback(); + + log("rollback"); + } + + public void close() throws SQLException { + clearTime(); + + connection.close(); + + log("close"); + } + + public PreparedStatement prepareStatement(String sql) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, autoGeneratedKeys); + } + + public PreparedStatement prepareStatement(String sql, int columnIndexes[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnIndexes); + } + + public PreparedStatement prepareStatement(String sql, String columnNames[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnNames); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public Statement createStatement() throws SQLException { + return connection.createStatement(); + } + + public CallableStatement prepareCall(String sql) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql); + } + + public String nativeSQL(String sql) throws SQLException { + lastSql = sql; + return connection.nativeSQL(sql); + } + + public void setAutoCommit(boolean autoCommit) throws SQLException { + connection.setAutoCommit(autoCommit); + } + + public boolean getAutoCommit() throws SQLException { + return connection.getAutoCommit(); + } + + public boolean isClosed() throws SQLException { + return connection.isClosed(); + } + + public DatabaseMetaData getMetaData() throws SQLException { + return connection.getMetaData(); + } + + public void setReadOnly(boolean readOnly) throws SQLException { + connection.setReadOnly(readOnly); + } + + public boolean isReadOnly() throws SQLException { + return connection.isReadOnly(); + } + + public void setCatalog(String catalog) throws SQLException { + connection.setCatalog(catalog); + } + + public String getCatalog() throws SQLException { + return connection.getCatalog(); + } + + public void setTransactionIsolation(int level) throws SQLException { + connection.setTransactionIsolation(level); + } + + public int getTransactionIsolation() throws SQLException { + return connection.getTransactionIsolation(); + } + + public SQLWarning getWarnings() throws SQLException { + return connection.getWarnings(); + } + + public void clearWarnings() throws SQLException { + connection.clearWarnings(); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency); + } + + public Map> getTypeMap() throws SQLException { + return connection.getTypeMap(); + } + + public void setTypeMap(Map> map) throws SQLException { + connection.setTypeMap(map); + } + + public void setHoldability(int holdability) throws SQLException { + connection.setHoldability(holdability); + } + + public int getHoldability() throws SQLException { + return connection.getHoldability(); + } + + public Savepoint setSavepoint() throws SQLException { + return connection.setSavepoint(); + } + + public Savepoint setSavepoint(String name) throws SQLException { + return connection.setSavepoint(name); + } + + public void rollback(Savepoint savepoint) throws SQLException { + connection.rollback(); + } + + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + connection.releaseSavepoint(savepoint); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public Clob createClob() throws SQLException { + return connection.createClob(); + } + + public Blob createBlob() throws SQLException { + return connection.createBlob(); + } + + public NClob createNClob() throws SQLException { + return connection.createNClob(); + } + + public SQLXML createSQLXML() throws SQLException { + return connection.createSQLXML(); + } + + public boolean isValid(int timeout) throws SQLException { + return connection.isValid(timeout); + } + + public void setClientInfo(String name, String value) throws SQLClientInfoException { + connection.setClientInfo(name, value); + } + + public void setClientInfo(Properties properties) throws SQLClientInfoException { + connection.setClientInfo(properties); + } + + public String getClientInfo(String name) throws SQLException { + return connection.getClientInfo(name); + } + + public Properties getClientInfo() throws SQLException { + return connection.getClientInfo(); + } + + public Array createArrayOf(String typeName, Object[] elements) throws SQLException { + return connection.createArrayOf(typeName, elements); + } + + public Struct createStruct(String typeName, Object[] attributes) throws SQLException { + return connection.createStruct(typeName, attributes); + } + + @Override + public void setSchema(String schema) throws SQLException { + connection.setSchema(schema); + } + + @Override + public String getSchema() throws SQLException { + return connection.getSchema(); + } + + @Override + public void abort(Executor executor) throws SQLException { + connection.abort(executor); + } + + @Override + public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { + connection.setNetworkTimeout(executor, milliseconds); + } + + @Override + public int getNetworkTimeout() throws SQLException { + return connection.getNetworkTimeout(); + } + + public T unwrap(Class iface) throws SQLException { + return connection.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return connection.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/Driver.java b/src/nl/astraeus/jdbc/Driver.java new file mode 100644 index 0000000..8317172 --- /dev/null +++ b/src/nl/astraeus/jdbc/Driver.java @@ -0,0 +1,116 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.http.SimpleWebServer; +import nl.astraeus.jdbc.web.JdbcStatisticsServlet; +import nl.astraeus.jdbc.web.ResourceServlet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.*; +import java.util.Enumeration; +import java.util.Properties; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:54:37 PM + */ +public class Driver implements java.sql.Driver { + private final static Logger log = LoggerFactory.getLogger(Driver.class); + + final private static String URL_PREFIX = "jdbc:stat:"; + + private java.sql.Driver driver = null; + private String[] drivers = { + "org.postgresql.Driver", + "oracle.jdbc.driver.OracleDriver", + "com.sybase.jdbc2.jdbc.SybDriver", + "net.sourceforge.jtds.jdbc.Driver", + "com.microsoft.jdbc.sqlserver.SQLServerDriver", + "com.microsoft.sqlserver.jdbc.SQLServerDriver", + "weblogic.jdbc.sqlserver.SQLServerDriver", + "com.informix.jdbc.IfxDriver", + "org.apache.derby.jdbc.ClientDriver", + "org.apache.derby.jdbc.EmbeddedDriver", + "com.mysql.jdbc.Driver", + "org.hsqldb.jdbcDriver", + "org.h2.Driver" }; + + static { + log.debug("Loading driver class " + Driver.class.getName()); + + try { + DriverManager.registerDriver(new Driver()); + } catch (SQLException e) { + log.error("", e); + } + } + + public Driver() { + for (String dr : drivers) { + try { + Class.forName(dr); + } catch (Throwable e) { + log.debug("Can't instantiate driver: " + dr, e); + } + } + } + + private java.sql.Driver findDriver(String url) throws SQLException { + Enumeration e = DriverManager.getDrivers(); + + while (e.hasMoreElements()) { + java.sql.Driver d = (java.sql.Driver) e.nextElement(); + + if (d.acceptsURL(url)) { + return d; + } + } + + throw new SQLException("Driver not found: " + url); + } + + public Connection connect(String url, Properties info) throws SQLException { + url = url.substring(URL_PREFIX.length()); + + if (driver == null) { + driver = findDriver(url); + } + + if (driver != null) { + SimpleWebServer server = new SimpleWebServer(18080); + + server.addServlet(new JdbcStatisticsServlet(), "/"); + server.addServlet(new ResourceServlet(), "/resources/*"); + + server.start(); + } + + return new ConnectionLogger(driver.connect(url, info)); + } + + public boolean acceptsURL(String url) throws SQLException { + return (url != null && url.startsWith(URL_PREFIX)); + } + + public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { + return driver.getPropertyInfo(url, info); + } + + public int getMajorVersion() { + return driver.getMajorVersion(); + } + + public int getMinorVersion() { + return driver.getMinorVersion(); + } + + public boolean jdbcCompliant() { + return driver.jdbcCompliant(); + } + + @Override + public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException { + return driver.getParentLogger(); + } +} diff --git a/src/nl/astraeus/jdbc/JdbcLogger.java b/src/nl/astraeus/jdbc/JdbcLogger.java new file mode 100644 index 0000000..f4bc125 --- /dev/null +++ b/src/nl/astraeus/jdbc/JdbcLogger.java @@ -0,0 +1,113 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.jdbc.util.Util; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/** + * User: riennentjes + * Date: Jul 12, 2008 + * Time: 9:15:21 AM + */ +public class JdbcLogger { + private final static Logger logger = LoggerFactory.getLogger(JdbcLogger.class); + + private final static JdbcLogger instance = new JdbcLogger(); + + public static JdbcLogger get() { + return instance; + } + + public final static class LogEntry { + public QueryType type; + public String sql; + public long milli; + public long nano; + public int count; + public int hash; + + public LogEntry(int hash, QueryType type, String sql, long milli, long nano) { + this.hash = hash; + this.type = type; + this.sql = sql; + this.milli = milli; + this.nano = nano; + this.count = 1; + } + + public void addCount(long milli, long nano) { + synchronized (this) { + count++; + this.milli += milli; + this.nano += nano; + } + } + + public int getCount() { + return count; + } + + public String getMilli() { + return Util.formatNano(milli*1000000/count); + } + + public String getNano() { + return Util.formatNano(nano/count); + } + + public String getTotal() { + return Util.formatNano(nano); + } + + public String getSql() { + return sql; + } + } + + private Map queries; + + public JdbcLogger() { + queries = new ConcurrentHashMap(); + } + + public void logEntry(QueryType type, String sql, long milli, long nano) { + int hash = sql.hashCode(); + LogEntry entry = queries.get(hash); + + if (entry == null) { + entry = new LogEntry(hash, type, sql, milli, nano); + queries.put(hash, entry); + } else { + entry.addCount(milli, nano); + } + + if (queries.size() > 1000) { + List toRemove = new LinkedList(); + List values = new LinkedList(queries.values()); + + Collections.sort(values, new Comparator() { + @Override + public int compare(LogEntry o1, LogEntry o2) { + return o1.count - o2.count; + } + }); + + while (queries.size() > 900) { + queries.remove(values.remove(0).hash); + + } + } + } + + public static void log(QueryType type, String sql, long milli, long nano) { + instance.logEntry(type, sql, milli, nano); + } + + public Collection getEntries() { + return queries.values(); + } + +} diff --git a/src/nl/astraeus/jdbc/PreparedStatementLogger.java b/src/nl/astraeus/jdbc/PreparedStatementLogger.java new file mode 100644 index 0000000..98aefc7 --- /dev/null +++ b/src/nl/astraeus/jdbc/PreparedStatementLogger.java @@ -0,0 +1,577 @@ +package nl.astraeus.jdbc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.InputStream; +import java.io.Reader; +import java.math.BigDecimal; +import java.net.URL; +import java.sql.*; +import java.util.Calendar; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 7:47:57 PM + */ +public class PreparedStatementLogger implements PreparedStatement { + private final static Logger log = LoggerFactory.getLogger(PreparedStatementLogger.class); + + private PreparedStatement statement; + + private String sql; + private QueryType type; + private long milli; + private long nano; + + //private ArrayList parameters; + + public PreparedStatementLogger(PreparedStatement statement) { + this.statement = statement; + this.sql = ""; + this.type = QueryType.UNKNOWN; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(QueryType type, String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(type, sql, m, n); + } + + public PreparedStatementLogger(Connection connection, String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql); + } + + public PreparedStatementLogger(Connection connection, String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatementLogger(Connection connection, String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, autoGeneratedKeys); + } + + public PreparedStatementLogger(Connection connection, String sql, int[] columnIndexes) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnIndexes); + } + + public PreparedStatementLogger(Connection connection, String sql, String[] columnNames) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnNames); + } + + public boolean execute() throws SQLException { + clearTime(); + + boolean result = statement.execute(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery() throws SQLException { + clearTime(); + + ResultSet result = statement.executeQuery(); + + log(type, sql); + + return result; + } + + public int executeUpdate() throws SQLException { + clearTime(); + + int result = statement.executeUpdate(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + ResultSet result = statement.executeQuery(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnNames); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnNames); + + log(type, sql); + + return result; + } + + + public void setNull(int parameterIndex, int sqlType) throws SQLException { + statement.setNull(parameterIndex, sqlType); + } + + public void setBoolean(int parameterIndex, boolean x) throws SQLException { + statement.setBoolean(parameterIndex, x); + } + + public void setByte(int parameterIndex, byte x) throws SQLException { + statement.setByte(parameterIndex, x); + } + + public void setShort(int parameterIndex, short x) throws SQLException { + statement.setShort(parameterIndex, x); + } + + public void setInt(int parameterIndex, int x) throws SQLException { + statement.setInt(parameterIndex, x); + } + + public void setLong(int parameterIndex, long x) throws SQLException { + statement.setLong(parameterIndex, x); + } + + public void setFloat(int parameterIndex, float x) throws SQLException { + statement.setFloat(parameterIndex, x); + } + + public void setDouble(int parameterIndex, double x) throws SQLException { + statement.setDouble(parameterIndex, x); + } + + public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { + statement.setBigDecimal(parameterIndex, x); + } + + public void setString(int parameterIndex, String x) throws SQLException { + statement.setString(parameterIndex, x); + } + + public void setBytes(int parameterIndex, byte x[]) throws SQLException { + statement.setBytes(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x) throws SQLException { + statement.setDate(parameterIndex, x); + } + + public void setTime(int parameterIndex, Time x) throws SQLException { + statement.setTime(parameterIndex, x); + } + + public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { + statement.setTimestamp(parameterIndex, x); + } + + public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setUnicodeStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType); + } + + public void setObject(int parameterIndex, Object x) throws SQLException { + statement.setObject(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setRef(int parameterIndex, Ref x) throws SQLException { + statement.setRef(parameterIndex, x); + } + + public void setBlob(int parameterIndex, Blob x) throws SQLException { + statement.setBlob(parameterIndex, x); + } + + public void setClob(int parameterIndex, Clob x) throws SQLException { + statement.setClob(parameterIndex, x); + } + + public void setArray(int parameterIndex, Array x) throws SQLException { + statement.setArray(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { + statement.setDate(parameterIndex, x, cal); + } + + public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { + statement.setTime(parameterIndex, x, cal); + } + + public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { + statement.setTimestamp(parameterIndex, x, cal); + } + + public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException { + statement.setNull(parameterIndex, sqlType, typeName); + } + + public void setURL(int parameterIndex, URL x) throws SQLException { + statement.setURL(parameterIndex, x); + } + + public void setRowId(int parameterIndex, RowId x) throws SQLException { + statement.setRowId(parameterIndex, x); + } + + public void setNString(int parameterIndex, String value) throws SQLException { + statement.setNString(parameterIndex, value); + } + + public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException { + statement.setNCharacterStream(parameterIndex, value, length); + } + + public void setNClob(int parameterIndex, NClob value) throws SQLException { + statement.setNClob(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setClob(parameterIndex, reader, length); + } + + public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException { + statement.setBlob(parameterIndex, inputStream, length); + } + + public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setNClob(parameterIndex, reader, length); + } + + public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException { + statement.setSQLXML(parameterIndex, xmlObject); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType, scaleOrLength); + } + + public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException { + statement.setAsciiStream(parameterIndex, x); + } + + public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException { + statement.setBinaryStream(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException { + statement.setCharacterStream(parameterIndex, reader); + } + + public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException { + statement.setNCharacterStream(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader) throws SQLException { + statement.setClob(parameterIndex, reader); + } + + public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException { + statement.setBlob(parameterIndex, inputStream); + } + + public void setNClob(int parameterIndex, Reader reader) throws SQLException { + statement.setNClob(parameterIndex, reader); + } + + + public void close() throws SQLException { + sql = ""; + type = QueryType.UNKNOWN; + milli = 0; + nano = 0; + + statement.close(); + } + + public ResultSetMetaData getMetaData() throws SQLException { + return statement.getMetaData(); + } + + public void clearParameters() throws SQLException { + statement.clearParameters(); + } + + public ParameterMetaData getParameterMetaData() throws SQLException { + return statement.getParameterMetaData(); + } + + public void addBatch() throws SQLException { + statement.addBatch(); + } + + public int getMaxFieldSize() throws SQLException { + return statement.getMaxFieldSize(); + } + + public void setMaxFieldSize(int max) throws SQLException { + statement.setMaxFieldSize(max); + } + + public int getMaxRows() throws SQLException { + return statement.getMaxRows(); + } + + public void setMaxRows(int max) throws SQLException { + statement.setMaxRows(max); + } + + public void setEscapeProcessing(boolean enable) throws SQLException { + statement.setEscapeProcessing(enable); + } + + public int getQueryTimeout() throws SQLException { + return statement.getQueryTimeout(); + } + + public void setQueryTimeout(int seconds) throws SQLException { + statement.setQueryTimeout(seconds); + } + + public void cancel() throws SQLException { + statement.cancel(); + } + + public SQLWarning getWarnings() throws SQLException { + return statement.getWarnings(); + } + + public void clearWarnings() throws SQLException { + statement.clearWarnings(); + } + + public void setCursorName(String name) throws SQLException { + statement.setCursorName(name); + } + + public boolean execute(String sql) throws SQLException { + return statement.execute(sql); + } + + public ResultSet getResultSet() throws SQLException { + return statement.getResultSet(); + } + + public int getUpdateCount() throws SQLException { + return statement.getUpdateCount(); + } + + public boolean getMoreResults() throws SQLException { + return statement.getMoreResults(); + } + + public void setFetchDirection(int direction) throws SQLException { + statement.setFetchDirection(direction); + } + + public int getFetchDirection() throws SQLException { + return statement.getFetchDirection(); + } + + public void setFetchSize(int rows) throws SQLException { + statement.setFetchSize(rows); + } + + public int getFetchSize() throws SQLException { + return statement.getFetchSize(); + } + + public int getResultSetConcurrency() throws SQLException { + return statement.getResultSetConcurrency(); + } + + public int getResultSetType() throws SQLException { + return statement.getResultSetType(); + } + + public void addBatch(String sql) throws SQLException { + statement.addBatch(sql); + } + + public void clearBatch() throws SQLException { + statement.clearBatch(); + } + + public int[] executeBatch() throws SQLException { + return statement.executeBatch(); + } + + public Connection getConnection() throws SQLException { + return statement.getConnection(); + } + + public boolean getMoreResults(int current) throws SQLException { + return statement.getMoreResults(current); + } + + public ResultSet getGeneratedKeys() throws SQLException { + return statement.getGeneratedKeys(); + } + + public int getResultSetHoldability() throws SQLException { + return statement.getResultSetHoldability(); + } + + public boolean isClosed() throws SQLException { + return statement.isClosed(); + } + + public void setPoolable(boolean poolable) throws SQLException { + statement.setPoolable(poolable); + } + + public boolean isPoolable() throws SQLException { + return statement.isPoolable(); + } + + @Override + public void closeOnCompletion() throws SQLException { + statement.closeOnCompletion();; + } + + @Override + public boolean isCloseOnCompletion() throws SQLException { + return statement.isCloseOnCompletion(); + } + + public T unwrap(Class iface) throws SQLException { + return statement.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return statement.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/QueryType.java b/src/nl/astraeus/jdbc/QueryType.java new file mode 100644 index 0000000..744fbfc --- /dev/null +++ b/src/nl/astraeus/jdbc/QueryType.java @@ -0,0 +1,24 @@ +package nl.astraeus.jdbc; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:32:49 PM + */ +public enum QueryType { + PLAIN("plain"), + PREPARED("prepared"), + CALLABLE("callable"), + UNKNOWN("unknown"); + + private String description; + + QueryType(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } + +} diff --git a/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java new file mode 100644 index 0000000..07aac40 --- /dev/null +++ b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java @@ -0,0 +1,68 @@ +package nl.astraeus.jdbc.example; + +import java.sql.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 7:32 PM + */ +public class JdbcStatisticsExample { + + + public static void main(String [] args) throws Exception { + Class.forName("org.h2.Driver"); + Class.forName("nl.astraeus.jdbc.Driver"); + + new JdbcStatisticsExample(); + } + + public JdbcStatisticsExample() throws Exception { + Connection conn = DriverManager.getConnection("jdbc:stat:jdbc:h2:mem:test"); + + Statement statement = null; + + statement = conn.createStatement(); + statement.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + + boolean running = true; + int count = 1; + PreparedStatement ps = null; + + while (running) { + Thread.sleep(10); + + String TableName = "TEST"+(System.nanoTime() % 1000); + + try { + ps = conn.prepareStatement("SELECT COUNT(*) FROM "+TableName); + ResultSet rs = ps.executeQuery(); + } catch (SQLException e) { + statement = conn.createStatement(); + statement.execute("CREATE TABLE "+TableName+" (ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + } finally { + if (ps!=null) { + ps.close(); + } + } + + ps = conn.prepareStatement("INSERT INTO "+TableName+" VALUES (?, ?)"); + + ps.setInt(1, count++); + ps.setString(2, "String "+System.currentTimeMillis()); + + ps.execute(); + ps.close(); + + Thread.sleep(10); + + ps = conn.prepareStatement("SELECT * FROM "+TableName); + ResultSet rs = ps.executeQuery(); + statement.close(); + } + + conn.close(); + } +} diff --git a/src/nl/astraeus/jdbc/util/IOUtils.java b/src/nl/astraeus/jdbc/util/IOUtils.java new file mode 100644 index 0000000..ce95d9d --- /dev/null +++ b/src/nl/astraeus/jdbc/util/IOUtils.java @@ -0,0 +1,38 @@ +package nl.astraeus.jdbc.util; + +import java.io.*; + +/** + * User: rnentjes + * Date: 4/9/12 + * Time: 2:33 PM + */ +public class IOUtils { + + public static String toString(InputStream in) throws IOException { + assert in != null; + + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + StringBuilder buffer = new StringBuilder(); + + while(reader.ready()) { + buffer.append(reader.readLine()); + buffer.append("\n"); + } + + return buffer.toString(); + } finally { + in.close(); + } + } + + public static void copy(InputStream in, OutputStream out) throws IOException { + byte [] buffer = new byte[1<<16]; + int bytes; + + while((bytes = in.read(buffer)) > 0) { + out.write(buffer, 0, bytes); + } + } +} diff --git a/src/nl/astraeus/jdbc/util/Util.java b/src/nl/astraeus/jdbc/util/Util.java new file mode 100644 index 0000000..eaa853b --- /dev/null +++ b/src/nl/astraeus/jdbc/util/Util.java @@ -0,0 +1,25 @@ +package nl.astraeus.jdbc.util; + +import java.text.DecimalFormat; +import java.text.NumberFormat; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 12:28 PM + */ +public class Util { + // utility functions + public static String formatNano(long l) { + NumberFormat format = new DecimalFormat("###,##0.000000"); + + return format.format((double) l / 1000000.0); + } + + public static void printMemoryUsage() { + System.out.println("Used memory: "+((Runtime.getRuntime().totalMemory() / (1024*1024))-(Runtime.getRuntime().freeMemory() / (1024*1024)))); + System.out.println("Free memory: "+(Runtime.getRuntime().freeMemory() / (1024*1024))); + System.out.println("Total memory: "+(Runtime.getRuntime().totalMemory() / (1024*1024))); + System.out.println("Max memory: "+(Runtime.getRuntime().maxMemory() / (1024*1024))); + } +} diff --git a/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java b/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java new file mode 100644 index 0000000..a162d6f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java @@ -0,0 +1,90 @@ +package nl.astraeus.jdbc.web; + +import nl.astraeus.jdbc.util.IOUtils; +import nl.astraeus.jdbc.util.Util; +import nl.astraeus.jdbc.web.page.Menu; +import nl.astraeus.jdbc.web.page.Page; +import nl.astraeus.jdbc.web.page.QueryOverview; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import java.io.IOException; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:05 PM + */ +public class JdbcStatisticsServlet extends HttpServlet { + + private String head; + private String bottom; + + @Override + public void init() throws ServletException { + super.init(); + + try { + head = IOUtils.toString(getClass().getResourceAsStream("head.html")); + bottom = IOUtils.toString(getClass().getResourceAsStream("bottom.html")); + } catch (IOException e) { + throw new ServletException(e); + } + + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + doPost(req, resp); + } + + @Override + protected void doPost(final HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + long nano = System.nanoTime(); + + HttpSession session = req.getSession(); + boolean ajax = "true".equals(req.getParameter("ajax")); + + resp.setContentType("text/html"); + + Page page = (Page)session.getAttribute("page"); + Page menu = (Page)session.getAttribute("menu"); + + session.setMaxInactiveInterval(1800); + + if (menu == null) { + menu = new Menu(); + + session.setAttribute("menu", menu); + } + + if (page == null || "menumain".equals(req.getParameter("action"))) { + page = new QueryOverview(); + } else if ("diagnostics".equals(req.getParameter("action"))) { + //page = new Diagnostics(); + } else { + page = page .processRequest(req); + } + + menu.processRequest(req); + + session.setAttribute("page", page); + + if (!ajax) { + resp.getWriter().print(head); + } + + resp.getWriter().print(menu.render(req)); + resp.getWriter().print(page.render(req)); + + if (!ajax) { + resp.getWriter().print(bottom); + } + + System.out.println("Request ends, time="+ Util.formatNano(System.nanoTime() - nano) +", page="+page.getClass().getSimpleName()); + } + +} diff --git a/src/nl/astraeus/jdbc/web/ResourceServlet.java b/src/nl/astraeus/jdbc/web/ResourceServlet.java new file mode 100644 index 0000000..7abfe6f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/ResourceServlet.java @@ -0,0 +1,49 @@ +package nl.astraeus.jdbc.web; + +import nl.astraeus.jdbc.util.IOUtils; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.InputStream; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:05 PM + */ +public class ResourceServlet extends HttpServlet { + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String uri = req.getRequestURI(); + + uri = "nl/astraeus/jdbc/web" + uri; + InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(uri); + + if (in == null) { + resp.sendError(404, "Cannot find resource '" + uri + "'."); + } else { + try { + if (uri.endsWith("js")) { + resp.setContentType("text/javascript"); + } else if (uri.endsWith("css")) { + resp.setContentType("text/css"); + } else if (uri.endsWith("png")) { + resp.setContentType("image/png"); + } else if (uri.endsWith("jpg")) { + resp.setContentType("image/jpeg"); + } else if (uri.endsWith("gif")) { + resp.setContentType("image/gif"); + } + + IOUtils.copy(in, resp.getOutputStream()); + } finally { + in.close(); + } + } + } + +} diff --git a/src/nl/astraeus/jdbc/web/bottom.html b/src/nl/astraeus/jdbc/web/bottom.html new file mode 100644 index 0000000..1288de4 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/bottom.html @@ -0,0 +1,8 @@ + + +
+ + + + + \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/head.html b/src/nl/astraeus/jdbc/web/head.html new file mode 100644 index 0000000..0f8f6a3 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/head.html @@ -0,0 +1,96 @@ + + + + + + + Simple JDBC Statistics + + + + + + + + + + + + + + + + + + + +
+
+ +
+ diff --git a/src/nl/astraeus/jdbc/web/page/Menu.html b/src/nl/astraeus/jdbc/web/page/Menu.html new file mode 100644 index 0000000..505c7c2 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.html @@ -0,0 +1,42 @@ + diff --git a/src/nl/astraeus/jdbc/web/page/Menu.java b/src/nl/astraeus/jdbc/web/page/Menu.java new file mode 100644 index 0000000..f0a349a --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.java @@ -0,0 +1,27 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 9:07 PM + */ +public class Menu extends TemplatePage { + + @Override + public Page processRequest(HttpServletRequest request) { + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + result.put("user", request.getSession().getAttribute("user")); + + return result; + } +} diff --git a/src/nl/astraeus/jdbc/web/page/Page.java b/src/nl/astraeus/jdbc/web/page/Page.java new file mode 100644 index 0000000..9d526d6 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Page.java @@ -0,0 +1,17 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:20 PM + */ +public abstract class Page { + + public abstract Page processRequest(HttpServletRequest request); + public abstract Map defineModel(HttpServletRequest request); + public abstract String render(HttpServletRequest request); + +} diff --git a/src/nl/astraeus/jdbc/web/page/QueryOverview.html b/src/nl/astraeus/jdbc/web/page/QueryOverview.html new file mode 100644 index 0000000..64a88fb --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/QueryOverview.html @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + {foreach(queries as q)} + + + + + + + {eachend} + +
Total timeAvg. time# CallsSql
{q.total}{q.nano}{q.count}{q.sql}
diff --git a/src/nl/astraeus/jdbc/web/page/QueryOverview.java b/src/nl/astraeus/jdbc/web/page/QueryOverview.java new file mode 100644 index 0000000..02982f1 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/QueryOverview.java @@ -0,0 +1,92 @@ +package nl.astraeus.jdbc.web.page; + +import nl.astraeus.jdbc.JdbcLogger; + +import javax.servlet.http.HttpServletRequest; +import java.util.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 9:16 PM + */ +public class QueryOverview extends TemplatePage { + + boolean sortTotalCalls = true; + boolean sortAvgTime = false; + boolean sortTotalTime = false; + + @Override + public Page processRequest(HttpServletRequest request) { + if ("sortTotalCalls".equals(request.getParameter("action"))) { + sortTotalCalls = true; + sortAvgTime = false; + sortTotalTime = false; + } else if ("sortAvgTime".equals(request.getParameter("action"))) { + sortTotalCalls = false; + sortAvgTime = true; + sortTotalTime = false; + } else if ("sortTotalTime".equals(request.getParameter("action"))) { + sortTotalCalls = false; + sortAvgTime = false; + sortTotalTime = true; + } + + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + List entries = new ArrayList(JdbcLogger.get().getEntries()); + + if (sortTotalCalls) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + return o2.count - o1.count; + } + }); + } else if (sortAvgTime) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + long n1 = o1.nano / o1.count; + long n2 = o2.nano / o2.count; + + if (n2 > n1) { + return 1; + } else if (n2 < n1) { + return -1; + } else { + return 0; + } + } + }); + } else if (sortTotalTime) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + if (o2.nano > o1.nano) { + return 1; + } else if (o2.nano < o1.nano) { + return -1; + } else { + return 0; + } + } + }); + } + + result.put("queries", entries); + result.put("count", entries.size()); + + result.put("sortTotalCalls", sortTotalCalls); + result.put("sortAvgTime", sortAvgTime); + result.put("sortTotalTime", sortTotalTime); + + return result; + } + +} diff --git a/src/nl/astraeus/jdbc/web/page/TemplatePage.java b/src/nl/astraeus/jdbc/web/page/TemplatePage.java new file mode 100644 index 0000000..33e2641 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/TemplatePage.java @@ -0,0 +1,58 @@ +package nl.astraeus.jdbc.web.page; + +import nl.astraeus.template.EscapeMode; +import nl.astraeus.template.SimpleTemplate; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:20 PM + */ +public abstract class TemplatePage extends Page { + + private SimpleTemplate template; + + protected TemplatePage() { + template = getSimpleTemplate(this.getClass()); + } + + public String render(HttpServletRequest request) { + return template.render(defineModel(request)); + } + + private static Map templateCache = new HashMap(); + + public synchronized static SimpleTemplate getSimpleTemplate(Class cls) { + SimpleTemplate result = templateCache.get(cls); + + if (result == null) { + InputStream in = null; + + try { + in = cls.getResourceAsStream(cls.getSimpleName() + ".html"); + + result = SimpleTemplate.readTemplate('{','}', EscapeMode.HTML, in); + + templateCache.put(cls, result); + } catch (IOException e) { + throw new IllegalStateException(e); + } finally { + if (in != null) { + try { + in.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + + return result; + } +} diff --git a/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css b/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css new file mode 100644 index 0000000..0e0056f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css @@ -0,0 +1,581 @@ +/*! + * Bootstrap Responsive v2.0.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ +.clearfix { + *zoom: 1; +} +.clearfix:before, .clearfix:after { + display: table; + content: ""; +} +.clearfix:after { + clear: both; +} +.hidden { + display: none; + visibility: hidden; +} +@media (max-width: 480px) { + .nav-collapse { + -webkit-transform: translate3d(0, 0, 0); + } + .page-header h1 small { + display: block; + line-height: 18px; + } + input[class*="span"], + select[class*="span"], + textarea[class*="span"], + .uneditable-input { + display: block; + width: 100%; + min-height: 28px; + /* Make inputs at least the height of their button counterpart */ + + /* Makes inputs behave like true block-level elements */ + + -webkit-box-sizing: border-box; + /* Older Webkit */ + + -moz-box-sizing: border-box; + /* Older FF */ + + -ms-box-sizing: border-box; + /* IE8 */ + + box-sizing: border-box; + /* CSS3 spec*/ + + } + .input-prepend input[class*="span"], .input-append input[class*="span"] { + width: auto; + } + input[type="checkbox"], input[type="radio"] { + border: 1px solid #ccc; + } + .form-horizontal .control-group > label { + float: none; + width: auto; + padding-top: 0; + text-align: left; + } + .form-horizontal .controls { + margin-left: 0; + } + .form-horizontal .control-list { + padding-top: 0; + } + .form-horizontal .form-actions { + padding-left: 10px; + padding-right: 10px; + } + .modal { + position: absolute; + top: 10px; + left: 10px; + right: 10px; + width: auto; + margin: 0; + } + .modal.fade.in { + top: auto; + } + .modal-header .close { + padding: 10px; + margin: -10px; + } + .carousel-caption { + position: static; + } +} +@media (max-width: 767px) { + .container { + width: auto; + padding: 0 20px; + } + .row-fluid { + width: 100%; + } + .row { + margin-left: 0; + } + .row > [class*="span"], .row-fluid > [class*="span"] { + float: none; + display: block; + width: auto; + margin: 0; + } +} +@media (min-width: 768px) and (max-width: 979px) { + .row { + margin-left: -20px; + *zoom: 1; + } + .row:before, .row:after { + display: table; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + margin-left: 20px; + } + .span1 { + width: 42px; + } + .span2 { + width: 104px; + } + .span3 { + width: 166px; + } + .span4 { + width: 228px; + } + .span5 { + width: 290px; + } + .span6 { + width: 352px; + } + .span7 { + width: 414px; + } + .span8 { + width: 476px; + } + .span9 { + width: 538px; + } + .span10 { + width: 600px; + } + .span11 { + width: 662px; + } + .span12, .container { + width: 724px; + } + .offset1 { + margin-left: 82px; + } + .offset2 { + margin-left: 144px; + } + .offset3 { + margin-left: 206px; + } + .offset4 { + margin-left: 268px; + } + .offset5 { + margin-left: 330px; + } + .offset6 { + margin-left: 392px; + } + .offset7 { + margin-left: 454px; + } + .offset8 { + margin-left: 516px; + } + .offset9 { + margin-left: 578px; + } + .offset10 { + margin-left: 640px; + } + .offset11 { + margin-left: 702px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, .row-fluid:after { + display: table; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid > [class*="span"] { + float: left; + margin-left: 2.762430939%; + } + .row-fluid > [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid > .span1 { + width: 5.801104972%; + } + .row-fluid > .span2 { + width: 14.364640883%; + } + .row-fluid > .span3 { + width: 22.928176794%; + } + .row-fluid > .span4 { + width: 31.491712705%; + } + .row-fluid > .span5 { + width: 40.055248616%; + } + .row-fluid > .span6 { + width: 48.618784527%; + } + .row-fluid > .span7 { + width: 57.182320438000005%; + } + .row-fluid > .span8 { + width: 65.74585634900001%; + } + .row-fluid > .span9 { + width: 74.30939226%; + } + .row-fluid > .span10 { + width: 82.87292817100001%; + } + .row-fluid > .span11 { + width: 91.436464082%; + } + .row-fluid > .span12 { + width: 99.999999993%; + } + input.span1, textarea.span1, .uneditable-input.span1 { + width: 32px; + } + input.span2, textarea.span2, .uneditable-input.span2 { + width: 94px; + } + input.span3, textarea.span3, .uneditable-input.span3 { + width: 156px; + } + input.span4, textarea.span4, .uneditable-input.span4 { + width: 218px; + } + input.span5, textarea.span5, .uneditable-input.span5 { + width: 280px; + } + input.span6, textarea.span6, .uneditable-input.span6 { + width: 342px; + } + input.span7, textarea.span7, .uneditable-input.span7 { + width: 404px; + } + input.span8, textarea.span8, .uneditable-input.span8 { + width: 466px; + } + input.span9, textarea.span9, .uneditable-input.span9 { + width: 528px; + } + input.span10, textarea.span10, .uneditable-input.span10 { + width: 590px; + } + input.span11, textarea.span11, .uneditable-input.span11 { + width: 652px; + } + input.span12, textarea.span12, .uneditable-input.span12 { + width: 714px; + } +} +@media (max-width: 979px) { + body { + padding-top: 0; + } + .navbar-fixed-top { + position: static; + margin-bottom: 18px; + } + .navbar-fixed-top .navbar-inner { + padding: 5px; + } + .navbar .container { + width: auto; + padding: 0; + } + .navbar .brand { + padding-left: 10px; + padding-right: 10px; + margin: 0 0 0 -5px; + } + .navbar .nav-collapse { + clear: left; + } + .navbar .nav { + float: none; + margin: 0 0 9px; + } + .navbar .nav > li { + float: none; + } + .navbar .nav > li > a { + margin-bottom: 2px; + } + .navbar .nav > .divider-vertical { + display: none; + } + .navbar .nav .nav-header { + color: #999999; + text-shadow: none; + } + .navbar .nav > li > a, .navbar .dropdown-menu a { + padding: 6px 15px; + font-weight: bold; + color: #999999; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + } + .navbar .dropdown-menu li + li a { + margin-bottom: 2px; + } + .navbar .nav > li > a:hover, .navbar .dropdown-menu a:hover { + background-color: #222222; + } + .navbar .dropdown-menu { + position: static; + top: auto; + left: auto; + float: none; + display: block; + max-width: none; + margin: 0 15px; + padding: 0; + background-color: transparent; + border: none; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + } + .navbar .dropdown-menu:before, .navbar .dropdown-menu:after { + display: none; + } + .navbar .dropdown-menu .divider { + display: none; + } + .navbar-form, .navbar-search { + float: none; + padding: 9px 15px; + margin: 9px 0; + border-top: 1px solid #222222; + border-bottom: 1px solid #222222; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + } + .navbar .nav.pull-right { + float: none; + margin-left: 0; + } + .navbar-static .navbar-inner { + padding-left: 10px; + padding-right: 10px; + } + .btn-navbar { + display: block; + } + .nav-collapse { + overflow: hidden; + height: 0; + } +} +@media (min-width: 980px) { + .nav-collapse.collapse { + height: auto !important; + } +} +@media (min-width: 1200px) { + .row { + margin-left: -30px; + *zoom: 1; + } + .row:before, .row:after { + display: table; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + margin-left: 30px; + } + .span1 { + width: 70px; + } + .span2 { + width: 170px; + } + .span3 { + width: 270px; + } + .span4 { + width: 370px; + } + .span5 { + width: 470px; + } + .span6 { + width: 570px; + } + .span7 { + width: 670px; + } + .span8 { + width: 770px; + } + .span9 { + width: 870px; + } + .span10 { + width: 970px; + } + .span11 { + width: 1070px; + } + .span12, .container { + width: 1170px; + } + .offset1 { + margin-left: 130px; + } + .offset2 { + margin-left: 230px; + } + .offset3 { + margin-left: 330px; + } + .offset4 { + margin-left: 430px; + } + .offset5 { + margin-left: 530px; + } + .offset6 { + margin-left: 630px; + } + .offset7 { + margin-left: 730px; + } + .offset8 { + margin-left: 830px; + } + .offset9 { + margin-left: 930px; + } + .offset10 { + margin-left: 1030px; + } + .offset11 { + margin-left: 1130px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, .row-fluid:after { + display: table; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid > [class*="span"] { + float: left; + margin-left: 2.564102564%; + } + .row-fluid > [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid > .span1 { + width: 5.982905983%; + } + .row-fluid > .span2 { + width: 14.529914530000001%; + } + .row-fluid > .span3 { + width: 23.076923077%; + } + .row-fluid > .span4 { + width: 31.623931624%; + } + .row-fluid > .span5 { + width: 40.170940171000005%; + } + .row-fluid > .span6 { + width: 48.717948718%; + } + .row-fluid > .span7 { + width: 57.264957265%; + } + .row-fluid > .span8 { + width: 65.81196581200001%; + } + .row-fluid > .span9 { + width: 74.358974359%; + } + .row-fluid > .span10 { + width: 82.905982906%; + } + .row-fluid > .span11 { + width: 91.45299145300001%; + } + .row-fluid > .span12 { + width: 100%; + } + input.span1, textarea.span1, .uneditable-input.span1 { + width: 60px; + } + input.span2, textarea.span2, .uneditable-input.span2 { + width: 160px; + } + input.span3, textarea.span3, .uneditable-input.span3 { + width: 260px; + } + input.span4, textarea.span4, .uneditable-input.span4 { + width: 360px; + } + input.span5, textarea.span5, .uneditable-input.span5 { + width: 460px; + } + input.span6, textarea.span6, .uneditable-input.span6 { + width: 560px; + } + input.span7, textarea.span7, .uneditable-input.span7 { + width: 660px; + } + input.span8, textarea.span8, .uneditable-input.span8 { + width: 760px; + } + input.span9, textarea.span9, .uneditable-input.span9 { + width: 860px; + } + input.span10, textarea.span10, .uneditable-input.span10 { + width: 960px; + } + input.span11, textarea.span11, .uneditable-input.span11 { + width: 1060px; + } + input.span12, textarea.span12, .uneditable-input.span12 { + width: 1160px; + } + .thumbnails { + margin-left: -30px; + } + .thumbnails > li { + margin-left: 30px; + } +} diff --git a/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css b/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css new file mode 100644 index 0000000..6229c12 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css @@ -0,0 +1,3521 @@ +/*! + * Bootstrap v2.0.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +nav, +section { + display: block; +} +audio, canvas, video { + display: inline-block; + *display: inline; + *zoom: 1; +} +audio:not([controls]) { + display: none; +} +html { + font-size: 100%; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} +a:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +a:hover, a:active { + outline: 0; +} +sub, sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} +sup { + top: -0.5em; +} +sub { + bottom: -0.25em; +} +img { + max-width: 100%; + height: auto; + border: 0; + -ms-interpolation-mode: bicubic; +} +button, +input, +select, +textarea { + margin: 0; + font-size: 100%; + vertical-align: middle; +} +button, input { + *overflow: visible; + line-height: normal; +} +button::-moz-focus-inner, input::-moz-focus-inner { + padding: 0; + border: 0; +} +button, +input[type="button"], +input[type="reset"], +input[type="submit"] { + cursor: pointer; + -webkit-appearance: button; +} +input[type="search"] { + -webkit-appearance: textfield; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +input[type="search"]::-webkit-search-decoration, input[type="search"]::-webkit-search-cancel-button { + -webkit-appearance: none; +} +textarea { + overflow: auto; + vertical-align: top; +} +.clearfix { + *zoom: 1; +} +.clearfix:before, .clearfix:after { + display: table; + content: ""; +} +.clearfix:after { + clear: both; +} +body { + margin: 0; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 18px; + color: #333333; + background-color: #ffffff; +} +a { + color: #0088cc; + text-decoration: none; +} +a:hover { + color: #005580; + text-decoration: underline; +} +.row { + margin-left: -20px; + *zoom: 1; +} +.row:before, .row:after { + display: table; + content: ""; +} +.row:after { + clear: both; +} +[class*="span"] { + float: left; + margin-left: 20px; +} +.span1 { + width: 60px; +} +.span2 { + width: 140px; +} +.span3 { + width: 220px; +} +.span4 { + width: 300px; +} +.span5 { + width: 380px; +} +.span6 { + width: 460px; +} +.span7 { + width: 540px; +} +.span8 { + width: 620px; +} +.span9 { + width: 700px; +} +.span10 { + width: 780px; +} +.span11 { + width: 860px; +} +.span12, .container { + width: 940px; +} +.offset1 { + margin-left: 100px; +} +.offset2 { + margin-left: 180px; +} +.offset3 { + margin-left: 260px; +} +.offset4 { + margin-left: 340px; +} +.offset5 { + margin-left: 420px; +} +.offset6 { + margin-left: 500px; +} +.offset7 { + margin-left: 580px; +} +.offset8 { + margin-left: 660px; +} +.offset9 { + margin-left: 740px; +} +.offset10 { + margin-left: 820px; +} +.offset11 { + margin-left: 900px; +} +.row-fluid { + width: 100%; + *zoom: 1; +} +.row-fluid:before, .row-fluid:after { + display: table; + content: ""; +} +.row-fluid:after { + clear: both; +} +.row-fluid > [class*="span"] { + float: left; + margin-left: 2.127659574%; +} +.row-fluid > [class*="span"]:first-child { + margin-left: 0; +} +.row-fluid > .span1 { + width: 6.382978723%; +} +.row-fluid > .span2 { + width: 14.89361702%; +} +.row-fluid > .span3 { + width: 23.404255317%; +} +.row-fluid > .span4 { + width: 31.914893614%; +} +.row-fluid > .span5 { + width: 40.425531911%; +} +.row-fluid > .span6 { + width: 48.93617020799999%; +} +.row-fluid > .span7 { + width: 57.446808505%; +} +.row-fluid > .span8 { + width: 65.95744680199999%; +} +.row-fluid > .span9 { + width: 74.468085099%; +} +.row-fluid > .span10 { + width: 82.97872339599999%; +} +.row-fluid > .span11 { + width: 91.489361693%; +} +.row-fluid > .span12 { + width: 99.99999998999999%; +} +.container { + width: 940px; + margin-left: auto; + margin-right: auto; + *zoom: 1; +} +.container:before, .container:after { + display: table; + content: ""; +} +.container:after { + clear: both; +} +.container-fluid { + padding-left: 20px; + padding-right: 20px; + *zoom: 1; +} +.container-fluid:before, .container-fluid:after { + display: table; + content: ""; +} +.container-fluid:after { + clear: both; +} +p { + margin: 0 0 9px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 18px; +} +p small { + font-size: 11px; + color: #999999; +} +.lead { + margin-bottom: 18px; + font-size: 20px; + font-weight: 200; + line-height: 27px; +} +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 0; + font-weight: bold; + color: #333333; + text-rendering: optimizelegibility; +} +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small { + font-weight: normal; + color: #999999; +} +h1 { + font-size: 30px; + line-height: 36px; +} +h1 small { + font-size: 18px; +} +h2 { + font-size: 24px; + line-height: 36px; +} +h2 small { + font-size: 18px; +} +h3 { + line-height: 27px; + font-size: 18px; +} +h3 small { + font-size: 14px; +} +h4, h5, h6 { + line-height: 18px; +} +h4 { + font-size: 14px; +} +h4 small { + font-size: 12px; +} +h5 { + font-size: 12px; +} +h6 { + font-size: 11px; + color: #999999; + text-transform: uppercase; +} +.page-header { + padding-bottom: 17px; + margin: 18px 0; + border-bottom: 1px solid #eeeeee; +} +.page-header h1 { + line-height: 1; +} +ul, ol { + padding: 0; + margin: 0 0 9px 25px; +} +ul ul, +ul ol, +ol ol, +ol ul { + margin-bottom: 0; +} +ul { + list-style: disc; +} +ol { + list-style: decimal; +} +li { + line-height: 18px; +} +ul.unstyled, ol.unstyled { + margin-left: 0; + list-style: none; +} +dl { + margin-bottom: 18px; +} +dt, dd { + line-height: 18px; +} +dt { + font-weight: bold; +} +dd { + margin-left: 9px; +} +hr { + margin: 18px 0; + border: 0; + border-top: 1px solid #eeeeee; + border-bottom: 1px solid #ffffff; +} +strong { + font-weight: bold; +} +em { + font-style: italic; +} +.muted { + color: #999999; +} +abbr { + font-size: 90%; + text-transform: uppercase; + border-bottom: 1px dotted #ddd; + cursor: help; +} +blockquote { + padding: 0 0 0 15px; + margin: 0 0 18px; + border-left: 5px solid #eeeeee; +} +blockquote p { + margin-bottom: 0; + font-size: 16px; + font-weight: 300; + line-height: 22.5px; +} +blockquote small { + display: block; + line-height: 18px; + color: #999999; +} +blockquote small:before { + content: '\2014 \00A0'; +} +blockquote.pull-right { + float: right; + padding-left: 0; + padding-right: 15px; + border-left: 0; + border-right: 5px solid #eeeeee; +} +blockquote.pull-right p, blockquote.pull-right small { + text-align: right; +} +q:before, +q:after, +blockquote:before, +blockquote:after { + content: ""; +} +address { + display: block; + margin-bottom: 18px; + line-height: 18px; + font-style: normal; +} +small { + font-size: 100%; +} +cite { + font-style: normal; +} +code, pre { + padding: 0 3px 2px; + font-family: Menlo, Monaco, "Courier New", monospace; + font-size: 12px; + color: #333333; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +code { + padding: 3px 4px; + color: #d14; + background-color: #f7f7f9; + border: 1px solid #e1e1e8; +} +pre { + display: block; + padding: 8.5px; + margin: 0 0 9px; + font-size: 12px; + line-height: 18px; + background-color: #f5f5f5; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.15); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + white-space: pre; + white-space: pre-wrap; + word-break: break-all; + word-wrap: break-word; +} +pre.prettyprint { + margin-bottom: 18px; +} +pre code { + padding: 0; + color: inherit; + background-color: transparent; + border: 0; +} +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} +form { + margin: 0 0 18px; +} +fieldset { + padding: 0; + margin: 0; + border: 0; +} +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 27px; + font-size: 19.5px; + line-height: 36px; + color: #333333; + border: 0; + border-bottom: 1px solid #eee; +} +legend small { + font-size: 13.5px; + color: #999999; +} +label, +input, +button, +select, +textarea { + font-size: 13px; + font-weight: normal; + line-height: 18px; +} +input, +button, +select, +textarea { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; +} +label { + display: block; + margin-bottom: 5px; + color: #333333; +} +input, +textarea, +select, +.uneditable-input { + display: inline-block; + width: 210px; + height: 18px; + padding: 4px; + margin-bottom: 9px; + font-size: 13px; + line-height: 18px; + color: #555555; + border: 1px solid #ccc; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.uneditable-textarea { + width: auto; + height: auto; +} +label input, label textarea, label select { + display: block; +} +input[type="image"], input[type="checkbox"], input[type="radio"] { + width: auto; + height: auto; + padding: 0; + margin: 3px 0; + *margin-top: 0; + /* IE7 */ + + line-height: normal; + cursor: pointer; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + border: 0 \9; + /* IE9 and down */ + +} +input[type="image"] { + border: 0; +} +input[type="file"] { + width: auto; + padding: initial; + line-height: initial; + border: initial; + background-color: #ffffff; + background-color: initial; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +input[type="button"], input[type="reset"], input[type="submit"] { + width: auto; + height: auto; +} +select, input[type="file"] { + height: 28px; + /* In IE7, the height of the select element cannot be changed by height, only font-size */ + + *margin-top: 4px; + /* For IE7, add top margin to align select with labels */ + + line-height: 28px; +} +input[type="file"] { + line-height: 18px \9; +} +select { + width: 220px; + background-color: #ffffff; +} +select[multiple], select[size] { + height: auto; +} +input[type="image"] { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +textarea { + height: auto; +} +input[type="hidden"] { + display: none; +} +.radio, .checkbox { + padding-left: 18px; +} +.radio input[type="radio"], .checkbox input[type="checkbox"] { + float: left; + margin-left: -18px; +} +.controls > .radio:first-child, .controls > .checkbox:first-child { + padding-top: 5px; +} +.radio.inline, .checkbox.inline { + display: inline-block; + padding-top: 5px; + margin-bottom: 0; + vertical-align: middle; +} +.radio.inline + .radio.inline, .checkbox.inline + .checkbox.inline { + margin-left: 10px; +} +input, textarea { + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; + -moz-transition: border linear 0.2s, box-shadow linear 0.2s; + -ms-transition: border linear 0.2s, box-shadow linear 0.2s; + -o-transition: border linear 0.2s, box-shadow linear 0.2s; + transition: border linear 0.2s, box-shadow linear 0.2s; +} +input:focus, textarea:focus { + border-color: rgba(82, 168, 236, 0.8); + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + outline: 0; + outline: thin dotted \9; + /* IE6-9 */ + +} +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus, +select:focus { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.input-mini { + width: 60px; +} +.input-small { + width: 90px; +} +.input-medium { + width: 150px; +} +.input-large { + width: 210px; +} +.input-xlarge { + width: 270px; +} +.input-xxlarge { + width: 530px; +} +input[class*="span"], +select[class*="span"], +textarea[class*="span"], +.uneditable-input { + float: none; + margin-left: 0; +} +input.span1, textarea.span1, .uneditable-input.span1 { + width: 50px; +} +input.span2, textarea.span2, .uneditable-input.span2 { + width: 130px; +} +input.span3, textarea.span3, .uneditable-input.span3 { + width: 210px; +} +input.span4, textarea.span4, .uneditable-input.span4 { + width: 290px; +} +input.span5, textarea.span5, .uneditable-input.span5 { + width: 370px; +} +input.span6, textarea.span6, .uneditable-input.span6 { + width: 450px; +} +input.span7, textarea.span7, .uneditable-input.span7 { + width: 530px; +} +input.span8, textarea.span8, .uneditable-input.span8 { + width: 610px; +} +input.span9, textarea.span9, .uneditable-input.span9 { + width: 690px; +} +input.span10, textarea.span10, .uneditable-input.span10 { + width: 770px; +} +input.span11, textarea.span11, .uneditable-input.span11 { + width: 850px; +} +input.span12, textarea.span12, .uneditable-input.span12 { + width: 930px; +} +input[disabled], +select[disabled], +textarea[disabled], +input[readonly], +select[readonly], +textarea[readonly] { + background-color: #f5f5f5; + border-color: #ddd; + cursor: not-allowed; +} +.control-group.warning > label, .control-group.warning .help-block, .control-group.warning .help-inline { + color: #c09853; +} +.control-group.warning input, .control-group.warning select, .control-group.warning textarea { + color: #c09853; + border-color: #c09853; +} +.control-group.warning input:focus, .control-group.warning select:focus, .control-group.warning textarea:focus { + border-color: #a47e3c; + -webkit-box-shadow: 0 0 6px #dbc59e; + -moz-box-shadow: 0 0 6px #dbc59e; + box-shadow: 0 0 6px #dbc59e; +} +.control-group.warning .input-prepend .add-on, .control-group.warning .input-append .add-on { + color: #c09853; + background-color: #fcf8e3; + border-color: #c09853; +} +.control-group.error > label, .control-group.error .help-block, .control-group.error .help-inline { + color: #b94a48; +} +.control-group.error input, .control-group.error select, .control-group.error textarea { + color: #b94a48; + border-color: #b94a48; +} +.control-group.error input:focus, .control-group.error select:focus, .control-group.error textarea:focus { + border-color: #953b39; + -webkit-box-shadow: 0 0 6px #d59392; + -moz-box-shadow: 0 0 6px #d59392; + box-shadow: 0 0 6px #d59392; +} +.control-group.error .input-prepend .add-on, .control-group.error .input-append .add-on { + color: #b94a48; + background-color: #f2dede; + border-color: #b94a48; +} +.control-group.success > label, .control-group.success .help-block, .control-group.success .help-inline { + color: #468847; +} +.control-group.success input, .control-group.success select, .control-group.success textarea { + color: #468847; + border-color: #468847; +} +.control-group.success input:focus, .control-group.success select:focus, .control-group.success textarea:focus { + border-color: #356635; + -webkit-box-shadow: 0 0 6px #7aba7b; + -moz-box-shadow: 0 0 6px #7aba7b; + box-shadow: 0 0 6px #7aba7b; +} +.control-group.success .input-prepend .add-on, .control-group.success .input-append .add-on { + color: #468847; + background-color: #dff0d8; + border-color: #468847; +} +input:focus:required:invalid, textarea:focus:required:invalid, select:focus:required:invalid { + color: #b94a48; + border-color: #ee5f5b; +} +input:focus:required:invalid:focus, textarea:focus:required:invalid:focus, select:focus:required:invalid:focus { + border-color: #e9322d; + -webkit-box-shadow: 0 0 6px #f8b9b7; + -moz-box-shadow: 0 0 6px #f8b9b7; + box-shadow: 0 0 6px #f8b9b7; +} +.form-actions { + padding: 17px 20px 18px; + margin-top: 18px; + margin-bottom: 18px; + background-color: #f5f5f5; + border-top: 1px solid #ddd; +} +.uneditable-input { + display: block; + background-color: #ffffff; + border-color: #eee; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + cursor: not-allowed; +} +:-moz-placeholder { + color: #999999; +} +::-webkit-input-placeholder { + color: #999999; +} +.help-block { + display: block; + margin-top: 5px; + margin-bottom: 0; + color: #999999; +} +.help-inline { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; + margin-bottom: 9px; + vertical-align: middle; + padding-left: 5px; +} +.input-prepend, .input-append { + margin-bottom: 5px; + *zoom: 1; +} +.input-prepend:before, +.input-append:before, +.input-prepend:after, +.input-append:after { + display: table; + content: ""; +} +.input-prepend:after, .input-append:after { + clear: both; +} +.input-prepend input, +.input-append input, +.input-prepend .uneditable-input, +.input-append .uneditable-input { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.input-prepend input:focus, +.input-append input:focus, +.input-prepend .uneditable-input:focus, +.input-append .uneditable-input:focus { + position: relative; + z-index: 2; +} +.input-prepend .uneditable-input, .input-append .uneditable-input { + border-left-color: #ccc; +} +.input-prepend .add-on, .input-append .add-on { + float: left; + display: block; + width: auto; + min-width: 16px; + height: 18px; + margin-right: -1px; + padding: 4px 5px; + font-weight: normal; + line-height: 18px; + color: #999999; + text-align: center; + text-shadow: 0 1px 0 #ffffff; + background-color: #f5f5f5; + border: 1px solid #ccc; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.input-prepend .active, .input-append .active { + background-color: #a9dba9; + border-color: #46a546; +} +.input-prepend .add-on { + *margin-top: 1px; + /* IE6-7 */ + +} +.input-append input, .input-append .uneditable-input { + float: left; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.input-append .uneditable-input { + border-left-color: #eee; + border-right-color: #ccc; +} +.input-append .add-on { + margin-right: 0; + margin-left: -1px; + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.input-append input:first-child { + *margin-left: -160px; +} +.input-append input:first-child + .add-on { + *margin-left: -21px; +} +.search-query { + padding-left: 14px; + padding-right: 14px; + margin-bottom: 0; + -webkit-border-radius: 14px; + -moz-border-radius: 14px; + border-radius: 14px; +} +.form-search input, +.form-inline input, +.form-horizontal input, +.form-search textarea, +.form-inline textarea, +.form-horizontal textarea, +.form-search select, +.form-inline select, +.form-horizontal select, +.form-search .help-inline, +.form-inline .help-inline, +.form-horizontal .help-inline, +.form-search .uneditable-input, +.form-inline .uneditable-input, +.form-horizontal .uneditable-input { + display: inline-block; + margin-bottom: 0; +} +.form-search .hide, .form-inline .hide, .form-horizontal .hide { + display: none; +} +.form-search label, +.form-inline label, +.form-search .input-append, +.form-inline .input-append, +.form-search .input-prepend, +.form-inline .input-prepend { + display: inline-block; +} +.form-search .input-append .add-on, +.form-inline .input-prepend .add-on, +.form-search .input-append .add-on, +.form-inline .input-prepend .add-on { + vertical-align: middle; +} +.form-search .radio, +.form-inline .radio, +.form-search .checkbox, +.form-inline .checkbox { + margin-bottom: 0; + vertical-align: middle; +} +.control-group { + margin-bottom: 9px; +} +legend + .control-group { + margin-top: 18px; + -webkit-margin-top-collapse: separate; +} +.form-horizontal .control-group { + margin-bottom: 18px; + *zoom: 1; +} +.form-horizontal .control-group:before, .form-horizontal .control-group:after { + display: table; + content: ""; +} +.form-horizontal .control-group:after { + clear: both; +} +.form-horizontal .control-label { + float: left; + width: 140px; + padding-top: 5px; + text-align: right; +} +.form-horizontal .controls { + margin-left: 160px; +} +.form-horizontal .form-actions { + padding-left: 160px; +} +table { + max-width: 100%; + border-collapse: collapse; + border-spacing: 0; +} +.table { + width: 100%; + margin-bottom: 18px; +} +.table th, .table td { + padding: 8px; + line-height: 18px; + text-align: left; + vertical-align: top; + border-top: 1px solid #ddd; +} +.table th { + font-weight: bold; +} +.table thead th { + vertical-align: bottom; +} +.table thead:first-child tr th, .table thead:first-child tr td { + border-top: 0; +} +.table tbody + tbody { + border-top: 2px solid #ddd; +} +.table-condensed th, .table-condensed td { + padding: 4px 5px; +} +.table-bordered { + border: 1px solid #ddd; + border-collapse: separate; + *border-collapse: collapsed; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.table-bordered th + th, +.table-bordered td + td, +.table-bordered th + td, +.table-bordered td + th { + border-left: 1px solid #ddd; +} +.table-bordered thead:first-child tr:first-child th, .table-bordered tbody:first-child tr:first-child th, .table-bordered tbody:first-child tr:first-child td { + border-top: 0; +} +.table-bordered thead:first-child tr:first-child th:first-child, .table-bordered tbody:first-child tr:first-child td:first-child { + -webkit-border-radius: 4px 0 0 0; + -moz-border-radius: 4px 0 0 0; + border-radius: 4px 0 0 0; +} +.table-bordered thead:first-child tr:first-child th:last-child, .table-bordered tbody:first-child tr:first-child td:last-child { + -webkit-border-radius: 0 4px 0 0; + -moz-border-radius: 0 4px 0 0; + border-radius: 0 4px 0 0; +} +.table-bordered thead:last-child tr:last-child th:first-child, .table-bordered tbody:last-child tr:last-child td:first-child { + -webkit-border-radius: 0 0 0 4px; + -moz-border-radius: 0 0 0 4px; + border-radius: 0 0 0 4px; +} +.table-bordered thead:last-child tr:last-child th:last-child, .table-bordered tbody:last-child tr:last-child td:last-child { + -webkit-border-radius: 0 0 4px 0; + -moz-border-radius: 0 0 4px 0; + border-radius: 0 0 4px 0; +} +.table-striped tbody tr:nth-child(odd) td, .table-striped tbody tr:nth-child(odd) th { + background-color: #f9f9f9; +} +.table tbody tr:hover td, .table tbody tr:hover th { + background-color: #f5f5f5; +} +table .span1 { + float: none; + width: 44px; + margin-left: 0; +} +table .span2 { + float: none; + width: 124px; + margin-left: 0; +} +table .span3 { + float: none; + width: 204px; + margin-left: 0; +} +table .span4 { + float: none; + width: 284px; + margin-left: 0; +} +table .span5 { + float: none; + width: 364px; + margin-left: 0; +} +table .span6 { + float: none; + width: 444px; + margin-left: 0; +} +table .span7 { + float: none; + width: 524px; + margin-left: 0; +} +table .span8 { + float: none; + width: 604px; + margin-left: 0; +} +table .span9 { + float: none; + width: 684px; + margin-left: 0; +} +table .span10 { + float: none; + width: 764px; + margin-left: 0; +} +table .span11 { + float: none; + width: 844px; + margin-left: 0; +} +table .span12 { + float: none; + width: 924px; + margin-left: 0; +} +[class^="icon-"], [class*=" icon-"] { + display: inline-block; + width: 14px; + height: 14px; + line-height: 14px; + vertical-align: text-top; + background-image: url("../img/glyphicons-halflings.png"); + background-position: 14px 14px; + background-repeat: no-repeat; + *margin-right: .3em; +} +[class^="icon-"]:last-child, [class*=" icon-"]:last-child { + *margin-left: 0; +} +.icon-white { + background-image: url("../img/glyphicons-halflings-white.png"); +} +.icon-glass { + background-position: 0 0; +} +.icon-music { + background-position: -24px 0; +} +.icon-search { + background-position: -48px 0; +} +.icon-envelope { + background-position: -72px 0; +} +.icon-heart { + background-position: -96px 0; +} +.icon-star { + background-position: -120px 0; +} +.icon-star-empty { + background-position: -144px 0; +} +.icon-user { + background-position: -168px 0; +} +.icon-film { + background-position: -192px 0; +} +.icon-th-large { + background-position: -216px 0; +} +.icon-th { + background-position: -240px 0; +} +.icon-th-list { + background-position: -264px 0; +} +.icon-ok { + background-position: -288px 0; +} +.icon-remove { + background-position: -312px 0; +} +.icon-zoom-in { + background-position: -336px 0; +} +.icon-zoom-out { + background-position: -360px 0; +} +.icon-off { + background-position: -384px 0; +} +.icon-signal { + background-position: -408px 0; +} +.icon-cog { + background-position: -432px 0; +} +.icon-trash { + background-position: -456px 0; +} +.icon-home { + background-position: 0 -24px; +} +.icon-file { + background-position: -24px -24px; +} +.icon-time { + background-position: -48px -24px; +} +.icon-road { + background-position: -72px -24px; +} +.icon-download-alt { + background-position: -96px -24px; +} +.icon-download { + background-position: -120px -24px; +} +.icon-upload { + background-position: -144px -24px; +} +.icon-inbox { + background-position: -168px -24px; +} +.icon-play-circle { + background-position: -192px -24px; +} +.icon-repeat { + background-position: -216px -24px; +} +.icon-refresh { + background-position: -240px -24px; +} +.icon-list-alt { + background-position: -264px -24px; +} +.icon-lock { + background-position: -287px -24px; +} +.icon-flag { + background-position: -312px -24px; +} +.icon-headphones { + background-position: -336px -24px; +} +.icon-volume-off { + background-position: -360px -24px; +} +.icon-volume-down { + background-position: -384px -24px; +} +.icon-volume-up { + background-position: -408px -24px; +} +.icon-qrcode { + background-position: -432px -24px; +} +.icon-barcode { + background-position: -456px -24px; +} +.icon-tag { + background-position: 0 -48px; +} +.icon-tags { + background-position: -25px -48px; +} +.icon-book { + background-position: -48px -48px; +} +.icon-bookmark { + background-position: -72px -48px; +} +.icon-print { + background-position: -96px -48px; +} +.icon-camera { + background-position: -120px -48px; +} +.icon-font { + background-position: -144px -48px; +} +.icon-bold { + background-position: -167px -48px; +} +.icon-italic { + background-position: -192px -48px; +} +.icon-text-height { + background-position: -216px -48px; +} +.icon-text-width { + background-position: -240px -48px; +} +.icon-align-left { + background-position: -264px -48px; +} +.icon-align-center { + background-position: -288px -48px; +} +.icon-align-right { + background-position: -312px -48px; +} +.icon-align-justify { + background-position: -336px -48px; +} +.icon-list { + background-position: -360px -48px; +} +.icon-indent-left { + background-position: -384px -48px; +} +.icon-indent-right { + background-position: -408px -48px; +} +.icon-facetime-video { + background-position: -432px -48px; +} +.icon-picture { + background-position: -456px -48px; +} +.icon-pencil { + background-position: 0 -72px; +} +.icon-map-marker { + background-position: -24px -72px; +} +.icon-adjust { + background-position: -48px -72px; +} +.icon-tint { + background-position: -72px -72px; +} +.icon-edit { + background-position: -96px -72px; +} +.icon-share { + background-position: -120px -72px; +} +.icon-check { + background-position: -144px -72px; +} +.icon-move { + background-position: -168px -72px; +} +.icon-step-backward { + background-position: -192px -72px; +} +.icon-fast-backward { + background-position: -216px -72px; +} +.icon-backward { + background-position: -240px -72px; +} +.icon-play { + background-position: -264px -72px; +} +.icon-pause { + background-position: -288px -72px; +} +.icon-stop { + background-position: -312px -72px; +} +.icon-forward { + background-position: -336px -72px; +} +.icon-fast-forward { + background-position: -360px -72px; +} +.icon-step-forward { + background-position: -384px -72px; +} +.icon-eject { + background-position: -408px -72px; +} +.icon-chevron-left { + background-position: -432px -72px; +} +.icon-chevron-right { + background-position: -456px -72px; +} +.icon-plus-sign { + background-position: 0 -96px; +} +.icon-minus-sign { + background-position: -24px -96px; +} +.icon-remove-sign { + background-position: -48px -96px; +} +.icon-ok-sign { + background-position: -72px -96px; +} +.icon-question-sign { + background-position: -96px -96px; +} +.icon-info-sign { + background-position: -120px -96px; +} +.icon-screenshot { + background-position: -144px -96px; +} +.icon-remove-circle { + background-position: -168px -96px; +} +.icon-ok-circle { + background-position: -192px -96px; +} +.icon-ban-circle { + background-position: -216px -96px; +} +.icon-arrow-left { + background-position: -240px -96px; +} +.icon-arrow-right { + background-position: -264px -96px; +} +.icon-arrow-up { + background-position: -289px -96px; +} +.icon-arrow-down { + background-position: -312px -96px; +} +.icon-share-alt { + background-position: -336px -96px; +} +.icon-resize-full { + background-position: -360px -96px; +} +.icon-resize-small { + background-position: -384px -96px; +} +.icon-plus { + background-position: -408px -96px; +} +.icon-minus { + background-position: -433px -96px; +} +.icon-asterisk { + background-position: -456px -96px; +} +.icon-exclamation-sign { + background-position: 0 -120px; +} +.icon-gift { + background-position: -24px -120px; +} +.icon-leaf { + background-position: -48px -120px; +} +.icon-fire { + background-position: -72px -120px; +} +.icon-eye-open { + background-position: -96px -120px; +} +.icon-eye-close { + background-position: -120px -120px; +} +.icon-warning-sign { + background-position: -144px -120px; +} +.icon-plane { + background-position: -168px -120px; +} +.icon-calendar { + background-position: -192px -120px; +} +.icon-random { + background-position: -216px -120px; +} +.icon-comment { + background-position: -240px -120px; +} +.icon-magnet { + background-position: -264px -120px; +} +.icon-chevron-up { + background-position: -288px -120px; +} +.icon-chevron-down { + background-position: -313px -119px; +} +.icon-retweet { + background-position: -336px -120px; +} +.icon-shopping-cart { + background-position: -360px -120px; +} +.icon-folder-close { + background-position: -384px -120px; +} +.icon-folder-open { + background-position: -408px -120px; +} +.icon-resize-vertical { + background-position: -432px -119px; +} +.icon-resize-horizontal { + background-position: -456px -118px; +} +.dropdown { + position: relative; +} +.dropdown-toggle { + *margin-bottom: -3px; +} +.dropdown-toggle:active, .open .dropdown-toggle { + outline: 0; +} +.caret { + display: inline-block; + width: 0; + height: 0; + text-indent: -99999px; + *text-indent: 0; + vertical-align: top; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 4px solid #000000; + opacity: 0.3; + filter: alpha(opacity=30); + content: "\2193"; +} +.dropdown .caret { + margin-top: 8px; + margin-left: 2px; +} +.dropdown:hover .caret, .open.dropdown .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + float: left; + display: none; + min-width: 160px; + _width: 160px; + padding: 4px 0; + margin: 0; + list-style: none; + background-color: #ffffff; + border-color: #ccc; + border-color: rgba(0, 0, 0, 0.2); + border-style: solid; + border-width: 1px; + -webkit-border-radius: 0 0 5px 5px; + -moz-border-radius: 0 0 5px 5px; + border-radius: 0 0 5px 5px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; + *border-right-width: 2px; + *border-bottom-width: 2px; +} +.dropdown-menu.bottom-up { + top: auto; + bottom: 100%; + margin-bottom: 2px; +} +.dropdown-menu .divider { + height: 1px; + margin: 5px 1px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #ffffff; + *width: 100%; + *margin: -5px 0 5px; +} +.dropdown-menu a { + display: block; + padding: 3px 15px; + clear: both; + font-weight: normal; + line-height: 18px; + color: #555555; + white-space: nowrap; +} +.dropdown-menu li > a:hover, .dropdown-menu .active > a, .dropdown-menu .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #0088cc; +} +.dropdown.open { + *z-index: 1000; +} +.dropdown.open .dropdown-toggle { + color: #ffffff; + background: #ccc; + background: rgba(0, 0, 0, 0.3); +} +.dropdown.open .dropdown-menu { + display: block; +} +.typeahead { + margin-top: 2px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #f5f5f5; + border: 1px solid #eee; + border: 1px solid rgba(0, 0, 0, 0.05); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 0, 0, 0.15); +} +.fade { + -webkit-transition: opacity 0.15s linear; + -moz-transition: opacity 0.15s linear; + -ms-transition: opacity 0.15s linear; + -o-transition: opacity 0.15s linear; + transition: opacity 0.15s linear; + opacity: 0; +} +.fade.in { + opacity: 1; +} +.collapse { + -webkit-transition: height 0.35s ease; + -moz-transition: height 0.35s ease; + -ms-transition: height 0.35s ease; + -o-transition: height 0.35s ease; + transition: height 0.35s ease; + position: relative; + overflow: hidden; + height: 0; +} +.collapse.in { + height: auto; +} +.close { + float: right; + font-size: 20px; + font-weight: bold; + line-height: 18px; + color: #000000; + text-shadow: 0 1px 0 #ffffff; + opacity: 0.2; + filter: alpha(opacity=20); +} +.close:hover { + color: #000000; + text-decoration: none; + opacity: 0.4; + filter: alpha(opacity=40); + cursor: pointer; +} +.btn { + display: inline-block; + padding: 4px 10px 4px; + margin-bottom: 0; + font-size: 13px; + line-height: 18px; + color: #333333; + text-align: center; + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); + vertical-align: middle; + background-color: #f5f5f5; + background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); + background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); + background-image: linear-gradient(top, #ffffff, #e6e6e6); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0); + border-color: #e6e6e6 #e6e6e6 #bfbfbf; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + border: 1px solid #ccc; + border-bottom-color: #bbb; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + cursor: pointer; + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + *margin-left: .3em; +} +.btn:hover, +.btn:active, +.btn.active, +.btn.disabled, +.btn[disabled] { + background-color: #e6e6e6; +} +.btn:active, .btn.active { + background-color: #cccccc \9; +} +.btn:first-child { + *margin-left: 0; +} +.btn:hover { + color: #333333; + text-decoration: none; + background-color: #e6e6e6; + background-position: 0 -15px; + -webkit-transition: background-position 0.1s linear; + -moz-transition: background-position 0.1s linear; + -ms-transition: background-position 0.1s linear; + -o-transition: background-position 0.1s linear; + transition: background-position 0.1s linear; +} +.btn:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.btn.active, .btn:active { + background-image: none; + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + background-color: #e6e6e6; + background-color: #d9d9d9 \9; + outline: 0; +} +.btn.disabled, .btn[disabled] { + cursor: default; + background-image: none; + background-color: #e6e6e6; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +.btn-large { + padding: 9px 14px; + font-size: 15px; + line-height: normal; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.btn-large [class^="icon-"] { + margin-top: 1px; +} +.btn-small { + padding: 5px 9px; + font-size: 11px; + line-height: 16px; +} +.btn-small [class^="icon-"] { + margin-top: -1px; +} +.btn-mini { + padding: 2px 6px; + font-size: 11px; + line-height: 14px; +} +.btn-primary, +.btn-primary:hover, +.btn-warning, +.btn-warning:hover, +.btn-danger, +.btn-danger:hover, +.btn-success, +.btn-success:hover, +.btn-info, +.btn-info:hover, +.btn-inverse, +.btn-inverse:hover { + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + color: #ffffff; +} +.btn-primary.active, +.btn-warning.active, +.btn-danger.active, +.btn-success.active, +.btn-info.active, +.btn-dark.active { + color: rgba(255, 255, 255, 0.75); +} +.btn-primary { + background-color: #006dcc; + background-image: -moz-linear-gradient(top, #0088cc, #0044cc); + background-image: -ms-linear-gradient(top, #0088cc, #0044cc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); + background-image: -o-linear-gradient(top, #0088cc, #0044cc); + background-image: linear-gradient(top, #0088cc, #0044cc); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); + border-color: #0044cc #0044cc #002a80; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-primary:hover, +.btn-primary:active, +.btn-primary.active, +.btn-primary.disabled, +.btn-primary[disabled] { + background-color: #0044cc; +} +.btn-primary:active, .btn-primary.active { + background-color: #003399 \9; +} +.btn-warning { + background-color: #faa732; + background-image: -moz-linear-gradient(top, #fbb450, #f89406); + background-image: -ms-linear-gradient(top, #fbb450, #f89406); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); + background-image: -webkit-linear-gradient(top, #fbb450, #f89406); + background-image: -o-linear-gradient(top, #fbb450, #f89406); + background-image: linear-gradient(top, #fbb450, #f89406); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0); + border-color: #f89406 #f89406 #ad6704; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-warning:hover, +.btn-warning:active, +.btn-warning.active, +.btn-warning.disabled, +.btn-warning[disabled] { + background-color: #f89406; +} +.btn-warning:active, .btn-warning.active { + background-color: #c67605 \9; +} +.btn-danger { + background-color: #da4f49; + background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -ms-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -o-linear-gradient(top, #ee5f5b, #bd362f); + background-image: linear-gradient(top, #ee5f5b, #bd362f); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0); + border-color: #bd362f #bd362f #802420; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-danger:hover, +.btn-danger:active, +.btn-danger.active, +.btn-danger.disabled, +.btn-danger[disabled] { + background-color: #bd362f; +} +.btn-danger:active, .btn-danger.active { + background-color: #942a25 \9; +} +.btn-success { + background-color: #5bb75b; + background-image: -moz-linear-gradient(top, #62c462, #51a351); + background-image: -ms-linear-gradient(top, #62c462, #51a351); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351)); + background-image: -webkit-linear-gradient(top, #62c462, #51a351); + background-image: -o-linear-gradient(top, #62c462, #51a351); + background-image: linear-gradient(top, #62c462, #51a351); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0); + border-color: #51a351 #51a351 #387038; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-success:hover, +.btn-success:active, +.btn-success.active, +.btn-success.disabled, +.btn-success[disabled] { + background-color: #51a351; +} +.btn-success:active, .btn-success.active { + background-color: #408140 \9; +} +.btn-info { + background-color: #49afcd; + background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -ms-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4)); + background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -o-linear-gradient(top, #5bc0de, #2f96b4); + background-image: linear-gradient(top, #5bc0de, #2f96b4); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0); + border-color: #2f96b4 #2f96b4 #1f6377; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-info:hover, +.btn-info:active, +.btn-info.active, +.btn-info.disabled, +.btn-info[disabled] { + background-color: #2f96b4; +} +.btn-info:active, .btn-info.active { + background-color: #24748c \9; +} +.btn-inverse { + background-color: #393939; + background-image: -moz-linear-gradient(top, #454545, #262626); + background-image: -ms-linear-gradient(top, #454545, #262626); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#454545), to(#262626)); + background-image: -webkit-linear-gradient(top, #454545, #262626); + background-image: -o-linear-gradient(top, #454545, #262626); + background-image: linear-gradient(top, #454545, #262626); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#454545', endColorstr='#262626', GradientType=0); + border-color: #262626 #262626 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-inverse:hover, +.btn-inverse:active, +.btn-inverse.active, +.btn-inverse.disabled, +.btn-inverse[disabled] { + background-color: #262626; +} +.btn-inverse:active, .btn-inverse.active { + background-color: #0c0c0c \9; +} +button.btn, input[type="submit"].btn { + *padding-top: 2px; + *padding-bottom: 2px; +} +button.btn::-moz-focus-inner, input[type="submit"].btn::-moz-focus-inner { + padding: 0; + border: 0; +} +button.btn.large, input[type="submit"].btn.large { + *padding-top: 7px; + *padding-bottom: 7px; +} +button.btn.small, input[type="submit"].btn.small { + *padding-top: 3px; + *padding-bottom: 3px; +} +.btn-group { + position: relative; + *zoom: 1; + *margin-left: .3em; +} +.btn-group:before, .btn-group:after { + display: table; + content: ""; +} +.btn-group:after { + clear: both; +} +.btn-group:first-child { + *margin-left: 0; +} +.btn-group + .btn-group { + margin-left: 5px; +} +.btn-toolbar { + margin-top: 9px; + margin-bottom: 9px; +} +.btn-toolbar .btn-group { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; +} +.btn-group .btn { + position: relative; + float: left; + margin-left: -1px; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.btn-group .btn:first-child { + margin-left: 0; + -webkit-border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; + border-top-left-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + border-bottom-left-radius: 4px; +} +.btn-group .btn:last-child, .btn-group .dropdown-toggle { + -webkit-border-top-right-radius: 4px; + -moz-border-radius-topright: 4px; + border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -moz-border-radius-bottomright: 4px; + border-bottom-right-radius: 4px; +} +.btn-group .btn.large:first-child { + margin-left: 0; + -webkit-border-top-left-radius: 6px; + -moz-border-radius-topleft: 6px; + border-top-left-radius: 6px; + -webkit-border-bottom-left-radius: 6px; + -moz-border-radius-bottomleft: 6px; + border-bottom-left-radius: 6px; +} +.btn-group .btn.large:last-child, .btn-group .large.dropdown-toggle { + -webkit-border-top-right-radius: 6px; + -moz-border-radius-topright: 6px; + border-top-right-radius: 6px; + -webkit-border-bottom-right-radius: 6px; + -moz-border-radius-bottomright: 6px; + border-bottom-right-radius: 6px; +} +.btn-group .btn:hover, +.btn-group .btn:focus, +.btn-group .btn:active, +.btn-group .btn.active { + z-index: 2; +} +.btn-group .dropdown-toggle:active, .btn-group.open .dropdown-toggle { + outline: 0; +} +.btn-group .dropdown-toggle { + padding-left: 8px; + padding-right: 8px; + -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + *padding-top: 5px; + *padding-bottom: 5px; +} +.btn-group.open { + *z-index: 1000; +} +.btn-group.open .dropdown-menu { + display: block; + margin-top: 1px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.btn-group.open .dropdown-toggle { + background-image: none; + -webkit-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); +} +.btn .caret { + margin-top: 7px; + margin-left: 0; +} +.btn:hover .caret, .open.btn-group .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.btn-primary .caret, +.btn-danger .caret, +.btn-info .caret, +.btn-success .caret, +.btn-inverse .caret { + border-top-color: #ffffff; + opacity: 0.75; + filter: alpha(opacity=75); +} +.btn-small .caret { + margin-top: 4px; +} +.alert { + padding: 8px 35px 8px 14px; + margin-bottom: 18px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + background-color: #fcf8e3; + border: 1px solid #fbeed5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.alert, .alert-heading { + color: #c09853; +} +.alert .close { + position: relative; + top: -2px; + right: -21px; + line-height: 18px; +} +.alert-success { + background-color: #dff0d8; + border-color: #d6e9c6; +} +.alert-success, .alert-success .alert-heading { + color: #468847; +} +.alert-danger, .alert-error { + background-color: #f2dede; + border-color: #eed3d7; +} +.alert-danger, +.alert-error, +.alert-danger .alert-heading, +.alert-error .alert-heading { + color: #b94a48; +} +.alert-info { + background-color: #d9edf7; + border-color: #bce8f1; +} +.alert-info, .alert-info .alert-heading { + color: #3a87ad; +} +.alert-block { + padding-top: 14px; + padding-bottom: 14px; +} +.alert-block > p, .alert-block > ul { + margin-bottom: 0; +} +.alert-block p + p { + margin-top: 5px; +} +.nav { + margin-left: 0; + margin-bottom: 18px; + list-style: none; +} +.nav > li > a { + display: block; +} +.nav > li > a:hover { + text-decoration: none; + background-color: #eeeeee; +} +.nav .nav-header { + display: block; + padding: 3px 15px; + font-size: 11px; + font-weight: bold; + line-height: 18px; + color: #999999; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + text-transform: uppercase; +} +.nav li + .nav-header { + margin-top: 9px; +} +.nav-list { + padding-left: 14px; + padding-right: 14px; + margin-bottom: 0; +} +.nav-list > li > a, .nav-list .nav-header { + margin-left: -15px; + margin-right: -15px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); +} +.nav-list > li > a { + padding: 3px 15px; +} +.nav-list .active > a, .nav-list .active > a:hover { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); + background-color: #0088cc; +} +.nav-list [class^="icon-"] { + margin-right: 2px; +} +.nav-tabs, .nav-pills { + *zoom: 1; +} +.nav-tabs:before, +.nav-pills:before, +.nav-tabs:after, +.nav-pills:after { + display: table; + content: ""; +} +.nav-tabs:after, .nav-pills:after { + clear: both; +} +.nav-tabs > li, .nav-pills > li { + float: left; +} +.nav-tabs > li > a, .nav-pills > li > a { + padding-right: 12px; + padding-left: 12px; + margin-right: 2px; + line-height: 14px; +} +.nav-tabs { + border-bottom: 1px solid #ddd; +} +.nav-tabs > li { + margin-bottom: -1px; +} +.nav-tabs > li > a { + padding-top: 9px; + padding-bottom: 9px; + border: 1px solid transparent; + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} +.nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #dddddd; +} +.nav-tabs > .active > a, .nav-tabs > .active > a:hover { + color: #555555; + background-color: #ffffff; + border: 1px solid #ddd; + border-bottom-color: transparent; + cursor: default; +} +.nav-pills > li > a { + padding-top: 8px; + padding-bottom: 8px; + margin-top: 2px; + margin-bottom: 2px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.nav-pills .active > a, .nav-pills .active > a:hover { + color: #ffffff; + background-color: #0088cc; +} +.nav-stacked > li { + float: none; +} +.nav-stacked > li > a { + margin-right: 0; +} +.nav-tabs.nav-stacked { + border-bottom: 0; +} +.nav-tabs.nav-stacked > li > a { + border: 1px solid #ddd; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.nav-tabs.nav-stacked > li:first-child > a { + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} +.nav-tabs.nav-stacked > li:last-child > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} +.nav-tabs.nav-stacked > li > a:hover { + border-color: #ddd; + z-index: 2; +} +.nav-pills.nav-stacked > li > a { + margin-bottom: 3px; +} +.nav-pills.nav-stacked > li:last-child > a { + margin-bottom: 1px; +} +.nav-tabs .dropdown-menu, .nav-pills .dropdown-menu { + margin-top: 1px; + border-width: 1px; +} +.nav-pills .dropdown-menu { + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.nav-tabs .dropdown-toggle .caret, .nav-pills .dropdown-toggle .caret { + border-top-color: #0088cc; + margin-top: 6px; +} +.nav-tabs .dropdown-toggle:hover .caret, .nav-pills .dropdown-toggle:hover .caret { + border-top-color: #005580; +} +.nav-tabs .active .dropdown-toggle .caret, .nav-pills .active .dropdown-toggle .caret { + border-top-color: #333333; +} +.nav > .dropdown.active > a:hover { + color: #000000; + cursor: pointer; +} +.nav-tabs .open .dropdown-toggle, .nav-pills .open .dropdown-toggle, .nav > .open.active > a:hover { + color: #ffffff; + background-color: #999999; + border-color: #999999; +} +.nav .open .caret, .nav .open.active .caret, .nav .open a:hover .caret { + border-top-color: #ffffff; + opacity: 1; + filter: alpha(opacity=100); +} +.tabs-stacked .open > a:hover { + border-color: #999999; +} +.tabbable { + *zoom: 1; +} +.tabbable:before, .tabbable:after { + display: table; + content: ""; +} +.tabbable:after { + clear: both; +} +.tab-content { + overflow: hidden; +} +.tabs-below .nav-tabs, .tabs-right .nav-tabs, .tabs-left .nav-tabs { + border-bottom: 0; +} +.tab-content > .tab-pane, .pill-content > .pill-pane { + display: none; +} +.tab-content > .active, .pill-content > .active { + display: block; +} +.tabs-below .nav-tabs { + border-top: 1px solid #ddd; +} +.tabs-below .nav-tabs > li { + margin-top: -1px; + margin-bottom: 0; +} +.tabs-below .nav-tabs > li > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} +.tabs-below .nav-tabs > li > a:hover { + border-bottom-color: transparent; + border-top-color: #ddd; +} +.tabs-below .nav-tabs .active > a, .tabs-below .nav-tabs .active > a:hover { + border-color: transparent #ddd #ddd #ddd; +} +.tabs-left .nav-tabs > li, .tabs-right .nav-tabs > li { + float: none; +} +.tabs-left .nav-tabs > li > a, .tabs-right .nav-tabs > li > a { + min-width: 74px; + margin-right: 0; + margin-bottom: 3px; +} +.tabs-left .nav-tabs { + float: left; + margin-right: 19px; + border-right: 1px solid #ddd; +} +.tabs-left .nav-tabs > li > a { + margin-right: -1px; + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} +.tabs-left .nav-tabs > li > a:hover { + border-color: #eeeeee #dddddd #eeeeee #eeeeee; +} +.tabs-left .nav-tabs .active > a, .tabs-left .nav-tabs .active > a:hover { + border-color: #ddd transparent #ddd #ddd; + *border-right-color: #ffffff; +} +.tabs-right .nav-tabs { + float: right; + margin-left: 19px; + border-left: 1px solid #ddd; +} +.tabs-right .nav-tabs > li > a { + margin-left: -1px; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} +.tabs-right .nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #eeeeee #dddddd; +} +.tabs-right .nav-tabs .active > a, .tabs-right .nav-tabs .active > a:hover { + border-color: #ddd #ddd #ddd transparent; + *border-left-color: #ffffff; +} +.navbar { + overflow: visible; + margin-bottom: 18px; +} +.navbar-inner { + padding-left: 20px; + padding-right: 20px; + background-color: #2c2c2c; + background-image: -moz-linear-gradient(top, #333333, #222222); + background-image: -ms-linear-gradient(top, #333333, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); + background-image: -webkit-linear-gradient(top, #333333, #222222); + background-image: -o-linear-gradient(top, #333333, #222222); + background-image: linear-gradient(top, #333333, #222222); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); +} +.btn-navbar { + display: none; + float: right; + padding: 7px 10px; + margin-left: 5px; + margin-right: 5px; + background-color: #2c2c2c; + background-image: -moz-linear-gradient(top, #333333, #222222); + background-image: -ms-linear-gradient(top, #333333, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); + background-image: -webkit-linear-gradient(top, #333333, #222222); + background-image: -o-linear-gradient(top, #333333, #222222); + background-image: linear-gradient(top, #333333, #222222); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); + border-color: #222222 #222222 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); +} +.btn-navbar:hover, +.btn-navbar:active, +.btn-navbar.active, +.btn-navbar.disabled, +.btn-navbar[disabled] { + background-color: #222222; +} +.btn-navbar:active, .btn-navbar.active { + background-color: #080808 \9; +} +.btn-navbar .icon-bar { + display: block; + width: 18px; + height: 2px; + background-color: #f5f5f5; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; + -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); +} +.btn-navbar .icon-bar + .icon-bar { + margin-top: 3px; +} +.nav-collapse.collapse { + height: auto; +} +.navbar .brand:hover { + text-decoration: none; +} +.navbar .brand { + float: left; + display: block; + padding: 8px 20px 12px; + margin-left: -20px; + font-size: 20px; + font-weight: 200; + line-height: 1; + color: #ffffff; +} +.navbar .navbar-text { + margin-bottom: 0; + line-height: 40px; + color: #999999; +} +.navbar .navbar-text a:hover { + color: #ffffff; + background-color: transparent; +} +.navbar .btn, .navbar .btn-group { + margin-top: 5px; +} +.navbar .btn-group .btn { + margin-top: 0; +} +.navbar-form { + margin-bottom: 0; + *zoom: 1; +} +.navbar-form:before, .navbar-form:after { + display: table; + content: ""; +} +.navbar-form:after { + clear: both; +} +.navbar-form input, .navbar-form select { + display: inline-block; + margin-top: 5px; + margin-bottom: 0; +} +.navbar-form .radio, .navbar-form .checkbox { + margin-top: 5px; +} +.navbar-form input[type="image"], .navbar-form input[type="checkbox"], .navbar-form input[type="radio"] { + margin-top: 3px; +} +.navbar-form .input-append, .navbar-form .input-prepend { + margin-top: 6px; + white-space: nowrap; +} +.navbar-form .input-append input, .navbar-form .input-prepend input { + margin-top: 0; +} +.navbar-search { + position: relative; + float: left; + margin-top: 6px; + margin-bottom: 0; +} +.navbar-search .search-query { + padding: 4px 9px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + font-weight: normal; + line-height: 1; + color: #ffffff; + color: rgba(255, 255, 255, 0.75); + background: #666; + background: rgba(255, 255, 255, 0.3); + border: 1px solid #111; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + -webkit-transition: none; + -moz-transition: none; + -ms-transition: none; + -o-transition: none; + transition: none; +} +.navbar-search .search-query :-moz-placeholder { + color: #eeeeee; +} +.navbar-search .search-query::-webkit-input-placeholder { + color: #eeeeee; +} +.navbar-search .search-query:hover { + color: #ffffff; + background-color: #999999; + background-color: rgba(255, 255, 255, 0.5); +} +.navbar-search .search-query:focus, .navbar-search .search-query.focused { + padding: 5px 10px; + color: #333333; + text-shadow: 0 1px 0 #ffffff; + background-color: #ffffff; + border: 0; + -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + outline: 0; +} +.navbar-fixed-top { + position: fixed; + top: 0; + right: 0; + left: 0; + z-index: 1030; +} +.navbar-fixed-top .navbar-inner { + padding-left: 0; + padding-right: 0; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.navbar .nav { + position: relative; + left: 0; + display: block; + float: left; + margin: 0 10px 0 0; +} +.navbar .nav.pull-right { + float: right; +} +.navbar .nav > li { + display: block; + float: left; +} +.navbar .nav > li > a { + float: none; + padding: 10px 10px 11px; + line-height: 19px; + color: #999999; + text-decoration: none; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.navbar .nav > li > a:hover { + background-color: transparent; + color: #ffffff; + text-decoration: none; +} +.navbar .nav .active > a, .navbar .nav .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #222222; +} +.navbar .divider-vertical { + height: 40px; + width: 1px; + margin: 0 9px; + overflow: hidden; + background-color: #222222; + border-right: 1px solid #333333; +} +.navbar .nav.pull-right { + margin-left: 10px; + margin-right: 0; +} +.navbar .dropdown-menu { + margin-top: 1px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.navbar .dropdown-menu:before { + content: ''; + display: inline-block; + border-left: 7px solid transparent; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-bottom-color: rgba(0, 0, 0, 0.2); + position: absolute; + top: -7px; + left: 9px; +} +.navbar .dropdown-menu:after { + content: ''; + display: inline-block; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid #ffffff; + position: absolute; + top: -6px; + left: 10px; +} +.navbar .nav .dropdown-toggle .caret, .navbar .nav .open.dropdown .caret { + border-top-color: #ffffff; +} +.navbar .nav .active .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.navbar .nav .open > .dropdown-toggle, .navbar .nav .active > .dropdown-toggle, .navbar .nav .open.active > .dropdown-toggle { + background-color: transparent; +} +.navbar .nav .active > .dropdown-toggle:hover { + color: #ffffff; +} +.navbar .nav.pull-right .dropdown-menu { + left: auto; + right: 0; +} +.navbar .nav.pull-right .dropdown-menu:before { + left: auto; + right: 12px; +} +.navbar .nav.pull-right .dropdown-menu:after { + left: auto; + right: 13px; +} +.breadcrumb { + padding: 7px 14px; + margin: 0 0 18px; + background-color: #fbfbfb; + background-image: -moz-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -ms-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5)); + background-image: -webkit-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -o-linear-gradient(top, #ffffff, #f5f5f5); + background-image: linear-gradient(top, #ffffff, #f5f5f5); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0); + border: 1px solid #ddd; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; +} +.breadcrumb li { + display: inline-block; + text-shadow: 0 1px 0 #ffffff; +} +.breadcrumb .divider { + padding: 0 5px; + color: #999999; +} +.breadcrumb .active a { + color: #333333; +} +.pagination { + height: 36px; + margin: 18px 0; +} +.pagination ul { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; + margin-left: 0; + margin-bottom: 0; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); +} +.pagination li { + display: inline; +} +.pagination a { + float: left; + padding: 0 14px; + line-height: 34px; + text-decoration: none; + border: 1px solid #ddd; + border-left-width: 0; +} +.pagination a:hover, .pagination .active a { + background-color: #f5f5f5; +} +.pagination .active a { + color: #999999; + cursor: default; +} +.pagination .disabled a, .pagination .disabled a:hover { + color: #999999; + background-color: transparent; + cursor: default; +} +.pagination li:first-child a { + border-left-width: 1px; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.pagination li:last-child a { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.pagination-centered { + text-align: center; +} +.pagination-right { + text-align: right; +} +.pager { + margin-left: 0; + margin-bottom: 18px; + list-style: none; + text-align: center; + *zoom: 1; +} +.pager:before, .pager:after { + display: table; + content: ""; +} +.pager:after { + clear: both; +} +.pager li { + display: inline; +} +.pager a { + display: inline-block; + padding: 5px 14px; + background-color: #fff; + border: 1px solid #ddd; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} +.pager a:hover { + text-decoration: none; + background-color: #f5f5f5; +} +.pager .next a { + float: right; +} +.pager .previous a { + float: left; +} +.modal-open .dropdown-menu { + z-index: 2050; +} +.modal-open .dropdown.open { + *z-index: 2050; +} +.modal-open .popover { + z-index: 2060; +} +.modal-open .tooltip { + z-index: 2070; +} +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + background-color: #000000; +} +.modal-backdrop.fade { + opacity: 0; +} +.modal-backdrop, .modal-backdrop.fade.in { + opacity: 0.8; + filter: alpha(opacity=80); +} +.modal { + position: fixed; + top: 50%; + left: 50%; + z-index: 1050; + max-height: 500px; + overflow: auto; + width: 560px; + margin: -250px 0 0 -280px; + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + /* IE6-7 */ + + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.wide-modal { + position: fixed; + top: 5%; + left: 5%; + z-index: 1050; + max-height: 90%; + overflow: auto; + width: 90%; + /*margin: -50px 0 0 -80px;*/ + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + /* IE6-7 */ + + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.modal.fade { + -webkit-transition: opacity .3s linear, top .3s ease-out; + -moz-transition: opacity .3s linear, top .3s ease-out; + -ms-transition: opacity .3s linear, top .3s ease-out; + -o-transition: opacity .3s linear, top .3s ease-out; + transition: opacity .3s linear, top .3s ease-out; + top: -25%; +} +.modal.fade.in { + top: 50%; +} +.modal-header { + padding: 9px 15px; + border-bottom: 1px solid #eee; +} +.modal-header .close { + margin-top: 2px; +} +.modal-body { + padding: 15px; +} +.modal-body .modal-form { + margin-bottom: 0; +} +.modal-footer { + padding: 14px 15px 15px; + margin-bottom: 0; + background-color: #f5f5f5; + border-top: 1px solid #ddd; + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; + *zoom: 1; +} +.modal-footer:before, .modal-footer:after { + display: table; + content: ""; +} +.modal-footer:after { + clear: both; +} +.modal-footer .btn { + float: right; + margin-left: 5px; + margin-bottom: 0; +} +.tooltip { + position: absolute; + z-index: 1020; + display: block; + visibility: visible; + padding: 5px; + font-size: 11px; + opacity: 0; + filter: alpha(opacity=0); +} +.tooltip.in { + opacity: 0.8; + filter: alpha(opacity=80); +} +.tooltip.top { + margin-top: -2px; +} +.tooltip.right { + margin-left: 2px; +} +.tooltip.bottom { + margin-top: 2px; +} +.tooltip.left { + margin-left: -2px; +} +.tooltip.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid #000000; +} +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #000000; +} +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-bottom: 5px solid #000000; +} +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-right: 5px solid #000000; +} +.tooltip-inner { + max-width: 200px; + padding: 3px 8px; + color: #ffffff; + text-align: center; + text-decoration: none; + background-color: #000000; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; +} +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1010; + display: none; + padding: 5px; +} +.popover.top { + margin-top: -5px; +} +.popover.right { + margin-left: 5px; +} +.popover.bottom { + margin-top: 5px; +} +.popover.left { + margin-left: -5px; +} +.popover.top .arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid #000000; +} +.popover.right .arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-right: 5px solid #000000; +} +.popover.bottom .arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-bottom: 5px solid #000000; +} +.popover.left .arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #000000; +} +.popover .arrow { + position: absolute; + width: 0; + height: 0; +} +.popover-inner { + padding: 3px; + width: 280px; + overflow: hidden; + background: #000000; + background: rgba(0, 0, 0, 0.8); + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); +} +.popover-title { + padding: 9px 15px; + line-height: 1; + background-color: #f5f5f5; + border-bottom: 1px solid #eee; + -webkit-border-radius: 3px 3px 0 0; + -moz-border-radius: 3px 3px 0 0; + border-radius: 3px 3px 0 0; +} +.popover-content { + padding: 14px; + background-color: #ffffff; + -webkit-border-radius: 0 0 3px 3px; + -moz-border-radius: 0 0 3px 3px; + border-radius: 0 0 3px 3px; + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.popover-content p, .popover-content ul, .popover-content ol { + margin-bottom: 0; +} +.thumbnails { + margin-left: -20px; + list-style: none; + *zoom: 1; +} +.thumbnails:before, .thumbnails:after { + display: table; + content: ""; +} +.thumbnails:after { + clear: both; +} +.thumbnails > li { + float: left; + margin: 0 0 18px 20px; +} +.thumbnail { + display: block; + padding: 4px; + line-height: 1; + border: 1px solid #ddd; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); +} +a.thumbnail:hover { + border-color: #0088cc; + -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); +} +.thumbnail > img { + display: block; + max-width: 100%; + margin-left: auto; + margin-right: auto; +} +.thumbnail .caption { + padding: 9px; +} +.label { + padding: 2px 4px 3px; + font-size: 11.049999999999999px; + font-weight: bold; + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #999999; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.label:hover { + color: #ffffff; + text-decoration: none; +} +.label-important { + background-color: #b94a48; +} +.label-important:hover { + background-color: #953b39; +} +.label-warning { + background-color: #f89406; +} +.label-warning:hover { + background-color: #c67605; +} +.label-success { + background-color: #468847; +} +.label-success:hover { + background-color: #356635; +} +.label-info { + background-color: #3a87ad; +} +.label-info:hover { + background-color: #2d6987; +} +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +@-moz-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +@keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +.progress { + overflow: hidden; + height: 18px; + margin-bottom: 18px; + background-color: #f7f7f7; + background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -ms-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9)); + background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: linear-gradient(top, #f5f5f5, #f9f9f9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0); + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.progress .bar { + width: 0%; + height: 18px; + color: #ffffff; + font-size: 12px; + text-align: center; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #0e90d2; + background-image: -moz-linear-gradient(top, #149bdf, #0480be); + background-image: -ms-linear-gradient(top, #149bdf, #0480be); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be)); + background-image: -webkit-linear-gradient(top, #149bdf, #0480be); + background-image: -o-linear-gradient(top, #149bdf, #0480be); + background-image: linear-gradient(top, #149bdf, #0480be); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0); + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition: width 0.6s ease; + -moz-transition: width 0.6s ease; + -ms-transition: width 0.6s ease; + -o-transition: width 0.6s ease; + transition: width 0.6s ease; +} +.progress-striped .bar { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + -webkit-background-size: 40px 40px; + -moz-background-size: 40px 40px; + -o-background-size: 40px 40px; + background-size: 40px 40px; +} +.progress.active .bar { + -webkit-animation: progress-bar-stripes 2s linear infinite; + -moz-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} +.progress-danger .bar { + background-color: #dd514c; + background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -o-linear-gradient(top, #ee5f5b, #c43c35); + background-image: linear-gradient(top, #ee5f5b, #c43c35); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0); +} +.progress-danger.progress-striped .bar { + background-color: #ee5f5b; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-success .bar { + background-color: #5eb95e; + background-image: -moz-linear-gradient(top, #62c462, #57a957); + background-image: -ms-linear-gradient(top, #62c462, #57a957); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957)); + background-image: -webkit-linear-gradient(top, #62c462, #57a957); + background-image: -o-linear-gradient(top, #62c462, #57a957); + background-image: linear-gradient(top, #62c462, #57a957); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0); +} +.progress-success.progress-striped .bar { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-info .bar { + background-color: #4bb1cf; + background-image: -moz-linear-gradient(top, #5bc0de, #339bb9); + background-image: -ms-linear-gradient(top, #5bc0de, #339bb9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9)); + background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9); + background-image: -o-linear-gradient(top, #5bc0de, #339bb9); + background-image: linear-gradient(top, #5bc0de, #339bb9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0); +} +.progress-info.progress-striped .bar { + background-color: #5bc0de; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.accordion { + margin-bottom: 18px; +} +.accordion-group { + margin-bottom: 2px; + border: 1px solid #e5e5e5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.accordion-heading { + border-bottom: 0; +} +.accordion-heading .accordion-toggle { + display: block; + padding: 8px 15px; +} +.accordion-inner { + padding: 9px 15px; + border-top: 1px solid #e5e5e5; +} +.carousel { + position: relative; + margin-bottom: 18px; + line-height: 1; +} +.carousel-inner { + overflow: hidden; + width: 100%; + position: relative; +} +.carousel .item { + display: none; + position: relative; + -webkit-transition: 0.6s ease-in-out left; + -moz-transition: 0.6s ease-in-out left; + -ms-transition: 0.6s ease-in-out left; + -o-transition: 0.6s ease-in-out left; + transition: 0.6s ease-in-out left; +} +.carousel .item > img { + display: block; + line-height: 1; +} +.carousel .active, .carousel .next, .carousel .prev { + display: block; +} +.carousel .active { + left: 0; +} +.carousel .next, .carousel .prev { + position: absolute; + top: 0; + width: 100%; +} +.carousel .next { + left: 100%; +} +.carousel .prev { + left: -100%; +} +.carousel .next.left, .carousel .prev.right { + left: 0; +} +.carousel .active.left { + left: -100%; +} +.carousel .active.right { + left: 100%; +} +.carousel-control { + position: absolute; + top: 40%; + left: 15px; + width: 40px; + height: 40px; + margin-top: -20px; + font-size: 60px; + font-weight: 100; + line-height: 30px; + color: #ffffff; + text-align: center; + background: #222222; + border: 3px solid #ffffff; + -webkit-border-radius: 23px; + -moz-border-radius: 23px; + border-radius: 23px; + opacity: 0.5; + filter: alpha(opacity=50); +} +.carousel-control.right { + left: auto; + right: 15px; +} +.carousel-control:hover { + color: #ffffff; + text-decoration: none; + opacity: 0.9; + filter: alpha(opacity=90); +} +.carousel-caption { + position: absolute; + left: 0; + right: 0; + bottom: 0; + padding: 10px 15px 5px; + background: #333333; + background: rgba(0, 0, 0, 0.75); +} +.carousel-caption h4, .carousel-caption p { + color: #ffffff; +} +.hero-unit { + padding: 60px; + margin-bottom: 30px; + background-color: #f5f5f5; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} +.hero-unit h1 { + margin-bottom: 0; + font-size: 60px; + line-height: 1; + letter-spacing: -1px; +} +.hero-unit p { + font-size: 18px; + font-weight: 200; + line-height: 27px; +} +.pull-right { + float: right; +} +.pull-left { + float: left; +} +.hide { + display: none; +} +.show { + display: block; +} +.invisible { + visibility: hidden; +} diff --git a/src/nl/astraeus/jdbc/web/resources/images/loading.gif b/src/nl/astraeus/jdbc/web/resources/images/loading.gif new file mode 100644 index 0000000..21c7e74 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/images/loading.gif Binary files differ diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f403193 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..73ff239 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..3b00020 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..275077f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/README b/README deleted file mode 100644 index 734abaf..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -This file was created by IntelliJ IDEA 11.1.1 for binding GitHub repository \ No newline at end of file diff --git a/Simple-jdbc-statistics.iml b/Simple-jdbc-statistics.iml new file mode 100644 index 0000000..ca90a9b --- /dev/null +++ b/Simple-jdbc-statistics.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/lib/h2-1.3.166.jar b/lib/h2-1.3.166.jar new file mode 100644 index 0000000..4985063 --- /dev/null +++ b/lib/h2-1.3.166.jar Binary files differ diff --git a/lib/servlet-api-2.5.jar b/lib/servlet-api-2.5.jar new file mode 100644 index 0000000..20b5755 --- /dev/null +++ b/lib/servlet-api-2.5.jar Binary files differ diff --git a/lib/slf4j-api-1.6.4.jar b/lib/slf4j-api-1.6.4.jar new file mode 100644 index 0000000..4d23f41 --- /dev/null +++ b/lib/slf4j-api-1.6.4.jar Binary files differ diff --git a/lib/slf4j-simple-1.6.4.jar b/lib/slf4j-simple-1.6.4.jar new file mode 100644 index 0000000..3d1b8d9 --- /dev/null +++ b/lib/slf4j-simple-1.6.4.jar Binary files differ diff --git a/lib/ssr-0.1.jar b/lib/ssr-0.1.jar new file mode 100644 index 0000000..65dfcf4 --- /dev/null +++ b/lib/ssr-0.1.jar Binary files differ diff --git a/lib/vst-0.4.jar b/lib/vst-0.4.jar new file mode 100644 index 0000000..db63792 --- /dev/null +++ b/lib/vst-0.4.jar Binary files differ diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..ac2dbe1 --- /dev/null +++ b/readme.md @@ -0,0 +1 @@ +A simple wrapper around jdbc drivers what will show current jdbc stats of the running queries on a simple web page on port 18080. \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/ConnectionLogger.java b/src/nl/astraeus/jdbc/ConnectionLogger.java new file mode 100644 index 0000000..c3e243f --- /dev/null +++ b/src/nl/astraeus/jdbc/ConnectionLogger.java @@ -0,0 +1,279 @@ +package nl.astraeus.jdbc; + +import java.sql.*; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Executor; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:12:34 PM + */ +public class ConnectionLogger implements Connection { + private Connection connection; + + private long milli; + private long nano; + private String lastSql; + + public ConnectionLogger(Connection connection) { + this.connection = connection; + this.lastSql = ""; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(QueryType.UNKNOWN, sql, m, n); + } + + public void commit() throws SQLException { + clearTime(); + + connection.commit(); + + log("commit"); + } + + public void rollback() throws SQLException { + clearTime(); + + connection.rollback(); + + log("rollback"); + } + + public void close() throws SQLException { + clearTime(); + + connection.close(); + + log("close"); + } + + public PreparedStatement prepareStatement(String sql) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, autoGeneratedKeys); + } + + public PreparedStatement prepareStatement(String sql, int columnIndexes[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnIndexes); + } + + public PreparedStatement prepareStatement(String sql, String columnNames[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnNames); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public Statement createStatement() throws SQLException { + return connection.createStatement(); + } + + public CallableStatement prepareCall(String sql) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql); + } + + public String nativeSQL(String sql) throws SQLException { + lastSql = sql; + return connection.nativeSQL(sql); + } + + public void setAutoCommit(boolean autoCommit) throws SQLException { + connection.setAutoCommit(autoCommit); + } + + public boolean getAutoCommit() throws SQLException { + return connection.getAutoCommit(); + } + + public boolean isClosed() throws SQLException { + return connection.isClosed(); + } + + public DatabaseMetaData getMetaData() throws SQLException { + return connection.getMetaData(); + } + + public void setReadOnly(boolean readOnly) throws SQLException { + connection.setReadOnly(readOnly); + } + + public boolean isReadOnly() throws SQLException { + return connection.isReadOnly(); + } + + public void setCatalog(String catalog) throws SQLException { + connection.setCatalog(catalog); + } + + public String getCatalog() throws SQLException { + return connection.getCatalog(); + } + + public void setTransactionIsolation(int level) throws SQLException { + connection.setTransactionIsolation(level); + } + + public int getTransactionIsolation() throws SQLException { + return connection.getTransactionIsolation(); + } + + public SQLWarning getWarnings() throws SQLException { + return connection.getWarnings(); + } + + public void clearWarnings() throws SQLException { + connection.clearWarnings(); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency); + } + + public Map> getTypeMap() throws SQLException { + return connection.getTypeMap(); + } + + public void setTypeMap(Map> map) throws SQLException { + connection.setTypeMap(map); + } + + public void setHoldability(int holdability) throws SQLException { + connection.setHoldability(holdability); + } + + public int getHoldability() throws SQLException { + return connection.getHoldability(); + } + + public Savepoint setSavepoint() throws SQLException { + return connection.setSavepoint(); + } + + public Savepoint setSavepoint(String name) throws SQLException { + return connection.setSavepoint(name); + } + + public void rollback(Savepoint savepoint) throws SQLException { + connection.rollback(); + } + + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + connection.releaseSavepoint(savepoint); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public Clob createClob() throws SQLException { + return connection.createClob(); + } + + public Blob createBlob() throws SQLException { + return connection.createBlob(); + } + + public NClob createNClob() throws SQLException { + return connection.createNClob(); + } + + public SQLXML createSQLXML() throws SQLException { + return connection.createSQLXML(); + } + + public boolean isValid(int timeout) throws SQLException { + return connection.isValid(timeout); + } + + public void setClientInfo(String name, String value) throws SQLClientInfoException { + connection.setClientInfo(name, value); + } + + public void setClientInfo(Properties properties) throws SQLClientInfoException { + connection.setClientInfo(properties); + } + + public String getClientInfo(String name) throws SQLException { + return connection.getClientInfo(name); + } + + public Properties getClientInfo() throws SQLException { + return connection.getClientInfo(); + } + + public Array createArrayOf(String typeName, Object[] elements) throws SQLException { + return connection.createArrayOf(typeName, elements); + } + + public Struct createStruct(String typeName, Object[] attributes) throws SQLException { + return connection.createStruct(typeName, attributes); + } + + @Override + public void setSchema(String schema) throws SQLException { + connection.setSchema(schema); + } + + @Override + public String getSchema() throws SQLException { + return connection.getSchema(); + } + + @Override + public void abort(Executor executor) throws SQLException { + connection.abort(executor); + } + + @Override + public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { + connection.setNetworkTimeout(executor, milliseconds); + } + + @Override + public int getNetworkTimeout() throws SQLException { + return connection.getNetworkTimeout(); + } + + public T unwrap(Class iface) throws SQLException { + return connection.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return connection.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/Driver.java b/src/nl/astraeus/jdbc/Driver.java new file mode 100644 index 0000000..8317172 --- /dev/null +++ b/src/nl/astraeus/jdbc/Driver.java @@ -0,0 +1,116 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.http.SimpleWebServer; +import nl.astraeus.jdbc.web.JdbcStatisticsServlet; +import nl.astraeus.jdbc.web.ResourceServlet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.*; +import java.util.Enumeration; +import java.util.Properties; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:54:37 PM + */ +public class Driver implements java.sql.Driver { + private final static Logger log = LoggerFactory.getLogger(Driver.class); + + final private static String URL_PREFIX = "jdbc:stat:"; + + private java.sql.Driver driver = null; + private String[] drivers = { + "org.postgresql.Driver", + "oracle.jdbc.driver.OracleDriver", + "com.sybase.jdbc2.jdbc.SybDriver", + "net.sourceforge.jtds.jdbc.Driver", + "com.microsoft.jdbc.sqlserver.SQLServerDriver", + "com.microsoft.sqlserver.jdbc.SQLServerDriver", + "weblogic.jdbc.sqlserver.SQLServerDriver", + "com.informix.jdbc.IfxDriver", + "org.apache.derby.jdbc.ClientDriver", + "org.apache.derby.jdbc.EmbeddedDriver", + "com.mysql.jdbc.Driver", + "org.hsqldb.jdbcDriver", + "org.h2.Driver" }; + + static { + log.debug("Loading driver class " + Driver.class.getName()); + + try { + DriverManager.registerDriver(new Driver()); + } catch (SQLException e) { + log.error("", e); + } + } + + public Driver() { + for (String dr : drivers) { + try { + Class.forName(dr); + } catch (Throwable e) { + log.debug("Can't instantiate driver: " + dr, e); + } + } + } + + private java.sql.Driver findDriver(String url) throws SQLException { + Enumeration e = DriverManager.getDrivers(); + + while (e.hasMoreElements()) { + java.sql.Driver d = (java.sql.Driver) e.nextElement(); + + if (d.acceptsURL(url)) { + return d; + } + } + + throw new SQLException("Driver not found: " + url); + } + + public Connection connect(String url, Properties info) throws SQLException { + url = url.substring(URL_PREFIX.length()); + + if (driver == null) { + driver = findDriver(url); + } + + if (driver != null) { + SimpleWebServer server = new SimpleWebServer(18080); + + server.addServlet(new JdbcStatisticsServlet(), "/"); + server.addServlet(new ResourceServlet(), "/resources/*"); + + server.start(); + } + + return new ConnectionLogger(driver.connect(url, info)); + } + + public boolean acceptsURL(String url) throws SQLException { + return (url != null && url.startsWith(URL_PREFIX)); + } + + public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { + return driver.getPropertyInfo(url, info); + } + + public int getMajorVersion() { + return driver.getMajorVersion(); + } + + public int getMinorVersion() { + return driver.getMinorVersion(); + } + + public boolean jdbcCompliant() { + return driver.jdbcCompliant(); + } + + @Override + public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException { + return driver.getParentLogger(); + } +} diff --git a/src/nl/astraeus/jdbc/JdbcLogger.java b/src/nl/astraeus/jdbc/JdbcLogger.java new file mode 100644 index 0000000..f4bc125 --- /dev/null +++ b/src/nl/astraeus/jdbc/JdbcLogger.java @@ -0,0 +1,113 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.jdbc.util.Util; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/** + * User: riennentjes + * Date: Jul 12, 2008 + * Time: 9:15:21 AM + */ +public class JdbcLogger { + private final static Logger logger = LoggerFactory.getLogger(JdbcLogger.class); + + private final static JdbcLogger instance = new JdbcLogger(); + + public static JdbcLogger get() { + return instance; + } + + public final static class LogEntry { + public QueryType type; + public String sql; + public long milli; + public long nano; + public int count; + public int hash; + + public LogEntry(int hash, QueryType type, String sql, long milli, long nano) { + this.hash = hash; + this.type = type; + this.sql = sql; + this.milli = milli; + this.nano = nano; + this.count = 1; + } + + public void addCount(long milli, long nano) { + synchronized (this) { + count++; + this.milli += milli; + this.nano += nano; + } + } + + public int getCount() { + return count; + } + + public String getMilli() { + return Util.formatNano(milli*1000000/count); + } + + public String getNano() { + return Util.formatNano(nano/count); + } + + public String getTotal() { + return Util.formatNano(nano); + } + + public String getSql() { + return sql; + } + } + + private Map queries; + + public JdbcLogger() { + queries = new ConcurrentHashMap(); + } + + public void logEntry(QueryType type, String sql, long milli, long nano) { + int hash = sql.hashCode(); + LogEntry entry = queries.get(hash); + + if (entry == null) { + entry = new LogEntry(hash, type, sql, milli, nano); + queries.put(hash, entry); + } else { + entry.addCount(milli, nano); + } + + if (queries.size() > 1000) { + List toRemove = new LinkedList(); + List values = new LinkedList(queries.values()); + + Collections.sort(values, new Comparator() { + @Override + public int compare(LogEntry o1, LogEntry o2) { + return o1.count - o2.count; + } + }); + + while (queries.size() > 900) { + queries.remove(values.remove(0).hash); + + } + } + } + + public static void log(QueryType type, String sql, long milli, long nano) { + instance.logEntry(type, sql, milli, nano); + } + + public Collection getEntries() { + return queries.values(); + } + +} diff --git a/src/nl/astraeus/jdbc/PreparedStatementLogger.java b/src/nl/astraeus/jdbc/PreparedStatementLogger.java new file mode 100644 index 0000000..98aefc7 --- /dev/null +++ b/src/nl/astraeus/jdbc/PreparedStatementLogger.java @@ -0,0 +1,577 @@ +package nl.astraeus.jdbc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.InputStream; +import java.io.Reader; +import java.math.BigDecimal; +import java.net.URL; +import java.sql.*; +import java.util.Calendar; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 7:47:57 PM + */ +public class PreparedStatementLogger implements PreparedStatement { + private final static Logger log = LoggerFactory.getLogger(PreparedStatementLogger.class); + + private PreparedStatement statement; + + private String sql; + private QueryType type; + private long milli; + private long nano; + + //private ArrayList parameters; + + public PreparedStatementLogger(PreparedStatement statement) { + this.statement = statement; + this.sql = ""; + this.type = QueryType.UNKNOWN; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(QueryType type, String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(type, sql, m, n); + } + + public PreparedStatementLogger(Connection connection, String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql); + } + + public PreparedStatementLogger(Connection connection, String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatementLogger(Connection connection, String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, autoGeneratedKeys); + } + + public PreparedStatementLogger(Connection connection, String sql, int[] columnIndexes) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnIndexes); + } + + public PreparedStatementLogger(Connection connection, String sql, String[] columnNames) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnNames); + } + + public boolean execute() throws SQLException { + clearTime(); + + boolean result = statement.execute(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery() throws SQLException { + clearTime(); + + ResultSet result = statement.executeQuery(); + + log(type, sql); + + return result; + } + + public int executeUpdate() throws SQLException { + clearTime(); + + int result = statement.executeUpdate(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + ResultSet result = statement.executeQuery(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnNames); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnNames); + + log(type, sql); + + return result; + } + + + public void setNull(int parameterIndex, int sqlType) throws SQLException { + statement.setNull(parameterIndex, sqlType); + } + + public void setBoolean(int parameterIndex, boolean x) throws SQLException { + statement.setBoolean(parameterIndex, x); + } + + public void setByte(int parameterIndex, byte x) throws SQLException { + statement.setByte(parameterIndex, x); + } + + public void setShort(int parameterIndex, short x) throws SQLException { + statement.setShort(parameterIndex, x); + } + + public void setInt(int parameterIndex, int x) throws SQLException { + statement.setInt(parameterIndex, x); + } + + public void setLong(int parameterIndex, long x) throws SQLException { + statement.setLong(parameterIndex, x); + } + + public void setFloat(int parameterIndex, float x) throws SQLException { + statement.setFloat(parameterIndex, x); + } + + public void setDouble(int parameterIndex, double x) throws SQLException { + statement.setDouble(parameterIndex, x); + } + + public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { + statement.setBigDecimal(parameterIndex, x); + } + + public void setString(int parameterIndex, String x) throws SQLException { + statement.setString(parameterIndex, x); + } + + public void setBytes(int parameterIndex, byte x[]) throws SQLException { + statement.setBytes(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x) throws SQLException { + statement.setDate(parameterIndex, x); + } + + public void setTime(int parameterIndex, Time x) throws SQLException { + statement.setTime(parameterIndex, x); + } + + public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { + statement.setTimestamp(parameterIndex, x); + } + + public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setUnicodeStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType); + } + + public void setObject(int parameterIndex, Object x) throws SQLException { + statement.setObject(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setRef(int parameterIndex, Ref x) throws SQLException { + statement.setRef(parameterIndex, x); + } + + public void setBlob(int parameterIndex, Blob x) throws SQLException { + statement.setBlob(parameterIndex, x); + } + + public void setClob(int parameterIndex, Clob x) throws SQLException { + statement.setClob(parameterIndex, x); + } + + public void setArray(int parameterIndex, Array x) throws SQLException { + statement.setArray(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { + statement.setDate(parameterIndex, x, cal); + } + + public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { + statement.setTime(parameterIndex, x, cal); + } + + public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { + statement.setTimestamp(parameterIndex, x, cal); + } + + public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException { + statement.setNull(parameterIndex, sqlType, typeName); + } + + public void setURL(int parameterIndex, URL x) throws SQLException { + statement.setURL(parameterIndex, x); + } + + public void setRowId(int parameterIndex, RowId x) throws SQLException { + statement.setRowId(parameterIndex, x); + } + + public void setNString(int parameterIndex, String value) throws SQLException { + statement.setNString(parameterIndex, value); + } + + public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException { + statement.setNCharacterStream(parameterIndex, value, length); + } + + public void setNClob(int parameterIndex, NClob value) throws SQLException { + statement.setNClob(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setClob(parameterIndex, reader, length); + } + + public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException { + statement.setBlob(parameterIndex, inputStream, length); + } + + public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setNClob(parameterIndex, reader, length); + } + + public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException { + statement.setSQLXML(parameterIndex, xmlObject); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType, scaleOrLength); + } + + public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException { + statement.setAsciiStream(parameterIndex, x); + } + + public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException { + statement.setBinaryStream(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException { + statement.setCharacterStream(parameterIndex, reader); + } + + public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException { + statement.setNCharacterStream(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader) throws SQLException { + statement.setClob(parameterIndex, reader); + } + + public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException { + statement.setBlob(parameterIndex, inputStream); + } + + public void setNClob(int parameterIndex, Reader reader) throws SQLException { + statement.setNClob(parameterIndex, reader); + } + + + public void close() throws SQLException { + sql = ""; + type = QueryType.UNKNOWN; + milli = 0; + nano = 0; + + statement.close(); + } + + public ResultSetMetaData getMetaData() throws SQLException { + return statement.getMetaData(); + } + + public void clearParameters() throws SQLException { + statement.clearParameters(); + } + + public ParameterMetaData getParameterMetaData() throws SQLException { + return statement.getParameterMetaData(); + } + + public void addBatch() throws SQLException { + statement.addBatch(); + } + + public int getMaxFieldSize() throws SQLException { + return statement.getMaxFieldSize(); + } + + public void setMaxFieldSize(int max) throws SQLException { + statement.setMaxFieldSize(max); + } + + public int getMaxRows() throws SQLException { + return statement.getMaxRows(); + } + + public void setMaxRows(int max) throws SQLException { + statement.setMaxRows(max); + } + + public void setEscapeProcessing(boolean enable) throws SQLException { + statement.setEscapeProcessing(enable); + } + + public int getQueryTimeout() throws SQLException { + return statement.getQueryTimeout(); + } + + public void setQueryTimeout(int seconds) throws SQLException { + statement.setQueryTimeout(seconds); + } + + public void cancel() throws SQLException { + statement.cancel(); + } + + public SQLWarning getWarnings() throws SQLException { + return statement.getWarnings(); + } + + public void clearWarnings() throws SQLException { + statement.clearWarnings(); + } + + public void setCursorName(String name) throws SQLException { + statement.setCursorName(name); + } + + public boolean execute(String sql) throws SQLException { + return statement.execute(sql); + } + + public ResultSet getResultSet() throws SQLException { + return statement.getResultSet(); + } + + public int getUpdateCount() throws SQLException { + return statement.getUpdateCount(); + } + + public boolean getMoreResults() throws SQLException { + return statement.getMoreResults(); + } + + public void setFetchDirection(int direction) throws SQLException { + statement.setFetchDirection(direction); + } + + public int getFetchDirection() throws SQLException { + return statement.getFetchDirection(); + } + + public void setFetchSize(int rows) throws SQLException { + statement.setFetchSize(rows); + } + + public int getFetchSize() throws SQLException { + return statement.getFetchSize(); + } + + public int getResultSetConcurrency() throws SQLException { + return statement.getResultSetConcurrency(); + } + + public int getResultSetType() throws SQLException { + return statement.getResultSetType(); + } + + public void addBatch(String sql) throws SQLException { + statement.addBatch(sql); + } + + public void clearBatch() throws SQLException { + statement.clearBatch(); + } + + public int[] executeBatch() throws SQLException { + return statement.executeBatch(); + } + + public Connection getConnection() throws SQLException { + return statement.getConnection(); + } + + public boolean getMoreResults(int current) throws SQLException { + return statement.getMoreResults(current); + } + + public ResultSet getGeneratedKeys() throws SQLException { + return statement.getGeneratedKeys(); + } + + public int getResultSetHoldability() throws SQLException { + return statement.getResultSetHoldability(); + } + + public boolean isClosed() throws SQLException { + return statement.isClosed(); + } + + public void setPoolable(boolean poolable) throws SQLException { + statement.setPoolable(poolable); + } + + public boolean isPoolable() throws SQLException { + return statement.isPoolable(); + } + + @Override + public void closeOnCompletion() throws SQLException { + statement.closeOnCompletion();; + } + + @Override + public boolean isCloseOnCompletion() throws SQLException { + return statement.isCloseOnCompletion(); + } + + public T unwrap(Class iface) throws SQLException { + return statement.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return statement.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/QueryType.java b/src/nl/astraeus/jdbc/QueryType.java new file mode 100644 index 0000000..744fbfc --- /dev/null +++ b/src/nl/astraeus/jdbc/QueryType.java @@ -0,0 +1,24 @@ +package nl.astraeus.jdbc; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:32:49 PM + */ +public enum QueryType { + PLAIN("plain"), + PREPARED("prepared"), + CALLABLE("callable"), + UNKNOWN("unknown"); + + private String description; + + QueryType(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } + +} diff --git a/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java new file mode 100644 index 0000000..07aac40 --- /dev/null +++ b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java @@ -0,0 +1,68 @@ +package nl.astraeus.jdbc.example; + +import java.sql.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 7:32 PM + */ +public class JdbcStatisticsExample { + + + public static void main(String [] args) throws Exception { + Class.forName("org.h2.Driver"); + Class.forName("nl.astraeus.jdbc.Driver"); + + new JdbcStatisticsExample(); + } + + public JdbcStatisticsExample() throws Exception { + Connection conn = DriverManager.getConnection("jdbc:stat:jdbc:h2:mem:test"); + + Statement statement = null; + + statement = conn.createStatement(); + statement.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + + boolean running = true; + int count = 1; + PreparedStatement ps = null; + + while (running) { + Thread.sleep(10); + + String TableName = "TEST"+(System.nanoTime() % 1000); + + try { + ps = conn.prepareStatement("SELECT COUNT(*) FROM "+TableName); + ResultSet rs = ps.executeQuery(); + } catch (SQLException e) { + statement = conn.createStatement(); + statement.execute("CREATE TABLE "+TableName+" (ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + } finally { + if (ps!=null) { + ps.close(); + } + } + + ps = conn.prepareStatement("INSERT INTO "+TableName+" VALUES (?, ?)"); + + ps.setInt(1, count++); + ps.setString(2, "String "+System.currentTimeMillis()); + + ps.execute(); + ps.close(); + + Thread.sleep(10); + + ps = conn.prepareStatement("SELECT * FROM "+TableName); + ResultSet rs = ps.executeQuery(); + statement.close(); + } + + conn.close(); + } +} diff --git a/src/nl/astraeus/jdbc/util/IOUtils.java b/src/nl/astraeus/jdbc/util/IOUtils.java new file mode 100644 index 0000000..ce95d9d --- /dev/null +++ b/src/nl/astraeus/jdbc/util/IOUtils.java @@ -0,0 +1,38 @@ +package nl.astraeus.jdbc.util; + +import java.io.*; + +/** + * User: rnentjes + * Date: 4/9/12 + * Time: 2:33 PM + */ +public class IOUtils { + + public static String toString(InputStream in) throws IOException { + assert in != null; + + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + StringBuilder buffer = new StringBuilder(); + + while(reader.ready()) { + buffer.append(reader.readLine()); + buffer.append("\n"); + } + + return buffer.toString(); + } finally { + in.close(); + } + } + + public static void copy(InputStream in, OutputStream out) throws IOException { + byte [] buffer = new byte[1<<16]; + int bytes; + + while((bytes = in.read(buffer)) > 0) { + out.write(buffer, 0, bytes); + } + } +} diff --git a/src/nl/astraeus/jdbc/util/Util.java b/src/nl/astraeus/jdbc/util/Util.java new file mode 100644 index 0000000..eaa853b --- /dev/null +++ b/src/nl/astraeus/jdbc/util/Util.java @@ -0,0 +1,25 @@ +package nl.astraeus.jdbc.util; + +import java.text.DecimalFormat; +import java.text.NumberFormat; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 12:28 PM + */ +public class Util { + // utility functions + public static String formatNano(long l) { + NumberFormat format = new DecimalFormat("###,##0.000000"); + + return format.format((double) l / 1000000.0); + } + + public static void printMemoryUsage() { + System.out.println("Used memory: "+((Runtime.getRuntime().totalMemory() / (1024*1024))-(Runtime.getRuntime().freeMemory() / (1024*1024)))); + System.out.println("Free memory: "+(Runtime.getRuntime().freeMemory() / (1024*1024))); + System.out.println("Total memory: "+(Runtime.getRuntime().totalMemory() / (1024*1024))); + System.out.println("Max memory: "+(Runtime.getRuntime().maxMemory() / (1024*1024))); + } +} diff --git a/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java b/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java new file mode 100644 index 0000000..a162d6f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java @@ -0,0 +1,90 @@ +package nl.astraeus.jdbc.web; + +import nl.astraeus.jdbc.util.IOUtils; +import nl.astraeus.jdbc.util.Util; +import nl.astraeus.jdbc.web.page.Menu; +import nl.astraeus.jdbc.web.page.Page; +import nl.astraeus.jdbc.web.page.QueryOverview; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import java.io.IOException; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:05 PM + */ +public class JdbcStatisticsServlet extends HttpServlet { + + private String head; + private String bottom; + + @Override + public void init() throws ServletException { + super.init(); + + try { + head = IOUtils.toString(getClass().getResourceAsStream("head.html")); + bottom = IOUtils.toString(getClass().getResourceAsStream("bottom.html")); + } catch (IOException e) { + throw new ServletException(e); + } + + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + doPost(req, resp); + } + + @Override + protected void doPost(final HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + long nano = System.nanoTime(); + + HttpSession session = req.getSession(); + boolean ajax = "true".equals(req.getParameter("ajax")); + + resp.setContentType("text/html"); + + Page page = (Page)session.getAttribute("page"); + Page menu = (Page)session.getAttribute("menu"); + + session.setMaxInactiveInterval(1800); + + if (menu == null) { + menu = new Menu(); + + session.setAttribute("menu", menu); + } + + if (page == null || "menumain".equals(req.getParameter("action"))) { + page = new QueryOverview(); + } else if ("diagnostics".equals(req.getParameter("action"))) { + //page = new Diagnostics(); + } else { + page = page .processRequest(req); + } + + menu.processRequest(req); + + session.setAttribute("page", page); + + if (!ajax) { + resp.getWriter().print(head); + } + + resp.getWriter().print(menu.render(req)); + resp.getWriter().print(page.render(req)); + + if (!ajax) { + resp.getWriter().print(bottom); + } + + System.out.println("Request ends, time="+ Util.formatNano(System.nanoTime() - nano) +", page="+page.getClass().getSimpleName()); + } + +} diff --git a/src/nl/astraeus/jdbc/web/ResourceServlet.java b/src/nl/astraeus/jdbc/web/ResourceServlet.java new file mode 100644 index 0000000..7abfe6f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/ResourceServlet.java @@ -0,0 +1,49 @@ +package nl.astraeus.jdbc.web; + +import nl.astraeus.jdbc.util.IOUtils; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.InputStream; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:05 PM + */ +public class ResourceServlet extends HttpServlet { + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String uri = req.getRequestURI(); + + uri = "nl/astraeus/jdbc/web" + uri; + InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(uri); + + if (in == null) { + resp.sendError(404, "Cannot find resource '" + uri + "'."); + } else { + try { + if (uri.endsWith("js")) { + resp.setContentType("text/javascript"); + } else if (uri.endsWith("css")) { + resp.setContentType("text/css"); + } else if (uri.endsWith("png")) { + resp.setContentType("image/png"); + } else if (uri.endsWith("jpg")) { + resp.setContentType("image/jpeg"); + } else if (uri.endsWith("gif")) { + resp.setContentType("image/gif"); + } + + IOUtils.copy(in, resp.getOutputStream()); + } finally { + in.close(); + } + } + } + +} diff --git a/src/nl/astraeus/jdbc/web/bottom.html b/src/nl/astraeus/jdbc/web/bottom.html new file mode 100644 index 0000000..1288de4 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/bottom.html @@ -0,0 +1,8 @@ + + +
+ + + + + \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/head.html b/src/nl/astraeus/jdbc/web/head.html new file mode 100644 index 0000000..0f8f6a3 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/head.html @@ -0,0 +1,96 @@ + + + + + + + Simple JDBC Statistics + + + + + + + + + + + + + + + + + + + +
+
+ +
+ diff --git a/src/nl/astraeus/jdbc/web/page/Menu.html b/src/nl/astraeus/jdbc/web/page/Menu.html new file mode 100644 index 0000000..505c7c2 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.html @@ -0,0 +1,42 @@ + diff --git a/src/nl/astraeus/jdbc/web/page/Menu.java b/src/nl/astraeus/jdbc/web/page/Menu.java new file mode 100644 index 0000000..f0a349a --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.java @@ -0,0 +1,27 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 9:07 PM + */ +public class Menu extends TemplatePage { + + @Override + public Page processRequest(HttpServletRequest request) { + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + result.put("user", request.getSession().getAttribute("user")); + + return result; + } +} diff --git a/src/nl/astraeus/jdbc/web/page/Page.java b/src/nl/astraeus/jdbc/web/page/Page.java new file mode 100644 index 0000000..9d526d6 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Page.java @@ -0,0 +1,17 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:20 PM + */ +public abstract class Page { + + public abstract Page processRequest(HttpServletRequest request); + public abstract Map defineModel(HttpServletRequest request); + public abstract String render(HttpServletRequest request); + +} diff --git a/src/nl/astraeus/jdbc/web/page/QueryOverview.html b/src/nl/astraeus/jdbc/web/page/QueryOverview.html new file mode 100644 index 0000000..64a88fb --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/QueryOverview.html @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + {foreach(queries as q)} + + + + + + + {eachend} + +
Total timeAvg. time# CallsSql
{q.total}{q.nano}{q.count}{q.sql}
diff --git a/src/nl/astraeus/jdbc/web/page/QueryOverview.java b/src/nl/astraeus/jdbc/web/page/QueryOverview.java new file mode 100644 index 0000000..02982f1 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/QueryOverview.java @@ -0,0 +1,92 @@ +package nl.astraeus.jdbc.web.page; + +import nl.astraeus.jdbc.JdbcLogger; + +import javax.servlet.http.HttpServletRequest; +import java.util.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 9:16 PM + */ +public class QueryOverview extends TemplatePage { + + boolean sortTotalCalls = true; + boolean sortAvgTime = false; + boolean sortTotalTime = false; + + @Override + public Page processRequest(HttpServletRequest request) { + if ("sortTotalCalls".equals(request.getParameter("action"))) { + sortTotalCalls = true; + sortAvgTime = false; + sortTotalTime = false; + } else if ("sortAvgTime".equals(request.getParameter("action"))) { + sortTotalCalls = false; + sortAvgTime = true; + sortTotalTime = false; + } else if ("sortTotalTime".equals(request.getParameter("action"))) { + sortTotalCalls = false; + sortAvgTime = false; + sortTotalTime = true; + } + + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + List entries = new ArrayList(JdbcLogger.get().getEntries()); + + if (sortTotalCalls) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + return o2.count - o1.count; + } + }); + } else if (sortAvgTime) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + long n1 = o1.nano / o1.count; + long n2 = o2.nano / o2.count; + + if (n2 > n1) { + return 1; + } else if (n2 < n1) { + return -1; + } else { + return 0; + } + } + }); + } else if (sortTotalTime) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + if (o2.nano > o1.nano) { + return 1; + } else if (o2.nano < o1.nano) { + return -1; + } else { + return 0; + } + } + }); + } + + result.put("queries", entries); + result.put("count", entries.size()); + + result.put("sortTotalCalls", sortTotalCalls); + result.put("sortAvgTime", sortAvgTime); + result.put("sortTotalTime", sortTotalTime); + + return result; + } + +} diff --git a/src/nl/astraeus/jdbc/web/page/TemplatePage.java b/src/nl/astraeus/jdbc/web/page/TemplatePage.java new file mode 100644 index 0000000..33e2641 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/TemplatePage.java @@ -0,0 +1,58 @@ +package nl.astraeus.jdbc.web.page; + +import nl.astraeus.template.EscapeMode; +import nl.astraeus.template.SimpleTemplate; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:20 PM + */ +public abstract class TemplatePage extends Page { + + private SimpleTemplate template; + + protected TemplatePage() { + template = getSimpleTemplate(this.getClass()); + } + + public String render(HttpServletRequest request) { + return template.render(defineModel(request)); + } + + private static Map templateCache = new HashMap(); + + public synchronized static SimpleTemplate getSimpleTemplate(Class cls) { + SimpleTemplate result = templateCache.get(cls); + + if (result == null) { + InputStream in = null; + + try { + in = cls.getResourceAsStream(cls.getSimpleName() + ".html"); + + result = SimpleTemplate.readTemplate('{','}', EscapeMode.HTML, in); + + templateCache.put(cls, result); + } catch (IOException e) { + throw new IllegalStateException(e); + } finally { + if (in != null) { + try { + in.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + + return result; + } +} diff --git a/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css b/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css new file mode 100644 index 0000000..0e0056f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css @@ -0,0 +1,581 @@ +/*! + * Bootstrap Responsive v2.0.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ +.clearfix { + *zoom: 1; +} +.clearfix:before, .clearfix:after { + display: table; + content: ""; +} +.clearfix:after { + clear: both; +} +.hidden { + display: none; + visibility: hidden; +} +@media (max-width: 480px) { + .nav-collapse { + -webkit-transform: translate3d(0, 0, 0); + } + .page-header h1 small { + display: block; + line-height: 18px; + } + input[class*="span"], + select[class*="span"], + textarea[class*="span"], + .uneditable-input { + display: block; + width: 100%; + min-height: 28px; + /* Make inputs at least the height of their button counterpart */ + + /* Makes inputs behave like true block-level elements */ + + -webkit-box-sizing: border-box; + /* Older Webkit */ + + -moz-box-sizing: border-box; + /* Older FF */ + + -ms-box-sizing: border-box; + /* IE8 */ + + box-sizing: border-box; + /* CSS3 spec*/ + + } + .input-prepend input[class*="span"], .input-append input[class*="span"] { + width: auto; + } + input[type="checkbox"], input[type="radio"] { + border: 1px solid #ccc; + } + .form-horizontal .control-group > label { + float: none; + width: auto; + padding-top: 0; + text-align: left; + } + .form-horizontal .controls { + margin-left: 0; + } + .form-horizontal .control-list { + padding-top: 0; + } + .form-horizontal .form-actions { + padding-left: 10px; + padding-right: 10px; + } + .modal { + position: absolute; + top: 10px; + left: 10px; + right: 10px; + width: auto; + margin: 0; + } + .modal.fade.in { + top: auto; + } + .modal-header .close { + padding: 10px; + margin: -10px; + } + .carousel-caption { + position: static; + } +} +@media (max-width: 767px) { + .container { + width: auto; + padding: 0 20px; + } + .row-fluid { + width: 100%; + } + .row { + margin-left: 0; + } + .row > [class*="span"], .row-fluid > [class*="span"] { + float: none; + display: block; + width: auto; + margin: 0; + } +} +@media (min-width: 768px) and (max-width: 979px) { + .row { + margin-left: -20px; + *zoom: 1; + } + .row:before, .row:after { + display: table; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + margin-left: 20px; + } + .span1 { + width: 42px; + } + .span2 { + width: 104px; + } + .span3 { + width: 166px; + } + .span4 { + width: 228px; + } + .span5 { + width: 290px; + } + .span6 { + width: 352px; + } + .span7 { + width: 414px; + } + .span8 { + width: 476px; + } + .span9 { + width: 538px; + } + .span10 { + width: 600px; + } + .span11 { + width: 662px; + } + .span12, .container { + width: 724px; + } + .offset1 { + margin-left: 82px; + } + .offset2 { + margin-left: 144px; + } + .offset3 { + margin-left: 206px; + } + .offset4 { + margin-left: 268px; + } + .offset5 { + margin-left: 330px; + } + .offset6 { + margin-left: 392px; + } + .offset7 { + margin-left: 454px; + } + .offset8 { + margin-left: 516px; + } + .offset9 { + margin-left: 578px; + } + .offset10 { + margin-left: 640px; + } + .offset11 { + margin-left: 702px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, .row-fluid:after { + display: table; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid > [class*="span"] { + float: left; + margin-left: 2.762430939%; + } + .row-fluid > [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid > .span1 { + width: 5.801104972%; + } + .row-fluid > .span2 { + width: 14.364640883%; + } + .row-fluid > .span3 { + width: 22.928176794%; + } + .row-fluid > .span4 { + width: 31.491712705%; + } + .row-fluid > .span5 { + width: 40.055248616%; + } + .row-fluid > .span6 { + width: 48.618784527%; + } + .row-fluid > .span7 { + width: 57.182320438000005%; + } + .row-fluid > .span8 { + width: 65.74585634900001%; + } + .row-fluid > .span9 { + width: 74.30939226%; + } + .row-fluid > .span10 { + width: 82.87292817100001%; + } + .row-fluid > .span11 { + width: 91.436464082%; + } + .row-fluid > .span12 { + width: 99.999999993%; + } + input.span1, textarea.span1, .uneditable-input.span1 { + width: 32px; + } + input.span2, textarea.span2, .uneditable-input.span2 { + width: 94px; + } + input.span3, textarea.span3, .uneditable-input.span3 { + width: 156px; + } + input.span4, textarea.span4, .uneditable-input.span4 { + width: 218px; + } + input.span5, textarea.span5, .uneditable-input.span5 { + width: 280px; + } + input.span6, textarea.span6, .uneditable-input.span6 { + width: 342px; + } + input.span7, textarea.span7, .uneditable-input.span7 { + width: 404px; + } + input.span8, textarea.span8, .uneditable-input.span8 { + width: 466px; + } + input.span9, textarea.span9, .uneditable-input.span9 { + width: 528px; + } + input.span10, textarea.span10, .uneditable-input.span10 { + width: 590px; + } + input.span11, textarea.span11, .uneditable-input.span11 { + width: 652px; + } + input.span12, textarea.span12, .uneditable-input.span12 { + width: 714px; + } +} +@media (max-width: 979px) { + body { + padding-top: 0; + } + .navbar-fixed-top { + position: static; + margin-bottom: 18px; + } + .navbar-fixed-top .navbar-inner { + padding: 5px; + } + .navbar .container { + width: auto; + padding: 0; + } + .navbar .brand { + padding-left: 10px; + padding-right: 10px; + margin: 0 0 0 -5px; + } + .navbar .nav-collapse { + clear: left; + } + .navbar .nav { + float: none; + margin: 0 0 9px; + } + .navbar .nav > li { + float: none; + } + .navbar .nav > li > a { + margin-bottom: 2px; + } + .navbar .nav > .divider-vertical { + display: none; + } + .navbar .nav .nav-header { + color: #999999; + text-shadow: none; + } + .navbar .nav > li > a, .navbar .dropdown-menu a { + padding: 6px 15px; + font-weight: bold; + color: #999999; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + } + .navbar .dropdown-menu li + li a { + margin-bottom: 2px; + } + .navbar .nav > li > a:hover, .navbar .dropdown-menu a:hover { + background-color: #222222; + } + .navbar .dropdown-menu { + position: static; + top: auto; + left: auto; + float: none; + display: block; + max-width: none; + margin: 0 15px; + padding: 0; + background-color: transparent; + border: none; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + } + .navbar .dropdown-menu:before, .navbar .dropdown-menu:after { + display: none; + } + .navbar .dropdown-menu .divider { + display: none; + } + .navbar-form, .navbar-search { + float: none; + padding: 9px 15px; + margin: 9px 0; + border-top: 1px solid #222222; + border-bottom: 1px solid #222222; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + } + .navbar .nav.pull-right { + float: none; + margin-left: 0; + } + .navbar-static .navbar-inner { + padding-left: 10px; + padding-right: 10px; + } + .btn-navbar { + display: block; + } + .nav-collapse { + overflow: hidden; + height: 0; + } +} +@media (min-width: 980px) { + .nav-collapse.collapse { + height: auto !important; + } +} +@media (min-width: 1200px) { + .row { + margin-left: -30px; + *zoom: 1; + } + .row:before, .row:after { + display: table; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + margin-left: 30px; + } + .span1 { + width: 70px; + } + .span2 { + width: 170px; + } + .span3 { + width: 270px; + } + .span4 { + width: 370px; + } + .span5 { + width: 470px; + } + .span6 { + width: 570px; + } + .span7 { + width: 670px; + } + .span8 { + width: 770px; + } + .span9 { + width: 870px; + } + .span10 { + width: 970px; + } + .span11 { + width: 1070px; + } + .span12, .container { + width: 1170px; + } + .offset1 { + margin-left: 130px; + } + .offset2 { + margin-left: 230px; + } + .offset3 { + margin-left: 330px; + } + .offset4 { + margin-left: 430px; + } + .offset5 { + margin-left: 530px; + } + .offset6 { + margin-left: 630px; + } + .offset7 { + margin-left: 730px; + } + .offset8 { + margin-left: 830px; + } + .offset9 { + margin-left: 930px; + } + .offset10 { + margin-left: 1030px; + } + .offset11 { + margin-left: 1130px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, .row-fluid:after { + display: table; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid > [class*="span"] { + float: left; + margin-left: 2.564102564%; + } + .row-fluid > [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid > .span1 { + width: 5.982905983%; + } + .row-fluid > .span2 { + width: 14.529914530000001%; + } + .row-fluid > .span3 { + width: 23.076923077%; + } + .row-fluid > .span4 { + width: 31.623931624%; + } + .row-fluid > .span5 { + width: 40.170940171000005%; + } + .row-fluid > .span6 { + width: 48.717948718%; + } + .row-fluid > .span7 { + width: 57.264957265%; + } + .row-fluid > .span8 { + width: 65.81196581200001%; + } + .row-fluid > .span9 { + width: 74.358974359%; + } + .row-fluid > .span10 { + width: 82.905982906%; + } + .row-fluid > .span11 { + width: 91.45299145300001%; + } + .row-fluid > .span12 { + width: 100%; + } + input.span1, textarea.span1, .uneditable-input.span1 { + width: 60px; + } + input.span2, textarea.span2, .uneditable-input.span2 { + width: 160px; + } + input.span3, textarea.span3, .uneditable-input.span3 { + width: 260px; + } + input.span4, textarea.span4, .uneditable-input.span4 { + width: 360px; + } + input.span5, textarea.span5, .uneditable-input.span5 { + width: 460px; + } + input.span6, textarea.span6, .uneditable-input.span6 { + width: 560px; + } + input.span7, textarea.span7, .uneditable-input.span7 { + width: 660px; + } + input.span8, textarea.span8, .uneditable-input.span8 { + width: 760px; + } + input.span9, textarea.span9, .uneditable-input.span9 { + width: 860px; + } + input.span10, textarea.span10, .uneditable-input.span10 { + width: 960px; + } + input.span11, textarea.span11, .uneditable-input.span11 { + width: 1060px; + } + input.span12, textarea.span12, .uneditable-input.span12 { + width: 1160px; + } + .thumbnails { + margin-left: -30px; + } + .thumbnails > li { + margin-left: 30px; + } +} diff --git a/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css b/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css new file mode 100644 index 0000000..6229c12 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css @@ -0,0 +1,3521 @@ +/*! + * Bootstrap v2.0.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +nav, +section { + display: block; +} +audio, canvas, video { + display: inline-block; + *display: inline; + *zoom: 1; +} +audio:not([controls]) { + display: none; +} +html { + font-size: 100%; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} +a:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +a:hover, a:active { + outline: 0; +} +sub, sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} +sup { + top: -0.5em; +} +sub { + bottom: -0.25em; +} +img { + max-width: 100%; + height: auto; + border: 0; + -ms-interpolation-mode: bicubic; +} +button, +input, +select, +textarea { + margin: 0; + font-size: 100%; + vertical-align: middle; +} +button, input { + *overflow: visible; + line-height: normal; +} +button::-moz-focus-inner, input::-moz-focus-inner { + padding: 0; + border: 0; +} +button, +input[type="button"], +input[type="reset"], +input[type="submit"] { + cursor: pointer; + -webkit-appearance: button; +} +input[type="search"] { + -webkit-appearance: textfield; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +input[type="search"]::-webkit-search-decoration, input[type="search"]::-webkit-search-cancel-button { + -webkit-appearance: none; +} +textarea { + overflow: auto; + vertical-align: top; +} +.clearfix { + *zoom: 1; +} +.clearfix:before, .clearfix:after { + display: table; + content: ""; +} +.clearfix:after { + clear: both; +} +body { + margin: 0; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 18px; + color: #333333; + background-color: #ffffff; +} +a { + color: #0088cc; + text-decoration: none; +} +a:hover { + color: #005580; + text-decoration: underline; +} +.row { + margin-left: -20px; + *zoom: 1; +} +.row:before, .row:after { + display: table; + content: ""; +} +.row:after { + clear: both; +} +[class*="span"] { + float: left; + margin-left: 20px; +} +.span1 { + width: 60px; +} +.span2 { + width: 140px; +} +.span3 { + width: 220px; +} +.span4 { + width: 300px; +} +.span5 { + width: 380px; +} +.span6 { + width: 460px; +} +.span7 { + width: 540px; +} +.span8 { + width: 620px; +} +.span9 { + width: 700px; +} +.span10 { + width: 780px; +} +.span11 { + width: 860px; +} +.span12, .container { + width: 940px; +} +.offset1 { + margin-left: 100px; +} +.offset2 { + margin-left: 180px; +} +.offset3 { + margin-left: 260px; +} +.offset4 { + margin-left: 340px; +} +.offset5 { + margin-left: 420px; +} +.offset6 { + margin-left: 500px; +} +.offset7 { + margin-left: 580px; +} +.offset8 { + margin-left: 660px; +} +.offset9 { + margin-left: 740px; +} +.offset10 { + margin-left: 820px; +} +.offset11 { + margin-left: 900px; +} +.row-fluid { + width: 100%; + *zoom: 1; +} +.row-fluid:before, .row-fluid:after { + display: table; + content: ""; +} +.row-fluid:after { + clear: both; +} +.row-fluid > [class*="span"] { + float: left; + margin-left: 2.127659574%; +} +.row-fluid > [class*="span"]:first-child { + margin-left: 0; +} +.row-fluid > .span1 { + width: 6.382978723%; +} +.row-fluid > .span2 { + width: 14.89361702%; +} +.row-fluid > .span3 { + width: 23.404255317%; +} +.row-fluid > .span4 { + width: 31.914893614%; +} +.row-fluid > .span5 { + width: 40.425531911%; +} +.row-fluid > .span6 { + width: 48.93617020799999%; +} +.row-fluid > .span7 { + width: 57.446808505%; +} +.row-fluid > .span8 { + width: 65.95744680199999%; +} +.row-fluid > .span9 { + width: 74.468085099%; +} +.row-fluid > .span10 { + width: 82.97872339599999%; +} +.row-fluid > .span11 { + width: 91.489361693%; +} +.row-fluid > .span12 { + width: 99.99999998999999%; +} +.container { + width: 940px; + margin-left: auto; + margin-right: auto; + *zoom: 1; +} +.container:before, .container:after { + display: table; + content: ""; +} +.container:after { + clear: both; +} +.container-fluid { + padding-left: 20px; + padding-right: 20px; + *zoom: 1; +} +.container-fluid:before, .container-fluid:after { + display: table; + content: ""; +} +.container-fluid:after { + clear: both; +} +p { + margin: 0 0 9px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 18px; +} +p small { + font-size: 11px; + color: #999999; +} +.lead { + margin-bottom: 18px; + font-size: 20px; + font-weight: 200; + line-height: 27px; +} +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 0; + font-weight: bold; + color: #333333; + text-rendering: optimizelegibility; +} +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small { + font-weight: normal; + color: #999999; +} +h1 { + font-size: 30px; + line-height: 36px; +} +h1 small { + font-size: 18px; +} +h2 { + font-size: 24px; + line-height: 36px; +} +h2 small { + font-size: 18px; +} +h3 { + line-height: 27px; + font-size: 18px; +} +h3 small { + font-size: 14px; +} +h4, h5, h6 { + line-height: 18px; +} +h4 { + font-size: 14px; +} +h4 small { + font-size: 12px; +} +h5 { + font-size: 12px; +} +h6 { + font-size: 11px; + color: #999999; + text-transform: uppercase; +} +.page-header { + padding-bottom: 17px; + margin: 18px 0; + border-bottom: 1px solid #eeeeee; +} +.page-header h1 { + line-height: 1; +} +ul, ol { + padding: 0; + margin: 0 0 9px 25px; +} +ul ul, +ul ol, +ol ol, +ol ul { + margin-bottom: 0; +} +ul { + list-style: disc; +} +ol { + list-style: decimal; +} +li { + line-height: 18px; +} +ul.unstyled, ol.unstyled { + margin-left: 0; + list-style: none; +} +dl { + margin-bottom: 18px; +} +dt, dd { + line-height: 18px; +} +dt { + font-weight: bold; +} +dd { + margin-left: 9px; +} +hr { + margin: 18px 0; + border: 0; + border-top: 1px solid #eeeeee; + border-bottom: 1px solid #ffffff; +} +strong { + font-weight: bold; +} +em { + font-style: italic; +} +.muted { + color: #999999; +} +abbr { + font-size: 90%; + text-transform: uppercase; + border-bottom: 1px dotted #ddd; + cursor: help; +} +blockquote { + padding: 0 0 0 15px; + margin: 0 0 18px; + border-left: 5px solid #eeeeee; +} +blockquote p { + margin-bottom: 0; + font-size: 16px; + font-weight: 300; + line-height: 22.5px; +} +blockquote small { + display: block; + line-height: 18px; + color: #999999; +} +blockquote small:before { + content: '\2014 \00A0'; +} +blockquote.pull-right { + float: right; + padding-left: 0; + padding-right: 15px; + border-left: 0; + border-right: 5px solid #eeeeee; +} +blockquote.pull-right p, blockquote.pull-right small { + text-align: right; +} +q:before, +q:after, +blockquote:before, +blockquote:after { + content: ""; +} +address { + display: block; + margin-bottom: 18px; + line-height: 18px; + font-style: normal; +} +small { + font-size: 100%; +} +cite { + font-style: normal; +} +code, pre { + padding: 0 3px 2px; + font-family: Menlo, Monaco, "Courier New", monospace; + font-size: 12px; + color: #333333; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +code { + padding: 3px 4px; + color: #d14; + background-color: #f7f7f9; + border: 1px solid #e1e1e8; +} +pre { + display: block; + padding: 8.5px; + margin: 0 0 9px; + font-size: 12px; + line-height: 18px; + background-color: #f5f5f5; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.15); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + white-space: pre; + white-space: pre-wrap; + word-break: break-all; + word-wrap: break-word; +} +pre.prettyprint { + margin-bottom: 18px; +} +pre code { + padding: 0; + color: inherit; + background-color: transparent; + border: 0; +} +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} +form { + margin: 0 0 18px; +} +fieldset { + padding: 0; + margin: 0; + border: 0; +} +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 27px; + font-size: 19.5px; + line-height: 36px; + color: #333333; + border: 0; + border-bottom: 1px solid #eee; +} +legend small { + font-size: 13.5px; + color: #999999; +} +label, +input, +button, +select, +textarea { + font-size: 13px; + font-weight: normal; + line-height: 18px; +} +input, +button, +select, +textarea { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; +} +label { + display: block; + margin-bottom: 5px; + color: #333333; +} +input, +textarea, +select, +.uneditable-input { + display: inline-block; + width: 210px; + height: 18px; + padding: 4px; + margin-bottom: 9px; + font-size: 13px; + line-height: 18px; + color: #555555; + border: 1px solid #ccc; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.uneditable-textarea { + width: auto; + height: auto; +} +label input, label textarea, label select { + display: block; +} +input[type="image"], input[type="checkbox"], input[type="radio"] { + width: auto; + height: auto; + padding: 0; + margin: 3px 0; + *margin-top: 0; + /* IE7 */ + + line-height: normal; + cursor: pointer; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + border: 0 \9; + /* IE9 and down */ + +} +input[type="image"] { + border: 0; +} +input[type="file"] { + width: auto; + padding: initial; + line-height: initial; + border: initial; + background-color: #ffffff; + background-color: initial; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +input[type="button"], input[type="reset"], input[type="submit"] { + width: auto; + height: auto; +} +select, input[type="file"] { + height: 28px; + /* In IE7, the height of the select element cannot be changed by height, only font-size */ + + *margin-top: 4px; + /* For IE7, add top margin to align select with labels */ + + line-height: 28px; +} +input[type="file"] { + line-height: 18px \9; +} +select { + width: 220px; + background-color: #ffffff; +} +select[multiple], select[size] { + height: auto; +} +input[type="image"] { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +textarea { + height: auto; +} +input[type="hidden"] { + display: none; +} +.radio, .checkbox { + padding-left: 18px; +} +.radio input[type="radio"], .checkbox input[type="checkbox"] { + float: left; + margin-left: -18px; +} +.controls > .radio:first-child, .controls > .checkbox:first-child { + padding-top: 5px; +} +.radio.inline, .checkbox.inline { + display: inline-block; + padding-top: 5px; + margin-bottom: 0; + vertical-align: middle; +} +.radio.inline + .radio.inline, .checkbox.inline + .checkbox.inline { + margin-left: 10px; +} +input, textarea { + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; + -moz-transition: border linear 0.2s, box-shadow linear 0.2s; + -ms-transition: border linear 0.2s, box-shadow linear 0.2s; + -o-transition: border linear 0.2s, box-shadow linear 0.2s; + transition: border linear 0.2s, box-shadow linear 0.2s; +} +input:focus, textarea:focus { + border-color: rgba(82, 168, 236, 0.8); + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + outline: 0; + outline: thin dotted \9; + /* IE6-9 */ + +} +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus, +select:focus { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.input-mini { + width: 60px; +} +.input-small { + width: 90px; +} +.input-medium { + width: 150px; +} +.input-large { + width: 210px; +} +.input-xlarge { + width: 270px; +} +.input-xxlarge { + width: 530px; +} +input[class*="span"], +select[class*="span"], +textarea[class*="span"], +.uneditable-input { + float: none; + margin-left: 0; +} +input.span1, textarea.span1, .uneditable-input.span1 { + width: 50px; +} +input.span2, textarea.span2, .uneditable-input.span2 { + width: 130px; +} +input.span3, textarea.span3, .uneditable-input.span3 { + width: 210px; +} +input.span4, textarea.span4, .uneditable-input.span4 { + width: 290px; +} +input.span5, textarea.span5, .uneditable-input.span5 { + width: 370px; +} +input.span6, textarea.span6, .uneditable-input.span6 { + width: 450px; +} +input.span7, textarea.span7, .uneditable-input.span7 { + width: 530px; +} +input.span8, textarea.span8, .uneditable-input.span8 { + width: 610px; +} +input.span9, textarea.span9, .uneditable-input.span9 { + width: 690px; +} +input.span10, textarea.span10, .uneditable-input.span10 { + width: 770px; +} +input.span11, textarea.span11, .uneditable-input.span11 { + width: 850px; +} +input.span12, textarea.span12, .uneditable-input.span12 { + width: 930px; +} +input[disabled], +select[disabled], +textarea[disabled], +input[readonly], +select[readonly], +textarea[readonly] { + background-color: #f5f5f5; + border-color: #ddd; + cursor: not-allowed; +} +.control-group.warning > label, .control-group.warning .help-block, .control-group.warning .help-inline { + color: #c09853; +} +.control-group.warning input, .control-group.warning select, .control-group.warning textarea { + color: #c09853; + border-color: #c09853; +} +.control-group.warning input:focus, .control-group.warning select:focus, .control-group.warning textarea:focus { + border-color: #a47e3c; + -webkit-box-shadow: 0 0 6px #dbc59e; + -moz-box-shadow: 0 0 6px #dbc59e; + box-shadow: 0 0 6px #dbc59e; +} +.control-group.warning .input-prepend .add-on, .control-group.warning .input-append .add-on { + color: #c09853; + background-color: #fcf8e3; + border-color: #c09853; +} +.control-group.error > label, .control-group.error .help-block, .control-group.error .help-inline { + color: #b94a48; +} +.control-group.error input, .control-group.error select, .control-group.error textarea { + color: #b94a48; + border-color: #b94a48; +} +.control-group.error input:focus, .control-group.error select:focus, .control-group.error textarea:focus { + border-color: #953b39; + -webkit-box-shadow: 0 0 6px #d59392; + -moz-box-shadow: 0 0 6px #d59392; + box-shadow: 0 0 6px #d59392; +} +.control-group.error .input-prepend .add-on, .control-group.error .input-append .add-on { + color: #b94a48; + background-color: #f2dede; + border-color: #b94a48; +} +.control-group.success > label, .control-group.success .help-block, .control-group.success .help-inline { + color: #468847; +} +.control-group.success input, .control-group.success select, .control-group.success textarea { + color: #468847; + border-color: #468847; +} +.control-group.success input:focus, .control-group.success select:focus, .control-group.success textarea:focus { + border-color: #356635; + -webkit-box-shadow: 0 0 6px #7aba7b; + -moz-box-shadow: 0 0 6px #7aba7b; + box-shadow: 0 0 6px #7aba7b; +} +.control-group.success .input-prepend .add-on, .control-group.success .input-append .add-on { + color: #468847; + background-color: #dff0d8; + border-color: #468847; +} +input:focus:required:invalid, textarea:focus:required:invalid, select:focus:required:invalid { + color: #b94a48; + border-color: #ee5f5b; +} +input:focus:required:invalid:focus, textarea:focus:required:invalid:focus, select:focus:required:invalid:focus { + border-color: #e9322d; + -webkit-box-shadow: 0 0 6px #f8b9b7; + -moz-box-shadow: 0 0 6px #f8b9b7; + box-shadow: 0 0 6px #f8b9b7; +} +.form-actions { + padding: 17px 20px 18px; + margin-top: 18px; + margin-bottom: 18px; + background-color: #f5f5f5; + border-top: 1px solid #ddd; +} +.uneditable-input { + display: block; + background-color: #ffffff; + border-color: #eee; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + cursor: not-allowed; +} +:-moz-placeholder { + color: #999999; +} +::-webkit-input-placeholder { + color: #999999; +} +.help-block { + display: block; + margin-top: 5px; + margin-bottom: 0; + color: #999999; +} +.help-inline { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; + margin-bottom: 9px; + vertical-align: middle; + padding-left: 5px; +} +.input-prepend, .input-append { + margin-bottom: 5px; + *zoom: 1; +} +.input-prepend:before, +.input-append:before, +.input-prepend:after, +.input-append:after { + display: table; + content: ""; +} +.input-prepend:after, .input-append:after { + clear: both; +} +.input-prepend input, +.input-append input, +.input-prepend .uneditable-input, +.input-append .uneditable-input { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.input-prepend input:focus, +.input-append input:focus, +.input-prepend .uneditable-input:focus, +.input-append .uneditable-input:focus { + position: relative; + z-index: 2; +} +.input-prepend .uneditable-input, .input-append .uneditable-input { + border-left-color: #ccc; +} +.input-prepend .add-on, .input-append .add-on { + float: left; + display: block; + width: auto; + min-width: 16px; + height: 18px; + margin-right: -1px; + padding: 4px 5px; + font-weight: normal; + line-height: 18px; + color: #999999; + text-align: center; + text-shadow: 0 1px 0 #ffffff; + background-color: #f5f5f5; + border: 1px solid #ccc; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.input-prepend .active, .input-append .active { + background-color: #a9dba9; + border-color: #46a546; +} +.input-prepend .add-on { + *margin-top: 1px; + /* IE6-7 */ + +} +.input-append input, .input-append .uneditable-input { + float: left; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.input-append .uneditable-input { + border-left-color: #eee; + border-right-color: #ccc; +} +.input-append .add-on { + margin-right: 0; + margin-left: -1px; + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.input-append input:first-child { + *margin-left: -160px; +} +.input-append input:first-child + .add-on { + *margin-left: -21px; +} +.search-query { + padding-left: 14px; + padding-right: 14px; + margin-bottom: 0; + -webkit-border-radius: 14px; + -moz-border-radius: 14px; + border-radius: 14px; +} +.form-search input, +.form-inline input, +.form-horizontal input, +.form-search textarea, +.form-inline textarea, +.form-horizontal textarea, +.form-search select, +.form-inline select, +.form-horizontal select, +.form-search .help-inline, +.form-inline .help-inline, +.form-horizontal .help-inline, +.form-search .uneditable-input, +.form-inline .uneditable-input, +.form-horizontal .uneditable-input { + display: inline-block; + margin-bottom: 0; +} +.form-search .hide, .form-inline .hide, .form-horizontal .hide { + display: none; +} +.form-search label, +.form-inline label, +.form-search .input-append, +.form-inline .input-append, +.form-search .input-prepend, +.form-inline .input-prepend { + display: inline-block; +} +.form-search .input-append .add-on, +.form-inline .input-prepend .add-on, +.form-search .input-append .add-on, +.form-inline .input-prepend .add-on { + vertical-align: middle; +} +.form-search .radio, +.form-inline .radio, +.form-search .checkbox, +.form-inline .checkbox { + margin-bottom: 0; + vertical-align: middle; +} +.control-group { + margin-bottom: 9px; +} +legend + .control-group { + margin-top: 18px; + -webkit-margin-top-collapse: separate; +} +.form-horizontal .control-group { + margin-bottom: 18px; + *zoom: 1; +} +.form-horizontal .control-group:before, .form-horizontal .control-group:after { + display: table; + content: ""; +} +.form-horizontal .control-group:after { + clear: both; +} +.form-horizontal .control-label { + float: left; + width: 140px; + padding-top: 5px; + text-align: right; +} +.form-horizontal .controls { + margin-left: 160px; +} +.form-horizontal .form-actions { + padding-left: 160px; +} +table { + max-width: 100%; + border-collapse: collapse; + border-spacing: 0; +} +.table { + width: 100%; + margin-bottom: 18px; +} +.table th, .table td { + padding: 8px; + line-height: 18px; + text-align: left; + vertical-align: top; + border-top: 1px solid #ddd; +} +.table th { + font-weight: bold; +} +.table thead th { + vertical-align: bottom; +} +.table thead:first-child tr th, .table thead:first-child tr td { + border-top: 0; +} +.table tbody + tbody { + border-top: 2px solid #ddd; +} +.table-condensed th, .table-condensed td { + padding: 4px 5px; +} +.table-bordered { + border: 1px solid #ddd; + border-collapse: separate; + *border-collapse: collapsed; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.table-bordered th + th, +.table-bordered td + td, +.table-bordered th + td, +.table-bordered td + th { + border-left: 1px solid #ddd; +} +.table-bordered thead:first-child tr:first-child th, .table-bordered tbody:first-child tr:first-child th, .table-bordered tbody:first-child tr:first-child td { + border-top: 0; +} +.table-bordered thead:first-child tr:first-child th:first-child, .table-bordered tbody:first-child tr:first-child td:first-child { + -webkit-border-radius: 4px 0 0 0; + -moz-border-radius: 4px 0 0 0; + border-radius: 4px 0 0 0; +} +.table-bordered thead:first-child tr:first-child th:last-child, .table-bordered tbody:first-child tr:first-child td:last-child { + -webkit-border-radius: 0 4px 0 0; + -moz-border-radius: 0 4px 0 0; + border-radius: 0 4px 0 0; +} +.table-bordered thead:last-child tr:last-child th:first-child, .table-bordered tbody:last-child tr:last-child td:first-child { + -webkit-border-radius: 0 0 0 4px; + -moz-border-radius: 0 0 0 4px; + border-radius: 0 0 0 4px; +} +.table-bordered thead:last-child tr:last-child th:last-child, .table-bordered tbody:last-child tr:last-child td:last-child { + -webkit-border-radius: 0 0 4px 0; + -moz-border-radius: 0 0 4px 0; + border-radius: 0 0 4px 0; +} +.table-striped tbody tr:nth-child(odd) td, .table-striped tbody tr:nth-child(odd) th { + background-color: #f9f9f9; +} +.table tbody tr:hover td, .table tbody tr:hover th { + background-color: #f5f5f5; +} +table .span1 { + float: none; + width: 44px; + margin-left: 0; +} +table .span2 { + float: none; + width: 124px; + margin-left: 0; +} +table .span3 { + float: none; + width: 204px; + margin-left: 0; +} +table .span4 { + float: none; + width: 284px; + margin-left: 0; +} +table .span5 { + float: none; + width: 364px; + margin-left: 0; +} +table .span6 { + float: none; + width: 444px; + margin-left: 0; +} +table .span7 { + float: none; + width: 524px; + margin-left: 0; +} +table .span8 { + float: none; + width: 604px; + margin-left: 0; +} +table .span9 { + float: none; + width: 684px; + margin-left: 0; +} +table .span10 { + float: none; + width: 764px; + margin-left: 0; +} +table .span11 { + float: none; + width: 844px; + margin-left: 0; +} +table .span12 { + float: none; + width: 924px; + margin-left: 0; +} +[class^="icon-"], [class*=" icon-"] { + display: inline-block; + width: 14px; + height: 14px; + line-height: 14px; + vertical-align: text-top; + background-image: url("../img/glyphicons-halflings.png"); + background-position: 14px 14px; + background-repeat: no-repeat; + *margin-right: .3em; +} +[class^="icon-"]:last-child, [class*=" icon-"]:last-child { + *margin-left: 0; +} +.icon-white { + background-image: url("../img/glyphicons-halflings-white.png"); +} +.icon-glass { + background-position: 0 0; +} +.icon-music { + background-position: -24px 0; +} +.icon-search { + background-position: -48px 0; +} +.icon-envelope { + background-position: -72px 0; +} +.icon-heart { + background-position: -96px 0; +} +.icon-star { + background-position: -120px 0; +} +.icon-star-empty { + background-position: -144px 0; +} +.icon-user { + background-position: -168px 0; +} +.icon-film { + background-position: -192px 0; +} +.icon-th-large { + background-position: -216px 0; +} +.icon-th { + background-position: -240px 0; +} +.icon-th-list { + background-position: -264px 0; +} +.icon-ok { + background-position: -288px 0; +} +.icon-remove { + background-position: -312px 0; +} +.icon-zoom-in { + background-position: -336px 0; +} +.icon-zoom-out { + background-position: -360px 0; +} +.icon-off { + background-position: -384px 0; +} +.icon-signal { + background-position: -408px 0; +} +.icon-cog { + background-position: -432px 0; +} +.icon-trash { + background-position: -456px 0; +} +.icon-home { + background-position: 0 -24px; +} +.icon-file { + background-position: -24px -24px; +} +.icon-time { + background-position: -48px -24px; +} +.icon-road { + background-position: -72px -24px; +} +.icon-download-alt { + background-position: -96px -24px; +} +.icon-download { + background-position: -120px -24px; +} +.icon-upload { + background-position: -144px -24px; +} +.icon-inbox { + background-position: -168px -24px; +} +.icon-play-circle { + background-position: -192px -24px; +} +.icon-repeat { + background-position: -216px -24px; +} +.icon-refresh { + background-position: -240px -24px; +} +.icon-list-alt { + background-position: -264px -24px; +} +.icon-lock { + background-position: -287px -24px; +} +.icon-flag { + background-position: -312px -24px; +} +.icon-headphones { + background-position: -336px -24px; +} +.icon-volume-off { + background-position: -360px -24px; +} +.icon-volume-down { + background-position: -384px -24px; +} +.icon-volume-up { + background-position: -408px -24px; +} +.icon-qrcode { + background-position: -432px -24px; +} +.icon-barcode { + background-position: -456px -24px; +} +.icon-tag { + background-position: 0 -48px; +} +.icon-tags { + background-position: -25px -48px; +} +.icon-book { + background-position: -48px -48px; +} +.icon-bookmark { + background-position: -72px -48px; +} +.icon-print { + background-position: -96px -48px; +} +.icon-camera { + background-position: -120px -48px; +} +.icon-font { + background-position: -144px -48px; +} +.icon-bold { + background-position: -167px -48px; +} +.icon-italic { + background-position: -192px -48px; +} +.icon-text-height { + background-position: -216px -48px; +} +.icon-text-width { + background-position: -240px -48px; +} +.icon-align-left { + background-position: -264px -48px; +} +.icon-align-center { + background-position: -288px -48px; +} +.icon-align-right { + background-position: -312px -48px; +} +.icon-align-justify { + background-position: -336px -48px; +} +.icon-list { + background-position: -360px -48px; +} +.icon-indent-left { + background-position: -384px -48px; +} +.icon-indent-right { + background-position: -408px -48px; +} +.icon-facetime-video { + background-position: -432px -48px; +} +.icon-picture { + background-position: -456px -48px; +} +.icon-pencil { + background-position: 0 -72px; +} +.icon-map-marker { + background-position: -24px -72px; +} +.icon-adjust { + background-position: -48px -72px; +} +.icon-tint { + background-position: -72px -72px; +} +.icon-edit { + background-position: -96px -72px; +} +.icon-share { + background-position: -120px -72px; +} +.icon-check { + background-position: -144px -72px; +} +.icon-move { + background-position: -168px -72px; +} +.icon-step-backward { + background-position: -192px -72px; +} +.icon-fast-backward { + background-position: -216px -72px; +} +.icon-backward { + background-position: -240px -72px; +} +.icon-play { + background-position: -264px -72px; +} +.icon-pause { + background-position: -288px -72px; +} +.icon-stop { + background-position: -312px -72px; +} +.icon-forward { + background-position: -336px -72px; +} +.icon-fast-forward { + background-position: -360px -72px; +} +.icon-step-forward { + background-position: -384px -72px; +} +.icon-eject { + background-position: -408px -72px; +} +.icon-chevron-left { + background-position: -432px -72px; +} +.icon-chevron-right { + background-position: -456px -72px; +} +.icon-plus-sign { + background-position: 0 -96px; +} +.icon-minus-sign { + background-position: -24px -96px; +} +.icon-remove-sign { + background-position: -48px -96px; +} +.icon-ok-sign { + background-position: -72px -96px; +} +.icon-question-sign { + background-position: -96px -96px; +} +.icon-info-sign { + background-position: -120px -96px; +} +.icon-screenshot { + background-position: -144px -96px; +} +.icon-remove-circle { + background-position: -168px -96px; +} +.icon-ok-circle { + background-position: -192px -96px; +} +.icon-ban-circle { + background-position: -216px -96px; +} +.icon-arrow-left { + background-position: -240px -96px; +} +.icon-arrow-right { + background-position: -264px -96px; +} +.icon-arrow-up { + background-position: -289px -96px; +} +.icon-arrow-down { + background-position: -312px -96px; +} +.icon-share-alt { + background-position: -336px -96px; +} +.icon-resize-full { + background-position: -360px -96px; +} +.icon-resize-small { + background-position: -384px -96px; +} +.icon-plus { + background-position: -408px -96px; +} +.icon-minus { + background-position: -433px -96px; +} +.icon-asterisk { + background-position: -456px -96px; +} +.icon-exclamation-sign { + background-position: 0 -120px; +} +.icon-gift { + background-position: -24px -120px; +} +.icon-leaf { + background-position: -48px -120px; +} +.icon-fire { + background-position: -72px -120px; +} +.icon-eye-open { + background-position: -96px -120px; +} +.icon-eye-close { + background-position: -120px -120px; +} +.icon-warning-sign { + background-position: -144px -120px; +} +.icon-plane { + background-position: -168px -120px; +} +.icon-calendar { + background-position: -192px -120px; +} +.icon-random { + background-position: -216px -120px; +} +.icon-comment { + background-position: -240px -120px; +} +.icon-magnet { + background-position: -264px -120px; +} +.icon-chevron-up { + background-position: -288px -120px; +} +.icon-chevron-down { + background-position: -313px -119px; +} +.icon-retweet { + background-position: -336px -120px; +} +.icon-shopping-cart { + background-position: -360px -120px; +} +.icon-folder-close { + background-position: -384px -120px; +} +.icon-folder-open { + background-position: -408px -120px; +} +.icon-resize-vertical { + background-position: -432px -119px; +} +.icon-resize-horizontal { + background-position: -456px -118px; +} +.dropdown { + position: relative; +} +.dropdown-toggle { + *margin-bottom: -3px; +} +.dropdown-toggle:active, .open .dropdown-toggle { + outline: 0; +} +.caret { + display: inline-block; + width: 0; + height: 0; + text-indent: -99999px; + *text-indent: 0; + vertical-align: top; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 4px solid #000000; + opacity: 0.3; + filter: alpha(opacity=30); + content: "\2193"; +} +.dropdown .caret { + margin-top: 8px; + margin-left: 2px; +} +.dropdown:hover .caret, .open.dropdown .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + float: left; + display: none; + min-width: 160px; + _width: 160px; + padding: 4px 0; + margin: 0; + list-style: none; + background-color: #ffffff; + border-color: #ccc; + border-color: rgba(0, 0, 0, 0.2); + border-style: solid; + border-width: 1px; + -webkit-border-radius: 0 0 5px 5px; + -moz-border-radius: 0 0 5px 5px; + border-radius: 0 0 5px 5px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; + *border-right-width: 2px; + *border-bottom-width: 2px; +} +.dropdown-menu.bottom-up { + top: auto; + bottom: 100%; + margin-bottom: 2px; +} +.dropdown-menu .divider { + height: 1px; + margin: 5px 1px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #ffffff; + *width: 100%; + *margin: -5px 0 5px; +} +.dropdown-menu a { + display: block; + padding: 3px 15px; + clear: both; + font-weight: normal; + line-height: 18px; + color: #555555; + white-space: nowrap; +} +.dropdown-menu li > a:hover, .dropdown-menu .active > a, .dropdown-menu .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #0088cc; +} +.dropdown.open { + *z-index: 1000; +} +.dropdown.open .dropdown-toggle { + color: #ffffff; + background: #ccc; + background: rgba(0, 0, 0, 0.3); +} +.dropdown.open .dropdown-menu { + display: block; +} +.typeahead { + margin-top: 2px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #f5f5f5; + border: 1px solid #eee; + border: 1px solid rgba(0, 0, 0, 0.05); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 0, 0, 0.15); +} +.fade { + -webkit-transition: opacity 0.15s linear; + -moz-transition: opacity 0.15s linear; + -ms-transition: opacity 0.15s linear; + -o-transition: opacity 0.15s linear; + transition: opacity 0.15s linear; + opacity: 0; +} +.fade.in { + opacity: 1; +} +.collapse { + -webkit-transition: height 0.35s ease; + -moz-transition: height 0.35s ease; + -ms-transition: height 0.35s ease; + -o-transition: height 0.35s ease; + transition: height 0.35s ease; + position: relative; + overflow: hidden; + height: 0; +} +.collapse.in { + height: auto; +} +.close { + float: right; + font-size: 20px; + font-weight: bold; + line-height: 18px; + color: #000000; + text-shadow: 0 1px 0 #ffffff; + opacity: 0.2; + filter: alpha(opacity=20); +} +.close:hover { + color: #000000; + text-decoration: none; + opacity: 0.4; + filter: alpha(opacity=40); + cursor: pointer; +} +.btn { + display: inline-block; + padding: 4px 10px 4px; + margin-bottom: 0; + font-size: 13px; + line-height: 18px; + color: #333333; + text-align: center; + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); + vertical-align: middle; + background-color: #f5f5f5; + background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); + background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); + background-image: linear-gradient(top, #ffffff, #e6e6e6); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0); + border-color: #e6e6e6 #e6e6e6 #bfbfbf; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + border: 1px solid #ccc; + border-bottom-color: #bbb; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + cursor: pointer; + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + *margin-left: .3em; +} +.btn:hover, +.btn:active, +.btn.active, +.btn.disabled, +.btn[disabled] { + background-color: #e6e6e6; +} +.btn:active, .btn.active { + background-color: #cccccc \9; +} +.btn:first-child { + *margin-left: 0; +} +.btn:hover { + color: #333333; + text-decoration: none; + background-color: #e6e6e6; + background-position: 0 -15px; + -webkit-transition: background-position 0.1s linear; + -moz-transition: background-position 0.1s linear; + -ms-transition: background-position 0.1s linear; + -o-transition: background-position 0.1s linear; + transition: background-position 0.1s linear; +} +.btn:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.btn.active, .btn:active { + background-image: none; + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + background-color: #e6e6e6; + background-color: #d9d9d9 \9; + outline: 0; +} +.btn.disabled, .btn[disabled] { + cursor: default; + background-image: none; + background-color: #e6e6e6; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +.btn-large { + padding: 9px 14px; + font-size: 15px; + line-height: normal; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.btn-large [class^="icon-"] { + margin-top: 1px; +} +.btn-small { + padding: 5px 9px; + font-size: 11px; + line-height: 16px; +} +.btn-small [class^="icon-"] { + margin-top: -1px; +} +.btn-mini { + padding: 2px 6px; + font-size: 11px; + line-height: 14px; +} +.btn-primary, +.btn-primary:hover, +.btn-warning, +.btn-warning:hover, +.btn-danger, +.btn-danger:hover, +.btn-success, +.btn-success:hover, +.btn-info, +.btn-info:hover, +.btn-inverse, +.btn-inverse:hover { + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + color: #ffffff; +} +.btn-primary.active, +.btn-warning.active, +.btn-danger.active, +.btn-success.active, +.btn-info.active, +.btn-dark.active { + color: rgba(255, 255, 255, 0.75); +} +.btn-primary { + background-color: #006dcc; + background-image: -moz-linear-gradient(top, #0088cc, #0044cc); + background-image: -ms-linear-gradient(top, #0088cc, #0044cc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); + background-image: -o-linear-gradient(top, #0088cc, #0044cc); + background-image: linear-gradient(top, #0088cc, #0044cc); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); + border-color: #0044cc #0044cc #002a80; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-primary:hover, +.btn-primary:active, +.btn-primary.active, +.btn-primary.disabled, +.btn-primary[disabled] { + background-color: #0044cc; +} +.btn-primary:active, .btn-primary.active { + background-color: #003399 \9; +} +.btn-warning { + background-color: #faa732; + background-image: -moz-linear-gradient(top, #fbb450, #f89406); + background-image: -ms-linear-gradient(top, #fbb450, #f89406); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); + background-image: -webkit-linear-gradient(top, #fbb450, #f89406); + background-image: -o-linear-gradient(top, #fbb450, #f89406); + background-image: linear-gradient(top, #fbb450, #f89406); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0); + border-color: #f89406 #f89406 #ad6704; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-warning:hover, +.btn-warning:active, +.btn-warning.active, +.btn-warning.disabled, +.btn-warning[disabled] { + background-color: #f89406; +} +.btn-warning:active, .btn-warning.active { + background-color: #c67605 \9; +} +.btn-danger { + background-color: #da4f49; + background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -ms-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -o-linear-gradient(top, #ee5f5b, #bd362f); + background-image: linear-gradient(top, #ee5f5b, #bd362f); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0); + border-color: #bd362f #bd362f #802420; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-danger:hover, +.btn-danger:active, +.btn-danger.active, +.btn-danger.disabled, +.btn-danger[disabled] { + background-color: #bd362f; +} +.btn-danger:active, .btn-danger.active { + background-color: #942a25 \9; +} +.btn-success { + background-color: #5bb75b; + background-image: -moz-linear-gradient(top, #62c462, #51a351); + background-image: -ms-linear-gradient(top, #62c462, #51a351); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351)); + background-image: -webkit-linear-gradient(top, #62c462, #51a351); + background-image: -o-linear-gradient(top, #62c462, #51a351); + background-image: linear-gradient(top, #62c462, #51a351); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0); + border-color: #51a351 #51a351 #387038; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-success:hover, +.btn-success:active, +.btn-success.active, +.btn-success.disabled, +.btn-success[disabled] { + background-color: #51a351; +} +.btn-success:active, .btn-success.active { + background-color: #408140 \9; +} +.btn-info { + background-color: #49afcd; + background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -ms-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4)); + background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -o-linear-gradient(top, #5bc0de, #2f96b4); + background-image: linear-gradient(top, #5bc0de, #2f96b4); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0); + border-color: #2f96b4 #2f96b4 #1f6377; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-info:hover, +.btn-info:active, +.btn-info.active, +.btn-info.disabled, +.btn-info[disabled] { + background-color: #2f96b4; +} +.btn-info:active, .btn-info.active { + background-color: #24748c \9; +} +.btn-inverse { + background-color: #393939; + background-image: -moz-linear-gradient(top, #454545, #262626); + background-image: -ms-linear-gradient(top, #454545, #262626); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#454545), to(#262626)); + background-image: -webkit-linear-gradient(top, #454545, #262626); + background-image: -o-linear-gradient(top, #454545, #262626); + background-image: linear-gradient(top, #454545, #262626); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#454545', endColorstr='#262626', GradientType=0); + border-color: #262626 #262626 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-inverse:hover, +.btn-inverse:active, +.btn-inverse.active, +.btn-inverse.disabled, +.btn-inverse[disabled] { + background-color: #262626; +} +.btn-inverse:active, .btn-inverse.active { + background-color: #0c0c0c \9; +} +button.btn, input[type="submit"].btn { + *padding-top: 2px; + *padding-bottom: 2px; +} +button.btn::-moz-focus-inner, input[type="submit"].btn::-moz-focus-inner { + padding: 0; + border: 0; +} +button.btn.large, input[type="submit"].btn.large { + *padding-top: 7px; + *padding-bottom: 7px; +} +button.btn.small, input[type="submit"].btn.small { + *padding-top: 3px; + *padding-bottom: 3px; +} +.btn-group { + position: relative; + *zoom: 1; + *margin-left: .3em; +} +.btn-group:before, .btn-group:after { + display: table; + content: ""; +} +.btn-group:after { + clear: both; +} +.btn-group:first-child { + *margin-left: 0; +} +.btn-group + .btn-group { + margin-left: 5px; +} +.btn-toolbar { + margin-top: 9px; + margin-bottom: 9px; +} +.btn-toolbar .btn-group { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; +} +.btn-group .btn { + position: relative; + float: left; + margin-left: -1px; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.btn-group .btn:first-child { + margin-left: 0; + -webkit-border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; + border-top-left-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + border-bottom-left-radius: 4px; +} +.btn-group .btn:last-child, .btn-group .dropdown-toggle { + -webkit-border-top-right-radius: 4px; + -moz-border-radius-topright: 4px; + border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -moz-border-radius-bottomright: 4px; + border-bottom-right-radius: 4px; +} +.btn-group .btn.large:first-child { + margin-left: 0; + -webkit-border-top-left-radius: 6px; + -moz-border-radius-topleft: 6px; + border-top-left-radius: 6px; + -webkit-border-bottom-left-radius: 6px; + -moz-border-radius-bottomleft: 6px; + border-bottom-left-radius: 6px; +} +.btn-group .btn.large:last-child, .btn-group .large.dropdown-toggle { + -webkit-border-top-right-radius: 6px; + -moz-border-radius-topright: 6px; + border-top-right-radius: 6px; + -webkit-border-bottom-right-radius: 6px; + -moz-border-radius-bottomright: 6px; + border-bottom-right-radius: 6px; +} +.btn-group .btn:hover, +.btn-group .btn:focus, +.btn-group .btn:active, +.btn-group .btn.active { + z-index: 2; +} +.btn-group .dropdown-toggle:active, .btn-group.open .dropdown-toggle { + outline: 0; +} +.btn-group .dropdown-toggle { + padding-left: 8px; + padding-right: 8px; + -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + *padding-top: 5px; + *padding-bottom: 5px; +} +.btn-group.open { + *z-index: 1000; +} +.btn-group.open .dropdown-menu { + display: block; + margin-top: 1px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.btn-group.open .dropdown-toggle { + background-image: none; + -webkit-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); +} +.btn .caret { + margin-top: 7px; + margin-left: 0; +} +.btn:hover .caret, .open.btn-group .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.btn-primary .caret, +.btn-danger .caret, +.btn-info .caret, +.btn-success .caret, +.btn-inverse .caret { + border-top-color: #ffffff; + opacity: 0.75; + filter: alpha(opacity=75); +} +.btn-small .caret { + margin-top: 4px; +} +.alert { + padding: 8px 35px 8px 14px; + margin-bottom: 18px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + background-color: #fcf8e3; + border: 1px solid #fbeed5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.alert, .alert-heading { + color: #c09853; +} +.alert .close { + position: relative; + top: -2px; + right: -21px; + line-height: 18px; +} +.alert-success { + background-color: #dff0d8; + border-color: #d6e9c6; +} +.alert-success, .alert-success .alert-heading { + color: #468847; +} +.alert-danger, .alert-error { + background-color: #f2dede; + border-color: #eed3d7; +} +.alert-danger, +.alert-error, +.alert-danger .alert-heading, +.alert-error .alert-heading { + color: #b94a48; +} +.alert-info { + background-color: #d9edf7; + border-color: #bce8f1; +} +.alert-info, .alert-info .alert-heading { + color: #3a87ad; +} +.alert-block { + padding-top: 14px; + padding-bottom: 14px; +} +.alert-block > p, .alert-block > ul { + margin-bottom: 0; +} +.alert-block p + p { + margin-top: 5px; +} +.nav { + margin-left: 0; + margin-bottom: 18px; + list-style: none; +} +.nav > li > a { + display: block; +} +.nav > li > a:hover { + text-decoration: none; + background-color: #eeeeee; +} +.nav .nav-header { + display: block; + padding: 3px 15px; + font-size: 11px; + font-weight: bold; + line-height: 18px; + color: #999999; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + text-transform: uppercase; +} +.nav li + .nav-header { + margin-top: 9px; +} +.nav-list { + padding-left: 14px; + padding-right: 14px; + margin-bottom: 0; +} +.nav-list > li > a, .nav-list .nav-header { + margin-left: -15px; + margin-right: -15px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); +} +.nav-list > li > a { + padding: 3px 15px; +} +.nav-list .active > a, .nav-list .active > a:hover { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); + background-color: #0088cc; +} +.nav-list [class^="icon-"] { + margin-right: 2px; +} +.nav-tabs, .nav-pills { + *zoom: 1; +} +.nav-tabs:before, +.nav-pills:before, +.nav-tabs:after, +.nav-pills:after { + display: table; + content: ""; +} +.nav-tabs:after, .nav-pills:after { + clear: both; +} +.nav-tabs > li, .nav-pills > li { + float: left; +} +.nav-tabs > li > a, .nav-pills > li > a { + padding-right: 12px; + padding-left: 12px; + margin-right: 2px; + line-height: 14px; +} +.nav-tabs { + border-bottom: 1px solid #ddd; +} +.nav-tabs > li { + margin-bottom: -1px; +} +.nav-tabs > li > a { + padding-top: 9px; + padding-bottom: 9px; + border: 1px solid transparent; + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} +.nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #dddddd; +} +.nav-tabs > .active > a, .nav-tabs > .active > a:hover { + color: #555555; + background-color: #ffffff; + border: 1px solid #ddd; + border-bottom-color: transparent; + cursor: default; +} +.nav-pills > li > a { + padding-top: 8px; + padding-bottom: 8px; + margin-top: 2px; + margin-bottom: 2px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.nav-pills .active > a, .nav-pills .active > a:hover { + color: #ffffff; + background-color: #0088cc; +} +.nav-stacked > li { + float: none; +} +.nav-stacked > li > a { + margin-right: 0; +} +.nav-tabs.nav-stacked { + border-bottom: 0; +} +.nav-tabs.nav-stacked > li > a { + border: 1px solid #ddd; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.nav-tabs.nav-stacked > li:first-child > a { + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} +.nav-tabs.nav-stacked > li:last-child > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} +.nav-tabs.nav-stacked > li > a:hover { + border-color: #ddd; + z-index: 2; +} +.nav-pills.nav-stacked > li > a { + margin-bottom: 3px; +} +.nav-pills.nav-stacked > li:last-child > a { + margin-bottom: 1px; +} +.nav-tabs .dropdown-menu, .nav-pills .dropdown-menu { + margin-top: 1px; + border-width: 1px; +} +.nav-pills .dropdown-menu { + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.nav-tabs .dropdown-toggle .caret, .nav-pills .dropdown-toggle .caret { + border-top-color: #0088cc; + margin-top: 6px; +} +.nav-tabs .dropdown-toggle:hover .caret, .nav-pills .dropdown-toggle:hover .caret { + border-top-color: #005580; +} +.nav-tabs .active .dropdown-toggle .caret, .nav-pills .active .dropdown-toggle .caret { + border-top-color: #333333; +} +.nav > .dropdown.active > a:hover { + color: #000000; + cursor: pointer; +} +.nav-tabs .open .dropdown-toggle, .nav-pills .open .dropdown-toggle, .nav > .open.active > a:hover { + color: #ffffff; + background-color: #999999; + border-color: #999999; +} +.nav .open .caret, .nav .open.active .caret, .nav .open a:hover .caret { + border-top-color: #ffffff; + opacity: 1; + filter: alpha(opacity=100); +} +.tabs-stacked .open > a:hover { + border-color: #999999; +} +.tabbable { + *zoom: 1; +} +.tabbable:before, .tabbable:after { + display: table; + content: ""; +} +.tabbable:after { + clear: both; +} +.tab-content { + overflow: hidden; +} +.tabs-below .nav-tabs, .tabs-right .nav-tabs, .tabs-left .nav-tabs { + border-bottom: 0; +} +.tab-content > .tab-pane, .pill-content > .pill-pane { + display: none; +} +.tab-content > .active, .pill-content > .active { + display: block; +} +.tabs-below .nav-tabs { + border-top: 1px solid #ddd; +} +.tabs-below .nav-tabs > li { + margin-top: -1px; + margin-bottom: 0; +} +.tabs-below .nav-tabs > li > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} +.tabs-below .nav-tabs > li > a:hover { + border-bottom-color: transparent; + border-top-color: #ddd; +} +.tabs-below .nav-tabs .active > a, .tabs-below .nav-tabs .active > a:hover { + border-color: transparent #ddd #ddd #ddd; +} +.tabs-left .nav-tabs > li, .tabs-right .nav-tabs > li { + float: none; +} +.tabs-left .nav-tabs > li > a, .tabs-right .nav-tabs > li > a { + min-width: 74px; + margin-right: 0; + margin-bottom: 3px; +} +.tabs-left .nav-tabs { + float: left; + margin-right: 19px; + border-right: 1px solid #ddd; +} +.tabs-left .nav-tabs > li > a { + margin-right: -1px; + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} +.tabs-left .nav-tabs > li > a:hover { + border-color: #eeeeee #dddddd #eeeeee #eeeeee; +} +.tabs-left .nav-tabs .active > a, .tabs-left .nav-tabs .active > a:hover { + border-color: #ddd transparent #ddd #ddd; + *border-right-color: #ffffff; +} +.tabs-right .nav-tabs { + float: right; + margin-left: 19px; + border-left: 1px solid #ddd; +} +.tabs-right .nav-tabs > li > a { + margin-left: -1px; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} +.tabs-right .nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #eeeeee #dddddd; +} +.tabs-right .nav-tabs .active > a, .tabs-right .nav-tabs .active > a:hover { + border-color: #ddd #ddd #ddd transparent; + *border-left-color: #ffffff; +} +.navbar { + overflow: visible; + margin-bottom: 18px; +} +.navbar-inner { + padding-left: 20px; + padding-right: 20px; + background-color: #2c2c2c; + background-image: -moz-linear-gradient(top, #333333, #222222); + background-image: -ms-linear-gradient(top, #333333, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); + background-image: -webkit-linear-gradient(top, #333333, #222222); + background-image: -o-linear-gradient(top, #333333, #222222); + background-image: linear-gradient(top, #333333, #222222); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); +} +.btn-navbar { + display: none; + float: right; + padding: 7px 10px; + margin-left: 5px; + margin-right: 5px; + background-color: #2c2c2c; + background-image: -moz-linear-gradient(top, #333333, #222222); + background-image: -ms-linear-gradient(top, #333333, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); + background-image: -webkit-linear-gradient(top, #333333, #222222); + background-image: -o-linear-gradient(top, #333333, #222222); + background-image: linear-gradient(top, #333333, #222222); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); + border-color: #222222 #222222 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); +} +.btn-navbar:hover, +.btn-navbar:active, +.btn-navbar.active, +.btn-navbar.disabled, +.btn-navbar[disabled] { + background-color: #222222; +} +.btn-navbar:active, .btn-navbar.active { + background-color: #080808 \9; +} +.btn-navbar .icon-bar { + display: block; + width: 18px; + height: 2px; + background-color: #f5f5f5; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; + -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); +} +.btn-navbar .icon-bar + .icon-bar { + margin-top: 3px; +} +.nav-collapse.collapse { + height: auto; +} +.navbar .brand:hover { + text-decoration: none; +} +.navbar .brand { + float: left; + display: block; + padding: 8px 20px 12px; + margin-left: -20px; + font-size: 20px; + font-weight: 200; + line-height: 1; + color: #ffffff; +} +.navbar .navbar-text { + margin-bottom: 0; + line-height: 40px; + color: #999999; +} +.navbar .navbar-text a:hover { + color: #ffffff; + background-color: transparent; +} +.navbar .btn, .navbar .btn-group { + margin-top: 5px; +} +.navbar .btn-group .btn { + margin-top: 0; +} +.navbar-form { + margin-bottom: 0; + *zoom: 1; +} +.navbar-form:before, .navbar-form:after { + display: table; + content: ""; +} +.navbar-form:after { + clear: both; +} +.navbar-form input, .navbar-form select { + display: inline-block; + margin-top: 5px; + margin-bottom: 0; +} +.navbar-form .radio, .navbar-form .checkbox { + margin-top: 5px; +} +.navbar-form input[type="image"], .navbar-form input[type="checkbox"], .navbar-form input[type="radio"] { + margin-top: 3px; +} +.navbar-form .input-append, .navbar-form .input-prepend { + margin-top: 6px; + white-space: nowrap; +} +.navbar-form .input-append input, .navbar-form .input-prepend input { + margin-top: 0; +} +.navbar-search { + position: relative; + float: left; + margin-top: 6px; + margin-bottom: 0; +} +.navbar-search .search-query { + padding: 4px 9px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + font-weight: normal; + line-height: 1; + color: #ffffff; + color: rgba(255, 255, 255, 0.75); + background: #666; + background: rgba(255, 255, 255, 0.3); + border: 1px solid #111; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + -webkit-transition: none; + -moz-transition: none; + -ms-transition: none; + -o-transition: none; + transition: none; +} +.navbar-search .search-query :-moz-placeholder { + color: #eeeeee; +} +.navbar-search .search-query::-webkit-input-placeholder { + color: #eeeeee; +} +.navbar-search .search-query:hover { + color: #ffffff; + background-color: #999999; + background-color: rgba(255, 255, 255, 0.5); +} +.navbar-search .search-query:focus, .navbar-search .search-query.focused { + padding: 5px 10px; + color: #333333; + text-shadow: 0 1px 0 #ffffff; + background-color: #ffffff; + border: 0; + -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + outline: 0; +} +.navbar-fixed-top { + position: fixed; + top: 0; + right: 0; + left: 0; + z-index: 1030; +} +.navbar-fixed-top .navbar-inner { + padding-left: 0; + padding-right: 0; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.navbar .nav { + position: relative; + left: 0; + display: block; + float: left; + margin: 0 10px 0 0; +} +.navbar .nav.pull-right { + float: right; +} +.navbar .nav > li { + display: block; + float: left; +} +.navbar .nav > li > a { + float: none; + padding: 10px 10px 11px; + line-height: 19px; + color: #999999; + text-decoration: none; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.navbar .nav > li > a:hover { + background-color: transparent; + color: #ffffff; + text-decoration: none; +} +.navbar .nav .active > a, .navbar .nav .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #222222; +} +.navbar .divider-vertical { + height: 40px; + width: 1px; + margin: 0 9px; + overflow: hidden; + background-color: #222222; + border-right: 1px solid #333333; +} +.navbar .nav.pull-right { + margin-left: 10px; + margin-right: 0; +} +.navbar .dropdown-menu { + margin-top: 1px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.navbar .dropdown-menu:before { + content: ''; + display: inline-block; + border-left: 7px solid transparent; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-bottom-color: rgba(0, 0, 0, 0.2); + position: absolute; + top: -7px; + left: 9px; +} +.navbar .dropdown-menu:after { + content: ''; + display: inline-block; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid #ffffff; + position: absolute; + top: -6px; + left: 10px; +} +.navbar .nav .dropdown-toggle .caret, .navbar .nav .open.dropdown .caret { + border-top-color: #ffffff; +} +.navbar .nav .active .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.navbar .nav .open > .dropdown-toggle, .navbar .nav .active > .dropdown-toggle, .navbar .nav .open.active > .dropdown-toggle { + background-color: transparent; +} +.navbar .nav .active > .dropdown-toggle:hover { + color: #ffffff; +} +.navbar .nav.pull-right .dropdown-menu { + left: auto; + right: 0; +} +.navbar .nav.pull-right .dropdown-menu:before { + left: auto; + right: 12px; +} +.navbar .nav.pull-right .dropdown-menu:after { + left: auto; + right: 13px; +} +.breadcrumb { + padding: 7px 14px; + margin: 0 0 18px; + background-color: #fbfbfb; + background-image: -moz-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -ms-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5)); + background-image: -webkit-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -o-linear-gradient(top, #ffffff, #f5f5f5); + background-image: linear-gradient(top, #ffffff, #f5f5f5); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0); + border: 1px solid #ddd; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; +} +.breadcrumb li { + display: inline-block; + text-shadow: 0 1px 0 #ffffff; +} +.breadcrumb .divider { + padding: 0 5px; + color: #999999; +} +.breadcrumb .active a { + color: #333333; +} +.pagination { + height: 36px; + margin: 18px 0; +} +.pagination ul { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; + margin-left: 0; + margin-bottom: 0; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); +} +.pagination li { + display: inline; +} +.pagination a { + float: left; + padding: 0 14px; + line-height: 34px; + text-decoration: none; + border: 1px solid #ddd; + border-left-width: 0; +} +.pagination a:hover, .pagination .active a { + background-color: #f5f5f5; +} +.pagination .active a { + color: #999999; + cursor: default; +} +.pagination .disabled a, .pagination .disabled a:hover { + color: #999999; + background-color: transparent; + cursor: default; +} +.pagination li:first-child a { + border-left-width: 1px; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.pagination li:last-child a { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.pagination-centered { + text-align: center; +} +.pagination-right { + text-align: right; +} +.pager { + margin-left: 0; + margin-bottom: 18px; + list-style: none; + text-align: center; + *zoom: 1; +} +.pager:before, .pager:after { + display: table; + content: ""; +} +.pager:after { + clear: both; +} +.pager li { + display: inline; +} +.pager a { + display: inline-block; + padding: 5px 14px; + background-color: #fff; + border: 1px solid #ddd; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} +.pager a:hover { + text-decoration: none; + background-color: #f5f5f5; +} +.pager .next a { + float: right; +} +.pager .previous a { + float: left; +} +.modal-open .dropdown-menu { + z-index: 2050; +} +.modal-open .dropdown.open { + *z-index: 2050; +} +.modal-open .popover { + z-index: 2060; +} +.modal-open .tooltip { + z-index: 2070; +} +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + background-color: #000000; +} +.modal-backdrop.fade { + opacity: 0; +} +.modal-backdrop, .modal-backdrop.fade.in { + opacity: 0.8; + filter: alpha(opacity=80); +} +.modal { + position: fixed; + top: 50%; + left: 50%; + z-index: 1050; + max-height: 500px; + overflow: auto; + width: 560px; + margin: -250px 0 0 -280px; + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + /* IE6-7 */ + + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.wide-modal { + position: fixed; + top: 5%; + left: 5%; + z-index: 1050; + max-height: 90%; + overflow: auto; + width: 90%; + /*margin: -50px 0 0 -80px;*/ + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + /* IE6-7 */ + + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.modal.fade { + -webkit-transition: opacity .3s linear, top .3s ease-out; + -moz-transition: opacity .3s linear, top .3s ease-out; + -ms-transition: opacity .3s linear, top .3s ease-out; + -o-transition: opacity .3s linear, top .3s ease-out; + transition: opacity .3s linear, top .3s ease-out; + top: -25%; +} +.modal.fade.in { + top: 50%; +} +.modal-header { + padding: 9px 15px; + border-bottom: 1px solid #eee; +} +.modal-header .close { + margin-top: 2px; +} +.modal-body { + padding: 15px; +} +.modal-body .modal-form { + margin-bottom: 0; +} +.modal-footer { + padding: 14px 15px 15px; + margin-bottom: 0; + background-color: #f5f5f5; + border-top: 1px solid #ddd; + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; + *zoom: 1; +} +.modal-footer:before, .modal-footer:after { + display: table; + content: ""; +} +.modal-footer:after { + clear: both; +} +.modal-footer .btn { + float: right; + margin-left: 5px; + margin-bottom: 0; +} +.tooltip { + position: absolute; + z-index: 1020; + display: block; + visibility: visible; + padding: 5px; + font-size: 11px; + opacity: 0; + filter: alpha(opacity=0); +} +.tooltip.in { + opacity: 0.8; + filter: alpha(opacity=80); +} +.tooltip.top { + margin-top: -2px; +} +.tooltip.right { + margin-left: 2px; +} +.tooltip.bottom { + margin-top: 2px; +} +.tooltip.left { + margin-left: -2px; +} +.tooltip.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid #000000; +} +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #000000; +} +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-bottom: 5px solid #000000; +} +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-right: 5px solid #000000; +} +.tooltip-inner { + max-width: 200px; + padding: 3px 8px; + color: #ffffff; + text-align: center; + text-decoration: none; + background-color: #000000; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; +} +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1010; + display: none; + padding: 5px; +} +.popover.top { + margin-top: -5px; +} +.popover.right { + margin-left: 5px; +} +.popover.bottom { + margin-top: 5px; +} +.popover.left { + margin-left: -5px; +} +.popover.top .arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid #000000; +} +.popover.right .arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-right: 5px solid #000000; +} +.popover.bottom .arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-bottom: 5px solid #000000; +} +.popover.left .arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #000000; +} +.popover .arrow { + position: absolute; + width: 0; + height: 0; +} +.popover-inner { + padding: 3px; + width: 280px; + overflow: hidden; + background: #000000; + background: rgba(0, 0, 0, 0.8); + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); +} +.popover-title { + padding: 9px 15px; + line-height: 1; + background-color: #f5f5f5; + border-bottom: 1px solid #eee; + -webkit-border-radius: 3px 3px 0 0; + -moz-border-radius: 3px 3px 0 0; + border-radius: 3px 3px 0 0; +} +.popover-content { + padding: 14px; + background-color: #ffffff; + -webkit-border-radius: 0 0 3px 3px; + -moz-border-radius: 0 0 3px 3px; + border-radius: 0 0 3px 3px; + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.popover-content p, .popover-content ul, .popover-content ol { + margin-bottom: 0; +} +.thumbnails { + margin-left: -20px; + list-style: none; + *zoom: 1; +} +.thumbnails:before, .thumbnails:after { + display: table; + content: ""; +} +.thumbnails:after { + clear: both; +} +.thumbnails > li { + float: left; + margin: 0 0 18px 20px; +} +.thumbnail { + display: block; + padding: 4px; + line-height: 1; + border: 1px solid #ddd; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); +} +a.thumbnail:hover { + border-color: #0088cc; + -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); +} +.thumbnail > img { + display: block; + max-width: 100%; + margin-left: auto; + margin-right: auto; +} +.thumbnail .caption { + padding: 9px; +} +.label { + padding: 2px 4px 3px; + font-size: 11.049999999999999px; + font-weight: bold; + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #999999; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.label:hover { + color: #ffffff; + text-decoration: none; +} +.label-important { + background-color: #b94a48; +} +.label-important:hover { + background-color: #953b39; +} +.label-warning { + background-color: #f89406; +} +.label-warning:hover { + background-color: #c67605; +} +.label-success { + background-color: #468847; +} +.label-success:hover { + background-color: #356635; +} +.label-info { + background-color: #3a87ad; +} +.label-info:hover { + background-color: #2d6987; +} +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +@-moz-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +@keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +.progress { + overflow: hidden; + height: 18px; + margin-bottom: 18px; + background-color: #f7f7f7; + background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -ms-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9)); + background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: linear-gradient(top, #f5f5f5, #f9f9f9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0); + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.progress .bar { + width: 0%; + height: 18px; + color: #ffffff; + font-size: 12px; + text-align: center; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #0e90d2; + background-image: -moz-linear-gradient(top, #149bdf, #0480be); + background-image: -ms-linear-gradient(top, #149bdf, #0480be); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be)); + background-image: -webkit-linear-gradient(top, #149bdf, #0480be); + background-image: -o-linear-gradient(top, #149bdf, #0480be); + background-image: linear-gradient(top, #149bdf, #0480be); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0); + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition: width 0.6s ease; + -moz-transition: width 0.6s ease; + -ms-transition: width 0.6s ease; + -o-transition: width 0.6s ease; + transition: width 0.6s ease; +} +.progress-striped .bar { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + -webkit-background-size: 40px 40px; + -moz-background-size: 40px 40px; + -o-background-size: 40px 40px; + background-size: 40px 40px; +} +.progress.active .bar { + -webkit-animation: progress-bar-stripes 2s linear infinite; + -moz-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} +.progress-danger .bar { + background-color: #dd514c; + background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -o-linear-gradient(top, #ee5f5b, #c43c35); + background-image: linear-gradient(top, #ee5f5b, #c43c35); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0); +} +.progress-danger.progress-striped .bar { + background-color: #ee5f5b; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-success .bar { + background-color: #5eb95e; + background-image: -moz-linear-gradient(top, #62c462, #57a957); + background-image: -ms-linear-gradient(top, #62c462, #57a957); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957)); + background-image: -webkit-linear-gradient(top, #62c462, #57a957); + background-image: -o-linear-gradient(top, #62c462, #57a957); + background-image: linear-gradient(top, #62c462, #57a957); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0); +} +.progress-success.progress-striped .bar { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-info .bar { + background-color: #4bb1cf; + background-image: -moz-linear-gradient(top, #5bc0de, #339bb9); + background-image: -ms-linear-gradient(top, #5bc0de, #339bb9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9)); + background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9); + background-image: -o-linear-gradient(top, #5bc0de, #339bb9); + background-image: linear-gradient(top, #5bc0de, #339bb9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0); +} +.progress-info.progress-striped .bar { + background-color: #5bc0de; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.accordion { + margin-bottom: 18px; +} +.accordion-group { + margin-bottom: 2px; + border: 1px solid #e5e5e5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.accordion-heading { + border-bottom: 0; +} +.accordion-heading .accordion-toggle { + display: block; + padding: 8px 15px; +} +.accordion-inner { + padding: 9px 15px; + border-top: 1px solid #e5e5e5; +} +.carousel { + position: relative; + margin-bottom: 18px; + line-height: 1; +} +.carousel-inner { + overflow: hidden; + width: 100%; + position: relative; +} +.carousel .item { + display: none; + position: relative; + -webkit-transition: 0.6s ease-in-out left; + -moz-transition: 0.6s ease-in-out left; + -ms-transition: 0.6s ease-in-out left; + -o-transition: 0.6s ease-in-out left; + transition: 0.6s ease-in-out left; +} +.carousel .item > img { + display: block; + line-height: 1; +} +.carousel .active, .carousel .next, .carousel .prev { + display: block; +} +.carousel .active { + left: 0; +} +.carousel .next, .carousel .prev { + position: absolute; + top: 0; + width: 100%; +} +.carousel .next { + left: 100%; +} +.carousel .prev { + left: -100%; +} +.carousel .next.left, .carousel .prev.right { + left: 0; +} +.carousel .active.left { + left: -100%; +} +.carousel .active.right { + left: 100%; +} +.carousel-control { + position: absolute; + top: 40%; + left: 15px; + width: 40px; + height: 40px; + margin-top: -20px; + font-size: 60px; + font-weight: 100; + line-height: 30px; + color: #ffffff; + text-align: center; + background: #222222; + border: 3px solid #ffffff; + -webkit-border-radius: 23px; + -moz-border-radius: 23px; + border-radius: 23px; + opacity: 0.5; + filter: alpha(opacity=50); +} +.carousel-control.right { + left: auto; + right: 15px; +} +.carousel-control:hover { + color: #ffffff; + text-decoration: none; + opacity: 0.9; + filter: alpha(opacity=90); +} +.carousel-caption { + position: absolute; + left: 0; + right: 0; + bottom: 0; + padding: 10px 15px 5px; + background: #333333; + background: rgba(0, 0, 0, 0.75); +} +.carousel-caption h4, .carousel-caption p { + color: #ffffff; +} +.hero-unit { + padding: 60px; + margin-bottom: 30px; + background-color: #f5f5f5; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} +.hero-unit h1 { + margin-bottom: 0; + font-size: 60px; + line-height: 1; + letter-spacing: -1px; +} +.hero-unit p { + font-size: 18px; + font-weight: 200; + line-height: 27px; +} +.pull-right { + float: right; +} +.pull-left { + float: left; +} +.hide { + display: none; +} +.show { + display: block; +} +.invisible { + visibility: hidden; +} diff --git a/src/nl/astraeus/jdbc/web/resources/images/loading.gif b/src/nl/astraeus/jdbc/web/resources/images/loading.gif new file mode 100644 index 0000000..21c7e74 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/images/loading.gif Binary files differ diff --git a/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png b/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png new file mode 100644 index 0000000..92d4445 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png Binary files differ diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f403193 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..73ff239 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..3b00020 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..275077f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/README b/README deleted file mode 100644 index 734abaf..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -This file was created by IntelliJ IDEA 11.1.1 for binding GitHub repository \ No newline at end of file diff --git a/Simple-jdbc-statistics.iml b/Simple-jdbc-statistics.iml new file mode 100644 index 0000000..ca90a9b --- /dev/null +++ b/Simple-jdbc-statistics.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/lib/h2-1.3.166.jar b/lib/h2-1.3.166.jar new file mode 100644 index 0000000..4985063 --- /dev/null +++ b/lib/h2-1.3.166.jar Binary files differ diff --git a/lib/servlet-api-2.5.jar b/lib/servlet-api-2.5.jar new file mode 100644 index 0000000..20b5755 --- /dev/null +++ b/lib/servlet-api-2.5.jar Binary files differ diff --git a/lib/slf4j-api-1.6.4.jar b/lib/slf4j-api-1.6.4.jar new file mode 100644 index 0000000..4d23f41 --- /dev/null +++ b/lib/slf4j-api-1.6.4.jar Binary files differ diff --git a/lib/slf4j-simple-1.6.4.jar b/lib/slf4j-simple-1.6.4.jar new file mode 100644 index 0000000..3d1b8d9 --- /dev/null +++ b/lib/slf4j-simple-1.6.4.jar Binary files differ diff --git a/lib/ssr-0.1.jar b/lib/ssr-0.1.jar new file mode 100644 index 0000000..65dfcf4 --- /dev/null +++ b/lib/ssr-0.1.jar Binary files differ diff --git a/lib/vst-0.4.jar b/lib/vst-0.4.jar new file mode 100644 index 0000000..db63792 --- /dev/null +++ b/lib/vst-0.4.jar Binary files differ diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..ac2dbe1 --- /dev/null +++ b/readme.md @@ -0,0 +1 @@ +A simple wrapper around jdbc drivers what will show current jdbc stats of the running queries on a simple web page on port 18080. \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/ConnectionLogger.java b/src/nl/astraeus/jdbc/ConnectionLogger.java new file mode 100644 index 0000000..c3e243f --- /dev/null +++ b/src/nl/astraeus/jdbc/ConnectionLogger.java @@ -0,0 +1,279 @@ +package nl.astraeus.jdbc; + +import java.sql.*; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Executor; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:12:34 PM + */ +public class ConnectionLogger implements Connection { + private Connection connection; + + private long milli; + private long nano; + private String lastSql; + + public ConnectionLogger(Connection connection) { + this.connection = connection; + this.lastSql = ""; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(QueryType.UNKNOWN, sql, m, n); + } + + public void commit() throws SQLException { + clearTime(); + + connection.commit(); + + log("commit"); + } + + public void rollback() throws SQLException { + clearTime(); + + connection.rollback(); + + log("rollback"); + } + + public void close() throws SQLException { + clearTime(); + + connection.close(); + + log("close"); + } + + public PreparedStatement prepareStatement(String sql) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, autoGeneratedKeys); + } + + public PreparedStatement prepareStatement(String sql, int columnIndexes[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnIndexes); + } + + public PreparedStatement prepareStatement(String sql, String columnNames[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnNames); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public Statement createStatement() throws SQLException { + return connection.createStatement(); + } + + public CallableStatement prepareCall(String sql) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql); + } + + public String nativeSQL(String sql) throws SQLException { + lastSql = sql; + return connection.nativeSQL(sql); + } + + public void setAutoCommit(boolean autoCommit) throws SQLException { + connection.setAutoCommit(autoCommit); + } + + public boolean getAutoCommit() throws SQLException { + return connection.getAutoCommit(); + } + + public boolean isClosed() throws SQLException { + return connection.isClosed(); + } + + public DatabaseMetaData getMetaData() throws SQLException { + return connection.getMetaData(); + } + + public void setReadOnly(boolean readOnly) throws SQLException { + connection.setReadOnly(readOnly); + } + + public boolean isReadOnly() throws SQLException { + return connection.isReadOnly(); + } + + public void setCatalog(String catalog) throws SQLException { + connection.setCatalog(catalog); + } + + public String getCatalog() throws SQLException { + return connection.getCatalog(); + } + + public void setTransactionIsolation(int level) throws SQLException { + connection.setTransactionIsolation(level); + } + + public int getTransactionIsolation() throws SQLException { + return connection.getTransactionIsolation(); + } + + public SQLWarning getWarnings() throws SQLException { + return connection.getWarnings(); + } + + public void clearWarnings() throws SQLException { + connection.clearWarnings(); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency); + } + + public Map> getTypeMap() throws SQLException { + return connection.getTypeMap(); + } + + public void setTypeMap(Map> map) throws SQLException { + connection.setTypeMap(map); + } + + public void setHoldability(int holdability) throws SQLException { + connection.setHoldability(holdability); + } + + public int getHoldability() throws SQLException { + return connection.getHoldability(); + } + + public Savepoint setSavepoint() throws SQLException { + return connection.setSavepoint(); + } + + public Savepoint setSavepoint(String name) throws SQLException { + return connection.setSavepoint(name); + } + + public void rollback(Savepoint savepoint) throws SQLException { + connection.rollback(); + } + + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + connection.releaseSavepoint(savepoint); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public Clob createClob() throws SQLException { + return connection.createClob(); + } + + public Blob createBlob() throws SQLException { + return connection.createBlob(); + } + + public NClob createNClob() throws SQLException { + return connection.createNClob(); + } + + public SQLXML createSQLXML() throws SQLException { + return connection.createSQLXML(); + } + + public boolean isValid(int timeout) throws SQLException { + return connection.isValid(timeout); + } + + public void setClientInfo(String name, String value) throws SQLClientInfoException { + connection.setClientInfo(name, value); + } + + public void setClientInfo(Properties properties) throws SQLClientInfoException { + connection.setClientInfo(properties); + } + + public String getClientInfo(String name) throws SQLException { + return connection.getClientInfo(name); + } + + public Properties getClientInfo() throws SQLException { + return connection.getClientInfo(); + } + + public Array createArrayOf(String typeName, Object[] elements) throws SQLException { + return connection.createArrayOf(typeName, elements); + } + + public Struct createStruct(String typeName, Object[] attributes) throws SQLException { + return connection.createStruct(typeName, attributes); + } + + @Override + public void setSchema(String schema) throws SQLException { + connection.setSchema(schema); + } + + @Override + public String getSchema() throws SQLException { + return connection.getSchema(); + } + + @Override + public void abort(Executor executor) throws SQLException { + connection.abort(executor); + } + + @Override + public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { + connection.setNetworkTimeout(executor, milliseconds); + } + + @Override + public int getNetworkTimeout() throws SQLException { + return connection.getNetworkTimeout(); + } + + public T unwrap(Class iface) throws SQLException { + return connection.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return connection.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/Driver.java b/src/nl/astraeus/jdbc/Driver.java new file mode 100644 index 0000000..8317172 --- /dev/null +++ b/src/nl/astraeus/jdbc/Driver.java @@ -0,0 +1,116 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.http.SimpleWebServer; +import nl.astraeus.jdbc.web.JdbcStatisticsServlet; +import nl.astraeus.jdbc.web.ResourceServlet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.*; +import java.util.Enumeration; +import java.util.Properties; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:54:37 PM + */ +public class Driver implements java.sql.Driver { + private final static Logger log = LoggerFactory.getLogger(Driver.class); + + final private static String URL_PREFIX = "jdbc:stat:"; + + private java.sql.Driver driver = null; + private String[] drivers = { + "org.postgresql.Driver", + "oracle.jdbc.driver.OracleDriver", + "com.sybase.jdbc2.jdbc.SybDriver", + "net.sourceforge.jtds.jdbc.Driver", + "com.microsoft.jdbc.sqlserver.SQLServerDriver", + "com.microsoft.sqlserver.jdbc.SQLServerDriver", + "weblogic.jdbc.sqlserver.SQLServerDriver", + "com.informix.jdbc.IfxDriver", + "org.apache.derby.jdbc.ClientDriver", + "org.apache.derby.jdbc.EmbeddedDriver", + "com.mysql.jdbc.Driver", + "org.hsqldb.jdbcDriver", + "org.h2.Driver" }; + + static { + log.debug("Loading driver class " + Driver.class.getName()); + + try { + DriverManager.registerDriver(new Driver()); + } catch (SQLException e) { + log.error("", e); + } + } + + public Driver() { + for (String dr : drivers) { + try { + Class.forName(dr); + } catch (Throwable e) { + log.debug("Can't instantiate driver: " + dr, e); + } + } + } + + private java.sql.Driver findDriver(String url) throws SQLException { + Enumeration e = DriverManager.getDrivers(); + + while (e.hasMoreElements()) { + java.sql.Driver d = (java.sql.Driver) e.nextElement(); + + if (d.acceptsURL(url)) { + return d; + } + } + + throw new SQLException("Driver not found: " + url); + } + + public Connection connect(String url, Properties info) throws SQLException { + url = url.substring(URL_PREFIX.length()); + + if (driver == null) { + driver = findDriver(url); + } + + if (driver != null) { + SimpleWebServer server = new SimpleWebServer(18080); + + server.addServlet(new JdbcStatisticsServlet(), "/"); + server.addServlet(new ResourceServlet(), "/resources/*"); + + server.start(); + } + + return new ConnectionLogger(driver.connect(url, info)); + } + + public boolean acceptsURL(String url) throws SQLException { + return (url != null && url.startsWith(URL_PREFIX)); + } + + public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { + return driver.getPropertyInfo(url, info); + } + + public int getMajorVersion() { + return driver.getMajorVersion(); + } + + public int getMinorVersion() { + return driver.getMinorVersion(); + } + + public boolean jdbcCompliant() { + return driver.jdbcCompliant(); + } + + @Override + public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException { + return driver.getParentLogger(); + } +} diff --git a/src/nl/astraeus/jdbc/JdbcLogger.java b/src/nl/astraeus/jdbc/JdbcLogger.java new file mode 100644 index 0000000..f4bc125 --- /dev/null +++ b/src/nl/astraeus/jdbc/JdbcLogger.java @@ -0,0 +1,113 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.jdbc.util.Util; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/** + * User: riennentjes + * Date: Jul 12, 2008 + * Time: 9:15:21 AM + */ +public class JdbcLogger { + private final static Logger logger = LoggerFactory.getLogger(JdbcLogger.class); + + private final static JdbcLogger instance = new JdbcLogger(); + + public static JdbcLogger get() { + return instance; + } + + public final static class LogEntry { + public QueryType type; + public String sql; + public long milli; + public long nano; + public int count; + public int hash; + + public LogEntry(int hash, QueryType type, String sql, long milli, long nano) { + this.hash = hash; + this.type = type; + this.sql = sql; + this.milli = milli; + this.nano = nano; + this.count = 1; + } + + public void addCount(long milli, long nano) { + synchronized (this) { + count++; + this.milli += milli; + this.nano += nano; + } + } + + public int getCount() { + return count; + } + + public String getMilli() { + return Util.formatNano(milli*1000000/count); + } + + public String getNano() { + return Util.formatNano(nano/count); + } + + public String getTotal() { + return Util.formatNano(nano); + } + + public String getSql() { + return sql; + } + } + + private Map queries; + + public JdbcLogger() { + queries = new ConcurrentHashMap(); + } + + public void logEntry(QueryType type, String sql, long milli, long nano) { + int hash = sql.hashCode(); + LogEntry entry = queries.get(hash); + + if (entry == null) { + entry = new LogEntry(hash, type, sql, milli, nano); + queries.put(hash, entry); + } else { + entry.addCount(milli, nano); + } + + if (queries.size() > 1000) { + List toRemove = new LinkedList(); + List values = new LinkedList(queries.values()); + + Collections.sort(values, new Comparator() { + @Override + public int compare(LogEntry o1, LogEntry o2) { + return o1.count - o2.count; + } + }); + + while (queries.size() > 900) { + queries.remove(values.remove(0).hash); + + } + } + } + + public static void log(QueryType type, String sql, long milli, long nano) { + instance.logEntry(type, sql, milli, nano); + } + + public Collection getEntries() { + return queries.values(); + } + +} diff --git a/src/nl/astraeus/jdbc/PreparedStatementLogger.java b/src/nl/astraeus/jdbc/PreparedStatementLogger.java new file mode 100644 index 0000000..98aefc7 --- /dev/null +++ b/src/nl/astraeus/jdbc/PreparedStatementLogger.java @@ -0,0 +1,577 @@ +package nl.astraeus.jdbc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.InputStream; +import java.io.Reader; +import java.math.BigDecimal; +import java.net.URL; +import java.sql.*; +import java.util.Calendar; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 7:47:57 PM + */ +public class PreparedStatementLogger implements PreparedStatement { + private final static Logger log = LoggerFactory.getLogger(PreparedStatementLogger.class); + + private PreparedStatement statement; + + private String sql; + private QueryType type; + private long milli; + private long nano; + + //private ArrayList parameters; + + public PreparedStatementLogger(PreparedStatement statement) { + this.statement = statement; + this.sql = ""; + this.type = QueryType.UNKNOWN; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(QueryType type, String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(type, sql, m, n); + } + + public PreparedStatementLogger(Connection connection, String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql); + } + + public PreparedStatementLogger(Connection connection, String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatementLogger(Connection connection, String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, autoGeneratedKeys); + } + + public PreparedStatementLogger(Connection connection, String sql, int[] columnIndexes) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnIndexes); + } + + public PreparedStatementLogger(Connection connection, String sql, String[] columnNames) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnNames); + } + + public boolean execute() throws SQLException { + clearTime(); + + boolean result = statement.execute(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery() throws SQLException { + clearTime(); + + ResultSet result = statement.executeQuery(); + + log(type, sql); + + return result; + } + + public int executeUpdate() throws SQLException { + clearTime(); + + int result = statement.executeUpdate(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + ResultSet result = statement.executeQuery(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnNames); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnNames); + + log(type, sql); + + return result; + } + + + public void setNull(int parameterIndex, int sqlType) throws SQLException { + statement.setNull(parameterIndex, sqlType); + } + + public void setBoolean(int parameterIndex, boolean x) throws SQLException { + statement.setBoolean(parameterIndex, x); + } + + public void setByte(int parameterIndex, byte x) throws SQLException { + statement.setByte(parameterIndex, x); + } + + public void setShort(int parameterIndex, short x) throws SQLException { + statement.setShort(parameterIndex, x); + } + + public void setInt(int parameterIndex, int x) throws SQLException { + statement.setInt(parameterIndex, x); + } + + public void setLong(int parameterIndex, long x) throws SQLException { + statement.setLong(parameterIndex, x); + } + + public void setFloat(int parameterIndex, float x) throws SQLException { + statement.setFloat(parameterIndex, x); + } + + public void setDouble(int parameterIndex, double x) throws SQLException { + statement.setDouble(parameterIndex, x); + } + + public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { + statement.setBigDecimal(parameterIndex, x); + } + + public void setString(int parameterIndex, String x) throws SQLException { + statement.setString(parameterIndex, x); + } + + public void setBytes(int parameterIndex, byte x[]) throws SQLException { + statement.setBytes(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x) throws SQLException { + statement.setDate(parameterIndex, x); + } + + public void setTime(int parameterIndex, Time x) throws SQLException { + statement.setTime(parameterIndex, x); + } + + public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { + statement.setTimestamp(parameterIndex, x); + } + + public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setUnicodeStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType); + } + + public void setObject(int parameterIndex, Object x) throws SQLException { + statement.setObject(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setRef(int parameterIndex, Ref x) throws SQLException { + statement.setRef(parameterIndex, x); + } + + public void setBlob(int parameterIndex, Blob x) throws SQLException { + statement.setBlob(parameterIndex, x); + } + + public void setClob(int parameterIndex, Clob x) throws SQLException { + statement.setClob(parameterIndex, x); + } + + public void setArray(int parameterIndex, Array x) throws SQLException { + statement.setArray(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { + statement.setDate(parameterIndex, x, cal); + } + + public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { + statement.setTime(parameterIndex, x, cal); + } + + public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { + statement.setTimestamp(parameterIndex, x, cal); + } + + public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException { + statement.setNull(parameterIndex, sqlType, typeName); + } + + public void setURL(int parameterIndex, URL x) throws SQLException { + statement.setURL(parameterIndex, x); + } + + public void setRowId(int parameterIndex, RowId x) throws SQLException { + statement.setRowId(parameterIndex, x); + } + + public void setNString(int parameterIndex, String value) throws SQLException { + statement.setNString(parameterIndex, value); + } + + public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException { + statement.setNCharacterStream(parameterIndex, value, length); + } + + public void setNClob(int parameterIndex, NClob value) throws SQLException { + statement.setNClob(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setClob(parameterIndex, reader, length); + } + + public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException { + statement.setBlob(parameterIndex, inputStream, length); + } + + public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setNClob(parameterIndex, reader, length); + } + + public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException { + statement.setSQLXML(parameterIndex, xmlObject); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType, scaleOrLength); + } + + public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException { + statement.setAsciiStream(parameterIndex, x); + } + + public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException { + statement.setBinaryStream(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException { + statement.setCharacterStream(parameterIndex, reader); + } + + public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException { + statement.setNCharacterStream(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader) throws SQLException { + statement.setClob(parameterIndex, reader); + } + + public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException { + statement.setBlob(parameterIndex, inputStream); + } + + public void setNClob(int parameterIndex, Reader reader) throws SQLException { + statement.setNClob(parameterIndex, reader); + } + + + public void close() throws SQLException { + sql = ""; + type = QueryType.UNKNOWN; + milli = 0; + nano = 0; + + statement.close(); + } + + public ResultSetMetaData getMetaData() throws SQLException { + return statement.getMetaData(); + } + + public void clearParameters() throws SQLException { + statement.clearParameters(); + } + + public ParameterMetaData getParameterMetaData() throws SQLException { + return statement.getParameterMetaData(); + } + + public void addBatch() throws SQLException { + statement.addBatch(); + } + + public int getMaxFieldSize() throws SQLException { + return statement.getMaxFieldSize(); + } + + public void setMaxFieldSize(int max) throws SQLException { + statement.setMaxFieldSize(max); + } + + public int getMaxRows() throws SQLException { + return statement.getMaxRows(); + } + + public void setMaxRows(int max) throws SQLException { + statement.setMaxRows(max); + } + + public void setEscapeProcessing(boolean enable) throws SQLException { + statement.setEscapeProcessing(enable); + } + + public int getQueryTimeout() throws SQLException { + return statement.getQueryTimeout(); + } + + public void setQueryTimeout(int seconds) throws SQLException { + statement.setQueryTimeout(seconds); + } + + public void cancel() throws SQLException { + statement.cancel(); + } + + public SQLWarning getWarnings() throws SQLException { + return statement.getWarnings(); + } + + public void clearWarnings() throws SQLException { + statement.clearWarnings(); + } + + public void setCursorName(String name) throws SQLException { + statement.setCursorName(name); + } + + public boolean execute(String sql) throws SQLException { + return statement.execute(sql); + } + + public ResultSet getResultSet() throws SQLException { + return statement.getResultSet(); + } + + public int getUpdateCount() throws SQLException { + return statement.getUpdateCount(); + } + + public boolean getMoreResults() throws SQLException { + return statement.getMoreResults(); + } + + public void setFetchDirection(int direction) throws SQLException { + statement.setFetchDirection(direction); + } + + public int getFetchDirection() throws SQLException { + return statement.getFetchDirection(); + } + + public void setFetchSize(int rows) throws SQLException { + statement.setFetchSize(rows); + } + + public int getFetchSize() throws SQLException { + return statement.getFetchSize(); + } + + public int getResultSetConcurrency() throws SQLException { + return statement.getResultSetConcurrency(); + } + + public int getResultSetType() throws SQLException { + return statement.getResultSetType(); + } + + public void addBatch(String sql) throws SQLException { + statement.addBatch(sql); + } + + public void clearBatch() throws SQLException { + statement.clearBatch(); + } + + public int[] executeBatch() throws SQLException { + return statement.executeBatch(); + } + + public Connection getConnection() throws SQLException { + return statement.getConnection(); + } + + public boolean getMoreResults(int current) throws SQLException { + return statement.getMoreResults(current); + } + + public ResultSet getGeneratedKeys() throws SQLException { + return statement.getGeneratedKeys(); + } + + public int getResultSetHoldability() throws SQLException { + return statement.getResultSetHoldability(); + } + + public boolean isClosed() throws SQLException { + return statement.isClosed(); + } + + public void setPoolable(boolean poolable) throws SQLException { + statement.setPoolable(poolable); + } + + public boolean isPoolable() throws SQLException { + return statement.isPoolable(); + } + + @Override + public void closeOnCompletion() throws SQLException { + statement.closeOnCompletion();; + } + + @Override + public boolean isCloseOnCompletion() throws SQLException { + return statement.isCloseOnCompletion(); + } + + public T unwrap(Class iface) throws SQLException { + return statement.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return statement.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/QueryType.java b/src/nl/astraeus/jdbc/QueryType.java new file mode 100644 index 0000000..744fbfc --- /dev/null +++ b/src/nl/astraeus/jdbc/QueryType.java @@ -0,0 +1,24 @@ +package nl.astraeus.jdbc; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:32:49 PM + */ +public enum QueryType { + PLAIN("plain"), + PREPARED("prepared"), + CALLABLE("callable"), + UNKNOWN("unknown"); + + private String description; + + QueryType(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } + +} diff --git a/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java new file mode 100644 index 0000000..07aac40 --- /dev/null +++ b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java @@ -0,0 +1,68 @@ +package nl.astraeus.jdbc.example; + +import java.sql.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 7:32 PM + */ +public class JdbcStatisticsExample { + + + public static void main(String [] args) throws Exception { + Class.forName("org.h2.Driver"); + Class.forName("nl.astraeus.jdbc.Driver"); + + new JdbcStatisticsExample(); + } + + public JdbcStatisticsExample() throws Exception { + Connection conn = DriverManager.getConnection("jdbc:stat:jdbc:h2:mem:test"); + + Statement statement = null; + + statement = conn.createStatement(); + statement.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + + boolean running = true; + int count = 1; + PreparedStatement ps = null; + + while (running) { + Thread.sleep(10); + + String TableName = "TEST"+(System.nanoTime() % 1000); + + try { + ps = conn.prepareStatement("SELECT COUNT(*) FROM "+TableName); + ResultSet rs = ps.executeQuery(); + } catch (SQLException e) { + statement = conn.createStatement(); + statement.execute("CREATE TABLE "+TableName+" (ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + } finally { + if (ps!=null) { + ps.close(); + } + } + + ps = conn.prepareStatement("INSERT INTO "+TableName+" VALUES (?, ?)"); + + ps.setInt(1, count++); + ps.setString(2, "String "+System.currentTimeMillis()); + + ps.execute(); + ps.close(); + + Thread.sleep(10); + + ps = conn.prepareStatement("SELECT * FROM "+TableName); + ResultSet rs = ps.executeQuery(); + statement.close(); + } + + conn.close(); + } +} diff --git a/src/nl/astraeus/jdbc/util/IOUtils.java b/src/nl/astraeus/jdbc/util/IOUtils.java new file mode 100644 index 0000000..ce95d9d --- /dev/null +++ b/src/nl/astraeus/jdbc/util/IOUtils.java @@ -0,0 +1,38 @@ +package nl.astraeus.jdbc.util; + +import java.io.*; + +/** + * User: rnentjes + * Date: 4/9/12 + * Time: 2:33 PM + */ +public class IOUtils { + + public static String toString(InputStream in) throws IOException { + assert in != null; + + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + StringBuilder buffer = new StringBuilder(); + + while(reader.ready()) { + buffer.append(reader.readLine()); + buffer.append("\n"); + } + + return buffer.toString(); + } finally { + in.close(); + } + } + + public static void copy(InputStream in, OutputStream out) throws IOException { + byte [] buffer = new byte[1<<16]; + int bytes; + + while((bytes = in.read(buffer)) > 0) { + out.write(buffer, 0, bytes); + } + } +} diff --git a/src/nl/astraeus/jdbc/util/Util.java b/src/nl/astraeus/jdbc/util/Util.java new file mode 100644 index 0000000..eaa853b --- /dev/null +++ b/src/nl/astraeus/jdbc/util/Util.java @@ -0,0 +1,25 @@ +package nl.astraeus.jdbc.util; + +import java.text.DecimalFormat; +import java.text.NumberFormat; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 12:28 PM + */ +public class Util { + // utility functions + public static String formatNano(long l) { + NumberFormat format = new DecimalFormat("###,##0.000000"); + + return format.format((double) l / 1000000.0); + } + + public static void printMemoryUsage() { + System.out.println("Used memory: "+((Runtime.getRuntime().totalMemory() / (1024*1024))-(Runtime.getRuntime().freeMemory() / (1024*1024)))); + System.out.println("Free memory: "+(Runtime.getRuntime().freeMemory() / (1024*1024))); + System.out.println("Total memory: "+(Runtime.getRuntime().totalMemory() / (1024*1024))); + System.out.println("Max memory: "+(Runtime.getRuntime().maxMemory() / (1024*1024))); + } +} diff --git a/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java b/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java new file mode 100644 index 0000000..a162d6f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java @@ -0,0 +1,90 @@ +package nl.astraeus.jdbc.web; + +import nl.astraeus.jdbc.util.IOUtils; +import nl.astraeus.jdbc.util.Util; +import nl.astraeus.jdbc.web.page.Menu; +import nl.astraeus.jdbc.web.page.Page; +import nl.astraeus.jdbc.web.page.QueryOverview; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import java.io.IOException; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:05 PM + */ +public class JdbcStatisticsServlet extends HttpServlet { + + private String head; + private String bottom; + + @Override + public void init() throws ServletException { + super.init(); + + try { + head = IOUtils.toString(getClass().getResourceAsStream("head.html")); + bottom = IOUtils.toString(getClass().getResourceAsStream("bottom.html")); + } catch (IOException e) { + throw new ServletException(e); + } + + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + doPost(req, resp); + } + + @Override + protected void doPost(final HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + long nano = System.nanoTime(); + + HttpSession session = req.getSession(); + boolean ajax = "true".equals(req.getParameter("ajax")); + + resp.setContentType("text/html"); + + Page page = (Page)session.getAttribute("page"); + Page menu = (Page)session.getAttribute("menu"); + + session.setMaxInactiveInterval(1800); + + if (menu == null) { + menu = new Menu(); + + session.setAttribute("menu", menu); + } + + if (page == null || "menumain".equals(req.getParameter("action"))) { + page = new QueryOverview(); + } else if ("diagnostics".equals(req.getParameter("action"))) { + //page = new Diagnostics(); + } else { + page = page .processRequest(req); + } + + menu.processRequest(req); + + session.setAttribute("page", page); + + if (!ajax) { + resp.getWriter().print(head); + } + + resp.getWriter().print(menu.render(req)); + resp.getWriter().print(page.render(req)); + + if (!ajax) { + resp.getWriter().print(bottom); + } + + System.out.println("Request ends, time="+ Util.formatNano(System.nanoTime() - nano) +", page="+page.getClass().getSimpleName()); + } + +} diff --git a/src/nl/astraeus/jdbc/web/ResourceServlet.java b/src/nl/astraeus/jdbc/web/ResourceServlet.java new file mode 100644 index 0000000..7abfe6f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/ResourceServlet.java @@ -0,0 +1,49 @@ +package nl.astraeus.jdbc.web; + +import nl.astraeus.jdbc.util.IOUtils; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.InputStream; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:05 PM + */ +public class ResourceServlet extends HttpServlet { + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String uri = req.getRequestURI(); + + uri = "nl/astraeus/jdbc/web" + uri; + InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(uri); + + if (in == null) { + resp.sendError(404, "Cannot find resource '" + uri + "'."); + } else { + try { + if (uri.endsWith("js")) { + resp.setContentType("text/javascript"); + } else if (uri.endsWith("css")) { + resp.setContentType("text/css"); + } else if (uri.endsWith("png")) { + resp.setContentType("image/png"); + } else if (uri.endsWith("jpg")) { + resp.setContentType("image/jpeg"); + } else if (uri.endsWith("gif")) { + resp.setContentType("image/gif"); + } + + IOUtils.copy(in, resp.getOutputStream()); + } finally { + in.close(); + } + } + } + +} diff --git a/src/nl/astraeus/jdbc/web/bottom.html b/src/nl/astraeus/jdbc/web/bottom.html new file mode 100644 index 0000000..1288de4 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/bottom.html @@ -0,0 +1,8 @@ + + +
+ + + + + \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/head.html b/src/nl/astraeus/jdbc/web/head.html new file mode 100644 index 0000000..0f8f6a3 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/head.html @@ -0,0 +1,96 @@ + + + + + + + Simple JDBC Statistics + + + + + + + + + + + + + + + + + + + +
+
+ +
+ diff --git a/src/nl/astraeus/jdbc/web/page/Menu.html b/src/nl/astraeus/jdbc/web/page/Menu.html new file mode 100644 index 0000000..505c7c2 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.html @@ -0,0 +1,42 @@ + diff --git a/src/nl/astraeus/jdbc/web/page/Menu.java b/src/nl/astraeus/jdbc/web/page/Menu.java new file mode 100644 index 0000000..f0a349a --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.java @@ -0,0 +1,27 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 9:07 PM + */ +public class Menu extends TemplatePage { + + @Override + public Page processRequest(HttpServletRequest request) { + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + result.put("user", request.getSession().getAttribute("user")); + + return result; + } +} diff --git a/src/nl/astraeus/jdbc/web/page/Page.java b/src/nl/astraeus/jdbc/web/page/Page.java new file mode 100644 index 0000000..9d526d6 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Page.java @@ -0,0 +1,17 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:20 PM + */ +public abstract class Page { + + public abstract Page processRequest(HttpServletRequest request); + public abstract Map defineModel(HttpServletRequest request); + public abstract String render(HttpServletRequest request); + +} diff --git a/src/nl/astraeus/jdbc/web/page/QueryOverview.html b/src/nl/astraeus/jdbc/web/page/QueryOverview.html new file mode 100644 index 0000000..64a88fb --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/QueryOverview.html @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + {foreach(queries as q)} + + + + + + + {eachend} + +
Total timeAvg. time# CallsSql
{q.total}{q.nano}{q.count}{q.sql}
diff --git a/src/nl/astraeus/jdbc/web/page/QueryOverview.java b/src/nl/astraeus/jdbc/web/page/QueryOverview.java new file mode 100644 index 0000000..02982f1 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/QueryOverview.java @@ -0,0 +1,92 @@ +package nl.astraeus.jdbc.web.page; + +import nl.astraeus.jdbc.JdbcLogger; + +import javax.servlet.http.HttpServletRequest; +import java.util.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 9:16 PM + */ +public class QueryOverview extends TemplatePage { + + boolean sortTotalCalls = true; + boolean sortAvgTime = false; + boolean sortTotalTime = false; + + @Override + public Page processRequest(HttpServletRequest request) { + if ("sortTotalCalls".equals(request.getParameter("action"))) { + sortTotalCalls = true; + sortAvgTime = false; + sortTotalTime = false; + } else if ("sortAvgTime".equals(request.getParameter("action"))) { + sortTotalCalls = false; + sortAvgTime = true; + sortTotalTime = false; + } else if ("sortTotalTime".equals(request.getParameter("action"))) { + sortTotalCalls = false; + sortAvgTime = false; + sortTotalTime = true; + } + + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + List entries = new ArrayList(JdbcLogger.get().getEntries()); + + if (sortTotalCalls) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + return o2.count - o1.count; + } + }); + } else if (sortAvgTime) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + long n1 = o1.nano / o1.count; + long n2 = o2.nano / o2.count; + + if (n2 > n1) { + return 1; + } else if (n2 < n1) { + return -1; + } else { + return 0; + } + } + }); + } else if (sortTotalTime) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + if (o2.nano > o1.nano) { + return 1; + } else if (o2.nano < o1.nano) { + return -1; + } else { + return 0; + } + } + }); + } + + result.put("queries", entries); + result.put("count", entries.size()); + + result.put("sortTotalCalls", sortTotalCalls); + result.put("sortAvgTime", sortAvgTime); + result.put("sortTotalTime", sortTotalTime); + + return result; + } + +} diff --git a/src/nl/astraeus/jdbc/web/page/TemplatePage.java b/src/nl/astraeus/jdbc/web/page/TemplatePage.java new file mode 100644 index 0000000..33e2641 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/TemplatePage.java @@ -0,0 +1,58 @@ +package nl.astraeus.jdbc.web.page; + +import nl.astraeus.template.EscapeMode; +import nl.astraeus.template.SimpleTemplate; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:20 PM + */ +public abstract class TemplatePage extends Page { + + private SimpleTemplate template; + + protected TemplatePage() { + template = getSimpleTemplate(this.getClass()); + } + + public String render(HttpServletRequest request) { + return template.render(defineModel(request)); + } + + private static Map templateCache = new HashMap(); + + public synchronized static SimpleTemplate getSimpleTemplate(Class cls) { + SimpleTemplate result = templateCache.get(cls); + + if (result == null) { + InputStream in = null; + + try { + in = cls.getResourceAsStream(cls.getSimpleName() + ".html"); + + result = SimpleTemplate.readTemplate('{','}', EscapeMode.HTML, in); + + templateCache.put(cls, result); + } catch (IOException e) { + throw new IllegalStateException(e); + } finally { + if (in != null) { + try { + in.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + + return result; + } +} diff --git a/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css b/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css new file mode 100644 index 0000000..0e0056f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css @@ -0,0 +1,581 @@ +/*! + * Bootstrap Responsive v2.0.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ +.clearfix { + *zoom: 1; +} +.clearfix:before, .clearfix:after { + display: table; + content: ""; +} +.clearfix:after { + clear: both; +} +.hidden { + display: none; + visibility: hidden; +} +@media (max-width: 480px) { + .nav-collapse { + -webkit-transform: translate3d(0, 0, 0); + } + .page-header h1 small { + display: block; + line-height: 18px; + } + input[class*="span"], + select[class*="span"], + textarea[class*="span"], + .uneditable-input { + display: block; + width: 100%; + min-height: 28px; + /* Make inputs at least the height of their button counterpart */ + + /* Makes inputs behave like true block-level elements */ + + -webkit-box-sizing: border-box; + /* Older Webkit */ + + -moz-box-sizing: border-box; + /* Older FF */ + + -ms-box-sizing: border-box; + /* IE8 */ + + box-sizing: border-box; + /* CSS3 spec*/ + + } + .input-prepend input[class*="span"], .input-append input[class*="span"] { + width: auto; + } + input[type="checkbox"], input[type="radio"] { + border: 1px solid #ccc; + } + .form-horizontal .control-group > label { + float: none; + width: auto; + padding-top: 0; + text-align: left; + } + .form-horizontal .controls { + margin-left: 0; + } + .form-horizontal .control-list { + padding-top: 0; + } + .form-horizontal .form-actions { + padding-left: 10px; + padding-right: 10px; + } + .modal { + position: absolute; + top: 10px; + left: 10px; + right: 10px; + width: auto; + margin: 0; + } + .modal.fade.in { + top: auto; + } + .modal-header .close { + padding: 10px; + margin: -10px; + } + .carousel-caption { + position: static; + } +} +@media (max-width: 767px) { + .container { + width: auto; + padding: 0 20px; + } + .row-fluid { + width: 100%; + } + .row { + margin-left: 0; + } + .row > [class*="span"], .row-fluid > [class*="span"] { + float: none; + display: block; + width: auto; + margin: 0; + } +} +@media (min-width: 768px) and (max-width: 979px) { + .row { + margin-left: -20px; + *zoom: 1; + } + .row:before, .row:after { + display: table; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + margin-left: 20px; + } + .span1 { + width: 42px; + } + .span2 { + width: 104px; + } + .span3 { + width: 166px; + } + .span4 { + width: 228px; + } + .span5 { + width: 290px; + } + .span6 { + width: 352px; + } + .span7 { + width: 414px; + } + .span8 { + width: 476px; + } + .span9 { + width: 538px; + } + .span10 { + width: 600px; + } + .span11 { + width: 662px; + } + .span12, .container { + width: 724px; + } + .offset1 { + margin-left: 82px; + } + .offset2 { + margin-left: 144px; + } + .offset3 { + margin-left: 206px; + } + .offset4 { + margin-left: 268px; + } + .offset5 { + margin-left: 330px; + } + .offset6 { + margin-left: 392px; + } + .offset7 { + margin-left: 454px; + } + .offset8 { + margin-left: 516px; + } + .offset9 { + margin-left: 578px; + } + .offset10 { + margin-left: 640px; + } + .offset11 { + margin-left: 702px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, .row-fluid:after { + display: table; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid > [class*="span"] { + float: left; + margin-left: 2.762430939%; + } + .row-fluid > [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid > .span1 { + width: 5.801104972%; + } + .row-fluid > .span2 { + width: 14.364640883%; + } + .row-fluid > .span3 { + width: 22.928176794%; + } + .row-fluid > .span4 { + width: 31.491712705%; + } + .row-fluid > .span5 { + width: 40.055248616%; + } + .row-fluid > .span6 { + width: 48.618784527%; + } + .row-fluid > .span7 { + width: 57.182320438000005%; + } + .row-fluid > .span8 { + width: 65.74585634900001%; + } + .row-fluid > .span9 { + width: 74.30939226%; + } + .row-fluid > .span10 { + width: 82.87292817100001%; + } + .row-fluid > .span11 { + width: 91.436464082%; + } + .row-fluid > .span12 { + width: 99.999999993%; + } + input.span1, textarea.span1, .uneditable-input.span1 { + width: 32px; + } + input.span2, textarea.span2, .uneditable-input.span2 { + width: 94px; + } + input.span3, textarea.span3, .uneditable-input.span3 { + width: 156px; + } + input.span4, textarea.span4, .uneditable-input.span4 { + width: 218px; + } + input.span5, textarea.span5, .uneditable-input.span5 { + width: 280px; + } + input.span6, textarea.span6, .uneditable-input.span6 { + width: 342px; + } + input.span7, textarea.span7, .uneditable-input.span7 { + width: 404px; + } + input.span8, textarea.span8, .uneditable-input.span8 { + width: 466px; + } + input.span9, textarea.span9, .uneditable-input.span9 { + width: 528px; + } + input.span10, textarea.span10, .uneditable-input.span10 { + width: 590px; + } + input.span11, textarea.span11, .uneditable-input.span11 { + width: 652px; + } + input.span12, textarea.span12, .uneditable-input.span12 { + width: 714px; + } +} +@media (max-width: 979px) { + body { + padding-top: 0; + } + .navbar-fixed-top { + position: static; + margin-bottom: 18px; + } + .navbar-fixed-top .navbar-inner { + padding: 5px; + } + .navbar .container { + width: auto; + padding: 0; + } + .navbar .brand { + padding-left: 10px; + padding-right: 10px; + margin: 0 0 0 -5px; + } + .navbar .nav-collapse { + clear: left; + } + .navbar .nav { + float: none; + margin: 0 0 9px; + } + .navbar .nav > li { + float: none; + } + .navbar .nav > li > a { + margin-bottom: 2px; + } + .navbar .nav > .divider-vertical { + display: none; + } + .navbar .nav .nav-header { + color: #999999; + text-shadow: none; + } + .navbar .nav > li > a, .navbar .dropdown-menu a { + padding: 6px 15px; + font-weight: bold; + color: #999999; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + } + .navbar .dropdown-menu li + li a { + margin-bottom: 2px; + } + .navbar .nav > li > a:hover, .navbar .dropdown-menu a:hover { + background-color: #222222; + } + .navbar .dropdown-menu { + position: static; + top: auto; + left: auto; + float: none; + display: block; + max-width: none; + margin: 0 15px; + padding: 0; + background-color: transparent; + border: none; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + } + .navbar .dropdown-menu:before, .navbar .dropdown-menu:after { + display: none; + } + .navbar .dropdown-menu .divider { + display: none; + } + .navbar-form, .navbar-search { + float: none; + padding: 9px 15px; + margin: 9px 0; + border-top: 1px solid #222222; + border-bottom: 1px solid #222222; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + } + .navbar .nav.pull-right { + float: none; + margin-left: 0; + } + .navbar-static .navbar-inner { + padding-left: 10px; + padding-right: 10px; + } + .btn-navbar { + display: block; + } + .nav-collapse { + overflow: hidden; + height: 0; + } +} +@media (min-width: 980px) { + .nav-collapse.collapse { + height: auto !important; + } +} +@media (min-width: 1200px) { + .row { + margin-left: -30px; + *zoom: 1; + } + .row:before, .row:after { + display: table; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + margin-left: 30px; + } + .span1 { + width: 70px; + } + .span2 { + width: 170px; + } + .span3 { + width: 270px; + } + .span4 { + width: 370px; + } + .span5 { + width: 470px; + } + .span6 { + width: 570px; + } + .span7 { + width: 670px; + } + .span8 { + width: 770px; + } + .span9 { + width: 870px; + } + .span10 { + width: 970px; + } + .span11 { + width: 1070px; + } + .span12, .container { + width: 1170px; + } + .offset1 { + margin-left: 130px; + } + .offset2 { + margin-left: 230px; + } + .offset3 { + margin-left: 330px; + } + .offset4 { + margin-left: 430px; + } + .offset5 { + margin-left: 530px; + } + .offset6 { + margin-left: 630px; + } + .offset7 { + margin-left: 730px; + } + .offset8 { + margin-left: 830px; + } + .offset9 { + margin-left: 930px; + } + .offset10 { + margin-left: 1030px; + } + .offset11 { + margin-left: 1130px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, .row-fluid:after { + display: table; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid > [class*="span"] { + float: left; + margin-left: 2.564102564%; + } + .row-fluid > [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid > .span1 { + width: 5.982905983%; + } + .row-fluid > .span2 { + width: 14.529914530000001%; + } + .row-fluid > .span3 { + width: 23.076923077%; + } + .row-fluid > .span4 { + width: 31.623931624%; + } + .row-fluid > .span5 { + width: 40.170940171000005%; + } + .row-fluid > .span6 { + width: 48.717948718%; + } + .row-fluid > .span7 { + width: 57.264957265%; + } + .row-fluid > .span8 { + width: 65.81196581200001%; + } + .row-fluid > .span9 { + width: 74.358974359%; + } + .row-fluid > .span10 { + width: 82.905982906%; + } + .row-fluid > .span11 { + width: 91.45299145300001%; + } + .row-fluid > .span12 { + width: 100%; + } + input.span1, textarea.span1, .uneditable-input.span1 { + width: 60px; + } + input.span2, textarea.span2, .uneditable-input.span2 { + width: 160px; + } + input.span3, textarea.span3, .uneditable-input.span3 { + width: 260px; + } + input.span4, textarea.span4, .uneditable-input.span4 { + width: 360px; + } + input.span5, textarea.span5, .uneditable-input.span5 { + width: 460px; + } + input.span6, textarea.span6, .uneditable-input.span6 { + width: 560px; + } + input.span7, textarea.span7, .uneditable-input.span7 { + width: 660px; + } + input.span8, textarea.span8, .uneditable-input.span8 { + width: 760px; + } + input.span9, textarea.span9, .uneditable-input.span9 { + width: 860px; + } + input.span10, textarea.span10, .uneditable-input.span10 { + width: 960px; + } + input.span11, textarea.span11, .uneditable-input.span11 { + width: 1060px; + } + input.span12, textarea.span12, .uneditable-input.span12 { + width: 1160px; + } + .thumbnails { + margin-left: -30px; + } + .thumbnails > li { + margin-left: 30px; + } +} diff --git a/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css b/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css new file mode 100644 index 0000000..6229c12 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css @@ -0,0 +1,3521 @@ +/*! + * Bootstrap v2.0.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +nav, +section { + display: block; +} +audio, canvas, video { + display: inline-block; + *display: inline; + *zoom: 1; +} +audio:not([controls]) { + display: none; +} +html { + font-size: 100%; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} +a:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +a:hover, a:active { + outline: 0; +} +sub, sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} +sup { + top: -0.5em; +} +sub { + bottom: -0.25em; +} +img { + max-width: 100%; + height: auto; + border: 0; + -ms-interpolation-mode: bicubic; +} +button, +input, +select, +textarea { + margin: 0; + font-size: 100%; + vertical-align: middle; +} +button, input { + *overflow: visible; + line-height: normal; +} +button::-moz-focus-inner, input::-moz-focus-inner { + padding: 0; + border: 0; +} +button, +input[type="button"], +input[type="reset"], +input[type="submit"] { + cursor: pointer; + -webkit-appearance: button; +} +input[type="search"] { + -webkit-appearance: textfield; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +input[type="search"]::-webkit-search-decoration, input[type="search"]::-webkit-search-cancel-button { + -webkit-appearance: none; +} +textarea { + overflow: auto; + vertical-align: top; +} +.clearfix { + *zoom: 1; +} +.clearfix:before, .clearfix:after { + display: table; + content: ""; +} +.clearfix:after { + clear: both; +} +body { + margin: 0; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 18px; + color: #333333; + background-color: #ffffff; +} +a { + color: #0088cc; + text-decoration: none; +} +a:hover { + color: #005580; + text-decoration: underline; +} +.row { + margin-left: -20px; + *zoom: 1; +} +.row:before, .row:after { + display: table; + content: ""; +} +.row:after { + clear: both; +} +[class*="span"] { + float: left; + margin-left: 20px; +} +.span1 { + width: 60px; +} +.span2 { + width: 140px; +} +.span3 { + width: 220px; +} +.span4 { + width: 300px; +} +.span5 { + width: 380px; +} +.span6 { + width: 460px; +} +.span7 { + width: 540px; +} +.span8 { + width: 620px; +} +.span9 { + width: 700px; +} +.span10 { + width: 780px; +} +.span11 { + width: 860px; +} +.span12, .container { + width: 940px; +} +.offset1 { + margin-left: 100px; +} +.offset2 { + margin-left: 180px; +} +.offset3 { + margin-left: 260px; +} +.offset4 { + margin-left: 340px; +} +.offset5 { + margin-left: 420px; +} +.offset6 { + margin-left: 500px; +} +.offset7 { + margin-left: 580px; +} +.offset8 { + margin-left: 660px; +} +.offset9 { + margin-left: 740px; +} +.offset10 { + margin-left: 820px; +} +.offset11 { + margin-left: 900px; +} +.row-fluid { + width: 100%; + *zoom: 1; +} +.row-fluid:before, .row-fluid:after { + display: table; + content: ""; +} +.row-fluid:after { + clear: both; +} +.row-fluid > [class*="span"] { + float: left; + margin-left: 2.127659574%; +} +.row-fluid > [class*="span"]:first-child { + margin-left: 0; +} +.row-fluid > .span1 { + width: 6.382978723%; +} +.row-fluid > .span2 { + width: 14.89361702%; +} +.row-fluid > .span3 { + width: 23.404255317%; +} +.row-fluid > .span4 { + width: 31.914893614%; +} +.row-fluid > .span5 { + width: 40.425531911%; +} +.row-fluid > .span6 { + width: 48.93617020799999%; +} +.row-fluid > .span7 { + width: 57.446808505%; +} +.row-fluid > .span8 { + width: 65.95744680199999%; +} +.row-fluid > .span9 { + width: 74.468085099%; +} +.row-fluid > .span10 { + width: 82.97872339599999%; +} +.row-fluid > .span11 { + width: 91.489361693%; +} +.row-fluid > .span12 { + width: 99.99999998999999%; +} +.container { + width: 940px; + margin-left: auto; + margin-right: auto; + *zoom: 1; +} +.container:before, .container:after { + display: table; + content: ""; +} +.container:after { + clear: both; +} +.container-fluid { + padding-left: 20px; + padding-right: 20px; + *zoom: 1; +} +.container-fluid:before, .container-fluid:after { + display: table; + content: ""; +} +.container-fluid:after { + clear: both; +} +p { + margin: 0 0 9px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 18px; +} +p small { + font-size: 11px; + color: #999999; +} +.lead { + margin-bottom: 18px; + font-size: 20px; + font-weight: 200; + line-height: 27px; +} +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 0; + font-weight: bold; + color: #333333; + text-rendering: optimizelegibility; +} +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small { + font-weight: normal; + color: #999999; +} +h1 { + font-size: 30px; + line-height: 36px; +} +h1 small { + font-size: 18px; +} +h2 { + font-size: 24px; + line-height: 36px; +} +h2 small { + font-size: 18px; +} +h3 { + line-height: 27px; + font-size: 18px; +} +h3 small { + font-size: 14px; +} +h4, h5, h6 { + line-height: 18px; +} +h4 { + font-size: 14px; +} +h4 small { + font-size: 12px; +} +h5 { + font-size: 12px; +} +h6 { + font-size: 11px; + color: #999999; + text-transform: uppercase; +} +.page-header { + padding-bottom: 17px; + margin: 18px 0; + border-bottom: 1px solid #eeeeee; +} +.page-header h1 { + line-height: 1; +} +ul, ol { + padding: 0; + margin: 0 0 9px 25px; +} +ul ul, +ul ol, +ol ol, +ol ul { + margin-bottom: 0; +} +ul { + list-style: disc; +} +ol { + list-style: decimal; +} +li { + line-height: 18px; +} +ul.unstyled, ol.unstyled { + margin-left: 0; + list-style: none; +} +dl { + margin-bottom: 18px; +} +dt, dd { + line-height: 18px; +} +dt { + font-weight: bold; +} +dd { + margin-left: 9px; +} +hr { + margin: 18px 0; + border: 0; + border-top: 1px solid #eeeeee; + border-bottom: 1px solid #ffffff; +} +strong { + font-weight: bold; +} +em { + font-style: italic; +} +.muted { + color: #999999; +} +abbr { + font-size: 90%; + text-transform: uppercase; + border-bottom: 1px dotted #ddd; + cursor: help; +} +blockquote { + padding: 0 0 0 15px; + margin: 0 0 18px; + border-left: 5px solid #eeeeee; +} +blockquote p { + margin-bottom: 0; + font-size: 16px; + font-weight: 300; + line-height: 22.5px; +} +blockquote small { + display: block; + line-height: 18px; + color: #999999; +} +blockquote small:before { + content: '\2014 \00A0'; +} +blockquote.pull-right { + float: right; + padding-left: 0; + padding-right: 15px; + border-left: 0; + border-right: 5px solid #eeeeee; +} +blockquote.pull-right p, blockquote.pull-right small { + text-align: right; +} +q:before, +q:after, +blockquote:before, +blockquote:after { + content: ""; +} +address { + display: block; + margin-bottom: 18px; + line-height: 18px; + font-style: normal; +} +small { + font-size: 100%; +} +cite { + font-style: normal; +} +code, pre { + padding: 0 3px 2px; + font-family: Menlo, Monaco, "Courier New", monospace; + font-size: 12px; + color: #333333; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +code { + padding: 3px 4px; + color: #d14; + background-color: #f7f7f9; + border: 1px solid #e1e1e8; +} +pre { + display: block; + padding: 8.5px; + margin: 0 0 9px; + font-size: 12px; + line-height: 18px; + background-color: #f5f5f5; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.15); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + white-space: pre; + white-space: pre-wrap; + word-break: break-all; + word-wrap: break-word; +} +pre.prettyprint { + margin-bottom: 18px; +} +pre code { + padding: 0; + color: inherit; + background-color: transparent; + border: 0; +} +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} +form { + margin: 0 0 18px; +} +fieldset { + padding: 0; + margin: 0; + border: 0; +} +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 27px; + font-size: 19.5px; + line-height: 36px; + color: #333333; + border: 0; + border-bottom: 1px solid #eee; +} +legend small { + font-size: 13.5px; + color: #999999; +} +label, +input, +button, +select, +textarea { + font-size: 13px; + font-weight: normal; + line-height: 18px; +} +input, +button, +select, +textarea { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; +} +label { + display: block; + margin-bottom: 5px; + color: #333333; +} +input, +textarea, +select, +.uneditable-input { + display: inline-block; + width: 210px; + height: 18px; + padding: 4px; + margin-bottom: 9px; + font-size: 13px; + line-height: 18px; + color: #555555; + border: 1px solid #ccc; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.uneditable-textarea { + width: auto; + height: auto; +} +label input, label textarea, label select { + display: block; +} +input[type="image"], input[type="checkbox"], input[type="radio"] { + width: auto; + height: auto; + padding: 0; + margin: 3px 0; + *margin-top: 0; + /* IE7 */ + + line-height: normal; + cursor: pointer; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + border: 0 \9; + /* IE9 and down */ + +} +input[type="image"] { + border: 0; +} +input[type="file"] { + width: auto; + padding: initial; + line-height: initial; + border: initial; + background-color: #ffffff; + background-color: initial; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +input[type="button"], input[type="reset"], input[type="submit"] { + width: auto; + height: auto; +} +select, input[type="file"] { + height: 28px; + /* In IE7, the height of the select element cannot be changed by height, only font-size */ + + *margin-top: 4px; + /* For IE7, add top margin to align select with labels */ + + line-height: 28px; +} +input[type="file"] { + line-height: 18px \9; +} +select { + width: 220px; + background-color: #ffffff; +} +select[multiple], select[size] { + height: auto; +} +input[type="image"] { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +textarea { + height: auto; +} +input[type="hidden"] { + display: none; +} +.radio, .checkbox { + padding-left: 18px; +} +.radio input[type="radio"], .checkbox input[type="checkbox"] { + float: left; + margin-left: -18px; +} +.controls > .radio:first-child, .controls > .checkbox:first-child { + padding-top: 5px; +} +.radio.inline, .checkbox.inline { + display: inline-block; + padding-top: 5px; + margin-bottom: 0; + vertical-align: middle; +} +.radio.inline + .radio.inline, .checkbox.inline + .checkbox.inline { + margin-left: 10px; +} +input, textarea { + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; + -moz-transition: border linear 0.2s, box-shadow linear 0.2s; + -ms-transition: border linear 0.2s, box-shadow linear 0.2s; + -o-transition: border linear 0.2s, box-shadow linear 0.2s; + transition: border linear 0.2s, box-shadow linear 0.2s; +} +input:focus, textarea:focus { + border-color: rgba(82, 168, 236, 0.8); + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + outline: 0; + outline: thin dotted \9; + /* IE6-9 */ + +} +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus, +select:focus { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.input-mini { + width: 60px; +} +.input-small { + width: 90px; +} +.input-medium { + width: 150px; +} +.input-large { + width: 210px; +} +.input-xlarge { + width: 270px; +} +.input-xxlarge { + width: 530px; +} +input[class*="span"], +select[class*="span"], +textarea[class*="span"], +.uneditable-input { + float: none; + margin-left: 0; +} +input.span1, textarea.span1, .uneditable-input.span1 { + width: 50px; +} +input.span2, textarea.span2, .uneditable-input.span2 { + width: 130px; +} +input.span3, textarea.span3, .uneditable-input.span3 { + width: 210px; +} +input.span4, textarea.span4, .uneditable-input.span4 { + width: 290px; +} +input.span5, textarea.span5, .uneditable-input.span5 { + width: 370px; +} +input.span6, textarea.span6, .uneditable-input.span6 { + width: 450px; +} +input.span7, textarea.span7, .uneditable-input.span7 { + width: 530px; +} +input.span8, textarea.span8, .uneditable-input.span8 { + width: 610px; +} +input.span9, textarea.span9, .uneditable-input.span9 { + width: 690px; +} +input.span10, textarea.span10, .uneditable-input.span10 { + width: 770px; +} +input.span11, textarea.span11, .uneditable-input.span11 { + width: 850px; +} +input.span12, textarea.span12, .uneditable-input.span12 { + width: 930px; +} +input[disabled], +select[disabled], +textarea[disabled], +input[readonly], +select[readonly], +textarea[readonly] { + background-color: #f5f5f5; + border-color: #ddd; + cursor: not-allowed; +} +.control-group.warning > label, .control-group.warning .help-block, .control-group.warning .help-inline { + color: #c09853; +} +.control-group.warning input, .control-group.warning select, .control-group.warning textarea { + color: #c09853; + border-color: #c09853; +} +.control-group.warning input:focus, .control-group.warning select:focus, .control-group.warning textarea:focus { + border-color: #a47e3c; + -webkit-box-shadow: 0 0 6px #dbc59e; + -moz-box-shadow: 0 0 6px #dbc59e; + box-shadow: 0 0 6px #dbc59e; +} +.control-group.warning .input-prepend .add-on, .control-group.warning .input-append .add-on { + color: #c09853; + background-color: #fcf8e3; + border-color: #c09853; +} +.control-group.error > label, .control-group.error .help-block, .control-group.error .help-inline { + color: #b94a48; +} +.control-group.error input, .control-group.error select, .control-group.error textarea { + color: #b94a48; + border-color: #b94a48; +} +.control-group.error input:focus, .control-group.error select:focus, .control-group.error textarea:focus { + border-color: #953b39; + -webkit-box-shadow: 0 0 6px #d59392; + -moz-box-shadow: 0 0 6px #d59392; + box-shadow: 0 0 6px #d59392; +} +.control-group.error .input-prepend .add-on, .control-group.error .input-append .add-on { + color: #b94a48; + background-color: #f2dede; + border-color: #b94a48; +} +.control-group.success > label, .control-group.success .help-block, .control-group.success .help-inline { + color: #468847; +} +.control-group.success input, .control-group.success select, .control-group.success textarea { + color: #468847; + border-color: #468847; +} +.control-group.success input:focus, .control-group.success select:focus, .control-group.success textarea:focus { + border-color: #356635; + -webkit-box-shadow: 0 0 6px #7aba7b; + -moz-box-shadow: 0 0 6px #7aba7b; + box-shadow: 0 0 6px #7aba7b; +} +.control-group.success .input-prepend .add-on, .control-group.success .input-append .add-on { + color: #468847; + background-color: #dff0d8; + border-color: #468847; +} +input:focus:required:invalid, textarea:focus:required:invalid, select:focus:required:invalid { + color: #b94a48; + border-color: #ee5f5b; +} +input:focus:required:invalid:focus, textarea:focus:required:invalid:focus, select:focus:required:invalid:focus { + border-color: #e9322d; + -webkit-box-shadow: 0 0 6px #f8b9b7; + -moz-box-shadow: 0 0 6px #f8b9b7; + box-shadow: 0 0 6px #f8b9b7; +} +.form-actions { + padding: 17px 20px 18px; + margin-top: 18px; + margin-bottom: 18px; + background-color: #f5f5f5; + border-top: 1px solid #ddd; +} +.uneditable-input { + display: block; + background-color: #ffffff; + border-color: #eee; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + cursor: not-allowed; +} +:-moz-placeholder { + color: #999999; +} +::-webkit-input-placeholder { + color: #999999; +} +.help-block { + display: block; + margin-top: 5px; + margin-bottom: 0; + color: #999999; +} +.help-inline { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; + margin-bottom: 9px; + vertical-align: middle; + padding-left: 5px; +} +.input-prepend, .input-append { + margin-bottom: 5px; + *zoom: 1; +} +.input-prepend:before, +.input-append:before, +.input-prepend:after, +.input-append:after { + display: table; + content: ""; +} +.input-prepend:after, .input-append:after { + clear: both; +} +.input-prepend input, +.input-append input, +.input-prepend .uneditable-input, +.input-append .uneditable-input { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.input-prepend input:focus, +.input-append input:focus, +.input-prepend .uneditable-input:focus, +.input-append .uneditable-input:focus { + position: relative; + z-index: 2; +} +.input-prepend .uneditable-input, .input-append .uneditable-input { + border-left-color: #ccc; +} +.input-prepend .add-on, .input-append .add-on { + float: left; + display: block; + width: auto; + min-width: 16px; + height: 18px; + margin-right: -1px; + padding: 4px 5px; + font-weight: normal; + line-height: 18px; + color: #999999; + text-align: center; + text-shadow: 0 1px 0 #ffffff; + background-color: #f5f5f5; + border: 1px solid #ccc; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.input-prepend .active, .input-append .active { + background-color: #a9dba9; + border-color: #46a546; +} +.input-prepend .add-on { + *margin-top: 1px; + /* IE6-7 */ + +} +.input-append input, .input-append .uneditable-input { + float: left; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.input-append .uneditable-input { + border-left-color: #eee; + border-right-color: #ccc; +} +.input-append .add-on { + margin-right: 0; + margin-left: -1px; + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.input-append input:first-child { + *margin-left: -160px; +} +.input-append input:first-child + .add-on { + *margin-left: -21px; +} +.search-query { + padding-left: 14px; + padding-right: 14px; + margin-bottom: 0; + -webkit-border-radius: 14px; + -moz-border-radius: 14px; + border-radius: 14px; +} +.form-search input, +.form-inline input, +.form-horizontal input, +.form-search textarea, +.form-inline textarea, +.form-horizontal textarea, +.form-search select, +.form-inline select, +.form-horizontal select, +.form-search .help-inline, +.form-inline .help-inline, +.form-horizontal .help-inline, +.form-search .uneditable-input, +.form-inline .uneditable-input, +.form-horizontal .uneditable-input { + display: inline-block; + margin-bottom: 0; +} +.form-search .hide, .form-inline .hide, .form-horizontal .hide { + display: none; +} +.form-search label, +.form-inline label, +.form-search .input-append, +.form-inline .input-append, +.form-search .input-prepend, +.form-inline .input-prepend { + display: inline-block; +} +.form-search .input-append .add-on, +.form-inline .input-prepend .add-on, +.form-search .input-append .add-on, +.form-inline .input-prepend .add-on { + vertical-align: middle; +} +.form-search .radio, +.form-inline .radio, +.form-search .checkbox, +.form-inline .checkbox { + margin-bottom: 0; + vertical-align: middle; +} +.control-group { + margin-bottom: 9px; +} +legend + .control-group { + margin-top: 18px; + -webkit-margin-top-collapse: separate; +} +.form-horizontal .control-group { + margin-bottom: 18px; + *zoom: 1; +} +.form-horizontal .control-group:before, .form-horizontal .control-group:after { + display: table; + content: ""; +} +.form-horizontal .control-group:after { + clear: both; +} +.form-horizontal .control-label { + float: left; + width: 140px; + padding-top: 5px; + text-align: right; +} +.form-horizontal .controls { + margin-left: 160px; +} +.form-horizontal .form-actions { + padding-left: 160px; +} +table { + max-width: 100%; + border-collapse: collapse; + border-spacing: 0; +} +.table { + width: 100%; + margin-bottom: 18px; +} +.table th, .table td { + padding: 8px; + line-height: 18px; + text-align: left; + vertical-align: top; + border-top: 1px solid #ddd; +} +.table th { + font-weight: bold; +} +.table thead th { + vertical-align: bottom; +} +.table thead:first-child tr th, .table thead:first-child tr td { + border-top: 0; +} +.table tbody + tbody { + border-top: 2px solid #ddd; +} +.table-condensed th, .table-condensed td { + padding: 4px 5px; +} +.table-bordered { + border: 1px solid #ddd; + border-collapse: separate; + *border-collapse: collapsed; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.table-bordered th + th, +.table-bordered td + td, +.table-bordered th + td, +.table-bordered td + th { + border-left: 1px solid #ddd; +} +.table-bordered thead:first-child tr:first-child th, .table-bordered tbody:first-child tr:first-child th, .table-bordered tbody:first-child tr:first-child td { + border-top: 0; +} +.table-bordered thead:first-child tr:first-child th:first-child, .table-bordered tbody:first-child tr:first-child td:first-child { + -webkit-border-radius: 4px 0 0 0; + -moz-border-radius: 4px 0 0 0; + border-radius: 4px 0 0 0; +} +.table-bordered thead:first-child tr:first-child th:last-child, .table-bordered tbody:first-child tr:first-child td:last-child { + -webkit-border-radius: 0 4px 0 0; + -moz-border-radius: 0 4px 0 0; + border-radius: 0 4px 0 0; +} +.table-bordered thead:last-child tr:last-child th:first-child, .table-bordered tbody:last-child tr:last-child td:first-child { + -webkit-border-radius: 0 0 0 4px; + -moz-border-radius: 0 0 0 4px; + border-radius: 0 0 0 4px; +} +.table-bordered thead:last-child tr:last-child th:last-child, .table-bordered tbody:last-child tr:last-child td:last-child { + -webkit-border-radius: 0 0 4px 0; + -moz-border-radius: 0 0 4px 0; + border-radius: 0 0 4px 0; +} +.table-striped tbody tr:nth-child(odd) td, .table-striped tbody tr:nth-child(odd) th { + background-color: #f9f9f9; +} +.table tbody tr:hover td, .table tbody tr:hover th { + background-color: #f5f5f5; +} +table .span1 { + float: none; + width: 44px; + margin-left: 0; +} +table .span2 { + float: none; + width: 124px; + margin-left: 0; +} +table .span3 { + float: none; + width: 204px; + margin-left: 0; +} +table .span4 { + float: none; + width: 284px; + margin-left: 0; +} +table .span5 { + float: none; + width: 364px; + margin-left: 0; +} +table .span6 { + float: none; + width: 444px; + margin-left: 0; +} +table .span7 { + float: none; + width: 524px; + margin-left: 0; +} +table .span8 { + float: none; + width: 604px; + margin-left: 0; +} +table .span9 { + float: none; + width: 684px; + margin-left: 0; +} +table .span10 { + float: none; + width: 764px; + margin-left: 0; +} +table .span11 { + float: none; + width: 844px; + margin-left: 0; +} +table .span12 { + float: none; + width: 924px; + margin-left: 0; +} +[class^="icon-"], [class*=" icon-"] { + display: inline-block; + width: 14px; + height: 14px; + line-height: 14px; + vertical-align: text-top; + background-image: url("../img/glyphicons-halflings.png"); + background-position: 14px 14px; + background-repeat: no-repeat; + *margin-right: .3em; +} +[class^="icon-"]:last-child, [class*=" icon-"]:last-child { + *margin-left: 0; +} +.icon-white { + background-image: url("../img/glyphicons-halflings-white.png"); +} +.icon-glass { + background-position: 0 0; +} +.icon-music { + background-position: -24px 0; +} +.icon-search { + background-position: -48px 0; +} +.icon-envelope { + background-position: -72px 0; +} +.icon-heart { + background-position: -96px 0; +} +.icon-star { + background-position: -120px 0; +} +.icon-star-empty { + background-position: -144px 0; +} +.icon-user { + background-position: -168px 0; +} +.icon-film { + background-position: -192px 0; +} +.icon-th-large { + background-position: -216px 0; +} +.icon-th { + background-position: -240px 0; +} +.icon-th-list { + background-position: -264px 0; +} +.icon-ok { + background-position: -288px 0; +} +.icon-remove { + background-position: -312px 0; +} +.icon-zoom-in { + background-position: -336px 0; +} +.icon-zoom-out { + background-position: -360px 0; +} +.icon-off { + background-position: -384px 0; +} +.icon-signal { + background-position: -408px 0; +} +.icon-cog { + background-position: -432px 0; +} +.icon-trash { + background-position: -456px 0; +} +.icon-home { + background-position: 0 -24px; +} +.icon-file { + background-position: -24px -24px; +} +.icon-time { + background-position: -48px -24px; +} +.icon-road { + background-position: -72px -24px; +} +.icon-download-alt { + background-position: -96px -24px; +} +.icon-download { + background-position: -120px -24px; +} +.icon-upload { + background-position: -144px -24px; +} +.icon-inbox { + background-position: -168px -24px; +} +.icon-play-circle { + background-position: -192px -24px; +} +.icon-repeat { + background-position: -216px -24px; +} +.icon-refresh { + background-position: -240px -24px; +} +.icon-list-alt { + background-position: -264px -24px; +} +.icon-lock { + background-position: -287px -24px; +} +.icon-flag { + background-position: -312px -24px; +} +.icon-headphones { + background-position: -336px -24px; +} +.icon-volume-off { + background-position: -360px -24px; +} +.icon-volume-down { + background-position: -384px -24px; +} +.icon-volume-up { + background-position: -408px -24px; +} +.icon-qrcode { + background-position: -432px -24px; +} +.icon-barcode { + background-position: -456px -24px; +} +.icon-tag { + background-position: 0 -48px; +} +.icon-tags { + background-position: -25px -48px; +} +.icon-book { + background-position: -48px -48px; +} +.icon-bookmark { + background-position: -72px -48px; +} +.icon-print { + background-position: -96px -48px; +} +.icon-camera { + background-position: -120px -48px; +} +.icon-font { + background-position: -144px -48px; +} +.icon-bold { + background-position: -167px -48px; +} +.icon-italic { + background-position: -192px -48px; +} +.icon-text-height { + background-position: -216px -48px; +} +.icon-text-width { + background-position: -240px -48px; +} +.icon-align-left { + background-position: -264px -48px; +} +.icon-align-center { + background-position: -288px -48px; +} +.icon-align-right { + background-position: -312px -48px; +} +.icon-align-justify { + background-position: -336px -48px; +} +.icon-list { + background-position: -360px -48px; +} +.icon-indent-left { + background-position: -384px -48px; +} +.icon-indent-right { + background-position: -408px -48px; +} +.icon-facetime-video { + background-position: -432px -48px; +} +.icon-picture { + background-position: -456px -48px; +} +.icon-pencil { + background-position: 0 -72px; +} +.icon-map-marker { + background-position: -24px -72px; +} +.icon-adjust { + background-position: -48px -72px; +} +.icon-tint { + background-position: -72px -72px; +} +.icon-edit { + background-position: -96px -72px; +} +.icon-share { + background-position: -120px -72px; +} +.icon-check { + background-position: -144px -72px; +} +.icon-move { + background-position: -168px -72px; +} +.icon-step-backward { + background-position: -192px -72px; +} +.icon-fast-backward { + background-position: -216px -72px; +} +.icon-backward { + background-position: -240px -72px; +} +.icon-play { + background-position: -264px -72px; +} +.icon-pause { + background-position: -288px -72px; +} +.icon-stop { + background-position: -312px -72px; +} +.icon-forward { + background-position: -336px -72px; +} +.icon-fast-forward { + background-position: -360px -72px; +} +.icon-step-forward { + background-position: -384px -72px; +} +.icon-eject { + background-position: -408px -72px; +} +.icon-chevron-left { + background-position: -432px -72px; +} +.icon-chevron-right { + background-position: -456px -72px; +} +.icon-plus-sign { + background-position: 0 -96px; +} +.icon-minus-sign { + background-position: -24px -96px; +} +.icon-remove-sign { + background-position: -48px -96px; +} +.icon-ok-sign { + background-position: -72px -96px; +} +.icon-question-sign { + background-position: -96px -96px; +} +.icon-info-sign { + background-position: -120px -96px; +} +.icon-screenshot { + background-position: -144px -96px; +} +.icon-remove-circle { + background-position: -168px -96px; +} +.icon-ok-circle { + background-position: -192px -96px; +} +.icon-ban-circle { + background-position: -216px -96px; +} +.icon-arrow-left { + background-position: -240px -96px; +} +.icon-arrow-right { + background-position: -264px -96px; +} +.icon-arrow-up { + background-position: -289px -96px; +} +.icon-arrow-down { + background-position: -312px -96px; +} +.icon-share-alt { + background-position: -336px -96px; +} +.icon-resize-full { + background-position: -360px -96px; +} +.icon-resize-small { + background-position: -384px -96px; +} +.icon-plus { + background-position: -408px -96px; +} +.icon-minus { + background-position: -433px -96px; +} +.icon-asterisk { + background-position: -456px -96px; +} +.icon-exclamation-sign { + background-position: 0 -120px; +} +.icon-gift { + background-position: -24px -120px; +} +.icon-leaf { + background-position: -48px -120px; +} +.icon-fire { + background-position: -72px -120px; +} +.icon-eye-open { + background-position: -96px -120px; +} +.icon-eye-close { + background-position: -120px -120px; +} +.icon-warning-sign { + background-position: -144px -120px; +} +.icon-plane { + background-position: -168px -120px; +} +.icon-calendar { + background-position: -192px -120px; +} +.icon-random { + background-position: -216px -120px; +} +.icon-comment { + background-position: -240px -120px; +} +.icon-magnet { + background-position: -264px -120px; +} +.icon-chevron-up { + background-position: -288px -120px; +} +.icon-chevron-down { + background-position: -313px -119px; +} +.icon-retweet { + background-position: -336px -120px; +} +.icon-shopping-cart { + background-position: -360px -120px; +} +.icon-folder-close { + background-position: -384px -120px; +} +.icon-folder-open { + background-position: -408px -120px; +} +.icon-resize-vertical { + background-position: -432px -119px; +} +.icon-resize-horizontal { + background-position: -456px -118px; +} +.dropdown { + position: relative; +} +.dropdown-toggle { + *margin-bottom: -3px; +} +.dropdown-toggle:active, .open .dropdown-toggle { + outline: 0; +} +.caret { + display: inline-block; + width: 0; + height: 0; + text-indent: -99999px; + *text-indent: 0; + vertical-align: top; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 4px solid #000000; + opacity: 0.3; + filter: alpha(opacity=30); + content: "\2193"; +} +.dropdown .caret { + margin-top: 8px; + margin-left: 2px; +} +.dropdown:hover .caret, .open.dropdown .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + float: left; + display: none; + min-width: 160px; + _width: 160px; + padding: 4px 0; + margin: 0; + list-style: none; + background-color: #ffffff; + border-color: #ccc; + border-color: rgba(0, 0, 0, 0.2); + border-style: solid; + border-width: 1px; + -webkit-border-radius: 0 0 5px 5px; + -moz-border-radius: 0 0 5px 5px; + border-radius: 0 0 5px 5px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; + *border-right-width: 2px; + *border-bottom-width: 2px; +} +.dropdown-menu.bottom-up { + top: auto; + bottom: 100%; + margin-bottom: 2px; +} +.dropdown-menu .divider { + height: 1px; + margin: 5px 1px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #ffffff; + *width: 100%; + *margin: -5px 0 5px; +} +.dropdown-menu a { + display: block; + padding: 3px 15px; + clear: both; + font-weight: normal; + line-height: 18px; + color: #555555; + white-space: nowrap; +} +.dropdown-menu li > a:hover, .dropdown-menu .active > a, .dropdown-menu .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #0088cc; +} +.dropdown.open { + *z-index: 1000; +} +.dropdown.open .dropdown-toggle { + color: #ffffff; + background: #ccc; + background: rgba(0, 0, 0, 0.3); +} +.dropdown.open .dropdown-menu { + display: block; +} +.typeahead { + margin-top: 2px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #f5f5f5; + border: 1px solid #eee; + border: 1px solid rgba(0, 0, 0, 0.05); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 0, 0, 0.15); +} +.fade { + -webkit-transition: opacity 0.15s linear; + -moz-transition: opacity 0.15s linear; + -ms-transition: opacity 0.15s linear; + -o-transition: opacity 0.15s linear; + transition: opacity 0.15s linear; + opacity: 0; +} +.fade.in { + opacity: 1; +} +.collapse { + -webkit-transition: height 0.35s ease; + -moz-transition: height 0.35s ease; + -ms-transition: height 0.35s ease; + -o-transition: height 0.35s ease; + transition: height 0.35s ease; + position: relative; + overflow: hidden; + height: 0; +} +.collapse.in { + height: auto; +} +.close { + float: right; + font-size: 20px; + font-weight: bold; + line-height: 18px; + color: #000000; + text-shadow: 0 1px 0 #ffffff; + opacity: 0.2; + filter: alpha(opacity=20); +} +.close:hover { + color: #000000; + text-decoration: none; + opacity: 0.4; + filter: alpha(opacity=40); + cursor: pointer; +} +.btn { + display: inline-block; + padding: 4px 10px 4px; + margin-bottom: 0; + font-size: 13px; + line-height: 18px; + color: #333333; + text-align: center; + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); + vertical-align: middle; + background-color: #f5f5f5; + background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); + background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); + background-image: linear-gradient(top, #ffffff, #e6e6e6); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0); + border-color: #e6e6e6 #e6e6e6 #bfbfbf; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + border: 1px solid #ccc; + border-bottom-color: #bbb; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + cursor: pointer; + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + *margin-left: .3em; +} +.btn:hover, +.btn:active, +.btn.active, +.btn.disabled, +.btn[disabled] { + background-color: #e6e6e6; +} +.btn:active, .btn.active { + background-color: #cccccc \9; +} +.btn:first-child { + *margin-left: 0; +} +.btn:hover { + color: #333333; + text-decoration: none; + background-color: #e6e6e6; + background-position: 0 -15px; + -webkit-transition: background-position 0.1s linear; + -moz-transition: background-position 0.1s linear; + -ms-transition: background-position 0.1s linear; + -o-transition: background-position 0.1s linear; + transition: background-position 0.1s linear; +} +.btn:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.btn.active, .btn:active { + background-image: none; + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + background-color: #e6e6e6; + background-color: #d9d9d9 \9; + outline: 0; +} +.btn.disabled, .btn[disabled] { + cursor: default; + background-image: none; + background-color: #e6e6e6; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +.btn-large { + padding: 9px 14px; + font-size: 15px; + line-height: normal; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.btn-large [class^="icon-"] { + margin-top: 1px; +} +.btn-small { + padding: 5px 9px; + font-size: 11px; + line-height: 16px; +} +.btn-small [class^="icon-"] { + margin-top: -1px; +} +.btn-mini { + padding: 2px 6px; + font-size: 11px; + line-height: 14px; +} +.btn-primary, +.btn-primary:hover, +.btn-warning, +.btn-warning:hover, +.btn-danger, +.btn-danger:hover, +.btn-success, +.btn-success:hover, +.btn-info, +.btn-info:hover, +.btn-inverse, +.btn-inverse:hover { + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + color: #ffffff; +} +.btn-primary.active, +.btn-warning.active, +.btn-danger.active, +.btn-success.active, +.btn-info.active, +.btn-dark.active { + color: rgba(255, 255, 255, 0.75); +} +.btn-primary { + background-color: #006dcc; + background-image: -moz-linear-gradient(top, #0088cc, #0044cc); + background-image: -ms-linear-gradient(top, #0088cc, #0044cc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); + background-image: -o-linear-gradient(top, #0088cc, #0044cc); + background-image: linear-gradient(top, #0088cc, #0044cc); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); + border-color: #0044cc #0044cc #002a80; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-primary:hover, +.btn-primary:active, +.btn-primary.active, +.btn-primary.disabled, +.btn-primary[disabled] { + background-color: #0044cc; +} +.btn-primary:active, .btn-primary.active { + background-color: #003399 \9; +} +.btn-warning { + background-color: #faa732; + background-image: -moz-linear-gradient(top, #fbb450, #f89406); + background-image: -ms-linear-gradient(top, #fbb450, #f89406); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); + background-image: -webkit-linear-gradient(top, #fbb450, #f89406); + background-image: -o-linear-gradient(top, #fbb450, #f89406); + background-image: linear-gradient(top, #fbb450, #f89406); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0); + border-color: #f89406 #f89406 #ad6704; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-warning:hover, +.btn-warning:active, +.btn-warning.active, +.btn-warning.disabled, +.btn-warning[disabled] { + background-color: #f89406; +} +.btn-warning:active, .btn-warning.active { + background-color: #c67605 \9; +} +.btn-danger { + background-color: #da4f49; + background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -ms-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -o-linear-gradient(top, #ee5f5b, #bd362f); + background-image: linear-gradient(top, #ee5f5b, #bd362f); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0); + border-color: #bd362f #bd362f #802420; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-danger:hover, +.btn-danger:active, +.btn-danger.active, +.btn-danger.disabled, +.btn-danger[disabled] { + background-color: #bd362f; +} +.btn-danger:active, .btn-danger.active { + background-color: #942a25 \9; +} +.btn-success { + background-color: #5bb75b; + background-image: -moz-linear-gradient(top, #62c462, #51a351); + background-image: -ms-linear-gradient(top, #62c462, #51a351); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351)); + background-image: -webkit-linear-gradient(top, #62c462, #51a351); + background-image: -o-linear-gradient(top, #62c462, #51a351); + background-image: linear-gradient(top, #62c462, #51a351); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0); + border-color: #51a351 #51a351 #387038; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-success:hover, +.btn-success:active, +.btn-success.active, +.btn-success.disabled, +.btn-success[disabled] { + background-color: #51a351; +} +.btn-success:active, .btn-success.active { + background-color: #408140 \9; +} +.btn-info { + background-color: #49afcd; + background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -ms-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4)); + background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -o-linear-gradient(top, #5bc0de, #2f96b4); + background-image: linear-gradient(top, #5bc0de, #2f96b4); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0); + border-color: #2f96b4 #2f96b4 #1f6377; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-info:hover, +.btn-info:active, +.btn-info.active, +.btn-info.disabled, +.btn-info[disabled] { + background-color: #2f96b4; +} +.btn-info:active, .btn-info.active { + background-color: #24748c \9; +} +.btn-inverse { + background-color: #393939; + background-image: -moz-linear-gradient(top, #454545, #262626); + background-image: -ms-linear-gradient(top, #454545, #262626); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#454545), to(#262626)); + background-image: -webkit-linear-gradient(top, #454545, #262626); + background-image: -o-linear-gradient(top, #454545, #262626); + background-image: linear-gradient(top, #454545, #262626); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#454545', endColorstr='#262626', GradientType=0); + border-color: #262626 #262626 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-inverse:hover, +.btn-inverse:active, +.btn-inverse.active, +.btn-inverse.disabled, +.btn-inverse[disabled] { + background-color: #262626; +} +.btn-inverse:active, .btn-inverse.active { + background-color: #0c0c0c \9; +} +button.btn, input[type="submit"].btn { + *padding-top: 2px; + *padding-bottom: 2px; +} +button.btn::-moz-focus-inner, input[type="submit"].btn::-moz-focus-inner { + padding: 0; + border: 0; +} +button.btn.large, input[type="submit"].btn.large { + *padding-top: 7px; + *padding-bottom: 7px; +} +button.btn.small, input[type="submit"].btn.small { + *padding-top: 3px; + *padding-bottom: 3px; +} +.btn-group { + position: relative; + *zoom: 1; + *margin-left: .3em; +} +.btn-group:before, .btn-group:after { + display: table; + content: ""; +} +.btn-group:after { + clear: both; +} +.btn-group:first-child { + *margin-left: 0; +} +.btn-group + .btn-group { + margin-left: 5px; +} +.btn-toolbar { + margin-top: 9px; + margin-bottom: 9px; +} +.btn-toolbar .btn-group { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; +} +.btn-group .btn { + position: relative; + float: left; + margin-left: -1px; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.btn-group .btn:first-child { + margin-left: 0; + -webkit-border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; + border-top-left-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + border-bottom-left-radius: 4px; +} +.btn-group .btn:last-child, .btn-group .dropdown-toggle { + -webkit-border-top-right-radius: 4px; + -moz-border-radius-topright: 4px; + border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -moz-border-radius-bottomright: 4px; + border-bottom-right-radius: 4px; +} +.btn-group .btn.large:first-child { + margin-left: 0; + -webkit-border-top-left-radius: 6px; + -moz-border-radius-topleft: 6px; + border-top-left-radius: 6px; + -webkit-border-bottom-left-radius: 6px; + -moz-border-radius-bottomleft: 6px; + border-bottom-left-radius: 6px; +} +.btn-group .btn.large:last-child, .btn-group .large.dropdown-toggle { + -webkit-border-top-right-radius: 6px; + -moz-border-radius-topright: 6px; + border-top-right-radius: 6px; + -webkit-border-bottom-right-radius: 6px; + -moz-border-radius-bottomright: 6px; + border-bottom-right-radius: 6px; +} +.btn-group .btn:hover, +.btn-group .btn:focus, +.btn-group .btn:active, +.btn-group .btn.active { + z-index: 2; +} +.btn-group .dropdown-toggle:active, .btn-group.open .dropdown-toggle { + outline: 0; +} +.btn-group .dropdown-toggle { + padding-left: 8px; + padding-right: 8px; + -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + *padding-top: 5px; + *padding-bottom: 5px; +} +.btn-group.open { + *z-index: 1000; +} +.btn-group.open .dropdown-menu { + display: block; + margin-top: 1px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.btn-group.open .dropdown-toggle { + background-image: none; + -webkit-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); +} +.btn .caret { + margin-top: 7px; + margin-left: 0; +} +.btn:hover .caret, .open.btn-group .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.btn-primary .caret, +.btn-danger .caret, +.btn-info .caret, +.btn-success .caret, +.btn-inverse .caret { + border-top-color: #ffffff; + opacity: 0.75; + filter: alpha(opacity=75); +} +.btn-small .caret { + margin-top: 4px; +} +.alert { + padding: 8px 35px 8px 14px; + margin-bottom: 18px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + background-color: #fcf8e3; + border: 1px solid #fbeed5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.alert, .alert-heading { + color: #c09853; +} +.alert .close { + position: relative; + top: -2px; + right: -21px; + line-height: 18px; +} +.alert-success { + background-color: #dff0d8; + border-color: #d6e9c6; +} +.alert-success, .alert-success .alert-heading { + color: #468847; +} +.alert-danger, .alert-error { + background-color: #f2dede; + border-color: #eed3d7; +} +.alert-danger, +.alert-error, +.alert-danger .alert-heading, +.alert-error .alert-heading { + color: #b94a48; +} +.alert-info { + background-color: #d9edf7; + border-color: #bce8f1; +} +.alert-info, .alert-info .alert-heading { + color: #3a87ad; +} +.alert-block { + padding-top: 14px; + padding-bottom: 14px; +} +.alert-block > p, .alert-block > ul { + margin-bottom: 0; +} +.alert-block p + p { + margin-top: 5px; +} +.nav { + margin-left: 0; + margin-bottom: 18px; + list-style: none; +} +.nav > li > a { + display: block; +} +.nav > li > a:hover { + text-decoration: none; + background-color: #eeeeee; +} +.nav .nav-header { + display: block; + padding: 3px 15px; + font-size: 11px; + font-weight: bold; + line-height: 18px; + color: #999999; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + text-transform: uppercase; +} +.nav li + .nav-header { + margin-top: 9px; +} +.nav-list { + padding-left: 14px; + padding-right: 14px; + margin-bottom: 0; +} +.nav-list > li > a, .nav-list .nav-header { + margin-left: -15px; + margin-right: -15px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); +} +.nav-list > li > a { + padding: 3px 15px; +} +.nav-list .active > a, .nav-list .active > a:hover { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); + background-color: #0088cc; +} +.nav-list [class^="icon-"] { + margin-right: 2px; +} +.nav-tabs, .nav-pills { + *zoom: 1; +} +.nav-tabs:before, +.nav-pills:before, +.nav-tabs:after, +.nav-pills:after { + display: table; + content: ""; +} +.nav-tabs:after, .nav-pills:after { + clear: both; +} +.nav-tabs > li, .nav-pills > li { + float: left; +} +.nav-tabs > li > a, .nav-pills > li > a { + padding-right: 12px; + padding-left: 12px; + margin-right: 2px; + line-height: 14px; +} +.nav-tabs { + border-bottom: 1px solid #ddd; +} +.nav-tabs > li { + margin-bottom: -1px; +} +.nav-tabs > li > a { + padding-top: 9px; + padding-bottom: 9px; + border: 1px solid transparent; + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} +.nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #dddddd; +} +.nav-tabs > .active > a, .nav-tabs > .active > a:hover { + color: #555555; + background-color: #ffffff; + border: 1px solid #ddd; + border-bottom-color: transparent; + cursor: default; +} +.nav-pills > li > a { + padding-top: 8px; + padding-bottom: 8px; + margin-top: 2px; + margin-bottom: 2px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.nav-pills .active > a, .nav-pills .active > a:hover { + color: #ffffff; + background-color: #0088cc; +} +.nav-stacked > li { + float: none; +} +.nav-stacked > li > a { + margin-right: 0; +} +.nav-tabs.nav-stacked { + border-bottom: 0; +} +.nav-tabs.nav-stacked > li > a { + border: 1px solid #ddd; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.nav-tabs.nav-stacked > li:first-child > a { + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} +.nav-tabs.nav-stacked > li:last-child > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} +.nav-tabs.nav-stacked > li > a:hover { + border-color: #ddd; + z-index: 2; +} +.nav-pills.nav-stacked > li > a { + margin-bottom: 3px; +} +.nav-pills.nav-stacked > li:last-child > a { + margin-bottom: 1px; +} +.nav-tabs .dropdown-menu, .nav-pills .dropdown-menu { + margin-top: 1px; + border-width: 1px; +} +.nav-pills .dropdown-menu { + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.nav-tabs .dropdown-toggle .caret, .nav-pills .dropdown-toggle .caret { + border-top-color: #0088cc; + margin-top: 6px; +} +.nav-tabs .dropdown-toggle:hover .caret, .nav-pills .dropdown-toggle:hover .caret { + border-top-color: #005580; +} +.nav-tabs .active .dropdown-toggle .caret, .nav-pills .active .dropdown-toggle .caret { + border-top-color: #333333; +} +.nav > .dropdown.active > a:hover { + color: #000000; + cursor: pointer; +} +.nav-tabs .open .dropdown-toggle, .nav-pills .open .dropdown-toggle, .nav > .open.active > a:hover { + color: #ffffff; + background-color: #999999; + border-color: #999999; +} +.nav .open .caret, .nav .open.active .caret, .nav .open a:hover .caret { + border-top-color: #ffffff; + opacity: 1; + filter: alpha(opacity=100); +} +.tabs-stacked .open > a:hover { + border-color: #999999; +} +.tabbable { + *zoom: 1; +} +.tabbable:before, .tabbable:after { + display: table; + content: ""; +} +.tabbable:after { + clear: both; +} +.tab-content { + overflow: hidden; +} +.tabs-below .nav-tabs, .tabs-right .nav-tabs, .tabs-left .nav-tabs { + border-bottom: 0; +} +.tab-content > .tab-pane, .pill-content > .pill-pane { + display: none; +} +.tab-content > .active, .pill-content > .active { + display: block; +} +.tabs-below .nav-tabs { + border-top: 1px solid #ddd; +} +.tabs-below .nav-tabs > li { + margin-top: -1px; + margin-bottom: 0; +} +.tabs-below .nav-tabs > li > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} +.tabs-below .nav-tabs > li > a:hover { + border-bottom-color: transparent; + border-top-color: #ddd; +} +.tabs-below .nav-tabs .active > a, .tabs-below .nav-tabs .active > a:hover { + border-color: transparent #ddd #ddd #ddd; +} +.tabs-left .nav-tabs > li, .tabs-right .nav-tabs > li { + float: none; +} +.tabs-left .nav-tabs > li > a, .tabs-right .nav-tabs > li > a { + min-width: 74px; + margin-right: 0; + margin-bottom: 3px; +} +.tabs-left .nav-tabs { + float: left; + margin-right: 19px; + border-right: 1px solid #ddd; +} +.tabs-left .nav-tabs > li > a { + margin-right: -1px; + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} +.tabs-left .nav-tabs > li > a:hover { + border-color: #eeeeee #dddddd #eeeeee #eeeeee; +} +.tabs-left .nav-tabs .active > a, .tabs-left .nav-tabs .active > a:hover { + border-color: #ddd transparent #ddd #ddd; + *border-right-color: #ffffff; +} +.tabs-right .nav-tabs { + float: right; + margin-left: 19px; + border-left: 1px solid #ddd; +} +.tabs-right .nav-tabs > li > a { + margin-left: -1px; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} +.tabs-right .nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #eeeeee #dddddd; +} +.tabs-right .nav-tabs .active > a, .tabs-right .nav-tabs .active > a:hover { + border-color: #ddd #ddd #ddd transparent; + *border-left-color: #ffffff; +} +.navbar { + overflow: visible; + margin-bottom: 18px; +} +.navbar-inner { + padding-left: 20px; + padding-right: 20px; + background-color: #2c2c2c; + background-image: -moz-linear-gradient(top, #333333, #222222); + background-image: -ms-linear-gradient(top, #333333, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); + background-image: -webkit-linear-gradient(top, #333333, #222222); + background-image: -o-linear-gradient(top, #333333, #222222); + background-image: linear-gradient(top, #333333, #222222); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); +} +.btn-navbar { + display: none; + float: right; + padding: 7px 10px; + margin-left: 5px; + margin-right: 5px; + background-color: #2c2c2c; + background-image: -moz-linear-gradient(top, #333333, #222222); + background-image: -ms-linear-gradient(top, #333333, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); + background-image: -webkit-linear-gradient(top, #333333, #222222); + background-image: -o-linear-gradient(top, #333333, #222222); + background-image: linear-gradient(top, #333333, #222222); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); + border-color: #222222 #222222 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); +} +.btn-navbar:hover, +.btn-navbar:active, +.btn-navbar.active, +.btn-navbar.disabled, +.btn-navbar[disabled] { + background-color: #222222; +} +.btn-navbar:active, .btn-navbar.active { + background-color: #080808 \9; +} +.btn-navbar .icon-bar { + display: block; + width: 18px; + height: 2px; + background-color: #f5f5f5; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; + -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); +} +.btn-navbar .icon-bar + .icon-bar { + margin-top: 3px; +} +.nav-collapse.collapse { + height: auto; +} +.navbar .brand:hover { + text-decoration: none; +} +.navbar .brand { + float: left; + display: block; + padding: 8px 20px 12px; + margin-left: -20px; + font-size: 20px; + font-weight: 200; + line-height: 1; + color: #ffffff; +} +.navbar .navbar-text { + margin-bottom: 0; + line-height: 40px; + color: #999999; +} +.navbar .navbar-text a:hover { + color: #ffffff; + background-color: transparent; +} +.navbar .btn, .navbar .btn-group { + margin-top: 5px; +} +.navbar .btn-group .btn { + margin-top: 0; +} +.navbar-form { + margin-bottom: 0; + *zoom: 1; +} +.navbar-form:before, .navbar-form:after { + display: table; + content: ""; +} +.navbar-form:after { + clear: both; +} +.navbar-form input, .navbar-form select { + display: inline-block; + margin-top: 5px; + margin-bottom: 0; +} +.navbar-form .radio, .navbar-form .checkbox { + margin-top: 5px; +} +.navbar-form input[type="image"], .navbar-form input[type="checkbox"], .navbar-form input[type="radio"] { + margin-top: 3px; +} +.navbar-form .input-append, .navbar-form .input-prepend { + margin-top: 6px; + white-space: nowrap; +} +.navbar-form .input-append input, .navbar-form .input-prepend input { + margin-top: 0; +} +.navbar-search { + position: relative; + float: left; + margin-top: 6px; + margin-bottom: 0; +} +.navbar-search .search-query { + padding: 4px 9px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + font-weight: normal; + line-height: 1; + color: #ffffff; + color: rgba(255, 255, 255, 0.75); + background: #666; + background: rgba(255, 255, 255, 0.3); + border: 1px solid #111; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + -webkit-transition: none; + -moz-transition: none; + -ms-transition: none; + -o-transition: none; + transition: none; +} +.navbar-search .search-query :-moz-placeholder { + color: #eeeeee; +} +.navbar-search .search-query::-webkit-input-placeholder { + color: #eeeeee; +} +.navbar-search .search-query:hover { + color: #ffffff; + background-color: #999999; + background-color: rgba(255, 255, 255, 0.5); +} +.navbar-search .search-query:focus, .navbar-search .search-query.focused { + padding: 5px 10px; + color: #333333; + text-shadow: 0 1px 0 #ffffff; + background-color: #ffffff; + border: 0; + -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + outline: 0; +} +.navbar-fixed-top { + position: fixed; + top: 0; + right: 0; + left: 0; + z-index: 1030; +} +.navbar-fixed-top .navbar-inner { + padding-left: 0; + padding-right: 0; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.navbar .nav { + position: relative; + left: 0; + display: block; + float: left; + margin: 0 10px 0 0; +} +.navbar .nav.pull-right { + float: right; +} +.navbar .nav > li { + display: block; + float: left; +} +.navbar .nav > li > a { + float: none; + padding: 10px 10px 11px; + line-height: 19px; + color: #999999; + text-decoration: none; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.navbar .nav > li > a:hover { + background-color: transparent; + color: #ffffff; + text-decoration: none; +} +.navbar .nav .active > a, .navbar .nav .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #222222; +} +.navbar .divider-vertical { + height: 40px; + width: 1px; + margin: 0 9px; + overflow: hidden; + background-color: #222222; + border-right: 1px solid #333333; +} +.navbar .nav.pull-right { + margin-left: 10px; + margin-right: 0; +} +.navbar .dropdown-menu { + margin-top: 1px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.navbar .dropdown-menu:before { + content: ''; + display: inline-block; + border-left: 7px solid transparent; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-bottom-color: rgba(0, 0, 0, 0.2); + position: absolute; + top: -7px; + left: 9px; +} +.navbar .dropdown-menu:after { + content: ''; + display: inline-block; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid #ffffff; + position: absolute; + top: -6px; + left: 10px; +} +.navbar .nav .dropdown-toggle .caret, .navbar .nav .open.dropdown .caret { + border-top-color: #ffffff; +} +.navbar .nav .active .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.navbar .nav .open > .dropdown-toggle, .navbar .nav .active > .dropdown-toggle, .navbar .nav .open.active > .dropdown-toggle { + background-color: transparent; +} +.navbar .nav .active > .dropdown-toggle:hover { + color: #ffffff; +} +.navbar .nav.pull-right .dropdown-menu { + left: auto; + right: 0; +} +.navbar .nav.pull-right .dropdown-menu:before { + left: auto; + right: 12px; +} +.navbar .nav.pull-right .dropdown-menu:after { + left: auto; + right: 13px; +} +.breadcrumb { + padding: 7px 14px; + margin: 0 0 18px; + background-color: #fbfbfb; + background-image: -moz-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -ms-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5)); + background-image: -webkit-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -o-linear-gradient(top, #ffffff, #f5f5f5); + background-image: linear-gradient(top, #ffffff, #f5f5f5); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0); + border: 1px solid #ddd; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; +} +.breadcrumb li { + display: inline-block; + text-shadow: 0 1px 0 #ffffff; +} +.breadcrumb .divider { + padding: 0 5px; + color: #999999; +} +.breadcrumb .active a { + color: #333333; +} +.pagination { + height: 36px; + margin: 18px 0; +} +.pagination ul { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; + margin-left: 0; + margin-bottom: 0; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); +} +.pagination li { + display: inline; +} +.pagination a { + float: left; + padding: 0 14px; + line-height: 34px; + text-decoration: none; + border: 1px solid #ddd; + border-left-width: 0; +} +.pagination a:hover, .pagination .active a { + background-color: #f5f5f5; +} +.pagination .active a { + color: #999999; + cursor: default; +} +.pagination .disabled a, .pagination .disabled a:hover { + color: #999999; + background-color: transparent; + cursor: default; +} +.pagination li:first-child a { + border-left-width: 1px; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.pagination li:last-child a { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.pagination-centered { + text-align: center; +} +.pagination-right { + text-align: right; +} +.pager { + margin-left: 0; + margin-bottom: 18px; + list-style: none; + text-align: center; + *zoom: 1; +} +.pager:before, .pager:after { + display: table; + content: ""; +} +.pager:after { + clear: both; +} +.pager li { + display: inline; +} +.pager a { + display: inline-block; + padding: 5px 14px; + background-color: #fff; + border: 1px solid #ddd; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} +.pager a:hover { + text-decoration: none; + background-color: #f5f5f5; +} +.pager .next a { + float: right; +} +.pager .previous a { + float: left; +} +.modal-open .dropdown-menu { + z-index: 2050; +} +.modal-open .dropdown.open { + *z-index: 2050; +} +.modal-open .popover { + z-index: 2060; +} +.modal-open .tooltip { + z-index: 2070; +} +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + background-color: #000000; +} +.modal-backdrop.fade { + opacity: 0; +} +.modal-backdrop, .modal-backdrop.fade.in { + opacity: 0.8; + filter: alpha(opacity=80); +} +.modal { + position: fixed; + top: 50%; + left: 50%; + z-index: 1050; + max-height: 500px; + overflow: auto; + width: 560px; + margin: -250px 0 0 -280px; + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + /* IE6-7 */ + + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.wide-modal { + position: fixed; + top: 5%; + left: 5%; + z-index: 1050; + max-height: 90%; + overflow: auto; + width: 90%; + /*margin: -50px 0 0 -80px;*/ + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + /* IE6-7 */ + + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.modal.fade { + -webkit-transition: opacity .3s linear, top .3s ease-out; + -moz-transition: opacity .3s linear, top .3s ease-out; + -ms-transition: opacity .3s linear, top .3s ease-out; + -o-transition: opacity .3s linear, top .3s ease-out; + transition: opacity .3s linear, top .3s ease-out; + top: -25%; +} +.modal.fade.in { + top: 50%; +} +.modal-header { + padding: 9px 15px; + border-bottom: 1px solid #eee; +} +.modal-header .close { + margin-top: 2px; +} +.modal-body { + padding: 15px; +} +.modal-body .modal-form { + margin-bottom: 0; +} +.modal-footer { + padding: 14px 15px 15px; + margin-bottom: 0; + background-color: #f5f5f5; + border-top: 1px solid #ddd; + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; + *zoom: 1; +} +.modal-footer:before, .modal-footer:after { + display: table; + content: ""; +} +.modal-footer:after { + clear: both; +} +.modal-footer .btn { + float: right; + margin-left: 5px; + margin-bottom: 0; +} +.tooltip { + position: absolute; + z-index: 1020; + display: block; + visibility: visible; + padding: 5px; + font-size: 11px; + opacity: 0; + filter: alpha(opacity=0); +} +.tooltip.in { + opacity: 0.8; + filter: alpha(opacity=80); +} +.tooltip.top { + margin-top: -2px; +} +.tooltip.right { + margin-left: 2px; +} +.tooltip.bottom { + margin-top: 2px; +} +.tooltip.left { + margin-left: -2px; +} +.tooltip.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid #000000; +} +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #000000; +} +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-bottom: 5px solid #000000; +} +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-right: 5px solid #000000; +} +.tooltip-inner { + max-width: 200px; + padding: 3px 8px; + color: #ffffff; + text-align: center; + text-decoration: none; + background-color: #000000; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; +} +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1010; + display: none; + padding: 5px; +} +.popover.top { + margin-top: -5px; +} +.popover.right { + margin-left: 5px; +} +.popover.bottom { + margin-top: 5px; +} +.popover.left { + margin-left: -5px; +} +.popover.top .arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid #000000; +} +.popover.right .arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-right: 5px solid #000000; +} +.popover.bottom .arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-bottom: 5px solid #000000; +} +.popover.left .arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #000000; +} +.popover .arrow { + position: absolute; + width: 0; + height: 0; +} +.popover-inner { + padding: 3px; + width: 280px; + overflow: hidden; + background: #000000; + background: rgba(0, 0, 0, 0.8); + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); +} +.popover-title { + padding: 9px 15px; + line-height: 1; + background-color: #f5f5f5; + border-bottom: 1px solid #eee; + -webkit-border-radius: 3px 3px 0 0; + -moz-border-radius: 3px 3px 0 0; + border-radius: 3px 3px 0 0; +} +.popover-content { + padding: 14px; + background-color: #ffffff; + -webkit-border-radius: 0 0 3px 3px; + -moz-border-radius: 0 0 3px 3px; + border-radius: 0 0 3px 3px; + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.popover-content p, .popover-content ul, .popover-content ol { + margin-bottom: 0; +} +.thumbnails { + margin-left: -20px; + list-style: none; + *zoom: 1; +} +.thumbnails:before, .thumbnails:after { + display: table; + content: ""; +} +.thumbnails:after { + clear: both; +} +.thumbnails > li { + float: left; + margin: 0 0 18px 20px; +} +.thumbnail { + display: block; + padding: 4px; + line-height: 1; + border: 1px solid #ddd; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); +} +a.thumbnail:hover { + border-color: #0088cc; + -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); +} +.thumbnail > img { + display: block; + max-width: 100%; + margin-left: auto; + margin-right: auto; +} +.thumbnail .caption { + padding: 9px; +} +.label { + padding: 2px 4px 3px; + font-size: 11.049999999999999px; + font-weight: bold; + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #999999; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.label:hover { + color: #ffffff; + text-decoration: none; +} +.label-important { + background-color: #b94a48; +} +.label-important:hover { + background-color: #953b39; +} +.label-warning { + background-color: #f89406; +} +.label-warning:hover { + background-color: #c67605; +} +.label-success { + background-color: #468847; +} +.label-success:hover { + background-color: #356635; +} +.label-info { + background-color: #3a87ad; +} +.label-info:hover { + background-color: #2d6987; +} +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +@-moz-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +@keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +.progress { + overflow: hidden; + height: 18px; + margin-bottom: 18px; + background-color: #f7f7f7; + background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -ms-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9)); + background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: linear-gradient(top, #f5f5f5, #f9f9f9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0); + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.progress .bar { + width: 0%; + height: 18px; + color: #ffffff; + font-size: 12px; + text-align: center; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #0e90d2; + background-image: -moz-linear-gradient(top, #149bdf, #0480be); + background-image: -ms-linear-gradient(top, #149bdf, #0480be); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be)); + background-image: -webkit-linear-gradient(top, #149bdf, #0480be); + background-image: -o-linear-gradient(top, #149bdf, #0480be); + background-image: linear-gradient(top, #149bdf, #0480be); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0); + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition: width 0.6s ease; + -moz-transition: width 0.6s ease; + -ms-transition: width 0.6s ease; + -o-transition: width 0.6s ease; + transition: width 0.6s ease; +} +.progress-striped .bar { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + -webkit-background-size: 40px 40px; + -moz-background-size: 40px 40px; + -o-background-size: 40px 40px; + background-size: 40px 40px; +} +.progress.active .bar { + -webkit-animation: progress-bar-stripes 2s linear infinite; + -moz-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} +.progress-danger .bar { + background-color: #dd514c; + background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -o-linear-gradient(top, #ee5f5b, #c43c35); + background-image: linear-gradient(top, #ee5f5b, #c43c35); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0); +} +.progress-danger.progress-striped .bar { + background-color: #ee5f5b; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-success .bar { + background-color: #5eb95e; + background-image: -moz-linear-gradient(top, #62c462, #57a957); + background-image: -ms-linear-gradient(top, #62c462, #57a957); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957)); + background-image: -webkit-linear-gradient(top, #62c462, #57a957); + background-image: -o-linear-gradient(top, #62c462, #57a957); + background-image: linear-gradient(top, #62c462, #57a957); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0); +} +.progress-success.progress-striped .bar { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-info .bar { + background-color: #4bb1cf; + background-image: -moz-linear-gradient(top, #5bc0de, #339bb9); + background-image: -ms-linear-gradient(top, #5bc0de, #339bb9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9)); + background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9); + background-image: -o-linear-gradient(top, #5bc0de, #339bb9); + background-image: linear-gradient(top, #5bc0de, #339bb9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0); +} +.progress-info.progress-striped .bar { + background-color: #5bc0de; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.accordion { + margin-bottom: 18px; +} +.accordion-group { + margin-bottom: 2px; + border: 1px solid #e5e5e5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.accordion-heading { + border-bottom: 0; +} +.accordion-heading .accordion-toggle { + display: block; + padding: 8px 15px; +} +.accordion-inner { + padding: 9px 15px; + border-top: 1px solid #e5e5e5; +} +.carousel { + position: relative; + margin-bottom: 18px; + line-height: 1; +} +.carousel-inner { + overflow: hidden; + width: 100%; + position: relative; +} +.carousel .item { + display: none; + position: relative; + -webkit-transition: 0.6s ease-in-out left; + -moz-transition: 0.6s ease-in-out left; + -ms-transition: 0.6s ease-in-out left; + -o-transition: 0.6s ease-in-out left; + transition: 0.6s ease-in-out left; +} +.carousel .item > img { + display: block; + line-height: 1; +} +.carousel .active, .carousel .next, .carousel .prev { + display: block; +} +.carousel .active { + left: 0; +} +.carousel .next, .carousel .prev { + position: absolute; + top: 0; + width: 100%; +} +.carousel .next { + left: 100%; +} +.carousel .prev { + left: -100%; +} +.carousel .next.left, .carousel .prev.right { + left: 0; +} +.carousel .active.left { + left: -100%; +} +.carousel .active.right { + left: 100%; +} +.carousel-control { + position: absolute; + top: 40%; + left: 15px; + width: 40px; + height: 40px; + margin-top: -20px; + font-size: 60px; + font-weight: 100; + line-height: 30px; + color: #ffffff; + text-align: center; + background: #222222; + border: 3px solid #ffffff; + -webkit-border-radius: 23px; + -moz-border-radius: 23px; + border-radius: 23px; + opacity: 0.5; + filter: alpha(opacity=50); +} +.carousel-control.right { + left: auto; + right: 15px; +} +.carousel-control:hover { + color: #ffffff; + text-decoration: none; + opacity: 0.9; + filter: alpha(opacity=90); +} +.carousel-caption { + position: absolute; + left: 0; + right: 0; + bottom: 0; + padding: 10px 15px 5px; + background: #333333; + background: rgba(0, 0, 0, 0.75); +} +.carousel-caption h4, .carousel-caption p { + color: #ffffff; +} +.hero-unit { + padding: 60px; + margin-bottom: 30px; + background-color: #f5f5f5; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} +.hero-unit h1 { + margin-bottom: 0; + font-size: 60px; + line-height: 1; + letter-spacing: -1px; +} +.hero-unit p { + font-size: 18px; + font-weight: 200; + line-height: 27px; +} +.pull-right { + float: right; +} +.pull-left { + float: left; +} +.hide { + display: none; +} +.show { + display: block; +} +.invisible { + visibility: hidden; +} diff --git a/src/nl/astraeus/jdbc/web/resources/images/loading.gif b/src/nl/astraeus/jdbc/web/resources/images/loading.gif new file mode 100644 index 0000000..21c7e74 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/images/loading.gif Binary files differ diff --git a/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png b/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png new file mode 100644 index 0000000..92d4445 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png Binary files differ diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-alert.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-alert.js new file mode 100644 index 0000000..2242ddd --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-alert.js @@ -0,0 +1,94 @@ +/* ========================================================== + * bootstrap-alert.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#alerts + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function( $ ){ + + "use strict" + + /* ALERT CLASS DEFINITION + * ====================== */ + + var dismiss = '[data-dismiss="alert"]' + , Alert = function ( el ) { + $(el).on('click', dismiss, this.close) + } + + Alert.prototype = { + + constructor: Alert + + , close: function ( e ) { + var $this = $(this) + , selector = $this.attr('data-target') + , $parent + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = $(selector) + $parent.trigger('close') + + e && e.preventDefault() + + $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent()) + + $parent + .trigger('close') + .removeClass('in') + + function removeElement() { + $parent + .trigger('closed') + .remove() + } + + $.support.transition && $parent.hasClass('fade') ? + $parent.on($.support.transition.end, removeElement) : + removeElement() + } + + } + + + /* ALERT PLUGIN DEFINITION + * ======================= */ + + $.fn.alert = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('alert') + if (!data) $this.data('alert', (data = new Alert(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.alert.Constructor = Alert + + + /* ALERT DATA-API + * ============== */ + + $(function () { + $('body').on('click.alert.data-api', dismiss, Alert.prototype.close) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f403193 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..73ff239 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..3b00020 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..275077f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/README b/README deleted file mode 100644 index 734abaf..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -This file was created by IntelliJ IDEA 11.1.1 for binding GitHub repository \ No newline at end of file diff --git a/Simple-jdbc-statistics.iml b/Simple-jdbc-statistics.iml new file mode 100644 index 0000000..ca90a9b --- /dev/null +++ b/Simple-jdbc-statistics.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/lib/h2-1.3.166.jar b/lib/h2-1.3.166.jar new file mode 100644 index 0000000..4985063 --- /dev/null +++ b/lib/h2-1.3.166.jar Binary files differ diff --git a/lib/servlet-api-2.5.jar b/lib/servlet-api-2.5.jar new file mode 100644 index 0000000..20b5755 --- /dev/null +++ b/lib/servlet-api-2.5.jar Binary files differ diff --git a/lib/slf4j-api-1.6.4.jar b/lib/slf4j-api-1.6.4.jar new file mode 100644 index 0000000..4d23f41 --- /dev/null +++ b/lib/slf4j-api-1.6.4.jar Binary files differ diff --git a/lib/slf4j-simple-1.6.4.jar b/lib/slf4j-simple-1.6.4.jar new file mode 100644 index 0000000..3d1b8d9 --- /dev/null +++ b/lib/slf4j-simple-1.6.4.jar Binary files differ diff --git a/lib/ssr-0.1.jar b/lib/ssr-0.1.jar new file mode 100644 index 0000000..65dfcf4 --- /dev/null +++ b/lib/ssr-0.1.jar Binary files differ diff --git a/lib/vst-0.4.jar b/lib/vst-0.4.jar new file mode 100644 index 0000000..db63792 --- /dev/null +++ b/lib/vst-0.4.jar Binary files differ diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..ac2dbe1 --- /dev/null +++ b/readme.md @@ -0,0 +1 @@ +A simple wrapper around jdbc drivers what will show current jdbc stats of the running queries on a simple web page on port 18080. \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/ConnectionLogger.java b/src/nl/astraeus/jdbc/ConnectionLogger.java new file mode 100644 index 0000000..c3e243f --- /dev/null +++ b/src/nl/astraeus/jdbc/ConnectionLogger.java @@ -0,0 +1,279 @@ +package nl.astraeus.jdbc; + +import java.sql.*; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Executor; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:12:34 PM + */ +public class ConnectionLogger implements Connection { + private Connection connection; + + private long milli; + private long nano; + private String lastSql; + + public ConnectionLogger(Connection connection) { + this.connection = connection; + this.lastSql = ""; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(QueryType.UNKNOWN, sql, m, n); + } + + public void commit() throws SQLException { + clearTime(); + + connection.commit(); + + log("commit"); + } + + public void rollback() throws SQLException { + clearTime(); + + connection.rollback(); + + log("rollback"); + } + + public void close() throws SQLException { + clearTime(); + + connection.close(); + + log("close"); + } + + public PreparedStatement prepareStatement(String sql) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, autoGeneratedKeys); + } + + public PreparedStatement prepareStatement(String sql, int columnIndexes[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnIndexes); + } + + public PreparedStatement prepareStatement(String sql, String columnNames[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnNames); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public Statement createStatement() throws SQLException { + return connection.createStatement(); + } + + public CallableStatement prepareCall(String sql) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql); + } + + public String nativeSQL(String sql) throws SQLException { + lastSql = sql; + return connection.nativeSQL(sql); + } + + public void setAutoCommit(boolean autoCommit) throws SQLException { + connection.setAutoCommit(autoCommit); + } + + public boolean getAutoCommit() throws SQLException { + return connection.getAutoCommit(); + } + + public boolean isClosed() throws SQLException { + return connection.isClosed(); + } + + public DatabaseMetaData getMetaData() throws SQLException { + return connection.getMetaData(); + } + + public void setReadOnly(boolean readOnly) throws SQLException { + connection.setReadOnly(readOnly); + } + + public boolean isReadOnly() throws SQLException { + return connection.isReadOnly(); + } + + public void setCatalog(String catalog) throws SQLException { + connection.setCatalog(catalog); + } + + public String getCatalog() throws SQLException { + return connection.getCatalog(); + } + + public void setTransactionIsolation(int level) throws SQLException { + connection.setTransactionIsolation(level); + } + + public int getTransactionIsolation() throws SQLException { + return connection.getTransactionIsolation(); + } + + public SQLWarning getWarnings() throws SQLException { + return connection.getWarnings(); + } + + public void clearWarnings() throws SQLException { + connection.clearWarnings(); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency); + } + + public Map> getTypeMap() throws SQLException { + return connection.getTypeMap(); + } + + public void setTypeMap(Map> map) throws SQLException { + connection.setTypeMap(map); + } + + public void setHoldability(int holdability) throws SQLException { + connection.setHoldability(holdability); + } + + public int getHoldability() throws SQLException { + return connection.getHoldability(); + } + + public Savepoint setSavepoint() throws SQLException { + return connection.setSavepoint(); + } + + public Savepoint setSavepoint(String name) throws SQLException { + return connection.setSavepoint(name); + } + + public void rollback(Savepoint savepoint) throws SQLException { + connection.rollback(); + } + + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + connection.releaseSavepoint(savepoint); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public Clob createClob() throws SQLException { + return connection.createClob(); + } + + public Blob createBlob() throws SQLException { + return connection.createBlob(); + } + + public NClob createNClob() throws SQLException { + return connection.createNClob(); + } + + public SQLXML createSQLXML() throws SQLException { + return connection.createSQLXML(); + } + + public boolean isValid(int timeout) throws SQLException { + return connection.isValid(timeout); + } + + public void setClientInfo(String name, String value) throws SQLClientInfoException { + connection.setClientInfo(name, value); + } + + public void setClientInfo(Properties properties) throws SQLClientInfoException { + connection.setClientInfo(properties); + } + + public String getClientInfo(String name) throws SQLException { + return connection.getClientInfo(name); + } + + public Properties getClientInfo() throws SQLException { + return connection.getClientInfo(); + } + + public Array createArrayOf(String typeName, Object[] elements) throws SQLException { + return connection.createArrayOf(typeName, elements); + } + + public Struct createStruct(String typeName, Object[] attributes) throws SQLException { + return connection.createStruct(typeName, attributes); + } + + @Override + public void setSchema(String schema) throws SQLException { + connection.setSchema(schema); + } + + @Override + public String getSchema() throws SQLException { + return connection.getSchema(); + } + + @Override + public void abort(Executor executor) throws SQLException { + connection.abort(executor); + } + + @Override + public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { + connection.setNetworkTimeout(executor, milliseconds); + } + + @Override + public int getNetworkTimeout() throws SQLException { + return connection.getNetworkTimeout(); + } + + public T unwrap(Class iface) throws SQLException { + return connection.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return connection.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/Driver.java b/src/nl/astraeus/jdbc/Driver.java new file mode 100644 index 0000000..8317172 --- /dev/null +++ b/src/nl/astraeus/jdbc/Driver.java @@ -0,0 +1,116 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.http.SimpleWebServer; +import nl.astraeus.jdbc.web.JdbcStatisticsServlet; +import nl.astraeus.jdbc.web.ResourceServlet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.*; +import java.util.Enumeration; +import java.util.Properties; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:54:37 PM + */ +public class Driver implements java.sql.Driver { + private final static Logger log = LoggerFactory.getLogger(Driver.class); + + final private static String URL_PREFIX = "jdbc:stat:"; + + private java.sql.Driver driver = null; + private String[] drivers = { + "org.postgresql.Driver", + "oracle.jdbc.driver.OracleDriver", + "com.sybase.jdbc2.jdbc.SybDriver", + "net.sourceforge.jtds.jdbc.Driver", + "com.microsoft.jdbc.sqlserver.SQLServerDriver", + "com.microsoft.sqlserver.jdbc.SQLServerDriver", + "weblogic.jdbc.sqlserver.SQLServerDriver", + "com.informix.jdbc.IfxDriver", + "org.apache.derby.jdbc.ClientDriver", + "org.apache.derby.jdbc.EmbeddedDriver", + "com.mysql.jdbc.Driver", + "org.hsqldb.jdbcDriver", + "org.h2.Driver" }; + + static { + log.debug("Loading driver class " + Driver.class.getName()); + + try { + DriverManager.registerDriver(new Driver()); + } catch (SQLException e) { + log.error("", e); + } + } + + public Driver() { + for (String dr : drivers) { + try { + Class.forName(dr); + } catch (Throwable e) { + log.debug("Can't instantiate driver: " + dr, e); + } + } + } + + private java.sql.Driver findDriver(String url) throws SQLException { + Enumeration e = DriverManager.getDrivers(); + + while (e.hasMoreElements()) { + java.sql.Driver d = (java.sql.Driver) e.nextElement(); + + if (d.acceptsURL(url)) { + return d; + } + } + + throw new SQLException("Driver not found: " + url); + } + + public Connection connect(String url, Properties info) throws SQLException { + url = url.substring(URL_PREFIX.length()); + + if (driver == null) { + driver = findDriver(url); + } + + if (driver != null) { + SimpleWebServer server = new SimpleWebServer(18080); + + server.addServlet(new JdbcStatisticsServlet(), "/"); + server.addServlet(new ResourceServlet(), "/resources/*"); + + server.start(); + } + + return new ConnectionLogger(driver.connect(url, info)); + } + + public boolean acceptsURL(String url) throws SQLException { + return (url != null && url.startsWith(URL_PREFIX)); + } + + public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { + return driver.getPropertyInfo(url, info); + } + + public int getMajorVersion() { + return driver.getMajorVersion(); + } + + public int getMinorVersion() { + return driver.getMinorVersion(); + } + + public boolean jdbcCompliant() { + return driver.jdbcCompliant(); + } + + @Override + public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException { + return driver.getParentLogger(); + } +} diff --git a/src/nl/astraeus/jdbc/JdbcLogger.java b/src/nl/astraeus/jdbc/JdbcLogger.java new file mode 100644 index 0000000..f4bc125 --- /dev/null +++ b/src/nl/astraeus/jdbc/JdbcLogger.java @@ -0,0 +1,113 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.jdbc.util.Util; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/** + * User: riennentjes + * Date: Jul 12, 2008 + * Time: 9:15:21 AM + */ +public class JdbcLogger { + private final static Logger logger = LoggerFactory.getLogger(JdbcLogger.class); + + private final static JdbcLogger instance = new JdbcLogger(); + + public static JdbcLogger get() { + return instance; + } + + public final static class LogEntry { + public QueryType type; + public String sql; + public long milli; + public long nano; + public int count; + public int hash; + + public LogEntry(int hash, QueryType type, String sql, long milli, long nano) { + this.hash = hash; + this.type = type; + this.sql = sql; + this.milli = milli; + this.nano = nano; + this.count = 1; + } + + public void addCount(long milli, long nano) { + synchronized (this) { + count++; + this.milli += milli; + this.nano += nano; + } + } + + public int getCount() { + return count; + } + + public String getMilli() { + return Util.formatNano(milli*1000000/count); + } + + public String getNano() { + return Util.formatNano(nano/count); + } + + public String getTotal() { + return Util.formatNano(nano); + } + + public String getSql() { + return sql; + } + } + + private Map queries; + + public JdbcLogger() { + queries = new ConcurrentHashMap(); + } + + public void logEntry(QueryType type, String sql, long milli, long nano) { + int hash = sql.hashCode(); + LogEntry entry = queries.get(hash); + + if (entry == null) { + entry = new LogEntry(hash, type, sql, milli, nano); + queries.put(hash, entry); + } else { + entry.addCount(milli, nano); + } + + if (queries.size() > 1000) { + List toRemove = new LinkedList(); + List values = new LinkedList(queries.values()); + + Collections.sort(values, new Comparator() { + @Override + public int compare(LogEntry o1, LogEntry o2) { + return o1.count - o2.count; + } + }); + + while (queries.size() > 900) { + queries.remove(values.remove(0).hash); + + } + } + } + + public static void log(QueryType type, String sql, long milli, long nano) { + instance.logEntry(type, sql, milli, nano); + } + + public Collection getEntries() { + return queries.values(); + } + +} diff --git a/src/nl/astraeus/jdbc/PreparedStatementLogger.java b/src/nl/astraeus/jdbc/PreparedStatementLogger.java new file mode 100644 index 0000000..98aefc7 --- /dev/null +++ b/src/nl/astraeus/jdbc/PreparedStatementLogger.java @@ -0,0 +1,577 @@ +package nl.astraeus.jdbc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.InputStream; +import java.io.Reader; +import java.math.BigDecimal; +import java.net.URL; +import java.sql.*; +import java.util.Calendar; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 7:47:57 PM + */ +public class PreparedStatementLogger implements PreparedStatement { + private final static Logger log = LoggerFactory.getLogger(PreparedStatementLogger.class); + + private PreparedStatement statement; + + private String sql; + private QueryType type; + private long milli; + private long nano; + + //private ArrayList parameters; + + public PreparedStatementLogger(PreparedStatement statement) { + this.statement = statement; + this.sql = ""; + this.type = QueryType.UNKNOWN; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(QueryType type, String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(type, sql, m, n); + } + + public PreparedStatementLogger(Connection connection, String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql); + } + + public PreparedStatementLogger(Connection connection, String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatementLogger(Connection connection, String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, autoGeneratedKeys); + } + + public PreparedStatementLogger(Connection connection, String sql, int[] columnIndexes) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnIndexes); + } + + public PreparedStatementLogger(Connection connection, String sql, String[] columnNames) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnNames); + } + + public boolean execute() throws SQLException { + clearTime(); + + boolean result = statement.execute(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery() throws SQLException { + clearTime(); + + ResultSet result = statement.executeQuery(); + + log(type, sql); + + return result; + } + + public int executeUpdate() throws SQLException { + clearTime(); + + int result = statement.executeUpdate(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + ResultSet result = statement.executeQuery(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnNames); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnNames); + + log(type, sql); + + return result; + } + + + public void setNull(int parameterIndex, int sqlType) throws SQLException { + statement.setNull(parameterIndex, sqlType); + } + + public void setBoolean(int parameterIndex, boolean x) throws SQLException { + statement.setBoolean(parameterIndex, x); + } + + public void setByte(int parameterIndex, byte x) throws SQLException { + statement.setByte(parameterIndex, x); + } + + public void setShort(int parameterIndex, short x) throws SQLException { + statement.setShort(parameterIndex, x); + } + + public void setInt(int parameterIndex, int x) throws SQLException { + statement.setInt(parameterIndex, x); + } + + public void setLong(int parameterIndex, long x) throws SQLException { + statement.setLong(parameterIndex, x); + } + + public void setFloat(int parameterIndex, float x) throws SQLException { + statement.setFloat(parameterIndex, x); + } + + public void setDouble(int parameterIndex, double x) throws SQLException { + statement.setDouble(parameterIndex, x); + } + + public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { + statement.setBigDecimal(parameterIndex, x); + } + + public void setString(int parameterIndex, String x) throws SQLException { + statement.setString(parameterIndex, x); + } + + public void setBytes(int parameterIndex, byte x[]) throws SQLException { + statement.setBytes(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x) throws SQLException { + statement.setDate(parameterIndex, x); + } + + public void setTime(int parameterIndex, Time x) throws SQLException { + statement.setTime(parameterIndex, x); + } + + public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { + statement.setTimestamp(parameterIndex, x); + } + + public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setUnicodeStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType); + } + + public void setObject(int parameterIndex, Object x) throws SQLException { + statement.setObject(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setRef(int parameterIndex, Ref x) throws SQLException { + statement.setRef(parameterIndex, x); + } + + public void setBlob(int parameterIndex, Blob x) throws SQLException { + statement.setBlob(parameterIndex, x); + } + + public void setClob(int parameterIndex, Clob x) throws SQLException { + statement.setClob(parameterIndex, x); + } + + public void setArray(int parameterIndex, Array x) throws SQLException { + statement.setArray(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { + statement.setDate(parameterIndex, x, cal); + } + + public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { + statement.setTime(parameterIndex, x, cal); + } + + public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { + statement.setTimestamp(parameterIndex, x, cal); + } + + public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException { + statement.setNull(parameterIndex, sqlType, typeName); + } + + public void setURL(int parameterIndex, URL x) throws SQLException { + statement.setURL(parameterIndex, x); + } + + public void setRowId(int parameterIndex, RowId x) throws SQLException { + statement.setRowId(parameterIndex, x); + } + + public void setNString(int parameterIndex, String value) throws SQLException { + statement.setNString(parameterIndex, value); + } + + public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException { + statement.setNCharacterStream(parameterIndex, value, length); + } + + public void setNClob(int parameterIndex, NClob value) throws SQLException { + statement.setNClob(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setClob(parameterIndex, reader, length); + } + + public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException { + statement.setBlob(parameterIndex, inputStream, length); + } + + public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setNClob(parameterIndex, reader, length); + } + + public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException { + statement.setSQLXML(parameterIndex, xmlObject); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType, scaleOrLength); + } + + public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException { + statement.setAsciiStream(parameterIndex, x); + } + + public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException { + statement.setBinaryStream(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException { + statement.setCharacterStream(parameterIndex, reader); + } + + public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException { + statement.setNCharacterStream(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader) throws SQLException { + statement.setClob(parameterIndex, reader); + } + + public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException { + statement.setBlob(parameterIndex, inputStream); + } + + public void setNClob(int parameterIndex, Reader reader) throws SQLException { + statement.setNClob(parameterIndex, reader); + } + + + public void close() throws SQLException { + sql = ""; + type = QueryType.UNKNOWN; + milli = 0; + nano = 0; + + statement.close(); + } + + public ResultSetMetaData getMetaData() throws SQLException { + return statement.getMetaData(); + } + + public void clearParameters() throws SQLException { + statement.clearParameters(); + } + + public ParameterMetaData getParameterMetaData() throws SQLException { + return statement.getParameterMetaData(); + } + + public void addBatch() throws SQLException { + statement.addBatch(); + } + + public int getMaxFieldSize() throws SQLException { + return statement.getMaxFieldSize(); + } + + public void setMaxFieldSize(int max) throws SQLException { + statement.setMaxFieldSize(max); + } + + public int getMaxRows() throws SQLException { + return statement.getMaxRows(); + } + + public void setMaxRows(int max) throws SQLException { + statement.setMaxRows(max); + } + + public void setEscapeProcessing(boolean enable) throws SQLException { + statement.setEscapeProcessing(enable); + } + + public int getQueryTimeout() throws SQLException { + return statement.getQueryTimeout(); + } + + public void setQueryTimeout(int seconds) throws SQLException { + statement.setQueryTimeout(seconds); + } + + public void cancel() throws SQLException { + statement.cancel(); + } + + public SQLWarning getWarnings() throws SQLException { + return statement.getWarnings(); + } + + public void clearWarnings() throws SQLException { + statement.clearWarnings(); + } + + public void setCursorName(String name) throws SQLException { + statement.setCursorName(name); + } + + public boolean execute(String sql) throws SQLException { + return statement.execute(sql); + } + + public ResultSet getResultSet() throws SQLException { + return statement.getResultSet(); + } + + public int getUpdateCount() throws SQLException { + return statement.getUpdateCount(); + } + + public boolean getMoreResults() throws SQLException { + return statement.getMoreResults(); + } + + public void setFetchDirection(int direction) throws SQLException { + statement.setFetchDirection(direction); + } + + public int getFetchDirection() throws SQLException { + return statement.getFetchDirection(); + } + + public void setFetchSize(int rows) throws SQLException { + statement.setFetchSize(rows); + } + + public int getFetchSize() throws SQLException { + return statement.getFetchSize(); + } + + public int getResultSetConcurrency() throws SQLException { + return statement.getResultSetConcurrency(); + } + + public int getResultSetType() throws SQLException { + return statement.getResultSetType(); + } + + public void addBatch(String sql) throws SQLException { + statement.addBatch(sql); + } + + public void clearBatch() throws SQLException { + statement.clearBatch(); + } + + public int[] executeBatch() throws SQLException { + return statement.executeBatch(); + } + + public Connection getConnection() throws SQLException { + return statement.getConnection(); + } + + public boolean getMoreResults(int current) throws SQLException { + return statement.getMoreResults(current); + } + + public ResultSet getGeneratedKeys() throws SQLException { + return statement.getGeneratedKeys(); + } + + public int getResultSetHoldability() throws SQLException { + return statement.getResultSetHoldability(); + } + + public boolean isClosed() throws SQLException { + return statement.isClosed(); + } + + public void setPoolable(boolean poolable) throws SQLException { + statement.setPoolable(poolable); + } + + public boolean isPoolable() throws SQLException { + return statement.isPoolable(); + } + + @Override + public void closeOnCompletion() throws SQLException { + statement.closeOnCompletion();; + } + + @Override + public boolean isCloseOnCompletion() throws SQLException { + return statement.isCloseOnCompletion(); + } + + public T unwrap(Class iface) throws SQLException { + return statement.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return statement.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/QueryType.java b/src/nl/astraeus/jdbc/QueryType.java new file mode 100644 index 0000000..744fbfc --- /dev/null +++ b/src/nl/astraeus/jdbc/QueryType.java @@ -0,0 +1,24 @@ +package nl.astraeus.jdbc; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:32:49 PM + */ +public enum QueryType { + PLAIN("plain"), + PREPARED("prepared"), + CALLABLE("callable"), + UNKNOWN("unknown"); + + private String description; + + QueryType(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } + +} diff --git a/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java new file mode 100644 index 0000000..07aac40 --- /dev/null +++ b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java @@ -0,0 +1,68 @@ +package nl.astraeus.jdbc.example; + +import java.sql.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 7:32 PM + */ +public class JdbcStatisticsExample { + + + public static void main(String [] args) throws Exception { + Class.forName("org.h2.Driver"); + Class.forName("nl.astraeus.jdbc.Driver"); + + new JdbcStatisticsExample(); + } + + public JdbcStatisticsExample() throws Exception { + Connection conn = DriverManager.getConnection("jdbc:stat:jdbc:h2:mem:test"); + + Statement statement = null; + + statement = conn.createStatement(); + statement.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + + boolean running = true; + int count = 1; + PreparedStatement ps = null; + + while (running) { + Thread.sleep(10); + + String TableName = "TEST"+(System.nanoTime() % 1000); + + try { + ps = conn.prepareStatement("SELECT COUNT(*) FROM "+TableName); + ResultSet rs = ps.executeQuery(); + } catch (SQLException e) { + statement = conn.createStatement(); + statement.execute("CREATE TABLE "+TableName+" (ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + } finally { + if (ps!=null) { + ps.close(); + } + } + + ps = conn.prepareStatement("INSERT INTO "+TableName+" VALUES (?, ?)"); + + ps.setInt(1, count++); + ps.setString(2, "String "+System.currentTimeMillis()); + + ps.execute(); + ps.close(); + + Thread.sleep(10); + + ps = conn.prepareStatement("SELECT * FROM "+TableName); + ResultSet rs = ps.executeQuery(); + statement.close(); + } + + conn.close(); + } +} diff --git a/src/nl/astraeus/jdbc/util/IOUtils.java b/src/nl/astraeus/jdbc/util/IOUtils.java new file mode 100644 index 0000000..ce95d9d --- /dev/null +++ b/src/nl/astraeus/jdbc/util/IOUtils.java @@ -0,0 +1,38 @@ +package nl.astraeus.jdbc.util; + +import java.io.*; + +/** + * User: rnentjes + * Date: 4/9/12 + * Time: 2:33 PM + */ +public class IOUtils { + + public static String toString(InputStream in) throws IOException { + assert in != null; + + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + StringBuilder buffer = new StringBuilder(); + + while(reader.ready()) { + buffer.append(reader.readLine()); + buffer.append("\n"); + } + + return buffer.toString(); + } finally { + in.close(); + } + } + + public static void copy(InputStream in, OutputStream out) throws IOException { + byte [] buffer = new byte[1<<16]; + int bytes; + + while((bytes = in.read(buffer)) > 0) { + out.write(buffer, 0, bytes); + } + } +} diff --git a/src/nl/astraeus/jdbc/util/Util.java b/src/nl/astraeus/jdbc/util/Util.java new file mode 100644 index 0000000..eaa853b --- /dev/null +++ b/src/nl/astraeus/jdbc/util/Util.java @@ -0,0 +1,25 @@ +package nl.astraeus.jdbc.util; + +import java.text.DecimalFormat; +import java.text.NumberFormat; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 12:28 PM + */ +public class Util { + // utility functions + public static String formatNano(long l) { + NumberFormat format = new DecimalFormat("###,##0.000000"); + + return format.format((double) l / 1000000.0); + } + + public static void printMemoryUsage() { + System.out.println("Used memory: "+((Runtime.getRuntime().totalMemory() / (1024*1024))-(Runtime.getRuntime().freeMemory() / (1024*1024)))); + System.out.println("Free memory: "+(Runtime.getRuntime().freeMemory() / (1024*1024))); + System.out.println("Total memory: "+(Runtime.getRuntime().totalMemory() / (1024*1024))); + System.out.println("Max memory: "+(Runtime.getRuntime().maxMemory() / (1024*1024))); + } +} diff --git a/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java b/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java new file mode 100644 index 0000000..a162d6f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java @@ -0,0 +1,90 @@ +package nl.astraeus.jdbc.web; + +import nl.astraeus.jdbc.util.IOUtils; +import nl.astraeus.jdbc.util.Util; +import nl.astraeus.jdbc.web.page.Menu; +import nl.astraeus.jdbc.web.page.Page; +import nl.astraeus.jdbc.web.page.QueryOverview; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import java.io.IOException; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:05 PM + */ +public class JdbcStatisticsServlet extends HttpServlet { + + private String head; + private String bottom; + + @Override + public void init() throws ServletException { + super.init(); + + try { + head = IOUtils.toString(getClass().getResourceAsStream("head.html")); + bottom = IOUtils.toString(getClass().getResourceAsStream("bottom.html")); + } catch (IOException e) { + throw new ServletException(e); + } + + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + doPost(req, resp); + } + + @Override + protected void doPost(final HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + long nano = System.nanoTime(); + + HttpSession session = req.getSession(); + boolean ajax = "true".equals(req.getParameter("ajax")); + + resp.setContentType("text/html"); + + Page page = (Page)session.getAttribute("page"); + Page menu = (Page)session.getAttribute("menu"); + + session.setMaxInactiveInterval(1800); + + if (menu == null) { + menu = new Menu(); + + session.setAttribute("menu", menu); + } + + if (page == null || "menumain".equals(req.getParameter("action"))) { + page = new QueryOverview(); + } else if ("diagnostics".equals(req.getParameter("action"))) { + //page = new Diagnostics(); + } else { + page = page .processRequest(req); + } + + menu.processRequest(req); + + session.setAttribute("page", page); + + if (!ajax) { + resp.getWriter().print(head); + } + + resp.getWriter().print(menu.render(req)); + resp.getWriter().print(page.render(req)); + + if (!ajax) { + resp.getWriter().print(bottom); + } + + System.out.println("Request ends, time="+ Util.formatNano(System.nanoTime() - nano) +", page="+page.getClass().getSimpleName()); + } + +} diff --git a/src/nl/astraeus/jdbc/web/ResourceServlet.java b/src/nl/astraeus/jdbc/web/ResourceServlet.java new file mode 100644 index 0000000..7abfe6f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/ResourceServlet.java @@ -0,0 +1,49 @@ +package nl.astraeus.jdbc.web; + +import nl.astraeus.jdbc.util.IOUtils; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.InputStream; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:05 PM + */ +public class ResourceServlet extends HttpServlet { + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String uri = req.getRequestURI(); + + uri = "nl/astraeus/jdbc/web" + uri; + InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(uri); + + if (in == null) { + resp.sendError(404, "Cannot find resource '" + uri + "'."); + } else { + try { + if (uri.endsWith("js")) { + resp.setContentType("text/javascript"); + } else if (uri.endsWith("css")) { + resp.setContentType("text/css"); + } else if (uri.endsWith("png")) { + resp.setContentType("image/png"); + } else if (uri.endsWith("jpg")) { + resp.setContentType("image/jpeg"); + } else if (uri.endsWith("gif")) { + resp.setContentType("image/gif"); + } + + IOUtils.copy(in, resp.getOutputStream()); + } finally { + in.close(); + } + } + } + +} diff --git a/src/nl/astraeus/jdbc/web/bottom.html b/src/nl/astraeus/jdbc/web/bottom.html new file mode 100644 index 0000000..1288de4 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/bottom.html @@ -0,0 +1,8 @@ + + +
+ + + + + \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/head.html b/src/nl/astraeus/jdbc/web/head.html new file mode 100644 index 0000000..0f8f6a3 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/head.html @@ -0,0 +1,96 @@ + + + + + + + Simple JDBC Statistics + + + + + + + + + + + + + + + + + + + +
+
+ +
+ diff --git a/src/nl/astraeus/jdbc/web/page/Menu.html b/src/nl/astraeus/jdbc/web/page/Menu.html new file mode 100644 index 0000000..505c7c2 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.html @@ -0,0 +1,42 @@ + diff --git a/src/nl/astraeus/jdbc/web/page/Menu.java b/src/nl/astraeus/jdbc/web/page/Menu.java new file mode 100644 index 0000000..f0a349a --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.java @@ -0,0 +1,27 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 9:07 PM + */ +public class Menu extends TemplatePage { + + @Override + public Page processRequest(HttpServletRequest request) { + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + result.put("user", request.getSession().getAttribute("user")); + + return result; + } +} diff --git a/src/nl/astraeus/jdbc/web/page/Page.java b/src/nl/astraeus/jdbc/web/page/Page.java new file mode 100644 index 0000000..9d526d6 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Page.java @@ -0,0 +1,17 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:20 PM + */ +public abstract class Page { + + public abstract Page processRequest(HttpServletRequest request); + public abstract Map defineModel(HttpServletRequest request); + public abstract String render(HttpServletRequest request); + +} diff --git a/src/nl/astraeus/jdbc/web/page/QueryOverview.html b/src/nl/astraeus/jdbc/web/page/QueryOverview.html new file mode 100644 index 0000000..64a88fb --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/QueryOverview.html @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + {foreach(queries as q)} + + + + + + + {eachend} + +
Total timeAvg. time# CallsSql
{q.total}{q.nano}{q.count}{q.sql}
diff --git a/src/nl/astraeus/jdbc/web/page/QueryOverview.java b/src/nl/astraeus/jdbc/web/page/QueryOverview.java new file mode 100644 index 0000000..02982f1 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/QueryOverview.java @@ -0,0 +1,92 @@ +package nl.astraeus.jdbc.web.page; + +import nl.astraeus.jdbc.JdbcLogger; + +import javax.servlet.http.HttpServletRequest; +import java.util.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 9:16 PM + */ +public class QueryOverview extends TemplatePage { + + boolean sortTotalCalls = true; + boolean sortAvgTime = false; + boolean sortTotalTime = false; + + @Override + public Page processRequest(HttpServletRequest request) { + if ("sortTotalCalls".equals(request.getParameter("action"))) { + sortTotalCalls = true; + sortAvgTime = false; + sortTotalTime = false; + } else if ("sortAvgTime".equals(request.getParameter("action"))) { + sortTotalCalls = false; + sortAvgTime = true; + sortTotalTime = false; + } else if ("sortTotalTime".equals(request.getParameter("action"))) { + sortTotalCalls = false; + sortAvgTime = false; + sortTotalTime = true; + } + + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + List entries = new ArrayList(JdbcLogger.get().getEntries()); + + if (sortTotalCalls) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + return o2.count - o1.count; + } + }); + } else if (sortAvgTime) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + long n1 = o1.nano / o1.count; + long n2 = o2.nano / o2.count; + + if (n2 > n1) { + return 1; + } else if (n2 < n1) { + return -1; + } else { + return 0; + } + } + }); + } else if (sortTotalTime) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + if (o2.nano > o1.nano) { + return 1; + } else if (o2.nano < o1.nano) { + return -1; + } else { + return 0; + } + } + }); + } + + result.put("queries", entries); + result.put("count", entries.size()); + + result.put("sortTotalCalls", sortTotalCalls); + result.put("sortAvgTime", sortAvgTime); + result.put("sortTotalTime", sortTotalTime); + + return result; + } + +} diff --git a/src/nl/astraeus/jdbc/web/page/TemplatePage.java b/src/nl/astraeus/jdbc/web/page/TemplatePage.java new file mode 100644 index 0000000..33e2641 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/TemplatePage.java @@ -0,0 +1,58 @@ +package nl.astraeus.jdbc.web.page; + +import nl.astraeus.template.EscapeMode; +import nl.astraeus.template.SimpleTemplate; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:20 PM + */ +public abstract class TemplatePage extends Page { + + private SimpleTemplate template; + + protected TemplatePage() { + template = getSimpleTemplate(this.getClass()); + } + + public String render(HttpServletRequest request) { + return template.render(defineModel(request)); + } + + private static Map templateCache = new HashMap(); + + public synchronized static SimpleTemplate getSimpleTemplate(Class cls) { + SimpleTemplate result = templateCache.get(cls); + + if (result == null) { + InputStream in = null; + + try { + in = cls.getResourceAsStream(cls.getSimpleName() + ".html"); + + result = SimpleTemplate.readTemplate('{','}', EscapeMode.HTML, in); + + templateCache.put(cls, result); + } catch (IOException e) { + throw new IllegalStateException(e); + } finally { + if (in != null) { + try { + in.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + + return result; + } +} diff --git a/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css b/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css new file mode 100644 index 0000000..0e0056f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css @@ -0,0 +1,581 @@ +/*! + * Bootstrap Responsive v2.0.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ +.clearfix { + *zoom: 1; +} +.clearfix:before, .clearfix:after { + display: table; + content: ""; +} +.clearfix:after { + clear: both; +} +.hidden { + display: none; + visibility: hidden; +} +@media (max-width: 480px) { + .nav-collapse { + -webkit-transform: translate3d(0, 0, 0); + } + .page-header h1 small { + display: block; + line-height: 18px; + } + input[class*="span"], + select[class*="span"], + textarea[class*="span"], + .uneditable-input { + display: block; + width: 100%; + min-height: 28px; + /* Make inputs at least the height of their button counterpart */ + + /* Makes inputs behave like true block-level elements */ + + -webkit-box-sizing: border-box; + /* Older Webkit */ + + -moz-box-sizing: border-box; + /* Older FF */ + + -ms-box-sizing: border-box; + /* IE8 */ + + box-sizing: border-box; + /* CSS3 spec*/ + + } + .input-prepend input[class*="span"], .input-append input[class*="span"] { + width: auto; + } + input[type="checkbox"], input[type="radio"] { + border: 1px solid #ccc; + } + .form-horizontal .control-group > label { + float: none; + width: auto; + padding-top: 0; + text-align: left; + } + .form-horizontal .controls { + margin-left: 0; + } + .form-horizontal .control-list { + padding-top: 0; + } + .form-horizontal .form-actions { + padding-left: 10px; + padding-right: 10px; + } + .modal { + position: absolute; + top: 10px; + left: 10px; + right: 10px; + width: auto; + margin: 0; + } + .modal.fade.in { + top: auto; + } + .modal-header .close { + padding: 10px; + margin: -10px; + } + .carousel-caption { + position: static; + } +} +@media (max-width: 767px) { + .container { + width: auto; + padding: 0 20px; + } + .row-fluid { + width: 100%; + } + .row { + margin-left: 0; + } + .row > [class*="span"], .row-fluid > [class*="span"] { + float: none; + display: block; + width: auto; + margin: 0; + } +} +@media (min-width: 768px) and (max-width: 979px) { + .row { + margin-left: -20px; + *zoom: 1; + } + .row:before, .row:after { + display: table; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + margin-left: 20px; + } + .span1 { + width: 42px; + } + .span2 { + width: 104px; + } + .span3 { + width: 166px; + } + .span4 { + width: 228px; + } + .span5 { + width: 290px; + } + .span6 { + width: 352px; + } + .span7 { + width: 414px; + } + .span8 { + width: 476px; + } + .span9 { + width: 538px; + } + .span10 { + width: 600px; + } + .span11 { + width: 662px; + } + .span12, .container { + width: 724px; + } + .offset1 { + margin-left: 82px; + } + .offset2 { + margin-left: 144px; + } + .offset3 { + margin-left: 206px; + } + .offset4 { + margin-left: 268px; + } + .offset5 { + margin-left: 330px; + } + .offset6 { + margin-left: 392px; + } + .offset7 { + margin-left: 454px; + } + .offset8 { + margin-left: 516px; + } + .offset9 { + margin-left: 578px; + } + .offset10 { + margin-left: 640px; + } + .offset11 { + margin-left: 702px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, .row-fluid:after { + display: table; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid > [class*="span"] { + float: left; + margin-left: 2.762430939%; + } + .row-fluid > [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid > .span1 { + width: 5.801104972%; + } + .row-fluid > .span2 { + width: 14.364640883%; + } + .row-fluid > .span3 { + width: 22.928176794%; + } + .row-fluid > .span4 { + width: 31.491712705%; + } + .row-fluid > .span5 { + width: 40.055248616%; + } + .row-fluid > .span6 { + width: 48.618784527%; + } + .row-fluid > .span7 { + width: 57.182320438000005%; + } + .row-fluid > .span8 { + width: 65.74585634900001%; + } + .row-fluid > .span9 { + width: 74.30939226%; + } + .row-fluid > .span10 { + width: 82.87292817100001%; + } + .row-fluid > .span11 { + width: 91.436464082%; + } + .row-fluid > .span12 { + width: 99.999999993%; + } + input.span1, textarea.span1, .uneditable-input.span1 { + width: 32px; + } + input.span2, textarea.span2, .uneditable-input.span2 { + width: 94px; + } + input.span3, textarea.span3, .uneditable-input.span3 { + width: 156px; + } + input.span4, textarea.span4, .uneditable-input.span4 { + width: 218px; + } + input.span5, textarea.span5, .uneditable-input.span5 { + width: 280px; + } + input.span6, textarea.span6, .uneditable-input.span6 { + width: 342px; + } + input.span7, textarea.span7, .uneditable-input.span7 { + width: 404px; + } + input.span8, textarea.span8, .uneditable-input.span8 { + width: 466px; + } + input.span9, textarea.span9, .uneditable-input.span9 { + width: 528px; + } + input.span10, textarea.span10, .uneditable-input.span10 { + width: 590px; + } + input.span11, textarea.span11, .uneditable-input.span11 { + width: 652px; + } + input.span12, textarea.span12, .uneditable-input.span12 { + width: 714px; + } +} +@media (max-width: 979px) { + body { + padding-top: 0; + } + .navbar-fixed-top { + position: static; + margin-bottom: 18px; + } + .navbar-fixed-top .navbar-inner { + padding: 5px; + } + .navbar .container { + width: auto; + padding: 0; + } + .navbar .brand { + padding-left: 10px; + padding-right: 10px; + margin: 0 0 0 -5px; + } + .navbar .nav-collapse { + clear: left; + } + .navbar .nav { + float: none; + margin: 0 0 9px; + } + .navbar .nav > li { + float: none; + } + .navbar .nav > li > a { + margin-bottom: 2px; + } + .navbar .nav > .divider-vertical { + display: none; + } + .navbar .nav .nav-header { + color: #999999; + text-shadow: none; + } + .navbar .nav > li > a, .navbar .dropdown-menu a { + padding: 6px 15px; + font-weight: bold; + color: #999999; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + } + .navbar .dropdown-menu li + li a { + margin-bottom: 2px; + } + .navbar .nav > li > a:hover, .navbar .dropdown-menu a:hover { + background-color: #222222; + } + .navbar .dropdown-menu { + position: static; + top: auto; + left: auto; + float: none; + display: block; + max-width: none; + margin: 0 15px; + padding: 0; + background-color: transparent; + border: none; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + } + .navbar .dropdown-menu:before, .navbar .dropdown-menu:after { + display: none; + } + .navbar .dropdown-menu .divider { + display: none; + } + .navbar-form, .navbar-search { + float: none; + padding: 9px 15px; + margin: 9px 0; + border-top: 1px solid #222222; + border-bottom: 1px solid #222222; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + } + .navbar .nav.pull-right { + float: none; + margin-left: 0; + } + .navbar-static .navbar-inner { + padding-left: 10px; + padding-right: 10px; + } + .btn-navbar { + display: block; + } + .nav-collapse { + overflow: hidden; + height: 0; + } +} +@media (min-width: 980px) { + .nav-collapse.collapse { + height: auto !important; + } +} +@media (min-width: 1200px) { + .row { + margin-left: -30px; + *zoom: 1; + } + .row:before, .row:after { + display: table; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + margin-left: 30px; + } + .span1 { + width: 70px; + } + .span2 { + width: 170px; + } + .span3 { + width: 270px; + } + .span4 { + width: 370px; + } + .span5 { + width: 470px; + } + .span6 { + width: 570px; + } + .span7 { + width: 670px; + } + .span8 { + width: 770px; + } + .span9 { + width: 870px; + } + .span10 { + width: 970px; + } + .span11 { + width: 1070px; + } + .span12, .container { + width: 1170px; + } + .offset1 { + margin-left: 130px; + } + .offset2 { + margin-left: 230px; + } + .offset3 { + margin-left: 330px; + } + .offset4 { + margin-left: 430px; + } + .offset5 { + margin-left: 530px; + } + .offset6 { + margin-left: 630px; + } + .offset7 { + margin-left: 730px; + } + .offset8 { + margin-left: 830px; + } + .offset9 { + margin-left: 930px; + } + .offset10 { + margin-left: 1030px; + } + .offset11 { + margin-left: 1130px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, .row-fluid:after { + display: table; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid > [class*="span"] { + float: left; + margin-left: 2.564102564%; + } + .row-fluid > [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid > .span1 { + width: 5.982905983%; + } + .row-fluid > .span2 { + width: 14.529914530000001%; + } + .row-fluid > .span3 { + width: 23.076923077%; + } + .row-fluid > .span4 { + width: 31.623931624%; + } + .row-fluid > .span5 { + width: 40.170940171000005%; + } + .row-fluid > .span6 { + width: 48.717948718%; + } + .row-fluid > .span7 { + width: 57.264957265%; + } + .row-fluid > .span8 { + width: 65.81196581200001%; + } + .row-fluid > .span9 { + width: 74.358974359%; + } + .row-fluid > .span10 { + width: 82.905982906%; + } + .row-fluid > .span11 { + width: 91.45299145300001%; + } + .row-fluid > .span12 { + width: 100%; + } + input.span1, textarea.span1, .uneditable-input.span1 { + width: 60px; + } + input.span2, textarea.span2, .uneditable-input.span2 { + width: 160px; + } + input.span3, textarea.span3, .uneditable-input.span3 { + width: 260px; + } + input.span4, textarea.span4, .uneditable-input.span4 { + width: 360px; + } + input.span5, textarea.span5, .uneditable-input.span5 { + width: 460px; + } + input.span6, textarea.span6, .uneditable-input.span6 { + width: 560px; + } + input.span7, textarea.span7, .uneditable-input.span7 { + width: 660px; + } + input.span8, textarea.span8, .uneditable-input.span8 { + width: 760px; + } + input.span9, textarea.span9, .uneditable-input.span9 { + width: 860px; + } + input.span10, textarea.span10, .uneditable-input.span10 { + width: 960px; + } + input.span11, textarea.span11, .uneditable-input.span11 { + width: 1060px; + } + input.span12, textarea.span12, .uneditable-input.span12 { + width: 1160px; + } + .thumbnails { + margin-left: -30px; + } + .thumbnails > li { + margin-left: 30px; + } +} diff --git a/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css b/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css new file mode 100644 index 0000000..6229c12 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css @@ -0,0 +1,3521 @@ +/*! + * Bootstrap v2.0.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +nav, +section { + display: block; +} +audio, canvas, video { + display: inline-block; + *display: inline; + *zoom: 1; +} +audio:not([controls]) { + display: none; +} +html { + font-size: 100%; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} +a:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +a:hover, a:active { + outline: 0; +} +sub, sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} +sup { + top: -0.5em; +} +sub { + bottom: -0.25em; +} +img { + max-width: 100%; + height: auto; + border: 0; + -ms-interpolation-mode: bicubic; +} +button, +input, +select, +textarea { + margin: 0; + font-size: 100%; + vertical-align: middle; +} +button, input { + *overflow: visible; + line-height: normal; +} +button::-moz-focus-inner, input::-moz-focus-inner { + padding: 0; + border: 0; +} +button, +input[type="button"], +input[type="reset"], +input[type="submit"] { + cursor: pointer; + -webkit-appearance: button; +} +input[type="search"] { + -webkit-appearance: textfield; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +input[type="search"]::-webkit-search-decoration, input[type="search"]::-webkit-search-cancel-button { + -webkit-appearance: none; +} +textarea { + overflow: auto; + vertical-align: top; +} +.clearfix { + *zoom: 1; +} +.clearfix:before, .clearfix:after { + display: table; + content: ""; +} +.clearfix:after { + clear: both; +} +body { + margin: 0; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 18px; + color: #333333; + background-color: #ffffff; +} +a { + color: #0088cc; + text-decoration: none; +} +a:hover { + color: #005580; + text-decoration: underline; +} +.row { + margin-left: -20px; + *zoom: 1; +} +.row:before, .row:after { + display: table; + content: ""; +} +.row:after { + clear: both; +} +[class*="span"] { + float: left; + margin-left: 20px; +} +.span1 { + width: 60px; +} +.span2 { + width: 140px; +} +.span3 { + width: 220px; +} +.span4 { + width: 300px; +} +.span5 { + width: 380px; +} +.span6 { + width: 460px; +} +.span7 { + width: 540px; +} +.span8 { + width: 620px; +} +.span9 { + width: 700px; +} +.span10 { + width: 780px; +} +.span11 { + width: 860px; +} +.span12, .container { + width: 940px; +} +.offset1 { + margin-left: 100px; +} +.offset2 { + margin-left: 180px; +} +.offset3 { + margin-left: 260px; +} +.offset4 { + margin-left: 340px; +} +.offset5 { + margin-left: 420px; +} +.offset6 { + margin-left: 500px; +} +.offset7 { + margin-left: 580px; +} +.offset8 { + margin-left: 660px; +} +.offset9 { + margin-left: 740px; +} +.offset10 { + margin-left: 820px; +} +.offset11 { + margin-left: 900px; +} +.row-fluid { + width: 100%; + *zoom: 1; +} +.row-fluid:before, .row-fluid:after { + display: table; + content: ""; +} +.row-fluid:after { + clear: both; +} +.row-fluid > [class*="span"] { + float: left; + margin-left: 2.127659574%; +} +.row-fluid > [class*="span"]:first-child { + margin-left: 0; +} +.row-fluid > .span1 { + width: 6.382978723%; +} +.row-fluid > .span2 { + width: 14.89361702%; +} +.row-fluid > .span3 { + width: 23.404255317%; +} +.row-fluid > .span4 { + width: 31.914893614%; +} +.row-fluid > .span5 { + width: 40.425531911%; +} +.row-fluid > .span6 { + width: 48.93617020799999%; +} +.row-fluid > .span7 { + width: 57.446808505%; +} +.row-fluid > .span8 { + width: 65.95744680199999%; +} +.row-fluid > .span9 { + width: 74.468085099%; +} +.row-fluid > .span10 { + width: 82.97872339599999%; +} +.row-fluid > .span11 { + width: 91.489361693%; +} +.row-fluid > .span12 { + width: 99.99999998999999%; +} +.container { + width: 940px; + margin-left: auto; + margin-right: auto; + *zoom: 1; +} +.container:before, .container:after { + display: table; + content: ""; +} +.container:after { + clear: both; +} +.container-fluid { + padding-left: 20px; + padding-right: 20px; + *zoom: 1; +} +.container-fluid:before, .container-fluid:after { + display: table; + content: ""; +} +.container-fluid:after { + clear: both; +} +p { + margin: 0 0 9px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 18px; +} +p small { + font-size: 11px; + color: #999999; +} +.lead { + margin-bottom: 18px; + font-size: 20px; + font-weight: 200; + line-height: 27px; +} +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 0; + font-weight: bold; + color: #333333; + text-rendering: optimizelegibility; +} +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small { + font-weight: normal; + color: #999999; +} +h1 { + font-size: 30px; + line-height: 36px; +} +h1 small { + font-size: 18px; +} +h2 { + font-size: 24px; + line-height: 36px; +} +h2 small { + font-size: 18px; +} +h3 { + line-height: 27px; + font-size: 18px; +} +h3 small { + font-size: 14px; +} +h4, h5, h6 { + line-height: 18px; +} +h4 { + font-size: 14px; +} +h4 small { + font-size: 12px; +} +h5 { + font-size: 12px; +} +h6 { + font-size: 11px; + color: #999999; + text-transform: uppercase; +} +.page-header { + padding-bottom: 17px; + margin: 18px 0; + border-bottom: 1px solid #eeeeee; +} +.page-header h1 { + line-height: 1; +} +ul, ol { + padding: 0; + margin: 0 0 9px 25px; +} +ul ul, +ul ol, +ol ol, +ol ul { + margin-bottom: 0; +} +ul { + list-style: disc; +} +ol { + list-style: decimal; +} +li { + line-height: 18px; +} +ul.unstyled, ol.unstyled { + margin-left: 0; + list-style: none; +} +dl { + margin-bottom: 18px; +} +dt, dd { + line-height: 18px; +} +dt { + font-weight: bold; +} +dd { + margin-left: 9px; +} +hr { + margin: 18px 0; + border: 0; + border-top: 1px solid #eeeeee; + border-bottom: 1px solid #ffffff; +} +strong { + font-weight: bold; +} +em { + font-style: italic; +} +.muted { + color: #999999; +} +abbr { + font-size: 90%; + text-transform: uppercase; + border-bottom: 1px dotted #ddd; + cursor: help; +} +blockquote { + padding: 0 0 0 15px; + margin: 0 0 18px; + border-left: 5px solid #eeeeee; +} +blockquote p { + margin-bottom: 0; + font-size: 16px; + font-weight: 300; + line-height: 22.5px; +} +blockquote small { + display: block; + line-height: 18px; + color: #999999; +} +blockquote small:before { + content: '\2014 \00A0'; +} +blockquote.pull-right { + float: right; + padding-left: 0; + padding-right: 15px; + border-left: 0; + border-right: 5px solid #eeeeee; +} +blockquote.pull-right p, blockquote.pull-right small { + text-align: right; +} +q:before, +q:after, +blockquote:before, +blockquote:after { + content: ""; +} +address { + display: block; + margin-bottom: 18px; + line-height: 18px; + font-style: normal; +} +small { + font-size: 100%; +} +cite { + font-style: normal; +} +code, pre { + padding: 0 3px 2px; + font-family: Menlo, Monaco, "Courier New", monospace; + font-size: 12px; + color: #333333; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +code { + padding: 3px 4px; + color: #d14; + background-color: #f7f7f9; + border: 1px solid #e1e1e8; +} +pre { + display: block; + padding: 8.5px; + margin: 0 0 9px; + font-size: 12px; + line-height: 18px; + background-color: #f5f5f5; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.15); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + white-space: pre; + white-space: pre-wrap; + word-break: break-all; + word-wrap: break-word; +} +pre.prettyprint { + margin-bottom: 18px; +} +pre code { + padding: 0; + color: inherit; + background-color: transparent; + border: 0; +} +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} +form { + margin: 0 0 18px; +} +fieldset { + padding: 0; + margin: 0; + border: 0; +} +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 27px; + font-size: 19.5px; + line-height: 36px; + color: #333333; + border: 0; + border-bottom: 1px solid #eee; +} +legend small { + font-size: 13.5px; + color: #999999; +} +label, +input, +button, +select, +textarea { + font-size: 13px; + font-weight: normal; + line-height: 18px; +} +input, +button, +select, +textarea { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; +} +label { + display: block; + margin-bottom: 5px; + color: #333333; +} +input, +textarea, +select, +.uneditable-input { + display: inline-block; + width: 210px; + height: 18px; + padding: 4px; + margin-bottom: 9px; + font-size: 13px; + line-height: 18px; + color: #555555; + border: 1px solid #ccc; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.uneditable-textarea { + width: auto; + height: auto; +} +label input, label textarea, label select { + display: block; +} +input[type="image"], input[type="checkbox"], input[type="radio"] { + width: auto; + height: auto; + padding: 0; + margin: 3px 0; + *margin-top: 0; + /* IE7 */ + + line-height: normal; + cursor: pointer; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + border: 0 \9; + /* IE9 and down */ + +} +input[type="image"] { + border: 0; +} +input[type="file"] { + width: auto; + padding: initial; + line-height: initial; + border: initial; + background-color: #ffffff; + background-color: initial; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +input[type="button"], input[type="reset"], input[type="submit"] { + width: auto; + height: auto; +} +select, input[type="file"] { + height: 28px; + /* In IE7, the height of the select element cannot be changed by height, only font-size */ + + *margin-top: 4px; + /* For IE7, add top margin to align select with labels */ + + line-height: 28px; +} +input[type="file"] { + line-height: 18px \9; +} +select { + width: 220px; + background-color: #ffffff; +} +select[multiple], select[size] { + height: auto; +} +input[type="image"] { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +textarea { + height: auto; +} +input[type="hidden"] { + display: none; +} +.radio, .checkbox { + padding-left: 18px; +} +.radio input[type="radio"], .checkbox input[type="checkbox"] { + float: left; + margin-left: -18px; +} +.controls > .radio:first-child, .controls > .checkbox:first-child { + padding-top: 5px; +} +.radio.inline, .checkbox.inline { + display: inline-block; + padding-top: 5px; + margin-bottom: 0; + vertical-align: middle; +} +.radio.inline + .radio.inline, .checkbox.inline + .checkbox.inline { + margin-left: 10px; +} +input, textarea { + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; + -moz-transition: border linear 0.2s, box-shadow linear 0.2s; + -ms-transition: border linear 0.2s, box-shadow linear 0.2s; + -o-transition: border linear 0.2s, box-shadow linear 0.2s; + transition: border linear 0.2s, box-shadow linear 0.2s; +} +input:focus, textarea:focus { + border-color: rgba(82, 168, 236, 0.8); + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + outline: 0; + outline: thin dotted \9; + /* IE6-9 */ + +} +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus, +select:focus { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.input-mini { + width: 60px; +} +.input-small { + width: 90px; +} +.input-medium { + width: 150px; +} +.input-large { + width: 210px; +} +.input-xlarge { + width: 270px; +} +.input-xxlarge { + width: 530px; +} +input[class*="span"], +select[class*="span"], +textarea[class*="span"], +.uneditable-input { + float: none; + margin-left: 0; +} +input.span1, textarea.span1, .uneditable-input.span1 { + width: 50px; +} +input.span2, textarea.span2, .uneditable-input.span2 { + width: 130px; +} +input.span3, textarea.span3, .uneditable-input.span3 { + width: 210px; +} +input.span4, textarea.span4, .uneditable-input.span4 { + width: 290px; +} +input.span5, textarea.span5, .uneditable-input.span5 { + width: 370px; +} +input.span6, textarea.span6, .uneditable-input.span6 { + width: 450px; +} +input.span7, textarea.span7, .uneditable-input.span7 { + width: 530px; +} +input.span8, textarea.span8, .uneditable-input.span8 { + width: 610px; +} +input.span9, textarea.span9, .uneditable-input.span9 { + width: 690px; +} +input.span10, textarea.span10, .uneditable-input.span10 { + width: 770px; +} +input.span11, textarea.span11, .uneditable-input.span11 { + width: 850px; +} +input.span12, textarea.span12, .uneditable-input.span12 { + width: 930px; +} +input[disabled], +select[disabled], +textarea[disabled], +input[readonly], +select[readonly], +textarea[readonly] { + background-color: #f5f5f5; + border-color: #ddd; + cursor: not-allowed; +} +.control-group.warning > label, .control-group.warning .help-block, .control-group.warning .help-inline { + color: #c09853; +} +.control-group.warning input, .control-group.warning select, .control-group.warning textarea { + color: #c09853; + border-color: #c09853; +} +.control-group.warning input:focus, .control-group.warning select:focus, .control-group.warning textarea:focus { + border-color: #a47e3c; + -webkit-box-shadow: 0 0 6px #dbc59e; + -moz-box-shadow: 0 0 6px #dbc59e; + box-shadow: 0 0 6px #dbc59e; +} +.control-group.warning .input-prepend .add-on, .control-group.warning .input-append .add-on { + color: #c09853; + background-color: #fcf8e3; + border-color: #c09853; +} +.control-group.error > label, .control-group.error .help-block, .control-group.error .help-inline { + color: #b94a48; +} +.control-group.error input, .control-group.error select, .control-group.error textarea { + color: #b94a48; + border-color: #b94a48; +} +.control-group.error input:focus, .control-group.error select:focus, .control-group.error textarea:focus { + border-color: #953b39; + -webkit-box-shadow: 0 0 6px #d59392; + -moz-box-shadow: 0 0 6px #d59392; + box-shadow: 0 0 6px #d59392; +} +.control-group.error .input-prepend .add-on, .control-group.error .input-append .add-on { + color: #b94a48; + background-color: #f2dede; + border-color: #b94a48; +} +.control-group.success > label, .control-group.success .help-block, .control-group.success .help-inline { + color: #468847; +} +.control-group.success input, .control-group.success select, .control-group.success textarea { + color: #468847; + border-color: #468847; +} +.control-group.success input:focus, .control-group.success select:focus, .control-group.success textarea:focus { + border-color: #356635; + -webkit-box-shadow: 0 0 6px #7aba7b; + -moz-box-shadow: 0 0 6px #7aba7b; + box-shadow: 0 0 6px #7aba7b; +} +.control-group.success .input-prepend .add-on, .control-group.success .input-append .add-on { + color: #468847; + background-color: #dff0d8; + border-color: #468847; +} +input:focus:required:invalid, textarea:focus:required:invalid, select:focus:required:invalid { + color: #b94a48; + border-color: #ee5f5b; +} +input:focus:required:invalid:focus, textarea:focus:required:invalid:focus, select:focus:required:invalid:focus { + border-color: #e9322d; + -webkit-box-shadow: 0 0 6px #f8b9b7; + -moz-box-shadow: 0 0 6px #f8b9b7; + box-shadow: 0 0 6px #f8b9b7; +} +.form-actions { + padding: 17px 20px 18px; + margin-top: 18px; + margin-bottom: 18px; + background-color: #f5f5f5; + border-top: 1px solid #ddd; +} +.uneditable-input { + display: block; + background-color: #ffffff; + border-color: #eee; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + cursor: not-allowed; +} +:-moz-placeholder { + color: #999999; +} +::-webkit-input-placeholder { + color: #999999; +} +.help-block { + display: block; + margin-top: 5px; + margin-bottom: 0; + color: #999999; +} +.help-inline { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; + margin-bottom: 9px; + vertical-align: middle; + padding-left: 5px; +} +.input-prepend, .input-append { + margin-bottom: 5px; + *zoom: 1; +} +.input-prepend:before, +.input-append:before, +.input-prepend:after, +.input-append:after { + display: table; + content: ""; +} +.input-prepend:after, .input-append:after { + clear: both; +} +.input-prepend input, +.input-append input, +.input-prepend .uneditable-input, +.input-append .uneditable-input { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.input-prepend input:focus, +.input-append input:focus, +.input-prepend .uneditable-input:focus, +.input-append .uneditable-input:focus { + position: relative; + z-index: 2; +} +.input-prepend .uneditable-input, .input-append .uneditable-input { + border-left-color: #ccc; +} +.input-prepend .add-on, .input-append .add-on { + float: left; + display: block; + width: auto; + min-width: 16px; + height: 18px; + margin-right: -1px; + padding: 4px 5px; + font-weight: normal; + line-height: 18px; + color: #999999; + text-align: center; + text-shadow: 0 1px 0 #ffffff; + background-color: #f5f5f5; + border: 1px solid #ccc; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.input-prepend .active, .input-append .active { + background-color: #a9dba9; + border-color: #46a546; +} +.input-prepend .add-on { + *margin-top: 1px; + /* IE6-7 */ + +} +.input-append input, .input-append .uneditable-input { + float: left; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.input-append .uneditable-input { + border-left-color: #eee; + border-right-color: #ccc; +} +.input-append .add-on { + margin-right: 0; + margin-left: -1px; + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.input-append input:first-child { + *margin-left: -160px; +} +.input-append input:first-child + .add-on { + *margin-left: -21px; +} +.search-query { + padding-left: 14px; + padding-right: 14px; + margin-bottom: 0; + -webkit-border-radius: 14px; + -moz-border-radius: 14px; + border-radius: 14px; +} +.form-search input, +.form-inline input, +.form-horizontal input, +.form-search textarea, +.form-inline textarea, +.form-horizontal textarea, +.form-search select, +.form-inline select, +.form-horizontal select, +.form-search .help-inline, +.form-inline .help-inline, +.form-horizontal .help-inline, +.form-search .uneditable-input, +.form-inline .uneditable-input, +.form-horizontal .uneditable-input { + display: inline-block; + margin-bottom: 0; +} +.form-search .hide, .form-inline .hide, .form-horizontal .hide { + display: none; +} +.form-search label, +.form-inline label, +.form-search .input-append, +.form-inline .input-append, +.form-search .input-prepend, +.form-inline .input-prepend { + display: inline-block; +} +.form-search .input-append .add-on, +.form-inline .input-prepend .add-on, +.form-search .input-append .add-on, +.form-inline .input-prepend .add-on { + vertical-align: middle; +} +.form-search .radio, +.form-inline .radio, +.form-search .checkbox, +.form-inline .checkbox { + margin-bottom: 0; + vertical-align: middle; +} +.control-group { + margin-bottom: 9px; +} +legend + .control-group { + margin-top: 18px; + -webkit-margin-top-collapse: separate; +} +.form-horizontal .control-group { + margin-bottom: 18px; + *zoom: 1; +} +.form-horizontal .control-group:before, .form-horizontal .control-group:after { + display: table; + content: ""; +} +.form-horizontal .control-group:after { + clear: both; +} +.form-horizontal .control-label { + float: left; + width: 140px; + padding-top: 5px; + text-align: right; +} +.form-horizontal .controls { + margin-left: 160px; +} +.form-horizontal .form-actions { + padding-left: 160px; +} +table { + max-width: 100%; + border-collapse: collapse; + border-spacing: 0; +} +.table { + width: 100%; + margin-bottom: 18px; +} +.table th, .table td { + padding: 8px; + line-height: 18px; + text-align: left; + vertical-align: top; + border-top: 1px solid #ddd; +} +.table th { + font-weight: bold; +} +.table thead th { + vertical-align: bottom; +} +.table thead:first-child tr th, .table thead:first-child tr td { + border-top: 0; +} +.table tbody + tbody { + border-top: 2px solid #ddd; +} +.table-condensed th, .table-condensed td { + padding: 4px 5px; +} +.table-bordered { + border: 1px solid #ddd; + border-collapse: separate; + *border-collapse: collapsed; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.table-bordered th + th, +.table-bordered td + td, +.table-bordered th + td, +.table-bordered td + th { + border-left: 1px solid #ddd; +} +.table-bordered thead:first-child tr:first-child th, .table-bordered tbody:first-child tr:first-child th, .table-bordered tbody:first-child tr:first-child td { + border-top: 0; +} +.table-bordered thead:first-child tr:first-child th:first-child, .table-bordered tbody:first-child tr:first-child td:first-child { + -webkit-border-radius: 4px 0 0 0; + -moz-border-radius: 4px 0 0 0; + border-radius: 4px 0 0 0; +} +.table-bordered thead:first-child tr:first-child th:last-child, .table-bordered tbody:first-child tr:first-child td:last-child { + -webkit-border-radius: 0 4px 0 0; + -moz-border-radius: 0 4px 0 0; + border-radius: 0 4px 0 0; +} +.table-bordered thead:last-child tr:last-child th:first-child, .table-bordered tbody:last-child tr:last-child td:first-child { + -webkit-border-radius: 0 0 0 4px; + -moz-border-radius: 0 0 0 4px; + border-radius: 0 0 0 4px; +} +.table-bordered thead:last-child tr:last-child th:last-child, .table-bordered tbody:last-child tr:last-child td:last-child { + -webkit-border-radius: 0 0 4px 0; + -moz-border-radius: 0 0 4px 0; + border-radius: 0 0 4px 0; +} +.table-striped tbody tr:nth-child(odd) td, .table-striped tbody tr:nth-child(odd) th { + background-color: #f9f9f9; +} +.table tbody tr:hover td, .table tbody tr:hover th { + background-color: #f5f5f5; +} +table .span1 { + float: none; + width: 44px; + margin-left: 0; +} +table .span2 { + float: none; + width: 124px; + margin-left: 0; +} +table .span3 { + float: none; + width: 204px; + margin-left: 0; +} +table .span4 { + float: none; + width: 284px; + margin-left: 0; +} +table .span5 { + float: none; + width: 364px; + margin-left: 0; +} +table .span6 { + float: none; + width: 444px; + margin-left: 0; +} +table .span7 { + float: none; + width: 524px; + margin-left: 0; +} +table .span8 { + float: none; + width: 604px; + margin-left: 0; +} +table .span9 { + float: none; + width: 684px; + margin-left: 0; +} +table .span10 { + float: none; + width: 764px; + margin-left: 0; +} +table .span11 { + float: none; + width: 844px; + margin-left: 0; +} +table .span12 { + float: none; + width: 924px; + margin-left: 0; +} +[class^="icon-"], [class*=" icon-"] { + display: inline-block; + width: 14px; + height: 14px; + line-height: 14px; + vertical-align: text-top; + background-image: url("../img/glyphicons-halflings.png"); + background-position: 14px 14px; + background-repeat: no-repeat; + *margin-right: .3em; +} +[class^="icon-"]:last-child, [class*=" icon-"]:last-child { + *margin-left: 0; +} +.icon-white { + background-image: url("../img/glyphicons-halflings-white.png"); +} +.icon-glass { + background-position: 0 0; +} +.icon-music { + background-position: -24px 0; +} +.icon-search { + background-position: -48px 0; +} +.icon-envelope { + background-position: -72px 0; +} +.icon-heart { + background-position: -96px 0; +} +.icon-star { + background-position: -120px 0; +} +.icon-star-empty { + background-position: -144px 0; +} +.icon-user { + background-position: -168px 0; +} +.icon-film { + background-position: -192px 0; +} +.icon-th-large { + background-position: -216px 0; +} +.icon-th { + background-position: -240px 0; +} +.icon-th-list { + background-position: -264px 0; +} +.icon-ok { + background-position: -288px 0; +} +.icon-remove { + background-position: -312px 0; +} +.icon-zoom-in { + background-position: -336px 0; +} +.icon-zoom-out { + background-position: -360px 0; +} +.icon-off { + background-position: -384px 0; +} +.icon-signal { + background-position: -408px 0; +} +.icon-cog { + background-position: -432px 0; +} +.icon-trash { + background-position: -456px 0; +} +.icon-home { + background-position: 0 -24px; +} +.icon-file { + background-position: -24px -24px; +} +.icon-time { + background-position: -48px -24px; +} +.icon-road { + background-position: -72px -24px; +} +.icon-download-alt { + background-position: -96px -24px; +} +.icon-download { + background-position: -120px -24px; +} +.icon-upload { + background-position: -144px -24px; +} +.icon-inbox { + background-position: -168px -24px; +} +.icon-play-circle { + background-position: -192px -24px; +} +.icon-repeat { + background-position: -216px -24px; +} +.icon-refresh { + background-position: -240px -24px; +} +.icon-list-alt { + background-position: -264px -24px; +} +.icon-lock { + background-position: -287px -24px; +} +.icon-flag { + background-position: -312px -24px; +} +.icon-headphones { + background-position: -336px -24px; +} +.icon-volume-off { + background-position: -360px -24px; +} +.icon-volume-down { + background-position: -384px -24px; +} +.icon-volume-up { + background-position: -408px -24px; +} +.icon-qrcode { + background-position: -432px -24px; +} +.icon-barcode { + background-position: -456px -24px; +} +.icon-tag { + background-position: 0 -48px; +} +.icon-tags { + background-position: -25px -48px; +} +.icon-book { + background-position: -48px -48px; +} +.icon-bookmark { + background-position: -72px -48px; +} +.icon-print { + background-position: -96px -48px; +} +.icon-camera { + background-position: -120px -48px; +} +.icon-font { + background-position: -144px -48px; +} +.icon-bold { + background-position: -167px -48px; +} +.icon-italic { + background-position: -192px -48px; +} +.icon-text-height { + background-position: -216px -48px; +} +.icon-text-width { + background-position: -240px -48px; +} +.icon-align-left { + background-position: -264px -48px; +} +.icon-align-center { + background-position: -288px -48px; +} +.icon-align-right { + background-position: -312px -48px; +} +.icon-align-justify { + background-position: -336px -48px; +} +.icon-list { + background-position: -360px -48px; +} +.icon-indent-left { + background-position: -384px -48px; +} +.icon-indent-right { + background-position: -408px -48px; +} +.icon-facetime-video { + background-position: -432px -48px; +} +.icon-picture { + background-position: -456px -48px; +} +.icon-pencil { + background-position: 0 -72px; +} +.icon-map-marker { + background-position: -24px -72px; +} +.icon-adjust { + background-position: -48px -72px; +} +.icon-tint { + background-position: -72px -72px; +} +.icon-edit { + background-position: -96px -72px; +} +.icon-share { + background-position: -120px -72px; +} +.icon-check { + background-position: -144px -72px; +} +.icon-move { + background-position: -168px -72px; +} +.icon-step-backward { + background-position: -192px -72px; +} +.icon-fast-backward { + background-position: -216px -72px; +} +.icon-backward { + background-position: -240px -72px; +} +.icon-play { + background-position: -264px -72px; +} +.icon-pause { + background-position: -288px -72px; +} +.icon-stop { + background-position: -312px -72px; +} +.icon-forward { + background-position: -336px -72px; +} +.icon-fast-forward { + background-position: -360px -72px; +} +.icon-step-forward { + background-position: -384px -72px; +} +.icon-eject { + background-position: -408px -72px; +} +.icon-chevron-left { + background-position: -432px -72px; +} +.icon-chevron-right { + background-position: -456px -72px; +} +.icon-plus-sign { + background-position: 0 -96px; +} +.icon-minus-sign { + background-position: -24px -96px; +} +.icon-remove-sign { + background-position: -48px -96px; +} +.icon-ok-sign { + background-position: -72px -96px; +} +.icon-question-sign { + background-position: -96px -96px; +} +.icon-info-sign { + background-position: -120px -96px; +} +.icon-screenshot { + background-position: -144px -96px; +} +.icon-remove-circle { + background-position: -168px -96px; +} +.icon-ok-circle { + background-position: -192px -96px; +} +.icon-ban-circle { + background-position: -216px -96px; +} +.icon-arrow-left { + background-position: -240px -96px; +} +.icon-arrow-right { + background-position: -264px -96px; +} +.icon-arrow-up { + background-position: -289px -96px; +} +.icon-arrow-down { + background-position: -312px -96px; +} +.icon-share-alt { + background-position: -336px -96px; +} +.icon-resize-full { + background-position: -360px -96px; +} +.icon-resize-small { + background-position: -384px -96px; +} +.icon-plus { + background-position: -408px -96px; +} +.icon-minus { + background-position: -433px -96px; +} +.icon-asterisk { + background-position: -456px -96px; +} +.icon-exclamation-sign { + background-position: 0 -120px; +} +.icon-gift { + background-position: -24px -120px; +} +.icon-leaf { + background-position: -48px -120px; +} +.icon-fire { + background-position: -72px -120px; +} +.icon-eye-open { + background-position: -96px -120px; +} +.icon-eye-close { + background-position: -120px -120px; +} +.icon-warning-sign { + background-position: -144px -120px; +} +.icon-plane { + background-position: -168px -120px; +} +.icon-calendar { + background-position: -192px -120px; +} +.icon-random { + background-position: -216px -120px; +} +.icon-comment { + background-position: -240px -120px; +} +.icon-magnet { + background-position: -264px -120px; +} +.icon-chevron-up { + background-position: -288px -120px; +} +.icon-chevron-down { + background-position: -313px -119px; +} +.icon-retweet { + background-position: -336px -120px; +} +.icon-shopping-cart { + background-position: -360px -120px; +} +.icon-folder-close { + background-position: -384px -120px; +} +.icon-folder-open { + background-position: -408px -120px; +} +.icon-resize-vertical { + background-position: -432px -119px; +} +.icon-resize-horizontal { + background-position: -456px -118px; +} +.dropdown { + position: relative; +} +.dropdown-toggle { + *margin-bottom: -3px; +} +.dropdown-toggle:active, .open .dropdown-toggle { + outline: 0; +} +.caret { + display: inline-block; + width: 0; + height: 0; + text-indent: -99999px; + *text-indent: 0; + vertical-align: top; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 4px solid #000000; + opacity: 0.3; + filter: alpha(opacity=30); + content: "\2193"; +} +.dropdown .caret { + margin-top: 8px; + margin-left: 2px; +} +.dropdown:hover .caret, .open.dropdown .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + float: left; + display: none; + min-width: 160px; + _width: 160px; + padding: 4px 0; + margin: 0; + list-style: none; + background-color: #ffffff; + border-color: #ccc; + border-color: rgba(0, 0, 0, 0.2); + border-style: solid; + border-width: 1px; + -webkit-border-radius: 0 0 5px 5px; + -moz-border-radius: 0 0 5px 5px; + border-radius: 0 0 5px 5px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; + *border-right-width: 2px; + *border-bottom-width: 2px; +} +.dropdown-menu.bottom-up { + top: auto; + bottom: 100%; + margin-bottom: 2px; +} +.dropdown-menu .divider { + height: 1px; + margin: 5px 1px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #ffffff; + *width: 100%; + *margin: -5px 0 5px; +} +.dropdown-menu a { + display: block; + padding: 3px 15px; + clear: both; + font-weight: normal; + line-height: 18px; + color: #555555; + white-space: nowrap; +} +.dropdown-menu li > a:hover, .dropdown-menu .active > a, .dropdown-menu .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #0088cc; +} +.dropdown.open { + *z-index: 1000; +} +.dropdown.open .dropdown-toggle { + color: #ffffff; + background: #ccc; + background: rgba(0, 0, 0, 0.3); +} +.dropdown.open .dropdown-menu { + display: block; +} +.typeahead { + margin-top: 2px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #f5f5f5; + border: 1px solid #eee; + border: 1px solid rgba(0, 0, 0, 0.05); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 0, 0, 0.15); +} +.fade { + -webkit-transition: opacity 0.15s linear; + -moz-transition: opacity 0.15s linear; + -ms-transition: opacity 0.15s linear; + -o-transition: opacity 0.15s linear; + transition: opacity 0.15s linear; + opacity: 0; +} +.fade.in { + opacity: 1; +} +.collapse { + -webkit-transition: height 0.35s ease; + -moz-transition: height 0.35s ease; + -ms-transition: height 0.35s ease; + -o-transition: height 0.35s ease; + transition: height 0.35s ease; + position: relative; + overflow: hidden; + height: 0; +} +.collapse.in { + height: auto; +} +.close { + float: right; + font-size: 20px; + font-weight: bold; + line-height: 18px; + color: #000000; + text-shadow: 0 1px 0 #ffffff; + opacity: 0.2; + filter: alpha(opacity=20); +} +.close:hover { + color: #000000; + text-decoration: none; + opacity: 0.4; + filter: alpha(opacity=40); + cursor: pointer; +} +.btn { + display: inline-block; + padding: 4px 10px 4px; + margin-bottom: 0; + font-size: 13px; + line-height: 18px; + color: #333333; + text-align: center; + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); + vertical-align: middle; + background-color: #f5f5f5; + background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); + background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); + background-image: linear-gradient(top, #ffffff, #e6e6e6); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0); + border-color: #e6e6e6 #e6e6e6 #bfbfbf; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + border: 1px solid #ccc; + border-bottom-color: #bbb; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + cursor: pointer; + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + *margin-left: .3em; +} +.btn:hover, +.btn:active, +.btn.active, +.btn.disabled, +.btn[disabled] { + background-color: #e6e6e6; +} +.btn:active, .btn.active { + background-color: #cccccc \9; +} +.btn:first-child { + *margin-left: 0; +} +.btn:hover { + color: #333333; + text-decoration: none; + background-color: #e6e6e6; + background-position: 0 -15px; + -webkit-transition: background-position 0.1s linear; + -moz-transition: background-position 0.1s linear; + -ms-transition: background-position 0.1s linear; + -o-transition: background-position 0.1s linear; + transition: background-position 0.1s linear; +} +.btn:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.btn.active, .btn:active { + background-image: none; + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + background-color: #e6e6e6; + background-color: #d9d9d9 \9; + outline: 0; +} +.btn.disabled, .btn[disabled] { + cursor: default; + background-image: none; + background-color: #e6e6e6; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +.btn-large { + padding: 9px 14px; + font-size: 15px; + line-height: normal; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.btn-large [class^="icon-"] { + margin-top: 1px; +} +.btn-small { + padding: 5px 9px; + font-size: 11px; + line-height: 16px; +} +.btn-small [class^="icon-"] { + margin-top: -1px; +} +.btn-mini { + padding: 2px 6px; + font-size: 11px; + line-height: 14px; +} +.btn-primary, +.btn-primary:hover, +.btn-warning, +.btn-warning:hover, +.btn-danger, +.btn-danger:hover, +.btn-success, +.btn-success:hover, +.btn-info, +.btn-info:hover, +.btn-inverse, +.btn-inverse:hover { + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + color: #ffffff; +} +.btn-primary.active, +.btn-warning.active, +.btn-danger.active, +.btn-success.active, +.btn-info.active, +.btn-dark.active { + color: rgba(255, 255, 255, 0.75); +} +.btn-primary { + background-color: #006dcc; + background-image: -moz-linear-gradient(top, #0088cc, #0044cc); + background-image: -ms-linear-gradient(top, #0088cc, #0044cc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); + background-image: -o-linear-gradient(top, #0088cc, #0044cc); + background-image: linear-gradient(top, #0088cc, #0044cc); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); + border-color: #0044cc #0044cc #002a80; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-primary:hover, +.btn-primary:active, +.btn-primary.active, +.btn-primary.disabled, +.btn-primary[disabled] { + background-color: #0044cc; +} +.btn-primary:active, .btn-primary.active { + background-color: #003399 \9; +} +.btn-warning { + background-color: #faa732; + background-image: -moz-linear-gradient(top, #fbb450, #f89406); + background-image: -ms-linear-gradient(top, #fbb450, #f89406); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); + background-image: -webkit-linear-gradient(top, #fbb450, #f89406); + background-image: -o-linear-gradient(top, #fbb450, #f89406); + background-image: linear-gradient(top, #fbb450, #f89406); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0); + border-color: #f89406 #f89406 #ad6704; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-warning:hover, +.btn-warning:active, +.btn-warning.active, +.btn-warning.disabled, +.btn-warning[disabled] { + background-color: #f89406; +} +.btn-warning:active, .btn-warning.active { + background-color: #c67605 \9; +} +.btn-danger { + background-color: #da4f49; + background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -ms-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -o-linear-gradient(top, #ee5f5b, #bd362f); + background-image: linear-gradient(top, #ee5f5b, #bd362f); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0); + border-color: #bd362f #bd362f #802420; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-danger:hover, +.btn-danger:active, +.btn-danger.active, +.btn-danger.disabled, +.btn-danger[disabled] { + background-color: #bd362f; +} +.btn-danger:active, .btn-danger.active { + background-color: #942a25 \9; +} +.btn-success { + background-color: #5bb75b; + background-image: -moz-linear-gradient(top, #62c462, #51a351); + background-image: -ms-linear-gradient(top, #62c462, #51a351); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351)); + background-image: -webkit-linear-gradient(top, #62c462, #51a351); + background-image: -o-linear-gradient(top, #62c462, #51a351); + background-image: linear-gradient(top, #62c462, #51a351); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0); + border-color: #51a351 #51a351 #387038; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-success:hover, +.btn-success:active, +.btn-success.active, +.btn-success.disabled, +.btn-success[disabled] { + background-color: #51a351; +} +.btn-success:active, .btn-success.active { + background-color: #408140 \9; +} +.btn-info { + background-color: #49afcd; + background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -ms-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4)); + background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -o-linear-gradient(top, #5bc0de, #2f96b4); + background-image: linear-gradient(top, #5bc0de, #2f96b4); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0); + border-color: #2f96b4 #2f96b4 #1f6377; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-info:hover, +.btn-info:active, +.btn-info.active, +.btn-info.disabled, +.btn-info[disabled] { + background-color: #2f96b4; +} +.btn-info:active, .btn-info.active { + background-color: #24748c \9; +} +.btn-inverse { + background-color: #393939; + background-image: -moz-linear-gradient(top, #454545, #262626); + background-image: -ms-linear-gradient(top, #454545, #262626); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#454545), to(#262626)); + background-image: -webkit-linear-gradient(top, #454545, #262626); + background-image: -o-linear-gradient(top, #454545, #262626); + background-image: linear-gradient(top, #454545, #262626); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#454545', endColorstr='#262626', GradientType=0); + border-color: #262626 #262626 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-inverse:hover, +.btn-inverse:active, +.btn-inverse.active, +.btn-inverse.disabled, +.btn-inverse[disabled] { + background-color: #262626; +} +.btn-inverse:active, .btn-inverse.active { + background-color: #0c0c0c \9; +} +button.btn, input[type="submit"].btn { + *padding-top: 2px; + *padding-bottom: 2px; +} +button.btn::-moz-focus-inner, input[type="submit"].btn::-moz-focus-inner { + padding: 0; + border: 0; +} +button.btn.large, input[type="submit"].btn.large { + *padding-top: 7px; + *padding-bottom: 7px; +} +button.btn.small, input[type="submit"].btn.small { + *padding-top: 3px; + *padding-bottom: 3px; +} +.btn-group { + position: relative; + *zoom: 1; + *margin-left: .3em; +} +.btn-group:before, .btn-group:after { + display: table; + content: ""; +} +.btn-group:after { + clear: both; +} +.btn-group:first-child { + *margin-left: 0; +} +.btn-group + .btn-group { + margin-left: 5px; +} +.btn-toolbar { + margin-top: 9px; + margin-bottom: 9px; +} +.btn-toolbar .btn-group { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; +} +.btn-group .btn { + position: relative; + float: left; + margin-left: -1px; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.btn-group .btn:first-child { + margin-left: 0; + -webkit-border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; + border-top-left-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + border-bottom-left-radius: 4px; +} +.btn-group .btn:last-child, .btn-group .dropdown-toggle { + -webkit-border-top-right-radius: 4px; + -moz-border-radius-topright: 4px; + border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -moz-border-radius-bottomright: 4px; + border-bottom-right-radius: 4px; +} +.btn-group .btn.large:first-child { + margin-left: 0; + -webkit-border-top-left-radius: 6px; + -moz-border-radius-topleft: 6px; + border-top-left-radius: 6px; + -webkit-border-bottom-left-radius: 6px; + -moz-border-radius-bottomleft: 6px; + border-bottom-left-radius: 6px; +} +.btn-group .btn.large:last-child, .btn-group .large.dropdown-toggle { + -webkit-border-top-right-radius: 6px; + -moz-border-radius-topright: 6px; + border-top-right-radius: 6px; + -webkit-border-bottom-right-radius: 6px; + -moz-border-radius-bottomright: 6px; + border-bottom-right-radius: 6px; +} +.btn-group .btn:hover, +.btn-group .btn:focus, +.btn-group .btn:active, +.btn-group .btn.active { + z-index: 2; +} +.btn-group .dropdown-toggle:active, .btn-group.open .dropdown-toggle { + outline: 0; +} +.btn-group .dropdown-toggle { + padding-left: 8px; + padding-right: 8px; + -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + *padding-top: 5px; + *padding-bottom: 5px; +} +.btn-group.open { + *z-index: 1000; +} +.btn-group.open .dropdown-menu { + display: block; + margin-top: 1px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.btn-group.open .dropdown-toggle { + background-image: none; + -webkit-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); +} +.btn .caret { + margin-top: 7px; + margin-left: 0; +} +.btn:hover .caret, .open.btn-group .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.btn-primary .caret, +.btn-danger .caret, +.btn-info .caret, +.btn-success .caret, +.btn-inverse .caret { + border-top-color: #ffffff; + opacity: 0.75; + filter: alpha(opacity=75); +} +.btn-small .caret { + margin-top: 4px; +} +.alert { + padding: 8px 35px 8px 14px; + margin-bottom: 18px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + background-color: #fcf8e3; + border: 1px solid #fbeed5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.alert, .alert-heading { + color: #c09853; +} +.alert .close { + position: relative; + top: -2px; + right: -21px; + line-height: 18px; +} +.alert-success { + background-color: #dff0d8; + border-color: #d6e9c6; +} +.alert-success, .alert-success .alert-heading { + color: #468847; +} +.alert-danger, .alert-error { + background-color: #f2dede; + border-color: #eed3d7; +} +.alert-danger, +.alert-error, +.alert-danger .alert-heading, +.alert-error .alert-heading { + color: #b94a48; +} +.alert-info { + background-color: #d9edf7; + border-color: #bce8f1; +} +.alert-info, .alert-info .alert-heading { + color: #3a87ad; +} +.alert-block { + padding-top: 14px; + padding-bottom: 14px; +} +.alert-block > p, .alert-block > ul { + margin-bottom: 0; +} +.alert-block p + p { + margin-top: 5px; +} +.nav { + margin-left: 0; + margin-bottom: 18px; + list-style: none; +} +.nav > li > a { + display: block; +} +.nav > li > a:hover { + text-decoration: none; + background-color: #eeeeee; +} +.nav .nav-header { + display: block; + padding: 3px 15px; + font-size: 11px; + font-weight: bold; + line-height: 18px; + color: #999999; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + text-transform: uppercase; +} +.nav li + .nav-header { + margin-top: 9px; +} +.nav-list { + padding-left: 14px; + padding-right: 14px; + margin-bottom: 0; +} +.nav-list > li > a, .nav-list .nav-header { + margin-left: -15px; + margin-right: -15px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); +} +.nav-list > li > a { + padding: 3px 15px; +} +.nav-list .active > a, .nav-list .active > a:hover { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); + background-color: #0088cc; +} +.nav-list [class^="icon-"] { + margin-right: 2px; +} +.nav-tabs, .nav-pills { + *zoom: 1; +} +.nav-tabs:before, +.nav-pills:before, +.nav-tabs:after, +.nav-pills:after { + display: table; + content: ""; +} +.nav-tabs:after, .nav-pills:after { + clear: both; +} +.nav-tabs > li, .nav-pills > li { + float: left; +} +.nav-tabs > li > a, .nav-pills > li > a { + padding-right: 12px; + padding-left: 12px; + margin-right: 2px; + line-height: 14px; +} +.nav-tabs { + border-bottom: 1px solid #ddd; +} +.nav-tabs > li { + margin-bottom: -1px; +} +.nav-tabs > li > a { + padding-top: 9px; + padding-bottom: 9px; + border: 1px solid transparent; + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} +.nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #dddddd; +} +.nav-tabs > .active > a, .nav-tabs > .active > a:hover { + color: #555555; + background-color: #ffffff; + border: 1px solid #ddd; + border-bottom-color: transparent; + cursor: default; +} +.nav-pills > li > a { + padding-top: 8px; + padding-bottom: 8px; + margin-top: 2px; + margin-bottom: 2px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.nav-pills .active > a, .nav-pills .active > a:hover { + color: #ffffff; + background-color: #0088cc; +} +.nav-stacked > li { + float: none; +} +.nav-stacked > li > a { + margin-right: 0; +} +.nav-tabs.nav-stacked { + border-bottom: 0; +} +.nav-tabs.nav-stacked > li > a { + border: 1px solid #ddd; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.nav-tabs.nav-stacked > li:first-child > a { + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} +.nav-tabs.nav-stacked > li:last-child > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} +.nav-tabs.nav-stacked > li > a:hover { + border-color: #ddd; + z-index: 2; +} +.nav-pills.nav-stacked > li > a { + margin-bottom: 3px; +} +.nav-pills.nav-stacked > li:last-child > a { + margin-bottom: 1px; +} +.nav-tabs .dropdown-menu, .nav-pills .dropdown-menu { + margin-top: 1px; + border-width: 1px; +} +.nav-pills .dropdown-menu { + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.nav-tabs .dropdown-toggle .caret, .nav-pills .dropdown-toggle .caret { + border-top-color: #0088cc; + margin-top: 6px; +} +.nav-tabs .dropdown-toggle:hover .caret, .nav-pills .dropdown-toggle:hover .caret { + border-top-color: #005580; +} +.nav-tabs .active .dropdown-toggle .caret, .nav-pills .active .dropdown-toggle .caret { + border-top-color: #333333; +} +.nav > .dropdown.active > a:hover { + color: #000000; + cursor: pointer; +} +.nav-tabs .open .dropdown-toggle, .nav-pills .open .dropdown-toggle, .nav > .open.active > a:hover { + color: #ffffff; + background-color: #999999; + border-color: #999999; +} +.nav .open .caret, .nav .open.active .caret, .nav .open a:hover .caret { + border-top-color: #ffffff; + opacity: 1; + filter: alpha(opacity=100); +} +.tabs-stacked .open > a:hover { + border-color: #999999; +} +.tabbable { + *zoom: 1; +} +.tabbable:before, .tabbable:after { + display: table; + content: ""; +} +.tabbable:after { + clear: both; +} +.tab-content { + overflow: hidden; +} +.tabs-below .nav-tabs, .tabs-right .nav-tabs, .tabs-left .nav-tabs { + border-bottom: 0; +} +.tab-content > .tab-pane, .pill-content > .pill-pane { + display: none; +} +.tab-content > .active, .pill-content > .active { + display: block; +} +.tabs-below .nav-tabs { + border-top: 1px solid #ddd; +} +.tabs-below .nav-tabs > li { + margin-top: -1px; + margin-bottom: 0; +} +.tabs-below .nav-tabs > li > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} +.tabs-below .nav-tabs > li > a:hover { + border-bottom-color: transparent; + border-top-color: #ddd; +} +.tabs-below .nav-tabs .active > a, .tabs-below .nav-tabs .active > a:hover { + border-color: transparent #ddd #ddd #ddd; +} +.tabs-left .nav-tabs > li, .tabs-right .nav-tabs > li { + float: none; +} +.tabs-left .nav-tabs > li > a, .tabs-right .nav-tabs > li > a { + min-width: 74px; + margin-right: 0; + margin-bottom: 3px; +} +.tabs-left .nav-tabs { + float: left; + margin-right: 19px; + border-right: 1px solid #ddd; +} +.tabs-left .nav-tabs > li > a { + margin-right: -1px; + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} +.tabs-left .nav-tabs > li > a:hover { + border-color: #eeeeee #dddddd #eeeeee #eeeeee; +} +.tabs-left .nav-tabs .active > a, .tabs-left .nav-tabs .active > a:hover { + border-color: #ddd transparent #ddd #ddd; + *border-right-color: #ffffff; +} +.tabs-right .nav-tabs { + float: right; + margin-left: 19px; + border-left: 1px solid #ddd; +} +.tabs-right .nav-tabs > li > a { + margin-left: -1px; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} +.tabs-right .nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #eeeeee #dddddd; +} +.tabs-right .nav-tabs .active > a, .tabs-right .nav-tabs .active > a:hover { + border-color: #ddd #ddd #ddd transparent; + *border-left-color: #ffffff; +} +.navbar { + overflow: visible; + margin-bottom: 18px; +} +.navbar-inner { + padding-left: 20px; + padding-right: 20px; + background-color: #2c2c2c; + background-image: -moz-linear-gradient(top, #333333, #222222); + background-image: -ms-linear-gradient(top, #333333, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); + background-image: -webkit-linear-gradient(top, #333333, #222222); + background-image: -o-linear-gradient(top, #333333, #222222); + background-image: linear-gradient(top, #333333, #222222); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); +} +.btn-navbar { + display: none; + float: right; + padding: 7px 10px; + margin-left: 5px; + margin-right: 5px; + background-color: #2c2c2c; + background-image: -moz-linear-gradient(top, #333333, #222222); + background-image: -ms-linear-gradient(top, #333333, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); + background-image: -webkit-linear-gradient(top, #333333, #222222); + background-image: -o-linear-gradient(top, #333333, #222222); + background-image: linear-gradient(top, #333333, #222222); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); + border-color: #222222 #222222 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); +} +.btn-navbar:hover, +.btn-navbar:active, +.btn-navbar.active, +.btn-navbar.disabled, +.btn-navbar[disabled] { + background-color: #222222; +} +.btn-navbar:active, .btn-navbar.active { + background-color: #080808 \9; +} +.btn-navbar .icon-bar { + display: block; + width: 18px; + height: 2px; + background-color: #f5f5f5; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; + -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); +} +.btn-navbar .icon-bar + .icon-bar { + margin-top: 3px; +} +.nav-collapse.collapse { + height: auto; +} +.navbar .brand:hover { + text-decoration: none; +} +.navbar .brand { + float: left; + display: block; + padding: 8px 20px 12px; + margin-left: -20px; + font-size: 20px; + font-weight: 200; + line-height: 1; + color: #ffffff; +} +.navbar .navbar-text { + margin-bottom: 0; + line-height: 40px; + color: #999999; +} +.navbar .navbar-text a:hover { + color: #ffffff; + background-color: transparent; +} +.navbar .btn, .navbar .btn-group { + margin-top: 5px; +} +.navbar .btn-group .btn { + margin-top: 0; +} +.navbar-form { + margin-bottom: 0; + *zoom: 1; +} +.navbar-form:before, .navbar-form:after { + display: table; + content: ""; +} +.navbar-form:after { + clear: both; +} +.navbar-form input, .navbar-form select { + display: inline-block; + margin-top: 5px; + margin-bottom: 0; +} +.navbar-form .radio, .navbar-form .checkbox { + margin-top: 5px; +} +.navbar-form input[type="image"], .navbar-form input[type="checkbox"], .navbar-form input[type="radio"] { + margin-top: 3px; +} +.navbar-form .input-append, .navbar-form .input-prepend { + margin-top: 6px; + white-space: nowrap; +} +.navbar-form .input-append input, .navbar-form .input-prepend input { + margin-top: 0; +} +.navbar-search { + position: relative; + float: left; + margin-top: 6px; + margin-bottom: 0; +} +.navbar-search .search-query { + padding: 4px 9px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + font-weight: normal; + line-height: 1; + color: #ffffff; + color: rgba(255, 255, 255, 0.75); + background: #666; + background: rgba(255, 255, 255, 0.3); + border: 1px solid #111; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + -webkit-transition: none; + -moz-transition: none; + -ms-transition: none; + -o-transition: none; + transition: none; +} +.navbar-search .search-query :-moz-placeholder { + color: #eeeeee; +} +.navbar-search .search-query::-webkit-input-placeholder { + color: #eeeeee; +} +.navbar-search .search-query:hover { + color: #ffffff; + background-color: #999999; + background-color: rgba(255, 255, 255, 0.5); +} +.navbar-search .search-query:focus, .navbar-search .search-query.focused { + padding: 5px 10px; + color: #333333; + text-shadow: 0 1px 0 #ffffff; + background-color: #ffffff; + border: 0; + -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + outline: 0; +} +.navbar-fixed-top { + position: fixed; + top: 0; + right: 0; + left: 0; + z-index: 1030; +} +.navbar-fixed-top .navbar-inner { + padding-left: 0; + padding-right: 0; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.navbar .nav { + position: relative; + left: 0; + display: block; + float: left; + margin: 0 10px 0 0; +} +.navbar .nav.pull-right { + float: right; +} +.navbar .nav > li { + display: block; + float: left; +} +.navbar .nav > li > a { + float: none; + padding: 10px 10px 11px; + line-height: 19px; + color: #999999; + text-decoration: none; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.navbar .nav > li > a:hover { + background-color: transparent; + color: #ffffff; + text-decoration: none; +} +.navbar .nav .active > a, .navbar .nav .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #222222; +} +.navbar .divider-vertical { + height: 40px; + width: 1px; + margin: 0 9px; + overflow: hidden; + background-color: #222222; + border-right: 1px solid #333333; +} +.navbar .nav.pull-right { + margin-left: 10px; + margin-right: 0; +} +.navbar .dropdown-menu { + margin-top: 1px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.navbar .dropdown-menu:before { + content: ''; + display: inline-block; + border-left: 7px solid transparent; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-bottom-color: rgba(0, 0, 0, 0.2); + position: absolute; + top: -7px; + left: 9px; +} +.navbar .dropdown-menu:after { + content: ''; + display: inline-block; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid #ffffff; + position: absolute; + top: -6px; + left: 10px; +} +.navbar .nav .dropdown-toggle .caret, .navbar .nav .open.dropdown .caret { + border-top-color: #ffffff; +} +.navbar .nav .active .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.navbar .nav .open > .dropdown-toggle, .navbar .nav .active > .dropdown-toggle, .navbar .nav .open.active > .dropdown-toggle { + background-color: transparent; +} +.navbar .nav .active > .dropdown-toggle:hover { + color: #ffffff; +} +.navbar .nav.pull-right .dropdown-menu { + left: auto; + right: 0; +} +.navbar .nav.pull-right .dropdown-menu:before { + left: auto; + right: 12px; +} +.navbar .nav.pull-right .dropdown-menu:after { + left: auto; + right: 13px; +} +.breadcrumb { + padding: 7px 14px; + margin: 0 0 18px; + background-color: #fbfbfb; + background-image: -moz-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -ms-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5)); + background-image: -webkit-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -o-linear-gradient(top, #ffffff, #f5f5f5); + background-image: linear-gradient(top, #ffffff, #f5f5f5); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0); + border: 1px solid #ddd; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; +} +.breadcrumb li { + display: inline-block; + text-shadow: 0 1px 0 #ffffff; +} +.breadcrumb .divider { + padding: 0 5px; + color: #999999; +} +.breadcrumb .active a { + color: #333333; +} +.pagination { + height: 36px; + margin: 18px 0; +} +.pagination ul { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; + margin-left: 0; + margin-bottom: 0; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); +} +.pagination li { + display: inline; +} +.pagination a { + float: left; + padding: 0 14px; + line-height: 34px; + text-decoration: none; + border: 1px solid #ddd; + border-left-width: 0; +} +.pagination a:hover, .pagination .active a { + background-color: #f5f5f5; +} +.pagination .active a { + color: #999999; + cursor: default; +} +.pagination .disabled a, .pagination .disabled a:hover { + color: #999999; + background-color: transparent; + cursor: default; +} +.pagination li:first-child a { + border-left-width: 1px; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.pagination li:last-child a { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.pagination-centered { + text-align: center; +} +.pagination-right { + text-align: right; +} +.pager { + margin-left: 0; + margin-bottom: 18px; + list-style: none; + text-align: center; + *zoom: 1; +} +.pager:before, .pager:after { + display: table; + content: ""; +} +.pager:after { + clear: both; +} +.pager li { + display: inline; +} +.pager a { + display: inline-block; + padding: 5px 14px; + background-color: #fff; + border: 1px solid #ddd; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} +.pager a:hover { + text-decoration: none; + background-color: #f5f5f5; +} +.pager .next a { + float: right; +} +.pager .previous a { + float: left; +} +.modal-open .dropdown-menu { + z-index: 2050; +} +.modal-open .dropdown.open { + *z-index: 2050; +} +.modal-open .popover { + z-index: 2060; +} +.modal-open .tooltip { + z-index: 2070; +} +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + background-color: #000000; +} +.modal-backdrop.fade { + opacity: 0; +} +.modal-backdrop, .modal-backdrop.fade.in { + opacity: 0.8; + filter: alpha(opacity=80); +} +.modal { + position: fixed; + top: 50%; + left: 50%; + z-index: 1050; + max-height: 500px; + overflow: auto; + width: 560px; + margin: -250px 0 0 -280px; + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + /* IE6-7 */ + + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.wide-modal { + position: fixed; + top: 5%; + left: 5%; + z-index: 1050; + max-height: 90%; + overflow: auto; + width: 90%; + /*margin: -50px 0 0 -80px;*/ + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + /* IE6-7 */ + + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.modal.fade { + -webkit-transition: opacity .3s linear, top .3s ease-out; + -moz-transition: opacity .3s linear, top .3s ease-out; + -ms-transition: opacity .3s linear, top .3s ease-out; + -o-transition: opacity .3s linear, top .3s ease-out; + transition: opacity .3s linear, top .3s ease-out; + top: -25%; +} +.modal.fade.in { + top: 50%; +} +.modal-header { + padding: 9px 15px; + border-bottom: 1px solid #eee; +} +.modal-header .close { + margin-top: 2px; +} +.modal-body { + padding: 15px; +} +.modal-body .modal-form { + margin-bottom: 0; +} +.modal-footer { + padding: 14px 15px 15px; + margin-bottom: 0; + background-color: #f5f5f5; + border-top: 1px solid #ddd; + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; + *zoom: 1; +} +.modal-footer:before, .modal-footer:after { + display: table; + content: ""; +} +.modal-footer:after { + clear: both; +} +.modal-footer .btn { + float: right; + margin-left: 5px; + margin-bottom: 0; +} +.tooltip { + position: absolute; + z-index: 1020; + display: block; + visibility: visible; + padding: 5px; + font-size: 11px; + opacity: 0; + filter: alpha(opacity=0); +} +.tooltip.in { + opacity: 0.8; + filter: alpha(opacity=80); +} +.tooltip.top { + margin-top: -2px; +} +.tooltip.right { + margin-left: 2px; +} +.tooltip.bottom { + margin-top: 2px; +} +.tooltip.left { + margin-left: -2px; +} +.tooltip.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid #000000; +} +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #000000; +} +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-bottom: 5px solid #000000; +} +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-right: 5px solid #000000; +} +.tooltip-inner { + max-width: 200px; + padding: 3px 8px; + color: #ffffff; + text-align: center; + text-decoration: none; + background-color: #000000; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; +} +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1010; + display: none; + padding: 5px; +} +.popover.top { + margin-top: -5px; +} +.popover.right { + margin-left: 5px; +} +.popover.bottom { + margin-top: 5px; +} +.popover.left { + margin-left: -5px; +} +.popover.top .arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid #000000; +} +.popover.right .arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-right: 5px solid #000000; +} +.popover.bottom .arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-bottom: 5px solid #000000; +} +.popover.left .arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #000000; +} +.popover .arrow { + position: absolute; + width: 0; + height: 0; +} +.popover-inner { + padding: 3px; + width: 280px; + overflow: hidden; + background: #000000; + background: rgba(0, 0, 0, 0.8); + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); +} +.popover-title { + padding: 9px 15px; + line-height: 1; + background-color: #f5f5f5; + border-bottom: 1px solid #eee; + -webkit-border-radius: 3px 3px 0 0; + -moz-border-radius: 3px 3px 0 0; + border-radius: 3px 3px 0 0; +} +.popover-content { + padding: 14px; + background-color: #ffffff; + -webkit-border-radius: 0 0 3px 3px; + -moz-border-radius: 0 0 3px 3px; + border-radius: 0 0 3px 3px; + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.popover-content p, .popover-content ul, .popover-content ol { + margin-bottom: 0; +} +.thumbnails { + margin-left: -20px; + list-style: none; + *zoom: 1; +} +.thumbnails:before, .thumbnails:after { + display: table; + content: ""; +} +.thumbnails:after { + clear: both; +} +.thumbnails > li { + float: left; + margin: 0 0 18px 20px; +} +.thumbnail { + display: block; + padding: 4px; + line-height: 1; + border: 1px solid #ddd; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); +} +a.thumbnail:hover { + border-color: #0088cc; + -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); +} +.thumbnail > img { + display: block; + max-width: 100%; + margin-left: auto; + margin-right: auto; +} +.thumbnail .caption { + padding: 9px; +} +.label { + padding: 2px 4px 3px; + font-size: 11.049999999999999px; + font-weight: bold; + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #999999; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.label:hover { + color: #ffffff; + text-decoration: none; +} +.label-important { + background-color: #b94a48; +} +.label-important:hover { + background-color: #953b39; +} +.label-warning { + background-color: #f89406; +} +.label-warning:hover { + background-color: #c67605; +} +.label-success { + background-color: #468847; +} +.label-success:hover { + background-color: #356635; +} +.label-info { + background-color: #3a87ad; +} +.label-info:hover { + background-color: #2d6987; +} +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +@-moz-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +@keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +.progress { + overflow: hidden; + height: 18px; + margin-bottom: 18px; + background-color: #f7f7f7; + background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -ms-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9)); + background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: linear-gradient(top, #f5f5f5, #f9f9f9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0); + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.progress .bar { + width: 0%; + height: 18px; + color: #ffffff; + font-size: 12px; + text-align: center; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #0e90d2; + background-image: -moz-linear-gradient(top, #149bdf, #0480be); + background-image: -ms-linear-gradient(top, #149bdf, #0480be); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be)); + background-image: -webkit-linear-gradient(top, #149bdf, #0480be); + background-image: -o-linear-gradient(top, #149bdf, #0480be); + background-image: linear-gradient(top, #149bdf, #0480be); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0); + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition: width 0.6s ease; + -moz-transition: width 0.6s ease; + -ms-transition: width 0.6s ease; + -o-transition: width 0.6s ease; + transition: width 0.6s ease; +} +.progress-striped .bar { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + -webkit-background-size: 40px 40px; + -moz-background-size: 40px 40px; + -o-background-size: 40px 40px; + background-size: 40px 40px; +} +.progress.active .bar { + -webkit-animation: progress-bar-stripes 2s linear infinite; + -moz-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} +.progress-danger .bar { + background-color: #dd514c; + background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -o-linear-gradient(top, #ee5f5b, #c43c35); + background-image: linear-gradient(top, #ee5f5b, #c43c35); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0); +} +.progress-danger.progress-striped .bar { + background-color: #ee5f5b; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-success .bar { + background-color: #5eb95e; + background-image: -moz-linear-gradient(top, #62c462, #57a957); + background-image: -ms-linear-gradient(top, #62c462, #57a957); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957)); + background-image: -webkit-linear-gradient(top, #62c462, #57a957); + background-image: -o-linear-gradient(top, #62c462, #57a957); + background-image: linear-gradient(top, #62c462, #57a957); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0); +} +.progress-success.progress-striped .bar { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-info .bar { + background-color: #4bb1cf; + background-image: -moz-linear-gradient(top, #5bc0de, #339bb9); + background-image: -ms-linear-gradient(top, #5bc0de, #339bb9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9)); + background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9); + background-image: -o-linear-gradient(top, #5bc0de, #339bb9); + background-image: linear-gradient(top, #5bc0de, #339bb9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0); +} +.progress-info.progress-striped .bar { + background-color: #5bc0de; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.accordion { + margin-bottom: 18px; +} +.accordion-group { + margin-bottom: 2px; + border: 1px solid #e5e5e5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.accordion-heading { + border-bottom: 0; +} +.accordion-heading .accordion-toggle { + display: block; + padding: 8px 15px; +} +.accordion-inner { + padding: 9px 15px; + border-top: 1px solid #e5e5e5; +} +.carousel { + position: relative; + margin-bottom: 18px; + line-height: 1; +} +.carousel-inner { + overflow: hidden; + width: 100%; + position: relative; +} +.carousel .item { + display: none; + position: relative; + -webkit-transition: 0.6s ease-in-out left; + -moz-transition: 0.6s ease-in-out left; + -ms-transition: 0.6s ease-in-out left; + -o-transition: 0.6s ease-in-out left; + transition: 0.6s ease-in-out left; +} +.carousel .item > img { + display: block; + line-height: 1; +} +.carousel .active, .carousel .next, .carousel .prev { + display: block; +} +.carousel .active { + left: 0; +} +.carousel .next, .carousel .prev { + position: absolute; + top: 0; + width: 100%; +} +.carousel .next { + left: 100%; +} +.carousel .prev { + left: -100%; +} +.carousel .next.left, .carousel .prev.right { + left: 0; +} +.carousel .active.left { + left: -100%; +} +.carousel .active.right { + left: 100%; +} +.carousel-control { + position: absolute; + top: 40%; + left: 15px; + width: 40px; + height: 40px; + margin-top: -20px; + font-size: 60px; + font-weight: 100; + line-height: 30px; + color: #ffffff; + text-align: center; + background: #222222; + border: 3px solid #ffffff; + -webkit-border-radius: 23px; + -moz-border-radius: 23px; + border-radius: 23px; + opacity: 0.5; + filter: alpha(opacity=50); +} +.carousel-control.right { + left: auto; + right: 15px; +} +.carousel-control:hover { + color: #ffffff; + text-decoration: none; + opacity: 0.9; + filter: alpha(opacity=90); +} +.carousel-caption { + position: absolute; + left: 0; + right: 0; + bottom: 0; + padding: 10px 15px 5px; + background: #333333; + background: rgba(0, 0, 0, 0.75); +} +.carousel-caption h4, .carousel-caption p { + color: #ffffff; +} +.hero-unit { + padding: 60px; + margin-bottom: 30px; + background-color: #f5f5f5; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} +.hero-unit h1 { + margin-bottom: 0; + font-size: 60px; + line-height: 1; + letter-spacing: -1px; +} +.hero-unit p { + font-size: 18px; + font-weight: 200; + line-height: 27px; +} +.pull-right { + float: right; +} +.pull-left { + float: left; +} +.hide { + display: none; +} +.show { + display: block; +} +.invisible { + visibility: hidden; +} diff --git a/src/nl/astraeus/jdbc/web/resources/images/loading.gif b/src/nl/astraeus/jdbc/web/resources/images/loading.gif new file mode 100644 index 0000000..21c7e74 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/images/loading.gif Binary files differ diff --git a/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png b/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png new file mode 100644 index 0000000..92d4445 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png Binary files differ diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-alert.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-alert.js new file mode 100644 index 0000000..2242ddd --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-alert.js @@ -0,0 +1,94 @@ +/* ========================================================== + * bootstrap-alert.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#alerts + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function( $ ){ + + "use strict" + + /* ALERT CLASS DEFINITION + * ====================== */ + + var dismiss = '[data-dismiss="alert"]' + , Alert = function ( el ) { + $(el).on('click', dismiss, this.close) + } + + Alert.prototype = { + + constructor: Alert + + , close: function ( e ) { + var $this = $(this) + , selector = $this.attr('data-target') + , $parent + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = $(selector) + $parent.trigger('close') + + e && e.preventDefault() + + $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent()) + + $parent + .trigger('close') + .removeClass('in') + + function removeElement() { + $parent + .trigger('closed') + .remove() + } + + $.support.transition && $parent.hasClass('fade') ? + $parent.on($.support.transition.end, removeElement) : + removeElement() + } + + } + + + /* ALERT PLUGIN DEFINITION + * ======================= */ + + $.fn.alert = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('alert') + if (!data) $this.data('alert', (data = new Alert(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.alert.Constructor = Alert + + + /* ALERT DATA-API + * ============== */ + + $(function () { + $('body').on('click.alert.data-api', dismiss, Alert.prototype.close) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-button.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-button.js new file mode 100644 index 0000000..0238ca3 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-button.js @@ -0,0 +1,100 @@ +/* ============================================================ + * bootstrap-button.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#buttons + * ============================================================ + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + +!function( $ ){ + + "use strict" + + /* BUTTON PUBLIC CLASS DEFINITION + * ============================== */ + + var Button = function ( element, options ) { + this.$element = $(element) + this.options = $.extend({}, $.fn.button.defaults, options) + } + + Button.prototype = { + + constructor: Button + + , setState: function ( state ) { + var d = 'disabled' + , $el = this.$element + , data = $el.data() + , val = $el.is('input') ? 'val' : 'html' + + state = state + 'Text' + data.resetText || $el.data('resetText', $el[val]()) + + $el[val](data[state] || this.options[state]) + + // push to event loop to allow forms to submit + setTimeout(function () { + state == 'loadingText' ? + $el.addClass(d).attr(d, d) : + $el.removeClass(d).removeAttr(d) + }, 0) + } + + , toggle: function () { + var $parent = this.$element.parent('[data-toggle="buttons-radio"]') + + $parent && $parent + .find('.active') + .removeClass('active') + + this.$element.toggleClass('active') + } + + } + + + /* BUTTON PLUGIN DEFINITION + * ======================== */ + + $.fn.button = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('button') + , options = typeof option == 'object' && option + if (!data) $this.data('button', (data = new Button(this, options))) + if (option == 'toggle') data.toggle() + else if (option) data.setState(option) + }) + } + + $.fn.button.defaults = { + loadingText: 'loading...' + } + + $.fn.button.Constructor = Button + + + /* BUTTON DATA-API + * =============== */ + + $(function () { + $('body').on('click.button.data-api', '[data-toggle^=button]', function ( e ) { + var $btn = $(e.target) + if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') + $btn.button('toggle') + }) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f403193 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..73ff239 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..3b00020 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..275077f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/README b/README deleted file mode 100644 index 734abaf..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -This file was created by IntelliJ IDEA 11.1.1 for binding GitHub repository \ No newline at end of file diff --git a/Simple-jdbc-statistics.iml b/Simple-jdbc-statistics.iml new file mode 100644 index 0000000..ca90a9b --- /dev/null +++ b/Simple-jdbc-statistics.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/lib/h2-1.3.166.jar b/lib/h2-1.3.166.jar new file mode 100644 index 0000000..4985063 --- /dev/null +++ b/lib/h2-1.3.166.jar Binary files differ diff --git a/lib/servlet-api-2.5.jar b/lib/servlet-api-2.5.jar new file mode 100644 index 0000000..20b5755 --- /dev/null +++ b/lib/servlet-api-2.5.jar Binary files differ diff --git a/lib/slf4j-api-1.6.4.jar b/lib/slf4j-api-1.6.4.jar new file mode 100644 index 0000000..4d23f41 --- /dev/null +++ b/lib/slf4j-api-1.6.4.jar Binary files differ diff --git a/lib/slf4j-simple-1.6.4.jar b/lib/slf4j-simple-1.6.4.jar new file mode 100644 index 0000000..3d1b8d9 --- /dev/null +++ b/lib/slf4j-simple-1.6.4.jar Binary files differ diff --git a/lib/ssr-0.1.jar b/lib/ssr-0.1.jar new file mode 100644 index 0000000..65dfcf4 --- /dev/null +++ b/lib/ssr-0.1.jar Binary files differ diff --git a/lib/vst-0.4.jar b/lib/vst-0.4.jar new file mode 100644 index 0000000..db63792 --- /dev/null +++ b/lib/vst-0.4.jar Binary files differ diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..ac2dbe1 --- /dev/null +++ b/readme.md @@ -0,0 +1 @@ +A simple wrapper around jdbc drivers what will show current jdbc stats of the running queries on a simple web page on port 18080. \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/ConnectionLogger.java b/src/nl/astraeus/jdbc/ConnectionLogger.java new file mode 100644 index 0000000..c3e243f --- /dev/null +++ b/src/nl/astraeus/jdbc/ConnectionLogger.java @@ -0,0 +1,279 @@ +package nl.astraeus.jdbc; + +import java.sql.*; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Executor; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:12:34 PM + */ +public class ConnectionLogger implements Connection { + private Connection connection; + + private long milli; + private long nano; + private String lastSql; + + public ConnectionLogger(Connection connection) { + this.connection = connection; + this.lastSql = ""; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(QueryType.UNKNOWN, sql, m, n); + } + + public void commit() throws SQLException { + clearTime(); + + connection.commit(); + + log("commit"); + } + + public void rollback() throws SQLException { + clearTime(); + + connection.rollback(); + + log("rollback"); + } + + public void close() throws SQLException { + clearTime(); + + connection.close(); + + log("close"); + } + + public PreparedStatement prepareStatement(String sql) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, autoGeneratedKeys); + } + + public PreparedStatement prepareStatement(String sql, int columnIndexes[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnIndexes); + } + + public PreparedStatement prepareStatement(String sql, String columnNames[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnNames); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public Statement createStatement() throws SQLException { + return connection.createStatement(); + } + + public CallableStatement prepareCall(String sql) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql); + } + + public String nativeSQL(String sql) throws SQLException { + lastSql = sql; + return connection.nativeSQL(sql); + } + + public void setAutoCommit(boolean autoCommit) throws SQLException { + connection.setAutoCommit(autoCommit); + } + + public boolean getAutoCommit() throws SQLException { + return connection.getAutoCommit(); + } + + public boolean isClosed() throws SQLException { + return connection.isClosed(); + } + + public DatabaseMetaData getMetaData() throws SQLException { + return connection.getMetaData(); + } + + public void setReadOnly(boolean readOnly) throws SQLException { + connection.setReadOnly(readOnly); + } + + public boolean isReadOnly() throws SQLException { + return connection.isReadOnly(); + } + + public void setCatalog(String catalog) throws SQLException { + connection.setCatalog(catalog); + } + + public String getCatalog() throws SQLException { + return connection.getCatalog(); + } + + public void setTransactionIsolation(int level) throws SQLException { + connection.setTransactionIsolation(level); + } + + public int getTransactionIsolation() throws SQLException { + return connection.getTransactionIsolation(); + } + + public SQLWarning getWarnings() throws SQLException { + return connection.getWarnings(); + } + + public void clearWarnings() throws SQLException { + connection.clearWarnings(); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency); + } + + public Map> getTypeMap() throws SQLException { + return connection.getTypeMap(); + } + + public void setTypeMap(Map> map) throws SQLException { + connection.setTypeMap(map); + } + + public void setHoldability(int holdability) throws SQLException { + connection.setHoldability(holdability); + } + + public int getHoldability() throws SQLException { + return connection.getHoldability(); + } + + public Savepoint setSavepoint() throws SQLException { + return connection.setSavepoint(); + } + + public Savepoint setSavepoint(String name) throws SQLException { + return connection.setSavepoint(name); + } + + public void rollback(Savepoint savepoint) throws SQLException { + connection.rollback(); + } + + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + connection.releaseSavepoint(savepoint); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public Clob createClob() throws SQLException { + return connection.createClob(); + } + + public Blob createBlob() throws SQLException { + return connection.createBlob(); + } + + public NClob createNClob() throws SQLException { + return connection.createNClob(); + } + + public SQLXML createSQLXML() throws SQLException { + return connection.createSQLXML(); + } + + public boolean isValid(int timeout) throws SQLException { + return connection.isValid(timeout); + } + + public void setClientInfo(String name, String value) throws SQLClientInfoException { + connection.setClientInfo(name, value); + } + + public void setClientInfo(Properties properties) throws SQLClientInfoException { + connection.setClientInfo(properties); + } + + public String getClientInfo(String name) throws SQLException { + return connection.getClientInfo(name); + } + + public Properties getClientInfo() throws SQLException { + return connection.getClientInfo(); + } + + public Array createArrayOf(String typeName, Object[] elements) throws SQLException { + return connection.createArrayOf(typeName, elements); + } + + public Struct createStruct(String typeName, Object[] attributes) throws SQLException { + return connection.createStruct(typeName, attributes); + } + + @Override + public void setSchema(String schema) throws SQLException { + connection.setSchema(schema); + } + + @Override + public String getSchema() throws SQLException { + return connection.getSchema(); + } + + @Override + public void abort(Executor executor) throws SQLException { + connection.abort(executor); + } + + @Override + public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { + connection.setNetworkTimeout(executor, milliseconds); + } + + @Override + public int getNetworkTimeout() throws SQLException { + return connection.getNetworkTimeout(); + } + + public T unwrap(Class iface) throws SQLException { + return connection.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return connection.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/Driver.java b/src/nl/astraeus/jdbc/Driver.java new file mode 100644 index 0000000..8317172 --- /dev/null +++ b/src/nl/astraeus/jdbc/Driver.java @@ -0,0 +1,116 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.http.SimpleWebServer; +import nl.astraeus.jdbc.web.JdbcStatisticsServlet; +import nl.astraeus.jdbc.web.ResourceServlet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.*; +import java.util.Enumeration; +import java.util.Properties; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:54:37 PM + */ +public class Driver implements java.sql.Driver { + private final static Logger log = LoggerFactory.getLogger(Driver.class); + + final private static String URL_PREFIX = "jdbc:stat:"; + + private java.sql.Driver driver = null; + private String[] drivers = { + "org.postgresql.Driver", + "oracle.jdbc.driver.OracleDriver", + "com.sybase.jdbc2.jdbc.SybDriver", + "net.sourceforge.jtds.jdbc.Driver", + "com.microsoft.jdbc.sqlserver.SQLServerDriver", + "com.microsoft.sqlserver.jdbc.SQLServerDriver", + "weblogic.jdbc.sqlserver.SQLServerDriver", + "com.informix.jdbc.IfxDriver", + "org.apache.derby.jdbc.ClientDriver", + "org.apache.derby.jdbc.EmbeddedDriver", + "com.mysql.jdbc.Driver", + "org.hsqldb.jdbcDriver", + "org.h2.Driver" }; + + static { + log.debug("Loading driver class " + Driver.class.getName()); + + try { + DriverManager.registerDriver(new Driver()); + } catch (SQLException e) { + log.error("", e); + } + } + + public Driver() { + for (String dr : drivers) { + try { + Class.forName(dr); + } catch (Throwable e) { + log.debug("Can't instantiate driver: " + dr, e); + } + } + } + + private java.sql.Driver findDriver(String url) throws SQLException { + Enumeration e = DriverManager.getDrivers(); + + while (e.hasMoreElements()) { + java.sql.Driver d = (java.sql.Driver) e.nextElement(); + + if (d.acceptsURL(url)) { + return d; + } + } + + throw new SQLException("Driver not found: " + url); + } + + public Connection connect(String url, Properties info) throws SQLException { + url = url.substring(URL_PREFIX.length()); + + if (driver == null) { + driver = findDriver(url); + } + + if (driver != null) { + SimpleWebServer server = new SimpleWebServer(18080); + + server.addServlet(new JdbcStatisticsServlet(), "/"); + server.addServlet(new ResourceServlet(), "/resources/*"); + + server.start(); + } + + return new ConnectionLogger(driver.connect(url, info)); + } + + public boolean acceptsURL(String url) throws SQLException { + return (url != null && url.startsWith(URL_PREFIX)); + } + + public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { + return driver.getPropertyInfo(url, info); + } + + public int getMajorVersion() { + return driver.getMajorVersion(); + } + + public int getMinorVersion() { + return driver.getMinorVersion(); + } + + public boolean jdbcCompliant() { + return driver.jdbcCompliant(); + } + + @Override + public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException { + return driver.getParentLogger(); + } +} diff --git a/src/nl/astraeus/jdbc/JdbcLogger.java b/src/nl/astraeus/jdbc/JdbcLogger.java new file mode 100644 index 0000000..f4bc125 --- /dev/null +++ b/src/nl/astraeus/jdbc/JdbcLogger.java @@ -0,0 +1,113 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.jdbc.util.Util; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/** + * User: riennentjes + * Date: Jul 12, 2008 + * Time: 9:15:21 AM + */ +public class JdbcLogger { + private final static Logger logger = LoggerFactory.getLogger(JdbcLogger.class); + + private final static JdbcLogger instance = new JdbcLogger(); + + public static JdbcLogger get() { + return instance; + } + + public final static class LogEntry { + public QueryType type; + public String sql; + public long milli; + public long nano; + public int count; + public int hash; + + public LogEntry(int hash, QueryType type, String sql, long milli, long nano) { + this.hash = hash; + this.type = type; + this.sql = sql; + this.milli = milli; + this.nano = nano; + this.count = 1; + } + + public void addCount(long milli, long nano) { + synchronized (this) { + count++; + this.milli += milli; + this.nano += nano; + } + } + + public int getCount() { + return count; + } + + public String getMilli() { + return Util.formatNano(milli*1000000/count); + } + + public String getNano() { + return Util.formatNano(nano/count); + } + + public String getTotal() { + return Util.formatNano(nano); + } + + public String getSql() { + return sql; + } + } + + private Map queries; + + public JdbcLogger() { + queries = new ConcurrentHashMap(); + } + + public void logEntry(QueryType type, String sql, long milli, long nano) { + int hash = sql.hashCode(); + LogEntry entry = queries.get(hash); + + if (entry == null) { + entry = new LogEntry(hash, type, sql, milli, nano); + queries.put(hash, entry); + } else { + entry.addCount(milli, nano); + } + + if (queries.size() > 1000) { + List toRemove = new LinkedList(); + List values = new LinkedList(queries.values()); + + Collections.sort(values, new Comparator() { + @Override + public int compare(LogEntry o1, LogEntry o2) { + return o1.count - o2.count; + } + }); + + while (queries.size() > 900) { + queries.remove(values.remove(0).hash); + + } + } + } + + public static void log(QueryType type, String sql, long milli, long nano) { + instance.logEntry(type, sql, milli, nano); + } + + public Collection getEntries() { + return queries.values(); + } + +} diff --git a/src/nl/astraeus/jdbc/PreparedStatementLogger.java b/src/nl/astraeus/jdbc/PreparedStatementLogger.java new file mode 100644 index 0000000..98aefc7 --- /dev/null +++ b/src/nl/astraeus/jdbc/PreparedStatementLogger.java @@ -0,0 +1,577 @@ +package nl.astraeus.jdbc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.InputStream; +import java.io.Reader; +import java.math.BigDecimal; +import java.net.URL; +import java.sql.*; +import java.util.Calendar; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 7:47:57 PM + */ +public class PreparedStatementLogger implements PreparedStatement { + private final static Logger log = LoggerFactory.getLogger(PreparedStatementLogger.class); + + private PreparedStatement statement; + + private String sql; + private QueryType type; + private long milli; + private long nano; + + //private ArrayList parameters; + + public PreparedStatementLogger(PreparedStatement statement) { + this.statement = statement; + this.sql = ""; + this.type = QueryType.UNKNOWN; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(QueryType type, String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(type, sql, m, n); + } + + public PreparedStatementLogger(Connection connection, String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql); + } + + public PreparedStatementLogger(Connection connection, String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatementLogger(Connection connection, String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, autoGeneratedKeys); + } + + public PreparedStatementLogger(Connection connection, String sql, int[] columnIndexes) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnIndexes); + } + + public PreparedStatementLogger(Connection connection, String sql, String[] columnNames) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnNames); + } + + public boolean execute() throws SQLException { + clearTime(); + + boolean result = statement.execute(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery() throws SQLException { + clearTime(); + + ResultSet result = statement.executeQuery(); + + log(type, sql); + + return result; + } + + public int executeUpdate() throws SQLException { + clearTime(); + + int result = statement.executeUpdate(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + ResultSet result = statement.executeQuery(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnNames); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnNames); + + log(type, sql); + + return result; + } + + + public void setNull(int parameterIndex, int sqlType) throws SQLException { + statement.setNull(parameterIndex, sqlType); + } + + public void setBoolean(int parameterIndex, boolean x) throws SQLException { + statement.setBoolean(parameterIndex, x); + } + + public void setByte(int parameterIndex, byte x) throws SQLException { + statement.setByte(parameterIndex, x); + } + + public void setShort(int parameterIndex, short x) throws SQLException { + statement.setShort(parameterIndex, x); + } + + public void setInt(int parameterIndex, int x) throws SQLException { + statement.setInt(parameterIndex, x); + } + + public void setLong(int parameterIndex, long x) throws SQLException { + statement.setLong(parameterIndex, x); + } + + public void setFloat(int parameterIndex, float x) throws SQLException { + statement.setFloat(parameterIndex, x); + } + + public void setDouble(int parameterIndex, double x) throws SQLException { + statement.setDouble(parameterIndex, x); + } + + public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { + statement.setBigDecimal(parameterIndex, x); + } + + public void setString(int parameterIndex, String x) throws SQLException { + statement.setString(parameterIndex, x); + } + + public void setBytes(int parameterIndex, byte x[]) throws SQLException { + statement.setBytes(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x) throws SQLException { + statement.setDate(parameterIndex, x); + } + + public void setTime(int parameterIndex, Time x) throws SQLException { + statement.setTime(parameterIndex, x); + } + + public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { + statement.setTimestamp(parameterIndex, x); + } + + public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setUnicodeStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType); + } + + public void setObject(int parameterIndex, Object x) throws SQLException { + statement.setObject(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setRef(int parameterIndex, Ref x) throws SQLException { + statement.setRef(parameterIndex, x); + } + + public void setBlob(int parameterIndex, Blob x) throws SQLException { + statement.setBlob(parameterIndex, x); + } + + public void setClob(int parameterIndex, Clob x) throws SQLException { + statement.setClob(parameterIndex, x); + } + + public void setArray(int parameterIndex, Array x) throws SQLException { + statement.setArray(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { + statement.setDate(parameterIndex, x, cal); + } + + public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { + statement.setTime(parameterIndex, x, cal); + } + + public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { + statement.setTimestamp(parameterIndex, x, cal); + } + + public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException { + statement.setNull(parameterIndex, sqlType, typeName); + } + + public void setURL(int parameterIndex, URL x) throws SQLException { + statement.setURL(parameterIndex, x); + } + + public void setRowId(int parameterIndex, RowId x) throws SQLException { + statement.setRowId(parameterIndex, x); + } + + public void setNString(int parameterIndex, String value) throws SQLException { + statement.setNString(parameterIndex, value); + } + + public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException { + statement.setNCharacterStream(parameterIndex, value, length); + } + + public void setNClob(int parameterIndex, NClob value) throws SQLException { + statement.setNClob(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setClob(parameterIndex, reader, length); + } + + public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException { + statement.setBlob(parameterIndex, inputStream, length); + } + + public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setNClob(parameterIndex, reader, length); + } + + public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException { + statement.setSQLXML(parameterIndex, xmlObject); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType, scaleOrLength); + } + + public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException { + statement.setAsciiStream(parameterIndex, x); + } + + public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException { + statement.setBinaryStream(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException { + statement.setCharacterStream(parameterIndex, reader); + } + + public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException { + statement.setNCharacterStream(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader) throws SQLException { + statement.setClob(parameterIndex, reader); + } + + public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException { + statement.setBlob(parameterIndex, inputStream); + } + + public void setNClob(int parameterIndex, Reader reader) throws SQLException { + statement.setNClob(parameterIndex, reader); + } + + + public void close() throws SQLException { + sql = ""; + type = QueryType.UNKNOWN; + milli = 0; + nano = 0; + + statement.close(); + } + + public ResultSetMetaData getMetaData() throws SQLException { + return statement.getMetaData(); + } + + public void clearParameters() throws SQLException { + statement.clearParameters(); + } + + public ParameterMetaData getParameterMetaData() throws SQLException { + return statement.getParameterMetaData(); + } + + public void addBatch() throws SQLException { + statement.addBatch(); + } + + public int getMaxFieldSize() throws SQLException { + return statement.getMaxFieldSize(); + } + + public void setMaxFieldSize(int max) throws SQLException { + statement.setMaxFieldSize(max); + } + + public int getMaxRows() throws SQLException { + return statement.getMaxRows(); + } + + public void setMaxRows(int max) throws SQLException { + statement.setMaxRows(max); + } + + public void setEscapeProcessing(boolean enable) throws SQLException { + statement.setEscapeProcessing(enable); + } + + public int getQueryTimeout() throws SQLException { + return statement.getQueryTimeout(); + } + + public void setQueryTimeout(int seconds) throws SQLException { + statement.setQueryTimeout(seconds); + } + + public void cancel() throws SQLException { + statement.cancel(); + } + + public SQLWarning getWarnings() throws SQLException { + return statement.getWarnings(); + } + + public void clearWarnings() throws SQLException { + statement.clearWarnings(); + } + + public void setCursorName(String name) throws SQLException { + statement.setCursorName(name); + } + + public boolean execute(String sql) throws SQLException { + return statement.execute(sql); + } + + public ResultSet getResultSet() throws SQLException { + return statement.getResultSet(); + } + + public int getUpdateCount() throws SQLException { + return statement.getUpdateCount(); + } + + public boolean getMoreResults() throws SQLException { + return statement.getMoreResults(); + } + + public void setFetchDirection(int direction) throws SQLException { + statement.setFetchDirection(direction); + } + + public int getFetchDirection() throws SQLException { + return statement.getFetchDirection(); + } + + public void setFetchSize(int rows) throws SQLException { + statement.setFetchSize(rows); + } + + public int getFetchSize() throws SQLException { + return statement.getFetchSize(); + } + + public int getResultSetConcurrency() throws SQLException { + return statement.getResultSetConcurrency(); + } + + public int getResultSetType() throws SQLException { + return statement.getResultSetType(); + } + + public void addBatch(String sql) throws SQLException { + statement.addBatch(sql); + } + + public void clearBatch() throws SQLException { + statement.clearBatch(); + } + + public int[] executeBatch() throws SQLException { + return statement.executeBatch(); + } + + public Connection getConnection() throws SQLException { + return statement.getConnection(); + } + + public boolean getMoreResults(int current) throws SQLException { + return statement.getMoreResults(current); + } + + public ResultSet getGeneratedKeys() throws SQLException { + return statement.getGeneratedKeys(); + } + + public int getResultSetHoldability() throws SQLException { + return statement.getResultSetHoldability(); + } + + public boolean isClosed() throws SQLException { + return statement.isClosed(); + } + + public void setPoolable(boolean poolable) throws SQLException { + statement.setPoolable(poolable); + } + + public boolean isPoolable() throws SQLException { + return statement.isPoolable(); + } + + @Override + public void closeOnCompletion() throws SQLException { + statement.closeOnCompletion();; + } + + @Override + public boolean isCloseOnCompletion() throws SQLException { + return statement.isCloseOnCompletion(); + } + + public T unwrap(Class iface) throws SQLException { + return statement.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return statement.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/QueryType.java b/src/nl/astraeus/jdbc/QueryType.java new file mode 100644 index 0000000..744fbfc --- /dev/null +++ b/src/nl/astraeus/jdbc/QueryType.java @@ -0,0 +1,24 @@ +package nl.astraeus.jdbc; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:32:49 PM + */ +public enum QueryType { + PLAIN("plain"), + PREPARED("prepared"), + CALLABLE("callable"), + UNKNOWN("unknown"); + + private String description; + + QueryType(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } + +} diff --git a/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java new file mode 100644 index 0000000..07aac40 --- /dev/null +++ b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java @@ -0,0 +1,68 @@ +package nl.astraeus.jdbc.example; + +import java.sql.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 7:32 PM + */ +public class JdbcStatisticsExample { + + + public static void main(String [] args) throws Exception { + Class.forName("org.h2.Driver"); + Class.forName("nl.astraeus.jdbc.Driver"); + + new JdbcStatisticsExample(); + } + + public JdbcStatisticsExample() throws Exception { + Connection conn = DriverManager.getConnection("jdbc:stat:jdbc:h2:mem:test"); + + Statement statement = null; + + statement = conn.createStatement(); + statement.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + + boolean running = true; + int count = 1; + PreparedStatement ps = null; + + while (running) { + Thread.sleep(10); + + String TableName = "TEST"+(System.nanoTime() % 1000); + + try { + ps = conn.prepareStatement("SELECT COUNT(*) FROM "+TableName); + ResultSet rs = ps.executeQuery(); + } catch (SQLException e) { + statement = conn.createStatement(); + statement.execute("CREATE TABLE "+TableName+" (ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + } finally { + if (ps!=null) { + ps.close(); + } + } + + ps = conn.prepareStatement("INSERT INTO "+TableName+" VALUES (?, ?)"); + + ps.setInt(1, count++); + ps.setString(2, "String "+System.currentTimeMillis()); + + ps.execute(); + ps.close(); + + Thread.sleep(10); + + ps = conn.prepareStatement("SELECT * FROM "+TableName); + ResultSet rs = ps.executeQuery(); + statement.close(); + } + + conn.close(); + } +} diff --git a/src/nl/astraeus/jdbc/util/IOUtils.java b/src/nl/astraeus/jdbc/util/IOUtils.java new file mode 100644 index 0000000..ce95d9d --- /dev/null +++ b/src/nl/astraeus/jdbc/util/IOUtils.java @@ -0,0 +1,38 @@ +package nl.astraeus.jdbc.util; + +import java.io.*; + +/** + * User: rnentjes + * Date: 4/9/12 + * Time: 2:33 PM + */ +public class IOUtils { + + public static String toString(InputStream in) throws IOException { + assert in != null; + + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + StringBuilder buffer = new StringBuilder(); + + while(reader.ready()) { + buffer.append(reader.readLine()); + buffer.append("\n"); + } + + return buffer.toString(); + } finally { + in.close(); + } + } + + public static void copy(InputStream in, OutputStream out) throws IOException { + byte [] buffer = new byte[1<<16]; + int bytes; + + while((bytes = in.read(buffer)) > 0) { + out.write(buffer, 0, bytes); + } + } +} diff --git a/src/nl/astraeus/jdbc/util/Util.java b/src/nl/astraeus/jdbc/util/Util.java new file mode 100644 index 0000000..eaa853b --- /dev/null +++ b/src/nl/astraeus/jdbc/util/Util.java @@ -0,0 +1,25 @@ +package nl.astraeus.jdbc.util; + +import java.text.DecimalFormat; +import java.text.NumberFormat; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 12:28 PM + */ +public class Util { + // utility functions + public static String formatNano(long l) { + NumberFormat format = new DecimalFormat("###,##0.000000"); + + return format.format((double) l / 1000000.0); + } + + public static void printMemoryUsage() { + System.out.println("Used memory: "+((Runtime.getRuntime().totalMemory() / (1024*1024))-(Runtime.getRuntime().freeMemory() / (1024*1024)))); + System.out.println("Free memory: "+(Runtime.getRuntime().freeMemory() / (1024*1024))); + System.out.println("Total memory: "+(Runtime.getRuntime().totalMemory() / (1024*1024))); + System.out.println("Max memory: "+(Runtime.getRuntime().maxMemory() / (1024*1024))); + } +} diff --git a/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java b/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java new file mode 100644 index 0000000..a162d6f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java @@ -0,0 +1,90 @@ +package nl.astraeus.jdbc.web; + +import nl.astraeus.jdbc.util.IOUtils; +import nl.astraeus.jdbc.util.Util; +import nl.astraeus.jdbc.web.page.Menu; +import nl.astraeus.jdbc.web.page.Page; +import nl.astraeus.jdbc.web.page.QueryOverview; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import java.io.IOException; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:05 PM + */ +public class JdbcStatisticsServlet extends HttpServlet { + + private String head; + private String bottom; + + @Override + public void init() throws ServletException { + super.init(); + + try { + head = IOUtils.toString(getClass().getResourceAsStream("head.html")); + bottom = IOUtils.toString(getClass().getResourceAsStream("bottom.html")); + } catch (IOException e) { + throw new ServletException(e); + } + + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + doPost(req, resp); + } + + @Override + protected void doPost(final HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + long nano = System.nanoTime(); + + HttpSession session = req.getSession(); + boolean ajax = "true".equals(req.getParameter("ajax")); + + resp.setContentType("text/html"); + + Page page = (Page)session.getAttribute("page"); + Page menu = (Page)session.getAttribute("menu"); + + session.setMaxInactiveInterval(1800); + + if (menu == null) { + menu = new Menu(); + + session.setAttribute("menu", menu); + } + + if (page == null || "menumain".equals(req.getParameter("action"))) { + page = new QueryOverview(); + } else if ("diagnostics".equals(req.getParameter("action"))) { + //page = new Diagnostics(); + } else { + page = page .processRequest(req); + } + + menu.processRequest(req); + + session.setAttribute("page", page); + + if (!ajax) { + resp.getWriter().print(head); + } + + resp.getWriter().print(menu.render(req)); + resp.getWriter().print(page.render(req)); + + if (!ajax) { + resp.getWriter().print(bottom); + } + + System.out.println("Request ends, time="+ Util.formatNano(System.nanoTime() - nano) +", page="+page.getClass().getSimpleName()); + } + +} diff --git a/src/nl/astraeus/jdbc/web/ResourceServlet.java b/src/nl/astraeus/jdbc/web/ResourceServlet.java new file mode 100644 index 0000000..7abfe6f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/ResourceServlet.java @@ -0,0 +1,49 @@ +package nl.astraeus.jdbc.web; + +import nl.astraeus.jdbc.util.IOUtils; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.InputStream; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:05 PM + */ +public class ResourceServlet extends HttpServlet { + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String uri = req.getRequestURI(); + + uri = "nl/astraeus/jdbc/web" + uri; + InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(uri); + + if (in == null) { + resp.sendError(404, "Cannot find resource '" + uri + "'."); + } else { + try { + if (uri.endsWith("js")) { + resp.setContentType("text/javascript"); + } else if (uri.endsWith("css")) { + resp.setContentType("text/css"); + } else if (uri.endsWith("png")) { + resp.setContentType("image/png"); + } else if (uri.endsWith("jpg")) { + resp.setContentType("image/jpeg"); + } else if (uri.endsWith("gif")) { + resp.setContentType("image/gif"); + } + + IOUtils.copy(in, resp.getOutputStream()); + } finally { + in.close(); + } + } + } + +} diff --git a/src/nl/astraeus/jdbc/web/bottom.html b/src/nl/astraeus/jdbc/web/bottom.html new file mode 100644 index 0000000..1288de4 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/bottom.html @@ -0,0 +1,8 @@ + + +
+ + + + + \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/head.html b/src/nl/astraeus/jdbc/web/head.html new file mode 100644 index 0000000..0f8f6a3 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/head.html @@ -0,0 +1,96 @@ + + + + + + + Simple JDBC Statistics + + + + + + + + + + + + + + + + + + + +
+
+ +
+ diff --git a/src/nl/astraeus/jdbc/web/page/Menu.html b/src/nl/astraeus/jdbc/web/page/Menu.html new file mode 100644 index 0000000..505c7c2 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.html @@ -0,0 +1,42 @@ + diff --git a/src/nl/astraeus/jdbc/web/page/Menu.java b/src/nl/astraeus/jdbc/web/page/Menu.java new file mode 100644 index 0000000..f0a349a --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.java @@ -0,0 +1,27 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 9:07 PM + */ +public class Menu extends TemplatePage { + + @Override + public Page processRequest(HttpServletRequest request) { + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + result.put("user", request.getSession().getAttribute("user")); + + return result; + } +} diff --git a/src/nl/astraeus/jdbc/web/page/Page.java b/src/nl/astraeus/jdbc/web/page/Page.java new file mode 100644 index 0000000..9d526d6 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Page.java @@ -0,0 +1,17 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:20 PM + */ +public abstract class Page { + + public abstract Page processRequest(HttpServletRequest request); + public abstract Map defineModel(HttpServletRequest request); + public abstract String render(HttpServletRequest request); + +} diff --git a/src/nl/astraeus/jdbc/web/page/QueryOverview.html b/src/nl/astraeus/jdbc/web/page/QueryOverview.html new file mode 100644 index 0000000..64a88fb --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/QueryOverview.html @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + {foreach(queries as q)} + + + + + + + {eachend} + +
Total timeAvg. time# CallsSql
{q.total}{q.nano}{q.count}{q.sql}
diff --git a/src/nl/astraeus/jdbc/web/page/QueryOverview.java b/src/nl/astraeus/jdbc/web/page/QueryOverview.java new file mode 100644 index 0000000..02982f1 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/QueryOverview.java @@ -0,0 +1,92 @@ +package nl.astraeus.jdbc.web.page; + +import nl.astraeus.jdbc.JdbcLogger; + +import javax.servlet.http.HttpServletRequest; +import java.util.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 9:16 PM + */ +public class QueryOverview extends TemplatePage { + + boolean sortTotalCalls = true; + boolean sortAvgTime = false; + boolean sortTotalTime = false; + + @Override + public Page processRequest(HttpServletRequest request) { + if ("sortTotalCalls".equals(request.getParameter("action"))) { + sortTotalCalls = true; + sortAvgTime = false; + sortTotalTime = false; + } else if ("sortAvgTime".equals(request.getParameter("action"))) { + sortTotalCalls = false; + sortAvgTime = true; + sortTotalTime = false; + } else if ("sortTotalTime".equals(request.getParameter("action"))) { + sortTotalCalls = false; + sortAvgTime = false; + sortTotalTime = true; + } + + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + List entries = new ArrayList(JdbcLogger.get().getEntries()); + + if (sortTotalCalls) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + return o2.count - o1.count; + } + }); + } else if (sortAvgTime) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + long n1 = o1.nano / o1.count; + long n2 = o2.nano / o2.count; + + if (n2 > n1) { + return 1; + } else if (n2 < n1) { + return -1; + } else { + return 0; + } + } + }); + } else if (sortTotalTime) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + if (o2.nano > o1.nano) { + return 1; + } else if (o2.nano < o1.nano) { + return -1; + } else { + return 0; + } + } + }); + } + + result.put("queries", entries); + result.put("count", entries.size()); + + result.put("sortTotalCalls", sortTotalCalls); + result.put("sortAvgTime", sortAvgTime); + result.put("sortTotalTime", sortTotalTime); + + return result; + } + +} diff --git a/src/nl/astraeus/jdbc/web/page/TemplatePage.java b/src/nl/astraeus/jdbc/web/page/TemplatePage.java new file mode 100644 index 0000000..33e2641 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/TemplatePage.java @@ -0,0 +1,58 @@ +package nl.astraeus.jdbc.web.page; + +import nl.astraeus.template.EscapeMode; +import nl.astraeus.template.SimpleTemplate; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:20 PM + */ +public abstract class TemplatePage extends Page { + + private SimpleTemplate template; + + protected TemplatePage() { + template = getSimpleTemplate(this.getClass()); + } + + public String render(HttpServletRequest request) { + return template.render(defineModel(request)); + } + + private static Map templateCache = new HashMap(); + + public synchronized static SimpleTemplate getSimpleTemplate(Class cls) { + SimpleTemplate result = templateCache.get(cls); + + if (result == null) { + InputStream in = null; + + try { + in = cls.getResourceAsStream(cls.getSimpleName() + ".html"); + + result = SimpleTemplate.readTemplate('{','}', EscapeMode.HTML, in); + + templateCache.put(cls, result); + } catch (IOException e) { + throw new IllegalStateException(e); + } finally { + if (in != null) { + try { + in.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + + return result; + } +} diff --git a/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css b/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css new file mode 100644 index 0000000..0e0056f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css @@ -0,0 +1,581 @@ +/*! + * Bootstrap Responsive v2.0.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ +.clearfix { + *zoom: 1; +} +.clearfix:before, .clearfix:after { + display: table; + content: ""; +} +.clearfix:after { + clear: both; +} +.hidden { + display: none; + visibility: hidden; +} +@media (max-width: 480px) { + .nav-collapse { + -webkit-transform: translate3d(0, 0, 0); + } + .page-header h1 small { + display: block; + line-height: 18px; + } + input[class*="span"], + select[class*="span"], + textarea[class*="span"], + .uneditable-input { + display: block; + width: 100%; + min-height: 28px; + /* Make inputs at least the height of their button counterpart */ + + /* Makes inputs behave like true block-level elements */ + + -webkit-box-sizing: border-box; + /* Older Webkit */ + + -moz-box-sizing: border-box; + /* Older FF */ + + -ms-box-sizing: border-box; + /* IE8 */ + + box-sizing: border-box; + /* CSS3 spec*/ + + } + .input-prepend input[class*="span"], .input-append input[class*="span"] { + width: auto; + } + input[type="checkbox"], input[type="radio"] { + border: 1px solid #ccc; + } + .form-horizontal .control-group > label { + float: none; + width: auto; + padding-top: 0; + text-align: left; + } + .form-horizontal .controls { + margin-left: 0; + } + .form-horizontal .control-list { + padding-top: 0; + } + .form-horizontal .form-actions { + padding-left: 10px; + padding-right: 10px; + } + .modal { + position: absolute; + top: 10px; + left: 10px; + right: 10px; + width: auto; + margin: 0; + } + .modal.fade.in { + top: auto; + } + .modal-header .close { + padding: 10px; + margin: -10px; + } + .carousel-caption { + position: static; + } +} +@media (max-width: 767px) { + .container { + width: auto; + padding: 0 20px; + } + .row-fluid { + width: 100%; + } + .row { + margin-left: 0; + } + .row > [class*="span"], .row-fluid > [class*="span"] { + float: none; + display: block; + width: auto; + margin: 0; + } +} +@media (min-width: 768px) and (max-width: 979px) { + .row { + margin-left: -20px; + *zoom: 1; + } + .row:before, .row:after { + display: table; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + margin-left: 20px; + } + .span1 { + width: 42px; + } + .span2 { + width: 104px; + } + .span3 { + width: 166px; + } + .span4 { + width: 228px; + } + .span5 { + width: 290px; + } + .span6 { + width: 352px; + } + .span7 { + width: 414px; + } + .span8 { + width: 476px; + } + .span9 { + width: 538px; + } + .span10 { + width: 600px; + } + .span11 { + width: 662px; + } + .span12, .container { + width: 724px; + } + .offset1 { + margin-left: 82px; + } + .offset2 { + margin-left: 144px; + } + .offset3 { + margin-left: 206px; + } + .offset4 { + margin-left: 268px; + } + .offset5 { + margin-left: 330px; + } + .offset6 { + margin-left: 392px; + } + .offset7 { + margin-left: 454px; + } + .offset8 { + margin-left: 516px; + } + .offset9 { + margin-left: 578px; + } + .offset10 { + margin-left: 640px; + } + .offset11 { + margin-left: 702px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, .row-fluid:after { + display: table; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid > [class*="span"] { + float: left; + margin-left: 2.762430939%; + } + .row-fluid > [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid > .span1 { + width: 5.801104972%; + } + .row-fluid > .span2 { + width: 14.364640883%; + } + .row-fluid > .span3 { + width: 22.928176794%; + } + .row-fluid > .span4 { + width: 31.491712705%; + } + .row-fluid > .span5 { + width: 40.055248616%; + } + .row-fluid > .span6 { + width: 48.618784527%; + } + .row-fluid > .span7 { + width: 57.182320438000005%; + } + .row-fluid > .span8 { + width: 65.74585634900001%; + } + .row-fluid > .span9 { + width: 74.30939226%; + } + .row-fluid > .span10 { + width: 82.87292817100001%; + } + .row-fluid > .span11 { + width: 91.436464082%; + } + .row-fluid > .span12 { + width: 99.999999993%; + } + input.span1, textarea.span1, .uneditable-input.span1 { + width: 32px; + } + input.span2, textarea.span2, .uneditable-input.span2 { + width: 94px; + } + input.span3, textarea.span3, .uneditable-input.span3 { + width: 156px; + } + input.span4, textarea.span4, .uneditable-input.span4 { + width: 218px; + } + input.span5, textarea.span5, .uneditable-input.span5 { + width: 280px; + } + input.span6, textarea.span6, .uneditable-input.span6 { + width: 342px; + } + input.span7, textarea.span7, .uneditable-input.span7 { + width: 404px; + } + input.span8, textarea.span8, .uneditable-input.span8 { + width: 466px; + } + input.span9, textarea.span9, .uneditable-input.span9 { + width: 528px; + } + input.span10, textarea.span10, .uneditable-input.span10 { + width: 590px; + } + input.span11, textarea.span11, .uneditable-input.span11 { + width: 652px; + } + input.span12, textarea.span12, .uneditable-input.span12 { + width: 714px; + } +} +@media (max-width: 979px) { + body { + padding-top: 0; + } + .navbar-fixed-top { + position: static; + margin-bottom: 18px; + } + .navbar-fixed-top .navbar-inner { + padding: 5px; + } + .navbar .container { + width: auto; + padding: 0; + } + .navbar .brand { + padding-left: 10px; + padding-right: 10px; + margin: 0 0 0 -5px; + } + .navbar .nav-collapse { + clear: left; + } + .navbar .nav { + float: none; + margin: 0 0 9px; + } + .navbar .nav > li { + float: none; + } + .navbar .nav > li > a { + margin-bottom: 2px; + } + .navbar .nav > .divider-vertical { + display: none; + } + .navbar .nav .nav-header { + color: #999999; + text-shadow: none; + } + .navbar .nav > li > a, .navbar .dropdown-menu a { + padding: 6px 15px; + font-weight: bold; + color: #999999; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + } + .navbar .dropdown-menu li + li a { + margin-bottom: 2px; + } + .navbar .nav > li > a:hover, .navbar .dropdown-menu a:hover { + background-color: #222222; + } + .navbar .dropdown-menu { + position: static; + top: auto; + left: auto; + float: none; + display: block; + max-width: none; + margin: 0 15px; + padding: 0; + background-color: transparent; + border: none; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + } + .navbar .dropdown-menu:before, .navbar .dropdown-menu:after { + display: none; + } + .navbar .dropdown-menu .divider { + display: none; + } + .navbar-form, .navbar-search { + float: none; + padding: 9px 15px; + margin: 9px 0; + border-top: 1px solid #222222; + border-bottom: 1px solid #222222; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + } + .navbar .nav.pull-right { + float: none; + margin-left: 0; + } + .navbar-static .navbar-inner { + padding-left: 10px; + padding-right: 10px; + } + .btn-navbar { + display: block; + } + .nav-collapse { + overflow: hidden; + height: 0; + } +} +@media (min-width: 980px) { + .nav-collapse.collapse { + height: auto !important; + } +} +@media (min-width: 1200px) { + .row { + margin-left: -30px; + *zoom: 1; + } + .row:before, .row:after { + display: table; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + margin-left: 30px; + } + .span1 { + width: 70px; + } + .span2 { + width: 170px; + } + .span3 { + width: 270px; + } + .span4 { + width: 370px; + } + .span5 { + width: 470px; + } + .span6 { + width: 570px; + } + .span7 { + width: 670px; + } + .span8 { + width: 770px; + } + .span9 { + width: 870px; + } + .span10 { + width: 970px; + } + .span11 { + width: 1070px; + } + .span12, .container { + width: 1170px; + } + .offset1 { + margin-left: 130px; + } + .offset2 { + margin-left: 230px; + } + .offset3 { + margin-left: 330px; + } + .offset4 { + margin-left: 430px; + } + .offset5 { + margin-left: 530px; + } + .offset6 { + margin-left: 630px; + } + .offset7 { + margin-left: 730px; + } + .offset8 { + margin-left: 830px; + } + .offset9 { + margin-left: 930px; + } + .offset10 { + margin-left: 1030px; + } + .offset11 { + margin-left: 1130px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, .row-fluid:after { + display: table; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid > [class*="span"] { + float: left; + margin-left: 2.564102564%; + } + .row-fluid > [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid > .span1 { + width: 5.982905983%; + } + .row-fluid > .span2 { + width: 14.529914530000001%; + } + .row-fluid > .span3 { + width: 23.076923077%; + } + .row-fluid > .span4 { + width: 31.623931624%; + } + .row-fluid > .span5 { + width: 40.170940171000005%; + } + .row-fluid > .span6 { + width: 48.717948718%; + } + .row-fluid > .span7 { + width: 57.264957265%; + } + .row-fluid > .span8 { + width: 65.81196581200001%; + } + .row-fluid > .span9 { + width: 74.358974359%; + } + .row-fluid > .span10 { + width: 82.905982906%; + } + .row-fluid > .span11 { + width: 91.45299145300001%; + } + .row-fluid > .span12 { + width: 100%; + } + input.span1, textarea.span1, .uneditable-input.span1 { + width: 60px; + } + input.span2, textarea.span2, .uneditable-input.span2 { + width: 160px; + } + input.span3, textarea.span3, .uneditable-input.span3 { + width: 260px; + } + input.span4, textarea.span4, .uneditable-input.span4 { + width: 360px; + } + input.span5, textarea.span5, .uneditable-input.span5 { + width: 460px; + } + input.span6, textarea.span6, .uneditable-input.span6 { + width: 560px; + } + input.span7, textarea.span7, .uneditable-input.span7 { + width: 660px; + } + input.span8, textarea.span8, .uneditable-input.span8 { + width: 760px; + } + input.span9, textarea.span9, .uneditable-input.span9 { + width: 860px; + } + input.span10, textarea.span10, .uneditable-input.span10 { + width: 960px; + } + input.span11, textarea.span11, .uneditable-input.span11 { + width: 1060px; + } + input.span12, textarea.span12, .uneditable-input.span12 { + width: 1160px; + } + .thumbnails { + margin-left: -30px; + } + .thumbnails > li { + margin-left: 30px; + } +} diff --git a/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css b/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css new file mode 100644 index 0000000..6229c12 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css @@ -0,0 +1,3521 @@ +/*! + * Bootstrap v2.0.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +nav, +section { + display: block; +} +audio, canvas, video { + display: inline-block; + *display: inline; + *zoom: 1; +} +audio:not([controls]) { + display: none; +} +html { + font-size: 100%; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} +a:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +a:hover, a:active { + outline: 0; +} +sub, sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} +sup { + top: -0.5em; +} +sub { + bottom: -0.25em; +} +img { + max-width: 100%; + height: auto; + border: 0; + -ms-interpolation-mode: bicubic; +} +button, +input, +select, +textarea { + margin: 0; + font-size: 100%; + vertical-align: middle; +} +button, input { + *overflow: visible; + line-height: normal; +} +button::-moz-focus-inner, input::-moz-focus-inner { + padding: 0; + border: 0; +} +button, +input[type="button"], +input[type="reset"], +input[type="submit"] { + cursor: pointer; + -webkit-appearance: button; +} +input[type="search"] { + -webkit-appearance: textfield; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +input[type="search"]::-webkit-search-decoration, input[type="search"]::-webkit-search-cancel-button { + -webkit-appearance: none; +} +textarea { + overflow: auto; + vertical-align: top; +} +.clearfix { + *zoom: 1; +} +.clearfix:before, .clearfix:after { + display: table; + content: ""; +} +.clearfix:after { + clear: both; +} +body { + margin: 0; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 18px; + color: #333333; + background-color: #ffffff; +} +a { + color: #0088cc; + text-decoration: none; +} +a:hover { + color: #005580; + text-decoration: underline; +} +.row { + margin-left: -20px; + *zoom: 1; +} +.row:before, .row:after { + display: table; + content: ""; +} +.row:after { + clear: both; +} +[class*="span"] { + float: left; + margin-left: 20px; +} +.span1 { + width: 60px; +} +.span2 { + width: 140px; +} +.span3 { + width: 220px; +} +.span4 { + width: 300px; +} +.span5 { + width: 380px; +} +.span6 { + width: 460px; +} +.span7 { + width: 540px; +} +.span8 { + width: 620px; +} +.span9 { + width: 700px; +} +.span10 { + width: 780px; +} +.span11 { + width: 860px; +} +.span12, .container { + width: 940px; +} +.offset1 { + margin-left: 100px; +} +.offset2 { + margin-left: 180px; +} +.offset3 { + margin-left: 260px; +} +.offset4 { + margin-left: 340px; +} +.offset5 { + margin-left: 420px; +} +.offset6 { + margin-left: 500px; +} +.offset7 { + margin-left: 580px; +} +.offset8 { + margin-left: 660px; +} +.offset9 { + margin-left: 740px; +} +.offset10 { + margin-left: 820px; +} +.offset11 { + margin-left: 900px; +} +.row-fluid { + width: 100%; + *zoom: 1; +} +.row-fluid:before, .row-fluid:after { + display: table; + content: ""; +} +.row-fluid:after { + clear: both; +} +.row-fluid > [class*="span"] { + float: left; + margin-left: 2.127659574%; +} +.row-fluid > [class*="span"]:first-child { + margin-left: 0; +} +.row-fluid > .span1 { + width: 6.382978723%; +} +.row-fluid > .span2 { + width: 14.89361702%; +} +.row-fluid > .span3 { + width: 23.404255317%; +} +.row-fluid > .span4 { + width: 31.914893614%; +} +.row-fluid > .span5 { + width: 40.425531911%; +} +.row-fluid > .span6 { + width: 48.93617020799999%; +} +.row-fluid > .span7 { + width: 57.446808505%; +} +.row-fluid > .span8 { + width: 65.95744680199999%; +} +.row-fluid > .span9 { + width: 74.468085099%; +} +.row-fluid > .span10 { + width: 82.97872339599999%; +} +.row-fluid > .span11 { + width: 91.489361693%; +} +.row-fluid > .span12 { + width: 99.99999998999999%; +} +.container { + width: 940px; + margin-left: auto; + margin-right: auto; + *zoom: 1; +} +.container:before, .container:after { + display: table; + content: ""; +} +.container:after { + clear: both; +} +.container-fluid { + padding-left: 20px; + padding-right: 20px; + *zoom: 1; +} +.container-fluid:before, .container-fluid:after { + display: table; + content: ""; +} +.container-fluid:after { + clear: both; +} +p { + margin: 0 0 9px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 18px; +} +p small { + font-size: 11px; + color: #999999; +} +.lead { + margin-bottom: 18px; + font-size: 20px; + font-weight: 200; + line-height: 27px; +} +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 0; + font-weight: bold; + color: #333333; + text-rendering: optimizelegibility; +} +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small { + font-weight: normal; + color: #999999; +} +h1 { + font-size: 30px; + line-height: 36px; +} +h1 small { + font-size: 18px; +} +h2 { + font-size: 24px; + line-height: 36px; +} +h2 small { + font-size: 18px; +} +h3 { + line-height: 27px; + font-size: 18px; +} +h3 small { + font-size: 14px; +} +h4, h5, h6 { + line-height: 18px; +} +h4 { + font-size: 14px; +} +h4 small { + font-size: 12px; +} +h5 { + font-size: 12px; +} +h6 { + font-size: 11px; + color: #999999; + text-transform: uppercase; +} +.page-header { + padding-bottom: 17px; + margin: 18px 0; + border-bottom: 1px solid #eeeeee; +} +.page-header h1 { + line-height: 1; +} +ul, ol { + padding: 0; + margin: 0 0 9px 25px; +} +ul ul, +ul ol, +ol ol, +ol ul { + margin-bottom: 0; +} +ul { + list-style: disc; +} +ol { + list-style: decimal; +} +li { + line-height: 18px; +} +ul.unstyled, ol.unstyled { + margin-left: 0; + list-style: none; +} +dl { + margin-bottom: 18px; +} +dt, dd { + line-height: 18px; +} +dt { + font-weight: bold; +} +dd { + margin-left: 9px; +} +hr { + margin: 18px 0; + border: 0; + border-top: 1px solid #eeeeee; + border-bottom: 1px solid #ffffff; +} +strong { + font-weight: bold; +} +em { + font-style: italic; +} +.muted { + color: #999999; +} +abbr { + font-size: 90%; + text-transform: uppercase; + border-bottom: 1px dotted #ddd; + cursor: help; +} +blockquote { + padding: 0 0 0 15px; + margin: 0 0 18px; + border-left: 5px solid #eeeeee; +} +blockquote p { + margin-bottom: 0; + font-size: 16px; + font-weight: 300; + line-height: 22.5px; +} +blockquote small { + display: block; + line-height: 18px; + color: #999999; +} +blockquote small:before { + content: '\2014 \00A0'; +} +blockquote.pull-right { + float: right; + padding-left: 0; + padding-right: 15px; + border-left: 0; + border-right: 5px solid #eeeeee; +} +blockquote.pull-right p, blockquote.pull-right small { + text-align: right; +} +q:before, +q:after, +blockquote:before, +blockquote:after { + content: ""; +} +address { + display: block; + margin-bottom: 18px; + line-height: 18px; + font-style: normal; +} +small { + font-size: 100%; +} +cite { + font-style: normal; +} +code, pre { + padding: 0 3px 2px; + font-family: Menlo, Monaco, "Courier New", monospace; + font-size: 12px; + color: #333333; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +code { + padding: 3px 4px; + color: #d14; + background-color: #f7f7f9; + border: 1px solid #e1e1e8; +} +pre { + display: block; + padding: 8.5px; + margin: 0 0 9px; + font-size: 12px; + line-height: 18px; + background-color: #f5f5f5; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.15); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + white-space: pre; + white-space: pre-wrap; + word-break: break-all; + word-wrap: break-word; +} +pre.prettyprint { + margin-bottom: 18px; +} +pre code { + padding: 0; + color: inherit; + background-color: transparent; + border: 0; +} +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} +form { + margin: 0 0 18px; +} +fieldset { + padding: 0; + margin: 0; + border: 0; +} +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 27px; + font-size: 19.5px; + line-height: 36px; + color: #333333; + border: 0; + border-bottom: 1px solid #eee; +} +legend small { + font-size: 13.5px; + color: #999999; +} +label, +input, +button, +select, +textarea { + font-size: 13px; + font-weight: normal; + line-height: 18px; +} +input, +button, +select, +textarea { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; +} +label { + display: block; + margin-bottom: 5px; + color: #333333; +} +input, +textarea, +select, +.uneditable-input { + display: inline-block; + width: 210px; + height: 18px; + padding: 4px; + margin-bottom: 9px; + font-size: 13px; + line-height: 18px; + color: #555555; + border: 1px solid #ccc; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.uneditable-textarea { + width: auto; + height: auto; +} +label input, label textarea, label select { + display: block; +} +input[type="image"], input[type="checkbox"], input[type="radio"] { + width: auto; + height: auto; + padding: 0; + margin: 3px 0; + *margin-top: 0; + /* IE7 */ + + line-height: normal; + cursor: pointer; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + border: 0 \9; + /* IE9 and down */ + +} +input[type="image"] { + border: 0; +} +input[type="file"] { + width: auto; + padding: initial; + line-height: initial; + border: initial; + background-color: #ffffff; + background-color: initial; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +input[type="button"], input[type="reset"], input[type="submit"] { + width: auto; + height: auto; +} +select, input[type="file"] { + height: 28px; + /* In IE7, the height of the select element cannot be changed by height, only font-size */ + + *margin-top: 4px; + /* For IE7, add top margin to align select with labels */ + + line-height: 28px; +} +input[type="file"] { + line-height: 18px \9; +} +select { + width: 220px; + background-color: #ffffff; +} +select[multiple], select[size] { + height: auto; +} +input[type="image"] { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +textarea { + height: auto; +} +input[type="hidden"] { + display: none; +} +.radio, .checkbox { + padding-left: 18px; +} +.radio input[type="radio"], .checkbox input[type="checkbox"] { + float: left; + margin-left: -18px; +} +.controls > .radio:first-child, .controls > .checkbox:first-child { + padding-top: 5px; +} +.radio.inline, .checkbox.inline { + display: inline-block; + padding-top: 5px; + margin-bottom: 0; + vertical-align: middle; +} +.radio.inline + .radio.inline, .checkbox.inline + .checkbox.inline { + margin-left: 10px; +} +input, textarea { + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; + -moz-transition: border linear 0.2s, box-shadow linear 0.2s; + -ms-transition: border linear 0.2s, box-shadow linear 0.2s; + -o-transition: border linear 0.2s, box-shadow linear 0.2s; + transition: border linear 0.2s, box-shadow linear 0.2s; +} +input:focus, textarea:focus { + border-color: rgba(82, 168, 236, 0.8); + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + outline: 0; + outline: thin dotted \9; + /* IE6-9 */ + +} +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus, +select:focus { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.input-mini { + width: 60px; +} +.input-small { + width: 90px; +} +.input-medium { + width: 150px; +} +.input-large { + width: 210px; +} +.input-xlarge { + width: 270px; +} +.input-xxlarge { + width: 530px; +} +input[class*="span"], +select[class*="span"], +textarea[class*="span"], +.uneditable-input { + float: none; + margin-left: 0; +} +input.span1, textarea.span1, .uneditable-input.span1 { + width: 50px; +} +input.span2, textarea.span2, .uneditable-input.span2 { + width: 130px; +} +input.span3, textarea.span3, .uneditable-input.span3 { + width: 210px; +} +input.span4, textarea.span4, .uneditable-input.span4 { + width: 290px; +} +input.span5, textarea.span5, .uneditable-input.span5 { + width: 370px; +} +input.span6, textarea.span6, .uneditable-input.span6 { + width: 450px; +} +input.span7, textarea.span7, .uneditable-input.span7 { + width: 530px; +} +input.span8, textarea.span8, .uneditable-input.span8 { + width: 610px; +} +input.span9, textarea.span9, .uneditable-input.span9 { + width: 690px; +} +input.span10, textarea.span10, .uneditable-input.span10 { + width: 770px; +} +input.span11, textarea.span11, .uneditable-input.span11 { + width: 850px; +} +input.span12, textarea.span12, .uneditable-input.span12 { + width: 930px; +} +input[disabled], +select[disabled], +textarea[disabled], +input[readonly], +select[readonly], +textarea[readonly] { + background-color: #f5f5f5; + border-color: #ddd; + cursor: not-allowed; +} +.control-group.warning > label, .control-group.warning .help-block, .control-group.warning .help-inline { + color: #c09853; +} +.control-group.warning input, .control-group.warning select, .control-group.warning textarea { + color: #c09853; + border-color: #c09853; +} +.control-group.warning input:focus, .control-group.warning select:focus, .control-group.warning textarea:focus { + border-color: #a47e3c; + -webkit-box-shadow: 0 0 6px #dbc59e; + -moz-box-shadow: 0 0 6px #dbc59e; + box-shadow: 0 0 6px #dbc59e; +} +.control-group.warning .input-prepend .add-on, .control-group.warning .input-append .add-on { + color: #c09853; + background-color: #fcf8e3; + border-color: #c09853; +} +.control-group.error > label, .control-group.error .help-block, .control-group.error .help-inline { + color: #b94a48; +} +.control-group.error input, .control-group.error select, .control-group.error textarea { + color: #b94a48; + border-color: #b94a48; +} +.control-group.error input:focus, .control-group.error select:focus, .control-group.error textarea:focus { + border-color: #953b39; + -webkit-box-shadow: 0 0 6px #d59392; + -moz-box-shadow: 0 0 6px #d59392; + box-shadow: 0 0 6px #d59392; +} +.control-group.error .input-prepend .add-on, .control-group.error .input-append .add-on { + color: #b94a48; + background-color: #f2dede; + border-color: #b94a48; +} +.control-group.success > label, .control-group.success .help-block, .control-group.success .help-inline { + color: #468847; +} +.control-group.success input, .control-group.success select, .control-group.success textarea { + color: #468847; + border-color: #468847; +} +.control-group.success input:focus, .control-group.success select:focus, .control-group.success textarea:focus { + border-color: #356635; + -webkit-box-shadow: 0 0 6px #7aba7b; + -moz-box-shadow: 0 0 6px #7aba7b; + box-shadow: 0 0 6px #7aba7b; +} +.control-group.success .input-prepend .add-on, .control-group.success .input-append .add-on { + color: #468847; + background-color: #dff0d8; + border-color: #468847; +} +input:focus:required:invalid, textarea:focus:required:invalid, select:focus:required:invalid { + color: #b94a48; + border-color: #ee5f5b; +} +input:focus:required:invalid:focus, textarea:focus:required:invalid:focus, select:focus:required:invalid:focus { + border-color: #e9322d; + -webkit-box-shadow: 0 0 6px #f8b9b7; + -moz-box-shadow: 0 0 6px #f8b9b7; + box-shadow: 0 0 6px #f8b9b7; +} +.form-actions { + padding: 17px 20px 18px; + margin-top: 18px; + margin-bottom: 18px; + background-color: #f5f5f5; + border-top: 1px solid #ddd; +} +.uneditable-input { + display: block; + background-color: #ffffff; + border-color: #eee; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + cursor: not-allowed; +} +:-moz-placeholder { + color: #999999; +} +::-webkit-input-placeholder { + color: #999999; +} +.help-block { + display: block; + margin-top: 5px; + margin-bottom: 0; + color: #999999; +} +.help-inline { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; + margin-bottom: 9px; + vertical-align: middle; + padding-left: 5px; +} +.input-prepend, .input-append { + margin-bottom: 5px; + *zoom: 1; +} +.input-prepend:before, +.input-append:before, +.input-prepend:after, +.input-append:after { + display: table; + content: ""; +} +.input-prepend:after, .input-append:after { + clear: both; +} +.input-prepend input, +.input-append input, +.input-prepend .uneditable-input, +.input-append .uneditable-input { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.input-prepend input:focus, +.input-append input:focus, +.input-prepend .uneditable-input:focus, +.input-append .uneditable-input:focus { + position: relative; + z-index: 2; +} +.input-prepend .uneditable-input, .input-append .uneditable-input { + border-left-color: #ccc; +} +.input-prepend .add-on, .input-append .add-on { + float: left; + display: block; + width: auto; + min-width: 16px; + height: 18px; + margin-right: -1px; + padding: 4px 5px; + font-weight: normal; + line-height: 18px; + color: #999999; + text-align: center; + text-shadow: 0 1px 0 #ffffff; + background-color: #f5f5f5; + border: 1px solid #ccc; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.input-prepend .active, .input-append .active { + background-color: #a9dba9; + border-color: #46a546; +} +.input-prepend .add-on { + *margin-top: 1px; + /* IE6-7 */ + +} +.input-append input, .input-append .uneditable-input { + float: left; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.input-append .uneditable-input { + border-left-color: #eee; + border-right-color: #ccc; +} +.input-append .add-on { + margin-right: 0; + margin-left: -1px; + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.input-append input:first-child { + *margin-left: -160px; +} +.input-append input:first-child + .add-on { + *margin-left: -21px; +} +.search-query { + padding-left: 14px; + padding-right: 14px; + margin-bottom: 0; + -webkit-border-radius: 14px; + -moz-border-radius: 14px; + border-radius: 14px; +} +.form-search input, +.form-inline input, +.form-horizontal input, +.form-search textarea, +.form-inline textarea, +.form-horizontal textarea, +.form-search select, +.form-inline select, +.form-horizontal select, +.form-search .help-inline, +.form-inline .help-inline, +.form-horizontal .help-inline, +.form-search .uneditable-input, +.form-inline .uneditable-input, +.form-horizontal .uneditable-input { + display: inline-block; + margin-bottom: 0; +} +.form-search .hide, .form-inline .hide, .form-horizontal .hide { + display: none; +} +.form-search label, +.form-inline label, +.form-search .input-append, +.form-inline .input-append, +.form-search .input-prepend, +.form-inline .input-prepend { + display: inline-block; +} +.form-search .input-append .add-on, +.form-inline .input-prepend .add-on, +.form-search .input-append .add-on, +.form-inline .input-prepend .add-on { + vertical-align: middle; +} +.form-search .radio, +.form-inline .radio, +.form-search .checkbox, +.form-inline .checkbox { + margin-bottom: 0; + vertical-align: middle; +} +.control-group { + margin-bottom: 9px; +} +legend + .control-group { + margin-top: 18px; + -webkit-margin-top-collapse: separate; +} +.form-horizontal .control-group { + margin-bottom: 18px; + *zoom: 1; +} +.form-horizontal .control-group:before, .form-horizontal .control-group:after { + display: table; + content: ""; +} +.form-horizontal .control-group:after { + clear: both; +} +.form-horizontal .control-label { + float: left; + width: 140px; + padding-top: 5px; + text-align: right; +} +.form-horizontal .controls { + margin-left: 160px; +} +.form-horizontal .form-actions { + padding-left: 160px; +} +table { + max-width: 100%; + border-collapse: collapse; + border-spacing: 0; +} +.table { + width: 100%; + margin-bottom: 18px; +} +.table th, .table td { + padding: 8px; + line-height: 18px; + text-align: left; + vertical-align: top; + border-top: 1px solid #ddd; +} +.table th { + font-weight: bold; +} +.table thead th { + vertical-align: bottom; +} +.table thead:first-child tr th, .table thead:first-child tr td { + border-top: 0; +} +.table tbody + tbody { + border-top: 2px solid #ddd; +} +.table-condensed th, .table-condensed td { + padding: 4px 5px; +} +.table-bordered { + border: 1px solid #ddd; + border-collapse: separate; + *border-collapse: collapsed; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.table-bordered th + th, +.table-bordered td + td, +.table-bordered th + td, +.table-bordered td + th { + border-left: 1px solid #ddd; +} +.table-bordered thead:first-child tr:first-child th, .table-bordered tbody:first-child tr:first-child th, .table-bordered tbody:first-child tr:first-child td { + border-top: 0; +} +.table-bordered thead:first-child tr:first-child th:first-child, .table-bordered tbody:first-child tr:first-child td:first-child { + -webkit-border-radius: 4px 0 0 0; + -moz-border-radius: 4px 0 0 0; + border-radius: 4px 0 0 0; +} +.table-bordered thead:first-child tr:first-child th:last-child, .table-bordered tbody:first-child tr:first-child td:last-child { + -webkit-border-radius: 0 4px 0 0; + -moz-border-radius: 0 4px 0 0; + border-radius: 0 4px 0 0; +} +.table-bordered thead:last-child tr:last-child th:first-child, .table-bordered tbody:last-child tr:last-child td:first-child { + -webkit-border-radius: 0 0 0 4px; + -moz-border-radius: 0 0 0 4px; + border-radius: 0 0 0 4px; +} +.table-bordered thead:last-child tr:last-child th:last-child, .table-bordered tbody:last-child tr:last-child td:last-child { + -webkit-border-radius: 0 0 4px 0; + -moz-border-radius: 0 0 4px 0; + border-radius: 0 0 4px 0; +} +.table-striped tbody tr:nth-child(odd) td, .table-striped tbody tr:nth-child(odd) th { + background-color: #f9f9f9; +} +.table tbody tr:hover td, .table tbody tr:hover th { + background-color: #f5f5f5; +} +table .span1 { + float: none; + width: 44px; + margin-left: 0; +} +table .span2 { + float: none; + width: 124px; + margin-left: 0; +} +table .span3 { + float: none; + width: 204px; + margin-left: 0; +} +table .span4 { + float: none; + width: 284px; + margin-left: 0; +} +table .span5 { + float: none; + width: 364px; + margin-left: 0; +} +table .span6 { + float: none; + width: 444px; + margin-left: 0; +} +table .span7 { + float: none; + width: 524px; + margin-left: 0; +} +table .span8 { + float: none; + width: 604px; + margin-left: 0; +} +table .span9 { + float: none; + width: 684px; + margin-left: 0; +} +table .span10 { + float: none; + width: 764px; + margin-left: 0; +} +table .span11 { + float: none; + width: 844px; + margin-left: 0; +} +table .span12 { + float: none; + width: 924px; + margin-left: 0; +} +[class^="icon-"], [class*=" icon-"] { + display: inline-block; + width: 14px; + height: 14px; + line-height: 14px; + vertical-align: text-top; + background-image: url("../img/glyphicons-halflings.png"); + background-position: 14px 14px; + background-repeat: no-repeat; + *margin-right: .3em; +} +[class^="icon-"]:last-child, [class*=" icon-"]:last-child { + *margin-left: 0; +} +.icon-white { + background-image: url("../img/glyphicons-halflings-white.png"); +} +.icon-glass { + background-position: 0 0; +} +.icon-music { + background-position: -24px 0; +} +.icon-search { + background-position: -48px 0; +} +.icon-envelope { + background-position: -72px 0; +} +.icon-heart { + background-position: -96px 0; +} +.icon-star { + background-position: -120px 0; +} +.icon-star-empty { + background-position: -144px 0; +} +.icon-user { + background-position: -168px 0; +} +.icon-film { + background-position: -192px 0; +} +.icon-th-large { + background-position: -216px 0; +} +.icon-th { + background-position: -240px 0; +} +.icon-th-list { + background-position: -264px 0; +} +.icon-ok { + background-position: -288px 0; +} +.icon-remove { + background-position: -312px 0; +} +.icon-zoom-in { + background-position: -336px 0; +} +.icon-zoom-out { + background-position: -360px 0; +} +.icon-off { + background-position: -384px 0; +} +.icon-signal { + background-position: -408px 0; +} +.icon-cog { + background-position: -432px 0; +} +.icon-trash { + background-position: -456px 0; +} +.icon-home { + background-position: 0 -24px; +} +.icon-file { + background-position: -24px -24px; +} +.icon-time { + background-position: -48px -24px; +} +.icon-road { + background-position: -72px -24px; +} +.icon-download-alt { + background-position: -96px -24px; +} +.icon-download { + background-position: -120px -24px; +} +.icon-upload { + background-position: -144px -24px; +} +.icon-inbox { + background-position: -168px -24px; +} +.icon-play-circle { + background-position: -192px -24px; +} +.icon-repeat { + background-position: -216px -24px; +} +.icon-refresh { + background-position: -240px -24px; +} +.icon-list-alt { + background-position: -264px -24px; +} +.icon-lock { + background-position: -287px -24px; +} +.icon-flag { + background-position: -312px -24px; +} +.icon-headphones { + background-position: -336px -24px; +} +.icon-volume-off { + background-position: -360px -24px; +} +.icon-volume-down { + background-position: -384px -24px; +} +.icon-volume-up { + background-position: -408px -24px; +} +.icon-qrcode { + background-position: -432px -24px; +} +.icon-barcode { + background-position: -456px -24px; +} +.icon-tag { + background-position: 0 -48px; +} +.icon-tags { + background-position: -25px -48px; +} +.icon-book { + background-position: -48px -48px; +} +.icon-bookmark { + background-position: -72px -48px; +} +.icon-print { + background-position: -96px -48px; +} +.icon-camera { + background-position: -120px -48px; +} +.icon-font { + background-position: -144px -48px; +} +.icon-bold { + background-position: -167px -48px; +} +.icon-italic { + background-position: -192px -48px; +} +.icon-text-height { + background-position: -216px -48px; +} +.icon-text-width { + background-position: -240px -48px; +} +.icon-align-left { + background-position: -264px -48px; +} +.icon-align-center { + background-position: -288px -48px; +} +.icon-align-right { + background-position: -312px -48px; +} +.icon-align-justify { + background-position: -336px -48px; +} +.icon-list { + background-position: -360px -48px; +} +.icon-indent-left { + background-position: -384px -48px; +} +.icon-indent-right { + background-position: -408px -48px; +} +.icon-facetime-video { + background-position: -432px -48px; +} +.icon-picture { + background-position: -456px -48px; +} +.icon-pencil { + background-position: 0 -72px; +} +.icon-map-marker { + background-position: -24px -72px; +} +.icon-adjust { + background-position: -48px -72px; +} +.icon-tint { + background-position: -72px -72px; +} +.icon-edit { + background-position: -96px -72px; +} +.icon-share { + background-position: -120px -72px; +} +.icon-check { + background-position: -144px -72px; +} +.icon-move { + background-position: -168px -72px; +} +.icon-step-backward { + background-position: -192px -72px; +} +.icon-fast-backward { + background-position: -216px -72px; +} +.icon-backward { + background-position: -240px -72px; +} +.icon-play { + background-position: -264px -72px; +} +.icon-pause { + background-position: -288px -72px; +} +.icon-stop { + background-position: -312px -72px; +} +.icon-forward { + background-position: -336px -72px; +} +.icon-fast-forward { + background-position: -360px -72px; +} +.icon-step-forward { + background-position: -384px -72px; +} +.icon-eject { + background-position: -408px -72px; +} +.icon-chevron-left { + background-position: -432px -72px; +} +.icon-chevron-right { + background-position: -456px -72px; +} +.icon-plus-sign { + background-position: 0 -96px; +} +.icon-minus-sign { + background-position: -24px -96px; +} +.icon-remove-sign { + background-position: -48px -96px; +} +.icon-ok-sign { + background-position: -72px -96px; +} +.icon-question-sign { + background-position: -96px -96px; +} +.icon-info-sign { + background-position: -120px -96px; +} +.icon-screenshot { + background-position: -144px -96px; +} +.icon-remove-circle { + background-position: -168px -96px; +} +.icon-ok-circle { + background-position: -192px -96px; +} +.icon-ban-circle { + background-position: -216px -96px; +} +.icon-arrow-left { + background-position: -240px -96px; +} +.icon-arrow-right { + background-position: -264px -96px; +} +.icon-arrow-up { + background-position: -289px -96px; +} +.icon-arrow-down { + background-position: -312px -96px; +} +.icon-share-alt { + background-position: -336px -96px; +} +.icon-resize-full { + background-position: -360px -96px; +} +.icon-resize-small { + background-position: -384px -96px; +} +.icon-plus { + background-position: -408px -96px; +} +.icon-minus { + background-position: -433px -96px; +} +.icon-asterisk { + background-position: -456px -96px; +} +.icon-exclamation-sign { + background-position: 0 -120px; +} +.icon-gift { + background-position: -24px -120px; +} +.icon-leaf { + background-position: -48px -120px; +} +.icon-fire { + background-position: -72px -120px; +} +.icon-eye-open { + background-position: -96px -120px; +} +.icon-eye-close { + background-position: -120px -120px; +} +.icon-warning-sign { + background-position: -144px -120px; +} +.icon-plane { + background-position: -168px -120px; +} +.icon-calendar { + background-position: -192px -120px; +} +.icon-random { + background-position: -216px -120px; +} +.icon-comment { + background-position: -240px -120px; +} +.icon-magnet { + background-position: -264px -120px; +} +.icon-chevron-up { + background-position: -288px -120px; +} +.icon-chevron-down { + background-position: -313px -119px; +} +.icon-retweet { + background-position: -336px -120px; +} +.icon-shopping-cart { + background-position: -360px -120px; +} +.icon-folder-close { + background-position: -384px -120px; +} +.icon-folder-open { + background-position: -408px -120px; +} +.icon-resize-vertical { + background-position: -432px -119px; +} +.icon-resize-horizontal { + background-position: -456px -118px; +} +.dropdown { + position: relative; +} +.dropdown-toggle { + *margin-bottom: -3px; +} +.dropdown-toggle:active, .open .dropdown-toggle { + outline: 0; +} +.caret { + display: inline-block; + width: 0; + height: 0; + text-indent: -99999px; + *text-indent: 0; + vertical-align: top; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 4px solid #000000; + opacity: 0.3; + filter: alpha(opacity=30); + content: "\2193"; +} +.dropdown .caret { + margin-top: 8px; + margin-left: 2px; +} +.dropdown:hover .caret, .open.dropdown .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + float: left; + display: none; + min-width: 160px; + _width: 160px; + padding: 4px 0; + margin: 0; + list-style: none; + background-color: #ffffff; + border-color: #ccc; + border-color: rgba(0, 0, 0, 0.2); + border-style: solid; + border-width: 1px; + -webkit-border-radius: 0 0 5px 5px; + -moz-border-radius: 0 0 5px 5px; + border-radius: 0 0 5px 5px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; + *border-right-width: 2px; + *border-bottom-width: 2px; +} +.dropdown-menu.bottom-up { + top: auto; + bottom: 100%; + margin-bottom: 2px; +} +.dropdown-menu .divider { + height: 1px; + margin: 5px 1px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #ffffff; + *width: 100%; + *margin: -5px 0 5px; +} +.dropdown-menu a { + display: block; + padding: 3px 15px; + clear: both; + font-weight: normal; + line-height: 18px; + color: #555555; + white-space: nowrap; +} +.dropdown-menu li > a:hover, .dropdown-menu .active > a, .dropdown-menu .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #0088cc; +} +.dropdown.open { + *z-index: 1000; +} +.dropdown.open .dropdown-toggle { + color: #ffffff; + background: #ccc; + background: rgba(0, 0, 0, 0.3); +} +.dropdown.open .dropdown-menu { + display: block; +} +.typeahead { + margin-top: 2px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #f5f5f5; + border: 1px solid #eee; + border: 1px solid rgba(0, 0, 0, 0.05); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 0, 0, 0.15); +} +.fade { + -webkit-transition: opacity 0.15s linear; + -moz-transition: opacity 0.15s linear; + -ms-transition: opacity 0.15s linear; + -o-transition: opacity 0.15s linear; + transition: opacity 0.15s linear; + opacity: 0; +} +.fade.in { + opacity: 1; +} +.collapse { + -webkit-transition: height 0.35s ease; + -moz-transition: height 0.35s ease; + -ms-transition: height 0.35s ease; + -o-transition: height 0.35s ease; + transition: height 0.35s ease; + position: relative; + overflow: hidden; + height: 0; +} +.collapse.in { + height: auto; +} +.close { + float: right; + font-size: 20px; + font-weight: bold; + line-height: 18px; + color: #000000; + text-shadow: 0 1px 0 #ffffff; + opacity: 0.2; + filter: alpha(opacity=20); +} +.close:hover { + color: #000000; + text-decoration: none; + opacity: 0.4; + filter: alpha(opacity=40); + cursor: pointer; +} +.btn { + display: inline-block; + padding: 4px 10px 4px; + margin-bottom: 0; + font-size: 13px; + line-height: 18px; + color: #333333; + text-align: center; + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); + vertical-align: middle; + background-color: #f5f5f5; + background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); + background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); + background-image: linear-gradient(top, #ffffff, #e6e6e6); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0); + border-color: #e6e6e6 #e6e6e6 #bfbfbf; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + border: 1px solid #ccc; + border-bottom-color: #bbb; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + cursor: pointer; + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + *margin-left: .3em; +} +.btn:hover, +.btn:active, +.btn.active, +.btn.disabled, +.btn[disabled] { + background-color: #e6e6e6; +} +.btn:active, .btn.active { + background-color: #cccccc \9; +} +.btn:first-child { + *margin-left: 0; +} +.btn:hover { + color: #333333; + text-decoration: none; + background-color: #e6e6e6; + background-position: 0 -15px; + -webkit-transition: background-position 0.1s linear; + -moz-transition: background-position 0.1s linear; + -ms-transition: background-position 0.1s linear; + -o-transition: background-position 0.1s linear; + transition: background-position 0.1s linear; +} +.btn:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.btn.active, .btn:active { + background-image: none; + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + background-color: #e6e6e6; + background-color: #d9d9d9 \9; + outline: 0; +} +.btn.disabled, .btn[disabled] { + cursor: default; + background-image: none; + background-color: #e6e6e6; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +.btn-large { + padding: 9px 14px; + font-size: 15px; + line-height: normal; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.btn-large [class^="icon-"] { + margin-top: 1px; +} +.btn-small { + padding: 5px 9px; + font-size: 11px; + line-height: 16px; +} +.btn-small [class^="icon-"] { + margin-top: -1px; +} +.btn-mini { + padding: 2px 6px; + font-size: 11px; + line-height: 14px; +} +.btn-primary, +.btn-primary:hover, +.btn-warning, +.btn-warning:hover, +.btn-danger, +.btn-danger:hover, +.btn-success, +.btn-success:hover, +.btn-info, +.btn-info:hover, +.btn-inverse, +.btn-inverse:hover { + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + color: #ffffff; +} +.btn-primary.active, +.btn-warning.active, +.btn-danger.active, +.btn-success.active, +.btn-info.active, +.btn-dark.active { + color: rgba(255, 255, 255, 0.75); +} +.btn-primary { + background-color: #006dcc; + background-image: -moz-linear-gradient(top, #0088cc, #0044cc); + background-image: -ms-linear-gradient(top, #0088cc, #0044cc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); + background-image: -o-linear-gradient(top, #0088cc, #0044cc); + background-image: linear-gradient(top, #0088cc, #0044cc); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); + border-color: #0044cc #0044cc #002a80; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-primary:hover, +.btn-primary:active, +.btn-primary.active, +.btn-primary.disabled, +.btn-primary[disabled] { + background-color: #0044cc; +} +.btn-primary:active, .btn-primary.active { + background-color: #003399 \9; +} +.btn-warning { + background-color: #faa732; + background-image: -moz-linear-gradient(top, #fbb450, #f89406); + background-image: -ms-linear-gradient(top, #fbb450, #f89406); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); + background-image: -webkit-linear-gradient(top, #fbb450, #f89406); + background-image: -o-linear-gradient(top, #fbb450, #f89406); + background-image: linear-gradient(top, #fbb450, #f89406); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0); + border-color: #f89406 #f89406 #ad6704; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-warning:hover, +.btn-warning:active, +.btn-warning.active, +.btn-warning.disabled, +.btn-warning[disabled] { + background-color: #f89406; +} +.btn-warning:active, .btn-warning.active { + background-color: #c67605 \9; +} +.btn-danger { + background-color: #da4f49; + background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -ms-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -o-linear-gradient(top, #ee5f5b, #bd362f); + background-image: linear-gradient(top, #ee5f5b, #bd362f); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0); + border-color: #bd362f #bd362f #802420; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-danger:hover, +.btn-danger:active, +.btn-danger.active, +.btn-danger.disabled, +.btn-danger[disabled] { + background-color: #bd362f; +} +.btn-danger:active, .btn-danger.active { + background-color: #942a25 \9; +} +.btn-success { + background-color: #5bb75b; + background-image: -moz-linear-gradient(top, #62c462, #51a351); + background-image: -ms-linear-gradient(top, #62c462, #51a351); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351)); + background-image: -webkit-linear-gradient(top, #62c462, #51a351); + background-image: -o-linear-gradient(top, #62c462, #51a351); + background-image: linear-gradient(top, #62c462, #51a351); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0); + border-color: #51a351 #51a351 #387038; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-success:hover, +.btn-success:active, +.btn-success.active, +.btn-success.disabled, +.btn-success[disabled] { + background-color: #51a351; +} +.btn-success:active, .btn-success.active { + background-color: #408140 \9; +} +.btn-info { + background-color: #49afcd; + background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -ms-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4)); + background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -o-linear-gradient(top, #5bc0de, #2f96b4); + background-image: linear-gradient(top, #5bc0de, #2f96b4); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0); + border-color: #2f96b4 #2f96b4 #1f6377; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-info:hover, +.btn-info:active, +.btn-info.active, +.btn-info.disabled, +.btn-info[disabled] { + background-color: #2f96b4; +} +.btn-info:active, .btn-info.active { + background-color: #24748c \9; +} +.btn-inverse { + background-color: #393939; + background-image: -moz-linear-gradient(top, #454545, #262626); + background-image: -ms-linear-gradient(top, #454545, #262626); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#454545), to(#262626)); + background-image: -webkit-linear-gradient(top, #454545, #262626); + background-image: -o-linear-gradient(top, #454545, #262626); + background-image: linear-gradient(top, #454545, #262626); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#454545', endColorstr='#262626', GradientType=0); + border-color: #262626 #262626 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-inverse:hover, +.btn-inverse:active, +.btn-inverse.active, +.btn-inverse.disabled, +.btn-inverse[disabled] { + background-color: #262626; +} +.btn-inverse:active, .btn-inverse.active { + background-color: #0c0c0c \9; +} +button.btn, input[type="submit"].btn { + *padding-top: 2px; + *padding-bottom: 2px; +} +button.btn::-moz-focus-inner, input[type="submit"].btn::-moz-focus-inner { + padding: 0; + border: 0; +} +button.btn.large, input[type="submit"].btn.large { + *padding-top: 7px; + *padding-bottom: 7px; +} +button.btn.small, input[type="submit"].btn.small { + *padding-top: 3px; + *padding-bottom: 3px; +} +.btn-group { + position: relative; + *zoom: 1; + *margin-left: .3em; +} +.btn-group:before, .btn-group:after { + display: table; + content: ""; +} +.btn-group:after { + clear: both; +} +.btn-group:first-child { + *margin-left: 0; +} +.btn-group + .btn-group { + margin-left: 5px; +} +.btn-toolbar { + margin-top: 9px; + margin-bottom: 9px; +} +.btn-toolbar .btn-group { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; +} +.btn-group .btn { + position: relative; + float: left; + margin-left: -1px; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.btn-group .btn:first-child { + margin-left: 0; + -webkit-border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; + border-top-left-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + border-bottom-left-radius: 4px; +} +.btn-group .btn:last-child, .btn-group .dropdown-toggle { + -webkit-border-top-right-radius: 4px; + -moz-border-radius-topright: 4px; + border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -moz-border-radius-bottomright: 4px; + border-bottom-right-radius: 4px; +} +.btn-group .btn.large:first-child { + margin-left: 0; + -webkit-border-top-left-radius: 6px; + -moz-border-radius-topleft: 6px; + border-top-left-radius: 6px; + -webkit-border-bottom-left-radius: 6px; + -moz-border-radius-bottomleft: 6px; + border-bottom-left-radius: 6px; +} +.btn-group .btn.large:last-child, .btn-group .large.dropdown-toggle { + -webkit-border-top-right-radius: 6px; + -moz-border-radius-topright: 6px; + border-top-right-radius: 6px; + -webkit-border-bottom-right-radius: 6px; + -moz-border-radius-bottomright: 6px; + border-bottom-right-radius: 6px; +} +.btn-group .btn:hover, +.btn-group .btn:focus, +.btn-group .btn:active, +.btn-group .btn.active { + z-index: 2; +} +.btn-group .dropdown-toggle:active, .btn-group.open .dropdown-toggle { + outline: 0; +} +.btn-group .dropdown-toggle { + padding-left: 8px; + padding-right: 8px; + -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + *padding-top: 5px; + *padding-bottom: 5px; +} +.btn-group.open { + *z-index: 1000; +} +.btn-group.open .dropdown-menu { + display: block; + margin-top: 1px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.btn-group.open .dropdown-toggle { + background-image: none; + -webkit-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); +} +.btn .caret { + margin-top: 7px; + margin-left: 0; +} +.btn:hover .caret, .open.btn-group .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.btn-primary .caret, +.btn-danger .caret, +.btn-info .caret, +.btn-success .caret, +.btn-inverse .caret { + border-top-color: #ffffff; + opacity: 0.75; + filter: alpha(opacity=75); +} +.btn-small .caret { + margin-top: 4px; +} +.alert { + padding: 8px 35px 8px 14px; + margin-bottom: 18px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + background-color: #fcf8e3; + border: 1px solid #fbeed5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.alert, .alert-heading { + color: #c09853; +} +.alert .close { + position: relative; + top: -2px; + right: -21px; + line-height: 18px; +} +.alert-success { + background-color: #dff0d8; + border-color: #d6e9c6; +} +.alert-success, .alert-success .alert-heading { + color: #468847; +} +.alert-danger, .alert-error { + background-color: #f2dede; + border-color: #eed3d7; +} +.alert-danger, +.alert-error, +.alert-danger .alert-heading, +.alert-error .alert-heading { + color: #b94a48; +} +.alert-info { + background-color: #d9edf7; + border-color: #bce8f1; +} +.alert-info, .alert-info .alert-heading { + color: #3a87ad; +} +.alert-block { + padding-top: 14px; + padding-bottom: 14px; +} +.alert-block > p, .alert-block > ul { + margin-bottom: 0; +} +.alert-block p + p { + margin-top: 5px; +} +.nav { + margin-left: 0; + margin-bottom: 18px; + list-style: none; +} +.nav > li > a { + display: block; +} +.nav > li > a:hover { + text-decoration: none; + background-color: #eeeeee; +} +.nav .nav-header { + display: block; + padding: 3px 15px; + font-size: 11px; + font-weight: bold; + line-height: 18px; + color: #999999; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + text-transform: uppercase; +} +.nav li + .nav-header { + margin-top: 9px; +} +.nav-list { + padding-left: 14px; + padding-right: 14px; + margin-bottom: 0; +} +.nav-list > li > a, .nav-list .nav-header { + margin-left: -15px; + margin-right: -15px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); +} +.nav-list > li > a { + padding: 3px 15px; +} +.nav-list .active > a, .nav-list .active > a:hover { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); + background-color: #0088cc; +} +.nav-list [class^="icon-"] { + margin-right: 2px; +} +.nav-tabs, .nav-pills { + *zoom: 1; +} +.nav-tabs:before, +.nav-pills:before, +.nav-tabs:after, +.nav-pills:after { + display: table; + content: ""; +} +.nav-tabs:after, .nav-pills:after { + clear: both; +} +.nav-tabs > li, .nav-pills > li { + float: left; +} +.nav-tabs > li > a, .nav-pills > li > a { + padding-right: 12px; + padding-left: 12px; + margin-right: 2px; + line-height: 14px; +} +.nav-tabs { + border-bottom: 1px solid #ddd; +} +.nav-tabs > li { + margin-bottom: -1px; +} +.nav-tabs > li > a { + padding-top: 9px; + padding-bottom: 9px; + border: 1px solid transparent; + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} +.nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #dddddd; +} +.nav-tabs > .active > a, .nav-tabs > .active > a:hover { + color: #555555; + background-color: #ffffff; + border: 1px solid #ddd; + border-bottom-color: transparent; + cursor: default; +} +.nav-pills > li > a { + padding-top: 8px; + padding-bottom: 8px; + margin-top: 2px; + margin-bottom: 2px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.nav-pills .active > a, .nav-pills .active > a:hover { + color: #ffffff; + background-color: #0088cc; +} +.nav-stacked > li { + float: none; +} +.nav-stacked > li > a { + margin-right: 0; +} +.nav-tabs.nav-stacked { + border-bottom: 0; +} +.nav-tabs.nav-stacked > li > a { + border: 1px solid #ddd; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.nav-tabs.nav-stacked > li:first-child > a { + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} +.nav-tabs.nav-stacked > li:last-child > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} +.nav-tabs.nav-stacked > li > a:hover { + border-color: #ddd; + z-index: 2; +} +.nav-pills.nav-stacked > li > a { + margin-bottom: 3px; +} +.nav-pills.nav-stacked > li:last-child > a { + margin-bottom: 1px; +} +.nav-tabs .dropdown-menu, .nav-pills .dropdown-menu { + margin-top: 1px; + border-width: 1px; +} +.nav-pills .dropdown-menu { + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.nav-tabs .dropdown-toggle .caret, .nav-pills .dropdown-toggle .caret { + border-top-color: #0088cc; + margin-top: 6px; +} +.nav-tabs .dropdown-toggle:hover .caret, .nav-pills .dropdown-toggle:hover .caret { + border-top-color: #005580; +} +.nav-tabs .active .dropdown-toggle .caret, .nav-pills .active .dropdown-toggle .caret { + border-top-color: #333333; +} +.nav > .dropdown.active > a:hover { + color: #000000; + cursor: pointer; +} +.nav-tabs .open .dropdown-toggle, .nav-pills .open .dropdown-toggle, .nav > .open.active > a:hover { + color: #ffffff; + background-color: #999999; + border-color: #999999; +} +.nav .open .caret, .nav .open.active .caret, .nav .open a:hover .caret { + border-top-color: #ffffff; + opacity: 1; + filter: alpha(opacity=100); +} +.tabs-stacked .open > a:hover { + border-color: #999999; +} +.tabbable { + *zoom: 1; +} +.tabbable:before, .tabbable:after { + display: table; + content: ""; +} +.tabbable:after { + clear: both; +} +.tab-content { + overflow: hidden; +} +.tabs-below .nav-tabs, .tabs-right .nav-tabs, .tabs-left .nav-tabs { + border-bottom: 0; +} +.tab-content > .tab-pane, .pill-content > .pill-pane { + display: none; +} +.tab-content > .active, .pill-content > .active { + display: block; +} +.tabs-below .nav-tabs { + border-top: 1px solid #ddd; +} +.tabs-below .nav-tabs > li { + margin-top: -1px; + margin-bottom: 0; +} +.tabs-below .nav-tabs > li > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} +.tabs-below .nav-tabs > li > a:hover { + border-bottom-color: transparent; + border-top-color: #ddd; +} +.tabs-below .nav-tabs .active > a, .tabs-below .nav-tabs .active > a:hover { + border-color: transparent #ddd #ddd #ddd; +} +.tabs-left .nav-tabs > li, .tabs-right .nav-tabs > li { + float: none; +} +.tabs-left .nav-tabs > li > a, .tabs-right .nav-tabs > li > a { + min-width: 74px; + margin-right: 0; + margin-bottom: 3px; +} +.tabs-left .nav-tabs { + float: left; + margin-right: 19px; + border-right: 1px solid #ddd; +} +.tabs-left .nav-tabs > li > a { + margin-right: -1px; + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} +.tabs-left .nav-tabs > li > a:hover { + border-color: #eeeeee #dddddd #eeeeee #eeeeee; +} +.tabs-left .nav-tabs .active > a, .tabs-left .nav-tabs .active > a:hover { + border-color: #ddd transparent #ddd #ddd; + *border-right-color: #ffffff; +} +.tabs-right .nav-tabs { + float: right; + margin-left: 19px; + border-left: 1px solid #ddd; +} +.tabs-right .nav-tabs > li > a { + margin-left: -1px; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} +.tabs-right .nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #eeeeee #dddddd; +} +.tabs-right .nav-tabs .active > a, .tabs-right .nav-tabs .active > a:hover { + border-color: #ddd #ddd #ddd transparent; + *border-left-color: #ffffff; +} +.navbar { + overflow: visible; + margin-bottom: 18px; +} +.navbar-inner { + padding-left: 20px; + padding-right: 20px; + background-color: #2c2c2c; + background-image: -moz-linear-gradient(top, #333333, #222222); + background-image: -ms-linear-gradient(top, #333333, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); + background-image: -webkit-linear-gradient(top, #333333, #222222); + background-image: -o-linear-gradient(top, #333333, #222222); + background-image: linear-gradient(top, #333333, #222222); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); +} +.btn-navbar { + display: none; + float: right; + padding: 7px 10px; + margin-left: 5px; + margin-right: 5px; + background-color: #2c2c2c; + background-image: -moz-linear-gradient(top, #333333, #222222); + background-image: -ms-linear-gradient(top, #333333, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); + background-image: -webkit-linear-gradient(top, #333333, #222222); + background-image: -o-linear-gradient(top, #333333, #222222); + background-image: linear-gradient(top, #333333, #222222); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); + border-color: #222222 #222222 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); +} +.btn-navbar:hover, +.btn-navbar:active, +.btn-navbar.active, +.btn-navbar.disabled, +.btn-navbar[disabled] { + background-color: #222222; +} +.btn-navbar:active, .btn-navbar.active { + background-color: #080808 \9; +} +.btn-navbar .icon-bar { + display: block; + width: 18px; + height: 2px; + background-color: #f5f5f5; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; + -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); +} +.btn-navbar .icon-bar + .icon-bar { + margin-top: 3px; +} +.nav-collapse.collapse { + height: auto; +} +.navbar .brand:hover { + text-decoration: none; +} +.navbar .brand { + float: left; + display: block; + padding: 8px 20px 12px; + margin-left: -20px; + font-size: 20px; + font-weight: 200; + line-height: 1; + color: #ffffff; +} +.navbar .navbar-text { + margin-bottom: 0; + line-height: 40px; + color: #999999; +} +.navbar .navbar-text a:hover { + color: #ffffff; + background-color: transparent; +} +.navbar .btn, .navbar .btn-group { + margin-top: 5px; +} +.navbar .btn-group .btn { + margin-top: 0; +} +.navbar-form { + margin-bottom: 0; + *zoom: 1; +} +.navbar-form:before, .navbar-form:after { + display: table; + content: ""; +} +.navbar-form:after { + clear: both; +} +.navbar-form input, .navbar-form select { + display: inline-block; + margin-top: 5px; + margin-bottom: 0; +} +.navbar-form .radio, .navbar-form .checkbox { + margin-top: 5px; +} +.navbar-form input[type="image"], .navbar-form input[type="checkbox"], .navbar-form input[type="radio"] { + margin-top: 3px; +} +.navbar-form .input-append, .navbar-form .input-prepend { + margin-top: 6px; + white-space: nowrap; +} +.navbar-form .input-append input, .navbar-form .input-prepend input { + margin-top: 0; +} +.navbar-search { + position: relative; + float: left; + margin-top: 6px; + margin-bottom: 0; +} +.navbar-search .search-query { + padding: 4px 9px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + font-weight: normal; + line-height: 1; + color: #ffffff; + color: rgba(255, 255, 255, 0.75); + background: #666; + background: rgba(255, 255, 255, 0.3); + border: 1px solid #111; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + -webkit-transition: none; + -moz-transition: none; + -ms-transition: none; + -o-transition: none; + transition: none; +} +.navbar-search .search-query :-moz-placeholder { + color: #eeeeee; +} +.navbar-search .search-query::-webkit-input-placeholder { + color: #eeeeee; +} +.navbar-search .search-query:hover { + color: #ffffff; + background-color: #999999; + background-color: rgba(255, 255, 255, 0.5); +} +.navbar-search .search-query:focus, .navbar-search .search-query.focused { + padding: 5px 10px; + color: #333333; + text-shadow: 0 1px 0 #ffffff; + background-color: #ffffff; + border: 0; + -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + outline: 0; +} +.navbar-fixed-top { + position: fixed; + top: 0; + right: 0; + left: 0; + z-index: 1030; +} +.navbar-fixed-top .navbar-inner { + padding-left: 0; + padding-right: 0; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.navbar .nav { + position: relative; + left: 0; + display: block; + float: left; + margin: 0 10px 0 0; +} +.navbar .nav.pull-right { + float: right; +} +.navbar .nav > li { + display: block; + float: left; +} +.navbar .nav > li > a { + float: none; + padding: 10px 10px 11px; + line-height: 19px; + color: #999999; + text-decoration: none; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.navbar .nav > li > a:hover { + background-color: transparent; + color: #ffffff; + text-decoration: none; +} +.navbar .nav .active > a, .navbar .nav .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #222222; +} +.navbar .divider-vertical { + height: 40px; + width: 1px; + margin: 0 9px; + overflow: hidden; + background-color: #222222; + border-right: 1px solid #333333; +} +.navbar .nav.pull-right { + margin-left: 10px; + margin-right: 0; +} +.navbar .dropdown-menu { + margin-top: 1px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.navbar .dropdown-menu:before { + content: ''; + display: inline-block; + border-left: 7px solid transparent; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-bottom-color: rgba(0, 0, 0, 0.2); + position: absolute; + top: -7px; + left: 9px; +} +.navbar .dropdown-menu:after { + content: ''; + display: inline-block; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid #ffffff; + position: absolute; + top: -6px; + left: 10px; +} +.navbar .nav .dropdown-toggle .caret, .navbar .nav .open.dropdown .caret { + border-top-color: #ffffff; +} +.navbar .nav .active .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.navbar .nav .open > .dropdown-toggle, .navbar .nav .active > .dropdown-toggle, .navbar .nav .open.active > .dropdown-toggle { + background-color: transparent; +} +.navbar .nav .active > .dropdown-toggle:hover { + color: #ffffff; +} +.navbar .nav.pull-right .dropdown-menu { + left: auto; + right: 0; +} +.navbar .nav.pull-right .dropdown-menu:before { + left: auto; + right: 12px; +} +.navbar .nav.pull-right .dropdown-menu:after { + left: auto; + right: 13px; +} +.breadcrumb { + padding: 7px 14px; + margin: 0 0 18px; + background-color: #fbfbfb; + background-image: -moz-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -ms-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5)); + background-image: -webkit-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -o-linear-gradient(top, #ffffff, #f5f5f5); + background-image: linear-gradient(top, #ffffff, #f5f5f5); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0); + border: 1px solid #ddd; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; +} +.breadcrumb li { + display: inline-block; + text-shadow: 0 1px 0 #ffffff; +} +.breadcrumb .divider { + padding: 0 5px; + color: #999999; +} +.breadcrumb .active a { + color: #333333; +} +.pagination { + height: 36px; + margin: 18px 0; +} +.pagination ul { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; + margin-left: 0; + margin-bottom: 0; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); +} +.pagination li { + display: inline; +} +.pagination a { + float: left; + padding: 0 14px; + line-height: 34px; + text-decoration: none; + border: 1px solid #ddd; + border-left-width: 0; +} +.pagination a:hover, .pagination .active a { + background-color: #f5f5f5; +} +.pagination .active a { + color: #999999; + cursor: default; +} +.pagination .disabled a, .pagination .disabled a:hover { + color: #999999; + background-color: transparent; + cursor: default; +} +.pagination li:first-child a { + border-left-width: 1px; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.pagination li:last-child a { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.pagination-centered { + text-align: center; +} +.pagination-right { + text-align: right; +} +.pager { + margin-left: 0; + margin-bottom: 18px; + list-style: none; + text-align: center; + *zoom: 1; +} +.pager:before, .pager:after { + display: table; + content: ""; +} +.pager:after { + clear: both; +} +.pager li { + display: inline; +} +.pager a { + display: inline-block; + padding: 5px 14px; + background-color: #fff; + border: 1px solid #ddd; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} +.pager a:hover { + text-decoration: none; + background-color: #f5f5f5; +} +.pager .next a { + float: right; +} +.pager .previous a { + float: left; +} +.modal-open .dropdown-menu { + z-index: 2050; +} +.modal-open .dropdown.open { + *z-index: 2050; +} +.modal-open .popover { + z-index: 2060; +} +.modal-open .tooltip { + z-index: 2070; +} +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + background-color: #000000; +} +.modal-backdrop.fade { + opacity: 0; +} +.modal-backdrop, .modal-backdrop.fade.in { + opacity: 0.8; + filter: alpha(opacity=80); +} +.modal { + position: fixed; + top: 50%; + left: 50%; + z-index: 1050; + max-height: 500px; + overflow: auto; + width: 560px; + margin: -250px 0 0 -280px; + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + /* IE6-7 */ + + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.wide-modal { + position: fixed; + top: 5%; + left: 5%; + z-index: 1050; + max-height: 90%; + overflow: auto; + width: 90%; + /*margin: -50px 0 0 -80px;*/ + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + /* IE6-7 */ + + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.modal.fade { + -webkit-transition: opacity .3s linear, top .3s ease-out; + -moz-transition: opacity .3s linear, top .3s ease-out; + -ms-transition: opacity .3s linear, top .3s ease-out; + -o-transition: opacity .3s linear, top .3s ease-out; + transition: opacity .3s linear, top .3s ease-out; + top: -25%; +} +.modal.fade.in { + top: 50%; +} +.modal-header { + padding: 9px 15px; + border-bottom: 1px solid #eee; +} +.modal-header .close { + margin-top: 2px; +} +.modal-body { + padding: 15px; +} +.modal-body .modal-form { + margin-bottom: 0; +} +.modal-footer { + padding: 14px 15px 15px; + margin-bottom: 0; + background-color: #f5f5f5; + border-top: 1px solid #ddd; + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; + *zoom: 1; +} +.modal-footer:before, .modal-footer:after { + display: table; + content: ""; +} +.modal-footer:after { + clear: both; +} +.modal-footer .btn { + float: right; + margin-left: 5px; + margin-bottom: 0; +} +.tooltip { + position: absolute; + z-index: 1020; + display: block; + visibility: visible; + padding: 5px; + font-size: 11px; + opacity: 0; + filter: alpha(opacity=0); +} +.tooltip.in { + opacity: 0.8; + filter: alpha(opacity=80); +} +.tooltip.top { + margin-top: -2px; +} +.tooltip.right { + margin-left: 2px; +} +.tooltip.bottom { + margin-top: 2px; +} +.tooltip.left { + margin-left: -2px; +} +.tooltip.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid #000000; +} +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #000000; +} +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-bottom: 5px solid #000000; +} +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-right: 5px solid #000000; +} +.tooltip-inner { + max-width: 200px; + padding: 3px 8px; + color: #ffffff; + text-align: center; + text-decoration: none; + background-color: #000000; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; +} +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1010; + display: none; + padding: 5px; +} +.popover.top { + margin-top: -5px; +} +.popover.right { + margin-left: 5px; +} +.popover.bottom { + margin-top: 5px; +} +.popover.left { + margin-left: -5px; +} +.popover.top .arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid #000000; +} +.popover.right .arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-right: 5px solid #000000; +} +.popover.bottom .arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-bottom: 5px solid #000000; +} +.popover.left .arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #000000; +} +.popover .arrow { + position: absolute; + width: 0; + height: 0; +} +.popover-inner { + padding: 3px; + width: 280px; + overflow: hidden; + background: #000000; + background: rgba(0, 0, 0, 0.8); + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); +} +.popover-title { + padding: 9px 15px; + line-height: 1; + background-color: #f5f5f5; + border-bottom: 1px solid #eee; + -webkit-border-radius: 3px 3px 0 0; + -moz-border-radius: 3px 3px 0 0; + border-radius: 3px 3px 0 0; +} +.popover-content { + padding: 14px; + background-color: #ffffff; + -webkit-border-radius: 0 0 3px 3px; + -moz-border-radius: 0 0 3px 3px; + border-radius: 0 0 3px 3px; + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.popover-content p, .popover-content ul, .popover-content ol { + margin-bottom: 0; +} +.thumbnails { + margin-left: -20px; + list-style: none; + *zoom: 1; +} +.thumbnails:before, .thumbnails:after { + display: table; + content: ""; +} +.thumbnails:after { + clear: both; +} +.thumbnails > li { + float: left; + margin: 0 0 18px 20px; +} +.thumbnail { + display: block; + padding: 4px; + line-height: 1; + border: 1px solid #ddd; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); +} +a.thumbnail:hover { + border-color: #0088cc; + -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); +} +.thumbnail > img { + display: block; + max-width: 100%; + margin-left: auto; + margin-right: auto; +} +.thumbnail .caption { + padding: 9px; +} +.label { + padding: 2px 4px 3px; + font-size: 11.049999999999999px; + font-weight: bold; + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #999999; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.label:hover { + color: #ffffff; + text-decoration: none; +} +.label-important { + background-color: #b94a48; +} +.label-important:hover { + background-color: #953b39; +} +.label-warning { + background-color: #f89406; +} +.label-warning:hover { + background-color: #c67605; +} +.label-success { + background-color: #468847; +} +.label-success:hover { + background-color: #356635; +} +.label-info { + background-color: #3a87ad; +} +.label-info:hover { + background-color: #2d6987; +} +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +@-moz-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +@keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +.progress { + overflow: hidden; + height: 18px; + margin-bottom: 18px; + background-color: #f7f7f7; + background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -ms-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9)); + background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: linear-gradient(top, #f5f5f5, #f9f9f9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0); + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.progress .bar { + width: 0%; + height: 18px; + color: #ffffff; + font-size: 12px; + text-align: center; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #0e90d2; + background-image: -moz-linear-gradient(top, #149bdf, #0480be); + background-image: -ms-linear-gradient(top, #149bdf, #0480be); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be)); + background-image: -webkit-linear-gradient(top, #149bdf, #0480be); + background-image: -o-linear-gradient(top, #149bdf, #0480be); + background-image: linear-gradient(top, #149bdf, #0480be); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0); + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition: width 0.6s ease; + -moz-transition: width 0.6s ease; + -ms-transition: width 0.6s ease; + -o-transition: width 0.6s ease; + transition: width 0.6s ease; +} +.progress-striped .bar { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + -webkit-background-size: 40px 40px; + -moz-background-size: 40px 40px; + -o-background-size: 40px 40px; + background-size: 40px 40px; +} +.progress.active .bar { + -webkit-animation: progress-bar-stripes 2s linear infinite; + -moz-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} +.progress-danger .bar { + background-color: #dd514c; + background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -o-linear-gradient(top, #ee5f5b, #c43c35); + background-image: linear-gradient(top, #ee5f5b, #c43c35); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0); +} +.progress-danger.progress-striped .bar { + background-color: #ee5f5b; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-success .bar { + background-color: #5eb95e; + background-image: -moz-linear-gradient(top, #62c462, #57a957); + background-image: -ms-linear-gradient(top, #62c462, #57a957); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957)); + background-image: -webkit-linear-gradient(top, #62c462, #57a957); + background-image: -o-linear-gradient(top, #62c462, #57a957); + background-image: linear-gradient(top, #62c462, #57a957); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0); +} +.progress-success.progress-striped .bar { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-info .bar { + background-color: #4bb1cf; + background-image: -moz-linear-gradient(top, #5bc0de, #339bb9); + background-image: -ms-linear-gradient(top, #5bc0de, #339bb9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9)); + background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9); + background-image: -o-linear-gradient(top, #5bc0de, #339bb9); + background-image: linear-gradient(top, #5bc0de, #339bb9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0); +} +.progress-info.progress-striped .bar { + background-color: #5bc0de; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.accordion { + margin-bottom: 18px; +} +.accordion-group { + margin-bottom: 2px; + border: 1px solid #e5e5e5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.accordion-heading { + border-bottom: 0; +} +.accordion-heading .accordion-toggle { + display: block; + padding: 8px 15px; +} +.accordion-inner { + padding: 9px 15px; + border-top: 1px solid #e5e5e5; +} +.carousel { + position: relative; + margin-bottom: 18px; + line-height: 1; +} +.carousel-inner { + overflow: hidden; + width: 100%; + position: relative; +} +.carousel .item { + display: none; + position: relative; + -webkit-transition: 0.6s ease-in-out left; + -moz-transition: 0.6s ease-in-out left; + -ms-transition: 0.6s ease-in-out left; + -o-transition: 0.6s ease-in-out left; + transition: 0.6s ease-in-out left; +} +.carousel .item > img { + display: block; + line-height: 1; +} +.carousel .active, .carousel .next, .carousel .prev { + display: block; +} +.carousel .active { + left: 0; +} +.carousel .next, .carousel .prev { + position: absolute; + top: 0; + width: 100%; +} +.carousel .next { + left: 100%; +} +.carousel .prev { + left: -100%; +} +.carousel .next.left, .carousel .prev.right { + left: 0; +} +.carousel .active.left { + left: -100%; +} +.carousel .active.right { + left: 100%; +} +.carousel-control { + position: absolute; + top: 40%; + left: 15px; + width: 40px; + height: 40px; + margin-top: -20px; + font-size: 60px; + font-weight: 100; + line-height: 30px; + color: #ffffff; + text-align: center; + background: #222222; + border: 3px solid #ffffff; + -webkit-border-radius: 23px; + -moz-border-radius: 23px; + border-radius: 23px; + opacity: 0.5; + filter: alpha(opacity=50); +} +.carousel-control.right { + left: auto; + right: 15px; +} +.carousel-control:hover { + color: #ffffff; + text-decoration: none; + opacity: 0.9; + filter: alpha(opacity=90); +} +.carousel-caption { + position: absolute; + left: 0; + right: 0; + bottom: 0; + padding: 10px 15px 5px; + background: #333333; + background: rgba(0, 0, 0, 0.75); +} +.carousel-caption h4, .carousel-caption p { + color: #ffffff; +} +.hero-unit { + padding: 60px; + margin-bottom: 30px; + background-color: #f5f5f5; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} +.hero-unit h1 { + margin-bottom: 0; + font-size: 60px; + line-height: 1; + letter-spacing: -1px; +} +.hero-unit p { + font-size: 18px; + font-weight: 200; + line-height: 27px; +} +.pull-right { + float: right; +} +.pull-left { + float: left; +} +.hide { + display: none; +} +.show { + display: block; +} +.invisible { + visibility: hidden; +} diff --git a/src/nl/astraeus/jdbc/web/resources/images/loading.gif b/src/nl/astraeus/jdbc/web/resources/images/loading.gif new file mode 100644 index 0000000..21c7e74 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/images/loading.gif Binary files differ diff --git a/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png b/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png new file mode 100644 index 0000000..92d4445 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png Binary files differ diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-alert.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-alert.js new file mode 100644 index 0000000..2242ddd --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-alert.js @@ -0,0 +1,94 @@ +/* ========================================================== + * bootstrap-alert.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#alerts + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function( $ ){ + + "use strict" + + /* ALERT CLASS DEFINITION + * ====================== */ + + var dismiss = '[data-dismiss="alert"]' + , Alert = function ( el ) { + $(el).on('click', dismiss, this.close) + } + + Alert.prototype = { + + constructor: Alert + + , close: function ( e ) { + var $this = $(this) + , selector = $this.attr('data-target') + , $parent + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = $(selector) + $parent.trigger('close') + + e && e.preventDefault() + + $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent()) + + $parent + .trigger('close') + .removeClass('in') + + function removeElement() { + $parent + .trigger('closed') + .remove() + } + + $.support.transition && $parent.hasClass('fade') ? + $parent.on($.support.transition.end, removeElement) : + removeElement() + } + + } + + + /* ALERT PLUGIN DEFINITION + * ======================= */ + + $.fn.alert = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('alert') + if (!data) $this.data('alert', (data = new Alert(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.alert.Constructor = Alert + + + /* ALERT DATA-API + * ============== */ + + $(function () { + $('body').on('click.alert.data-api', dismiss, Alert.prototype.close) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-button.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-button.js new file mode 100644 index 0000000..0238ca3 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-button.js @@ -0,0 +1,100 @@ +/* ============================================================ + * bootstrap-button.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#buttons + * ============================================================ + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + +!function( $ ){ + + "use strict" + + /* BUTTON PUBLIC CLASS DEFINITION + * ============================== */ + + var Button = function ( element, options ) { + this.$element = $(element) + this.options = $.extend({}, $.fn.button.defaults, options) + } + + Button.prototype = { + + constructor: Button + + , setState: function ( state ) { + var d = 'disabled' + , $el = this.$element + , data = $el.data() + , val = $el.is('input') ? 'val' : 'html' + + state = state + 'Text' + data.resetText || $el.data('resetText', $el[val]()) + + $el[val](data[state] || this.options[state]) + + // push to event loop to allow forms to submit + setTimeout(function () { + state == 'loadingText' ? + $el.addClass(d).attr(d, d) : + $el.removeClass(d).removeAttr(d) + }, 0) + } + + , toggle: function () { + var $parent = this.$element.parent('[data-toggle="buttons-radio"]') + + $parent && $parent + .find('.active') + .removeClass('active') + + this.$element.toggleClass('active') + } + + } + + + /* BUTTON PLUGIN DEFINITION + * ======================== */ + + $.fn.button = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('button') + , options = typeof option == 'object' && option + if (!data) $this.data('button', (data = new Button(this, options))) + if (option == 'toggle') data.toggle() + else if (option) data.setState(option) + }) + } + + $.fn.button.defaults = { + loadingText: 'loading...' + } + + $.fn.button.Constructor = Button + + + /* BUTTON DATA-API + * =============== */ + + $(function () { + $('body').on('click.button.data-api', '[data-toggle^=button]', function ( e ) { + var $btn = $(e.target) + if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') + $btn.button('toggle') + }) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-carousel.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-carousel.js new file mode 100644 index 0000000..810256e --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-carousel.js @@ -0,0 +1,157 @@ +/* ========================================================== + * bootstrap-carousel.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#carousel + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function( $ ){ + + "use strict" + + /* CAROUSEL CLASS DEFINITION + * ========================= */ + + var Carousel = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, $.fn.carousel.defaults, options) + this.options.slide && this.slide(this.options.slide) + } + + Carousel.prototype = { + + cycle: function () { + this.interval = setInterval($.proxy(this.next, this), this.options.interval) + return this + } + + , to: function (pos) { + var $active = this.$element.find('.active') + , children = $active.parent().children() + , activePos = children.index($active) + , that = this + + if (pos > (children.length - 1) || pos < 0) return + + if (this.sliding) { + return this.$element.one('slid', function () { + that.to(pos) + }) + } + + if (activePos == pos) { + return this.pause().cycle() + } + + return this.slide(pos > activePos ? 'next' : 'prev', $(children[pos])) + } + + , pause: function () { + clearInterval(this.interval) + this.interval = null + return this + } + + , next: function () { + if (this.sliding) return + return this.slide('next') + } + + , prev: function () { + if (this.sliding) return + return this.slide('prev') + } + + , slide: function (type, next) { + var $active = this.$element.find('.active') + , $next = next || $active[type]() + , isCycling = this.interval + , direction = type == 'next' ? 'left' : 'right' + , fallback = type == 'next' ? 'first' : 'last' + , that = this + + if (!$next.length) return + + this.sliding = true + + isCycling && this.pause() + + $next = $next.length ? $next : this.$element.find('.item')[fallback]() + + if (!$.support.transition && this.$element.hasClass('slide')) { + this.$element.trigger('slide') + $active.removeClass('active') + $next.addClass('active') + this.sliding = false + this.$element.trigger('slid') + } else { + $next.addClass(type) + $next[0].offsetWidth // force reflow + $active.addClass(direction) + $next.addClass(direction) + this.$element.trigger('slide') + this.$element.one($.support.transition.end, function () { + $next.removeClass([type, direction].join(' ')).addClass('active') + $active.removeClass(['active', direction].join(' ')) + that.sliding = false + setTimeout(function () { that.$element.trigger('slid') }, 0) + }) + } + + isCycling && this.cycle() + + return this + } + + } + + + /* CAROUSEL PLUGIN DEFINITION + * ========================== */ + + $.fn.carousel = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('carousel') + , options = typeof option == 'object' && option + if (!data) $this.data('carousel', (data = new Carousel(this, options))) + if (typeof option == 'number') data.to(option) + else if (typeof option == 'string' || (option = options.slide)) data[option]() + else data.cycle() + }) + } + + $.fn.carousel.defaults = { + interval: 5000 + } + + $.fn.carousel.Constructor = Carousel + + + /* CAROUSEL DATA-API + * ================= */ + + $(function () { + $('body').on('click.carousel.data-api', '[data-slide]', function ( e ) { + var $this = $(this), href + , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 + , options = !$target.data('modal') && $.extend({}, $target.data(), $this.data()) + $target.carousel(options) + e.preventDefault() + }) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f403193 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..73ff239 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..3b00020 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..275077f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/README b/README deleted file mode 100644 index 734abaf..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -This file was created by IntelliJ IDEA 11.1.1 for binding GitHub repository \ No newline at end of file diff --git a/Simple-jdbc-statistics.iml b/Simple-jdbc-statistics.iml new file mode 100644 index 0000000..ca90a9b --- /dev/null +++ b/Simple-jdbc-statistics.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/lib/h2-1.3.166.jar b/lib/h2-1.3.166.jar new file mode 100644 index 0000000..4985063 --- /dev/null +++ b/lib/h2-1.3.166.jar Binary files differ diff --git a/lib/servlet-api-2.5.jar b/lib/servlet-api-2.5.jar new file mode 100644 index 0000000..20b5755 --- /dev/null +++ b/lib/servlet-api-2.5.jar Binary files differ diff --git a/lib/slf4j-api-1.6.4.jar b/lib/slf4j-api-1.6.4.jar new file mode 100644 index 0000000..4d23f41 --- /dev/null +++ b/lib/slf4j-api-1.6.4.jar Binary files differ diff --git a/lib/slf4j-simple-1.6.4.jar b/lib/slf4j-simple-1.6.4.jar new file mode 100644 index 0000000..3d1b8d9 --- /dev/null +++ b/lib/slf4j-simple-1.6.4.jar Binary files differ diff --git a/lib/ssr-0.1.jar b/lib/ssr-0.1.jar new file mode 100644 index 0000000..65dfcf4 --- /dev/null +++ b/lib/ssr-0.1.jar Binary files differ diff --git a/lib/vst-0.4.jar b/lib/vst-0.4.jar new file mode 100644 index 0000000..db63792 --- /dev/null +++ b/lib/vst-0.4.jar Binary files differ diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..ac2dbe1 --- /dev/null +++ b/readme.md @@ -0,0 +1 @@ +A simple wrapper around jdbc drivers what will show current jdbc stats of the running queries on a simple web page on port 18080. \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/ConnectionLogger.java b/src/nl/astraeus/jdbc/ConnectionLogger.java new file mode 100644 index 0000000..c3e243f --- /dev/null +++ b/src/nl/astraeus/jdbc/ConnectionLogger.java @@ -0,0 +1,279 @@ +package nl.astraeus.jdbc; + +import java.sql.*; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Executor; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:12:34 PM + */ +public class ConnectionLogger implements Connection { + private Connection connection; + + private long milli; + private long nano; + private String lastSql; + + public ConnectionLogger(Connection connection) { + this.connection = connection; + this.lastSql = ""; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(QueryType.UNKNOWN, sql, m, n); + } + + public void commit() throws SQLException { + clearTime(); + + connection.commit(); + + log("commit"); + } + + public void rollback() throws SQLException { + clearTime(); + + connection.rollback(); + + log("rollback"); + } + + public void close() throws SQLException { + clearTime(); + + connection.close(); + + log("close"); + } + + public PreparedStatement prepareStatement(String sql) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, autoGeneratedKeys); + } + + public PreparedStatement prepareStatement(String sql, int columnIndexes[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnIndexes); + } + + public PreparedStatement prepareStatement(String sql, String columnNames[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnNames); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public Statement createStatement() throws SQLException { + return connection.createStatement(); + } + + public CallableStatement prepareCall(String sql) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql); + } + + public String nativeSQL(String sql) throws SQLException { + lastSql = sql; + return connection.nativeSQL(sql); + } + + public void setAutoCommit(boolean autoCommit) throws SQLException { + connection.setAutoCommit(autoCommit); + } + + public boolean getAutoCommit() throws SQLException { + return connection.getAutoCommit(); + } + + public boolean isClosed() throws SQLException { + return connection.isClosed(); + } + + public DatabaseMetaData getMetaData() throws SQLException { + return connection.getMetaData(); + } + + public void setReadOnly(boolean readOnly) throws SQLException { + connection.setReadOnly(readOnly); + } + + public boolean isReadOnly() throws SQLException { + return connection.isReadOnly(); + } + + public void setCatalog(String catalog) throws SQLException { + connection.setCatalog(catalog); + } + + public String getCatalog() throws SQLException { + return connection.getCatalog(); + } + + public void setTransactionIsolation(int level) throws SQLException { + connection.setTransactionIsolation(level); + } + + public int getTransactionIsolation() throws SQLException { + return connection.getTransactionIsolation(); + } + + public SQLWarning getWarnings() throws SQLException { + return connection.getWarnings(); + } + + public void clearWarnings() throws SQLException { + connection.clearWarnings(); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency); + } + + public Map> getTypeMap() throws SQLException { + return connection.getTypeMap(); + } + + public void setTypeMap(Map> map) throws SQLException { + connection.setTypeMap(map); + } + + public void setHoldability(int holdability) throws SQLException { + connection.setHoldability(holdability); + } + + public int getHoldability() throws SQLException { + return connection.getHoldability(); + } + + public Savepoint setSavepoint() throws SQLException { + return connection.setSavepoint(); + } + + public Savepoint setSavepoint(String name) throws SQLException { + return connection.setSavepoint(name); + } + + public void rollback(Savepoint savepoint) throws SQLException { + connection.rollback(); + } + + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + connection.releaseSavepoint(savepoint); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public Clob createClob() throws SQLException { + return connection.createClob(); + } + + public Blob createBlob() throws SQLException { + return connection.createBlob(); + } + + public NClob createNClob() throws SQLException { + return connection.createNClob(); + } + + public SQLXML createSQLXML() throws SQLException { + return connection.createSQLXML(); + } + + public boolean isValid(int timeout) throws SQLException { + return connection.isValid(timeout); + } + + public void setClientInfo(String name, String value) throws SQLClientInfoException { + connection.setClientInfo(name, value); + } + + public void setClientInfo(Properties properties) throws SQLClientInfoException { + connection.setClientInfo(properties); + } + + public String getClientInfo(String name) throws SQLException { + return connection.getClientInfo(name); + } + + public Properties getClientInfo() throws SQLException { + return connection.getClientInfo(); + } + + public Array createArrayOf(String typeName, Object[] elements) throws SQLException { + return connection.createArrayOf(typeName, elements); + } + + public Struct createStruct(String typeName, Object[] attributes) throws SQLException { + return connection.createStruct(typeName, attributes); + } + + @Override + public void setSchema(String schema) throws SQLException { + connection.setSchema(schema); + } + + @Override + public String getSchema() throws SQLException { + return connection.getSchema(); + } + + @Override + public void abort(Executor executor) throws SQLException { + connection.abort(executor); + } + + @Override + public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { + connection.setNetworkTimeout(executor, milliseconds); + } + + @Override + public int getNetworkTimeout() throws SQLException { + return connection.getNetworkTimeout(); + } + + public T unwrap(Class iface) throws SQLException { + return connection.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return connection.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/Driver.java b/src/nl/astraeus/jdbc/Driver.java new file mode 100644 index 0000000..8317172 --- /dev/null +++ b/src/nl/astraeus/jdbc/Driver.java @@ -0,0 +1,116 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.http.SimpleWebServer; +import nl.astraeus.jdbc.web.JdbcStatisticsServlet; +import nl.astraeus.jdbc.web.ResourceServlet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.*; +import java.util.Enumeration; +import java.util.Properties; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:54:37 PM + */ +public class Driver implements java.sql.Driver { + private final static Logger log = LoggerFactory.getLogger(Driver.class); + + final private static String URL_PREFIX = "jdbc:stat:"; + + private java.sql.Driver driver = null; + private String[] drivers = { + "org.postgresql.Driver", + "oracle.jdbc.driver.OracleDriver", + "com.sybase.jdbc2.jdbc.SybDriver", + "net.sourceforge.jtds.jdbc.Driver", + "com.microsoft.jdbc.sqlserver.SQLServerDriver", + "com.microsoft.sqlserver.jdbc.SQLServerDriver", + "weblogic.jdbc.sqlserver.SQLServerDriver", + "com.informix.jdbc.IfxDriver", + "org.apache.derby.jdbc.ClientDriver", + "org.apache.derby.jdbc.EmbeddedDriver", + "com.mysql.jdbc.Driver", + "org.hsqldb.jdbcDriver", + "org.h2.Driver" }; + + static { + log.debug("Loading driver class " + Driver.class.getName()); + + try { + DriverManager.registerDriver(new Driver()); + } catch (SQLException e) { + log.error("", e); + } + } + + public Driver() { + for (String dr : drivers) { + try { + Class.forName(dr); + } catch (Throwable e) { + log.debug("Can't instantiate driver: " + dr, e); + } + } + } + + private java.sql.Driver findDriver(String url) throws SQLException { + Enumeration e = DriverManager.getDrivers(); + + while (e.hasMoreElements()) { + java.sql.Driver d = (java.sql.Driver) e.nextElement(); + + if (d.acceptsURL(url)) { + return d; + } + } + + throw new SQLException("Driver not found: " + url); + } + + public Connection connect(String url, Properties info) throws SQLException { + url = url.substring(URL_PREFIX.length()); + + if (driver == null) { + driver = findDriver(url); + } + + if (driver != null) { + SimpleWebServer server = new SimpleWebServer(18080); + + server.addServlet(new JdbcStatisticsServlet(), "/"); + server.addServlet(new ResourceServlet(), "/resources/*"); + + server.start(); + } + + return new ConnectionLogger(driver.connect(url, info)); + } + + public boolean acceptsURL(String url) throws SQLException { + return (url != null && url.startsWith(URL_PREFIX)); + } + + public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { + return driver.getPropertyInfo(url, info); + } + + public int getMajorVersion() { + return driver.getMajorVersion(); + } + + public int getMinorVersion() { + return driver.getMinorVersion(); + } + + public boolean jdbcCompliant() { + return driver.jdbcCompliant(); + } + + @Override + public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException { + return driver.getParentLogger(); + } +} diff --git a/src/nl/astraeus/jdbc/JdbcLogger.java b/src/nl/astraeus/jdbc/JdbcLogger.java new file mode 100644 index 0000000..f4bc125 --- /dev/null +++ b/src/nl/astraeus/jdbc/JdbcLogger.java @@ -0,0 +1,113 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.jdbc.util.Util; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/** + * User: riennentjes + * Date: Jul 12, 2008 + * Time: 9:15:21 AM + */ +public class JdbcLogger { + private final static Logger logger = LoggerFactory.getLogger(JdbcLogger.class); + + private final static JdbcLogger instance = new JdbcLogger(); + + public static JdbcLogger get() { + return instance; + } + + public final static class LogEntry { + public QueryType type; + public String sql; + public long milli; + public long nano; + public int count; + public int hash; + + public LogEntry(int hash, QueryType type, String sql, long milli, long nano) { + this.hash = hash; + this.type = type; + this.sql = sql; + this.milli = milli; + this.nano = nano; + this.count = 1; + } + + public void addCount(long milli, long nano) { + synchronized (this) { + count++; + this.milli += milli; + this.nano += nano; + } + } + + public int getCount() { + return count; + } + + public String getMilli() { + return Util.formatNano(milli*1000000/count); + } + + public String getNano() { + return Util.formatNano(nano/count); + } + + public String getTotal() { + return Util.formatNano(nano); + } + + public String getSql() { + return sql; + } + } + + private Map queries; + + public JdbcLogger() { + queries = new ConcurrentHashMap(); + } + + public void logEntry(QueryType type, String sql, long milli, long nano) { + int hash = sql.hashCode(); + LogEntry entry = queries.get(hash); + + if (entry == null) { + entry = new LogEntry(hash, type, sql, milli, nano); + queries.put(hash, entry); + } else { + entry.addCount(milli, nano); + } + + if (queries.size() > 1000) { + List toRemove = new LinkedList(); + List values = new LinkedList(queries.values()); + + Collections.sort(values, new Comparator() { + @Override + public int compare(LogEntry o1, LogEntry o2) { + return o1.count - o2.count; + } + }); + + while (queries.size() > 900) { + queries.remove(values.remove(0).hash); + + } + } + } + + public static void log(QueryType type, String sql, long milli, long nano) { + instance.logEntry(type, sql, milli, nano); + } + + public Collection getEntries() { + return queries.values(); + } + +} diff --git a/src/nl/astraeus/jdbc/PreparedStatementLogger.java b/src/nl/astraeus/jdbc/PreparedStatementLogger.java new file mode 100644 index 0000000..98aefc7 --- /dev/null +++ b/src/nl/astraeus/jdbc/PreparedStatementLogger.java @@ -0,0 +1,577 @@ +package nl.astraeus.jdbc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.InputStream; +import java.io.Reader; +import java.math.BigDecimal; +import java.net.URL; +import java.sql.*; +import java.util.Calendar; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 7:47:57 PM + */ +public class PreparedStatementLogger implements PreparedStatement { + private final static Logger log = LoggerFactory.getLogger(PreparedStatementLogger.class); + + private PreparedStatement statement; + + private String sql; + private QueryType type; + private long milli; + private long nano; + + //private ArrayList parameters; + + public PreparedStatementLogger(PreparedStatement statement) { + this.statement = statement; + this.sql = ""; + this.type = QueryType.UNKNOWN; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(QueryType type, String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(type, sql, m, n); + } + + public PreparedStatementLogger(Connection connection, String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql); + } + + public PreparedStatementLogger(Connection connection, String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatementLogger(Connection connection, String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, autoGeneratedKeys); + } + + public PreparedStatementLogger(Connection connection, String sql, int[] columnIndexes) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnIndexes); + } + + public PreparedStatementLogger(Connection connection, String sql, String[] columnNames) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnNames); + } + + public boolean execute() throws SQLException { + clearTime(); + + boolean result = statement.execute(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery() throws SQLException { + clearTime(); + + ResultSet result = statement.executeQuery(); + + log(type, sql); + + return result; + } + + public int executeUpdate() throws SQLException { + clearTime(); + + int result = statement.executeUpdate(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + ResultSet result = statement.executeQuery(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnNames); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnNames); + + log(type, sql); + + return result; + } + + + public void setNull(int parameterIndex, int sqlType) throws SQLException { + statement.setNull(parameterIndex, sqlType); + } + + public void setBoolean(int parameterIndex, boolean x) throws SQLException { + statement.setBoolean(parameterIndex, x); + } + + public void setByte(int parameterIndex, byte x) throws SQLException { + statement.setByte(parameterIndex, x); + } + + public void setShort(int parameterIndex, short x) throws SQLException { + statement.setShort(parameterIndex, x); + } + + public void setInt(int parameterIndex, int x) throws SQLException { + statement.setInt(parameterIndex, x); + } + + public void setLong(int parameterIndex, long x) throws SQLException { + statement.setLong(parameterIndex, x); + } + + public void setFloat(int parameterIndex, float x) throws SQLException { + statement.setFloat(parameterIndex, x); + } + + public void setDouble(int parameterIndex, double x) throws SQLException { + statement.setDouble(parameterIndex, x); + } + + public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { + statement.setBigDecimal(parameterIndex, x); + } + + public void setString(int parameterIndex, String x) throws SQLException { + statement.setString(parameterIndex, x); + } + + public void setBytes(int parameterIndex, byte x[]) throws SQLException { + statement.setBytes(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x) throws SQLException { + statement.setDate(parameterIndex, x); + } + + public void setTime(int parameterIndex, Time x) throws SQLException { + statement.setTime(parameterIndex, x); + } + + public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { + statement.setTimestamp(parameterIndex, x); + } + + public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setUnicodeStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType); + } + + public void setObject(int parameterIndex, Object x) throws SQLException { + statement.setObject(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setRef(int parameterIndex, Ref x) throws SQLException { + statement.setRef(parameterIndex, x); + } + + public void setBlob(int parameterIndex, Blob x) throws SQLException { + statement.setBlob(parameterIndex, x); + } + + public void setClob(int parameterIndex, Clob x) throws SQLException { + statement.setClob(parameterIndex, x); + } + + public void setArray(int parameterIndex, Array x) throws SQLException { + statement.setArray(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { + statement.setDate(parameterIndex, x, cal); + } + + public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { + statement.setTime(parameterIndex, x, cal); + } + + public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { + statement.setTimestamp(parameterIndex, x, cal); + } + + public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException { + statement.setNull(parameterIndex, sqlType, typeName); + } + + public void setURL(int parameterIndex, URL x) throws SQLException { + statement.setURL(parameterIndex, x); + } + + public void setRowId(int parameterIndex, RowId x) throws SQLException { + statement.setRowId(parameterIndex, x); + } + + public void setNString(int parameterIndex, String value) throws SQLException { + statement.setNString(parameterIndex, value); + } + + public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException { + statement.setNCharacterStream(parameterIndex, value, length); + } + + public void setNClob(int parameterIndex, NClob value) throws SQLException { + statement.setNClob(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setClob(parameterIndex, reader, length); + } + + public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException { + statement.setBlob(parameterIndex, inputStream, length); + } + + public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setNClob(parameterIndex, reader, length); + } + + public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException { + statement.setSQLXML(parameterIndex, xmlObject); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType, scaleOrLength); + } + + public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException { + statement.setAsciiStream(parameterIndex, x); + } + + public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException { + statement.setBinaryStream(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException { + statement.setCharacterStream(parameterIndex, reader); + } + + public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException { + statement.setNCharacterStream(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader) throws SQLException { + statement.setClob(parameterIndex, reader); + } + + public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException { + statement.setBlob(parameterIndex, inputStream); + } + + public void setNClob(int parameterIndex, Reader reader) throws SQLException { + statement.setNClob(parameterIndex, reader); + } + + + public void close() throws SQLException { + sql = ""; + type = QueryType.UNKNOWN; + milli = 0; + nano = 0; + + statement.close(); + } + + public ResultSetMetaData getMetaData() throws SQLException { + return statement.getMetaData(); + } + + public void clearParameters() throws SQLException { + statement.clearParameters(); + } + + public ParameterMetaData getParameterMetaData() throws SQLException { + return statement.getParameterMetaData(); + } + + public void addBatch() throws SQLException { + statement.addBatch(); + } + + public int getMaxFieldSize() throws SQLException { + return statement.getMaxFieldSize(); + } + + public void setMaxFieldSize(int max) throws SQLException { + statement.setMaxFieldSize(max); + } + + public int getMaxRows() throws SQLException { + return statement.getMaxRows(); + } + + public void setMaxRows(int max) throws SQLException { + statement.setMaxRows(max); + } + + public void setEscapeProcessing(boolean enable) throws SQLException { + statement.setEscapeProcessing(enable); + } + + public int getQueryTimeout() throws SQLException { + return statement.getQueryTimeout(); + } + + public void setQueryTimeout(int seconds) throws SQLException { + statement.setQueryTimeout(seconds); + } + + public void cancel() throws SQLException { + statement.cancel(); + } + + public SQLWarning getWarnings() throws SQLException { + return statement.getWarnings(); + } + + public void clearWarnings() throws SQLException { + statement.clearWarnings(); + } + + public void setCursorName(String name) throws SQLException { + statement.setCursorName(name); + } + + public boolean execute(String sql) throws SQLException { + return statement.execute(sql); + } + + public ResultSet getResultSet() throws SQLException { + return statement.getResultSet(); + } + + public int getUpdateCount() throws SQLException { + return statement.getUpdateCount(); + } + + public boolean getMoreResults() throws SQLException { + return statement.getMoreResults(); + } + + public void setFetchDirection(int direction) throws SQLException { + statement.setFetchDirection(direction); + } + + public int getFetchDirection() throws SQLException { + return statement.getFetchDirection(); + } + + public void setFetchSize(int rows) throws SQLException { + statement.setFetchSize(rows); + } + + public int getFetchSize() throws SQLException { + return statement.getFetchSize(); + } + + public int getResultSetConcurrency() throws SQLException { + return statement.getResultSetConcurrency(); + } + + public int getResultSetType() throws SQLException { + return statement.getResultSetType(); + } + + public void addBatch(String sql) throws SQLException { + statement.addBatch(sql); + } + + public void clearBatch() throws SQLException { + statement.clearBatch(); + } + + public int[] executeBatch() throws SQLException { + return statement.executeBatch(); + } + + public Connection getConnection() throws SQLException { + return statement.getConnection(); + } + + public boolean getMoreResults(int current) throws SQLException { + return statement.getMoreResults(current); + } + + public ResultSet getGeneratedKeys() throws SQLException { + return statement.getGeneratedKeys(); + } + + public int getResultSetHoldability() throws SQLException { + return statement.getResultSetHoldability(); + } + + public boolean isClosed() throws SQLException { + return statement.isClosed(); + } + + public void setPoolable(boolean poolable) throws SQLException { + statement.setPoolable(poolable); + } + + public boolean isPoolable() throws SQLException { + return statement.isPoolable(); + } + + @Override + public void closeOnCompletion() throws SQLException { + statement.closeOnCompletion();; + } + + @Override + public boolean isCloseOnCompletion() throws SQLException { + return statement.isCloseOnCompletion(); + } + + public T unwrap(Class iface) throws SQLException { + return statement.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return statement.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/QueryType.java b/src/nl/astraeus/jdbc/QueryType.java new file mode 100644 index 0000000..744fbfc --- /dev/null +++ b/src/nl/astraeus/jdbc/QueryType.java @@ -0,0 +1,24 @@ +package nl.astraeus.jdbc; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:32:49 PM + */ +public enum QueryType { + PLAIN("plain"), + PREPARED("prepared"), + CALLABLE("callable"), + UNKNOWN("unknown"); + + private String description; + + QueryType(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } + +} diff --git a/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java new file mode 100644 index 0000000..07aac40 --- /dev/null +++ b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java @@ -0,0 +1,68 @@ +package nl.astraeus.jdbc.example; + +import java.sql.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 7:32 PM + */ +public class JdbcStatisticsExample { + + + public static void main(String [] args) throws Exception { + Class.forName("org.h2.Driver"); + Class.forName("nl.astraeus.jdbc.Driver"); + + new JdbcStatisticsExample(); + } + + public JdbcStatisticsExample() throws Exception { + Connection conn = DriverManager.getConnection("jdbc:stat:jdbc:h2:mem:test"); + + Statement statement = null; + + statement = conn.createStatement(); + statement.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + + boolean running = true; + int count = 1; + PreparedStatement ps = null; + + while (running) { + Thread.sleep(10); + + String TableName = "TEST"+(System.nanoTime() % 1000); + + try { + ps = conn.prepareStatement("SELECT COUNT(*) FROM "+TableName); + ResultSet rs = ps.executeQuery(); + } catch (SQLException e) { + statement = conn.createStatement(); + statement.execute("CREATE TABLE "+TableName+" (ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + } finally { + if (ps!=null) { + ps.close(); + } + } + + ps = conn.prepareStatement("INSERT INTO "+TableName+" VALUES (?, ?)"); + + ps.setInt(1, count++); + ps.setString(2, "String "+System.currentTimeMillis()); + + ps.execute(); + ps.close(); + + Thread.sleep(10); + + ps = conn.prepareStatement("SELECT * FROM "+TableName); + ResultSet rs = ps.executeQuery(); + statement.close(); + } + + conn.close(); + } +} diff --git a/src/nl/astraeus/jdbc/util/IOUtils.java b/src/nl/astraeus/jdbc/util/IOUtils.java new file mode 100644 index 0000000..ce95d9d --- /dev/null +++ b/src/nl/astraeus/jdbc/util/IOUtils.java @@ -0,0 +1,38 @@ +package nl.astraeus.jdbc.util; + +import java.io.*; + +/** + * User: rnentjes + * Date: 4/9/12 + * Time: 2:33 PM + */ +public class IOUtils { + + public static String toString(InputStream in) throws IOException { + assert in != null; + + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + StringBuilder buffer = new StringBuilder(); + + while(reader.ready()) { + buffer.append(reader.readLine()); + buffer.append("\n"); + } + + return buffer.toString(); + } finally { + in.close(); + } + } + + public static void copy(InputStream in, OutputStream out) throws IOException { + byte [] buffer = new byte[1<<16]; + int bytes; + + while((bytes = in.read(buffer)) > 0) { + out.write(buffer, 0, bytes); + } + } +} diff --git a/src/nl/astraeus/jdbc/util/Util.java b/src/nl/astraeus/jdbc/util/Util.java new file mode 100644 index 0000000..eaa853b --- /dev/null +++ b/src/nl/astraeus/jdbc/util/Util.java @@ -0,0 +1,25 @@ +package nl.astraeus.jdbc.util; + +import java.text.DecimalFormat; +import java.text.NumberFormat; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 12:28 PM + */ +public class Util { + // utility functions + public static String formatNano(long l) { + NumberFormat format = new DecimalFormat("###,##0.000000"); + + return format.format((double) l / 1000000.0); + } + + public static void printMemoryUsage() { + System.out.println("Used memory: "+((Runtime.getRuntime().totalMemory() / (1024*1024))-(Runtime.getRuntime().freeMemory() / (1024*1024)))); + System.out.println("Free memory: "+(Runtime.getRuntime().freeMemory() / (1024*1024))); + System.out.println("Total memory: "+(Runtime.getRuntime().totalMemory() / (1024*1024))); + System.out.println("Max memory: "+(Runtime.getRuntime().maxMemory() / (1024*1024))); + } +} diff --git a/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java b/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java new file mode 100644 index 0000000..a162d6f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java @@ -0,0 +1,90 @@ +package nl.astraeus.jdbc.web; + +import nl.astraeus.jdbc.util.IOUtils; +import nl.astraeus.jdbc.util.Util; +import nl.astraeus.jdbc.web.page.Menu; +import nl.astraeus.jdbc.web.page.Page; +import nl.astraeus.jdbc.web.page.QueryOverview; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import java.io.IOException; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:05 PM + */ +public class JdbcStatisticsServlet extends HttpServlet { + + private String head; + private String bottom; + + @Override + public void init() throws ServletException { + super.init(); + + try { + head = IOUtils.toString(getClass().getResourceAsStream("head.html")); + bottom = IOUtils.toString(getClass().getResourceAsStream("bottom.html")); + } catch (IOException e) { + throw new ServletException(e); + } + + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + doPost(req, resp); + } + + @Override + protected void doPost(final HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + long nano = System.nanoTime(); + + HttpSession session = req.getSession(); + boolean ajax = "true".equals(req.getParameter("ajax")); + + resp.setContentType("text/html"); + + Page page = (Page)session.getAttribute("page"); + Page menu = (Page)session.getAttribute("menu"); + + session.setMaxInactiveInterval(1800); + + if (menu == null) { + menu = new Menu(); + + session.setAttribute("menu", menu); + } + + if (page == null || "menumain".equals(req.getParameter("action"))) { + page = new QueryOverview(); + } else if ("diagnostics".equals(req.getParameter("action"))) { + //page = new Diagnostics(); + } else { + page = page .processRequest(req); + } + + menu.processRequest(req); + + session.setAttribute("page", page); + + if (!ajax) { + resp.getWriter().print(head); + } + + resp.getWriter().print(menu.render(req)); + resp.getWriter().print(page.render(req)); + + if (!ajax) { + resp.getWriter().print(bottom); + } + + System.out.println("Request ends, time="+ Util.formatNano(System.nanoTime() - nano) +", page="+page.getClass().getSimpleName()); + } + +} diff --git a/src/nl/astraeus/jdbc/web/ResourceServlet.java b/src/nl/astraeus/jdbc/web/ResourceServlet.java new file mode 100644 index 0000000..7abfe6f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/ResourceServlet.java @@ -0,0 +1,49 @@ +package nl.astraeus.jdbc.web; + +import nl.astraeus.jdbc.util.IOUtils; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.InputStream; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:05 PM + */ +public class ResourceServlet extends HttpServlet { + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String uri = req.getRequestURI(); + + uri = "nl/astraeus/jdbc/web" + uri; + InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(uri); + + if (in == null) { + resp.sendError(404, "Cannot find resource '" + uri + "'."); + } else { + try { + if (uri.endsWith("js")) { + resp.setContentType("text/javascript"); + } else if (uri.endsWith("css")) { + resp.setContentType("text/css"); + } else if (uri.endsWith("png")) { + resp.setContentType("image/png"); + } else if (uri.endsWith("jpg")) { + resp.setContentType("image/jpeg"); + } else if (uri.endsWith("gif")) { + resp.setContentType("image/gif"); + } + + IOUtils.copy(in, resp.getOutputStream()); + } finally { + in.close(); + } + } + } + +} diff --git a/src/nl/astraeus/jdbc/web/bottom.html b/src/nl/astraeus/jdbc/web/bottom.html new file mode 100644 index 0000000..1288de4 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/bottom.html @@ -0,0 +1,8 @@ + + +
+ + + + + \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/head.html b/src/nl/astraeus/jdbc/web/head.html new file mode 100644 index 0000000..0f8f6a3 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/head.html @@ -0,0 +1,96 @@ + + + + + + + Simple JDBC Statistics + + + + + + + + + + + + + + + + + + + +
+
+ +
+ diff --git a/src/nl/astraeus/jdbc/web/page/Menu.html b/src/nl/astraeus/jdbc/web/page/Menu.html new file mode 100644 index 0000000..505c7c2 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.html @@ -0,0 +1,42 @@ + diff --git a/src/nl/astraeus/jdbc/web/page/Menu.java b/src/nl/astraeus/jdbc/web/page/Menu.java new file mode 100644 index 0000000..f0a349a --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.java @@ -0,0 +1,27 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 9:07 PM + */ +public class Menu extends TemplatePage { + + @Override + public Page processRequest(HttpServletRequest request) { + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + result.put("user", request.getSession().getAttribute("user")); + + return result; + } +} diff --git a/src/nl/astraeus/jdbc/web/page/Page.java b/src/nl/astraeus/jdbc/web/page/Page.java new file mode 100644 index 0000000..9d526d6 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Page.java @@ -0,0 +1,17 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:20 PM + */ +public abstract class Page { + + public abstract Page processRequest(HttpServletRequest request); + public abstract Map defineModel(HttpServletRequest request); + public abstract String render(HttpServletRequest request); + +} diff --git a/src/nl/astraeus/jdbc/web/page/QueryOverview.html b/src/nl/astraeus/jdbc/web/page/QueryOverview.html new file mode 100644 index 0000000..64a88fb --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/QueryOverview.html @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + {foreach(queries as q)} + + + + + + + {eachend} + +
Total timeAvg. time# CallsSql
{q.total}{q.nano}{q.count}{q.sql}
diff --git a/src/nl/astraeus/jdbc/web/page/QueryOverview.java b/src/nl/astraeus/jdbc/web/page/QueryOverview.java new file mode 100644 index 0000000..02982f1 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/QueryOverview.java @@ -0,0 +1,92 @@ +package nl.astraeus.jdbc.web.page; + +import nl.astraeus.jdbc.JdbcLogger; + +import javax.servlet.http.HttpServletRequest; +import java.util.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 9:16 PM + */ +public class QueryOverview extends TemplatePage { + + boolean sortTotalCalls = true; + boolean sortAvgTime = false; + boolean sortTotalTime = false; + + @Override + public Page processRequest(HttpServletRequest request) { + if ("sortTotalCalls".equals(request.getParameter("action"))) { + sortTotalCalls = true; + sortAvgTime = false; + sortTotalTime = false; + } else if ("sortAvgTime".equals(request.getParameter("action"))) { + sortTotalCalls = false; + sortAvgTime = true; + sortTotalTime = false; + } else if ("sortTotalTime".equals(request.getParameter("action"))) { + sortTotalCalls = false; + sortAvgTime = false; + sortTotalTime = true; + } + + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + List entries = new ArrayList(JdbcLogger.get().getEntries()); + + if (sortTotalCalls) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + return o2.count - o1.count; + } + }); + } else if (sortAvgTime) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + long n1 = o1.nano / o1.count; + long n2 = o2.nano / o2.count; + + if (n2 > n1) { + return 1; + } else if (n2 < n1) { + return -1; + } else { + return 0; + } + } + }); + } else if (sortTotalTime) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + if (o2.nano > o1.nano) { + return 1; + } else if (o2.nano < o1.nano) { + return -1; + } else { + return 0; + } + } + }); + } + + result.put("queries", entries); + result.put("count", entries.size()); + + result.put("sortTotalCalls", sortTotalCalls); + result.put("sortAvgTime", sortAvgTime); + result.put("sortTotalTime", sortTotalTime); + + return result; + } + +} diff --git a/src/nl/astraeus/jdbc/web/page/TemplatePage.java b/src/nl/astraeus/jdbc/web/page/TemplatePage.java new file mode 100644 index 0000000..33e2641 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/TemplatePage.java @@ -0,0 +1,58 @@ +package nl.astraeus.jdbc.web.page; + +import nl.astraeus.template.EscapeMode; +import nl.astraeus.template.SimpleTemplate; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:20 PM + */ +public abstract class TemplatePage extends Page { + + private SimpleTemplate template; + + protected TemplatePage() { + template = getSimpleTemplate(this.getClass()); + } + + public String render(HttpServletRequest request) { + return template.render(defineModel(request)); + } + + private static Map templateCache = new HashMap(); + + public synchronized static SimpleTemplate getSimpleTemplate(Class cls) { + SimpleTemplate result = templateCache.get(cls); + + if (result == null) { + InputStream in = null; + + try { + in = cls.getResourceAsStream(cls.getSimpleName() + ".html"); + + result = SimpleTemplate.readTemplate('{','}', EscapeMode.HTML, in); + + templateCache.put(cls, result); + } catch (IOException e) { + throw new IllegalStateException(e); + } finally { + if (in != null) { + try { + in.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + + return result; + } +} diff --git a/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css b/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css new file mode 100644 index 0000000..0e0056f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css @@ -0,0 +1,581 @@ +/*! + * Bootstrap Responsive v2.0.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ +.clearfix { + *zoom: 1; +} +.clearfix:before, .clearfix:after { + display: table; + content: ""; +} +.clearfix:after { + clear: both; +} +.hidden { + display: none; + visibility: hidden; +} +@media (max-width: 480px) { + .nav-collapse { + -webkit-transform: translate3d(0, 0, 0); + } + .page-header h1 small { + display: block; + line-height: 18px; + } + input[class*="span"], + select[class*="span"], + textarea[class*="span"], + .uneditable-input { + display: block; + width: 100%; + min-height: 28px; + /* Make inputs at least the height of their button counterpart */ + + /* Makes inputs behave like true block-level elements */ + + -webkit-box-sizing: border-box; + /* Older Webkit */ + + -moz-box-sizing: border-box; + /* Older FF */ + + -ms-box-sizing: border-box; + /* IE8 */ + + box-sizing: border-box; + /* CSS3 spec*/ + + } + .input-prepend input[class*="span"], .input-append input[class*="span"] { + width: auto; + } + input[type="checkbox"], input[type="radio"] { + border: 1px solid #ccc; + } + .form-horizontal .control-group > label { + float: none; + width: auto; + padding-top: 0; + text-align: left; + } + .form-horizontal .controls { + margin-left: 0; + } + .form-horizontal .control-list { + padding-top: 0; + } + .form-horizontal .form-actions { + padding-left: 10px; + padding-right: 10px; + } + .modal { + position: absolute; + top: 10px; + left: 10px; + right: 10px; + width: auto; + margin: 0; + } + .modal.fade.in { + top: auto; + } + .modal-header .close { + padding: 10px; + margin: -10px; + } + .carousel-caption { + position: static; + } +} +@media (max-width: 767px) { + .container { + width: auto; + padding: 0 20px; + } + .row-fluid { + width: 100%; + } + .row { + margin-left: 0; + } + .row > [class*="span"], .row-fluid > [class*="span"] { + float: none; + display: block; + width: auto; + margin: 0; + } +} +@media (min-width: 768px) and (max-width: 979px) { + .row { + margin-left: -20px; + *zoom: 1; + } + .row:before, .row:after { + display: table; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + margin-left: 20px; + } + .span1 { + width: 42px; + } + .span2 { + width: 104px; + } + .span3 { + width: 166px; + } + .span4 { + width: 228px; + } + .span5 { + width: 290px; + } + .span6 { + width: 352px; + } + .span7 { + width: 414px; + } + .span8 { + width: 476px; + } + .span9 { + width: 538px; + } + .span10 { + width: 600px; + } + .span11 { + width: 662px; + } + .span12, .container { + width: 724px; + } + .offset1 { + margin-left: 82px; + } + .offset2 { + margin-left: 144px; + } + .offset3 { + margin-left: 206px; + } + .offset4 { + margin-left: 268px; + } + .offset5 { + margin-left: 330px; + } + .offset6 { + margin-left: 392px; + } + .offset7 { + margin-left: 454px; + } + .offset8 { + margin-left: 516px; + } + .offset9 { + margin-left: 578px; + } + .offset10 { + margin-left: 640px; + } + .offset11 { + margin-left: 702px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, .row-fluid:after { + display: table; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid > [class*="span"] { + float: left; + margin-left: 2.762430939%; + } + .row-fluid > [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid > .span1 { + width: 5.801104972%; + } + .row-fluid > .span2 { + width: 14.364640883%; + } + .row-fluid > .span3 { + width: 22.928176794%; + } + .row-fluid > .span4 { + width: 31.491712705%; + } + .row-fluid > .span5 { + width: 40.055248616%; + } + .row-fluid > .span6 { + width: 48.618784527%; + } + .row-fluid > .span7 { + width: 57.182320438000005%; + } + .row-fluid > .span8 { + width: 65.74585634900001%; + } + .row-fluid > .span9 { + width: 74.30939226%; + } + .row-fluid > .span10 { + width: 82.87292817100001%; + } + .row-fluid > .span11 { + width: 91.436464082%; + } + .row-fluid > .span12 { + width: 99.999999993%; + } + input.span1, textarea.span1, .uneditable-input.span1 { + width: 32px; + } + input.span2, textarea.span2, .uneditable-input.span2 { + width: 94px; + } + input.span3, textarea.span3, .uneditable-input.span3 { + width: 156px; + } + input.span4, textarea.span4, .uneditable-input.span4 { + width: 218px; + } + input.span5, textarea.span5, .uneditable-input.span5 { + width: 280px; + } + input.span6, textarea.span6, .uneditable-input.span6 { + width: 342px; + } + input.span7, textarea.span7, .uneditable-input.span7 { + width: 404px; + } + input.span8, textarea.span8, .uneditable-input.span8 { + width: 466px; + } + input.span9, textarea.span9, .uneditable-input.span9 { + width: 528px; + } + input.span10, textarea.span10, .uneditable-input.span10 { + width: 590px; + } + input.span11, textarea.span11, .uneditable-input.span11 { + width: 652px; + } + input.span12, textarea.span12, .uneditable-input.span12 { + width: 714px; + } +} +@media (max-width: 979px) { + body { + padding-top: 0; + } + .navbar-fixed-top { + position: static; + margin-bottom: 18px; + } + .navbar-fixed-top .navbar-inner { + padding: 5px; + } + .navbar .container { + width: auto; + padding: 0; + } + .navbar .brand { + padding-left: 10px; + padding-right: 10px; + margin: 0 0 0 -5px; + } + .navbar .nav-collapse { + clear: left; + } + .navbar .nav { + float: none; + margin: 0 0 9px; + } + .navbar .nav > li { + float: none; + } + .navbar .nav > li > a { + margin-bottom: 2px; + } + .navbar .nav > .divider-vertical { + display: none; + } + .navbar .nav .nav-header { + color: #999999; + text-shadow: none; + } + .navbar .nav > li > a, .navbar .dropdown-menu a { + padding: 6px 15px; + font-weight: bold; + color: #999999; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + } + .navbar .dropdown-menu li + li a { + margin-bottom: 2px; + } + .navbar .nav > li > a:hover, .navbar .dropdown-menu a:hover { + background-color: #222222; + } + .navbar .dropdown-menu { + position: static; + top: auto; + left: auto; + float: none; + display: block; + max-width: none; + margin: 0 15px; + padding: 0; + background-color: transparent; + border: none; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + } + .navbar .dropdown-menu:before, .navbar .dropdown-menu:after { + display: none; + } + .navbar .dropdown-menu .divider { + display: none; + } + .navbar-form, .navbar-search { + float: none; + padding: 9px 15px; + margin: 9px 0; + border-top: 1px solid #222222; + border-bottom: 1px solid #222222; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + } + .navbar .nav.pull-right { + float: none; + margin-left: 0; + } + .navbar-static .navbar-inner { + padding-left: 10px; + padding-right: 10px; + } + .btn-navbar { + display: block; + } + .nav-collapse { + overflow: hidden; + height: 0; + } +} +@media (min-width: 980px) { + .nav-collapse.collapse { + height: auto !important; + } +} +@media (min-width: 1200px) { + .row { + margin-left: -30px; + *zoom: 1; + } + .row:before, .row:after { + display: table; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + margin-left: 30px; + } + .span1 { + width: 70px; + } + .span2 { + width: 170px; + } + .span3 { + width: 270px; + } + .span4 { + width: 370px; + } + .span5 { + width: 470px; + } + .span6 { + width: 570px; + } + .span7 { + width: 670px; + } + .span8 { + width: 770px; + } + .span9 { + width: 870px; + } + .span10 { + width: 970px; + } + .span11 { + width: 1070px; + } + .span12, .container { + width: 1170px; + } + .offset1 { + margin-left: 130px; + } + .offset2 { + margin-left: 230px; + } + .offset3 { + margin-left: 330px; + } + .offset4 { + margin-left: 430px; + } + .offset5 { + margin-left: 530px; + } + .offset6 { + margin-left: 630px; + } + .offset7 { + margin-left: 730px; + } + .offset8 { + margin-left: 830px; + } + .offset9 { + margin-left: 930px; + } + .offset10 { + margin-left: 1030px; + } + .offset11 { + margin-left: 1130px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, .row-fluid:after { + display: table; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid > [class*="span"] { + float: left; + margin-left: 2.564102564%; + } + .row-fluid > [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid > .span1 { + width: 5.982905983%; + } + .row-fluid > .span2 { + width: 14.529914530000001%; + } + .row-fluid > .span3 { + width: 23.076923077%; + } + .row-fluid > .span4 { + width: 31.623931624%; + } + .row-fluid > .span5 { + width: 40.170940171000005%; + } + .row-fluid > .span6 { + width: 48.717948718%; + } + .row-fluid > .span7 { + width: 57.264957265%; + } + .row-fluid > .span8 { + width: 65.81196581200001%; + } + .row-fluid > .span9 { + width: 74.358974359%; + } + .row-fluid > .span10 { + width: 82.905982906%; + } + .row-fluid > .span11 { + width: 91.45299145300001%; + } + .row-fluid > .span12 { + width: 100%; + } + input.span1, textarea.span1, .uneditable-input.span1 { + width: 60px; + } + input.span2, textarea.span2, .uneditable-input.span2 { + width: 160px; + } + input.span3, textarea.span3, .uneditable-input.span3 { + width: 260px; + } + input.span4, textarea.span4, .uneditable-input.span4 { + width: 360px; + } + input.span5, textarea.span5, .uneditable-input.span5 { + width: 460px; + } + input.span6, textarea.span6, .uneditable-input.span6 { + width: 560px; + } + input.span7, textarea.span7, .uneditable-input.span7 { + width: 660px; + } + input.span8, textarea.span8, .uneditable-input.span8 { + width: 760px; + } + input.span9, textarea.span9, .uneditable-input.span9 { + width: 860px; + } + input.span10, textarea.span10, .uneditable-input.span10 { + width: 960px; + } + input.span11, textarea.span11, .uneditable-input.span11 { + width: 1060px; + } + input.span12, textarea.span12, .uneditable-input.span12 { + width: 1160px; + } + .thumbnails { + margin-left: -30px; + } + .thumbnails > li { + margin-left: 30px; + } +} diff --git a/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css b/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css new file mode 100644 index 0000000..6229c12 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css @@ -0,0 +1,3521 @@ +/*! + * Bootstrap v2.0.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +nav, +section { + display: block; +} +audio, canvas, video { + display: inline-block; + *display: inline; + *zoom: 1; +} +audio:not([controls]) { + display: none; +} +html { + font-size: 100%; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} +a:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +a:hover, a:active { + outline: 0; +} +sub, sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} +sup { + top: -0.5em; +} +sub { + bottom: -0.25em; +} +img { + max-width: 100%; + height: auto; + border: 0; + -ms-interpolation-mode: bicubic; +} +button, +input, +select, +textarea { + margin: 0; + font-size: 100%; + vertical-align: middle; +} +button, input { + *overflow: visible; + line-height: normal; +} +button::-moz-focus-inner, input::-moz-focus-inner { + padding: 0; + border: 0; +} +button, +input[type="button"], +input[type="reset"], +input[type="submit"] { + cursor: pointer; + -webkit-appearance: button; +} +input[type="search"] { + -webkit-appearance: textfield; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +input[type="search"]::-webkit-search-decoration, input[type="search"]::-webkit-search-cancel-button { + -webkit-appearance: none; +} +textarea { + overflow: auto; + vertical-align: top; +} +.clearfix { + *zoom: 1; +} +.clearfix:before, .clearfix:after { + display: table; + content: ""; +} +.clearfix:after { + clear: both; +} +body { + margin: 0; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 18px; + color: #333333; + background-color: #ffffff; +} +a { + color: #0088cc; + text-decoration: none; +} +a:hover { + color: #005580; + text-decoration: underline; +} +.row { + margin-left: -20px; + *zoom: 1; +} +.row:before, .row:after { + display: table; + content: ""; +} +.row:after { + clear: both; +} +[class*="span"] { + float: left; + margin-left: 20px; +} +.span1 { + width: 60px; +} +.span2 { + width: 140px; +} +.span3 { + width: 220px; +} +.span4 { + width: 300px; +} +.span5 { + width: 380px; +} +.span6 { + width: 460px; +} +.span7 { + width: 540px; +} +.span8 { + width: 620px; +} +.span9 { + width: 700px; +} +.span10 { + width: 780px; +} +.span11 { + width: 860px; +} +.span12, .container { + width: 940px; +} +.offset1 { + margin-left: 100px; +} +.offset2 { + margin-left: 180px; +} +.offset3 { + margin-left: 260px; +} +.offset4 { + margin-left: 340px; +} +.offset5 { + margin-left: 420px; +} +.offset6 { + margin-left: 500px; +} +.offset7 { + margin-left: 580px; +} +.offset8 { + margin-left: 660px; +} +.offset9 { + margin-left: 740px; +} +.offset10 { + margin-left: 820px; +} +.offset11 { + margin-left: 900px; +} +.row-fluid { + width: 100%; + *zoom: 1; +} +.row-fluid:before, .row-fluid:after { + display: table; + content: ""; +} +.row-fluid:after { + clear: both; +} +.row-fluid > [class*="span"] { + float: left; + margin-left: 2.127659574%; +} +.row-fluid > [class*="span"]:first-child { + margin-left: 0; +} +.row-fluid > .span1 { + width: 6.382978723%; +} +.row-fluid > .span2 { + width: 14.89361702%; +} +.row-fluid > .span3 { + width: 23.404255317%; +} +.row-fluid > .span4 { + width: 31.914893614%; +} +.row-fluid > .span5 { + width: 40.425531911%; +} +.row-fluid > .span6 { + width: 48.93617020799999%; +} +.row-fluid > .span7 { + width: 57.446808505%; +} +.row-fluid > .span8 { + width: 65.95744680199999%; +} +.row-fluid > .span9 { + width: 74.468085099%; +} +.row-fluid > .span10 { + width: 82.97872339599999%; +} +.row-fluid > .span11 { + width: 91.489361693%; +} +.row-fluid > .span12 { + width: 99.99999998999999%; +} +.container { + width: 940px; + margin-left: auto; + margin-right: auto; + *zoom: 1; +} +.container:before, .container:after { + display: table; + content: ""; +} +.container:after { + clear: both; +} +.container-fluid { + padding-left: 20px; + padding-right: 20px; + *zoom: 1; +} +.container-fluid:before, .container-fluid:after { + display: table; + content: ""; +} +.container-fluid:after { + clear: both; +} +p { + margin: 0 0 9px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 18px; +} +p small { + font-size: 11px; + color: #999999; +} +.lead { + margin-bottom: 18px; + font-size: 20px; + font-weight: 200; + line-height: 27px; +} +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 0; + font-weight: bold; + color: #333333; + text-rendering: optimizelegibility; +} +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small { + font-weight: normal; + color: #999999; +} +h1 { + font-size: 30px; + line-height: 36px; +} +h1 small { + font-size: 18px; +} +h2 { + font-size: 24px; + line-height: 36px; +} +h2 small { + font-size: 18px; +} +h3 { + line-height: 27px; + font-size: 18px; +} +h3 small { + font-size: 14px; +} +h4, h5, h6 { + line-height: 18px; +} +h4 { + font-size: 14px; +} +h4 small { + font-size: 12px; +} +h5 { + font-size: 12px; +} +h6 { + font-size: 11px; + color: #999999; + text-transform: uppercase; +} +.page-header { + padding-bottom: 17px; + margin: 18px 0; + border-bottom: 1px solid #eeeeee; +} +.page-header h1 { + line-height: 1; +} +ul, ol { + padding: 0; + margin: 0 0 9px 25px; +} +ul ul, +ul ol, +ol ol, +ol ul { + margin-bottom: 0; +} +ul { + list-style: disc; +} +ol { + list-style: decimal; +} +li { + line-height: 18px; +} +ul.unstyled, ol.unstyled { + margin-left: 0; + list-style: none; +} +dl { + margin-bottom: 18px; +} +dt, dd { + line-height: 18px; +} +dt { + font-weight: bold; +} +dd { + margin-left: 9px; +} +hr { + margin: 18px 0; + border: 0; + border-top: 1px solid #eeeeee; + border-bottom: 1px solid #ffffff; +} +strong { + font-weight: bold; +} +em { + font-style: italic; +} +.muted { + color: #999999; +} +abbr { + font-size: 90%; + text-transform: uppercase; + border-bottom: 1px dotted #ddd; + cursor: help; +} +blockquote { + padding: 0 0 0 15px; + margin: 0 0 18px; + border-left: 5px solid #eeeeee; +} +blockquote p { + margin-bottom: 0; + font-size: 16px; + font-weight: 300; + line-height: 22.5px; +} +blockquote small { + display: block; + line-height: 18px; + color: #999999; +} +blockquote small:before { + content: '\2014 \00A0'; +} +blockquote.pull-right { + float: right; + padding-left: 0; + padding-right: 15px; + border-left: 0; + border-right: 5px solid #eeeeee; +} +blockquote.pull-right p, blockquote.pull-right small { + text-align: right; +} +q:before, +q:after, +blockquote:before, +blockquote:after { + content: ""; +} +address { + display: block; + margin-bottom: 18px; + line-height: 18px; + font-style: normal; +} +small { + font-size: 100%; +} +cite { + font-style: normal; +} +code, pre { + padding: 0 3px 2px; + font-family: Menlo, Monaco, "Courier New", monospace; + font-size: 12px; + color: #333333; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +code { + padding: 3px 4px; + color: #d14; + background-color: #f7f7f9; + border: 1px solid #e1e1e8; +} +pre { + display: block; + padding: 8.5px; + margin: 0 0 9px; + font-size: 12px; + line-height: 18px; + background-color: #f5f5f5; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.15); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + white-space: pre; + white-space: pre-wrap; + word-break: break-all; + word-wrap: break-word; +} +pre.prettyprint { + margin-bottom: 18px; +} +pre code { + padding: 0; + color: inherit; + background-color: transparent; + border: 0; +} +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} +form { + margin: 0 0 18px; +} +fieldset { + padding: 0; + margin: 0; + border: 0; +} +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 27px; + font-size: 19.5px; + line-height: 36px; + color: #333333; + border: 0; + border-bottom: 1px solid #eee; +} +legend small { + font-size: 13.5px; + color: #999999; +} +label, +input, +button, +select, +textarea { + font-size: 13px; + font-weight: normal; + line-height: 18px; +} +input, +button, +select, +textarea { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; +} +label { + display: block; + margin-bottom: 5px; + color: #333333; +} +input, +textarea, +select, +.uneditable-input { + display: inline-block; + width: 210px; + height: 18px; + padding: 4px; + margin-bottom: 9px; + font-size: 13px; + line-height: 18px; + color: #555555; + border: 1px solid #ccc; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.uneditable-textarea { + width: auto; + height: auto; +} +label input, label textarea, label select { + display: block; +} +input[type="image"], input[type="checkbox"], input[type="radio"] { + width: auto; + height: auto; + padding: 0; + margin: 3px 0; + *margin-top: 0; + /* IE7 */ + + line-height: normal; + cursor: pointer; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + border: 0 \9; + /* IE9 and down */ + +} +input[type="image"] { + border: 0; +} +input[type="file"] { + width: auto; + padding: initial; + line-height: initial; + border: initial; + background-color: #ffffff; + background-color: initial; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +input[type="button"], input[type="reset"], input[type="submit"] { + width: auto; + height: auto; +} +select, input[type="file"] { + height: 28px; + /* In IE7, the height of the select element cannot be changed by height, only font-size */ + + *margin-top: 4px; + /* For IE7, add top margin to align select with labels */ + + line-height: 28px; +} +input[type="file"] { + line-height: 18px \9; +} +select { + width: 220px; + background-color: #ffffff; +} +select[multiple], select[size] { + height: auto; +} +input[type="image"] { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +textarea { + height: auto; +} +input[type="hidden"] { + display: none; +} +.radio, .checkbox { + padding-left: 18px; +} +.radio input[type="radio"], .checkbox input[type="checkbox"] { + float: left; + margin-left: -18px; +} +.controls > .radio:first-child, .controls > .checkbox:first-child { + padding-top: 5px; +} +.radio.inline, .checkbox.inline { + display: inline-block; + padding-top: 5px; + margin-bottom: 0; + vertical-align: middle; +} +.radio.inline + .radio.inline, .checkbox.inline + .checkbox.inline { + margin-left: 10px; +} +input, textarea { + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; + -moz-transition: border linear 0.2s, box-shadow linear 0.2s; + -ms-transition: border linear 0.2s, box-shadow linear 0.2s; + -o-transition: border linear 0.2s, box-shadow linear 0.2s; + transition: border linear 0.2s, box-shadow linear 0.2s; +} +input:focus, textarea:focus { + border-color: rgba(82, 168, 236, 0.8); + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + outline: 0; + outline: thin dotted \9; + /* IE6-9 */ + +} +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus, +select:focus { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.input-mini { + width: 60px; +} +.input-small { + width: 90px; +} +.input-medium { + width: 150px; +} +.input-large { + width: 210px; +} +.input-xlarge { + width: 270px; +} +.input-xxlarge { + width: 530px; +} +input[class*="span"], +select[class*="span"], +textarea[class*="span"], +.uneditable-input { + float: none; + margin-left: 0; +} +input.span1, textarea.span1, .uneditable-input.span1 { + width: 50px; +} +input.span2, textarea.span2, .uneditable-input.span2 { + width: 130px; +} +input.span3, textarea.span3, .uneditable-input.span3 { + width: 210px; +} +input.span4, textarea.span4, .uneditable-input.span4 { + width: 290px; +} +input.span5, textarea.span5, .uneditable-input.span5 { + width: 370px; +} +input.span6, textarea.span6, .uneditable-input.span6 { + width: 450px; +} +input.span7, textarea.span7, .uneditable-input.span7 { + width: 530px; +} +input.span8, textarea.span8, .uneditable-input.span8 { + width: 610px; +} +input.span9, textarea.span9, .uneditable-input.span9 { + width: 690px; +} +input.span10, textarea.span10, .uneditable-input.span10 { + width: 770px; +} +input.span11, textarea.span11, .uneditable-input.span11 { + width: 850px; +} +input.span12, textarea.span12, .uneditable-input.span12 { + width: 930px; +} +input[disabled], +select[disabled], +textarea[disabled], +input[readonly], +select[readonly], +textarea[readonly] { + background-color: #f5f5f5; + border-color: #ddd; + cursor: not-allowed; +} +.control-group.warning > label, .control-group.warning .help-block, .control-group.warning .help-inline { + color: #c09853; +} +.control-group.warning input, .control-group.warning select, .control-group.warning textarea { + color: #c09853; + border-color: #c09853; +} +.control-group.warning input:focus, .control-group.warning select:focus, .control-group.warning textarea:focus { + border-color: #a47e3c; + -webkit-box-shadow: 0 0 6px #dbc59e; + -moz-box-shadow: 0 0 6px #dbc59e; + box-shadow: 0 0 6px #dbc59e; +} +.control-group.warning .input-prepend .add-on, .control-group.warning .input-append .add-on { + color: #c09853; + background-color: #fcf8e3; + border-color: #c09853; +} +.control-group.error > label, .control-group.error .help-block, .control-group.error .help-inline { + color: #b94a48; +} +.control-group.error input, .control-group.error select, .control-group.error textarea { + color: #b94a48; + border-color: #b94a48; +} +.control-group.error input:focus, .control-group.error select:focus, .control-group.error textarea:focus { + border-color: #953b39; + -webkit-box-shadow: 0 0 6px #d59392; + -moz-box-shadow: 0 0 6px #d59392; + box-shadow: 0 0 6px #d59392; +} +.control-group.error .input-prepend .add-on, .control-group.error .input-append .add-on { + color: #b94a48; + background-color: #f2dede; + border-color: #b94a48; +} +.control-group.success > label, .control-group.success .help-block, .control-group.success .help-inline { + color: #468847; +} +.control-group.success input, .control-group.success select, .control-group.success textarea { + color: #468847; + border-color: #468847; +} +.control-group.success input:focus, .control-group.success select:focus, .control-group.success textarea:focus { + border-color: #356635; + -webkit-box-shadow: 0 0 6px #7aba7b; + -moz-box-shadow: 0 0 6px #7aba7b; + box-shadow: 0 0 6px #7aba7b; +} +.control-group.success .input-prepend .add-on, .control-group.success .input-append .add-on { + color: #468847; + background-color: #dff0d8; + border-color: #468847; +} +input:focus:required:invalid, textarea:focus:required:invalid, select:focus:required:invalid { + color: #b94a48; + border-color: #ee5f5b; +} +input:focus:required:invalid:focus, textarea:focus:required:invalid:focus, select:focus:required:invalid:focus { + border-color: #e9322d; + -webkit-box-shadow: 0 0 6px #f8b9b7; + -moz-box-shadow: 0 0 6px #f8b9b7; + box-shadow: 0 0 6px #f8b9b7; +} +.form-actions { + padding: 17px 20px 18px; + margin-top: 18px; + margin-bottom: 18px; + background-color: #f5f5f5; + border-top: 1px solid #ddd; +} +.uneditable-input { + display: block; + background-color: #ffffff; + border-color: #eee; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + cursor: not-allowed; +} +:-moz-placeholder { + color: #999999; +} +::-webkit-input-placeholder { + color: #999999; +} +.help-block { + display: block; + margin-top: 5px; + margin-bottom: 0; + color: #999999; +} +.help-inline { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; + margin-bottom: 9px; + vertical-align: middle; + padding-left: 5px; +} +.input-prepend, .input-append { + margin-bottom: 5px; + *zoom: 1; +} +.input-prepend:before, +.input-append:before, +.input-prepend:after, +.input-append:after { + display: table; + content: ""; +} +.input-prepend:after, .input-append:after { + clear: both; +} +.input-prepend input, +.input-append input, +.input-prepend .uneditable-input, +.input-append .uneditable-input { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.input-prepend input:focus, +.input-append input:focus, +.input-prepend .uneditable-input:focus, +.input-append .uneditable-input:focus { + position: relative; + z-index: 2; +} +.input-prepend .uneditable-input, .input-append .uneditable-input { + border-left-color: #ccc; +} +.input-prepend .add-on, .input-append .add-on { + float: left; + display: block; + width: auto; + min-width: 16px; + height: 18px; + margin-right: -1px; + padding: 4px 5px; + font-weight: normal; + line-height: 18px; + color: #999999; + text-align: center; + text-shadow: 0 1px 0 #ffffff; + background-color: #f5f5f5; + border: 1px solid #ccc; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.input-prepend .active, .input-append .active { + background-color: #a9dba9; + border-color: #46a546; +} +.input-prepend .add-on { + *margin-top: 1px; + /* IE6-7 */ + +} +.input-append input, .input-append .uneditable-input { + float: left; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.input-append .uneditable-input { + border-left-color: #eee; + border-right-color: #ccc; +} +.input-append .add-on { + margin-right: 0; + margin-left: -1px; + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.input-append input:first-child { + *margin-left: -160px; +} +.input-append input:first-child + .add-on { + *margin-left: -21px; +} +.search-query { + padding-left: 14px; + padding-right: 14px; + margin-bottom: 0; + -webkit-border-radius: 14px; + -moz-border-radius: 14px; + border-radius: 14px; +} +.form-search input, +.form-inline input, +.form-horizontal input, +.form-search textarea, +.form-inline textarea, +.form-horizontal textarea, +.form-search select, +.form-inline select, +.form-horizontal select, +.form-search .help-inline, +.form-inline .help-inline, +.form-horizontal .help-inline, +.form-search .uneditable-input, +.form-inline .uneditable-input, +.form-horizontal .uneditable-input { + display: inline-block; + margin-bottom: 0; +} +.form-search .hide, .form-inline .hide, .form-horizontal .hide { + display: none; +} +.form-search label, +.form-inline label, +.form-search .input-append, +.form-inline .input-append, +.form-search .input-prepend, +.form-inline .input-prepend { + display: inline-block; +} +.form-search .input-append .add-on, +.form-inline .input-prepend .add-on, +.form-search .input-append .add-on, +.form-inline .input-prepend .add-on { + vertical-align: middle; +} +.form-search .radio, +.form-inline .radio, +.form-search .checkbox, +.form-inline .checkbox { + margin-bottom: 0; + vertical-align: middle; +} +.control-group { + margin-bottom: 9px; +} +legend + .control-group { + margin-top: 18px; + -webkit-margin-top-collapse: separate; +} +.form-horizontal .control-group { + margin-bottom: 18px; + *zoom: 1; +} +.form-horizontal .control-group:before, .form-horizontal .control-group:after { + display: table; + content: ""; +} +.form-horizontal .control-group:after { + clear: both; +} +.form-horizontal .control-label { + float: left; + width: 140px; + padding-top: 5px; + text-align: right; +} +.form-horizontal .controls { + margin-left: 160px; +} +.form-horizontal .form-actions { + padding-left: 160px; +} +table { + max-width: 100%; + border-collapse: collapse; + border-spacing: 0; +} +.table { + width: 100%; + margin-bottom: 18px; +} +.table th, .table td { + padding: 8px; + line-height: 18px; + text-align: left; + vertical-align: top; + border-top: 1px solid #ddd; +} +.table th { + font-weight: bold; +} +.table thead th { + vertical-align: bottom; +} +.table thead:first-child tr th, .table thead:first-child tr td { + border-top: 0; +} +.table tbody + tbody { + border-top: 2px solid #ddd; +} +.table-condensed th, .table-condensed td { + padding: 4px 5px; +} +.table-bordered { + border: 1px solid #ddd; + border-collapse: separate; + *border-collapse: collapsed; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.table-bordered th + th, +.table-bordered td + td, +.table-bordered th + td, +.table-bordered td + th { + border-left: 1px solid #ddd; +} +.table-bordered thead:first-child tr:first-child th, .table-bordered tbody:first-child tr:first-child th, .table-bordered tbody:first-child tr:first-child td { + border-top: 0; +} +.table-bordered thead:first-child tr:first-child th:first-child, .table-bordered tbody:first-child tr:first-child td:first-child { + -webkit-border-radius: 4px 0 0 0; + -moz-border-radius: 4px 0 0 0; + border-radius: 4px 0 0 0; +} +.table-bordered thead:first-child tr:first-child th:last-child, .table-bordered tbody:first-child tr:first-child td:last-child { + -webkit-border-radius: 0 4px 0 0; + -moz-border-radius: 0 4px 0 0; + border-radius: 0 4px 0 0; +} +.table-bordered thead:last-child tr:last-child th:first-child, .table-bordered tbody:last-child tr:last-child td:first-child { + -webkit-border-radius: 0 0 0 4px; + -moz-border-radius: 0 0 0 4px; + border-radius: 0 0 0 4px; +} +.table-bordered thead:last-child tr:last-child th:last-child, .table-bordered tbody:last-child tr:last-child td:last-child { + -webkit-border-radius: 0 0 4px 0; + -moz-border-radius: 0 0 4px 0; + border-radius: 0 0 4px 0; +} +.table-striped tbody tr:nth-child(odd) td, .table-striped tbody tr:nth-child(odd) th { + background-color: #f9f9f9; +} +.table tbody tr:hover td, .table tbody tr:hover th { + background-color: #f5f5f5; +} +table .span1 { + float: none; + width: 44px; + margin-left: 0; +} +table .span2 { + float: none; + width: 124px; + margin-left: 0; +} +table .span3 { + float: none; + width: 204px; + margin-left: 0; +} +table .span4 { + float: none; + width: 284px; + margin-left: 0; +} +table .span5 { + float: none; + width: 364px; + margin-left: 0; +} +table .span6 { + float: none; + width: 444px; + margin-left: 0; +} +table .span7 { + float: none; + width: 524px; + margin-left: 0; +} +table .span8 { + float: none; + width: 604px; + margin-left: 0; +} +table .span9 { + float: none; + width: 684px; + margin-left: 0; +} +table .span10 { + float: none; + width: 764px; + margin-left: 0; +} +table .span11 { + float: none; + width: 844px; + margin-left: 0; +} +table .span12 { + float: none; + width: 924px; + margin-left: 0; +} +[class^="icon-"], [class*=" icon-"] { + display: inline-block; + width: 14px; + height: 14px; + line-height: 14px; + vertical-align: text-top; + background-image: url("../img/glyphicons-halflings.png"); + background-position: 14px 14px; + background-repeat: no-repeat; + *margin-right: .3em; +} +[class^="icon-"]:last-child, [class*=" icon-"]:last-child { + *margin-left: 0; +} +.icon-white { + background-image: url("../img/glyphicons-halflings-white.png"); +} +.icon-glass { + background-position: 0 0; +} +.icon-music { + background-position: -24px 0; +} +.icon-search { + background-position: -48px 0; +} +.icon-envelope { + background-position: -72px 0; +} +.icon-heart { + background-position: -96px 0; +} +.icon-star { + background-position: -120px 0; +} +.icon-star-empty { + background-position: -144px 0; +} +.icon-user { + background-position: -168px 0; +} +.icon-film { + background-position: -192px 0; +} +.icon-th-large { + background-position: -216px 0; +} +.icon-th { + background-position: -240px 0; +} +.icon-th-list { + background-position: -264px 0; +} +.icon-ok { + background-position: -288px 0; +} +.icon-remove { + background-position: -312px 0; +} +.icon-zoom-in { + background-position: -336px 0; +} +.icon-zoom-out { + background-position: -360px 0; +} +.icon-off { + background-position: -384px 0; +} +.icon-signal { + background-position: -408px 0; +} +.icon-cog { + background-position: -432px 0; +} +.icon-trash { + background-position: -456px 0; +} +.icon-home { + background-position: 0 -24px; +} +.icon-file { + background-position: -24px -24px; +} +.icon-time { + background-position: -48px -24px; +} +.icon-road { + background-position: -72px -24px; +} +.icon-download-alt { + background-position: -96px -24px; +} +.icon-download { + background-position: -120px -24px; +} +.icon-upload { + background-position: -144px -24px; +} +.icon-inbox { + background-position: -168px -24px; +} +.icon-play-circle { + background-position: -192px -24px; +} +.icon-repeat { + background-position: -216px -24px; +} +.icon-refresh { + background-position: -240px -24px; +} +.icon-list-alt { + background-position: -264px -24px; +} +.icon-lock { + background-position: -287px -24px; +} +.icon-flag { + background-position: -312px -24px; +} +.icon-headphones { + background-position: -336px -24px; +} +.icon-volume-off { + background-position: -360px -24px; +} +.icon-volume-down { + background-position: -384px -24px; +} +.icon-volume-up { + background-position: -408px -24px; +} +.icon-qrcode { + background-position: -432px -24px; +} +.icon-barcode { + background-position: -456px -24px; +} +.icon-tag { + background-position: 0 -48px; +} +.icon-tags { + background-position: -25px -48px; +} +.icon-book { + background-position: -48px -48px; +} +.icon-bookmark { + background-position: -72px -48px; +} +.icon-print { + background-position: -96px -48px; +} +.icon-camera { + background-position: -120px -48px; +} +.icon-font { + background-position: -144px -48px; +} +.icon-bold { + background-position: -167px -48px; +} +.icon-italic { + background-position: -192px -48px; +} +.icon-text-height { + background-position: -216px -48px; +} +.icon-text-width { + background-position: -240px -48px; +} +.icon-align-left { + background-position: -264px -48px; +} +.icon-align-center { + background-position: -288px -48px; +} +.icon-align-right { + background-position: -312px -48px; +} +.icon-align-justify { + background-position: -336px -48px; +} +.icon-list { + background-position: -360px -48px; +} +.icon-indent-left { + background-position: -384px -48px; +} +.icon-indent-right { + background-position: -408px -48px; +} +.icon-facetime-video { + background-position: -432px -48px; +} +.icon-picture { + background-position: -456px -48px; +} +.icon-pencil { + background-position: 0 -72px; +} +.icon-map-marker { + background-position: -24px -72px; +} +.icon-adjust { + background-position: -48px -72px; +} +.icon-tint { + background-position: -72px -72px; +} +.icon-edit { + background-position: -96px -72px; +} +.icon-share { + background-position: -120px -72px; +} +.icon-check { + background-position: -144px -72px; +} +.icon-move { + background-position: -168px -72px; +} +.icon-step-backward { + background-position: -192px -72px; +} +.icon-fast-backward { + background-position: -216px -72px; +} +.icon-backward { + background-position: -240px -72px; +} +.icon-play { + background-position: -264px -72px; +} +.icon-pause { + background-position: -288px -72px; +} +.icon-stop { + background-position: -312px -72px; +} +.icon-forward { + background-position: -336px -72px; +} +.icon-fast-forward { + background-position: -360px -72px; +} +.icon-step-forward { + background-position: -384px -72px; +} +.icon-eject { + background-position: -408px -72px; +} +.icon-chevron-left { + background-position: -432px -72px; +} +.icon-chevron-right { + background-position: -456px -72px; +} +.icon-plus-sign { + background-position: 0 -96px; +} +.icon-minus-sign { + background-position: -24px -96px; +} +.icon-remove-sign { + background-position: -48px -96px; +} +.icon-ok-sign { + background-position: -72px -96px; +} +.icon-question-sign { + background-position: -96px -96px; +} +.icon-info-sign { + background-position: -120px -96px; +} +.icon-screenshot { + background-position: -144px -96px; +} +.icon-remove-circle { + background-position: -168px -96px; +} +.icon-ok-circle { + background-position: -192px -96px; +} +.icon-ban-circle { + background-position: -216px -96px; +} +.icon-arrow-left { + background-position: -240px -96px; +} +.icon-arrow-right { + background-position: -264px -96px; +} +.icon-arrow-up { + background-position: -289px -96px; +} +.icon-arrow-down { + background-position: -312px -96px; +} +.icon-share-alt { + background-position: -336px -96px; +} +.icon-resize-full { + background-position: -360px -96px; +} +.icon-resize-small { + background-position: -384px -96px; +} +.icon-plus { + background-position: -408px -96px; +} +.icon-minus { + background-position: -433px -96px; +} +.icon-asterisk { + background-position: -456px -96px; +} +.icon-exclamation-sign { + background-position: 0 -120px; +} +.icon-gift { + background-position: -24px -120px; +} +.icon-leaf { + background-position: -48px -120px; +} +.icon-fire { + background-position: -72px -120px; +} +.icon-eye-open { + background-position: -96px -120px; +} +.icon-eye-close { + background-position: -120px -120px; +} +.icon-warning-sign { + background-position: -144px -120px; +} +.icon-plane { + background-position: -168px -120px; +} +.icon-calendar { + background-position: -192px -120px; +} +.icon-random { + background-position: -216px -120px; +} +.icon-comment { + background-position: -240px -120px; +} +.icon-magnet { + background-position: -264px -120px; +} +.icon-chevron-up { + background-position: -288px -120px; +} +.icon-chevron-down { + background-position: -313px -119px; +} +.icon-retweet { + background-position: -336px -120px; +} +.icon-shopping-cart { + background-position: -360px -120px; +} +.icon-folder-close { + background-position: -384px -120px; +} +.icon-folder-open { + background-position: -408px -120px; +} +.icon-resize-vertical { + background-position: -432px -119px; +} +.icon-resize-horizontal { + background-position: -456px -118px; +} +.dropdown { + position: relative; +} +.dropdown-toggle { + *margin-bottom: -3px; +} +.dropdown-toggle:active, .open .dropdown-toggle { + outline: 0; +} +.caret { + display: inline-block; + width: 0; + height: 0; + text-indent: -99999px; + *text-indent: 0; + vertical-align: top; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 4px solid #000000; + opacity: 0.3; + filter: alpha(opacity=30); + content: "\2193"; +} +.dropdown .caret { + margin-top: 8px; + margin-left: 2px; +} +.dropdown:hover .caret, .open.dropdown .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + float: left; + display: none; + min-width: 160px; + _width: 160px; + padding: 4px 0; + margin: 0; + list-style: none; + background-color: #ffffff; + border-color: #ccc; + border-color: rgba(0, 0, 0, 0.2); + border-style: solid; + border-width: 1px; + -webkit-border-radius: 0 0 5px 5px; + -moz-border-radius: 0 0 5px 5px; + border-radius: 0 0 5px 5px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; + *border-right-width: 2px; + *border-bottom-width: 2px; +} +.dropdown-menu.bottom-up { + top: auto; + bottom: 100%; + margin-bottom: 2px; +} +.dropdown-menu .divider { + height: 1px; + margin: 5px 1px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #ffffff; + *width: 100%; + *margin: -5px 0 5px; +} +.dropdown-menu a { + display: block; + padding: 3px 15px; + clear: both; + font-weight: normal; + line-height: 18px; + color: #555555; + white-space: nowrap; +} +.dropdown-menu li > a:hover, .dropdown-menu .active > a, .dropdown-menu .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #0088cc; +} +.dropdown.open { + *z-index: 1000; +} +.dropdown.open .dropdown-toggle { + color: #ffffff; + background: #ccc; + background: rgba(0, 0, 0, 0.3); +} +.dropdown.open .dropdown-menu { + display: block; +} +.typeahead { + margin-top: 2px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #f5f5f5; + border: 1px solid #eee; + border: 1px solid rgba(0, 0, 0, 0.05); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 0, 0, 0.15); +} +.fade { + -webkit-transition: opacity 0.15s linear; + -moz-transition: opacity 0.15s linear; + -ms-transition: opacity 0.15s linear; + -o-transition: opacity 0.15s linear; + transition: opacity 0.15s linear; + opacity: 0; +} +.fade.in { + opacity: 1; +} +.collapse { + -webkit-transition: height 0.35s ease; + -moz-transition: height 0.35s ease; + -ms-transition: height 0.35s ease; + -o-transition: height 0.35s ease; + transition: height 0.35s ease; + position: relative; + overflow: hidden; + height: 0; +} +.collapse.in { + height: auto; +} +.close { + float: right; + font-size: 20px; + font-weight: bold; + line-height: 18px; + color: #000000; + text-shadow: 0 1px 0 #ffffff; + opacity: 0.2; + filter: alpha(opacity=20); +} +.close:hover { + color: #000000; + text-decoration: none; + opacity: 0.4; + filter: alpha(opacity=40); + cursor: pointer; +} +.btn { + display: inline-block; + padding: 4px 10px 4px; + margin-bottom: 0; + font-size: 13px; + line-height: 18px; + color: #333333; + text-align: center; + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); + vertical-align: middle; + background-color: #f5f5f5; + background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); + background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); + background-image: linear-gradient(top, #ffffff, #e6e6e6); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0); + border-color: #e6e6e6 #e6e6e6 #bfbfbf; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + border: 1px solid #ccc; + border-bottom-color: #bbb; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + cursor: pointer; + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + *margin-left: .3em; +} +.btn:hover, +.btn:active, +.btn.active, +.btn.disabled, +.btn[disabled] { + background-color: #e6e6e6; +} +.btn:active, .btn.active { + background-color: #cccccc \9; +} +.btn:first-child { + *margin-left: 0; +} +.btn:hover { + color: #333333; + text-decoration: none; + background-color: #e6e6e6; + background-position: 0 -15px; + -webkit-transition: background-position 0.1s linear; + -moz-transition: background-position 0.1s linear; + -ms-transition: background-position 0.1s linear; + -o-transition: background-position 0.1s linear; + transition: background-position 0.1s linear; +} +.btn:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.btn.active, .btn:active { + background-image: none; + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + background-color: #e6e6e6; + background-color: #d9d9d9 \9; + outline: 0; +} +.btn.disabled, .btn[disabled] { + cursor: default; + background-image: none; + background-color: #e6e6e6; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +.btn-large { + padding: 9px 14px; + font-size: 15px; + line-height: normal; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.btn-large [class^="icon-"] { + margin-top: 1px; +} +.btn-small { + padding: 5px 9px; + font-size: 11px; + line-height: 16px; +} +.btn-small [class^="icon-"] { + margin-top: -1px; +} +.btn-mini { + padding: 2px 6px; + font-size: 11px; + line-height: 14px; +} +.btn-primary, +.btn-primary:hover, +.btn-warning, +.btn-warning:hover, +.btn-danger, +.btn-danger:hover, +.btn-success, +.btn-success:hover, +.btn-info, +.btn-info:hover, +.btn-inverse, +.btn-inverse:hover { + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + color: #ffffff; +} +.btn-primary.active, +.btn-warning.active, +.btn-danger.active, +.btn-success.active, +.btn-info.active, +.btn-dark.active { + color: rgba(255, 255, 255, 0.75); +} +.btn-primary { + background-color: #006dcc; + background-image: -moz-linear-gradient(top, #0088cc, #0044cc); + background-image: -ms-linear-gradient(top, #0088cc, #0044cc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); + background-image: -o-linear-gradient(top, #0088cc, #0044cc); + background-image: linear-gradient(top, #0088cc, #0044cc); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); + border-color: #0044cc #0044cc #002a80; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-primary:hover, +.btn-primary:active, +.btn-primary.active, +.btn-primary.disabled, +.btn-primary[disabled] { + background-color: #0044cc; +} +.btn-primary:active, .btn-primary.active { + background-color: #003399 \9; +} +.btn-warning { + background-color: #faa732; + background-image: -moz-linear-gradient(top, #fbb450, #f89406); + background-image: -ms-linear-gradient(top, #fbb450, #f89406); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); + background-image: -webkit-linear-gradient(top, #fbb450, #f89406); + background-image: -o-linear-gradient(top, #fbb450, #f89406); + background-image: linear-gradient(top, #fbb450, #f89406); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0); + border-color: #f89406 #f89406 #ad6704; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-warning:hover, +.btn-warning:active, +.btn-warning.active, +.btn-warning.disabled, +.btn-warning[disabled] { + background-color: #f89406; +} +.btn-warning:active, .btn-warning.active { + background-color: #c67605 \9; +} +.btn-danger { + background-color: #da4f49; + background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -ms-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -o-linear-gradient(top, #ee5f5b, #bd362f); + background-image: linear-gradient(top, #ee5f5b, #bd362f); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0); + border-color: #bd362f #bd362f #802420; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-danger:hover, +.btn-danger:active, +.btn-danger.active, +.btn-danger.disabled, +.btn-danger[disabled] { + background-color: #bd362f; +} +.btn-danger:active, .btn-danger.active { + background-color: #942a25 \9; +} +.btn-success { + background-color: #5bb75b; + background-image: -moz-linear-gradient(top, #62c462, #51a351); + background-image: -ms-linear-gradient(top, #62c462, #51a351); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351)); + background-image: -webkit-linear-gradient(top, #62c462, #51a351); + background-image: -o-linear-gradient(top, #62c462, #51a351); + background-image: linear-gradient(top, #62c462, #51a351); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0); + border-color: #51a351 #51a351 #387038; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-success:hover, +.btn-success:active, +.btn-success.active, +.btn-success.disabled, +.btn-success[disabled] { + background-color: #51a351; +} +.btn-success:active, .btn-success.active { + background-color: #408140 \9; +} +.btn-info { + background-color: #49afcd; + background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -ms-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4)); + background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -o-linear-gradient(top, #5bc0de, #2f96b4); + background-image: linear-gradient(top, #5bc0de, #2f96b4); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0); + border-color: #2f96b4 #2f96b4 #1f6377; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-info:hover, +.btn-info:active, +.btn-info.active, +.btn-info.disabled, +.btn-info[disabled] { + background-color: #2f96b4; +} +.btn-info:active, .btn-info.active { + background-color: #24748c \9; +} +.btn-inverse { + background-color: #393939; + background-image: -moz-linear-gradient(top, #454545, #262626); + background-image: -ms-linear-gradient(top, #454545, #262626); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#454545), to(#262626)); + background-image: -webkit-linear-gradient(top, #454545, #262626); + background-image: -o-linear-gradient(top, #454545, #262626); + background-image: linear-gradient(top, #454545, #262626); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#454545', endColorstr='#262626', GradientType=0); + border-color: #262626 #262626 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-inverse:hover, +.btn-inverse:active, +.btn-inverse.active, +.btn-inverse.disabled, +.btn-inverse[disabled] { + background-color: #262626; +} +.btn-inverse:active, .btn-inverse.active { + background-color: #0c0c0c \9; +} +button.btn, input[type="submit"].btn { + *padding-top: 2px; + *padding-bottom: 2px; +} +button.btn::-moz-focus-inner, input[type="submit"].btn::-moz-focus-inner { + padding: 0; + border: 0; +} +button.btn.large, input[type="submit"].btn.large { + *padding-top: 7px; + *padding-bottom: 7px; +} +button.btn.small, input[type="submit"].btn.small { + *padding-top: 3px; + *padding-bottom: 3px; +} +.btn-group { + position: relative; + *zoom: 1; + *margin-left: .3em; +} +.btn-group:before, .btn-group:after { + display: table; + content: ""; +} +.btn-group:after { + clear: both; +} +.btn-group:first-child { + *margin-left: 0; +} +.btn-group + .btn-group { + margin-left: 5px; +} +.btn-toolbar { + margin-top: 9px; + margin-bottom: 9px; +} +.btn-toolbar .btn-group { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; +} +.btn-group .btn { + position: relative; + float: left; + margin-left: -1px; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.btn-group .btn:first-child { + margin-left: 0; + -webkit-border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; + border-top-left-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + border-bottom-left-radius: 4px; +} +.btn-group .btn:last-child, .btn-group .dropdown-toggle { + -webkit-border-top-right-radius: 4px; + -moz-border-radius-topright: 4px; + border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -moz-border-radius-bottomright: 4px; + border-bottom-right-radius: 4px; +} +.btn-group .btn.large:first-child { + margin-left: 0; + -webkit-border-top-left-radius: 6px; + -moz-border-radius-topleft: 6px; + border-top-left-radius: 6px; + -webkit-border-bottom-left-radius: 6px; + -moz-border-radius-bottomleft: 6px; + border-bottom-left-radius: 6px; +} +.btn-group .btn.large:last-child, .btn-group .large.dropdown-toggle { + -webkit-border-top-right-radius: 6px; + -moz-border-radius-topright: 6px; + border-top-right-radius: 6px; + -webkit-border-bottom-right-radius: 6px; + -moz-border-radius-bottomright: 6px; + border-bottom-right-radius: 6px; +} +.btn-group .btn:hover, +.btn-group .btn:focus, +.btn-group .btn:active, +.btn-group .btn.active { + z-index: 2; +} +.btn-group .dropdown-toggle:active, .btn-group.open .dropdown-toggle { + outline: 0; +} +.btn-group .dropdown-toggle { + padding-left: 8px; + padding-right: 8px; + -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + *padding-top: 5px; + *padding-bottom: 5px; +} +.btn-group.open { + *z-index: 1000; +} +.btn-group.open .dropdown-menu { + display: block; + margin-top: 1px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.btn-group.open .dropdown-toggle { + background-image: none; + -webkit-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); +} +.btn .caret { + margin-top: 7px; + margin-left: 0; +} +.btn:hover .caret, .open.btn-group .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.btn-primary .caret, +.btn-danger .caret, +.btn-info .caret, +.btn-success .caret, +.btn-inverse .caret { + border-top-color: #ffffff; + opacity: 0.75; + filter: alpha(opacity=75); +} +.btn-small .caret { + margin-top: 4px; +} +.alert { + padding: 8px 35px 8px 14px; + margin-bottom: 18px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + background-color: #fcf8e3; + border: 1px solid #fbeed5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.alert, .alert-heading { + color: #c09853; +} +.alert .close { + position: relative; + top: -2px; + right: -21px; + line-height: 18px; +} +.alert-success { + background-color: #dff0d8; + border-color: #d6e9c6; +} +.alert-success, .alert-success .alert-heading { + color: #468847; +} +.alert-danger, .alert-error { + background-color: #f2dede; + border-color: #eed3d7; +} +.alert-danger, +.alert-error, +.alert-danger .alert-heading, +.alert-error .alert-heading { + color: #b94a48; +} +.alert-info { + background-color: #d9edf7; + border-color: #bce8f1; +} +.alert-info, .alert-info .alert-heading { + color: #3a87ad; +} +.alert-block { + padding-top: 14px; + padding-bottom: 14px; +} +.alert-block > p, .alert-block > ul { + margin-bottom: 0; +} +.alert-block p + p { + margin-top: 5px; +} +.nav { + margin-left: 0; + margin-bottom: 18px; + list-style: none; +} +.nav > li > a { + display: block; +} +.nav > li > a:hover { + text-decoration: none; + background-color: #eeeeee; +} +.nav .nav-header { + display: block; + padding: 3px 15px; + font-size: 11px; + font-weight: bold; + line-height: 18px; + color: #999999; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + text-transform: uppercase; +} +.nav li + .nav-header { + margin-top: 9px; +} +.nav-list { + padding-left: 14px; + padding-right: 14px; + margin-bottom: 0; +} +.nav-list > li > a, .nav-list .nav-header { + margin-left: -15px; + margin-right: -15px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); +} +.nav-list > li > a { + padding: 3px 15px; +} +.nav-list .active > a, .nav-list .active > a:hover { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); + background-color: #0088cc; +} +.nav-list [class^="icon-"] { + margin-right: 2px; +} +.nav-tabs, .nav-pills { + *zoom: 1; +} +.nav-tabs:before, +.nav-pills:before, +.nav-tabs:after, +.nav-pills:after { + display: table; + content: ""; +} +.nav-tabs:after, .nav-pills:after { + clear: both; +} +.nav-tabs > li, .nav-pills > li { + float: left; +} +.nav-tabs > li > a, .nav-pills > li > a { + padding-right: 12px; + padding-left: 12px; + margin-right: 2px; + line-height: 14px; +} +.nav-tabs { + border-bottom: 1px solid #ddd; +} +.nav-tabs > li { + margin-bottom: -1px; +} +.nav-tabs > li > a { + padding-top: 9px; + padding-bottom: 9px; + border: 1px solid transparent; + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} +.nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #dddddd; +} +.nav-tabs > .active > a, .nav-tabs > .active > a:hover { + color: #555555; + background-color: #ffffff; + border: 1px solid #ddd; + border-bottom-color: transparent; + cursor: default; +} +.nav-pills > li > a { + padding-top: 8px; + padding-bottom: 8px; + margin-top: 2px; + margin-bottom: 2px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.nav-pills .active > a, .nav-pills .active > a:hover { + color: #ffffff; + background-color: #0088cc; +} +.nav-stacked > li { + float: none; +} +.nav-stacked > li > a { + margin-right: 0; +} +.nav-tabs.nav-stacked { + border-bottom: 0; +} +.nav-tabs.nav-stacked > li > a { + border: 1px solid #ddd; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.nav-tabs.nav-stacked > li:first-child > a { + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} +.nav-tabs.nav-stacked > li:last-child > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} +.nav-tabs.nav-stacked > li > a:hover { + border-color: #ddd; + z-index: 2; +} +.nav-pills.nav-stacked > li > a { + margin-bottom: 3px; +} +.nav-pills.nav-stacked > li:last-child > a { + margin-bottom: 1px; +} +.nav-tabs .dropdown-menu, .nav-pills .dropdown-menu { + margin-top: 1px; + border-width: 1px; +} +.nav-pills .dropdown-menu { + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.nav-tabs .dropdown-toggle .caret, .nav-pills .dropdown-toggle .caret { + border-top-color: #0088cc; + margin-top: 6px; +} +.nav-tabs .dropdown-toggle:hover .caret, .nav-pills .dropdown-toggle:hover .caret { + border-top-color: #005580; +} +.nav-tabs .active .dropdown-toggle .caret, .nav-pills .active .dropdown-toggle .caret { + border-top-color: #333333; +} +.nav > .dropdown.active > a:hover { + color: #000000; + cursor: pointer; +} +.nav-tabs .open .dropdown-toggle, .nav-pills .open .dropdown-toggle, .nav > .open.active > a:hover { + color: #ffffff; + background-color: #999999; + border-color: #999999; +} +.nav .open .caret, .nav .open.active .caret, .nav .open a:hover .caret { + border-top-color: #ffffff; + opacity: 1; + filter: alpha(opacity=100); +} +.tabs-stacked .open > a:hover { + border-color: #999999; +} +.tabbable { + *zoom: 1; +} +.tabbable:before, .tabbable:after { + display: table; + content: ""; +} +.tabbable:after { + clear: both; +} +.tab-content { + overflow: hidden; +} +.tabs-below .nav-tabs, .tabs-right .nav-tabs, .tabs-left .nav-tabs { + border-bottom: 0; +} +.tab-content > .tab-pane, .pill-content > .pill-pane { + display: none; +} +.tab-content > .active, .pill-content > .active { + display: block; +} +.tabs-below .nav-tabs { + border-top: 1px solid #ddd; +} +.tabs-below .nav-tabs > li { + margin-top: -1px; + margin-bottom: 0; +} +.tabs-below .nav-tabs > li > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} +.tabs-below .nav-tabs > li > a:hover { + border-bottom-color: transparent; + border-top-color: #ddd; +} +.tabs-below .nav-tabs .active > a, .tabs-below .nav-tabs .active > a:hover { + border-color: transparent #ddd #ddd #ddd; +} +.tabs-left .nav-tabs > li, .tabs-right .nav-tabs > li { + float: none; +} +.tabs-left .nav-tabs > li > a, .tabs-right .nav-tabs > li > a { + min-width: 74px; + margin-right: 0; + margin-bottom: 3px; +} +.tabs-left .nav-tabs { + float: left; + margin-right: 19px; + border-right: 1px solid #ddd; +} +.tabs-left .nav-tabs > li > a { + margin-right: -1px; + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} +.tabs-left .nav-tabs > li > a:hover { + border-color: #eeeeee #dddddd #eeeeee #eeeeee; +} +.tabs-left .nav-tabs .active > a, .tabs-left .nav-tabs .active > a:hover { + border-color: #ddd transparent #ddd #ddd; + *border-right-color: #ffffff; +} +.tabs-right .nav-tabs { + float: right; + margin-left: 19px; + border-left: 1px solid #ddd; +} +.tabs-right .nav-tabs > li > a { + margin-left: -1px; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} +.tabs-right .nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #eeeeee #dddddd; +} +.tabs-right .nav-tabs .active > a, .tabs-right .nav-tabs .active > a:hover { + border-color: #ddd #ddd #ddd transparent; + *border-left-color: #ffffff; +} +.navbar { + overflow: visible; + margin-bottom: 18px; +} +.navbar-inner { + padding-left: 20px; + padding-right: 20px; + background-color: #2c2c2c; + background-image: -moz-linear-gradient(top, #333333, #222222); + background-image: -ms-linear-gradient(top, #333333, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); + background-image: -webkit-linear-gradient(top, #333333, #222222); + background-image: -o-linear-gradient(top, #333333, #222222); + background-image: linear-gradient(top, #333333, #222222); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); +} +.btn-navbar { + display: none; + float: right; + padding: 7px 10px; + margin-left: 5px; + margin-right: 5px; + background-color: #2c2c2c; + background-image: -moz-linear-gradient(top, #333333, #222222); + background-image: -ms-linear-gradient(top, #333333, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); + background-image: -webkit-linear-gradient(top, #333333, #222222); + background-image: -o-linear-gradient(top, #333333, #222222); + background-image: linear-gradient(top, #333333, #222222); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); + border-color: #222222 #222222 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); +} +.btn-navbar:hover, +.btn-navbar:active, +.btn-navbar.active, +.btn-navbar.disabled, +.btn-navbar[disabled] { + background-color: #222222; +} +.btn-navbar:active, .btn-navbar.active { + background-color: #080808 \9; +} +.btn-navbar .icon-bar { + display: block; + width: 18px; + height: 2px; + background-color: #f5f5f5; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; + -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); +} +.btn-navbar .icon-bar + .icon-bar { + margin-top: 3px; +} +.nav-collapse.collapse { + height: auto; +} +.navbar .brand:hover { + text-decoration: none; +} +.navbar .brand { + float: left; + display: block; + padding: 8px 20px 12px; + margin-left: -20px; + font-size: 20px; + font-weight: 200; + line-height: 1; + color: #ffffff; +} +.navbar .navbar-text { + margin-bottom: 0; + line-height: 40px; + color: #999999; +} +.navbar .navbar-text a:hover { + color: #ffffff; + background-color: transparent; +} +.navbar .btn, .navbar .btn-group { + margin-top: 5px; +} +.navbar .btn-group .btn { + margin-top: 0; +} +.navbar-form { + margin-bottom: 0; + *zoom: 1; +} +.navbar-form:before, .navbar-form:after { + display: table; + content: ""; +} +.navbar-form:after { + clear: both; +} +.navbar-form input, .navbar-form select { + display: inline-block; + margin-top: 5px; + margin-bottom: 0; +} +.navbar-form .radio, .navbar-form .checkbox { + margin-top: 5px; +} +.navbar-form input[type="image"], .navbar-form input[type="checkbox"], .navbar-form input[type="radio"] { + margin-top: 3px; +} +.navbar-form .input-append, .navbar-form .input-prepend { + margin-top: 6px; + white-space: nowrap; +} +.navbar-form .input-append input, .navbar-form .input-prepend input { + margin-top: 0; +} +.navbar-search { + position: relative; + float: left; + margin-top: 6px; + margin-bottom: 0; +} +.navbar-search .search-query { + padding: 4px 9px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + font-weight: normal; + line-height: 1; + color: #ffffff; + color: rgba(255, 255, 255, 0.75); + background: #666; + background: rgba(255, 255, 255, 0.3); + border: 1px solid #111; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + -webkit-transition: none; + -moz-transition: none; + -ms-transition: none; + -o-transition: none; + transition: none; +} +.navbar-search .search-query :-moz-placeholder { + color: #eeeeee; +} +.navbar-search .search-query::-webkit-input-placeholder { + color: #eeeeee; +} +.navbar-search .search-query:hover { + color: #ffffff; + background-color: #999999; + background-color: rgba(255, 255, 255, 0.5); +} +.navbar-search .search-query:focus, .navbar-search .search-query.focused { + padding: 5px 10px; + color: #333333; + text-shadow: 0 1px 0 #ffffff; + background-color: #ffffff; + border: 0; + -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + outline: 0; +} +.navbar-fixed-top { + position: fixed; + top: 0; + right: 0; + left: 0; + z-index: 1030; +} +.navbar-fixed-top .navbar-inner { + padding-left: 0; + padding-right: 0; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.navbar .nav { + position: relative; + left: 0; + display: block; + float: left; + margin: 0 10px 0 0; +} +.navbar .nav.pull-right { + float: right; +} +.navbar .nav > li { + display: block; + float: left; +} +.navbar .nav > li > a { + float: none; + padding: 10px 10px 11px; + line-height: 19px; + color: #999999; + text-decoration: none; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.navbar .nav > li > a:hover { + background-color: transparent; + color: #ffffff; + text-decoration: none; +} +.navbar .nav .active > a, .navbar .nav .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #222222; +} +.navbar .divider-vertical { + height: 40px; + width: 1px; + margin: 0 9px; + overflow: hidden; + background-color: #222222; + border-right: 1px solid #333333; +} +.navbar .nav.pull-right { + margin-left: 10px; + margin-right: 0; +} +.navbar .dropdown-menu { + margin-top: 1px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.navbar .dropdown-menu:before { + content: ''; + display: inline-block; + border-left: 7px solid transparent; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-bottom-color: rgba(0, 0, 0, 0.2); + position: absolute; + top: -7px; + left: 9px; +} +.navbar .dropdown-menu:after { + content: ''; + display: inline-block; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid #ffffff; + position: absolute; + top: -6px; + left: 10px; +} +.navbar .nav .dropdown-toggle .caret, .navbar .nav .open.dropdown .caret { + border-top-color: #ffffff; +} +.navbar .nav .active .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.navbar .nav .open > .dropdown-toggle, .navbar .nav .active > .dropdown-toggle, .navbar .nav .open.active > .dropdown-toggle { + background-color: transparent; +} +.navbar .nav .active > .dropdown-toggle:hover { + color: #ffffff; +} +.navbar .nav.pull-right .dropdown-menu { + left: auto; + right: 0; +} +.navbar .nav.pull-right .dropdown-menu:before { + left: auto; + right: 12px; +} +.navbar .nav.pull-right .dropdown-menu:after { + left: auto; + right: 13px; +} +.breadcrumb { + padding: 7px 14px; + margin: 0 0 18px; + background-color: #fbfbfb; + background-image: -moz-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -ms-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5)); + background-image: -webkit-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -o-linear-gradient(top, #ffffff, #f5f5f5); + background-image: linear-gradient(top, #ffffff, #f5f5f5); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0); + border: 1px solid #ddd; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; +} +.breadcrumb li { + display: inline-block; + text-shadow: 0 1px 0 #ffffff; +} +.breadcrumb .divider { + padding: 0 5px; + color: #999999; +} +.breadcrumb .active a { + color: #333333; +} +.pagination { + height: 36px; + margin: 18px 0; +} +.pagination ul { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; + margin-left: 0; + margin-bottom: 0; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); +} +.pagination li { + display: inline; +} +.pagination a { + float: left; + padding: 0 14px; + line-height: 34px; + text-decoration: none; + border: 1px solid #ddd; + border-left-width: 0; +} +.pagination a:hover, .pagination .active a { + background-color: #f5f5f5; +} +.pagination .active a { + color: #999999; + cursor: default; +} +.pagination .disabled a, .pagination .disabled a:hover { + color: #999999; + background-color: transparent; + cursor: default; +} +.pagination li:first-child a { + border-left-width: 1px; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.pagination li:last-child a { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.pagination-centered { + text-align: center; +} +.pagination-right { + text-align: right; +} +.pager { + margin-left: 0; + margin-bottom: 18px; + list-style: none; + text-align: center; + *zoom: 1; +} +.pager:before, .pager:after { + display: table; + content: ""; +} +.pager:after { + clear: both; +} +.pager li { + display: inline; +} +.pager a { + display: inline-block; + padding: 5px 14px; + background-color: #fff; + border: 1px solid #ddd; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} +.pager a:hover { + text-decoration: none; + background-color: #f5f5f5; +} +.pager .next a { + float: right; +} +.pager .previous a { + float: left; +} +.modal-open .dropdown-menu { + z-index: 2050; +} +.modal-open .dropdown.open { + *z-index: 2050; +} +.modal-open .popover { + z-index: 2060; +} +.modal-open .tooltip { + z-index: 2070; +} +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + background-color: #000000; +} +.modal-backdrop.fade { + opacity: 0; +} +.modal-backdrop, .modal-backdrop.fade.in { + opacity: 0.8; + filter: alpha(opacity=80); +} +.modal { + position: fixed; + top: 50%; + left: 50%; + z-index: 1050; + max-height: 500px; + overflow: auto; + width: 560px; + margin: -250px 0 0 -280px; + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + /* IE6-7 */ + + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.wide-modal { + position: fixed; + top: 5%; + left: 5%; + z-index: 1050; + max-height: 90%; + overflow: auto; + width: 90%; + /*margin: -50px 0 0 -80px;*/ + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + /* IE6-7 */ + + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.modal.fade { + -webkit-transition: opacity .3s linear, top .3s ease-out; + -moz-transition: opacity .3s linear, top .3s ease-out; + -ms-transition: opacity .3s linear, top .3s ease-out; + -o-transition: opacity .3s linear, top .3s ease-out; + transition: opacity .3s linear, top .3s ease-out; + top: -25%; +} +.modal.fade.in { + top: 50%; +} +.modal-header { + padding: 9px 15px; + border-bottom: 1px solid #eee; +} +.modal-header .close { + margin-top: 2px; +} +.modal-body { + padding: 15px; +} +.modal-body .modal-form { + margin-bottom: 0; +} +.modal-footer { + padding: 14px 15px 15px; + margin-bottom: 0; + background-color: #f5f5f5; + border-top: 1px solid #ddd; + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; + *zoom: 1; +} +.modal-footer:before, .modal-footer:after { + display: table; + content: ""; +} +.modal-footer:after { + clear: both; +} +.modal-footer .btn { + float: right; + margin-left: 5px; + margin-bottom: 0; +} +.tooltip { + position: absolute; + z-index: 1020; + display: block; + visibility: visible; + padding: 5px; + font-size: 11px; + opacity: 0; + filter: alpha(opacity=0); +} +.tooltip.in { + opacity: 0.8; + filter: alpha(opacity=80); +} +.tooltip.top { + margin-top: -2px; +} +.tooltip.right { + margin-left: 2px; +} +.tooltip.bottom { + margin-top: 2px; +} +.tooltip.left { + margin-left: -2px; +} +.tooltip.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid #000000; +} +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #000000; +} +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-bottom: 5px solid #000000; +} +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-right: 5px solid #000000; +} +.tooltip-inner { + max-width: 200px; + padding: 3px 8px; + color: #ffffff; + text-align: center; + text-decoration: none; + background-color: #000000; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; +} +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1010; + display: none; + padding: 5px; +} +.popover.top { + margin-top: -5px; +} +.popover.right { + margin-left: 5px; +} +.popover.bottom { + margin-top: 5px; +} +.popover.left { + margin-left: -5px; +} +.popover.top .arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid #000000; +} +.popover.right .arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-right: 5px solid #000000; +} +.popover.bottom .arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-bottom: 5px solid #000000; +} +.popover.left .arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #000000; +} +.popover .arrow { + position: absolute; + width: 0; + height: 0; +} +.popover-inner { + padding: 3px; + width: 280px; + overflow: hidden; + background: #000000; + background: rgba(0, 0, 0, 0.8); + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); +} +.popover-title { + padding: 9px 15px; + line-height: 1; + background-color: #f5f5f5; + border-bottom: 1px solid #eee; + -webkit-border-radius: 3px 3px 0 0; + -moz-border-radius: 3px 3px 0 0; + border-radius: 3px 3px 0 0; +} +.popover-content { + padding: 14px; + background-color: #ffffff; + -webkit-border-radius: 0 0 3px 3px; + -moz-border-radius: 0 0 3px 3px; + border-radius: 0 0 3px 3px; + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.popover-content p, .popover-content ul, .popover-content ol { + margin-bottom: 0; +} +.thumbnails { + margin-left: -20px; + list-style: none; + *zoom: 1; +} +.thumbnails:before, .thumbnails:after { + display: table; + content: ""; +} +.thumbnails:after { + clear: both; +} +.thumbnails > li { + float: left; + margin: 0 0 18px 20px; +} +.thumbnail { + display: block; + padding: 4px; + line-height: 1; + border: 1px solid #ddd; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); +} +a.thumbnail:hover { + border-color: #0088cc; + -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); +} +.thumbnail > img { + display: block; + max-width: 100%; + margin-left: auto; + margin-right: auto; +} +.thumbnail .caption { + padding: 9px; +} +.label { + padding: 2px 4px 3px; + font-size: 11.049999999999999px; + font-weight: bold; + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #999999; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.label:hover { + color: #ffffff; + text-decoration: none; +} +.label-important { + background-color: #b94a48; +} +.label-important:hover { + background-color: #953b39; +} +.label-warning { + background-color: #f89406; +} +.label-warning:hover { + background-color: #c67605; +} +.label-success { + background-color: #468847; +} +.label-success:hover { + background-color: #356635; +} +.label-info { + background-color: #3a87ad; +} +.label-info:hover { + background-color: #2d6987; +} +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +@-moz-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +@keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +.progress { + overflow: hidden; + height: 18px; + margin-bottom: 18px; + background-color: #f7f7f7; + background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -ms-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9)); + background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: linear-gradient(top, #f5f5f5, #f9f9f9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0); + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.progress .bar { + width: 0%; + height: 18px; + color: #ffffff; + font-size: 12px; + text-align: center; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #0e90d2; + background-image: -moz-linear-gradient(top, #149bdf, #0480be); + background-image: -ms-linear-gradient(top, #149bdf, #0480be); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be)); + background-image: -webkit-linear-gradient(top, #149bdf, #0480be); + background-image: -o-linear-gradient(top, #149bdf, #0480be); + background-image: linear-gradient(top, #149bdf, #0480be); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0); + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition: width 0.6s ease; + -moz-transition: width 0.6s ease; + -ms-transition: width 0.6s ease; + -o-transition: width 0.6s ease; + transition: width 0.6s ease; +} +.progress-striped .bar { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + -webkit-background-size: 40px 40px; + -moz-background-size: 40px 40px; + -o-background-size: 40px 40px; + background-size: 40px 40px; +} +.progress.active .bar { + -webkit-animation: progress-bar-stripes 2s linear infinite; + -moz-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} +.progress-danger .bar { + background-color: #dd514c; + background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -o-linear-gradient(top, #ee5f5b, #c43c35); + background-image: linear-gradient(top, #ee5f5b, #c43c35); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0); +} +.progress-danger.progress-striped .bar { + background-color: #ee5f5b; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-success .bar { + background-color: #5eb95e; + background-image: -moz-linear-gradient(top, #62c462, #57a957); + background-image: -ms-linear-gradient(top, #62c462, #57a957); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957)); + background-image: -webkit-linear-gradient(top, #62c462, #57a957); + background-image: -o-linear-gradient(top, #62c462, #57a957); + background-image: linear-gradient(top, #62c462, #57a957); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0); +} +.progress-success.progress-striped .bar { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-info .bar { + background-color: #4bb1cf; + background-image: -moz-linear-gradient(top, #5bc0de, #339bb9); + background-image: -ms-linear-gradient(top, #5bc0de, #339bb9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9)); + background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9); + background-image: -o-linear-gradient(top, #5bc0de, #339bb9); + background-image: linear-gradient(top, #5bc0de, #339bb9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0); +} +.progress-info.progress-striped .bar { + background-color: #5bc0de; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.accordion { + margin-bottom: 18px; +} +.accordion-group { + margin-bottom: 2px; + border: 1px solid #e5e5e5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.accordion-heading { + border-bottom: 0; +} +.accordion-heading .accordion-toggle { + display: block; + padding: 8px 15px; +} +.accordion-inner { + padding: 9px 15px; + border-top: 1px solid #e5e5e5; +} +.carousel { + position: relative; + margin-bottom: 18px; + line-height: 1; +} +.carousel-inner { + overflow: hidden; + width: 100%; + position: relative; +} +.carousel .item { + display: none; + position: relative; + -webkit-transition: 0.6s ease-in-out left; + -moz-transition: 0.6s ease-in-out left; + -ms-transition: 0.6s ease-in-out left; + -o-transition: 0.6s ease-in-out left; + transition: 0.6s ease-in-out left; +} +.carousel .item > img { + display: block; + line-height: 1; +} +.carousel .active, .carousel .next, .carousel .prev { + display: block; +} +.carousel .active { + left: 0; +} +.carousel .next, .carousel .prev { + position: absolute; + top: 0; + width: 100%; +} +.carousel .next { + left: 100%; +} +.carousel .prev { + left: -100%; +} +.carousel .next.left, .carousel .prev.right { + left: 0; +} +.carousel .active.left { + left: -100%; +} +.carousel .active.right { + left: 100%; +} +.carousel-control { + position: absolute; + top: 40%; + left: 15px; + width: 40px; + height: 40px; + margin-top: -20px; + font-size: 60px; + font-weight: 100; + line-height: 30px; + color: #ffffff; + text-align: center; + background: #222222; + border: 3px solid #ffffff; + -webkit-border-radius: 23px; + -moz-border-radius: 23px; + border-radius: 23px; + opacity: 0.5; + filter: alpha(opacity=50); +} +.carousel-control.right { + left: auto; + right: 15px; +} +.carousel-control:hover { + color: #ffffff; + text-decoration: none; + opacity: 0.9; + filter: alpha(opacity=90); +} +.carousel-caption { + position: absolute; + left: 0; + right: 0; + bottom: 0; + padding: 10px 15px 5px; + background: #333333; + background: rgba(0, 0, 0, 0.75); +} +.carousel-caption h4, .carousel-caption p { + color: #ffffff; +} +.hero-unit { + padding: 60px; + margin-bottom: 30px; + background-color: #f5f5f5; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} +.hero-unit h1 { + margin-bottom: 0; + font-size: 60px; + line-height: 1; + letter-spacing: -1px; +} +.hero-unit p { + font-size: 18px; + font-weight: 200; + line-height: 27px; +} +.pull-right { + float: right; +} +.pull-left { + float: left; +} +.hide { + display: none; +} +.show { + display: block; +} +.invisible { + visibility: hidden; +} diff --git a/src/nl/astraeus/jdbc/web/resources/images/loading.gif b/src/nl/astraeus/jdbc/web/resources/images/loading.gif new file mode 100644 index 0000000..21c7e74 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/images/loading.gif Binary files differ diff --git a/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png b/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png new file mode 100644 index 0000000..92d4445 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png Binary files differ diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-alert.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-alert.js new file mode 100644 index 0000000..2242ddd --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-alert.js @@ -0,0 +1,94 @@ +/* ========================================================== + * bootstrap-alert.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#alerts + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function( $ ){ + + "use strict" + + /* ALERT CLASS DEFINITION + * ====================== */ + + var dismiss = '[data-dismiss="alert"]' + , Alert = function ( el ) { + $(el).on('click', dismiss, this.close) + } + + Alert.prototype = { + + constructor: Alert + + , close: function ( e ) { + var $this = $(this) + , selector = $this.attr('data-target') + , $parent + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = $(selector) + $parent.trigger('close') + + e && e.preventDefault() + + $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent()) + + $parent + .trigger('close') + .removeClass('in') + + function removeElement() { + $parent + .trigger('closed') + .remove() + } + + $.support.transition && $parent.hasClass('fade') ? + $parent.on($.support.transition.end, removeElement) : + removeElement() + } + + } + + + /* ALERT PLUGIN DEFINITION + * ======================= */ + + $.fn.alert = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('alert') + if (!data) $this.data('alert', (data = new Alert(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.alert.Constructor = Alert + + + /* ALERT DATA-API + * ============== */ + + $(function () { + $('body').on('click.alert.data-api', dismiss, Alert.prototype.close) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-button.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-button.js new file mode 100644 index 0000000..0238ca3 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-button.js @@ -0,0 +1,100 @@ +/* ============================================================ + * bootstrap-button.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#buttons + * ============================================================ + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + +!function( $ ){ + + "use strict" + + /* BUTTON PUBLIC CLASS DEFINITION + * ============================== */ + + var Button = function ( element, options ) { + this.$element = $(element) + this.options = $.extend({}, $.fn.button.defaults, options) + } + + Button.prototype = { + + constructor: Button + + , setState: function ( state ) { + var d = 'disabled' + , $el = this.$element + , data = $el.data() + , val = $el.is('input') ? 'val' : 'html' + + state = state + 'Text' + data.resetText || $el.data('resetText', $el[val]()) + + $el[val](data[state] || this.options[state]) + + // push to event loop to allow forms to submit + setTimeout(function () { + state == 'loadingText' ? + $el.addClass(d).attr(d, d) : + $el.removeClass(d).removeAttr(d) + }, 0) + } + + , toggle: function () { + var $parent = this.$element.parent('[data-toggle="buttons-radio"]') + + $parent && $parent + .find('.active') + .removeClass('active') + + this.$element.toggleClass('active') + } + + } + + + /* BUTTON PLUGIN DEFINITION + * ======================== */ + + $.fn.button = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('button') + , options = typeof option == 'object' && option + if (!data) $this.data('button', (data = new Button(this, options))) + if (option == 'toggle') data.toggle() + else if (option) data.setState(option) + }) + } + + $.fn.button.defaults = { + loadingText: 'loading...' + } + + $.fn.button.Constructor = Button + + + /* BUTTON DATA-API + * =============== */ + + $(function () { + $('body').on('click.button.data-api', '[data-toggle^=button]', function ( e ) { + var $btn = $(e.target) + if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') + $btn.button('toggle') + }) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-carousel.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-carousel.js new file mode 100644 index 0000000..810256e --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-carousel.js @@ -0,0 +1,157 @@ +/* ========================================================== + * bootstrap-carousel.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#carousel + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function( $ ){ + + "use strict" + + /* CAROUSEL CLASS DEFINITION + * ========================= */ + + var Carousel = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, $.fn.carousel.defaults, options) + this.options.slide && this.slide(this.options.slide) + } + + Carousel.prototype = { + + cycle: function () { + this.interval = setInterval($.proxy(this.next, this), this.options.interval) + return this + } + + , to: function (pos) { + var $active = this.$element.find('.active') + , children = $active.parent().children() + , activePos = children.index($active) + , that = this + + if (pos > (children.length - 1) || pos < 0) return + + if (this.sliding) { + return this.$element.one('slid', function () { + that.to(pos) + }) + } + + if (activePos == pos) { + return this.pause().cycle() + } + + return this.slide(pos > activePos ? 'next' : 'prev', $(children[pos])) + } + + , pause: function () { + clearInterval(this.interval) + this.interval = null + return this + } + + , next: function () { + if (this.sliding) return + return this.slide('next') + } + + , prev: function () { + if (this.sliding) return + return this.slide('prev') + } + + , slide: function (type, next) { + var $active = this.$element.find('.active') + , $next = next || $active[type]() + , isCycling = this.interval + , direction = type == 'next' ? 'left' : 'right' + , fallback = type == 'next' ? 'first' : 'last' + , that = this + + if (!$next.length) return + + this.sliding = true + + isCycling && this.pause() + + $next = $next.length ? $next : this.$element.find('.item')[fallback]() + + if (!$.support.transition && this.$element.hasClass('slide')) { + this.$element.trigger('slide') + $active.removeClass('active') + $next.addClass('active') + this.sliding = false + this.$element.trigger('slid') + } else { + $next.addClass(type) + $next[0].offsetWidth // force reflow + $active.addClass(direction) + $next.addClass(direction) + this.$element.trigger('slide') + this.$element.one($.support.transition.end, function () { + $next.removeClass([type, direction].join(' ')).addClass('active') + $active.removeClass(['active', direction].join(' ')) + that.sliding = false + setTimeout(function () { that.$element.trigger('slid') }, 0) + }) + } + + isCycling && this.cycle() + + return this + } + + } + + + /* CAROUSEL PLUGIN DEFINITION + * ========================== */ + + $.fn.carousel = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('carousel') + , options = typeof option == 'object' && option + if (!data) $this.data('carousel', (data = new Carousel(this, options))) + if (typeof option == 'number') data.to(option) + else if (typeof option == 'string' || (option = options.slide)) data[option]() + else data.cycle() + }) + } + + $.fn.carousel.defaults = { + interval: 5000 + } + + $.fn.carousel.Constructor = Carousel + + + /* CAROUSEL DATA-API + * ================= */ + + $(function () { + $('body').on('click.carousel.data-api', '[data-slide]', function ( e ) { + var $this = $(this), href + , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 + , options = !$target.data('modal') && $.extend({}, $target.data(), $this.data()) + $target.carousel(options) + e.preventDefault() + }) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-collapse.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-collapse.js new file mode 100644 index 0000000..d195efc --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-collapse.js @@ -0,0 +1,136 @@ +/* ============================================================= + * bootstrap-collapse.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#collapse + * ============================================================= + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + +!function( $ ){ + + "use strict" + + var Collapse = function ( element, options ) { + this.$element = $(element) + this.options = $.extend({}, $.fn.collapse.defaults, options) + + if (this.options["parent"]) { + this.$parent = $(this.options["parent"]) + } + + this.options.toggle && this.toggle() + } + + Collapse.prototype = { + + constructor: Collapse + + , dimension: function () { + var hasWidth = this.$element.hasClass('width') + return hasWidth ? 'width' : 'height' + } + + , show: function () { + var dimension = this.dimension() + , scroll = $.camelCase(['scroll', dimension].join('-')) + , actives = this.$parent && this.$parent.find('.in') + , hasData + + if (actives && actives.length) { + hasData = actives.data('collapse') + actives.collapse('hide') + hasData || actives.data('collapse', null) + } + + this.$element[dimension](0) + this.transition('addClass', 'show', 'shown') + this.$element[dimension](this.$element[0][scroll]) + + } + + , hide: function () { + var dimension = this.dimension() + this.reset(this.$element[dimension]()) + this.transition('removeClass', 'hide', 'hidden') + this.$element[dimension](0) + } + + , reset: function ( size ) { + var dimension = this.dimension() + + this.$element + .removeClass('collapse') + [dimension](size || 'auto') + [0].offsetWidth + + this.$element.addClass('collapse') + } + + , transition: function ( method, startEvent, completeEvent ) { + var that = this + , complete = function () { + if (startEvent == 'show') that.reset() + that.$element.trigger(completeEvent) + } + + this.$element + .trigger(startEvent) + [method]('in') + + $.support.transition && this.$element.hasClass('collapse') ? + this.$element.one($.support.transition.end, complete) : + complete() + } + + , toggle: function () { + this[this.$element.hasClass('in') ? 'hide' : 'show']() + } + + } + + /* COLLAPSIBLE PLUGIN DEFINITION + * ============================== */ + + $.fn.collapse = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('collapse') + , options = typeof option == 'object' && option + if (!data) $this.data('collapse', (data = new Collapse(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.collapse.defaults = { + toggle: true + } + + $.fn.collapse.Constructor = Collapse + + + /* COLLAPSIBLE DATA-API + * ==================== */ + + $(function () { + $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function ( e ) { + var $this = $(this), href + , target = $this.attr('data-target') + || e.preventDefault() + || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 + , option = $(target).data('collapse') ? 'toggle' : $this.data() + $(target).collapse(option) + }) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f403193 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..73ff239 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..3b00020 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..275077f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/README b/README deleted file mode 100644 index 734abaf..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -This file was created by IntelliJ IDEA 11.1.1 for binding GitHub repository \ No newline at end of file diff --git a/Simple-jdbc-statistics.iml b/Simple-jdbc-statistics.iml new file mode 100644 index 0000000..ca90a9b --- /dev/null +++ b/Simple-jdbc-statistics.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/lib/h2-1.3.166.jar b/lib/h2-1.3.166.jar new file mode 100644 index 0000000..4985063 --- /dev/null +++ b/lib/h2-1.3.166.jar Binary files differ diff --git a/lib/servlet-api-2.5.jar b/lib/servlet-api-2.5.jar new file mode 100644 index 0000000..20b5755 --- /dev/null +++ b/lib/servlet-api-2.5.jar Binary files differ diff --git a/lib/slf4j-api-1.6.4.jar b/lib/slf4j-api-1.6.4.jar new file mode 100644 index 0000000..4d23f41 --- /dev/null +++ b/lib/slf4j-api-1.6.4.jar Binary files differ diff --git a/lib/slf4j-simple-1.6.4.jar b/lib/slf4j-simple-1.6.4.jar new file mode 100644 index 0000000..3d1b8d9 --- /dev/null +++ b/lib/slf4j-simple-1.6.4.jar Binary files differ diff --git a/lib/ssr-0.1.jar b/lib/ssr-0.1.jar new file mode 100644 index 0000000..65dfcf4 --- /dev/null +++ b/lib/ssr-0.1.jar Binary files differ diff --git a/lib/vst-0.4.jar b/lib/vst-0.4.jar new file mode 100644 index 0000000..db63792 --- /dev/null +++ b/lib/vst-0.4.jar Binary files differ diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..ac2dbe1 --- /dev/null +++ b/readme.md @@ -0,0 +1 @@ +A simple wrapper around jdbc drivers what will show current jdbc stats of the running queries on a simple web page on port 18080. \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/ConnectionLogger.java b/src/nl/astraeus/jdbc/ConnectionLogger.java new file mode 100644 index 0000000..c3e243f --- /dev/null +++ b/src/nl/astraeus/jdbc/ConnectionLogger.java @@ -0,0 +1,279 @@ +package nl.astraeus.jdbc; + +import java.sql.*; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Executor; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:12:34 PM + */ +public class ConnectionLogger implements Connection { + private Connection connection; + + private long milli; + private long nano; + private String lastSql; + + public ConnectionLogger(Connection connection) { + this.connection = connection; + this.lastSql = ""; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(QueryType.UNKNOWN, sql, m, n); + } + + public void commit() throws SQLException { + clearTime(); + + connection.commit(); + + log("commit"); + } + + public void rollback() throws SQLException { + clearTime(); + + connection.rollback(); + + log("rollback"); + } + + public void close() throws SQLException { + clearTime(); + + connection.close(); + + log("close"); + } + + public PreparedStatement prepareStatement(String sql) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, autoGeneratedKeys); + } + + public PreparedStatement prepareStatement(String sql, int columnIndexes[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnIndexes); + } + + public PreparedStatement prepareStatement(String sql, String columnNames[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnNames); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public Statement createStatement() throws SQLException { + return connection.createStatement(); + } + + public CallableStatement prepareCall(String sql) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql); + } + + public String nativeSQL(String sql) throws SQLException { + lastSql = sql; + return connection.nativeSQL(sql); + } + + public void setAutoCommit(boolean autoCommit) throws SQLException { + connection.setAutoCommit(autoCommit); + } + + public boolean getAutoCommit() throws SQLException { + return connection.getAutoCommit(); + } + + public boolean isClosed() throws SQLException { + return connection.isClosed(); + } + + public DatabaseMetaData getMetaData() throws SQLException { + return connection.getMetaData(); + } + + public void setReadOnly(boolean readOnly) throws SQLException { + connection.setReadOnly(readOnly); + } + + public boolean isReadOnly() throws SQLException { + return connection.isReadOnly(); + } + + public void setCatalog(String catalog) throws SQLException { + connection.setCatalog(catalog); + } + + public String getCatalog() throws SQLException { + return connection.getCatalog(); + } + + public void setTransactionIsolation(int level) throws SQLException { + connection.setTransactionIsolation(level); + } + + public int getTransactionIsolation() throws SQLException { + return connection.getTransactionIsolation(); + } + + public SQLWarning getWarnings() throws SQLException { + return connection.getWarnings(); + } + + public void clearWarnings() throws SQLException { + connection.clearWarnings(); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency); + } + + public Map> getTypeMap() throws SQLException { + return connection.getTypeMap(); + } + + public void setTypeMap(Map> map) throws SQLException { + connection.setTypeMap(map); + } + + public void setHoldability(int holdability) throws SQLException { + connection.setHoldability(holdability); + } + + public int getHoldability() throws SQLException { + return connection.getHoldability(); + } + + public Savepoint setSavepoint() throws SQLException { + return connection.setSavepoint(); + } + + public Savepoint setSavepoint(String name) throws SQLException { + return connection.setSavepoint(name); + } + + public void rollback(Savepoint savepoint) throws SQLException { + connection.rollback(); + } + + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + connection.releaseSavepoint(savepoint); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public Clob createClob() throws SQLException { + return connection.createClob(); + } + + public Blob createBlob() throws SQLException { + return connection.createBlob(); + } + + public NClob createNClob() throws SQLException { + return connection.createNClob(); + } + + public SQLXML createSQLXML() throws SQLException { + return connection.createSQLXML(); + } + + public boolean isValid(int timeout) throws SQLException { + return connection.isValid(timeout); + } + + public void setClientInfo(String name, String value) throws SQLClientInfoException { + connection.setClientInfo(name, value); + } + + public void setClientInfo(Properties properties) throws SQLClientInfoException { + connection.setClientInfo(properties); + } + + public String getClientInfo(String name) throws SQLException { + return connection.getClientInfo(name); + } + + public Properties getClientInfo() throws SQLException { + return connection.getClientInfo(); + } + + public Array createArrayOf(String typeName, Object[] elements) throws SQLException { + return connection.createArrayOf(typeName, elements); + } + + public Struct createStruct(String typeName, Object[] attributes) throws SQLException { + return connection.createStruct(typeName, attributes); + } + + @Override + public void setSchema(String schema) throws SQLException { + connection.setSchema(schema); + } + + @Override + public String getSchema() throws SQLException { + return connection.getSchema(); + } + + @Override + public void abort(Executor executor) throws SQLException { + connection.abort(executor); + } + + @Override + public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { + connection.setNetworkTimeout(executor, milliseconds); + } + + @Override + public int getNetworkTimeout() throws SQLException { + return connection.getNetworkTimeout(); + } + + public T unwrap(Class iface) throws SQLException { + return connection.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return connection.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/Driver.java b/src/nl/astraeus/jdbc/Driver.java new file mode 100644 index 0000000..8317172 --- /dev/null +++ b/src/nl/astraeus/jdbc/Driver.java @@ -0,0 +1,116 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.http.SimpleWebServer; +import nl.astraeus.jdbc.web.JdbcStatisticsServlet; +import nl.astraeus.jdbc.web.ResourceServlet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.*; +import java.util.Enumeration; +import java.util.Properties; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:54:37 PM + */ +public class Driver implements java.sql.Driver { + private final static Logger log = LoggerFactory.getLogger(Driver.class); + + final private static String URL_PREFIX = "jdbc:stat:"; + + private java.sql.Driver driver = null; + private String[] drivers = { + "org.postgresql.Driver", + "oracle.jdbc.driver.OracleDriver", + "com.sybase.jdbc2.jdbc.SybDriver", + "net.sourceforge.jtds.jdbc.Driver", + "com.microsoft.jdbc.sqlserver.SQLServerDriver", + "com.microsoft.sqlserver.jdbc.SQLServerDriver", + "weblogic.jdbc.sqlserver.SQLServerDriver", + "com.informix.jdbc.IfxDriver", + "org.apache.derby.jdbc.ClientDriver", + "org.apache.derby.jdbc.EmbeddedDriver", + "com.mysql.jdbc.Driver", + "org.hsqldb.jdbcDriver", + "org.h2.Driver" }; + + static { + log.debug("Loading driver class " + Driver.class.getName()); + + try { + DriverManager.registerDriver(new Driver()); + } catch (SQLException e) { + log.error("", e); + } + } + + public Driver() { + for (String dr : drivers) { + try { + Class.forName(dr); + } catch (Throwable e) { + log.debug("Can't instantiate driver: " + dr, e); + } + } + } + + private java.sql.Driver findDriver(String url) throws SQLException { + Enumeration e = DriverManager.getDrivers(); + + while (e.hasMoreElements()) { + java.sql.Driver d = (java.sql.Driver) e.nextElement(); + + if (d.acceptsURL(url)) { + return d; + } + } + + throw new SQLException("Driver not found: " + url); + } + + public Connection connect(String url, Properties info) throws SQLException { + url = url.substring(URL_PREFIX.length()); + + if (driver == null) { + driver = findDriver(url); + } + + if (driver != null) { + SimpleWebServer server = new SimpleWebServer(18080); + + server.addServlet(new JdbcStatisticsServlet(), "/"); + server.addServlet(new ResourceServlet(), "/resources/*"); + + server.start(); + } + + return new ConnectionLogger(driver.connect(url, info)); + } + + public boolean acceptsURL(String url) throws SQLException { + return (url != null && url.startsWith(URL_PREFIX)); + } + + public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { + return driver.getPropertyInfo(url, info); + } + + public int getMajorVersion() { + return driver.getMajorVersion(); + } + + public int getMinorVersion() { + return driver.getMinorVersion(); + } + + public boolean jdbcCompliant() { + return driver.jdbcCompliant(); + } + + @Override + public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException { + return driver.getParentLogger(); + } +} diff --git a/src/nl/astraeus/jdbc/JdbcLogger.java b/src/nl/astraeus/jdbc/JdbcLogger.java new file mode 100644 index 0000000..f4bc125 --- /dev/null +++ b/src/nl/astraeus/jdbc/JdbcLogger.java @@ -0,0 +1,113 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.jdbc.util.Util; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/** + * User: riennentjes + * Date: Jul 12, 2008 + * Time: 9:15:21 AM + */ +public class JdbcLogger { + private final static Logger logger = LoggerFactory.getLogger(JdbcLogger.class); + + private final static JdbcLogger instance = new JdbcLogger(); + + public static JdbcLogger get() { + return instance; + } + + public final static class LogEntry { + public QueryType type; + public String sql; + public long milli; + public long nano; + public int count; + public int hash; + + public LogEntry(int hash, QueryType type, String sql, long milli, long nano) { + this.hash = hash; + this.type = type; + this.sql = sql; + this.milli = milli; + this.nano = nano; + this.count = 1; + } + + public void addCount(long milli, long nano) { + synchronized (this) { + count++; + this.milli += milli; + this.nano += nano; + } + } + + public int getCount() { + return count; + } + + public String getMilli() { + return Util.formatNano(milli*1000000/count); + } + + public String getNano() { + return Util.formatNano(nano/count); + } + + public String getTotal() { + return Util.formatNano(nano); + } + + public String getSql() { + return sql; + } + } + + private Map queries; + + public JdbcLogger() { + queries = new ConcurrentHashMap(); + } + + public void logEntry(QueryType type, String sql, long milli, long nano) { + int hash = sql.hashCode(); + LogEntry entry = queries.get(hash); + + if (entry == null) { + entry = new LogEntry(hash, type, sql, milli, nano); + queries.put(hash, entry); + } else { + entry.addCount(milli, nano); + } + + if (queries.size() > 1000) { + List toRemove = new LinkedList(); + List values = new LinkedList(queries.values()); + + Collections.sort(values, new Comparator() { + @Override + public int compare(LogEntry o1, LogEntry o2) { + return o1.count - o2.count; + } + }); + + while (queries.size() > 900) { + queries.remove(values.remove(0).hash); + + } + } + } + + public static void log(QueryType type, String sql, long milli, long nano) { + instance.logEntry(type, sql, milli, nano); + } + + public Collection getEntries() { + return queries.values(); + } + +} diff --git a/src/nl/astraeus/jdbc/PreparedStatementLogger.java b/src/nl/astraeus/jdbc/PreparedStatementLogger.java new file mode 100644 index 0000000..98aefc7 --- /dev/null +++ b/src/nl/astraeus/jdbc/PreparedStatementLogger.java @@ -0,0 +1,577 @@ +package nl.astraeus.jdbc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.InputStream; +import java.io.Reader; +import java.math.BigDecimal; +import java.net.URL; +import java.sql.*; +import java.util.Calendar; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 7:47:57 PM + */ +public class PreparedStatementLogger implements PreparedStatement { + private final static Logger log = LoggerFactory.getLogger(PreparedStatementLogger.class); + + private PreparedStatement statement; + + private String sql; + private QueryType type; + private long milli; + private long nano; + + //private ArrayList parameters; + + public PreparedStatementLogger(PreparedStatement statement) { + this.statement = statement; + this.sql = ""; + this.type = QueryType.UNKNOWN; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(QueryType type, String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(type, sql, m, n); + } + + public PreparedStatementLogger(Connection connection, String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql); + } + + public PreparedStatementLogger(Connection connection, String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatementLogger(Connection connection, String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, autoGeneratedKeys); + } + + public PreparedStatementLogger(Connection connection, String sql, int[] columnIndexes) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnIndexes); + } + + public PreparedStatementLogger(Connection connection, String sql, String[] columnNames) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnNames); + } + + public boolean execute() throws SQLException { + clearTime(); + + boolean result = statement.execute(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery() throws SQLException { + clearTime(); + + ResultSet result = statement.executeQuery(); + + log(type, sql); + + return result; + } + + public int executeUpdate() throws SQLException { + clearTime(); + + int result = statement.executeUpdate(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + ResultSet result = statement.executeQuery(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnNames); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnNames); + + log(type, sql); + + return result; + } + + + public void setNull(int parameterIndex, int sqlType) throws SQLException { + statement.setNull(parameterIndex, sqlType); + } + + public void setBoolean(int parameterIndex, boolean x) throws SQLException { + statement.setBoolean(parameterIndex, x); + } + + public void setByte(int parameterIndex, byte x) throws SQLException { + statement.setByte(parameterIndex, x); + } + + public void setShort(int parameterIndex, short x) throws SQLException { + statement.setShort(parameterIndex, x); + } + + public void setInt(int parameterIndex, int x) throws SQLException { + statement.setInt(parameterIndex, x); + } + + public void setLong(int parameterIndex, long x) throws SQLException { + statement.setLong(parameterIndex, x); + } + + public void setFloat(int parameterIndex, float x) throws SQLException { + statement.setFloat(parameterIndex, x); + } + + public void setDouble(int parameterIndex, double x) throws SQLException { + statement.setDouble(parameterIndex, x); + } + + public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { + statement.setBigDecimal(parameterIndex, x); + } + + public void setString(int parameterIndex, String x) throws SQLException { + statement.setString(parameterIndex, x); + } + + public void setBytes(int parameterIndex, byte x[]) throws SQLException { + statement.setBytes(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x) throws SQLException { + statement.setDate(parameterIndex, x); + } + + public void setTime(int parameterIndex, Time x) throws SQLException { + statement.setTime(parameterIndex, x); + } + + public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { + statement.setTimestamp(parameterIndex, x); + } + + public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setUnicodeStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType); + } + + public void setObject(int parameterIndex, Object x) throws SQLException { + statement.setObject(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setRef(int parameterIndex, Ref x) throws SQLException { + statement.setRef(parameterIndex, x); + } + + public void setBlob(int parameterIndex, Blob x) throws SQLException { + statement.setBlob(parameterIndex, x); + } + + public void setClob(int parameterIndex, Clob x) throws SQLException { + statement.setClob(parameterIndex, x); + } + + public void setArray(int parameterIndex, Array x) throws SQLException { + statement.setArray(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { + statement.setDate(parameterIndex, x, cal); + } + + public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { + statement.setTime(parameterIndex, x, cal); + } + + public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { + statement.setTimestamp(parameterIndex, x, cal); + } + + public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException { + statement.setNull(parameterIndex, sqlType, typeName); + } + + public void setURL(int parameterIndex, URL x) throws SQLException { + statement.setURL(parameterIndex, x); + } + + public void setRowId(int parameterIndex, RowId x) throws SQLException { + statement.setRowId(parameterIndex, x); + } + + public void setNString(int parameterIndex, String value) throws SQLException { + statement.setNString(parameterIndex, value); + } + + public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException { + statement.setNCharacterStream(parameterIndex, value, length); + } + + public void setNClob(int parameterIndex, NClob value) throws SQLException { + statement.setNClob(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setClob(parameterIndex, reader, length); + } + + public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException { + statement.setBlob(parameterIndex, inputStream, length); + } + + public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setNClob(parameterIndex, reader, length); + } + + public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException { + statement.setSQLXML(parameterIndex, xmlObject); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType, scaleOrLength); + } + + public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException { + statement.setAsciiStream(parameterIndex, x); + } + + public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException { + statement.setBinaryStream(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException { + statement.setCharacterStream(parameterIndex, reader); + } + + public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException { + statement.setNCharacterStream(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader) throws SQLException { + statement.setClob(parameterIndex, reader); + } + + public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException { + statement.setBlob(parameterIndex, inputStream); + } + + public void setNClob(int parameterIndex, Reader reader) throws SQLException { + statement.setNClob(parameterIndex, reader); + } + + + public void close() throws SQLException { + sql = ""; + type = QueryType.UNKNOWN; + milli = 0; + nano = 0; + + statement.close(); + } + + public ResultSetMetaData getMetaData() throws SQLException { + return statement.getMetaData(); + } + + public void clearParameters() throws SQLException { + statement.clearParameters(); + } + + public ParameterMetaData getParameterMetaData() throws SQLException { + return statement.getParameterMetaData(); + } + + public void addBatch() throws SQLException { + statement.addBatch(); + } + + public int getMaxFieldSize() throws SQLException { + return statement.getMaxFieldSize(); + } + + public void setMaxFieldSize(int max) throws SQLException { + statement.setMaxFieldSize(max); + } + + public int getMaxRows() throws SQLException { + return statement.getMaxRows(); + } + + public void setMaxRows(int max) throws SQLException { + statement.setMaxRows(max); + } + + public void setEscapeProcessing(boolean enable) throws SQLException { + statement.setEscapeProcessing(enable); + } + + public int getQueryTimeout() throws SQLException { + return statement.getQueryTimeout(); + } + + public void setQueryTimeout(int seconds) throws SQLException { + statement.setQueryTimeout(seconds); + } + + public void cancel() throws SQLException { + statement.cancel(); + } + + public SQLWarning getWarnings() throws SQLException { + return statement.getWarnings(); + } + + public void clearWarnings() throws SQLException { + statement.clearWarnings(); + } + + public void setCursorName(String name) throws SQLException { + statement.setCursorName(name); + } + + public boolean execute(String sql) throws SQLException { + return statement.execute(sql); + } + + public ResultSet getResultSet() throws SQLException { + return statement.getResultSet(); + } + + public int getUpdateCount() throws SQLException { + return statement.getUpdateCount(); + } + + public boolean getMoreResults() throws SQLException { + return statement.getMoreResults(); + } + + public void setFetchDirection(int direction) throws SQLException { + statement.setFetchDirection(direction); + } + + public int getFetchDirection() throws SQLException { + return statement.getFetchDirection(); + } + + public void setFetchSize(int rows) throws SQLException { + statement.setFetchSize(rows); + } + + public int getFetchSize() throws SQLException { + return statement.getFetchSize(); + } + + public int getResultSetConcurrency() throws SQLException { + return statement.getResultSetConcurrency(); + } + + public int getResultSetType() throws SQLException { + return statement.getResultSetType(); + } + + public void addBatch(String sql) throws SQLException { + statement.addBatch(sql); + } + + public void clearBatch() throws SQLException { + statement.clearBatch(); + } + + public int[] executeBatch() throws SQLException { + return statement.executeBatch(); + } + + public Connection getConnection() throws SQLException { + return statement.getConnection(); + } + + public boolean getMoreResults(int current) throws SQLException { + return statement.getMoreResults(current); + } + + public ResultSet getGeneratedKeys() throws SQLException { + return statement.getGeneratedKeys(); + } + + public int getResultSetHoldability() throws SQLException { + return statement.getResultSetHoldability(); + } + + public boolean isClosed() throws SQLException { + return statement.isClosed(); + } + + public void setPoolable(boolean poolable) throws SQLException { + statement.setPoolable(poolable); + } + + public boolean isPoolable() throws SQLException { + return statement.isPoolable(); + } + + @Override + public void closeOnCompletion() throws SQLException { + statement.closeOnCompletion();; + } + + @Override + public boolean isCloseOnCompletion() throws SQLException { + return statement.isCloseOnCompletion(); + } + + public T unwrap(Class iface) throws SQLException { + return statement.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return statement.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/QueryType.java b/src/nl/astraeus/jdbc/QueryType.java new file mode 100644 index 0000000..744fbfc --- /dev/null +++ b/src/nl/astraeus/jdbc/QueryType.java @@ -0,0 +1,24 @@ +package nl.astraeus.jdbc; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:32:49 PM + */ +public enum QueryType { + PLAIN("plain"), + PREPARED("prepared"), + CALLABLE("callable"), + UNKNOWN("unknown"); + + private String description; + + QueryType(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } + +} diff --git a/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java new file mode 100644 index 0000000..07aac40 --- /dev/null +++ b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java @@ -0,0 +1,68 @@ +package nl.astraeus.jdbc.example; + +import java.sql.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 7:32 PM + */ +public class JdbcStatisticsExample { + + + public static void main(String [] args) throws Exception { + Class.forName("org.h2.Driver"); + Class.forName("nl.astraeus.jdbc.Driver"); + + new JdbcStatisticsExample(); + } + + public JdbcStatisticsExample() throws Exception { + Connection conn = DriverManager.getConnection("jdbc:stat:jdbc:h2:mem:test"); + + Statement statement = null; + + statement = conn.createStatement(); + statement.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + + boolean running = true; + int count = 1; + PreparedStatement ps = null; + + while (running) { + Thread.sleep(10); + + String TableName = "TEST"+(System.nanoTime() % 1000); + + try { + ps = conn.prepareStatement("SELECT COUNT(*) FROM "+TableName); + ResultSet rs = ps.executeQuery(); + } catch (SQLException e) { + statement = conn.createStatement(); + statement.execute("CREATE TABLE "+TableName+" (ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + } finally { + if (ps!=null) { + ps.close(); + } + } + + ps = conn.prepareStatement("INSERT INTO "+TableName+" VALUES (?, ?)"); + + ps.setInt(1, count++); + ps.setString(2, "String "+System.currentTimeMillis()); + + ps.execute(); + ps.close(); + + Thread.sleep(10); + + ps = conn.prepareStatement("SELECT * FROM "+TableName); + ResultSet rs = ps.executeQuery(); + statement.close(); + } + + conn.close(); + } +} diff --git a/src/nl/astraeus/jdbc/util/IOUtils.java b/src/nl/astraeus/jdbc/util/IOUtils.java new file mode 100644 index 0000000..ce95d9d --- /dev/null +++ b/src/nl/astraeus/jdbc/util/IOUtils.java @@ -0,0 +1,38 @@ +package nl.astraeus.jdbc.util; + +import java.io.*; + +/** + * User: rnentjes + * Date: 4/9/12 + * Time: 2:33 PM + */ +public class IOUtils { + + public static String toString(InputStream in) throws IOException { + assert in != null; + + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + StringBuilder buffer = new StringBuilder(); + + while(reader.ready()) { + buffer.append(reader.readLine()); + buffer.append("\n"); + } + + return buffer.toString(); + } finally { + in.close(); + } + } + + public static void copy(InputStream in, OutputStream out) throws IOException { + byte [] buffer = new byte[1<<16]; + int bytes; + + while((bytes = in.read(buffer)) > 0) { + out.write(buffer, 0, bytes); + } + } +} diff --git a/src/nl/astraeus/jdbc/util/Util.java b/src/nl/astraeus/jdbc/util/Util.java new file mode 100644 index 0000000..eaa853b --- /dev/null +++ b/src/nl/astraeus/jdbc/util/Util.java @@ -0,0 +1,25 @@ +package nl.astraeus.jdbc.util; + +import java.text.DecimalFormat; +import java.text.NumberFormat; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 12:28 PM + */ +public class Util { + // utility functions + public static String formatNano(long l) { + NumberFormat format = new DecimalFormat("###,##0.000000"); + + return format.format((double) l / 1000000.0); + } + + public static void printMemoryUsage() { + System.out.println("Used memory: "+((Runtime.getRuntime().totalMemory() / (1024*1024))-(Runtime.getRuntime().freeMemory() / (1024*1024)))); + System.out.println("Free memory: "+(Runtime.getRuntime().freeMemory() / (1024*1024))); + System.out.println("Total memory: "+(Runtime.getRuntime().totalMemory() / (1024*1024))); + System.out.println("Max memory: "+(Runtime.getRuntime().maxMemory() / (1024*1024))); + } +} diff --git a/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java b/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java new file mode 100644 index 0000000..a162d6f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java @@ -0,0 +1,90 @@ +package nl.astraeus.jdbc.web; + +import nl.astraeus.jdbc.util.IOUtils; +import nl.astraeus.jdbc.util.Util; +import nl.astraeus.jdbc.web.page.Menu; +import nl.astraeus.jdbc.web.page.Page; +import nl.astraeus.jdbc.web.page.QueryOverview; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import java.io.IOException; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:05 PM + */ +public class JdbcStatisticsServlet extends HttpServlet { + + private String head; + private String bottom; + + @Override + public void init() throws ServletException { + super.init(); + + try { + head = IOUtils.toString(getClass().getResourceAsStream("head.html")); + bottom = IOUtils.toString(getClass().getResourceAsStream("bottom.html")); + } catch (IOException e) { + throw new ServletException(e); + } + + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + doPost(req, resp); + } + + @Override + protected void doPost(final HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + long nano = System.nanoTime(); + + HttpSession session = req.getSession(); + boolean ajax = "true".equals(req.getParameter("ajax")); + + resp.setContentType("text/html"); + + Page page = (Page)session.getAttribute("page"); + Page menu = (Page)session.getAttribute("menu"); + + session.setMaxInactiveInterval(1800); + + if (menu == null) { + menu = new Menu(); + + session.setAttribute("menu", menu); + } + + if (page == null || "menumain".equals(req.getParameter("action"))) { + page = new QueryOverview(); + } else if ("diagnostics".equals(req.getParameter("action"))) { + //page = new Diagnostics(); + } else { + page = page .processRequest(req); + } + + menu.processRequest(req); + + session.setAttribute("page", page); + + if (!ajax) { + resp.getWriter().print(head); + } + + resp.getWriter().print(menu.render(req)); + resp.getWriter().print(page.render(req)); + + if (!ajax) { + resp.getWriter().print(bottom); + } + + System.out.println("Request ends, time="+ Util.formatNano(System.nanoTime() - nano) +", page="+page.getClass().getSimpleName()); + } + +} diff --git a/src/nl/astraeus/jdbc/web/ResourceServlet.java b/src/nl/astraeus/jdbc/web/ResourceServlet.java new file mode 100644 index 0000000..7abfe6f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/ResourceServlet.java @@ -0,0 +1,49 @@ +package nl.astraeus.jdbc.web; + +import nl.astraeus.jdbc.util.IOUtils; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.InputStream; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:05 PM + */ +public class ResourceServlet extends HttpServlet { + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String uri = req.getRequestURI(); + + uri = "nl/astraeus/jdbc/web" + uri; + InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(uri); + + if (in == null) { + resp.sendError(404, "Cannot find resource '" + uri + "'."); + } else { + try { + if (uri.endsWith("js")) { + resp.setContentType("text/javascript"); + } else if (uri.endsWith("css")) { + resp.setContentType("text/css"); + } else if (uri.endsWith("png")) { + resp.setContentType("image/png"); + } else if (uri.endsWith("jpg")) { + resp.setContentType("image/jpeg"); + } else if (uri.endsWith("gif")) { + resp.setContentType("image/gif"); + } + + IOUtils.copy(in, resp.getOutputStream()); + } finally { + in.close(); + } + } + } + +} diff --git a/src/nl/astraeus/jdbc/web/bottom.html b/src/nl/astraeus/jdbc/web/bottom.html new file mode 100644 index 0000000..1288de4 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/bottom.html @@ -0,0 +1,8 @@ + + +
+ + + + + \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/head.html b/src/nl/astraeus/jdbc/web/head.html new file mode 100644 index 0000000..0f8f6a3 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/head.html @@ -0,0 +1,96 @@ + + + + + + + Simple JDBC Statistics + + + + + + + + + + + + + + + + + + + +
+
+ +
+ diff --git a/src/nl/astraeus/jdbc/web/page/Menu.html b/src/nl/astraeus/jdbc/web/page/Menu.html new file mode 100644 index 0000000..505c7c2 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.html @@ -0,0 +1,42 @@ + diff --git a/src/nl/astraeus/jdbc/web/page/Menu.java b/src/nl/astraeus/jdbc/web/page/Menu.java new file mode 100644 index 0000000..f0a349a --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.java @@ -0,0 +1,27 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 9:07 PM + */ +public class Menu extends TemplatePage { + + @Override + public Page processRequest(HttpServletRequest request) { + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + result.put("user", request.getSession().getAttribute("user")); + + return result; + } +} diff --git a/src/nl/astraeus/jdbc/web/page/Page.java b/src/nl/astraeus/jdbc/web/page/Page.java new file mode 100644 index 0000000..9d526d6 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Page.java @@ -0,0 +1,17 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:20 PM + */ +public abstract class Page { + + public abstract Page processRequest(HttpServletRequest request); + public abstract Map defineModel(HttpServletRequest request); + public abstract String render(HttpServletRequest request); + +} diff --git a/src/nl/astraeus/jdbc/web/page/QueryOverview.html b/src/nl/astraeus/jdbc/web/page/QueryOverview.html new file mode 100644 index 0000000..64a88fb --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/QueryOverview.html @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + {foreach(queries as q)} + + + + + + + {eachend} + +
Total timeAvg. time# CallsSql
{q.total}{q.nano}{q.count}{q.sql}
diff --git a/src/nl/astraeus/jdbc/web/page/QueryOverview.java b/src/nl/astraeus/jdbc/web/page/QueryOverview.java new file mode 100644 index 0000000..02982f1 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/QueryOverview.java @@ -0,0 +1,92 @@ +package nl.astraeus.jdbc.web.page; + +import nl.astraeus.jdbc.JdbcLogger; + +import javax.servlet.http.HttpServletRequest; +import java.util.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 9:16 PM + */ +public class QueryOverview extends TemplatePage { + + boolean sortTotalCalls = true; + boolean sortAvgTime = false; + boolean sortTotalTime = false; + + @Override + public Page processRequest(HttpServletRequest request) { + if ("sortTotalCalls".equals(request.getParameter("action"))) { + sortTotalCalls = true; + sortAvgTime = false; + sortTotalTime = false; + } else if ("sortAvgTime".equals(request.getParameter("action"))) { + sortTotalCalls = false; + sortAvgTime = true; + sortTotalTime = false; + } else if ("sortTotalTime".equals(request.getParameter("action"))) { + sortTotalCalls = false; + sortAvgTime = false; + sortTotalTime = true; + } + + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + List entries = new ArrayList(JdbcLogger.get().getEntries()); + + if (sortTotalCalls) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + return o2.count - o1.count; + } + }); + } else if (sortAvgTime) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + long n1 = o1.nano / o1.count; + long n2 = o2.nano / o2.count; + + if (n2 > n1) { + return 1; + } else if (n2 < n1) { + return -1; + } else { + return 0; + } + } + }); + } else if (sortTotalTime) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + if (o2.nano > o1.nano) { + return 1; + } else if (o2.nano < o1.nano) { + return -1; + } else { + return 0; + } + } + }); + } + + result.put("queries", entries); + result.put("count", entries.size()); + + result.put("sortTotalCalls", sortTotalCalls); + result.put("sortAvgTime", sortAvgTime); + result.put("sortTotalTime", sortTotalTime); + + return result; + } + +} diff --git a/src/nl/astraeus/jdbc/web/page/TemplatePage.java b/src/nl/astraeus/jdbc/web/page/TemplatePage.java new file mode 100644 index 0000000..33e2641 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/TemplatePage.java @@ -0,0 +1,58 @@ +package nl.astraeus.jdbc.web.page; + +import nl.astraeus.template.EscapeMode; +import nl.astraeus.template.SimpleTemplate; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:20 PM + */ +public abstract class TemplatePage extends Page { + + private SimpleTemplate template; + + protected TemplatePage() { + template = getSimpleTemplate(this.getClass()); + } + + public String render(HttpServletRequest request) { + return template.render(defineModel(request)); + } + + private static Map templateCache = new HashMap(); + + public synchronized static SimpleTemplate getSimpleTemplate(Class cls) { + SimpleTemplate result = templateCache.get(cls); + + if (result == null) { + InputStream in = null; + + try { + in = cls.getResourceAsStream(cls.getSimpleName() + ".html"); + + result = SimpleTemplate.readTemplate('{','}', EscapeMode.HTML, in); + + templateCache.put(cls, result); + } catch (IOException e) { + throw new IllegalStateException(e); + } finally { + if (in != null) { + try { + in.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + + return result; + } +} diff --git a/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css b/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css new file mode 100644 index 0000000..0e0056f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css @@ -0,0 +1,581 @@ +/*! + * Bootstrap Responsive v2.0.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ +.clearfix { + *zoom: 1; +} +.clearfix:before, .clearfix:after { + display: table; + content: ""; +} +.clearfix:after { + clear: both; +} +.hidden { + display: none; + visibility: hidden; +} +@media (max-width: 480px) { + .nav-collapse { + -webkit-transform: translate3d(0, 0, 0); + } + .page-header h1 small { + display: block; + line-height: 18px; + } + input[class*="span"], + select[class*="span"], + textarea[class*="span"], + .uneditable-input { + display: block; + width: 100%; + min-height: 28px; + /* Make inputs at least the height of their button counterpart */ + + /* Makes inputs behave like true block-level elements */ + + -webkit-box-sizing: border-box; + /* Older Webkit */ + + -moz-box-sizing: border-box; + /* Older FF */ + + -ms-box-sizing: border-box; + /* IE8 */ + + box-sizing: border-box; + /* CSS3 spec*/ + + } + .input-prepend input[class*="span"], .input-append input[class*="span"] { + width: auto; + } + input[type="checkbox"], input[type="radio"] { + border: 1px solid #ccc; + } + .form-horizontal .control-group > label { + float: none; + width: auto; + padding-top: 0; + text-align: left; + } + .form-horizontal .controls { + margin-left: 0; + } + .form-horizontal .control-list { + padding-top: 0; + } + .form-horizontal .form-actions { + padding-left: 10px; + padding-right: 10px; + } + .modal { + position: absolute; + top: 10px; + left: 10px; + right: 10px; + width: auto; + margin: 0; + } + .modal.fade.in { + top: auto; + } + .modal-header .close { + padding: 10px; + margin: -10px; + } + .carousel-caption { + position: static; + } +} +@media (max-width: 767px) { + .container { + width: auto; + padding: 0 20px; + } + .row-fluid { + width: 100%; + } + .row { + margin-left: 0; + } + .row > [class*="span"], .row-fluid > [class*="span"] { + float: none; + display: block; + width: auto; + margin: 0; + } +} +@media (min-width: 768px) and (max-width: 979px) { + .row { + margin-left: -20px; + *zoom: 1; + } + .row:before, .row:after { + display: table; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + margin-left: 20px; + } + .span1 { + width: 42px; + } + .span2 { + width: 104px; + } + .span3 { + width: 166px; + } + .span4 { + width: 228px; + } + .span5 { + width: 290px; + } + .span6 { + width: 352px; + } + .span7 { + width: 414px; + } + .span8 { + width: 476px; + } + .span9 { + width: 538px; + } + .span10 { + width: 600px; + } + .span11 { + width: 662px; + } + .span12, .container { + width: 724px; + } + .offset1 { + margin-left: 82px; + } + .offset2 { + margin-left: 144px; + } + .offset3 { + margin-left: 206px; + } + .offset4 { + margin-left: 268px; + } + .offset5 { + margin-left: 330px; + } + .offset6 { + margin-left: 392px; + } + .offset7 { + margin-left: 454px; + } + .offset8 { + margin-left: 516px; + } + .offset9 { + margin-left: 578px; + } + .offset10 { + margin-left: 640px; + } + .offset11 { + margin-left: 702px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, .row-fluid:after { + display: table; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid > [class*="span"] { + float: left; + margin-left: 2.762430939%; + } + .row-fluid > [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid > .span1 { + width: 5.801104972%; + } + .row-fluid > .span2 { + width: 14.364640883%; + } + .row-fluid > .span3 { + width: 22.928176794%; + } + .row-fluid > .span4 { + width: 31.491712705%; + } + .row-fluid > .span5 { + width: 40.055248616%; + } + .row-fluid > .span6 { + width: 48.618784527%; + } + .row-fluid > .span7 { + width: 57.182320438000005%; + } + .row-fluid > .span8 { + width: 65.74585634900001%; + } + .row-fluid > .span9 { + width: 74.30939226%; + } + .row-fluid > .span10 { + width: 82.87292817100001%; + } + .row-fluid > .span11 { + width: 91.436464082%; + } + .row-fluid > .span12 { + width: 99.999999993%; + } + input.span1, textarea.span1, .uneditable-input.span1 { + width: 32px; + } + input.span2, textarea.span2, .uneditable-input.span2 { + width: 94px; + } + input.span3, textarea.span3, .uneditable-input.span3 { + width: 156px; + } + input.span4, textarea.span4, .uneditable-input.span4 { + width: 218px; + } + input.span5, textarea.span5, .uneditable-input.span5 { + width: 280px; + } + input.span6, textarea.span6, .uneditable-input.span6 { + width: 342px; + } + input.span7, textarea.span7, .uneditable-input.span7 { + width: 404px; + } + input.span8, textarea.span8, .uneditable-input.span8 { + width: 466px; + } + input.span9, textarea.span9, .uneditable-input.span9 { + width: 528px; + } + input.span10, textarea.span10, .uneditable-input.span10 { + width: 590px; + } + input.span11, textarea.span11, .uneditable-input.span11 { + width: 652px; + } + input.span12, textarea.span12, .uneditable-input.span12 { + width: 714px; + } +} +@media (max-width: 979px) { + body { + padding-top: 0; + } + .navbar-fixed-top { + position: static; + margin-bottom: 18px; + } + .navbar-fixed-top .navbar-inner { + padding: 5px; + } + .navbar .container { + width: auto; + padding: 0; + } + .navbar .brand { + padding-left: 10px; + padding-right: 10px; + margin: 0 0 0 -5px; + } + .navbar .nav-collapse { + clear: left; + } + .navbar .nav { + float: none; + margin: 0 0 9px; + } + .navbar .nav > li { + float: none; + } + .navbar .nav > li > a { + margin-bottom: 2px; + } + .navbar .nav > .divider-vertical { + display: none; + } + .navbar .nav .nav-header { + color: #999999; + text-shadow: none; + } + .navbar .nav > li > a, .navbar .dropdown-menu a { + padding: 6px 15px; + font-weight: bold; + color: #999999; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + } + .navbar .dropdown-menu li + li a { + margin-bottom: 2px; + } + .navbar .nav > li > a:hover, .navbar .dropdown-menu a:hover { + background-color: #222222; + } + .navbar .dropdown-menu { + position: static; + top: auto; + left: auto; + float: none; + display: block; + max-width: none; + margin: 0 15px; + padding: 0; + background-color: transparent; + border: none; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + } + .navbar .dropdown-menu:before, .navbar .dropdown-menu:after { + display: none; + } + .navbar .dropdown-menu .divider { + display: none; + } + .navbar-form, .navbar-search { + float: none; + padding: 9px 15px; + margin: 9px 0; + border-top: 1px solid #222222; + border-bottom: 1px solid #222222; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + } + .navbar .nav.pull-right { + float: none; + margin-left: 0; + } + .navbar-static .navbar-inner { + padding-left: 10px; + padding-right: 10px; + } + .btn-navbar { + display: block; + } + .nav-collapse { + overflow: hidden; + height: 0; + } +} +@media (min-width: 980px) { + .nav-collapse.collapse { + height: auto !important; + } +} +@media (min-width: 1200px) { + .row { + margin-left: -30px; + *zoom: 1; + } + .row:before, .row:after { + display: table; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + margin-left: 30px; + } + .span1 { + width: 70px; + } + .span2 { + width: 170px; + } + .span3 { + width: 270px; + } + .span4 { + width: 370px; + } + .span5 { + width: 470px; + } + .span6 { + width: 570px; + } + .span7 { + width: 670px; + } + .span8 { + width: 770px; + } + .span9 { + width: 870px; + } + .span10 { + width: 970px; + } + .span11 { + width: 1070px; + } + .span12, .container { + width: 1170px; + } + .offset1 { + margin-left: 130px; + } + .offset2 { + margin-left: 230px; + } + .offset3 { + margin-left: 330px; + } + .offset4 { + margin-left: 430px; + } + .offset5 { + margin-left: 530px; + } + .offset6 { + margin-left: 630px; + } + .offset7 { + margin-left: 730px; + } + .offset8 { + margin-left: 830px; + } + .offset9 { + margin-left: 930px; + } + .offset10 { + margin-left: 1030px; + } + .offset11 { + margin-left: 1130px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, .row-fluid:after { + display: table; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid > [class*="span"] { + float: left; + margin-left: 2.564102564%; + } + .row-fluid > [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid > .span1 { + width: 5.982905983%; + } + .row-fluid > .span2 { + width: 14.529914530000001%; + } + .row-fluid > .span3 { + width: 23.076923077%; + } + .row-fluid > .span4 { + width: 31.623931624%; + } + .row-fluid > .span5 { + width: 40.170940171000005%; + } + .row-fluid > .span6 { + width: 48.717948718%; + } + .row-fluid > .span7 { + width: 57.264957265%; + } + .row-fluid > .span8 { + width: 65.81196581200001%; + } + .row-fluid > .span9 { + width: 74.358974359%; + } + .row-fluid > .span10 { + width: 82.905982906%; + } + .row-fluid > .span11 { + width: 91.45299145300001%; + } + .row-fluid > .span12 { + width: 100%; + } + input.span1, textarea.span1, .uneditable-input.span1 { + width: 60px; + } + input.span2, textarea.span2, .uneditable-input.span2 { + width: 160px; + } + input.span3, textarea.span3, .uneditable-input.span3 { + width: 260px; + } + input.span4, textarea.span4, .uneditable-input.span4 { + width: 360px; + } + input.span5, textarea.span5, .uneditable-input.span5 { + width: 460px; + } + input.span6, textarea.span6, .uneditable-input.span6 { + width: 560px; + } + input.span7, textarea.span7, .uneditable-input.span7 { + width: 660px; + } + input.span8, textarea.span8, .uneditable-input.span8 { + width: 760px; + } + input.span9, textarea.span9, .uneditable-input.span9 { + width: 860px; + } + input.span10, textarea.span10, .uneditable-input.span10 { + width: 960px; + } + input.span11, textarea.span11, .uneditable-input.span11 { + width: 1060px; + } + input.span12, textarea.span12, .uneditable-input.span12 { + width: 1160px; + } + .thumbnails { + margin-left: -30px; + } + .thumbnails > li { + margin-left: 30px; + } +} diff --git a/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css b/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css new file mode 100644 index 0000000..6229c12 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css @@ -0,0 +1,3521 @@ +/*! + * Bootstrap v2.0.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +nav, +section { + display: block; +} +audio, canvas, video { + display: inline-block; + *display: inline; + *zoom: 1; +} +audio:not([controls]) { + display: none; +} +html { + font-size: 100%; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} +a:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +a:hover, a:active { + outline: 0; +} +sub, sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} +sup { + top: -0.5em; +} +sub { + bottom: -0.25em; +} +img { + max-width: 100%; + height: auto; + border: 0; + -ms-interpolation-mode: bicubic; +} +button, +input, +select, +textarea { + margin: 0; + font-size: 100%; + vertical-align: middle; +} +button, input { + *overflow: visible; + line-height: normal; +} +button::-moz-focus-inner, input::-moz-focus-inner { + padding: 0; + border: 0; +} +button, +input[type="button"], +input[type="reset"], +input[type="submit"] { + cursor: pointer; + -webkit-appearance: button; +} +input[type="search"] { + -webkit-appearance: textfield; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +input[type="search"]::-webkit-search-decoration, input[type="search"]::-webkit-search-cancel-button { + -webkit-appearance: none; +} +textarea { + overflow: auto; + vertical-align: top; +} +.clearfix { + *zoom: 1; +} +.clearfix:before, .clearfix:after { + display: table; + content: ""; +} +.clearfix:after { + clear: both; +} +body { + margin: 0; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 18px; + color: #333333; + background-color: #ffffff; +} +a { + color: #0088cc; + text-decoration: none; +} +a:hover { + color: #005580; + text-decoration: underline; +} +.row { + margin-left: -20px; + *zoom: 1; +} +.row:before, .row:after { + display: table; + content: ""; +} +.row:after { + clear: both; +} +[class*="span"] { + float: left; + margin-left: 20px; +} +.span1 { + width: 60px; +} +.span2 { + width: 140px; +} +.span3 { + width: 220px; +} +.span4 { + width: 300px; +} +.span5 { + width: 380px; +} +.span6 { + width: 460px; +} +.span7 { + width: 540px; +} +.span8 { + width: 620px; +} +.span9 { + width: 700px; +} +.span10 { + width: 780px; +} +.span11 { + width: 860px; +} +.span12, .container { + width: 940px; +} +.offset1 { + margin-left: 100px; +} +.offset2 { + margin-left: 180px; +} +.offset3 { + margin-left: 260px; +} +.offset4 { + margin-left: 340px; +} +.offset5 { + margin-left: 420px; +} +.offset6 { + margin-left: 500px; +} +.offset7 { + margin-left: 580px; +} +.offset8 { + margin-left: 660px; +} +.offset9 { + margin-left: 740px; +} +.offset10 { + margin-left: 820px; +} +.offset11 { + margin-left: 900px; +} +.row-fluid { + width: 100%; + *zoom: 1; +} +.row-fluid:before, .row-fluid:after { + display: table; + content: ""; +} +.row-fluid:after { + clear: both; +} +.row-fluid > [class*="span"] { + float: left; + margin-left: 2.127659574%; +} +.row-fluid > [class*="span"]:first-child { + margin-left: 0; +} +.row-fluid > .span1 { + width: 6.382978723%; +} +.row-fluid > .span2 { + width: 14.89361702%; +} +.row-fluid > .span3 { + width: 23.404255317%; +} +.row-fluid > .span4 { + width: 31.914893614%; +} +.row-fluid > .span5 { + width: 40.425531911%; +} +.row-fluid > .span6 { + width: 48.93617020799999%; +} +.row-fluid > .span7 { + width: 57.446808505%; +} +.row-fluid > .span8 { + width: 65.95744680199999%; +} +.row-fluid > .span9 { + width: 74.468085099%; +} +.row-fluid > .span10 { + width: 82.97872339599999%; +} +.row-fluid > .span11 { + width: 91.489361693%; +} +.row-fluid > .span12 { + width: 99.99999998999999%; +} +.container { + width: 940px; + margin-left: auto; + margin-right: auto; + *zoom: 1; +} +.container:before, .container:after { + display: table; + content: ""; +} +.container:after { + clear: both; +} +.container-fluid { + padding-left: 20px; + padding-right: 20px; + *zoom: 1; +} +.container-fluid:before, .container-fluid:after { + display: table; + content: ""; +} +.container-fluid:after { + clear: both; +} +p { + margin: 0 0 9px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 18px; +} +p small { + font-size: 11px; + color: #999999; +} +.lead { + margin-bottom: 18px; + font-size: 20px; + font-weight: 200; + line-height: 27px; +} +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 0; + font-weight: bold; + color: #333333; + text-rendering: optimizelegibility; +} +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small { + font-weight: normal; + color: #999999; +} +h1 { + font-size: 30px; + line-height: 36px; +} +h1 small { + font-size: 18px; +} +h2 { + font-size: 24px; + line-height: 36px; +} +h2 small { + font-size: 18px; +} +h3 { + line-height: 27px; + font-size: 18px; +} +h3 small { + font-size: 14px; +} +h4, h5, h6 { + line-height: 18px; +} +h4 { + font-size: 14px; +} +h4 small { + font-size: 12px; +} +h5 { + font-size: 12px; +} +h6 { + font-size: 11px; + color: #999999; + text-transform: uppercase; +} +.page-header { + padding-bottom: 17px; + margin: 18px 0; + border-bottom: 1px solid #eeeeee; +} +.page-header h1 { + line-height: 1; +} +ul, ol { + padding: 0; + margin: 0 0 9px 25px; +} +ul ul, +ul ol, +ol ol, +ol ul { + margin-bottom: 0; +} +ul { + list-style: disc; +} +ol { + list-style: decimal; +} +li { + line-height: 18px; +} +ul.unstyled, ol.unstyled { + margin-left: 0; + list-style: none; +} +dl { + margin-bottom: 18px; +} +dt, dd { + line-height: 18px; +} +dt { + font-weight: bold; +} +dd { + margin-left: 9px; +} +hr { + margin: 18px 0; + border: 0; + border-top: 1px solid #eeeeee; + border-bottom: 1px solid #ffffff; +} +strong { + font-weight: bold; +} +em { + font-style: italic; +} +.muted { + color: #999999; +} +abbr { + font-size: 90%; + text-transform: uppercase; + border-bottom: 1px dotted #ddd; + cursor: help; +} +blockquote { + padding: 0 0 0 15px; + margin: 0 0 18px; + border-left: 5px solid #eeeeee; +} +blockquote p { + margin-bottom: 0; + font-size: 16px; + font-weight: 300; + line-height: 22.5px; +} +blockquote small { + display: block; + line-height: 18px; + color: #999999; +} +blockquote small:before { + content: '\2014 \00A0'; +} +blockquote.pull-right { + float: right; + padding-left: 0; + padding-right: 15px; + border-left: 0; + border-right: 5px solid #eeeeee; +} +blockquote.pull-right p, blockquote.pull-right small { + text-align: right; +} +q:before, +q:after, +blockquote:before, +blockquote:after { + content: ""; +} +address { + display: block; + margin-bottom: 18px; + line-height: 18px; + font-style: normal; +} +small { + font-size: 100%; +} +cite { + font-style: normal; +} +code, pre { + padding: 0 3px 2px; + font-family: Menlo, Monaco, "Courier New", monospace; + font-size: 12px; + color: #333333; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +code { + padding: 3px 4px; + color: #d14; + background-color: #f7f7f9; + border: 1px solid #e1e1e8; +} +pre { + display: block; + padding: 8.5px; + margin: 0 0 9px; + font-size: 12px; + line-height: 18px; + background-color: #f5f5f5; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.15); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + white-space: pre; + white-space: pre-wrap; + word-break: break-all; + word-wrap: break-word; +} +pre.prettyprint { + margin-bottom: 18px; +} +pre code { + padding: 0; + color: inherit; + background-color: transparent; + border: 0; +} +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} +form { + margin: 0 0 18px; +} +fieldset { + padding: 0; + margin: 0; + border: 0; +} +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 27px; + font-size: 19.5px; + line-height: 36px; + color: #333333; + border: 0; + border-bottom: 1px solid #eee; +} +legend small { + font-size: 13.5px; + color: #999999; +} +label, +input, +button, +select, +textarea { + font-size: 13px; + font-weight: normal; + line-height: 18px; +} +input, +button, +select, +textarea { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; +} +label { + display: block; + margin-bottom: 5px; + color: #333333; +} +input, +textarea, +select, +.uneditable-input { + display: inline-block; + width: 210px; + height: 18px; + padding: 4px; + margin-bottom: 9px; + font-size: 13px; + line-height: 18px; + color: #555555; + border: 1px solid #ccc; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.uneditable-textarea { + width: auto; + height: auto; +} +label input, label textarea, label select { + display: block; +} +input[type="image"], input[type="checkbox"], input[type="radio"] { + width: auto; + height: auto; + padding: 0; + margin: 3px 0; + *margin-top: 0; + /* IE7 */ + + line-height: normal; + cursor: pointer; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + border: 0 \9; + /* IE9 and down */ + +} +input[type="image"] { + border: 0; +} +input[type="file"] { + width: auto; + padding: initial; + line-height: initial; + border: initial; + background-color: #ffffff; + background-color: initial; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +input[type="button"], input[type="reset"], input[type="submit"] { + width: auto; + height: auto; +} +select, input[type="file"] { + height: 28px; + /* In IE7, the height of the select element cannot be changed by height, only font-size */ + + *margin-top: 4px; + /* For IE7, add top margin to align select with labels */ + + line-height: 28px; +} +input[type="file"] { + line-height: 18px \9; +} +select { + width: 220px; + background-color: #ffffff; +} +select[multiple], select[size] { + height: auto; +} +input[type="image"] { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +textarea { + height: auto; +} +input[type="hidden"] { + display: none; +} +.radio, .checkbox { + padding-left: 18px; +} +.radio input[type="radio"], .checkbox input[type="checkbox"] { + float: left; + margin-left: -18px; +} +.controls > .radio:first-child, .controls > .checkbox:first-child { + padding-top: 5px; +} +.radio.inline, .checkbox.inline { + display: inline-block; + padding-top: 5px; + margin-bottom: 0; + vertical-align: middle; +} +.radio.inline + .radio.inline, .checkbox.inline + .checkbox.inline { + margin-left: 10px; +} +input, textarea { + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; + -moz-transition: border linear 0.2s, box-shadow linear 0.2s; + -ms-transition: border linear 0.2s, box-shadow linear 0.2s; + -o-transition: border linear 0.2s, box-shadow linear 0.2s; + transition: border linear 0.2s, box-shadow linear 0.2s; +} +input:focus, textarea:focus { + border-color: rgba(82, 168, 236, 0.8); + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + outline: 0; + outline: thin dotted \9; + /* IE6-9 */ + +} +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus, +select:focus { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.input-mini { + width: 60px; +} +.input-small { + width: 90px; +} +.input-medium { + width: 150px; +} +.input-large { + width: 210px; +} +.input-xlarge { + width: 270px; +} +.input-xxlarge { + width: 530px; +} +input[class*="span"], +select[class*="span"], +textarea[class*="span"], +.uneditable-input { + float: none; + margin-left: 0; +} +input.span1, textarea.span1, .uneditable-input.span1 { + width: 50px; +} +input.span2, textarea.span2, .uneditable-input.span2 { + width: 130px; +} +input.span3, textarea.span3, .uneditable-input.span3 { + width: 210px; +} +input.span4, textarea.span4, .uneditable-input.span4 { + width: 290px; +} +input.span5, textarea.span5, .uneditable-input.span5 { + width: 370px; +} +input.span6, textarea.span6, .uneditable-input.span6 { + width: 450px; +} +input.span7, textarea.span7, .uneditable-input.span7 { + width: 530px; +} +input.span8, textarea.span8, .uneditable-input.span8 { + width: 610px; +} +input.span9, textarea.span9, .uneditable-input.span9 { + width: 690px; +} +input.span10, textarea.span10, .uneditable-input.span10 { + width: 770px; +} +input.span11, textarea.span11, .uneditable-input.span11 { + width: 850px; +} +input.span12, textarea.span12, .uneditable-input.span12 { + width: 930px; +} +input[disabled], +select[disabled], +textarea[disabled], +input[readonly], +select[readonly], +textarea[readonly] { + background-color: #f5f5f5; + border-color: #ddd; + cursor: not-allowed; +} +.control-group.warning > label, .control-group.warning .help-block, .control-group.warning .help-inline { + color: #c09853; +} +.control-group.warning input, .control-group.warning select, .control-group.warning textarea { + color: #c09853; + border-color: #c09853; +} +.control-group.warning input:focus, .control-group.warning select:focus, .control-group.warning textarea:focus { + border-color: #a47e3c; + -webkit-box-shadow: 0 0 6px #dbc59e; + -moz-box-shadow: 0 0 6px #dbc59e; + box-shadow: 0 0 6px #dbc59e; +} +.control-group.warning .input-prepend .add-on, .control-group.warning .input-append .add-on { + color: #c09853; + background-color: #fcf8e3; + border-color: #c09853; +} +.control-group.error > label, .control-group.error .help-block, .control-group.error .help-inline { + color: #b94a48; +} +.control-group.error input, .control-group.error select, .control-group.error textarea { + color: #b94a48; + border-color: #b94a48; +} +.control-group.error input:focus, .control-group.error select:focus, .control-group.error textarea:focus { + border-color: #953b39; + -webkit-box-shadow: 0 0 6px #d59392; + -moz-box-shadow: 0 0 6px #d59392; + box-shadow: 0 0 6px #d59392; +} +.control-group.error .input-prepend .add-on, .control-group.error .input-append .add-on { + color: #b94a48; + background-color: #f2dede; + border-color: #b94a48; +} +.control-group.success > label, .control-group.success .help-block, .control-group.success .help-inline { + color: #468847; +} +.control-group.success input, .control-group.success select, .control-group.success textarea { + color: #468847; + border-color: #468847; +} +.control-group.success input:focus, .control-group.success select:focus, .control-group.success textarea:focus { + border-color: #356635; + -webkit-box-shadow: 0 0 6px #7aba7b; + -moz-box-shadow: 0 0 6px #7aba7b; + box-shadow: 0 0 6px #7aba7b; +} +.control-group.success .input-prepend .add-on, .control-group.success .input-append .add-on { + color: #468847; + background-color: #dff0d8; + border-color: #468847; +} +input:focus:required:invalid, textarea:focus:required:invalid, select:focus:required:invalid { + color: #b94a48; + border-color: #ee5f5b; +} +input:focus:required:invalid:focus, textarea:focus:required:invalid:focus, select:focus:required:invalid:focus { + border-color: #e9322d; + -webkit-box-shadow: 0 0 6px #f8b9b7; + -moz-box-shadow: 0 0 6px #f8b9b7; + box-shadow: 0 0 6px #f8b9b7; +} +.form-actions { + padding: 17px 20px 18px; + margin-top: 18px; + margin-bottom: 18px; + background-color: #f5f5f5; + border-top: 1px solid #ddd; +} +.uneditable-input { + display: block; + background-color: #ffffff; + border-color: #eee; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + cursor: not-allowed; +} +:-moz-placeholder { + color: #999999; +} +::-webkit-input-placeholder { + color: #999999; +} +.help-block { + display: block; + margin-top: 5px; + margin-bottom: 0; + color: #999999; +} +.help-inline { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; + margin-bottom: 9px; + vertical-align: middle; + padding-left: 5px; +} +.input-prepend, .input-append { + margin-bottom: 5px; + *zoom: 1; +} +.input-prepend:before, +.input-append:before, +.input-prepend:after, +.input-append:after { + display: table; + content: ""; +} +.input-prepend:after, .input-append:after { + clear: both; +} +.input-prepend input, +.input-append input, +.input-prepend .uneditable-input, +.input-append .uneditable-input { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.input-prepend input:focus, +.input-append input:focus, +.input-prepend .uneditable-input:focus, +.input-append .uneditable-input:focus { + position: relative; + z-index: 2; +} +.input-prepend .uneditable-input, .input-append .uneditable-input { + border-left-color: #ccc; +} +.input-prepend .add-on, .input-append .add-on { + float: left; + display: block; + width: auto; + min-width: 16px; + height: 18px; + margin-right: -1px; + padding: 4px 5px; + font-weight: normal; + line-height: 18px; + color: #999999; + text-align: center; + text-shadow: 0 1px 0 #ffffff; + background-color: #f5f5f5; + border: 1px solid #ccc; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.input-prepend .active, .input-append .active { + background-color: #a9dba9; + border-color: #46a546; +} +.input-prepend .add-on { + *margin-top: 1px; + /* IE6-7 */ + +} +.input-append input, .input-append .uneditable-input { + float: left; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.input-append .uneditable-input { + border-left-color: #eee; + border-right-color: #ccc; +} +.input-append .add-on { + margin-right: 0; + margin-left: -1px; + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.input-append input:first-child { + *margin-left: -160px; +} +.input-append input:first-child + .add-on { + *margin-left: -21px; +} +.search-query { + padding-left: 14px; + padding-right: 14px; + margin-bottom: 0; + -webkit-border-radius: 14px; + -moz-border-radius: 14px; + border-radius: 14px; +} +.form-search input, +.form-inline input, +.form-horizontal input, +.form-search textarea, +.form-inline textarea, +.form-horizontal textarea, +.form-search select, +.form-inline select, +.form-horizontal select, +.form-search .help-inline, +.form-inline .help-inline, +.form-horizontal .help-inline, +.form-search .uneditable-input, +.form-inline .uneditable-input, +.form-horizontal .uneditable-input { + display: inline-block; + margin-bottom: 0; +} +.form-search .hide, .form-inline .hide, .form-horizontal .hide { + display: none; +} +.form-search label, +.form-inline label, +.form-search .input-append, +.form-inline .input-append, +.form-search .input-prepend, +.form-inline .input-prepend { + display: inline-block; +} +.form-search .input-append .add-on, +.form-inline .input-prepend .add-on, +.form-search .input-append .add-on, +.form-inline .input-prepend .add-on { + vertical-align: middle; +} +.form-search .radio, +.form-inline .radio, +.form-search .checkbox, +.form-inline .checkbox { + margin-bottom: 0; + vertical-align: middle; +} +.control-group { + margin-bottom: 9px; +} +legend + .control-group { + margin-top: 18px; + -webkit-margin-top-collapse: separate; +} +.form-horizontal .control-group { + margin-bottom: 18px; + *zoom: 1; +} +.form-horizontal .control-group:before, .form-horizontal .control-group:after { + display: table; + content: ""; +} +.form-horizontal .control-group:after { + clear: both; +} +.form-horizontal .control-label { + float: left; + width: 140px; + padding-top: 5px; + text-align: right; +} +.form-horizontal .controls { + margin-left: 160px; +} +.form-horizontal .form-actions { + padding-left: 160px; +} +table { + max-width: 100%; + border-collapse: collapse; + border-spacing: 0; +} +.table { + width: 100%; + margin-bottom: 18px; +} +.table th, .table td { + padding: 8px; + line-height: 18px; + text-align: left; + vertical-align: top; + border-top: 1px solid #ddd; +} +.table th { + font-weight: bold; +} +.table thead th { + vertical-align: bottom; +} +.table thead:first-child tr th, .table thead:first-child tr td { + border-top: 0; +} +.table tbody + tbody { + border-top: 2px solid #ddd; +} +.table-condensed th, .table-condensed td { + padding: 4px 5px; +} +.table-bordered { + border: 1px solid #ddd; + border-collapse: separate; + *border-collapse: collapsed; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.table-bordered th + th, +.table-bordered td + td, +.table-bordered th + td, +.table-bordered td + th { + border-left: 1px solid #ddd; +} +.table-bordered thead:first-child tr:first-child th, .table-bordered tbody:first-child tr:first-child th, .table-bordered tbody:first-child tr:first-child td { + border-top: 0; +} +.table-bordered thead:first-child tr:first-child th:first-child, .table-bordered tbody:first-child tr:first-child td:first-child { + -webkit-border-radius: 4px 0 0 0; + -moz-border-radius: 4px 0 0 0; + border-radius: 4px 0 0 0; +} +.table-bordered thead:first-child tr:first-child th:last-child, .table-bordered tbody:first-child tr:first-child td:last-child { + -webkit-border-radius: 0 4px 0 0; + -moz-border-radius: 0 4px 0 0; + border-radius: 0 4px 0 0; +} +.table-bordered thead:last-child tr:last-child th:first-child, .table-bordered tbody:last-child tr:last-child td:first-child { + -webkit-border-radius: 0 0 0 4px; + -moz-border-radius: 0 0 0 4px; + border-radius: 0 0 0 4px; +} +.table-bordered thead:last-child tr:last-child th:last-child, .table-bordered tbody:last-child tr:last-child td:last-child { + -webkit-border-radius: 0 0 4px 0; + -moz-border-radius: 0 0 4px 0; + border-radius: 0 0 4px 0; +} +.table-striped tbody tr:nth-child(odd) td, .table-striped tbody tr:nth-child(odd) th { + background-color: #f9f9f9; +} +.table tbody tr:hover td, .table tbody tr:hover th { + background-color: #f5f5f5; +} +table .span1 { + float: none; + width: 44px; + margin-left: 0; +} +table .span2 { + float: none; + width: 124px; + margin-left: 0; +} +table .span3 { + float: none; + width: 204px; + margin-left: 0; +} +table .span4 { + float: none; + width: 284px; + margin-left: 0; +} +table .span5 { + float: none; + width: 364px; + margin-left: 0; +} +table .span6 { + float: none; + width: 444px; + margin-left: 0; +} +table .span7 { + float: none; + width: 524px; + margin-left: 0; +} +table .span8 { + float: none; + width: 604px; + margin-left: 0; +} +table .span9 { + float: none; + width: 684px; + margin-left: 0; +} +table .span10 { + float: none; + width: 764px; + margin-left: 0; +} +table .span11 { + float: none; + width: 844px; + margin-left: 0; +} +table .span12 { + float: none; + width: 924px; + margin-left: 0; +} +[class^="icon-"], [class*=" icon-"] { + display: inline-block; + width: 14px; + height: 14px; + line-height: 14px; + vertical-align: text-top; + background-image: url("../img/glyphicons-halflings.png"); + background-position: 14px 14px; + background-repeat: no-repeat; + *margin-right: .3em; +} +[class^="icon-"]:last-child, [class*=" icon-"]:last-child { + *margin-left: 0; +} +.icon-white { + background-image: url("../img/glyphicons-halflings-white.png"); +} +.icon-glass { + background-position: 0 0; +} +.icon-music { + background-position: -24px 0; +} +.icon-search { + background-position: -48px 0; +} +.icon-envelope { + background-position: -72px 0; +} +.icon-heart { + background-position: -96px 0; +} +.icon-star { + background-position: -120px 0; +} +.icon-star-empty { + background-position: -144px 0; +} +.icon-user { + background-position: -168px 0; +} +.icon-film { + background-position: -192px 0; +} +.icon-th-large { + background-position: -216px 0; +} +.icon-th { + background-position: -240px 0; +} +.icon-th-list { + background-position: -264px 0; +} +.icon-ok { + background-position: -288px 0; +} +.icon-remove { + background-position: -312px 0; +} +.icon-zoom-in { + background-position: -336px 0; +} +.icon-zoom-out { + background-position: -360px 0; +} +.icon-off { + background-position: -384px 0; +} +.icon-signal { + background-position: -408px 0; +} +.icon-cog { + background-position: -432px 0; +} +.icon-trash { + background-position: -456px 0; +} +.icon-home { + background-position: 0 -24px; +} +.icon-file { + background-position: -24px -24px; +} +.icon-time { + background-position: -48px -24px; +} +.icon-road { + background-position: -72px -24px; +} +.icon-download-alt { + background-position: -96px -24px; +} +.icon-download { + background-position: -120px -24px; +} +.icon-upload { + background-position: -144px -24px; +} +.icon-inbox { + background-position: -168px -24px; +} +.icon-play-circle { + background-position: -192px -24px; +} +.icon-repeat { + background-position: -216px -24px; +} +.icon-refresh { + background-position: -240px -24px; +} +.icon-list-alt { + background-position: -264px -24px; +} +.icon-lock { + background-position: -287px -24px; +} +.icon-flag { + background-position: -312px -24px; +} +.icon-headphones { + background-position: -336px -24px; +} +.icon-volume-off { + background-position: -360px -24px; +} +.icon-volume-down { + background-position: -384px -24px; +} +.icon-volume-up { + background-position: -408px -24px; +} +.icon-qrcode { + background-position: -432px -24px; +} +.icon-barcode { + background-position: -456px -24px; +} +.icon-tag { + background-position: 0 -48px; +} +.icon-tags { + background-position: -25px -48px; +} +.icon-book { + background-position: -48px -48px; +} +.icon-bookmark { + background-position: -72px -48px; +} +.icon-print { + background-position: -96px -48px; +} +.icon-camera { + background-position: -120px -48px; +} +.icon-font { + background-position: -144px -48px; +} +.icon-bold { + background-position: -167px -48px; +} +.icon-italic { + background-position: -192px -48px; +} +.icon-text-height { + background-position: -216px -48px; +} +.icon-text-width { + background-position: -240px -48px; +} +.icon-align-left { + background-position: -264px -48px; +} +.icon-align-center { + background-position: -288px -48px; +} +.icon-align-right { + background-position: -312px -48px; +} +.icon-align-justify { + background-position: -336px -48px; +} +.icon-list { + background-position: -360px -48px; +} +.icon-indent-left { + background-position: -384px -48px; +} +.icon-indent-right { + background-position: -408px -48px; +} +.icon-facetime-video { + background-position: -432px -48px; +} +.icon-picture { + background-position: -456px -48px; +} +.icon-pencil { + background-position: 0 -72px; +} +.icon-map-marker { + background-position: -24px -72px; +} +.icon-adjust { + background-position: -48px -72px; +} +.icon-tint { + background-position: -72px -72px; +} +.icon-edit { + background-position: -96px -72px; +} +.icon-share { + background-position: -120px -72px; +} +.icon-check { + background-position: -144px -72px; +} +.icon-move { + background-position: -168px -72px; +} +.icon-step-backward { + background-position: -192px -72px; +} +.icon-fast-backward { + background-position: -216px -72px; +} +.icon-backward { + background-position: -240px -72px; +} +.icon-play { + background-position: -264px -72px; +} +.icon-pause { + background-position: -288px -72px; +} +.icon-stop { + background-position: -312px -72px; +} +.icon-forward { + background-position: -336px -72px; +} +.icon-fast-forward { + background-position: -360px -72px; +} +.icon-step-forward { + background-position: -384px -72px; +} +.icon-eject { + background-position: -408px -72px; +} +.icon-chevron-left { + background-position: -432px -72px; +} +.icon-chevron-right { + background-position: -456px -72px; +} +.icon-plus-sign { + background-position: 0 -96px; +} +.icon-minus-sign { + background-position: -24px -96px; +} +.icon-remove-sign { + background-position: -48px -96px; +} +.icon-ok-sign { + background-position: -72px -96px; +} +.icon-question-sign { + background-position: -96px -96px; +} +.icon-info-sign { + background-position: -120px -96px; +} +.icon-screenshot { + background-position: -144px -96px; +} +.icon-remove-circle { + background-position: -168px -96px; +} +.icon-ok-circle { + background-position: -192px -96px; +} +.icon-ban-circle { + background-position: -216px -96px; +} +.icon-arrow-left { + background-position: -240px -96px; +} +.icon-arrow-right { + background-position: -264px -96px; +} +.icon-arrow-up { + background-position: -289px -96px; +} +.icon-arrow-down { + background-position: -312px -96px; +} +.icon-share-alt { + background-position: -336px -96px; +} +.icon-resize-full { + background-position: -360px -96px; +} +.icon-resize-small { + background-position: -384px -96px; +} +.icon-plus { + background-position: -408px -96px; +} +.icon-minus { + background-position: -433px -96px; +} +.icon-asterisk { + background-position: -456px -96px; +} +.icon-exclamation-sign { + background-position: 0 -120px; +} +.icon-gift { + background-position: -24px -120px; +} +.icon-leaf { + background-position: -48px -120px; +} +.icon-fire { + background-position: -72px -120px; +} +.icon-eye-open { + background-position: -96px -120px; +} +.icon-eye-close { + background-position: -120px -120px; +} +.icon-warning-sign { + background-position: -144px -120px; +} +.icon-plane { + background-position: -168px -120px; +} +.icon-calendar { + background-position: -192px -120px; +} +.icon-random { + background-position: -216px -120px; +} +.icon-comment { + background-position: -240px -120px; +} +.icon-magnet { + background-position: -264px -120px; +} +.icon-chevron-up { + background-position: -288px -120px; +} +.icon-chevron-down { + background-position: -313px -119px; +} +.icon-retweet { + background-position: -336px -120px; +} +.icon-shopping-cart { + background-position: -360px -120px; +} +.icon-folder-close { + background-position: -384px -120px; +} +.icon-folder-open { + background-position: -408px -120px; +} +.icon-resize-vertical { + background-position: -432px -119px; +} +.icon-resize-horizontal { + background-position: -456px -118px; +} +.dropdown { + position: relative; +} +.dropdown-toggle { + *margin-bottom: -3px; +} +.dropdown-toggle:active, .open .dropdown-toggle { + outline: 0; +} +.caret { + display: inline-block; + width: 0; + height: 0; + text-indent: -99999px; + *text-indent: 0; + vertical-align: top; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 4px solid #000000; + opacity: 0.3; + filter: alpha(opacity=30); + content: "\2193"; +} +.dropdown .caret { + margin-top: 8px; + margin-left: 2px; +} +.dropdown:hover .caret, .open.dropdown .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + float: left; + display: none; + min-width: 160px; + _width: 160px; + padding: 4px 0; + margin: 0; + list-style: none; + background-color: #ffffff; + border-color: #ccc; + border-color: rgba(0, 0, 0, 0.2); + border-style: solid; + border-width: 1px; + -webkit-border-radius: 0 0 5px 5px; + -moz-border-radius: 0 0 5px 5px; + border-radius: 0 0 5px 5px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; + *border-right-width: 2px; + *border-bottom-width: 2px; +} +.dropdown-menu.bottom-up { + top: auto; + bottom: 100%; + margin-bottom: 2px; +} +.dropdown-menu .divider { + height: 1px; + margin: 5px 1px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #ffffff; + *width: 100%; + *margin: -5px 0 5px; +} +.dropdown-menu a { + display: block; + padding: 3px 15px; + clear: both; + font-weight: normal; + line-height: 18px; + color: #555555; + white-space: nowrap; +} +.dropdown-menu li > a:hover, .dropdown-menu .active > a, .dropdown-menu .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #0088cc; +} +.dropdown.open { + *z-index: 1000; +} +.dropdown.open .dropdown-toggle { + color: #ffffff; + background: #ccc; + background: rgba(0, 0, 0, 0.3); +} +.dropdown.open .dropdown-menu { + display: block; +} +.typeahead { + margin-top: 2px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #f5f5f5; + border: 1px solid #eee; + border: 1px solid rgba(0, 0, 0, 0.05); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 0, 0, 0.15); +} +.fade { + -webkit-transition: opacity 0.15s linear; + -moz-transition: opacity 0.15s linear; + -ms-transition: opacity 0.15s linear; + -o-transition: opacity 0.15s linear; + transition: opacity 0.15s linear; + opacity: 0; +} +.fade.in { + opacity: 1; +} +.collapse { + -webkit-transition: height 0.35s ease; + -moz-transition: height 0.35s ease; + -ms-transition: height 0.35s ease; + -o-transition: height 0.35s ease; + transition: height 0.35s ease; + position: relative; + overflow: hidden; + height: 0; +} +.collapse.in { + height: auto; +} +.close { + float: right; + font-size: 20px; + font-weight: bold; + line-height: 18px; + color: #000000; + text-shadow: 0 1px 0 #ffffff; + opacity: 0.2; + filter: alpha(opacity=20); +} +.close:hover { + color: #000000; + text-decoration: none; + opacity: 0.4; + filter: alpha(opacity=40); + cursor: pointer; +} +.btn { + display: inline-block; + padding: 4px 10px 4px; + margin-bottom: 0; + font-size: 13px; + line-height: 18px; + color: #333333; + text-align: center; + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); + vertical-align: middle; + background-color: #f5f5f5; + background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); + background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); + background-image: linear-gradient(top, #ffffff, #e6e6e6); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0); + border-color: #e6e6e6 #e6e6e6 #bfbfbf; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + border: 1px solid #ccc; + border-bottom-color: #bbb; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + cursor: pointer; + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + *margin-left: .3em; +} +.btn:hover, +.btn:active, +.btn.active, +.btn.disabled, +.btn[disabled] { + background-color: #e6e6e6; +} +.btn:active, .btn.active { + background-color: #cccccc \9; +} +.btn:first-child { + *margin-left: 0; +} +.btn:hover { + color: #333333; + text-decoration: none; + background-color: #e6e6e6; + background-position: 0 -15px; + -webkit-transition: background-position 0.1s linear; + -moz-transition: background-position 0.1s linear; + -ms-transition: background-position 0.1s linear; + -o-transition: background-position 0.1s linear; + transition: background-position 0.1s linear; +} +.btn:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.btn.active, .btn:active { + background-image: none; + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + background-color: #e6e6e6; + background-color: #d9d9d9 \9; + outline: 0; +} +.btn.disabled, .btn[disabled] { + cursor: default; + background-image: none; + background-color: #e6e6e6; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +.btn-large { + padding: 9px 14px; + font-size: 15px; + line-height: normal; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.btn-large [class^="icon-"] { + margin-top: 1px; +} +.btn-small { + padding: 5px 9px; + font-size: 11px; + line-height: 16px; +} +.btn-small [class^="icon-"] { + margin-top: -1px; +} +.btn-mini { + padding: 2px 6px; + font-size: 11px; + line-height: 14px; +} +.btn-primary, +.btn-primary:hover, +.btn-warning, +.btn-warning:hover, +.btn-danger, +.btn-danger:hover, +.btn-success, +.btn-success:hover, +.btn-info, +.btn-info:hover, +.btn-inverse, +.btn-inverse:hover { + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + color: #ffffff; +} +.btn-primary.active, +.btn-warning.active, +.btn-danger.active, +.btn-success.active, +.btn-info.active, +.btn-dark.active { + color: rgba(255, 255, 255, 0.75); +} +.btn-primary { + background-color: #006dcc; + background-image: -moz-linear-gradient(top, #0088cc, #0044cc); + background-image: -ms-linear-gradient(top, #0088cc, #0044cc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); + background-image: -o-linear-gradient(top, #0088cc, #0044cc); + background-image: linear-gradient(top, #0088cc, #0044cc); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); + border-color: #0044cc #0044cc #002a80; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-primary:hover, +.btn-primary:active, +.btn-primary.active, +.btn-primary.disabled, +.btn-primary[disabled] { + background-color: #0044cc; +} +.btn-primary:active, .btn-primary.active { + background-color: #003399 \9; +} +.btn-warning { + background-color: #faa732; + background-image: -moz-linear-gradient(top, #fbb450, #f89406); + background-image: -ms-linear-gradient(top, #fbb450, #f89406); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); + background-image: -webkit-linear-gradient(top, #fbb450, #f89406); + background-image: -o-linear-gradient(top, #fbb450, #f89406); + background-image: linear-gradient(top, #fbb450, #f89406); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0); + border-color: #f89406 #f89406 #ad6704; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-warning:hover, +.btn-warning:active, +.btn-warning.active, +.btn-warning.disabled, +.btn-warning[disabled] { + background-color: #f89406; +} +.btn-warning:active, .btn-warning.active { + background-color: #c67605 \9; +} +.btn-danger { + background-color: #da4f49; + background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -ms-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -o-linear-gradient(top, #ee5f5b, #bd362f); + background-image: linear-gradient(top, #ee5f5b, #bd362f); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0); + border-color: #bd362f #bd362f #802420; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-danger:hover, +.btn-danger:active, +.btn-danger.active, +.btn-danger.disabled, +.btn-danger[disabled] { + background-color: #bd362f; +} +.btn-danger:active, .btn-danger.active { + background-color: #942a25 \9; +} +.btn-success { + background-color: #5bb75b; + background-image: -moz-linear-gradient(top, #62c462, #51a351); + background-image: -ms-linear-gradient(top, #62c462, #51a351); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351)); + background-image: -webkit-linear-gradient(top, #62c462, #51a351); + background-image: -o-linear-gradient(top, #62c462, #51a351); + background-image: linear-gradient(top, #62c462, #51a351); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0); + border-color: #51a351 #51a351 #387038; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-success:hover, +.btn-success:active, +.btn-success.active, +.btn-success.disabled, +.btn-success[disabled] { + background-color: #51a351; +} +.btn-success:active, .btn-success.active { + background-color: #408140 \9; +} +.btn-info { + background-color: #49afcd; + background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -ms-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4)); + background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -o-linear-gradient(top, #5bc0de, #2f96b4); + background-image: linear-gradient(top, #5bc0de, #2f96b4); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0); + border-color: #2f96b4 #2f96b4 #1f6377; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-info:hover, +.btn-info:active, +.btn-info.active, +.btn-info.disabled, +.btn-info[disabled] { + background-color: #2f96b4; +} +.btn-info:active, .btn-info.active { + background-color: #24748c \9; +} +.btn-inverse { + background-color: #393939; + background-image: -moz-linear-gradient(top, #454545, #262626); + background-image: -ms-linear-gradient(top, #454545, #262626); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#454545), to(#262626)); + background-image: -webkit-linear-gradient(top, #454545, #262626); + background-image: -o-linear-gradient(top, #454545, #262626); + background-image: linear-gradient(top, #454545, #262626); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#454545', endColorstr='#262626', GradientType=0); + border-color: #262626 #262626 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-inverse:hover, +.btn-inverse:active, +.btn-inverse.active, +.btn-inverse.disabled, +.btn-inverse[disabled] { + background-color: #262626; +} +.btn-inverse:active, .btn-inverse.active { + background-color: #0c0c0c \9; +} +button.btn, input[type="submit"].btn { + *padding-top: 2px; + *padding-bottom: 2px; +} +button.btn::-moz-focus-inner, input[type="submit"].btn::-moz-focus-inner { + padding: 0; + border: 0; +} +button.btn.large, input[type="submit"].btn.large { + *padding-top: 7px; + *padding-bottom: 7px; +} +button.btn.small, input[type="submit"].btn.small { + *padding-top: 3px; + *padding-bottom: 3px; +} +.btn-group { + position: relative; + *zoom: 1; + *margin-left: .3em; +} +.btn-group:before, .btn-group:after { + display: table; + content: ""; +} +.btn-group:after { + clear: both; +} +.btn-group:first-child { + *margin-left: 0; +} +.btn-group + .btn-group { + margin-left: 5px; +} +.btn-toolbar { + margin-top: 9px; + margin-bottom: 9px; +} +.btn-toolbar .btn-group { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; +} +.btn-group .btn { + position: relative; + float: left; + margin-left: -1px; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.btn-group .btn:first-child { + margin-left: 0; + -webkit-border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; + border-top-left-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + border-bottom-left-radius: 4px; +} +.btn-group .btn:last-child, .btn-group .dropdown-toggle { + -webkit-border-top-right-radius: 4px; + -moz-border-radius-topright: 4px; + border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -moz-border-radius-bottomright: 4px; + border-bottom-right-radius: 4px; +} +.btn-group .btn.large:first-child { + margin-left: 0; + -webkit-border-top-left-radius: 6px; + -moz-border-radius-topleft: 6px; + border-top-left-radius: 6px; + -webkit-border-bottom-left-radius: 6px; + -moz-border-radius-bottomleft: 6px; + border-bottom-left-radius: 6px; +} +.btn-group .btn.large:last-child, .btn-group .large.dropdown-toggle { + -webkit-border-top-right-radius: 6px; + -moz-border-radius-topright: 6px; + border-top-right-radius: 6px; + -webkit-border-bottom-right-radius: 6px; + -moz-border-radius-bottomright: 6px; + border-bottom-right-radius: 6px; +} +.btn-group .btn:hover, +.btn-group .btn:focus, +.btn-group .btn:active, +.btn-group .btn.active { + z-index: 2; +} +.btn-group .dropdown-toggle:active, .btn-group.open .dropdown-toggle { + outline: 0; +} +.btn-group .dropdown-toggle { + padding-left: 8px; + padding-right: 8px; + -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + *padding-top: 5px; + *padding-bottom: 5px; +} +.btn-group.open { + *z-index: 1000; +} +.btn-group.open .dropdown-menu { + display: block; + margin-top: 1px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.btn-group.open .dropdown-toggle { + background-image: none; + -webkit-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); +} +.btn .caret { + margin-top: 7px; + margin-left: 0; +} +.btn:hover .caret, .open.btn-group .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.btn-primary .caret, +.btn-danger .caret, +.btn-info .caret, +.btn-success .caret, +.btn-inverse .caret { + border-top-color: #ffffff; + opacity: 0.75; + filter: alpha(opacity=75); +} +.btn-small .caret { + margin-top: 4px; +} +.alert { + padding: 8px 35px 8px 14px; + margin-bottom: 18px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + background-color: #fcf8e3; + border: 1px solid #fbeed5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.alert, .alert-heading { + color: #c09853; +} +.alert .close { + position: relative; + top: -2px; + right: -21px; + line-height: 18px; +} +.alert-success { + background-color: #dff0d8; + border-color: #d6e9c6; +} +.alert-success, .alert-success .alert-heading { + color: #468847; +} +.alert-danger, .alert-error { + background-color: #f2dede; + border-color: #eed3d7; +} +.alert-danger, +.alert-error, +.alert-danger .alert-heading, +.alert-error .alert-heading { + color: #b94a48; +} +.alert-info { + background-color: #d9edf7; + border-color: #bce8f1; +} +.alert-info, .alert-info .alert-heading { + color: #3a87ad; +} +.alert-block { + padding-top: 14px; + padding-bottom: 14px; +} +.alert-block > p, .alert-block > ul { + margin-bottom: 0; +} +.alert-block p + p { + margin-top: 5px; +} +.nav { + margin-left: 0; + margin-bottom: 18px; + list-style: none; +} +.nav > li > a { + display: block; +} +.nav > li > a:hover { + text-decoration: none; + background-color: #eeeeee; +} +.nav .nav-header { + display: block; + padding: 3px 15px; + font-size: 11px; + font-weight: bold; + line-height: 18px; + color: #999999; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + text-transform: uppercase; +} +.nav li + .nav-header { + margin-top: 9px; +} +.nav-list { + padding-left: 14px; + padding-right: 14px; + margin-bottom: 0; +} +.nav-list > li > a, .nav-list .nav-header { + margin-left: -15px; + margin-right: -15px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); +} +.nav-list > li > a { + padding: 3px 15px; +} +.nav-list .active > a, .nav-list .active > a:hover { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); + background-color: #0088cc; +} +.nav-list [class^="icon-"] { + margin-right: 2px; +} +.nav-tabs, .nav-pills { + *zoom: 1; +} +.nav-tabs:before, +.nav-pills:before, +.nav-tabs:after, +.nav-pills:after { + display: table; + content: ""; +} +.nav-tabs:after, .nav-pills:after { + clear: both; +} +.nav-tabs > li, .nav-pills > li { + float: left; +} +.nav-tabs > li > a, .nav-pills > li > a { + padding-right: 12px; + padding-left: 12px; + margin-right: 2px; + line-height: 14px; +} +.nav-tabs { + border-bottom: 1px solid #ddd; +} +.nav-tabs > li { + margin-bottom: -1px; +} +.nav-tabs > li > a { + padding-top: 9px; + padding-bottom: 9px; + border: 1px solid transparent; + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} +.nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #dddddd; +} +.nav-tabs > .active > a, .nav-tabs > .active > a:hover { + color: #555555; + background-color: #ffffff; + border: 1px solid #ddd; + border-bottom-color: transparent; + cursor: default; +} +.nav-pills > li > a { + padding-top: 8px; + padding-bottom: 8px; + margin-top: 2px; + margin-bottom: 2px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.nav-pills .active > a, .nav-pills .active > a:hover { + color: #ffffff; + background-color: #0088cc; +} +.nav-stacked > li { + float: none; +} +.nav-stacked > li > a { + margin-right: 0; +} +.nav-tabs.nav-stacked { + border-bottom: 0; +} +.nav-tabs.nav-stacked > li > a { + border: 1px solid #ddd; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.nav-tabs.nav-stacked > li:first-child > a { + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} +.nav-tabs.nav-stacked > li:last-child > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} +.nav-tabs.nav-stacked > li > a:hover { + border-color: #ddd; + z-index: 2; +} +.nav-pills.nav-stacked > li > a { + margin-bottom: 3px; +} +.nav-pills.nav-stacked > li:last-child > a { + margin-bottom: 1px; +} +.nav-tabs .dropdown-menu, .nav-pills .dropdown-menu { + margin-top: 1px; + border-width: 1px; +} +.nav-pills .dropdown-menu { + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.nav-tabs .dropdown-toggle .caret, .nav-pills .dropdown-toggle .caret { + border-top-color: #0088cc; + margin-top: 6px; +} +.nav-tabs .dropdown-toggle:hover .caret, .nav-pills .dropdown-toggle:hover .caret { + border-top-color: #005580; +} +.nav-tabs .active .dropdown-toggle .caret, .nav-pills .active .dropdown-toggle .caret { + border-top-color: #333333; +} +.nav > .dropdown.active > a:hover { + color: #000000; + cursor: pointer; +} +.nav-tabs .open .dropdown-toggle, .nav-pills .open .dropdown-toggle, .nav > .open.active > a:hover { + color: #ffffff; + background-color: #999999; + border-color: #999999; +} +.nav .open .caret, .nav .open.active .caret, .nav .open a:hover .caret { + border-top-color: #ffffff; + opacity: 1; + filter: alpha(opacity=100); +} +.tabs-stacked .open > a:hover { + border-color: #999999; +} +.tabbable { + *zoom: 1; +} +.tabbable:before, .tabbable:after { + display: table; + content: ""; +} +.tabbable:after { + clear: both; +} +.tab-content { + overflow: hidden; +} +.tabs-below .nav-tabs, .tabs-right .nav-tabs, .tabs-left .nav-tabs { + border-bottom: 0; +} +.tab-content > .tab-pane, .pill-content > .pill-pane { + display: none; +} +.tab-content > .active, .pill-content > .active { + display: block; +} +.tabs-below .nav-tabs { + border-top: 1px solid #ddd; +} +.tabs-below .nav-tabs > li { + margin-top: -1px; + margin-bottom: 0; +} +.tabs-below .nav-tabs > li > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} +.tabs-below .nav-tabs > li > a:hover { + border-bottom-color: transparent; + border-top-color: #ddd; +} +.tabs-below .nav-tabs .active > a, .tabs-below .nav-tabs .active > a:hover { + border-color: transparent #ddd #ddd #ddd; +} +.tabs-left .nav-tabs > li, .tabs-right .nav-tabs > li { + float: none; +} +.tabs-left .nav-tabs > li > a, .tabs-right .nav-tabs > li > a { + min-width: 74px; + margin-right: 0; + margin-bottom: 3px; +} +.tabs-left .nav-tabs { + float: left; + margin-right: 19px; + border-right: 1px solid #ddd; +} +.tabs-left .nav-tabs > li > a { + margin-right: -1px; + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} +.tabs-left .nav-tabs > li > a:hover { + border-color: #eeeeee #dddddd #eeeeee #eeeeee; +} +.tabs-left .nav-tabs .active > a, .tabs-left .nav-tabs .active > a:hover { + border-color: #ddd transparent #ddd #ddd; + *border-right-color: #ffffff; +} +.tabs-right .nav-tabs { + float: right; + margin-left: 19px; + border-left: 1px solid #ddd; +} +.tabs-right .nav-tabs > li > a { + margin-left: -1px; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} +.tabs-right .nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #eeeeee #dddddd; +} +.tabs-right .nav-tabs .active > a, .tabs-right .nav-tabs .active > a:hover { + border-color: #ddd #ddd #ddd transparent; + *border-left-color: #ffffff; +} +.navbar { + overflow: visible; + margin-bottom: 18px; +} +.navbar-inner { + padding-left: 20px; + padding-right: 20px; + background-color: #2c2c2c; + background-image: -moz-linear-gradient(top, #333333, #222222); + background-image: -ms-linear-gradient(top, #333333, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); + background-image: -webkit-linear-gradient(top, #333333, #222222); + background-image: -o-linear-gradient(top, #333333, #222222); + background-image: linear-gradient(top, #333333, #222222); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); +} +.btn-navbar { + display: none; + float: right; + padding: 7px 10px; + margin-left: 5px; + margin-right: 5px; + background-color: #2c2c2c; + background-image: -moz-linear-gradient(top, #333333, #222222); + background-image: -ms-linear-gradient(top, #333333, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); + background-image: -webkit-linear-gradient(top, #333333, #222222); + background-image: -o-linear-gradient(top, #333333, #222222); + background-image: linear-gradient(top, #333333, #222222); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); + border-color: #222222 #222222 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); +} +.btn-navbar:hover, +.btn-navbar:active, +.btn-navbar.active, +.btn-navbar.disabled, +.btn-navbar[disabled] { + background-color: #222222; +} +.btn-navbar:active, .btn-navbar.active { + background-color: #080808 \9; +} +.btn-navbar .icon-bar { + display: block; + width: 18px; + height: 2px; + background-color: #f5f5f5; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; + -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); +} +.btn-navbar .icon-bar + .icon-bar { + margin-top: 3px; +} +.nav-collapse.collapse { + height: auto; +} +.navbar .brand:hover { + text-decoration: none; +} +.navbar .brand { + float: left; + display: block; + padding: 8px 20px 12px; + margin-left: -20px; + font-size: 20px; + font-weight: 200; + line-height: 1; + color: #ffffff; +} +.navbar .navbar-text { + margin-bottom: 0; + line-height: 40px; + color: #999999; +} +.navbar .navbar-text a:hover { + color: #ffffff; + background-color: transparent; +} +.navbar .btn, .navbar .btn-group { + margin-top: 5px; +} +.navbar .btn-group .btn { + margin-top: 0; +} +.navbar-form { + margin-bottom: 0; + *zoom: 1; +} +.navbar-form:before, .navbar-form:after { + display: table; + content: ""; +} +.navbar-form:after { + clear: both; +} +.navbar-form input, .navbar-form select { + display: inline-block; + margin-top: 5px; + margin-bottom: 0; +} +.navbar-form .radio, .navbar-form .checkbox { + margin-top: 5px; +} +.navbar-form input[type="image"], .navbar-form input[type="checkbox"], .navbar-form input[type="radio"] { + margin-top: 3px; +} +.navbar-form .input-append, .navbar-form .input-prepend { + margin-top: 6px; + white-space: nowrap; +} +.navbar-form .input-append input, .navbar-form .input-prepend input { + margin-top: 0; +} +.navbar-search { + position: relative; + float: left; + margin-top: 6px; + margin-bottom: 0; +} +.navbar-search .search-query { + padding: 4px 9px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + font-weight: normal; + line-height: 1; + color: #ffffff; + color: rgba(255, 255, 255, 0.75); + background: #666; + background: rgba(255, 255, 255, 0.3); + border: 1px solid #111; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + -webkit-transition: none; + -moz-transition: none; + -ms-transition: none; + -o-transition: none; + transition: none; +} +.navbar-search .search-query :-moz-placeholder { + color: #eeeeee; +} +.navbar-search .search-query::-webkit-input-placeholder { + color: #eeeeee; +} +.navbar-search .search-query:hover { + color: #ffffff; + background-color: #999999; + background-color: rgba(255, 255, 255, 0.5); +} +.navbar-search .search-query:focus, .navbar-search .search-query.focused { + padding: 5px 10px; + color: #333333; + text-shadow: 0 1px 0 #ffffff; + background-color: #ffffff; + border: 0; + -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + outline: 0; +} +.navbar-fixed-top { + position: fixed; + top: 0; + right: 0; + left: 0; + z-index: 1030; +} +.navbar-fixed-top .navbar-inner { + padding-left: 0; + padding-right: 0; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.navbar .nav { + position: relative; + left: 0; + display: block; + float: left; + margin: 0 10px 0 0; +} +.navbar .nav.pull-right { + float: right; +} +.navbar .nav > li { + display: block; + float: left; +} +.navbar .nav > li > a { + float: none; + padding: 10px 10px 11px; + line-height: 19px; + color: #999999; + text-decoration: none; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.navbar .nav > li > a:hover { + background-color: transparent; + color: #ffffff; + text-decoration: none; +} +.navbar .nav .active > a, .navbar .nav .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #222222; +} +.navbar .divider-vertical { + height: 40px; + width: 1px; + margin: 0 9px; + overflow: hidden; + background-color: #222222; + border-right: 1px solid #333333; +} +.navbar .nav.pull-right { + margin-left: 10px; + margin-right: 0; +} +.navbar .dropdown-menu { + margin-top: 1px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.navbar .dropdown-menu:before { + content: ''; + display: inline-block; + border-left: 7px solid transparent; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-bottom-color: rgba(0, 0, 0, 0.2); + position: absolute; + top: -7px; + left: 9px; +} +.navbar .dropdown-menu:after { + content: ''; + display: inline-block; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid #ffffff; + position: absolute; + top: -6px; + left: 10px; +} +.navbar .nav .dropdown-toggle .caret, .navbar .nav .open.dropdown .caret { + border-top-color: #ffffff; +} +.navbar .nav .active .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.navbar .nav .open > .dropdown-toggle, .navbar .nav .active > .dropdown-toggle, .navbar .nav .open.active > .dropdown-toggle { + background-color: transparent; +} +.navbar .nav .active > .dropdown-toggle:hover { + color: #ffffff; +} +.navbar .nav.pull-right .dropdown-menu { + left: auto; + right: 0; +} +.navbar .nav.pull-right .dropdown-menu:before { + left: auto; + right: 12px; +} +.navbar .nav.pull-right .dropdown-menu:after { + left: auto; + right: 13px; +} +.breadcrumb { + padding: 7px 14px; + margin: 0 0 18px; + background-color: #fbfbfb; + background-image: -moz-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -ms-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5)); + background-image: -webkit-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -o-linear-gradient(top, #ffffff, #f5f5f5); + background-image: linear-gradient(top, #ffffff, #f5f5f5); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0); + border: 1px solid #ddd; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; +} +.breadcrumb li { + display: inline-block; + text-shadow: 0 1px 0 #ffffff; +} +.breadcrumb .divider { + padding: 0 5px; + color: #999999; +} +.breadcrumb .active a { + color: #333333; +} +.pagination { + height: 36px; + margin: 18px 0; +} +.pagination ul { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; + margin-left: 0; + margin-bottom: 0; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); +} +.pagination li { + display: inline; +} +.pagination a { + float: left; + padding: 0 14px; + line-height: 34px; + text-decoration: none; + border: 1px solid #ddd; + border-left-width: 0; +} +.pagination a:hover, .pagination .active a { + background-color: #f5f5f5; +} +.pagination .active a { + color: #999999; + cursor: default; +} +.pagination .disabled a, .pagination .disabled a:hover { + color: #999999; + background-color: transparent; + cursor: default; +} +.pagination li:first-child a { + border-left-width: 1px; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.pagination li:last-child a { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.pagination-centered { + text-align: center; +} +.pagination-right { + text-align: right; +} +.pager { + margin-left: 0; + margin-bottom: 18px; + list-style: none; + text-align: center; + *zoom: 1; +} +.pager:before, .pager:after { + display: table; + content: ""; +} +.pager:after { + clear: both; +} +.pager li { + display: inline; +} +.pager a { + display: inline-block; + padding: 5px 14px; + background-color: #fff; + border: 1px solid #ddd; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} +.pager a:hover { + text-decoration: none; + background-color: #f5f5f5; +} +.pager .next a { + float: right; +} +.pager .previous a { + float: left; +} +.modal-open .dropdown-menu { + z-index: 2050; +} +.modal-open .dropdown.open { + *z-index: 2050; +} +.modal-open .popover { + z-index: 2060; +} +.modal-open .tooltip { + z-index: 2070; +} +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + background-color: #000000; +} +.modal-backdrop.fade { + opacity: 0; +} +.modal-backdrop, .modal-backdrop.fade.in { + opacity: 0.8; + filter: alpha(opacity=80); +} +.modal { + position: fixed; + top: 50%; + left: 50%; + z-index: 1050; + max-height: 500px; + overflow: auto; + width: 560px; + margin: -250px 0 0 -280px; + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + /* IE6-7 */ + + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.wide-modal { + position: fixed; + top: 5%; + left: 5%; + z-index: 1050; + max-height: 90%; + overflow: auto; + width: 90%; + /*margin: -50px 0 0 -80px;*/ + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + /* IE6-7 */ + + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.modal.fade { + -webkit-transition: opacity .3s linear, top .3s ease-out; + -moz-transition: opacity .3s linear, top .3s ease-out; + -ms-transition: opacity .3s linear, top .3s ease-out; + -o-transition: opacity .3s linear, top .3s ease-out; + transition: opacity .3s linear, top .3s ease-out; + top: -25%; +} +.modal.fade.in { + top: 50%; +} +.modal-header { + padding: 9px 15px; + border-bottom: 1px solid #eee; +} +.modal-header .close { + margin-top: 2px; +} +.modal-body { + padding: 15px; +} +.modal-body .modal-form { + margin-bottom: 0; +} +.modal-footer { + padding: 14px 15px 15px; + margin-bottom: 0; + background-color: #f5f5f5; + border-top: 1px solid #ddd; + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; + *zoom: 1; +} +.modal-footer:before, .modal-footer:after { + display: table; + content: ""; +} +.modal-footer:after { + clear: both; +} +.modal-footer .btn { + float: right; + margin-left: 5px; + margin-bottom: 0; +} +.tooltip { + position: absolute; + z-index: 1020; + display: block; + visibility: visible; + padding: 5px; + font-size: 11px; + opacity: 0; + filter: alpha(opacity=0); +} +.tooltip.in { + opacity: 0.8; + filter: alpha(opacity=80); +} +.tooltip.top { + margin-top: -2px; +} +.tooltip.right { + margin-left: 2px; +} +.tooltip.bottom { + margin-top: 2px; +} +.tooltip.left { + margin-left: -2px; +} +.tooltip.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid #000000; +} +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #000000; +} +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-bottom: 5px solid #000000; +} +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-right: 5px solid #000000; +} +.tooltip-inner { + max-width: 200px; + padding: 3px 8px; + color: #ffffff; + text-align: center; + text-decoration: none; + background-color: #000000; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; +} +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1010; + display: none; + padding: 5px; +} +.popover.top { + margin-top: -5px; +} +.popover.right { + margin-left: 5px; +} +.popover.bottom { + margin-top: 5px; +} +.popover.left { + margin-left: -5px; +} +.popover.top .arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid #000000; +} +.popover.right .arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-right: 5px solid #000000; +} +.popover.bottom .arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-bottom: 5px solid #000000; +} +.popover.left .arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #000000; +} +.popover .arrow { + position: absolute; + width: 0; + height: 0; +} +.popover-inner { + padding: 3px; + width: 280px; + overflow: hidden; + background: #000000; + background: rgba(0, 0, 0, 0.8); + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); +} +.popover-title { + padding: 9px 15px; + line-height: 1; + background-color: #f5f5f5; + border-bottom: 1px solid #eee; + -webkit-border-radius: 3px 3px 0 0; + -moz-border-radius: 3px 3px 0 0; + border-radius: 3px 3px 0 0; +} +.popover-content { + padding: 14px; + background-color: #ffffff; + -webkit-border-radius: 0 0 3px 3px; + -moz-border-radius: 0 0 3px 3px; + border-radius: 0 0 3px 3px; + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.popover-content p, .popover-content ul, .popover-content ol { + margin-bottom: 0; +} +.thumbnails { + margin-left: -20px; + list-style: none; + *zoom: 1; +} +.thumbnails:before, .thumbnails:after { + display: table; + content: ""; +} +.thumbnails:after { + clear: both; +} +.thumbnails > li { + float: left; + margin: 0 0 18px 20px; +} +.thumbnail { + display: block; + padding: 4px; + line-height: 1; + border: 1px solid #ddd; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); +} +a.thumbnail:hover { + border-color: #0088cc; + -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); +} +.thumbnail > img { + display: block; + max-width: 100%; + margin-left: auto; + margin-right: auto; +} +.thumbnail .caption { + padding: 9px; +} +.label { + padding: 2px 4px 3px; + font-size: 11.049999999999999px; + font-weight: bold; + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #999999; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.label:hover { + color: #ffffff; + text-decoration: none; +} +.label-important { + background-color: #b94a48; +} +.label-important:hover { + background-color: #953b39; +} +.label-warning { + background-color: #f89406; +} +.label-warning:hover { + background-color: #c67605; +} +.label-success { + background-color: #468847; +} +.label-success:hover { + background-color: #356635; +} +.label-info { + background-color: #3a87ad; +} +.label-info:hover { + background-color: #2d6987; +} +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +@-moz-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +@keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +.progress { + overflow: hidden; + height: 18px; + margin-bottom: 18px; + background-color: #f7f7f7; + background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -ms-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9)); + background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: linear-gradient(top, #f5f5f5, #f9f9f9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0); + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.progress .bar { + width: 0%; + height: 18px; + color: #ffffff; + font-size: 12px; + text-align: center; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #0e90d2; + background-image: -moz-linear-gradient(top, #149bdf, #0480be); + background-image: -ms-linear-gradient(top, #149bdf, #0480be); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be)); + background-image: -webkit-linear-gradient(top, #149bdf, #0480be); + background-image: -o-linear-gradient(top, #149bdf, #0480be); + background-image: linear-gradient(top, #149bdf, #0480be); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0); + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition: width 0.6s ease; + -moz-transition: width 0.6s ease; + -ms-transition: width 0.6s ease; + -o-transition: width 0.6s ease; + transition: width 0.6s ease; +} +.progress-striped .bar { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + -webkit-background-size: 40px 40px; + -moz-background-size: 40px 40px; + -o-background-size: 40px 40px; + background-size: 40px 40px; +} +.progress.active .bar { + -webkit-animation: progress-bar-stripes 2s linear infinite; + -moz-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} +.progress-danger .bar { + background-color: #dd514c; + background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -o-linear-gradient(top, #ee5f5b, #c43c35); + background-image: linear-gradient(top, #ee5f5b, #c43c35); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0); +} +.progress-danger.progress-striped .bar { + background-color: #ee5f5b; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-success .bar { + background-color: #5eb95e; + background-image: -moz-linear-gradient(top, #62c462, #57a957); + background-image: -ms-linear-gradient(top, #62c462, #57a957); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957)); + background-image: -webkit-linear-gradient(top, #62c462, #57a957); + background-image: -o-linear-gradient(top, #62c462, #57a957); + background-image: linear-gradient(top, #62c462, #57a957); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0); +} +.progress-success.progress-striped .bar { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-info .bar { + background-color: #4bb1cf; + background-image: -moz-linear-gradient(top, #5bc0de, #339bb9); + background-image: -ms-linear-gradient(top, #5bc0de, #339bb9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9)); + background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9); + background-image: -o-linear-gradient(top, #5bc0de, #339bb9); + background-image: linear-gradient(top, #5bc0de, #339bb9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0); +} +.progress-info.progress-striped .bar { + background-color: #5bc0de; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.accordion { + margin-bottom: 18px; +} +.accordion-group { + margin-bottom: 2px; + border: 1px solid #e5e5e5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.accordion-heading { + border-bottom: 0; +} +.accordion-heading .accordion-toggle { + display: block; + padding: 8px 15px; +} +.accordion-inner { + padding: 9px 15px; + border-top: 1px solid #e5e5e5; +} +.carousel { + position: relative; + margin-bottom: 18px; + line-height: 1; +} +.carousel-inner { + overflow: hidden; + width: 100%; + position: relative; +} +.carousel .item { + display: none; + position: relative; + -webkit-transition: 0.6s ease-in-out left; + -moz-transition: 0.6s ease-in-out left; + -ms-transition: 0.6s ease-in-out left; + -o-transition: 0.6s ease-in-out left; + transition: 0.6s ease-in-out left; +} +.carousel .item > img { + display: block; + line-height: 1; +} +.carousel .active, .carousel .next, .carousel .prev { + display: block; +} +.carousel .active { + left: 0; +} +.carousel .next, .carousel .prev { + position: absolute; + top: 0; + width: 100%; +} +.carousel .next { + left: 100%; +} +.carousel .prev { + left: -100%; +} +.carousel .next.left, .carousel .prev.right { + left: 0; +} +.carousel .active.left { + left: -100%; +} +.carousel .active.right { + left: 100%; +} +.carousel-control { + position: absolute; + top: 40%; + left: 15px; + width: 40px; + height: 40px; + margin-top: -20px; + font-size: 60px; + font-weight: 100; + line-height: 30px; + color: #ffffff; + text-align: center; + background: #222222; + border: 3px solid #ffffff; + -webkit-border-radius: 23px; + -moz-border-radius: 23px; + border-radius: 23px; + opacity: 0.5; + filter: alpha(opacity=50); +} +.carousel-control.right { + left: auto; + right: 15px; +} +.carousel-control:hover { + color: #ffffff; + text-decoration: none; + opacity: 0.9; + filter: alpha(opacity=90); +} +.carousel-caption { + position: absolute; + left: 0; + right: 0; + bottom: 0; + padding: 10px 15px 5px; + background: #333333; + background: rgba(0, 0, 0, 0.75); +} +.carousel-caption h4, .carousel-caption p { + color: #ffffff; +} +.hero-unit { + padding: 60px; + margin-bottom: 30px; + background-color: #f5f5f5; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} +.hero-unit h1 { + margin-bottom: 0; + font-size: 60px; + line-height: 1; + letter-spacing: -1px; +} +.hero-unit p { + font-size: 18px; + font-weight: 200; + line-height: 27px; +} +.pull-right { + float: right; +} +.pull-left { + float: left; +} +.hide { + display: none; +} +.show { + display: block; +} +.invisible { + visibility: hidden; +} diff --git a/src/nl/astraeus/jdbc/web/resources/images/loading.gif b/src/nl/astraeus/jdbc/web/resources/images/loading.gif new file mode 100644 index 0000000..21c7e74 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/images/loading.gif Binary files differ diff --git a/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png b/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png new file mode 100644 index 0000000..92d4445 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png Binary files differ diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-alert.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-alert.js new file mode 100644 index 0000000..2242ddd --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-alert.js @@ -0,0 +1,94 @@ +/* ========================================================== + * bootstrap-alert.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#alerts + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function( $ ){ + + "use strict" + + /* ALERT CLASS DEFINITION + * ====================== */ + + var dismiss = '[data-dismiss="alert"]' + , Alert = function ( el ) { + $(el).on('click', dismiss, this.close) + } + + Alert.prototype = { + + constructor: Alert + + , close: function ( e ) { + var $this = $(this) + , selector = $this.attr('data-target') + , $parent + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = $(selector) + $parent.trigger('close') + + e && e.preventDefault() + + $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent()) + + $parent + .trigger('close') + .removeClass('in') + + function removeElement() { + $parent + .trigger('closed') + .remove() + } + + $.support.transition && $parent.hasClass('fade') ? + $parent.on($.support.transition.end, removeElement) : + removeElement() + } + + } + + + /* ALERT PLUGIN DEFINITION + * ======================= */ + + $.fn.alert = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('alert') + if (!data) $this.data('alert', (data = new Alert(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.alert.Constructor = Alert + + + /* ALERT DATA-API + * ============== */ + + $(function () { + $('body').on('click.alert.data-api', dismiss, Alert.prototype.close) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-button.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-button.js new file mode 100644 index 0000000..0238ca3 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-button.js @@ -0,0 +1,100 @@ +/* ============================================================ + * bootstrap-button.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#buttons + * ============================================================ + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + +!function( $ ){ + + "use strict" + + /* BUTTON PUBLIC CLASS DEFINITION + * ============================== */ + + var Button = function ( element, options ) { + this.$element = $(element) + this.options = $.extend({}, $.fn.button.defaults, options) + } + + Button.prototype = { + + constructor: Button + + , setState: function ( state ) { + var d = 'disabled' + , $el = this.$element + , data = $el.data() + , val = $el.is('input') ? 'val' : 'html' + + state = state + 'Text' + data.resetText || $el.data('resetText', $el[val]()) + + $el[val](data[state] || this.options[state]) + + // push to event loop to allow forms to submit + setTimeout(function () { + state == 'loadingText' ? + $el.addClass(d).attr(d, d) : + $el.removeClass(d).removeAttr(d) + }, 0) + } + + , toggle: function () { + var $parent = this.$element.parent('[data-toggle="buttons-radio"]') + + $parent && $parent + .find('.active') + .removeClass('active') + + this.$element.toggleClass('active') + } + + } + + + /* BUTTON PLUGIN DEFINITION + * ======================== */ + + $.fn.button = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('button') + , options = typeof option == 'object' && option + if (!data) $this.data('button', (data = new Button(this, options))) + if (option == 'toggle') data.toggle() + else if (option) data.setState(option) + }) + } + + $.fn.button.defaults = { + loadingText: 'loading...' + } + + $.fn.button.Constructor = Button + + + /* BUTTON DATA-API + * =============== */ + + $(function () { + $('body').on('click.button.data-api', '[data-toggle^=button]', function ( e ) { + var $btn = $(e.target) + if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') + $btn.button('toggle') + }) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-carousel.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-carousel.js new file mode 100644 index 0000000..810256e --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-carousel.js @@ -0,0 +1,157 @@ +/* ========================================================== + * bootstrap-carousel.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#carousel + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function( $ ){ + + "use strict" + + /* CAROUSEL CLASS DEFINITION + * ========================= */ + + var Carousel = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, $.fn.carousel.defaults, options) + this.options.slide && this.slide(this.options.slide) + } + + Carousel.prototype = { + + cycle: function () { + this.interval = setInterval($.proxy(this.next, this), this.options.interval) + return this + } + + , to: function (pos) { + var $active = this.$element.find('.active') + , children = $active.parent().children() + , activePos = children.index($active) + , that = this + + if (pos > (children.length - 1) || pos < 0) return + + if (this.sliding) { + return this.$element.one('slid', function () { + that.to(pos) + }) + } + + if (activePos == pos) { + return this.pause().cycle() + } + + return this.slide(pos > activePos ? 'next' : 'prev', $(children[pos])) + } + + , pause: function () { + clearInterval(this.interval) + this.interval = null + return this + } + + , next: function () { + if (this.sliding) return + return this.slide('next') + } + + , prev: function () { + if (this.sliding) return + return this.slide('prev') + } + + , slide: function (type, next) { + var $active = this.$element.find('.active') + , $next = next || $active[type]() + , isCycling = this.interval + , direction = type == 'next' ? 'left' : 'right' + , fallback = type == 'next' ? 'first' : 'last' + , that = this + + if (!$next.length) return + + this.sliding = true + + isCycling && this.pause() + + $next = $next.length ? $next : this.$element.find('.item')[fallback]() + + if (!$.support.transition && this.$element.hasClass('slide')) { + this.$element.trigger('slide') + $active.removeClass('active') + $next.addClass('active') + this.sliding = false + this.$element.trigger('slid') + } else { + $next.addClass(type) + $next[0].offsetWidth // force reflow + $active.addClass(direction) + $next.addClass(direction) + this.$element.trigger('slide') + this.$element.one($.support.transition.end, function () { + $next.removeClass([type, direction].join(' ')).addClass('active') + $active.removeClass(['active', direction].join(' ')) + that.sliding = false + setTimeout(function () { that.$element.trigger('slid') }, 0) + }) + } + + isCycling && this.cycle() + + return this + } + + } + + + /* CAROUSEL PLUGIN DEFINITION + * ========================== */ + + $.fn.carousel = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('carousel') + , options = typeof option == 'object' && option + if (!data) $this.data('carousel', (data = new Carousel(this, options))) + if (typeof option == 'number') data.to(option) + else if (typeof option == 'string' || (option = options.slide)) data[option]() + else data.cycle() + }) + } + + $.fn.carousel.defaults = { + interval: 5000 + } + + $.fn.carousel.Constructor = Carousel + + + /* CAROUSEL DATA-API + * ================= */ + + $(function () { + $('body').on('click.carousel.data-api', '[data-slide]', function ( e ) { + var $this = $(this), href + , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 + , options = !$target.data('modal') && $.extend({}, $target.data(), $this.data()) + $target.carousel(options) + e.preventDefault() + }) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-collapse.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-collapse.js new file mode 100644 index 0000000..d195efc --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-collapse.js @@ -0,0 +1,136 @@ +/* ============================================================= + * bootstrap-collapse.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#collapse + * ============================================================= + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + +!function( $ ){ + + "use strict" + + var Collapse = function ( element, options ) { + this.$element = $(element) + this.options = $.extend({}, $.fn.collapse.defaults, options) + + if (this.options["parent"]) { + this.$parent = $(this.options["parent"]) + } + + this.options.toggle && this.toggle() + } + + Collapse.prototype = { + + constructor: Collapse + + , dimension: function () { + var hasWidth = this.$element.hasClass('width') + return hasWidth ? 'width' : 'height' + } + + , show: function () { + var dimension = this.dimension() + , scroll = $.camelCase(['scroll', dimension].join('-')) + , actives = this.$parent && this.$parent.find('.in') + , hasData + + if (actives && actives.length) { + hasData = actives.data('collapse') + actives.collapse('hide') + hasData || actives.data('collapse', null) + } + + this.$element[dimension](0) + this.transition('addClass', 'show', 'shown') + this.$element[dimension](this.$element[0][scroll]) + + } + + , hide: function () { + var dimension = this.dimension() + this.reset(this.$element[dimension]()) + this.transition('removeClass', 'hide', 'hidden') + this.$element[dimension](0) + } + + , reset: function ( size ) { + var dimension = this.dimension() + + this.$element + .removeClass('collapse') + [dimension](size || 'auto') + [0].offsetWidth + + this.$element.addClass('collapse') + } + + , transition: function ( method, startEvent, completeEvent ) { + var that = this + , complete = function () { + if (startEvent == 'show') that.reset() + that.$element.trigger(completeEvent) + } + + this.$element + .trigger(startEvent) + [method]('in') + + $.support.transition && this.$element.hasClass('collapse') ? + this.$element.one($.support.transition.end, complete) : + complete() + } + + , toggle: function () { + this[this.$element.hasClass('in') ? 'hide' : 'show']() + } + + } + + /* COLLAPSIBLE PLUGIN DEFINITION + * ============================== */ + + $.fn.collapse = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('collapse') + , options = typeof option == 'object' && option + if (!data) $this.data('collapse', (data = new Collapse(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.collapse.defaults = { + toggle: true + } + + $.fn.collapse.Constructor = Collapse + + + /* COLLAPSIBLE DATA-API + * ==================== */ + + $(function () { + $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function ( e ) { + var $this = $(this), href + , target = $this.attr('data-target') + || e.preventDefault() + || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 + , option = $(target).data('collapse') ? 'toggle' : $this.data() + $(target).collapse(option) + }) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-dropdown.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-dropdown.js new file mode 100644 index 0000000..f1f6c33 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-dropdown.js @@ -0,0 +1,92 @@ +/* ============================================================ + * bootstrap-dropdown.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#dropdowns + * ============================================================ + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + + +!function( $ ){ + + "use strict" + + /* DROPDOWN CLASS DEFINITION + * ========================= */ + + var toggle = '[data-toggle="dropdown"]' + , Dropdown = function ( element ) { + var $el = $(element).on('click.dropdown.data-api', this.toggle) + $('html').on('click.dropdown.data-api', function () { + $el.parent().removeClass('open') + }) + } + + Dropdown.prototype = { + + constructor: Dropdown + + , toggle: function ( e ) { + var $this = $(this) + , selector = $this.attr('data-target') + , $parent + , isActive + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = $(selector) + $parent.length || ($parent = $this.parent()) + + isActive = $parent.hasClass('open') + + clearMenus() + !isActive && $parent.toggleClass('open') + + return false + } + + } + + function clearMenus() { + $(toggle).parent().removeClass('open') + } + + + /* DROPDOWN PLUGIN DEFINITION + * ========================== */ + + $.fn.dropdown = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('dropdown') + if (!data) $this.data('dropdown', (data = new Dropdown(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.dropdown.Constructor = Dropdown + + + /* APPLY TO STANDARD DROPDOWN ELEMENTS + * =================================== */ + + $(function () { + $('html').on('click.dropdown.data-api', clearMenus) + $('body').on('click.dropdown.data-api', toggle, Dropdown.prototype.toggle) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b4ad836 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Simple-jdbc-statistics \ No newline at end of file diff --git a/.idea/ant.xml b/.idea/ant.xml new file mode 100644 index 0000000..2581ca3 --- /dev/null +++ b/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f6eb4e7 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..3572571 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/lib.xml b/.idea/libraries/lib.xml new file mode 100644 index 0000000..07e0885 --- /dev/null +++ b/.idea/libraries/lib.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f403193 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..73ff239 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..3b00020 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..275077f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/README b/README deleted file mode 100644 index 734abaf..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -This file was created by IntelliJ IDEA 11.1.1 for binding GitHub repository \ No newline at end of file diff --git a/Simple-jdbc-statistics.iml b/Simple-jdbc-statistics.iml new file mode 100644 index 0000000..ca90a9b --- /dev/null +++ b/Simple-jdbc-statistics.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/lib/h2-1.3.166.jar b/lib/h2-1.3.166.jar new file mode 100644 index 0000000..4985063 --- /dev/null +++ b/lib/h2-1.3.166.jar Binary files differ diff --git a/lib/servlet-api-2.5.jar b/lib/servlet-api-2.5.jar new file mode 100644 index 0000000..20b5755 --- /dev/null +++ b/lib/servlet-api-2.5.jar Binary files differ diff --git a/lib/slf4j-api-1.6.4.jar b/lib/slf4j-api-1.6.4.jar new file mode 100644 index 0000000..4d23f41 --- /dev/null +++ b/lib/slf4j-api-1.6.4.jar Binary files differ diff --git a/lib/slf4j-simple-1.6.4.jar b/lib/slf4j-simple-1.6.4.jar new file mode 100644 index 0000000..3d1b8d9 --- /dev/null +++ b/lib/slf4j-simple-1.6.4.jar Binary files differ diff --git a/lib/ssr-0.1.jar b/lib/ssr-0.1.jar new file mode 100644 index 0000000..65dfcf4 --- /dev/null +++ b/lib/ssr-0.1.jar Binary files differ diff --git a/lib/vst-0.4.jar b/lib/vst-0.4.jar new file mode 100644 index 0000000..db63792 --- /dev/null +++ b/lib/vst-0.4.jar Binary files differ diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..ac2dbe1 --- /dev/null +++ b/readme.md @@ -0,0 +1 @@ +A simple wrapper around jdbc drivers what will show current jdbc stats of the running queries on a simple web page on port 18080. \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/ConnectionLogger.java b/src/nl/astraeus/jdbc/ConnectionLogger.java new file mode 100644 index 0000000..c3e243f --- /dev/null +++ b/src/nl/astraeus/jdbc/ConnectionLogger.java @@ -0,0 +1,279 @@ +package nl.astraeus.jdbc; + +import java.sql.*; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Executor; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:12:34 PM + */ +public class ConnectionLogger implements Connection { + private Connection connection; + + private long milli; + private long nano; + private String lastSql; + + public ConnectionLogger(Connection connection) { + this.connection = connection; + this.lastSql = ""; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(QueryType.UNKNOWN, sql, m, n); + } + + public void commit() throws SQLException { + clearTime(); + + connection.commit(); + + log("commit"); + } + + public void rollback() throws SQLException { + clearTime(); + + connection.rollback(); + + log("rollback"); + } + + public void close() throws SQLException { + clearTime(); + + connection.close(); + + log("close"); + } + + public PreparedStatement prepareStatement(String sql) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, autoGeneratedKeys); + } + + public PreparedStatement prepareStatement(String sql, int columnIndexes[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnIndexes); + } + + public PreparedStatement prepareStatement(String sql, String columnNames[]) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, columnNames); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return new PreparedStatementLogger(connection, sql, resultSetType, resultSetConcurrency); + } + + public Statement createStatement() throws SQLException { + return connection.createStatement(); + } + + public CallableStatement prepareCall(String sql) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql); + } + + public String nativeSQL(String sql) throws SQLException { + lastSql = sql; + return connection.nativeSQL(sql); + } + + public void setAutoCommit(boolean autoCommit) throws SQLException { + connection.setAutoCommit(autoCommit); + } + + public boolean getAutoCommit() throws SQLException { + return connection.getAutoCommit(); + } + + public boolean isClosed() throws SQLException { + return connection.isClosed(); + } + + public DatabaseMetaData getMetaData() throws SQLException { + return connection.getMetaData(); + } + + public void setReadOnly(boolean readOnly) throws SQLException { + connection.setReadOnly(readOnly); + } + + public boolean isReadOnly() throws SQLException { + return connection.isReadOnly(); + } + + public void setCatalog(String catalog) throws SQLException { + connection.setCatalog(catalog); + } + + public String getCatalog() throws SQLException { + return connection.getCatalog(); + } + + public void setTransactionIsolation(int level) throws SQLException { + connection.setTransactionIsolation(level); + } + + public int getTransactionIsolation() throws SQLException { + return connection.getTransactionIsolation(); + } + + public SQLWarning getWarnings() throws SQLException { + return connection.getWarnings(); + } + + public void clearWarnings() throws SQLException { + connection.clearWarnings(); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency); + } + + public Map> getTypeMap() throws SQLException { + return connection.getTypeMap(); + } + + public void setTypeMap(Map> map) throws SQLException { + connection.setTypeMap(map); + } + + public void setHoldability(int holdability) throws SQLException { + connection.setHoldability(holdability); + } + + public int getHoldability() throws SQLException { + return connection.getHoldability(); + } + + public Savepoint setSavepoint() throws SQLException { + return connection.setSavepoint(); + } + + public Savepoint setSavepoint(String name) throws SQLException { + return connection.setSavepoint(name); + } + + public void rollback(Savepoint savepoint) throws SQLException { + connection.rollback(); + } + + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + connection.releaseSavepoint(savepoint); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + return connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + lastSql = sql; + return connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + + public Clob createClob() throws SQLException { + return connection.createClob(); + } + + public Blob createBlob() throws SQLException { + return connection.createBlob(); + } + + public NClob createNClob() throws SQLException { + return connection.createNClob(); + } + + public SQLXML createSQLXML() throws SQLException { + return connection.createSQLXML(); + } + + public boolean isValid(int timeout) throws SQLException { + return connection.isValid(timeout); + } + + public void setClientInfo(String name, String value) throws SQLClientInfoException { + connection.setClientInfo(name, value); + } + + public void setClientInfo(Properties properties) throws SQLClientInfoException { + connection.setClientInfo(properties); + } + + public String getClientInfo(String name) throws SQLException { + return connection.getClientInfo(name); + } + + public Properties getClientInfo() throws SQLException { + return connection.getClientInfo(); + } + + public Array createArrayOf(String typeName, Object[] elements) throws SQLException { + return connection.createArrayOf(typeName, elements); + } + + public Struct createStruct(String typeName, Object[] attributes) throws SQLException { + return connection.createStruct(typeName, attributes); + } + + @Override + public void setSchema(String schema) throws SQLException { + connection.setSchema(schema); + } + + @Override + public String getSchema() throws SQLException { + return connection.getSchema(); + } + + @Override + public void abort(Executor executor) throws SQLException { + connection.abort(executor); + } + + @Override + public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { + connection.setNetworkTimeout(executor, milliseconds); + } + + @Override + public int getNetworkTimeout() throws SQLException { + return connection.getNetworkTimeout(); + } + + public T unwrap(Class iface) throws SQLException { + return connection.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return connection.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/Driver.java b/src/nl/astraeus/jdbc/Driver.java new file mode 100644 index 0000000..8317172 --- /dev/null +++ b/src/nl/astraeus/jdbc/Driver.java @@ -0,0 +1,116 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.http.SimpleWebServer; +import nl.astraeus.jdbc.web.JdbcStatisticsServlet; +import nl.astraeus.jdbc.web.ResourceServlet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.*; +import java.util.Enumeration; +import java.util.Properties; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:54:37 PM + */ +public class Driver implements java.sql.Driver { + private final static Logger log = LoggerFactory.getLogger(Driver.class); + + final private static String URL_PREFIX = "jdbc:stat:"; + + private java.sql.Driver driver = null; + private String[] drivers = { + "org.postgresql.Driver", + "oracle.jdbc.driver.OracleDriver", + "com.sybase.jdbc2.jdbc.SybDriver", + "net.sourceforge.jtds.jdbc.Driver", + "com.microsoft.jdbc.sqlserver.SQLServerDriver", + "com.microsoft.sqlserver.jdbc.SQLServerDriver", + "weblogic.jdbc.sqlserver.SQLServerDriver", + "com.informix.jdbc.IfxDriver", + "org.apache.derby.jdbc.ClientDriver", + "org.apache.derby.jdbc.EmbeddedDriver", + "com.mysql.jdbc.Driver", + "org.hsqldb.jdbcDriver", + "org.h2.Driver" }; + + static { + log.debug("Loading driver class " + Driver.class.getName()); + + try { + DriverManager.registerDriver(new Driver()); + } catch (SQLException e) { + log.error("", e); + } + } + + public Driver() { + for (String dr : drivers) { + try { + Class.forName(dr); + } catch (Throwable e) { + log.debug("Can't instantiate driver: " + dr, e); + } + } + } + + private java.sql.Driver findDriver(String url) throws SQLException { + Enumeration e = DriverManager.getDrivers(); + + while (e.hasMoreElements()) { + java.sql.Driver d = (java.sql.Driver) e.nextElement(); + + if (d.acceptsURL(url)) { + return d; + } + } + + throw new SQLException("Driver not found: " + url); + } + + public Connection connect(String url, Properties info) throws SQLException { + url = url.substring(URL_PREFIX.length()); + + if (driver == null) { + driver = findDriver(url); + } + + if (driver != null) { + SimpleWebServer server = new SimpleWebServer(18080); + + server.addServlet(new JdbcStatisticsServlet(), "/"); + server.addServlet(new ResourceServlet(), "/resources/*"); + + server.start(); + } + + return new ConnectionLogger(driver.connect(url, info)); + } + + public boolean acceptsURL(String url) throws SQLException { + return (url != null && url.startsWith(URL_PREFIX)); + } + + public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { + return driver.getPropertyInfo(url, info); + } + + public int getMajorVersion() { + return driver.getMajorVersion(); + } + + public int getMinorVersion() { + return driver.getMinorVersion(); + } + + public boolean jdbcCompliant() { + return driver.jdbcCompliant(); + } + + @Override + public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException { + return driver.getParentLogger(); + } +} diff --git a/src/nl/astraeus/jdbc/JdbcLogger.java b/src/nl/astraeus/jdbc/JdbcLogger.java new file mode 100644 index 0000000..f4bc125 --- /dev/null +++ b/src/nl/astraeus/jdbc/JdbcLogger.java @@ -0,0 +1,113 @@ +package nl.astraeus.jdbc; + +import nl.astraeus.jdbc.util.Util; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/** + * User: riennentjes + * Date: Jul 12, 2008 + * Time: 9:15:21 AM + */ +public class JdbcLogger { + private final static Logger logger = LoggerFactory.getLogger(JdbcLogger.class); + + private final static JdbcLogger instance = new JdbcLogger(); + + public static JdbcLogger get() { + return instance; + } + + public final static class LogEntry { + public QueryType type; + public String sql; + public long milli; + public long nano; + public int count; + public int hash; + + public LogEntry(int hash, QueryType type, String sql, long milli, long nano) { + this.hash = hash; + this.type = type; + this.sql = sql; + this.milli = milli; + this.nano = nano; + this.count = 1; + } + + public void addCount(long milli, long nano) { + synchronized (this) { + count++; + this.milli += milli; + this.nano += nano; + } + } + + public int getCount() { + return count; + } + + public String getMilli() { + return Util.formatNano(milli*1000000/count); + } + + public String getNano() { + return Util.formatNano(nano/count); + } + + public String getTotal() { + return Util.formatNano(nano); + } + + public String getSql() { + return sql; + } + } + + private Map queries; + + public JdbcLogger() { + queries = new ConcurrentHashMap(); + } + + public void logEntry(QueryType type, String sql, long milli, long nano) { + int hash = sql.hashCode(); + LogEntry entry = queries.get(hash); + + if (entry == null) { + entry = new LogEntry(hash, type, sql, milli, nano); + queries.put(hash, entry); + } else { + entry.addCount(milli, nano); + } + + if (queries.size() > 1000) { + List toRemove = new LinkedList(); + List values = new LinkedList(queries.values()); + + Collections.sort(values, new Comparator() { + @Override + public int compare(LogEntry o1, LogEntry o2) { + return o1.count - o2.count; + } + }); + + while (queries.size() > 900) { + queries.remove(values.remove(0).hash); + + } + } + } + + public static void log(QueryType type, String sql, long milli, long nano) { + instance.logEntry(type, sql, milli, nano); + } + + public Collection getEntries() { + return queries.values(); + } + +} diff --git a/src/nl/astraeus/jdbc/PreparedStatementLogger.java b/src/nl/astraeus/jdbc/PreparedStatementLogger.java new file mode 100644 index 0000000..98aefc7 --- /dev/null +++ b/src/nl/astraeus/jdbc/PreparedStatementLogger.java @@ -0,0 +1,577 @@ +package nl.astraeus.jdbc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.InputStream; +import java.io.Reader; +import java.math.BigDecimal; +import java.net.URL; +import java.sql.*; +import java.util.Calendar; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 7:47:57 PM + */ +public class PreparedStatementLogger implements PreparedStatement { + private final static Logger log = LoggerFactory.getLogger(PreparedStatementLogger.class); + + private PreparedStatement statement; + + private String sql; + private QueryType type; + private long milli; + private long nano; + + //private ArrayList parameters; + + public PreparedStatementLogger(PreparedStatement statement) { + this.statement = statement; + this.sql = ""; + this.type = QueryType.UNKNOWN; + } + + private void clearTime() { + milli = System.currentTimeMillis(); + nano = System.nanoTime(); + } + + private void log(QueryType type, String sql) { + long m = System.currentTimeMillis() - milli; + long n = System.nanoTime() - nano; + + JdbcLogger.log(type, sql, m, n); + } + + public PreparedStatementLogger(Connection connection, String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql); + } + + public PreparedStatementLogger(Connection connection, String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, resultSetType, resultSetConcurrency); + } + + public PreparedStatementLogger(Connection connection, String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, autoGeneratedKeys); + } + + public PreparedStatementLogger(Connection connection, String sql, int[] columnIndexes) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnIndexes); + } + + public PreparedStatementLogger(Connection connection, String sql, String[] columnNames) throws SQLException { + this.sql = sql; + this.type = QueryType.PREPARED; + clearTime(); + statement = connection.prepareStatement(sql, columnNames); + } + + public boolean execute() throws SQLException { + clearTime(); + + boolean result = statement.execute(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery() throws SQLException { + clearTime(); + + ResultSet result = statement.executeQuery(); + + log(type, sql); + + return result; + } + + public int executeUpdate() throws SQLException { + clearTime(); + + int result = statement.executeUpdate(); + + log(type, sql); + + return result; + } + + public ResultSet executeQuery(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + ResultSet result = statement.executeQuery(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public int executeUpdate(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + int result = statement.executeUpdate(sql, columnNames); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, autoGeneratedKeys); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, int columnIndexes[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnIndexes); + + log(type, sql); + + return result; + } + + public boolean execute(String sql, String columnNames[]) throws SQLException { + this.sql = sql; + this.type = QueryType.PLAIN; + + clearTime(); + + boolean result = statement.execute(sql, columnNames); + + log(type, sql); + + return result; + } + + + public void setNull(int parameterIndex, int sqlType) throws SQLException { + statement.setNull(parameterIndex, sqlType); + } + + public void setBoolean(int parameterIndex, boolean x) throws SQLException { + statement.setBoolean(parameterIndex, x); + } + + public void setByte(int parameterIndex, byte x) throws SQLException { + statement.setByte(parameterIndex, x); + } + + public void setShort(int parameterIndex, short x) throws SQLException { + statement.setShort(parameterIndex, x); + } + + public void setInt(int parameterIndex, int x) throws SQLException { + statement.setInt(parameterIndex, x); + } + + public void setLong(int parameterIndex, long x) throws SQLException { + statement.setLong(parameterIndex, x); + } + + public void setFloat(int parameterIndex, float x) throws SQLException { + statement.setFloat(parameterIndex, x); + } + + public void setDouble(int parameterIndex, double x) throws SQLException { + statement.setDouble(parameterIndex, x); + } + + public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { + statement.setBigDecimal(parameterIndex, x); + } + + public void setString(int parameterIndex, String x) throws SQLException { + statement.setString(parameterIndex, x); + } + + public void setBytes(int parameterIndex, byte x[]) throws SQLException { + statement.setBytes(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x) throws SQLException { + statement.setDate(parameterIndex, x); + } + + public void setTime(int parameterIndex, Time x) throws SQLException { + statement.setTime(parameterIndex, x); + } + + public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { + statement.setTimestamp(parameterIndex, x); + } + + public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setUnicodeStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType); + } + + public void setObject(int parameterIndex, Object x) throws SQLException { + statement.setObject(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setRef(int parameterIndex, Ref x) throws SQLException { + statement.setRef(parameterIndex, x); + } + + public void setBlob(int parameterIndex, Blob x) throws SQLException { + statement.setBlob(parameterIndex, x); + } + + public void setClob(int parameterIndex, Clob x) throws SQLException { + statement.setClob(parameterIndex, x); + } + + public void setArray(int parameterIndex, Array x) throws SQLException { + statement.setArray(parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { + statement.setDate(parameterIndex, x, cal); + } + + public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { + statement.setTime(parameterIndex, x, cal); + } + + public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { + statement.setTimestamp(parameterIndex, x, cal); + } + + public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException { + statement.setNull(parameterIndex, sqlType, typeName); + } + + public void setURL(int parameterIndex, URL x) throws SQLException { + statement.setURL(parameterIndex, x); + } + + public void setRowId(int parameterIndex, RowId x) throws SQLException { + statement.setRowId(parameterIndex, x); + } + + public void setNString(int parameterIndex, String value) throws SQLException { + statement.setNString(parameterIndex, value); + } + + public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException { + statement.setNCharacterStream(parameterIndex, value, length); + } + + public void setNClob(int parameterIndex, NClob value) throws SQLException { + statement.setNClob(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setClob(parameterIndex, reader, length); + } + + public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException { + statement.setBlob(parameterIndex, inputStream, length); + } + + public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setNClob(parameterIndex, reader, length); + } + + public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException { + statement.setSQLXML(parameterIndex, xmlObject); + } + + public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException { + statement.setObject(parameterIndex, x, targetSqlType, scaleOrLength); + } + + public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setAsciiStream(parameterIndex, x, length); + } + + public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException { + statement.setBinaryStream(parameterIndex, x, length); + } + + public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException { + statement.setCharacterStream(parameterIndex, reader, length); + } + + public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException { + statement.setAsciiStream(parameterIndex, x); + } + + public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException { + statement.setBinaryStream(parameterIndex, x); + } + + public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException { + statement.setCharacterStream(parameterIndex, reader); + } + + public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException { + statement.setNCharacterStream(parameterIndex, value); + } + + public void setClob(int parameterIndex, Reader reader) throws SQLException { + statement.setClob(parameterIndex, reader); + } + + public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException { + statement.setBlob(parameterIndex, inputStream); + } + + public void setNClob(int parameterIndex, Reader reader) throws SQLException { + statement.setNClob(parameterIndex, reader); + } + + + public void close() throws SQLException { + sql = ""; + type = QueryType.UNKNOWN; + milli = 0; + nano = 0; + + statement.close(); + } + + public ResultSetMetaData getMetaData() throws SQLException { + return statement.getMetaData(); + } + + public void clearParameters() throws SQLException { + statement.clearParameters(); + } + + public ParameterMetaData getParameterMetaData() throws SQLException { + return statement.getParameterMetaData(); + } + + public void addBatch() throws SQLException { + statement.addBatch(); + } + + public int getMaxFieldSize() throws SQLException { + return statement.getMaxFieldSize(); + } + + public void setMaxFieldSize(int max) throws SQLException { + statement.setMaxFieldSize(max); + } + + public int getMaxRows() throws SQLException { + return statement.getMaxRows(); + } + + public void setMaxRows(int max) throws SQLException { + statement.setMaxRows(max); + } + + public void setEscapeProcessing(boolean enable) throws SQLException { + statement.setEscapeProcessing(enable); + } + + public int getQueryTimeout() throws SQLException { + return statement.getQueryTimeout(); + } + + public void setQueryTimeout(int seconds) throws SQLException { + statement.setQueryTimeout(seconds); + } + + public void cancel() throws SQLException { + statement.cancel(); + } + + public SQLWarning getWarnings() throws SQLException { + return statement.getWarnings(); + } + + public void clearWarnings() throws SQLException { + statement.clearWarnings(); + } + + public void setCursorName(String name) throws SQLException { + statement.setCursorName(name); + } + + public boolean execute(String sql) throws SQLException { + return statement.execute(sql); + } + + public ResultSet getResultSet() throws SQLException { + return statement.getResultSet(); + } + + public int getUpdateCount() throws SQLException { + return statement.getUpdateCount(); + } + + public boolean getMoreResults() throws SQLException { + return statement.getMoreResults(); + } + + public void setFetchDirection(int direction) throws SQLException { + statement.setFetchDirection(direction); + } + + public int getFetchDirection() throws SQLException { + return statement.getFetchDirection(); + } + + public void setFetchSize(int rows) throws SQLException { + statement.setFetchSize(rows); + } + + public int getFetchSize() throws SQLException { + return statement.getFetchSize(); + } + + public int getResultSetConcurrency() throws SQLException { + return statement.getResultSetConcurrency(); + } + + public int getResultSetType() throws SQLException { + return statement.getResultSetType(); + } + + public void addBatch(String sql) throws SQLException { + statement.addBatch(sql); + } + + public void clearBatch() throws SQLException { + statement.clearBatch(); + } + + public int[] executeBatch() throws SQLException { + return statement.executeBatch(); + } + + public Connection getConnection() throws SQLException { + return statement.getConnection(); + } + + public boolean getMoreResults(int current) throws SQLException { + return statement.getMoreResults(current); + } + + public ResultSet getGeneratedKeys() throws SQLException { + return statement.getGeneratedKeys(); + } + + public int getResultSetHoldability() throws SQLException { + return statement.getResultSetHoldability(); + } + + public boolean isClosed() throws SQLException { + return statement.isClosed(); + } + + public void setPoolable(boolean poolable) throws SQLException { + statement.setPoolable(poolable); + } + + public boolean isPoolable() throws SQLException { + return statement.isPoolable(); + } + + @Override + public void closeOnCompletion() throws SQLException { + statement.closeOnCompletion();; + } + + @Override + public boolean isCloseOnCompletion() throws SQLException { + return statement.isCloseOnCompletion(); + } + + public T unwrap(Class iface) throws SQLException { + return statement.unwrap(iface); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return statement.isWrapperFor(iface); + } +} diff --git a/src/nl/astraeus/jdbc/QueryType.java b/src/nl/astraeus/jdbc/QueryType.java new file mode 100644 index 0000000..744fbfc --- /dev/null +++ b/src/nl/astraeus/jdbc/QueryType.java @@ -0,0 +1,24 @@ +package nl.astraeus.jdbc; + +/** + * User: riennentjes + * Date: Jul 10, 2008 + * Time: 8:32:49 PM + */ +public enum QueryType { + PLAIN("plain"), + PREPARED("prepared"), + CALLABLE("callable"), + UNKNOWN("unknown"); + + private String description; + + QueryType(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } + +} diff --git a/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java new file mode 100644 index 0000000..07aac40 --- /dev/null +++ b/src/nl/astraeus/jdbc/example/JdbcStatisticsExample.java @@ -0,0 +1,68 @@ +package nl.astraeus.jdbc.example; + +import java.sql.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 7:32 PM + */ +public class JdbcStatisticsExample { + + + public static void main(String [] args) throws Exception { + Class.forName("org.h2.Driver"); + Class.forName("nl.astraeus.jdbc.Driver"); + + new JdbcStatisticsExample(); + } + + public JdbcStatisticsExample() throws Exception { + Connection conn = DriverManager.getConnection("jdbc:stat:jdbc:h2:mem:test"); + + Statement statement = null; + + statement = conn.createStatement(); + statement.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + + boolean running = true; + int count = 1; + PreparedStatement ps = null; + + while (running) { + Thread.sleep(10); + + String TableName = "TEST"+(System.nanoTime() % 1000); + + try { + ps = conn.prepareStatement("SELECT COUNT(*) FROM "+TableName); + ResultSet rs = ps.executeQuery(); + } catch (SQLException e) { + statement = conn.createStatement(); + statement.execute("CREATE TABLE "+TableName+" (ID INT PRIMARY KEY, NAME VARCHAR(255))"); + statement.close(); + } finally { + if (ps!=null) { + ps.close(); + } + } + + ps = conn.prepareStatement("INSERT INTO "+TableName+" VALUES (?, ?)"); + + ps.setInt(1, count++); + ps.setString(2, "String "+System.currentTimeMillis()); + + ps.execute(); + ps.close(); + + Thread.sleep(10); + + ps = conn.prepareStatement("SELECT * FROM "+TableName); + ResultSet rs = ps.executeQuery(); + statement.close(); + } + + conn.close(); + } +} diff --git a/src/nl/astraeus/jdbc/util/IOUtils.java b/src/nl/astraeus/jdbc/util/IOUtils.java new file mode 100644 index 0000000..ce95d9d --- /dev/null +++ b/src/nl/astraeus/jdbc/util/IOUtils.java @@ -0,0 +1,38 @@ +package nl.astraeus.jdbc.util; + +import java.io.*; + +/** + * User: rnentjes + * Date: 4/9/12 + * Time: 2:33 PM + */ +public class IOUtils { + + public static String toString(InputStream in) throws IOException { + assert in != null; + + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + StringBuilder buffer = new StringBuilder(); + + while(reader.ready()) { + buffer.append(reader.readLine()); + buffer.append("\n"); + } + + return buffer.toString(); + } finally { + in.close(); + } + } + + public static void copy(InputStream in, OutputStream out) throws IOException { + byte [] buffer = new byte[1<<16]; + int bytes; + + while((bytes = in.read(buffer)) > 0) { + out.write(buffer, 0, bytes); + } + } +} diff --git a/src/nl/astraeus/jdbc/util/Util.java b/src/nl/astraeus/jdbc/util/Util.java new file mode 100644 index 0000000..eaa853b --- /dev/null +++ b/src/nl/astraeus/jdbc/util/Util.java @@ -0,0 +1,25 @@ +package nl.astraeus.jdbc.util; + +import java.text.DecimalFormat; +import java.text.NumberFormat; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 12:28 PM + */ +public class Util { + // utility functions + public static String formatNano(long l) { + NumberFormat format = new DecimalFormat("###,##0.000000"); + + return format.format((double) l / 1000000.0); + } + + public static void printMemoryUsage() { + System.out.println("Used memory: "+((Runtime.getRuntime().totalMemory() / (1024*1024))-(Runtime.getRuntime().freeMemory() / (1024*1024)))); + System.out.println("Free memory: "+(Runtime.getRuntime().freeMemory() / (1024*1024))); + System.out.println("Total memory: "+(Runtime.getRuntime().totalMemory() / (1024*1024))); + System.out.println("Max memory: "+(Runtime.getRuntime().maxMemory() / (1024*1024))); + } +} diff --git a/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java b/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java new file mode 100644 index 0000000..a162d6f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/JdbcStatisticsServlet.java @@ -0,0 +1,90 @@ +package nl.astraeus.jdbc.web; + +import nl.astraeus.jdbc.util.IOUtils; +import nl.astraeus.jdbc.util.Util; +import nl.astraeus.jdbc.web.page.Menu; +import nl.astraeus.jdbc.web.page.Page; +import nl.astraeus.jdbc.web.page.QueryOverview; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import java.io.IOException; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:05 PM + */ +public class JdbcStatisticsServlet extends HttpServlet { + + private String head; + private String bottom; + + @Override + public void init() throws ServletException { + super.init(); + + try { + head = IOUtils.toString(getClass().getResourceAsStream("head.html")); + bottom = IOUtils.toString(getClass().getResourceAsStream("bottom.html")); + } catch (IOException e) { + throw new ServletException(e); + } + + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + doPost(req, resp); + } + + @Override + protected void doPost(final HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + long nano = System.nanoTime(); + + HttpSession session = req.getSession(); + boolean ajax = "true".equals(req.getParameter("ajax")); + + resp.setContentType("text/html"); + + Page page = (Page)session.getAttribute("page"); + Page menu = (Page)session.getAttribute("menu"); + + session.setMaxInactiveInterval(1800); + + if (menu == null) { + menu = new Menu(); + + session.setAttribute("menu", menu); + } + + if (page == null || "menumain".equals(req.getParameter("action"))) { + page = new QueryOverview(); + } else if ("diagnostics".equals(req.getParameter("action"))) { + //page = new Diagnostics(); + } else { + page = page .processRequest(req); + } + + menu.processRequest(req); + + session.setAttribute("page", page); + + if (!ajax) { + resp.getWriter().print(head); + } + + resp.getWriter().print(menu.render(req)); + resp.getWriter().print(page.render(req)); + + if (!ajax) { + resp.getWriter().print(bottom); + } + + System.out.println("Request ends, time="+ Util.formatNano(System.nanoTime() - nano) +", page="+page.getClass().getSimpleName()); + } + +} diff --git a/src/nl/astraeus/jdbc/web/ResourceServlet.java b/src/nl/astraeus/jdbc/web/ResourceServlet.java new file mode 100644 index 0000000..7abfe6f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/ResourceServlet.java @@ -0,0 +1,49 @@ +package nl.astraeus.jdbc.web; + +import nl.astraeus.jdbc.util.IOUtils; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.InputStream; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:05 PM + */ +public class ResourceServlet extends HttpServlet { + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String uri = req.getRequestURI(); + + uri = "nl/astraeus/jdbc/web" + uri; + InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(uri); + + if (in == null) { + resp.sendError(404, "Cannot find resource '" + uri + "'."); + } else { + try { + if (uri.endsWith("js")) { + resp.setContentType("text/javascript"); + } else if (uri.endsWith("css")) { + resp.setContentType("text/css"); + } else if (uri.endsWith("png")) { + resp.setContentType("image/png"); + } else if (uri.endsWith("jpg")) { + resp.setContentType("image/jpeg"); + } else if (uri.endsWith("gif")) { + resp.setContentType("image/gif"); + } + + IOUtils.copy(in, resp.getOutputStream()); + } finally { + in.close(); + } + } + } + +} diff --git a/src/nl/astraeus/jdbc/web/bottom.html b/src/nl/astraeus/jdbc/web/bottom.html new file mode 100644 index 0000000..1288de4 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/bottom.html @@ -0,0 +1,8 @@ + + +
+ + + + + \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/head.html b/src/nl/astraeus/jdbc/web/head.html new file mode 100644 index 0000000..0f8f6a3 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/head.html @@ -0,0 +1,96 @@ + + + + + + + Simple JDBC Statistics + + + + + + + + + + + + + + + + + + + +
+
+ +
+ diff --git a/src/nl/astraeus/jdbc/web/page/Menu.html b/src/nl/astraeus/jdbc/web/page/Menu.html new file mode 100644 index 0000000..505c7c2 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.html @@ -0,0 +1,42 @@ + diff --git a/src/nl/astraeus/jdbc/web/page/Menu.java b/src/nl/astraeus/jdbc/web/page/Menu.java new file mode 100644 index 0000000..f0a349a --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.java @@ -0,0 +1,27 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 9:07 PM + */ +public class Menu extends TemplatePage { + + @Override + public Page processRequest(HttpServletRequest request) { + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + result.put("user", request.getSession().getAttribute("user")); + + return result; + } +} diff --git a/src/nl/astraeus/jdbc/web/page/Page.java b/src/nl/astraeus/jdbc/web/page/Page.java new file mode 100644 index 0000000..9d526d6 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Page.java @@ -0,0 +1,17 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:20 PM + */ +public abstract class Page { + + public abstract Page processRequest(HttpServletRequest request); + public abstract Map defineModel(HttpServletRequest request); + public abstract String render(HttpServletRequest request); + +} diff --git a/src/nl/astraeus/jdbc/web/page/QueryOverview.html b/src/nl/astraeus/jdbc/web/page/QueryOverview.html new file mode 100644 index 0000000..64a88fb --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/QueryOverview.html @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + {foreach(queries as q)} + + + + + + + {eachend} + +
Total timeAvg. time# CallsSql
{q.total}{q.nano}{q.count}{q.sql}
diff --git a/src/nl/astraeus/jdbc/web/page/QueryOverview.java b/src/nl/astraeus/jdbc/web/page/QueryOverview.java new file mode 100644 index 0000000..02982f1 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/QueryOverview.java @@ -0,0 +1,92 @@ +package nl.astraeus.jdbc.web.page; + +import nl.astraeus.jdbc.JdbcLogger; + +import javax.servlet.http.HttpServletRequest; +import java.util.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 9:16 PM + */ +public class QueryOverview extends TemplatePage { + + boolean sortTotalCalls = true; + boolean sortAvgTime = false; + boolean sortTotalTime = false; + + @Override + public Page processRequest(HttpServletRequest request) { + if ("sortTotalCalls".equals(request.getParameter("action"))) { + sortTotalCalls = true; + sortAvgTime = false; + sortTotalTime = false; + } else if ("sortAvgTime".equals(request.getParameter("action"))) { + sortTotalCalls = false; + sortAvgTime = true; + sortTotalTime = false; + } else if ("sortTotalTime".equals(request.getParameter("action"))) { + sortTotalCalls = false; + sortAvgTime = false; + sortTotalTime = true; + } + + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + List entries = new ArrayList(JdbcLogger.get().getEntries()); + + if (sortTotalCalls) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + return o2.count - o1.count; + } + }); + } else if (sortAvgTime) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + long n1 = o1.nano / o1.count; + long n2 = o2.nano / o2.count; + + if (n2 > n1) { + return 1; + } else if (n2 < n1) { + return -1; + } else { + return 0; + } + } + }); + } else if (sortTotalTime) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + if (o2.nano > o1.nano) { + return 1; + } else if (o2.nano < o1.nano) { + return -1; + } else { + return 0; + } + } + }); + } + + result.put("queries", entries); + result.put("count", entries.size()); + + result.put("sortTotalCalls", sortTotalCalls); + result.put("sortAvgTime", sortAvgTime); + result.put("sortTotalTime", sortTotalTime); + + return result; + } + +} diff --git a/src/nl/astraeus/jdbc/web/page/TemplatePage.java b/src/nl/astraeus/jdbc/web/page/TemplatePage.java new file mode 100644 index 0000000..33e2641 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/TemplatePage.java @@ -0,0 +1,58 @@ +package nl.astraeus.jdbc.web.page; + +import nl.astraeus.template.EscapeMode; +import nl.astraeus.template.SimpleTemplate; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:20 PM + */ +public abstract class TemplatePage extends Page { + + private SimpleTemplate template; + + protected TemplatePage() { + template = getSimpleTemplate(this.getClass()); + } + + public String render(HttpServletRequest request) { + return template.render(defineModel(request)); + } + + private static Map templateCache = new HashMap(); + + public synchronized static SimpleTemplate getSimpleTemplate(Class cls) { + SimpleTemplate result = templateCache.get(cls); + + if (result == null) { + InputStream in = null; + + try { + in = cls.getResourceAsStream(cls.getSimpleName() + ".html"); + + result = SimpleTemplate.readTemplate('{','}', EscapeMode.HTML, in); + + templateCache.put(cls, result); + } catch (IOException e) { + throw new IllegalStateException(e); + } finally { + if (in != null) { + try { + in.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + + return result; + } +} diff --git a/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css b/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css new file mode 100644 index 0000000..0e0056f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css @@ -0,0 +1,581 @@ +/*! + * Bootstrap Responsive v2.0.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ +.clearfix { + *zoom: 1; +} +.clearfix:before, .clearfix:after { + display: table; + content: ""; +} +.clearfix:after { + clear: both; +} +.hidden { + display: none; + visibility: hidden; +} +@media (max-width: 480px) { + .nav-collapse { + -webkit-transform: translate3d(0, 0, 0); + } + .page-header h1 small { + display: block; + line-height: 18px; + } + input[class*="span"], + select[class*="span"], + textarea[class*="span"], + .uneditable-input { + display: block; + width: 100%; + min-height: 28px; + /* Make inputs at least the height of their button counterpart */ + + /* Makes inputs behave like true block-level elements */ + + -webkit-box-sizing: border-box; + /* Older Webkit */ + + -moz-box-sizing: border-box; + /* Older FF */ + + -ms-box-sizing: border-box; + /* IE8 */ + + box-sizing: border-box; + /* CSS3 spec*/ + + } + .input-prepend input[class*="span"], .input-append input[class*="span"] { + width: auto; + } + input[type="checkbox"], input[type="radio"] { + border: 1px solid #ccc; + } + .form-horizontal .control-group > label { + float: none; + width: auto; + padding-top: 0; + text-align: left; + } + .form-horizontal .controls { + margin-left: 0; + } + .form-horizontal .control-list { + padding-top: 0; + } + .form-horizontal .form-actions { + padding-left: 10px; + padding-right: 10px; + } + .modal { + position: absolute; + top: 10px; + left: 10px; + right: 10px; + width: auto; + margin: 0; + } + .modal.fade.in { + top: auto; + } + .modal-header .close { + padding: 10px; + margin: -10px; + } + .carousel-caption { + position: static; + } +} +@media (max-width: 767px) { + .container { + width: auto; + padding: 0 20px; + } + .row-fluid { + width: 100%; + } + .row { + margin-left: 0; + } + .row > [class*="span"], .row-fluid > [class*="span"] { + float: none; + display: block; + width: auto; + margin: 0; + } +} +@media (min-width: 768px) and (max-width: 979px) { + .row { + margin-left: -20px; + *zoom: 1; + } + .row:before, .row:after { + display: table; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + margin-left: 20px; + } + .span1 { + width: 42px; + } + .span2 { + width: 104px; + } + .span3 { + width: 166px; + } + .span4 { + width: 228px; + } + .span5 { + width: 290px; + } + .span6 { + width: 352px; + } + .span7 { + width: 414px; + } + .span8 { + width: 476px; + } + .span9 { + width: 538px; + } + .span10 { + width: 600px; + } + .span11 { + width: 662px; + } + .span12, .container { + width: 724px; + } + .offset1 { + margin-left: 82px; + } + .offset2 { + margin-left: 144px; + } + .offset3 { + margin-left: 206px; + } + .offset4 { + margin-left: 268px; + } + .offset5 { + margin-left: 330px; + } + .offset6 { + margin-left: 392px; + } + .offset7 { + margin-left: 454px; + } + .offset8 { + margin-left: 516px; + } + .offset9 { + margin-left: 578px; + } + .offset10 { + margin-left: 640px; + } + .offset11 { + margin-left: 702px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, .row-fluid:after { + display: table; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid > [class*="span"] { + float: left; + margin-left: 2.762430939%; + } + .row-fluid > [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid > .span1 { + width: 5.801104972%; + } + .row-fluid > .span2 { + width: 14.364640883%; + } + .row-fluid > .span3 { + width: 22.928176794%; + } + .row-fluid > .span4 { + width: 31.491712705%; + } + .row-fluid > .span5 { + width: 40.055248616%; + } + .row-fluid > .span6 { + width: 48.618784527%; + } + .row-fluid > .span7 { + width: 57.182320438000005%; + } + .row-fluid > .span8 { + width: 65.74585634900001%; + } + .row-fluid > .span9 { + width: 74.30939226%; + } + .row-fluid > .span10 { + width: 82.87292817100001%; + } + .row-fluid > .span11 { + width: 91.436464082%; + } + .row-fluid > .span12 { + width: 99.999999993%; + } + input.span1, textarea.span1, .uneditable-input.span1 { + width: 32px; + } + input.span2, textarea.span2, .uneditable-input.span2 { + width: 94px; + } + input.span3, textarea.span3, .uneditable-input.span3 { + width: 156px; + } + input.span4, textarea.span4, .uneditable-input.span4 { + width: 218px; + } + input.span5, textarea.span5, .uneditable-input.span5 { + width: 280px; + } + input.span6, textarea.span6, .uneditable-input.span6 { + width: 342px; + } + input.span7, textarea.span7, .uneditable-input.span7 { + width: 404px; + } + input.span8, textarea.span8, .uneditable-input.span8 { + width: 466px; + } + input.span9, textarea.span9, .uneditable-input.span9 { + width: 528px; + } + input.span10, textarea.span10, .uneditable-input.span10 { + width: 590px; + } + input.span11, textarea.span11, .uneditable-input.span11 { + width: 652px; + } + input.span12, textarea.span12, .uneditable-input.span12 { + width: 714px; + } +} +@media (max-width: 979px) { + body { + padding-top: 0; + } + .navbar-fixed-top { + position: static; + margin-bottom: 18px; + } + .navbar-fixed-top .navbar-inner { + padding: 5px; + } + .navbar .container { + width: auto; + padding: 0; + } + .navbar .brand { + padding-left: 10px; + padding-right: 10px; + margin: 0 0 0 -5px; + } + .navbar .nav-collapse { + clear: left; + } + .navbar .nav { + float: none; + margin: 0 0 9px; + } + .navbar .nav > li { + float: none; + } + .navbar .nav > li > a { + margin-bottom: 2px; + } + .navbar .nav > .divider-vertical { + display: none; + } + .navbar .nav .nav-header { + color: #999999; + text-shadow: none; + } + .navbar .nav > li > a, .navbar .dropdown-menu a { + padding: 6px 15px; + font-weight: bold; + color: #999999; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + } + .navbar .dropdown-menu li + li a { + margin-bottom: 2px; + } + .navbar .nav > li > a:hover, .navbar .dropdown-menu a:hover { + background-color: #222222; + } + .navbar .dropdown-menu { + position: static; + top: auto; + left: auto; + float: none; + display: block; + max-width: none; + margin: 0 15px; + padding: 0; + background-color: transparent; + border: none; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + } + .navbar .dropdown-menu:before, .navbar .dropdown-menu:after { + display: none; + } + .navbar .dropdown-menu .divider { + display: none; + } + .navbar-form, .navbar-search { + float: none; + padding: 9px 15px; + margin: 9px 0; + border-top: 1px solid #222222; + border-bottom: 1px solid #222222; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + } + .navbar .nav.pull-right { + float: none; + margin-left: 0; + } + .navbar-static .navbar-inner { + padding-left: 10px; + padding-right: 10px; + } + .btn-navbar { + display: block; + } + .nav-collapse { + overflow: hidden; + height: 0; + } +} +@media (min-width: 980px) { + .nav-collapse.collapse { + height: auto !important; + } +} +@media (min-width: 1200px) { + .row { + margin-left: -30px; + *zoom: 1; + } + .row:before, .row:after { + display: table; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + margin-left: 30px; + } + .span1 { + width: 70px; + } + .span2 { + width: 170px; + } + .span3 { + width: 270px; + } + .span4 { + width: 370px; + } + .span5 { + width: 470px; + } + .span6 { + width: 570px; + } + .span7 { + width: 670px; + } + .span8 { + width: 770px; + } + .span9 { + width: 870px; + } + .span10 { + width: 970px; + } + .span11 { + width: 1070px; + } + .span12, .container { + width: 1170px; + } + .offset1 { + margin-left: 130px; + } + .offset2 { + margin-left: 230px; + } + .offset3 { + margin-left: 330px; + } + .offset4 { + margin-left: 430px; + } + .offset5 { + margin-left: 530px; + } + .offset6 { + margin-left: 630px; + } + .offset7 { + margin-left: 730px; + } + .offset8 { + margin-left: 830px; + } + .offset9 { + margin-left: 930px; + } + .offset10 { + margin-left: 1030px; + } + .offset11 { + margin-left: 1130px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, .row-fluid:after { + display: table; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid > [class*="span"] { + float: left; + margin-left: 2.564102564%; + } + .row-fluid > [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid > .span1 { + width: 5.982905983%; + } + .row-fluid > .span2 { + width: 14.529914530000001%; + } + .row-fluid > .span3 { + width: 23.076923077%; + } + .row-fluid > .span4 { + width: 31.623931624%; + } + .row-fluid > .span5 { + width: 40.170940171000005%; + } + .row-fluid > .span6 { + width: 48.717948718%; + } + .row-fluid > .span7 { + width: 57.264957265%; + } + .row-fluid > .span8 { + width: 65.81196581200001%; + } + .row-fluid > .span9 { + width: 74.358974359%; + } + .row-fluid > .span10 { + width: 82.905982906%; + } + .row-fluid > .span11 { + width: 91.45299145300001%; + } + .row-fluid > .span12 { + width: 100%; + } + input.span1, textarea.span1, .uneditable-input.span1 { + width: 60px; + } + input.span2, textarea.span2, .uneditable-input.span2 { + width: 160px; + } + input.span3, textarea.span3, .uneditable-input.span3 { + width: 260px; + } + input.span4, textarea.span4, .uneditable-input.span4 { + width: 360px; + } + input.span5, textarea.span5, .uneditable-input.span5 { + width: 460px; + } + input.span6, textarea.span6, .uneditable-input.span6 { + width: 560px; + } + input.span7, textarea.span7, .uneditable-input.span7 { + width: 660px; + } + input.span8, textarea.span8, .uneditable-input.span8 { + width: 760px; + } + input.span9, textarea.span9, .uneditable-input.span9 { + width: 860px; + } + input.span10, textarea.span10, .uneditable-input.span10 { + width: 960px; + } + input.span11, textarea.span11, .uneditable-input.span11 { + width: 1060px; + } + input.span12, textarea.span12, .uneditable-input.span12 { + width: 1160px; + } + .thumbnails { + margin-left: -30px; + } + .thumbnails > li { + margin-left: 30px; + } +} diff --git a/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css b/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css new file mode 100644 index 0000000..6229c12 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css @@ -0,0 +1,3521 @@ +/*! + * Bootstrap v2.0.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +nav, +section { + display: block; +} +audio, canvas, video { + display: inline-block; + *display: inline; + *zoom: 1; +} +audio:not([controls]) { + display: none; +} +html { + font-size: 100%; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} +a:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +a:hover, a:active { + outline: 0; +} +sub, sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} +sup { + top: -0.5em; +} +sub { + bottom: -0.25em; +} +img { + max-width: 100%; + height: auto; + border: 0; + -ms-interpolation-mode: bicubic; +} +button, +input, +select, +textarea { + margin: 0; + font-size: 100%; + vertical-align: middle; +} +button, input { + *overflow: visible; + line-height: normal; +} +button::-moz-focus-inner, input::-moz-focus-inner { + padding: 0; + border: 0; +} +button, +input[type="button"], +input[type="reset"], +input[type="submit"] { + cursor: pointer; + -webkit-appearance: button; +} +input[type="search"] { + -webkit-appearance: textfield; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +input[type="search"]::-webkit-search-decoration, input[type="search"]::-webkit-search-cancel-button { + -webkit-appearance: none; +} +textarea { + overflow: auto; + vertical-align: top; +} +.clearfix { + *zoom: 1; +} +.clearfix:before, .clearfix:after { + display: table; + content: ""; +} +.clearfix:after { + clear: both; +} +body { + margin: 0; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 18px; + color: #333333; + background-color: #ffffff; +} +a { + color: #0088cc; + text-decoration: none; +} +a:hover { + color: #005580; + text-decoration: underline; +} +.row { + margin-left: -20px; + *zoom: 1; +} +.row:before, .row:after { + display: table; + content: ""; +} +.row:after { + clear: both; +} +[class*="span"] { + float: left; + margin-left: 20px; +} +.span1 { + width: 60px; +} +.span2 { + width: 140px; +} +.span3 { + width: 220px; +} +.span4 { + width: 300px; +} +.span5 { + width: 380px; +} +.span6 { + width: 460px; +} +.span7 { + width: 540px; +} +.span8 { + width: 620px; +} +.span9 { + width: 700px; +} +.span10 { + width: 780px; +} +.span11 { + width: 860px; +} +.span12, .container { + width: 940px; +} +.offset1 { + margin-left: 100px; +} +.offset2 { + margin-left: 180px; +} +.offset3 { + margin-left: 260px; +} +.offset4 { + margin-left: 340px; +} +.offset5 { + margin-left: 420px; +} +.offset6 { + margin-left: 500px; +} +.offset7 { + margin-left: 580px; +} +.offset8 { + margin-left: 660px; +} +.offset9 { + margin-left: 740px; +} +.offset10 { + margin-left: 820px; +} +.offset11 { + margin-left: 900px; +} +.row-fluid { + width: 100%; + *zoom: 1; +} +.row-fluid:before, .row-fluid:after { + display: table; + content: ""; +} +.row-fluid:after { + clear: both; +} +.row-fluid > [class*="span"] { + float: left; + margin-left: 2.127659574%; +} +.row-fluid > [class*="span"]:first-child { + margin-left: 0; +} +.row-fluid > .span1 { + width: 6.382978723%; +} +.row-fluid > .span2 { + width: 14.89361702%; +} +.row-fluid > .span3 { + width: 23.404255317%; +} +.row-fluid > .span4 { + width: 31.914893614%; +} +.row-fluid > .span5 { + width: 40.425531911%; +} +.row-fluid > .span6 { + width: 48.93617020799999%; +} +.row-fluid > .span7 { + width: 57.446808505%; +} +.row-fluid > .span8 { + width: 65.95744680199999%; +} +.row-fluid > .span9 { + width: 74.468085099%; +} +.row-fluid > .span10 { + width: 82.97872339599999%; +} +.row-fluid > .span11 { + width: 91.489361693%; +} +.row-fluid > .span12 { + width: 99.99999998999999%; +} +.container { + width: 940px; + margin-left: auto; + margin-right: auto; + *zoom: 1; +} +.container:before, .container:after { + display: table; + content: ""; +} +.container:after { + clear: both; +} +.container-fluid { + padding-left: 20px; + padding-right: 20px; + *zoom: 1; +} +.container-fluid:before, .container-fluid:after { + display: table; + content: ""; +} +.container-fluid:after { + clear: both; +} +p { + margin: 0 0 9px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 18px; +} +p small { + font-size: 11px; + color: #999999; +} +.lead { + margin-bottom: 18px; + font-size: 20px; + font-weight: 200; + line-height: 27px; +} +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 0; + font-weight: bold; + color: #333333; + text-rendering: optimizelegibility; +} +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small { + font-weight: normal; + color: #999999; +} +h1 { + font-size: 30px; + line-height: 36px; +} +h1 small { + font-size: 18px; +} +h2 { + font-size: 24px; + line-height: 36px; +} +h2 small { + font-size: 18px; +} +h3 { + line-height: 27px; + font-size: 18px; +} +h3 small { + font-size: 14px; +} +h4, h5, h6 { + line-height: 18px; +} +h4 { + font-size: 14px; +} +h4 small { + font-size: 12px; +} +h5 { + font-size: 12px; +} +h6 { + font-size: 11px; + color: #999999; + text-transform: uppercase; +} +.page-header { + padding-bottom: 17px; + margin: 18px 0; + border-bottom: 1px solid #eeeeee; +} +.page-header h1 { + line-height: 1; +} +ul, ol { + padding: 0; + margin: 0 0 9px 25px; +} +ul ul, +ul ol, +ol ol, +ol ul { + margin-bottom: 0; +} +ul { + list-style: disc; +} +ol { + list-style: decimal; +} +li { + line-height: 18px; +} +ul.unstyled, ol.unstyled { + margin-left: 0; + list-style: none; +} +dl { + margin-bottom: 18px; +} +dt, dd { + line-height: 18px; +} +dt { + font-weight: bold; +} +dd { + margin-left: 9px; +} +hr { + margin: 18px 0; + border: 0; + border-top: 1px solid #eeeeee; + border-bottom: 1px solid #ffffff; +} +strong { + font-weight: bold; +} +em { + font-style: italic; +} +.muted { + color: #999999; +} +abbr { + font-size: 90%; + text-transform: uppercase; + border-bottom: 1px dotted #ddd; + cursor: help; +} +blockquote { + padding: 0 0 0 15px; + margin: 0 0 18px; + border-left: 5px solid #eeeeee; +} +blockquote p { + margin-bottom: 0; + font-size: 16px; + font-weight: 300; + line-height: 22.5px; +} +blockquote small { + display: block; + line-height: 18px; + color: #999999; +} +blockquote small:before { + content: '\2014 \00A0'; +} +blockquote.pull-right { + float: right; + padding-left: 0; + padding-right: 15px; + border-left: 0; + border-right: 5px solid #eeeeee; +} +blockquote.pull-right p, blockquote.pull-right small { + text-align: right; +} +q:before, +q:after, +blockquote:before, +blockquote:after { + content: ""; +} +address { + display: block; + margin-bottom: 18px; + line-height: 18px; + font-style: normal; +} +small { + font-size: 100%; +} +cite { + font-style: normal; +} +code, pre { + padding: 0 3px 2px; + font-family: Menlo, Monaco, "Courier New", monospace; + font-size: 12px; + color: #333333; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +code { + padding: 3px 4px; + color: #d14; + background-color: #f7f7f9; + border: 1px solid #e1e1e8; +} +pre { + display: block; + padding: 8.5px; + margin: 0 0 9px; + font-size: 12px; + line-height: 18px; + background-color: #f5f5f5; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.15); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + white-space: pre; + white-space: pre-wrap; + word-break: break-all; + word-wrap: break-word; +} +pre.prettyprint { + margin-bottom: 18px; +} +pre code { + padding: 0; + color: inherit; + background-color: transparent; + border: 0; +} +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} +form { + margin: 0 0 18px; +} +fieldset { + padding: 0; + margin: 0; + border: 0; +} +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 27px; + font-size: 19.5px; + line-height: 36px; + color: #333333; + border: 0; + border-bottom: 1px solid #eee; +} +legend small { + font-size: 13.5px; + color: #999999; +} +label, +input, +button, +select, +textarea { + font-size: 13px; + font-weight: normal; + line-height: 18px; +} +input, +button, +select, +textarea { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; +} +label { + display: block; + margin-bottom: 5px; + color: #333333; +} +input, +textarea, +select, +.uneditable-input { + display: inline-block; + width: 210px; + height: 18px; + padding: 4px; + margin-bottom: 9px; + font-size: 13px; + line-height: 18px; + color: #555555; + border: 1px solid #ccc; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.uneditable-textarea { + width: auto; + height: auto; +} +label input, label textarea, label select { + display: block; +} +input[type="image"], input[type="checkbox"], input[type="radio"] { + width: auto; + height: auto; + padding: 0; + margin: 3px 0; + *margin-top: 0; + /* IE7 */ + + line-height: normal; + cursor: pointer; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + border: 0 \9; + /* IE9 and down */ + +} +input[type="image"] { + border: 0; +} +input[type="file"] { + width: auto; + padding: initial; + line-height: initial; + border: initial; + background-color: #ffffff; + background-color: initial; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +input[type="button"], input[type="reset"], input[type="submit"] { + width: auto; + height: auto; +} +select, input[type="file"] { + height: 28px; + /* In IE7, the height of the select element cannot be changed by height, only font-size */ + + *margin-top: 4px; + /* For IE7, add top margin to align select with labels */ + + line-height: 28px; +} +input[type="file"] { + line-height: 18px \9; +} +select { + width: 220px; + background-color: #ffffff; +} +select[multiple], select[size] { + height: auto; +} +input[type="image"] { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +textarea { + height: auto; +} +input[type="hidden"] { + display: none; +} +.radio, .checkbox { + padding-left: 18px; +} +.radio input[type="radio"], .checkbox input[type="checkbox"] { + float: left; + margin-left: -18px; +} +.controls > .radio:first-child, .controls > .checkbox:first-child { + padding-top: 5px; +} +.radio.inline, .checkbox.inline { + display: inline-block; + padding-top: 5px; + margin-bottom: 0; + vertical-align: middle; +} +.radio.inline + .radio.inline, .checkbox.inline + .checkbox.inline { + margin-left: 10px; +} +input, textarea { + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; + -moz-transition: border linear 0.2s, box-shadow linear 0.2s; + -ms-transition: border linear 0.2s, box-shadow linear 0.2s; + -o-transition: border linear 0.2s, box-shadow linear 0.2s; + transition: border linear 0.2s, box-shadow linear 0.2s; +} +input:focus, textarea:focus { + border-color: rgba(82, 168, 236, 0.8); + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + outline: 0; + outline: thin dotted \9; + /* IE6-9 */ + +} +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus, +select:focus { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.input-mini { + width: 60px; +} +.input-small { + width: 90px; +} +.input-medium { + width: 150px; +} +.input-large { + width: 210px; +} +.input-xlarge { + width: 270px; +} +.input-xxlarge { + width: 530px; +} +input[class*="span"], +select[class*="span"], +textarea[class*="span"], +.uneditable-input { + float: none; + margin-left: 0; +} +input.span1, textarea.span1, .uneditable-input.span1 { + width: 50px; +} +input.span2, textarea.span2, .uneditable-input.span2 { + width: 130px; +} +input.span3, textarea.span3, .uneditable-input.span3 { + width: 210px; +} +input.span4, textarea.span4, .uneditable-input.span4 { + width: 290px; +} +input.span5, textarea.span5, .uneditable-input.span5 { + width: 370px; +} +input.span6, textarea.span6, .uneditable-input.span6 { + width: 450px; +} +input.span7, textarea.span7, .uneditable-input.span7 { + width: 530px; +} +input.span8, textarea.span8, .uneditable-input.span8 { + width: 610px; +} +input.span9, textarea.span9, .uneditable-input.span9 { + width: 690px; +} +input.span10, textarea.span10, .uneditable-input.span10 { + width: 770px; +} +input.span11, textarea.span11, .uneditable-input.span11 { + width: 850px; +} +input.span12, textarea.span12, .uneditable-input.span12 { + width: 930px; +} +input[disabled], +select[disabled], +textarea[disabled], +input[readonly], +select[readonly], +textarea[readonly] { + background-color: #f5f5f5; + border-color: #ddd; + cursor: not-allowed; +} +.control-group.warning > label, .control-group.warning .help-block, .control-group.warning .help-inline { + color: #c09853; +} +.control-group.warning input, .control-group.warning select, .control-group.warning textarea { + color: #c09853; + border-color: #c09853; +} +.control-group.warning input:focus, .control-group.warning select:focus, .control-group.warning textarea:focus { + border-color: #a47e3c; + -webkit-box-shadow: 0 0 6px #dbc59e; + -moz-box-shadow: 0 0 6px #dbc59e; + box-shadow: 0 0 6px #dbc59e; +} +.control-group.warning .input-prepend .add-on, .control-group.warning .input-append .add-on { + color: #c09853; + background-color: #fcf8e3; + border-color: #c09853; +} +.control-group.error > label, .control-group.error .help-block, .control-group.error .help-inline { + color: #b94a48; +} +.control-group.error input, .control-group.error select, .control-group.error textarea { + color: #b94a48; + border-color: #b94a48; +} +.control-group.error input:focus, .control-group.error select:focus, .control-group.error textarea:focus { + border-color: #953b39; + -webkit-box-shadow: 0 0 6px #d59392; + -moz-box-shadow: 0 0 6px #d59392; + box-shadow: 0 0 6px #d59392; +} +.control-group.error .input-prepend .add-on, .control-group.error .input-append .add-on { + color: #b94a48; + background-color: #f2dede; + border-color: #b94a48; +} +.control-group.success > label, .control-group.success .help-block, .control-group.success .help-inline { + color: #468847; +} +.control-group.success input, .control-group.success select, .control-group.success textarea { + color: #468847; + border-color: #468847; +} +.control-group.success input:focus, .control-group.success select:focus, .control-group.success textarea:focus { + border-color: #356635; + -webkit-box-shadow: 0 0 6px #7aba7b; + -moz-box-shadow: 0 0 6px #7aba7b; + box-shadow: 0 0 6px #7aba7b; +} +.control-group.success .input-prepend .add-on, .control-group.success .input-append .add-on { + color: #468847; + background-color: #dff0d8; + border-color: #468847; +} +input:focus:required:invalid, textarea:focus:required:invalid, select:focus:required:invalid { + color: #b94a48; + border-color: #ee5f5b; +} +input:focus:required:invalid:focus, textarea:focus:required:invalid:focus, select:focus:required:invalid:focus { + border-color: #e9322d; + -webkit-box-shadow: 0 0 6px #f8b9b7; + -moz-box-shadow: 0 0 6px #f8b9b7; + box-shadow: 0 0 6px #f8b9b7; +} +.form-actions { + padding: 17px 20px 18px; + margin-top: 18px; + margin-bottom: 18px; + background-color: #f5f5f5; + border-top: 1px solid #ddd; +} +.uneditable-input { + display: block; + background-color: #ffffff; + border-color: #eee; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + cursor: not-allowed; +} +:-moz-placeholder { + color: #999999; +} +::-webkit-input-placeholder { + color: #999999; +} +.help-block { + display: block; + margin-top: 5px; + margin-bottom: 0; + color: #999999; +} +.help-inline { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; + margin-bottom: 9px; + vertical-align: middle; + padding-left: 5px; +} +.input-prepend, .input-append { + margin-bottom: 5px; + *zoom: 1; +} +.input-prepend:before, +.input-append:before, +.input-prepend:after, +.input-append:after { + display: table; + content: ""; +} +.input-prepend:after, .input-append:after { + clear: both; +} +.input-prepend input, +.input-append input, +.input-prepend .uneditable-input, +.input-append .uneditable-input { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.input-prepend input:focus, +.input-append input:focus, +.input-prepend .uneditable-input:focus, +.input-append .uneditable-input:focus { + position: relative; + z-index: 2; +} +.input-prepend .uneditable-input, .input-append .uneditable-input { + border-left-color: #ccc; +} +.input-prepend .add-on, .input-append .add-on { + float: left; + display: block; + width: auto; + min-width: 16px; + height: 18px; + margin-right: -1px; + padding: 4px 5px; + font-weight: normal; + line-height: 18px; + color: #999999; + text-align: center; + text-shadow: 0 1px 0 #ffffff; + background-color: #f5f5f5; + border: 1px solid #ccc; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.input-prepend .active, .input-append .active { + background-color: #a9dba9; + border-color: #46a546; +} +.input-prepend .add-on { + *margin-top: 1px; + /* IE6-7 */ + +} +.input-append input, .input-append .uneditable-input { + float: left; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.input-append .uneditable-input { + border-left-color: #eee; + border-right-color: #ccc; +} +.input-append .add-on { + margin-right: 0; + margin-left: -1px; + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.input-append input:first-child { + *margin-left: -160px; +} +.input-append input:first-child + .add-on { + *margin-left: -21px; +} +.search-query { + padding-left: 14px; + padding-right: 14px; + margin-bottom: 0; + -webkit-border-radius: 14px; + -moz-border-radius: 14px; + border-radius: 14px; +} +.form-search input, +.form-inline input, +.form-horizontal input, +.form-search textarea, +.form-inline textarea, +.form-horizontal textarea, +.form-search select, +.form-inline select, +.form-horizontal select, +.form-search .help-inline, +.form-inline .help-inline, +.form-horizontal .help-inline, +.form-search .uneditable-input, +.form-inline .uneditable-input, +.form-horizontal .uneditable-input { + display: inline-block; + margin-bottom: 0; +} +.form-search .hide, .form-inline .hide, .form-horizontal .hide { + display: none; +} +.form-search label, +.form-inline label, +.form-search .input-append, +.form-inline .input-append, +.form-search .input-prepend, +.form-inline .input-prepend { + display: inline-block; +} +.form-search .input-append .add-on, +.form-inline .input-prepend .add-on, +.form-search .input-append .add-on, +.form-inline .input-prepend .add-on { + vertical-align: middle; +} +.form-search .radio, +.form-inline .radio, +.form-search .checkbox, +.form-inline .checkbox { + margin-bottom: 0; + vertical-align: middle; +} +.control-group { + margin-bottom: 9px; +} +legend + .control-group { + margin-top: 18px; + -webkit-margin-top-collapse: separate; +} +.form-horizontal .control-group { + margin-bottom: 18px; + *zoom: 1; +} +.form-horizontal .control-group:before, .form-horizontal .control-group:after { + display: table; + content: ""; +} +.form-horizontal .control-group:after { + clear: both; +} +.form-horizontal .control-label { + float: left; + width: 140px; + padding-top: 5px; + text-align: right; +} +.form-horizontal .controls { + margin-left: 160px; +} +.form-horizontal .form-actions { + padding-left: 160px; +} +table { + max-width: 100%; + border-collapse: collapse; + border-spacing: 0; +} +.table { + width: 100%; + margin-bottom: 18px; +} +.table th, .table td { + padding: 8px; + line-height: 18px; + text-align: left; + vertical-align: top; + border-top: 1px solid #ddd; +} +.table th { + font-weight: bold; +} +.table thead th { + vertical-align: bottom; +} +.table thead:first-child tr th, .table thead:first-child tr td { + border-top: 0; +} +.table tbody + tbody { + border-top: 2px solid #ddd; +} +.table-condensed th, .table-condensed td { + padding: 4px 5px; +} +.table-bordered { + border: 1px solid #ddd; + border-collapse: separate; + *border-collapse: collapsed; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.table-bordered th + th, +.table-bordered td + td, +.table-bordered th + td, +.table-bordered td + th { + border-left: 1px solid #ddd; +} +.table-bordered thead:first-child tr:first-child th, .table-bordered tbody:first-child tr:first-child th, .table-bordered tbody:first-child tr:first-child td { + border-top: 0; +} +.table-bordered thead:first-child tr:first-child th:first-child, .table-bordered tbody:first-child tr:first-child td:first-child { + -webkit-border-radius: 4px 0 0 0; + -moz-border-radius: 4px 0 0 0; + border-radius: 4px 0 0 0; +} +.table-bordered thead:first-child tr:first-child th:last-child, .table-bordered tbody:first-child tr:first-child td:last-child { + -webkit-border-radius: 0 4px 0 0; + -moz-border-radius: 0 4px 0 0; + border-radius: 0 4px 0 0; +} +.table-bordered thead:last-child tr:last-child th:first-child, .table-bordered tbody:last-child tr:last-child td:first-child { + -webkit-border-radius: 0 0 0 4px; + -moz-border-radius: 0 0 0 4px; + border-radius: 0 0 0 4px; +} +.table-bordered thead:last-child tr:last-child th:last-child, .table-bordered tbody:last-child tr:last-child td:last-child { + -webkit-border-radius: 0 0 4px 0; + -moz-border-radius: 0 0 4px 0; + border-radius: 0 0 4px 0; +} +.table-striped tbody tr:nth-child(odd) td, .table-striped tbody tr:nth-child(odd) th { + background-color: #f9f9f9; +} +.table tbody tr:hover td, .table tbody tr:hover th { + background-color: #f5f5f5; +} +table .span1 { + float: none; + width: 44px; + margin-left: 0; +} +table .span2 { + float: none; + width: 124px; + margin-left: 0; +} +table .span3 { + float: none; + width: 204px; + margin-left: 0; +} +table .span4 { + float: none; + width: 284px; + margin-left: 0; +} +table .span5 { + float: none; + width: 364px; + margin-left: 0; +} +table .span6 { + float: none; + width: 444px; + margin-left: 0; +} +table .span7 { + float: none; + width: 524px; + margin-left: 0; +} +table .span8 { + float: none; + width: 604px; + margin-left: 0; +} +table .span9 { + float: none; + width: 684px; + margin-left: 0; +} +table .span10 { + float: none; + width: 764px; + margin-left: 0; +} +table .span11 { + float: none; + width: 844px; + margin-left: 0; +} +table .span12 { + float: none; + width: 924px; + margin-left: 0; +} +[class^="icon-"], [class*=" icon-"] { + display: inline-block; + width: 14px; + height: 14px; + line-height: 14px; + vertical-align: text-top; + background-image: url("../img/glyphicons-halflings.png"); + background-position: 14px 14px; + background-repeat: no-repeat; + *margin-right: .3em; +} +[class^="icon-"]:last-child, [class*=" icon-"]:last-child { + *margin-left: 0; +} +.icon-white { + background-image: url("../img/glyphicons-halflings-white.png"); +} +.icon-glass { + background-position: 0 0; +} +.icon-music { + background-position: -24px 0; +} +.icon-search { + background-position: -48px 0; +} +.icon-envelope { + background-position: -72px 0; +} +.icon-heart { + background-position: -96px 0; +} +.icon-star { + background-position: -120px 0; +} +.icon-star-empty { + background-position: -144px 0; +} +.icon-user { + background-position: -168px 0; +} +.icon-film { + background-position: -192px 0; +} +.icon-th-large { + background-position: -216px 0; +} +.icon-th { + background-position: -240px 0; +} +.icon-th-list { + background-position: -264px 0; +} +.icon-ok { + background-position: -288px 0; +} +.icon-remove { + background-position: -312px 0; +} +.icon-zoom-in { + background-position: -336px 0; +} +.icon-zoom-out { + background-position: -360px 0; +} +.icon-off { + background-position: -384px 0; +} +.icon-signal { + background-position: -408px 0; +} +.icon-cog { + background-position: -432px 0; +} +.icon-trash { + background-position: -456px 0; +} +.icon-home { + background-position: 0 -24px; +} +.icon-file { + background-position: -24px -24px; +} +.icon-time { + background-position: -48px -24px; +} +.icon-road { + background-position: -72px -24px; +} +.icon-download-alt { + background-position: -96px -24px; +} +.icon-download { + background-position: -120px -24px; +} +.icon-upload { + background-position: -144px -24px; +} +.icon-inbox { + background-position: -168px -24px; +} +.icon-play-circle { + background-position: -192px -24px; +} +.icon-repeat { + background-position: -216px -24px; +} +.icon-refresh { + background-position: -240px -24px; +} +.icon-list-alt { + background-position: -264px -24px; +} +.icon-lock { + background-position: -287px -24px; +} +.icon-flag { + background-position: -312px -24px; +} +.icon-headphones { + background-position: -336px -24px; +} +.icon-volume-off { + background-position: -360px -24px; +} +.icon-volume-down { + background-position: -384px -24px; +} +.icon-volume-up { + background-position: -408px -24px; +} +.icon-qrcode { + background-position: -432px -24px; +} +.icon-barcode { + background-position: -456px -24px; +} +.icon-tag { + background-position: 0 -48px; +} +.icon-tags { + background-position: -25px -48px; +} +.icon-book { + background-position: -48px -48px; +} +.icon-bookmark { + background-position: -72px -48px; +} +.icon-print { + background-position: -96px -48px; +} +.icon-camera { + background-position: -120px -48px; +} +.icon-font { + background-position: -144px -48px; +} +.icon-bold { + background-position: -167px -48px; +} +.icon-italic { + background-position: -192px -48px; +} +.icon-text-height { + background-position: -216px -48px; +} +.icon-text-width { + background-position: -240px -48px; +} +.icon-align-left { + background-position: -264px -48px; +} +.icon-align-center { + background-position: -288px -48px; +} +.icon-align-right { + background-position: -312px -48px; +} +.icon-align-justify { + background-position: -336px -48px; +} +.icon-list { + background-position: -360px -48px; +} +.icon-indent-left { + background-position: -384px -48px; +} +.icon-indent-right { + background-position: -408px -48px; +} +.icon-facetime-video { + background-position: -432px -48px; +} +.icon-picture { + background-position: -456px -48px; +} +.icon-pencil { + background-position: 0 -72px; +} +.icon-map-marker { + background-position: -24px -72px; +} +.icon-adjust { + background-position: -48px -72px; +} +.icon-tint { + background-position: -72px -72px; +} +.icon-edit { + background-position: -96px -72px; +} +.icon-share { + background-position: -120px -72px; +} +.icon-check { + background-position: -144px -72px; +} +.icon-move { + background-position: -168px -72px; +} +.icon-step-backward { + background-position: -192px -72px; +} +.icon-fast-backward { + background-position: -216px -72px; +} +.icon-backward { + background-position: -240px -72px; +} +.icon-play { + background-position: -264px -72px; +} +.icon-pause { + background-position: -288px -72px; +} +.icon-stop { + background-position: -312px -72px; +} +.icon-forward { + background-position: -336px -72px; +} +.icon-fast-forward { + background-position: -360px -72px; +} +.icon-step-forward { + background-position: -384px -72px; +} +.icon-eject { + background-position: -408px -72px; +} +.icon-chevron-left { + background-position: -432px -72px; +} +.icon-chevron-right { + background-position: -456px -72px; +} +.icon-plus-sign { + background-position: 0 -96px; +} +.icon-minus-sign { + background-position: -24px -96px; +} +.icon-remove-sign { + background-position: -48px -96px; +} +.icon-ok-sign { + background-position: -72px -96px; +} +.icon-question-sign { + background-position: -96px -96px; +} +.icon-info-sign { + background-position: -120px -96px; +} +.icon-screenshot { + background-position: -144px -96px; +} +.icon-remove-circle { + background-position: -168px -96px; +} +.icon-ok-circle { + background-position: -192px -96px; +} +.icon-ban-circle { + background-position: -216px -96px; +} +.icon-arrow-left { + background-position: -240px -96px; +} +.icon-arrow-right { + background-position: -264px -96px; +} +.icon-arrow-up { + background-position: -289px -96px; +} +.icon-arrow-down { + background-position: -312px -96px; +} +.icon-share-alt { + background-position: -336px -96px; +} +.icon-resize-full { + background-position: -360px -96px; +} +.icon-resize-small { + background-position: -384px -96px; +} +.icon-plus { + background-position: -408px -96px; +} +.icon-minus { + background-position: -433px -96px; +} +.icon-asterisk { + background-position: -456px -96px; +} +.icon-exclamation-sign { + background-position: 0 -120px; +} +.icon-gift { + background-position: -24px -120px; +} +.icon-leaf { + background-position: -48px -120px; +} +.icon-fire { + background-position: -72px -120px; +} +.icon-eye-open { + background-position: -96px -120px; +} +.icon-eye-close { + background-position: -120px -120px; +} +.icon-warning-sign { + background-position: -144px -120px; +} +.icon-plane { + background-position: -168px -120px; +} +.icon-calendar { + background-position: -192px -120px; +} +.icon-random { + background-position: -216px -120px; +} +.icon-comment { + background-position: -240px -120px; +} +.icon-magnet { + background-position: -264px -120px; +} +.icon-chevron-up { + background-position: -288px -120px; +} +.icon-chevron-down { + background-position: -313px -119px; +} +.icon-retweet { + background-position: -336px -120px; +} +.icon-shopping-cart { + background-position: -360px -120px; +} +.icon-folder-close { + background-position: -384px -120px; +} +.icon-folder-open { + background-position: -408px -120px; +} +.icon-resize-vertical { + background-position: -432px -119px; +} +.icon-resize-horizontal { + background-position: -456px -118px; +} +.dropdown { + position: relative; +} +.dropdown-toggle { + *margin-bottom: -3px; +} +.dropdown-toggle:active, .open .dropdown-toggle { + outline: 0; +} +.caret { + display: inline-block; + width: 0; + height: 0; + text-indent: -99999px; + *text-indent: 0; + vertical-align: top; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 4px solid #000000; + opacity: 0.3; + filter: alpha(opacity=30); + content: "\2193"; +} +.dropdown .caret { + margin-top: 8px; + margin-left: 2px; +} +.dropdown:hover .caret, .open.dropdown .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + float: left; + display: none; + min-width: 160px; + _width: 160px; + padding: 4px 0; + margin: 0; + list-style: none; + background-color: #ffffff; + border-color: #ccc; + border-color: rgba(0, 0, 0, 0.2); + border-style: solid; + border-width: 1px; + -webkit-border-radius: 0 0 5px 5px; + -moz-border-radius: 0 0 5px 5px; + border-radius: 0 0 5px 5px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; + *border-right-width: 2px; + *border-bottom-width: 2px; +} +.dropdown-menu.bottom-up { + top: auto; + bottom: 100%; + margin-bottom: 2px; +} +.dropdown-menu .divider { + height: 1px; + margin: 5px 1px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #ffffff; + *width: 100%; + *margin: -5px 0 5px; +} +.dropdown-menu a { + display: block; + padding: 3px 15px; + clear: both; + font-weight: normal; + line-height: 18px; + color: #555555; + white-space: nowrap; +} +.dropdown-menu li > a:hover, .dropdown-menu .active > a, .dropdown-menu .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #0088cc; +} +.dropdown.open { + *z-index: 1000; +} +.dropdown.open .dropdown-toggle { + color: #ffffff; + background: #ccc; + background: rgba(0, 0, 0, 0.3); +} +.dropdown.open .dropdown-menu { + display: block; +} +.typeahead { + margin-top: 2px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #f5f5f5; + border: 1px solid #eee; + border: 1px solid rgba(0, 0, 0, 0.05); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 0, 0, 0.15); +} +.fade { + -webkit-transition: opacity 0.15s linear; + -moz-transition: opacity 0.15s linear; + -ms-transition: opacity 0.15s linear; + -o-transition: opacity 0.15s linear; + transition: opacity 0.15s linear; + opacity: 0; +} +.fade.in { + opacity: 1; +} +.collapse { + -webkit-transition: height 0.35s ease; + -moz-transition: height 0.35s ease; + -ms-transition: height 0.35s ease; + -o-transition: height 0.35s ease; + transition: height 0.35s ease; + position: relative; + overflow: hidden; + height: 0; +} +.collapse.in { + height: auto; +} +.close { + float: right; + font-size: 20px; + font-weight: bold; + line-height: 18px; + color: #000000; + text-shadow: 0 1px 0 #ffffff; + opacity: 0.2; + filter: alpha(opacity=20); +} +.close:hover { + color: #000000; + text-decoration: none; + opacity: 0.4; + filter: alpha(opacity=40); + cursor: pointer; +} +.btn { + display: inline-block; + padding: 4px 10px 4px; + margin-bottom: 0; + font-size: 13px; + line-height: 18px; + color: #333333; + text-align: center; + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); + vertical-align: middle; + background-color: #f5f5f5; + background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); + background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); + background-image: linear-gradient(top, #ffffff, #e6e6e6); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0); + border-color: #e6e6e6 #e6e6e6 #bfbfbf; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + border: 1px solid #ccc; + border-bottom-color: #bbb; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + cursor: pointer; + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + *margin-left: .3em; +} +.btn:hover, +.btn:active, +.btn.active, +.btn.disabled, +.btn[disabled] { + background-color: #e6e6e6; +} +.btn:active, .btn.active { + background-color: #cccccc \9; +} +.btn:first-child { + *margin-left: 0; +} +.btn:hover { + color: #333333; + text-decoration: none; + background-color: #e6e6e6; + background-position: 0 -15px; + -webkit-transition: background-position 0.1s linear; + -moz-transition: background-position 0.1s linear; + -ms-transition: background-position 0.1s linear; + -o-transition: background-position 0.1s linear; + transition: background-position 0.1s linear; +} +.btn:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.btn.active, .btn:active { + background-image: none; + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + background-color: #e6e6e6; + background-color: #d9d9d9 \9; + outline: 0; +} +.btn.disabled, .btn[disabled] { + cursor: default; + background-image: none; + background-color: #e6e6e6; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +.btn-large { + padding: 9px 14px; + font-size: 15px; + line-height: normal; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.btn-large [class^="icon-"] { + margin-top: 1px; +} +.btn-small { + padding: 5px 9px; + font-size: 11px; + line-height: 16px; +} +.btn-small [class^="icon-"] { + margin-top: -1px; +} +.btn-mini { + padding: 2px 6px; + font-size: 11px; + line-height: 14px; +} +.btn-primary, +.btn-primary:hover, +.btn-warning, +.btn-warning:hover, +.btn-danger, +.btn-danger:hover, +.btn-success, +.btn-success:hover, +.btn-info, +.btn-info:hover, +.btn-inverse, +.btn-inverse:hover { + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + color: #ffffff; +} +.btn-primary.active, +.btn-warning.active, +.btn-danger.active, +.btn-success.active, +.btn-info.active, +.btn-dark.active { + color: rgba(255, 255, 255, 0.75); +} +.btn-primary { + background-color: #006dcc; + background-image: -moz-linear-gradient(top, #0088cc, #0044cc); + background-image: -ms-linear-gradient(top, #0088cc, #0044cc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); + background-image: -o-linear-gradient(top, #0088cc, #0044cc); + background-image: linear-gradient(top, #0088cc, #0044cc); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); + border-color: #0044cc #0044cc #002a80; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-primary:hover, +.btn-primary:active, +.btn-primary.active, +.btn-primary.disabled, +.btn-primary[disabled] { + background-color: #0044cc; +} +.btn-primary:active, .btn-primary.active { + background-color: #003399 \9; +} +.btn-warning { + background-color: #faa732; + background-image: -moz-linear-gradient(top, #fbb450, #f89406); + background-image: -ms-linear-gradient(top, #fbb450, #f89406); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); + background-image: -webkit-linear-gradient(top, #fbb450, #f89406); + background-image: -o-linear-gradient(top, #fbb450, #f89406); + background-image: linear-gradient(top, #fbb450, #f89406); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0); + border-color: #f89406 #f89406 #ad6704; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-warning:hover, +.btn-warning:active, +.btn-warning.active, +.btn-warning.disabled, +.btn-warning[disabled] { + background-color: #f89406; +} +.btn-warning:active, .btn-warning.active { + background-color: #c67605 \9; +} +.btn-danger { + background-color: #da4f49; + background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -ms-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -o-linear-gradient(top, #ee5f5b, #bd362f); + background-image: linear-gradient(top, #ee5f5b, #bd362f); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0); + border-color: #bd362f #bd362f #802420; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-danger:hover, +.btn-danger:active, +.btn-danger.active, +.btn-danger.disabled, +.btn-danger[disabled] { + background-color: #bd362f; +} +.btn-danger:active, .btn-danger.active { + background-color: #942a25 \9; +} +.btn-success { + background-color: #5bb75b; + background-image: -moz-linear-gradient(top, #62c462, #51a351); + background-image: -ms-linear-gradient(top, #62c462, #51a351); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351)); + background-image: -webkit-linear-gradient(top, #62c462, #51a351); + background-image: -o-linear-gradient(top, #62c462, #51a351); + background-image: linear-gradient(top, #62c462, #51a351); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0); + border-color: #51a351 #51a351 #387038; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-success:hover, +.btn-success:active, +.btn-success.active, +.btn-success.disabled, +.btn-success[disabled] { + background-color: #51a351; +} +.btn-success:active, .btn-success.active { + background-color: #408140 \9; +} +.btn-info { + background-color: #49afcd; + background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -ms-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4)); + background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -o-linear-gradient(top, #5bc0de, #2f96b4); + background-image: linear-gradient(top, #5bc0de, #2f96b4); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0); + border-color: #2f96b4 #2f96b4 #1f6377; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-info:hover, +.btn-info:active, +.btn-info.active, +.btn-info.disabled, +.btn-info[disabled] { + background-color: #2f96b4; +} +.btn-info:active, .btn-info.active { + background-color: #24748c \9; +} +.btn-inverse { + background-color: #393939; + background-image: -moz-linear-gradient(top, #454545, #262626); + background-image: -ms-linear-gradient(top, #454545, #262626); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#454545), to(#262626)); + background-image: -webkit-linear-gradient(top, #454545, #262626); + background-image: -o-linear-gradient(top, #454545, #262626); + background-image: linear-gradient(top, #454545, #262626); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#454545', endColorstr='#262626', GradientType=0); + border-color: #262626 #262626 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-inverse:hover, +.btn-inverse:active, +.btn-inverse.active, +.btn-inverse.disabled, +.btn-inverse[disabled] { + background-color: #262626; +} +.btn-inverse:active, .btn-inverse.active { + background-color: #0c0c0c \9; +} +button.btn, input[type="submit"].btn { + *padding-top: 2px; + *padding-bottom: 2px; +} +button.btn::-moz-focus-inner, input[type="submit"].btn::-moz-focus-inner { + padding: 0; + border: 0; +} +button.btn.large, input[type="submit"].btn.large { + *padding-top: 7px; + *padding-bottom: 7px; +} +button.btn.small, input[type="submit"].btn.small { + *padding-top: 3px; + *padding-bottom: 3px; +} +.btn-group { + position: relative; + *zoom: 1; + *margin-left: .3em; +} +.btn-group:before, .btn-group:after { + display: table; + content: ""; +} +.btn-group:after { + clear: both; +} +.btn-group:first-child { + *margin-left: 0; +} +.btn-group + .btn-group { + margin-left: 5px; +} +.btn-toolbar { + margin-top: 9px; + margin-bottom: 9px; +} +.btn-toolbar .btn-group { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; +} +.btn-group .btn { + position: relative; + float: left; + margin-left: -1px; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.btn-group .btn:first-child { + margin-left: 0; + -webkit-border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; + border-top-left-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + border-bottom-left-radius: 4px; +} +.btn-group .btn:last-child, .btn-group .dropdown-toggle { + -webkit-border-top-right-radius: 4px; + -moz-border-radius-topright: 4px; + border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -moz-border-radius-bottomright: 4px; + border-bottom-right-radius: 4px; +} +.btn-group .btn.large:first-child { + margin-left: 0; + -webkit-border-top-left-radius: 6px; + -moz-border-radius-topleft: 6px; + border-top-left-radius: 6px; + -webkit-border-bottom-left-radius: 6px; + -moz-border-radius-bottomleft: 6px; + border-bottom-left-radius: 6px; +} +.btn-group .btn.large:last-child, .btn-group .large.dropdown-toggle { + -webkit-border-top-right-radius: 6px; + -moz-border-radius-topright: 6px; + border-top-right-radius: 6px; + -webkit-border-bottom-right-radius: 6px; + -moz-border-radius-bottomright: 6px; + border-bottom-right-radius: 6px; +} +.btn-group .btn:hover, +.btn-group .btn:focus, +.btn-group .btn:active, +.btn-group .btn.active { + z-index: 2; +} +.btn-group .dropdown-toggle:active, .btn-group.open .dropdown-toggle { + outline: 0; +} +.btn-group .dropdown-toggle { + padding-left: 8px; + padding-right: 8px; + -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + *padding-top: 5px; + *padding-bottom: 5px; +} +.btn-group.open { + *z-index: 1000; +} +.btn-group.open .dropdown-menu { + display: block; + margin-top: 1px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.btn-group.open .dropdown-toggle { + background-image: none; + -webkit-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); +} +.btn .caret { + margin-top: 7px; + margin-left: 0; +} +.btn:hover .caret, .open.btn-group .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.btn-primary .caret, +.btn-danger .caret, +.btn-info .caret, +.btn-success .caret, +.btn-inverse .caret { + border-top-color: #ffffff; + opacity: 0.75; + filter: alpha(opacity=75); +} +.btn-small .caret { + margin-top: 4px; +} +.alert { + padding: 8px 35px 8px 14px; + margin-bottom: 18px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + background-color: #fcf8e3; + border: 1px solid #fbeed5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.alert, .alert-heading { + color: #c09853; +} +.alert .close { + position: relative; + top: -2px; + right: -21px; + line-height: 18px; +} +.alert-success { + background-color: #dff0d8; + border-color: #d6e9c6; +} +.alert-success, .alert-success .alert-heading { + color: #468847; +} +.alert-danger, .alert-error { + background-color: #f2dede; + border-color: #eed3d7; +} +.alert-danger, +.alert-error, +.alert-danger .alert-heading, +.alert-error .alert-heading { + color: #b94a48; +} +.alert-info { + background-color: #d9edf7; + border-color: #bce8f1; +} +.alert-info, .alert-info .alert-heading { + color: #3a87ad; +} +.alert-block { + padding-top: 14px; + padding-bottom: 14px; +} +.alert-block > p, .alert-block > ul { + margin-bottom: 0; +} +.alert-block p + p { + margin-top: 5px; +} +.nav { + margin-left: 0; + margin-bottom: 18px; + list-style: none; +} +.nav > li > a { + display: block; +} +.nav > li > a:hover { + text-decoration: none; + background-color: #eeeeee; +} +.nav .nav-header { + display: block; + padding: 3px 15px; + font-size: 11px; + font-weight: bold; + line-height: 18px; + color: #999999; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + text-transform: uppercase; +} +.nav li + .nav-header { + margin-top: 9px; +} +.nav-list { + padding-left: 14px; + padding-right: 14px; + margin-bottom: 0; +} +.nav-list > li > a, .nav-list .nav-header { + margin-left: -15px; + margin-right: -15px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); +} +.nav-list > li > a { + padding: 3px 15px; +} +.nav-list .active > a, .nav-list .active > a:hover { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); + background-color: #0088cc; +} +.nav-list [class^="icon-"] { + margin-right: 2px; +} +.nav-tabs, .nav-pills { + *zoom: 1; +} +.nav-tabs:before, +.nav-pills:before, +.nav-tabs:after, +.nav-pills:after { + display: table; + content: ""; +} +.nav-tabs:after, .nav-pills:after { + clear: both; +} +.nav-tabs > li, .nav-pills > li { + float: left; +} +.nav-tabs > li > a, .nav-pills > li > a { + padding-right: 12px; + padding-left: 12px; + margin-right: 2px; + line-height: 14px; +} +.nav-tabs { + border-bottom: 1px solid #ddd; +} +.nav-tabs > li { + margin-bottom: -1px; +} +.nav-tabs > li > a { + padding-top: 9px; + padding-bottom: 9px; + border: 1px solid transparent; + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} +.nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #dddddd; +} +.nav-tabs > .active > a, .nav-tabs > .active > a:hover { + color: #555555; + background-color: #ffffff; + border: 1px solid #ddd; + border-bottom-color: transparent; + cursor: default; +} +.nav-pills > li > a { + padding-top: 8px; + padding-bottom: 8px; + margin-top: 2px; + margin-bottom: 2px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.nav-pills .active > a, .nav-pills .active > a:hover { + color: #ffffff; + background-color: #0088cc; +} +.nav-stacked > li { + float: none; +} +.nav-stacked > li > a { + margin-right: 0; +} +.nav-tabs.nav-stacked { + border-bottom: 0; +} +.nav-tabs.nav-stacked > li > a { + border: 1px solid #ddd; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.nav-tabs.nav-stacked > li:first-child > a { + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} +.nav-tabs.nav-stacked > li:last-child > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} +.nav-tabs.nav-stacked > li > a:hover { + border-color: #ddd; + z-index: 2; +} +.nav-pills.nav-stacked > li > a { + margin-bottom: 3px; +} +.nav-pills.nav-stacked > li:last-child > a { + margin-bottom: 1px; +} +.nav-tabs .dropdown-menu, .nav-pills .dropdown-menu { + margin-top: 1px; + border-width: 1px; +} +.nav-pills .dropdown-menu { + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.nav-tabs .dropdown-toggle .caret, .nav-pills .dropdown-toggle .caret { + border-top-color: #0088cc; + margin-top: 6px; +} +.nav-tabs .dropdown-toggle:hover .caret, .nav-pills .dropdown-toggle:hover .caret { + border-top-color: #005580; +} +.nav-tabs .active .dropdown-toggle .caret, .nav-pills .active .dropdown-toggle .caret { + border-top-color: #333333; +} +.nav > .dropdown.active > a:hover { + color: #000000; + cursor: pointer; +} +.nav-tabs .open .dropdown-toggle, .nav-pills .open .dropdown-toggle, .nav > .open.active > a:hover { + color: #ffffff; + background-color: #999999; + border-color: #999999; +} +.nav .open .caret, .nav .open.active .caret, .nav .open a:hover .caret { + border-top-color: #ffffff; + opacity: 1; + filter: alpha(opacity=100); +} +.tabs-stacked .open > a:hover { + border-color: #999999; +} +.tabbable { + *zoom: 1; +} +.tabbable:before, .tabbable:after { + display: table; + content: ""; +} +.tabbable:after { + clear: both; +} +.tab-content { + overflow: hidden; +} +.tabs-below .nav-tabs, .tabs-right .nav-tabs, .tabs-left .nav-tabs { + border-bottom: 0; +} +.tab-content > .tab-pane, .pill-content > .pill-pane { + display: none; +} +.tab-content > .active, .pill-content > .active { + display: block; +} +.tabs-below .nav-tabs { + border-top: 1px solid #ddd; +} +.tabs-below .nav-tabs > li { + margin-top: -1px; + margin-bottom: 0; +} +.tabs-below .nav-tabs > li > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} +.tabs-below .nav-tabs > li > a:hover { + border-bottom-color: transparent; + border-top-color: #ddd; +} +.tabs-below .nav-tabs .active > a, .tabs-below .nav-tabs .active > a:hover { + border-color: transparent #ddd #ddd #ddd; +} +.tabs-left .nav-tabs > li, .tabs-right .nav-tabs > li { + float: none; +} +.tabs-left .nav-tabs > li > a, .tabs-right .nav-tabs > li > a { + min-width: 74px; + margin-right: 0; + margin-bottom: 3px; +} +.tabs-left .nav-tabs { + float: left; + margin-right: 19px; + border-right: 1px solid #ddd; +} +.tabs-left .nav-tabs > li > a { + margin-right: -1px; + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} +.tabs-left .nav-tabs > li > a:hover { + border-color: #eeeeee #dddddd #eeeeee #eeeeee; +} +.tabs-left .nav-tabs .active > a, .tabs-left .nav-tabs .active > a:hover { + border-color: #ddd transparent #ddd #ddd; + *border-right-color: #ffffff; +} +.tabs-right .nav-tabs { + float: right; + margin-left: 19px; + border-left: 1px solid #ddd; +} +.tabs-right .nav-tabs > li > a { + margin-left: -1px; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} +.tabs-right .nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #eeeeee #dddddd; +} +.tabs-right .nav-tabs .active > a, .tabs-right .nav-tabs .active > a:hover { + border-color: #ddd #ddd #ddd transparent; + *border-left-color: #ffffff; +} +.navbar { + overflow: visible; + margin-bottom: 18px; +} +.navbar-inner { + padding-left: 20px; + padding-right: 20px; + background-color: #2c2c2c; + background-image: -moz-linear-gradient(top, #333333, #222222); + background-image: -ms-linear-gradient(top, #333333, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); + background-image: -webkit-linear-gradient(top, #333333, #222222); + background-image: -o-linear-gradient(top, #333333, #222222); + background-image: linear-gradient(top, #333333, #222222); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); +} +.btn-navbar { + display: none; + float: right; + padding: 7px 10px; + margin-left: 5px; + margin-right: 5px; + background-color: #2c2c2c; + background-image: -moz-linear-gradient(top, #333333, #222222); + background-image: -ms-linear-gradient(top, #333333, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); + background-image: -webkit-linear-gradient(top, #333333, #222222); + background-image: -o-linear-gradient(top, #333333, #222222); + background-image: linear-gradient(top, #333333, #222222); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); + border-color: #222222 #222222 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); +} +.btn-navbar:hover, +.btn-navbar:active, +.btn-navbar.active, +.btn-navbar.disabled, +.btn-navbar[disabled] { + background-color: #222222; +} +.btn-navbar:active, .btn-navbar.active { + background-color: #080808 \9; +} +.btn-navbar .icon-bar { + display: block; + width: 18px; + height: 2px; + background-color: #f5f5f5; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; + -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); +} +.btn-navbar .icon-bar + .icon-bar { + margin-top: 3px; +} +.nav-collapse.collapse { + height: auto; +} +.navbar .brand:hover { + text-decoration: none; +} +.navbar .brand { + float: left; + display: block; + padding: 8px 20px 12px; + margin-left: -20px; + font-size: 20px; + font-weight: 200; + line-height: 1; + color: #ffffff; +} +.navbar .navbar-text { + margin-bottom: 0; + line-height: 40px; + color: #999999; +} +.navbar .navbar-text a:hover { + color: #ffffff; + background-color: transparent; +} +.navbar .btn, .navbar .btn-group { + margin-top: 5px; +} +.navbar .btn-group .btn { + margin-top: 0; +} +.navbar-form { + margin-bottom: 0; + *zoom: 1; +} +.navbar-form:before, .navbar-form:after { + display: table; + content: ""; +} +.navbar-form:after { + clear: both; +} +.navbar-form input, .navbar-form select { + display: inline-block; + margin-top: 5px; + margin-bottom: 0; +} +.navbar-form .radio, .navbar-form .checkbox { + margin-top: 5px; +} +.navbar-form input[type="image"], .navbar-form input[type="checkbox"], .navbar-form input[type="radio"] { + margin-top: 3px; +} +.navbar-form .input-append, .navbar-form .input-prepend { + margin-top: 6px; + white-space: nowrap; +} +.navbar-form .input-append input, .navbar-form .input-prepend input { + margin-top: 0; +} +.navbar-search { + position: relative; + float: left; + margin-top: 6px; + margin-bottom: 0; +} +.navbar-search .search-query { + padding: 4px 9px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + font-weight: normal; + line-height: 1; + color: #ffffff; + color: rgba(255, 255, 255, 0.75); + background: #666; + background: rgba(255, 255, 255, 0.3); + border: 1px solid #111; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + -webkit-transition: none; + -moz-transition: none; + -ms-transition: none; + -o-transition: none; + transition: none; +} +.navbar-search .search-query :-moz-placeholder { + color: #eeeeee; +} +.navbar-search .search-query::-webkit-input-placeholder { + color: #eeeeee; +} +.navbar-search .search-query:hover { + color: #ffffff; + background-color: #999999; + background-color: rgba(255, 255, 255, 0.5); +} +.navbar-search .search-query:focus, .navbar-search .search-query.focused { + padding: 5px 10px; + color: #333333; + text-shadow: 0 1px 0 #ffffff; + background-color: #ffffff; + border: 0; + -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + outline: 0; +} +.navbar-fixed-top { + position: fixed; + top: 0; + right: 0; + left: 0; + z-index: 1030; +} +.navbar-fixed-top .navbar-inner { + padding-left: 0; + padding-right: 0; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.navbar .nav { + position: relative; + left: 0; + display: block; + float: left; + margin: 0 10px 0 0; +} +.navbar .nav.pull-right { + float: right; +} +.navbar .nav > li { + display: block; + float: left; +} +.navbar .nav > li > a { + float: none; + padding: 10px 10px 11px; + line-height: 19px; + color: #999999; + text-decoration: none; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.navbar .nav > li > a:hover { + background-color: transparent; + color: #ffffff; + text-decoration: none; +} +.navbar .nav .active > a, .navbar .nav .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #222222; +} +.navbar .divider-vertical { + height: 40px; + width: 1px; + margin: 0 9px; + overflow: hidden; + background-color: #222222; + border-right: 1px solid #333333; +} +.navbar .nav.pull-right { + margin-left: 10px; + margin-right: 0; +} +.navbar .dropdown-menu { + margin-top: 1px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.navbar .dropdown-menu:before { + content: ''; + display: inline-block; + border-left: 7px solid transparent; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-bottom-color: rgba(0, 0, 0, 0.2); + position: absolute; + top: -7px; + left: 9px; +} +.navbar .dropdown-menu:after { + content: ''; + display: inline-block; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid #ffffff; + position: absolute; + top: -6px; + left: 10px; +} +.navbar .nav .dropdown-toggle .caret, .navbar .nav .open.dropdown .caret { + border-top-color: #ffffff; +} +.navbar .nav .active .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.navbar .nav .open > .dropdown-toggle, .navbar .nav .active > .dropdown-toggle, .navbar .nav .open.active > .dropdown-toggle { + background-color: transparent; +} +.navbar .nav .active > .dropdown-toggle:hover { + color: #ffffff; +} +.navbar .nav.pull-right .dropdown-menu { + left: auto; + right: 0; +} +.navbar .nav.pull-right .dropdown-menu:before { + left: auto; + right: 12px; +} +.navbar .nav.pull-right .dropdown-menu:after { + left: auto; + right: 13px; +} +.breadcrumb { + padding: 7px 14px; + margin: 0 0 18px; + background-color: #fbfbfb; + background-image: -moz-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -ms-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5)); + background-image: -webkit-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -o-linear-gradient(top, #ffffff, #f5f5f5); + background-image: linear-gradient(top, #ffffff, #f5f5f5); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0); + border: 1px solid #ddd; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; +} +.breadcrumb li { + display: inline-block; + text-shadow: 0 1px 0 #ffffff; +} +.breadcrumb .divider { + padding: 0 5px; + color: #999999; +} +.breadcrumb .active a { + color: #333333; +} +.pagination { + height: 36px; + margin: 18px 0; +} +.pagination ul { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; + margin-left: 0; + margin-bottom: 0; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); +} +.pagination li { + display: inline; +} +.pagination a { + float: left; + padding: 0 14px; + line-height: 34px; + text-decoration: none; + border: 1px solid #ddd; + border-left-width: 0; +} +.pagination a:hover, .pagination .active a { + background-color: #f5f5f5; +} +.pagination .active a { + color: #999999; + cursor: default; +} +.pagination .disabled a, .pagination .disabled a:hover { + color: #999999; + background-color: transparent; + cursor: default; +} +.pagination li:first-child a { + border-left-width: 1px; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.pagination li:last-child a { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.pagination-centered { + text-align: center; +} +.pagination-right { + text-align: right; +} +.pager { + margin-left: 0; + margin-bottom: 18px; + list-style: none; + text-align: center; + *zoom: 1; +} +.pager:before, .pager:after { + display: table; + content: ""; +} +.pager:after { + clear: both; +} +.pager li { + display: inline; +} +.pager a { + display: inline-block; + padding: 5px 14px; + background-color: #fff; + border: 1px solid #ddd; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} +.pager a:hover { + text-decoration: none; + background-color: #f5f5f5; +} +.pager .next a { + float: right; +} +.pager .previous a { + float: left; +} +.modal-open .dropdown-menu { + z-index: 2050; +} +.modal-open .dropdown.open { + *z-index: 2050; +} +.modal-open .popover { + z-index: 2060; +} +.modal-open .tooltip { + z-index: 2070; +} +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + background-color: #000000; +} +.modal-backdrop.fade { + opacity: 0; +} +.modal-backdrop, .modal-backdrop.fade.in { + opacity: 0.8; + filter: alpha(opacity=80); +} +.modal { + position: fixed; + top: 50%; + left: 50%; + z-index: 1050; + max-height: 500px; + overflow: auto; + width: 560px; + margin: -250px 0 0 -280px; + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + /* IE6-7 */ + + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.wide-modal { + position: fixed; + top: 5%; + left: 5%; + z-index: 1050; + max-height: 90%; + overflow: auto; + width: 90%; + /*margin: -50px 0 0 -80px;*/ + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + /* IE6-7 */ + + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.modal.fade { + -webkit-transition: opacity .3s linear, top .3s ease-out; + -moz-transition: opacity .3s linear, top .3s ease-out; + -ms-transition: opacity .3s linear, top .3s ease-out; + -o-transition: opacity .3s linear, top .3s ease-out; + transition: opacity .3s linear, top .3s ease-out; + top: -25%; +} +.modal.fade.in { + top: 50%; +} +.modal-header { + padding: 9px 15px; + border-bottom: 1px solid #eee; +} +.modal-header .close { + margin-top: 2px; +} +.modal-body { + padding: 15px; +} +.modal-body .modal-form { + margin-bottom: 0; +} +.modal-footer { + padding: 14px 15px 15px; + margin-bottom: 0; + background-color: #f5f5f5; + border-top: 1px solid #ddd; + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; + *zoom: 1; +} +.modal-footer:before, .modal-footer:after { + display: table; + content: ""; +} +.modal-footer:after { + clear: both; +} +.modal-footer .btn { + float: right; + margin-left: 5px; + margin-bottom: 0; +} +.tooltip { + position: absolute; + z-index: 1020; + display: block; + visibility: visible; + padding: 5px; + font-size: 11px; + opacity: 0; + filter: alpha(opacity=0); +} +.tooltip.in { + opacity: 0.8; + filter: alpha(opacity=80); +} +.tooltip.top { + margin-top: -2px; +} +.tooltip.right { + margin-left: 2px; +} +.tooltip.bottom { + margin-top: 2px; +} +.tooltip.left { + margin-left: -2px; +} +.tooltip.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid #000000; +} +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #000000; +} +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-bottom: 5px solid #000000; +} +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-right: 5px solid #000000; +} +.tooltip-inner { + max-width: 200px; + padding: 3px 8px; + color: #ffffff; + text-align: center; + text-decoration: none; + background-color: #000000; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; +} +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1010; + display: none; + padding: 5px; +} +.popover.top { + margin-top: -5px; +} +.popover.right { + margin-left: 5px; +} +.popover.bottom { + margin-top: 5px; +} +.popover.left { + margin-left: -5px; +} +.popover.top .arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid #000000; +} +.popover.right .arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-right: 5px solid #000000; +} +.popover.bottom .arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-bottom: 5px solid #000000; +} +.popover.left .arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #000000; +} +.popover .arrow { + position: absolute; + width: 0; + height: 0; +} +.popover-inner { + padding: 3px; + width: 280px; + overflow: hidden; + background: #000000; + background: rgba(0, 0, 0, 0.8); + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); +} +.popover-title { + padding: 9px 15px; + line-height: 1; + background-color: #f5f5f5; + border-bottom: 1px solid #eee; + -webkit-border-radius: 3px 3px 0 0; + -moz-border-radius: 3px 3px 0 0; + border-radius: 3px 3px 0 0; +} +.popover-content { + padding: 14px; + background-color: #ffffff; + -webkit-border-radius: 0 0 3px 3px; + -moz-border-radius: 0 0 3px 3px; + border-radius: 0 0 3px 3px; + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.popover-content p, .popover-content ul, .popover-content ol { + margin-bottom: 0; +} +.thumbnails { + margin-left: -20px; + list-style: none; + *zoom: 1; +} +.thumbnails:before, .thumbnails:after { + display: table; + content: ""; +} +.thumbnails:after { + clear: both; +} +.thumbnails > li { + float: left; + margin: 0 0 18px 20px; +} +.thumbnail { + display: block; + padding: 4px; + line-height: 1; + border: 1px solid #ddd; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); +} +a.thumbnail:hover { + border-color: #0088cc; + -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); +} +.thumbnail > img { + display: block; + max-width: 100%; + margin-left: auto; + margin-right: auto; +} +.thumbnail .caption { + padding: 9px; +} +.label { + padding: 2px 4px 3px; + font-size: 11.049999999999999px; + font-weight: bold; + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #999999; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.label:hover { + color: #ffffff; + text-decoration: none; +} +.label-important { + background-color: #b94a48; +} +.label-important:hover { + background-color: #953b39; +} +.label-warning { + background-color: #f89406; +} +.label-warning:hover { + background-color: #c67605; +} +.label-success { + background-color: #468847; +} +.label-success:hover { + background-color: #356635; +} +.label-info { + background-color: #3a87ad; +} +.label-info:hover { + background-color: #2d6987; +} +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +@-moz-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +@keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +.progress { + overflow: hidden; + height: 18px; + margin-bottom: 18px; + background-color: #f7f7f7; + background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -ms-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9)); + background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: linear-gradient(top, #f5f5f5, #f9f9f9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0); + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.progress .bar { + width: 0%; + height: 18px; + color: #ffffff; + font-size: 12px; + text-align: center; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #0e90d2; + background-image: -moz-linear-gradient(top, #149bdf, #0480be); + background-image: -ms-linear-gradient(top, #149bdf, #0480be); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be)); + background-image: -webkit-linear-gradient(top, #149bdf, #0480be); + background-image: -o-linear-gradient(top, #149bdf, #0480be); + background-image: linear-gradient(top, #149bdf, #0480be); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0); + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition: width 0.6s ease; + -moz-transition: width 0.6s ease; + -ms-transition: width 0.6s ease; + -o-transition: width 0.6s ease; + transition: width 0.6s ease; +} +.progress-striped .bar { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + -webkit-background-size: 40px 40px; + -moz-background-size: 40px 40px; + -o-background-size: 40px 40px; + background-size: 40px 40px; +} +.progress.active .bar { + -webkit-animation: progress-bar-stripes 2s linear infinite; + -moz-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} +.progress-danger .bar { + background-color: #dd514c; + background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -o-linear-gradient(top, #ee5f5b, #c43c35); + background-image: linear-gradient(top, #ee5f5b, #c43c35); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0); +} +.progress-danger.progress-striped .bar { + background-color: #ee5f5b; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-success .bar { + background-color: #5eb95e; + background-image: -moz-linear-gradient(top, #62c462, #57a957); + background-image: -ms-linear-gradient(top, #62c462, #57a957); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957)); + background-image: -webkit-linear-gradient(top, #62c462, #57a957); + background-image: -o-linear-gradient(top, #62c462, #57a957); + background-image: linear-gradient(top, #62c462, #57a957); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0); +} +.progress-success.progress-striped .bar { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-info .bar { + background-color: #4bb1cf; + background-image: -moz-linear-gradient(top, #5bc0de, #339bb9); + background-image: -ms-linear-gradient(top, #5bc0de, #339bb9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9)); + background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9); + background-image: -o-linear-gradient(top, #5bc0de, #339bb9); + background-image: linear-gradient(top, #5bc0de, #339bb9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0); +} +.progress-info.progress-striped .bar { + background-color: #5bc0de; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.accordion { + margin-bottom: 18px; +} +.accordion-group { + margin-bottom: 2px; + border: 1px solid #e5e5e5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.accordion-heading { + border-bottom: 0; +} +.accordion-heading .accordion-toggle { + display: block; + padding: 8px 15px; +} +.accordion-inner { + padding: 9px 15px; + border-top: 1px solid #e5e5e5; +} +.carousel { + position: relative; + margin-bottom: 18px; + line-height: 1; +} +.carousel-inner { + overflow: hidden; + width: 100%; + position: relative; +} +.carousel .item { + display: none; + position: relative; + -webkit-transition: 0.6s ease-in-out left; + -moz-transition: 0.6s ease-in-out left; + -ms-transition: 0.6s ease-in-out left; + -o-transition: 0.6s ease-in-out left; + transition: 0.6s ease-in-out left; +} +.carousel .item > img { + display: block; + line-height: 1; +} +.carousel .active, .carousel .next, .carousel .prev { + display: block; +} +.carousel .active { + left: 0; +} +.carousel .next, .carousel .prev { + position: absolute; + top: 0; + width: 100%; +} +.carousel .next { + left: 100%; +} +.carousel .prev { + left: -100%; +} +.carousel .next.left, .carousel .prev.right { + left: 0; +} +.carousel .active.left { + left: -100%; +} +.carousel .active.right { + left: 100%; +} +.carousel-control { + position: absolute; + top: 40%; + left: 15px; + width: 40px; + height: 40px; + margin-top: -20px; + font-size: 60px; + font-weight: 100; + line-height: 30px; + color: #ffffff; + text-align: center; + background: #222222; + border: 3px solid #ffffff; + -webkit-border-radius: 23px; + -moz-border-radius: 23px; + border-radius: 23px; + opacity: 0.5; + filter: alpha(opacity=50); +} +.carousel-control.right { + left: auto; + right: 15px; +} +.carousel-control:hover { + color: #ffffff; + text-decoration: none; + opacity: 0.9; + filter: alpha(opacity=90); +} +.carousel-caption { + position: absolute; + left: 0; + right: 0; + bottom: 0; + padding: 10px 15px 5px; + background: #333333; + background: rgba(0, 0, 0, 0.75); +} +.carousel-caption h4, .carousel-caption p { + color: #ffffff; +} +.hero-unit { + padding: 60px; + margin-bottom: 30px; + background-color: #f5f5f5; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} +.hero-unit h1 { + margin-bottom: 0; + font-size: 60px; + line-height: 1; + letter-spacing: -1px; +} +.hero-unit p { + font-size: 18px; + font-weight: 200; + line-height: 27px; +} +.pull-right { + float: right; +} +.pull-left { + float: left; +} +.hide { + display: none; +} +.show { + display: block; +} +.invisible { + visibility: hidden; +} diff --git a/src/nl/astraeus/jdbc/web/resources/images/loading.gif b/src/nl/astraeus/jdbc/web/resources/images/loading.gif new file mode 100644 index 0000000..21c7e74 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/images/loading.gif Binary files differ diff --git a/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png b/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png new file mode 100644 index 0000000..92d4445 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png Binary files differ diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-alert.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-alert.js new file mode 100644 index 0000000..2242ddd --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-alert.js @@ -0,0 +1,94 @@ +/* ========================================================== + * bootstrap-alert.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#alerts + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function( $ ){ + + "use strict" + + /* ALERT CLASS DEFINITION + * ====================== */ + + var dismiss = '[data-dismiss="alert"]' + , Alert = function ( el ) { + $(el).on('click', dismiss, this.close) + } + + Alert.prototype = { + + constructor: Alert + + , close: function ( e ) { + var $this = $(this) + , selector = $this.attr('data-target') + , $parent + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = $(selector) + $parent.trigger('close') + + e && e.preventDefault() + + $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent()) + + $parent + .trigger('close') + .removeClass('in') + + function removeElement() { + $parent + .trigger('closed') + .remove() + } + + $.support.transition && $parent.hasClass('fade') ? + $parent.on($.support.transition.end, removeElement) : + removeElement() + } + + } + + + /* ALERT PLUGIN DEFINITION + * ======================= */ + + $.fn.alert = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('alert') + if (!data) $this.data('alert', (data = new Alert(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.alert.Constructor = Alert + + + /* ALERT DATA-API + * ============== */ + + $(function () { + $('body').on('click.alert.data-api', dismiss, Alert.prototype.close) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-button.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-button.js new file mode 100644 index 0000000..0238ca3 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-button.js @@ -0,0 +1,100 @@ +/* ============================================================ + * bootstrap-button.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#buttons + * ============================================================ + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + +!function( $ ){ + + "use strict" + + /* BUTTON PUBLIC CLASS DEFINITION + * ============================== */ + + var Button = function ( element, options ) { + this.$element = $(element) + this.options = $.extend({}, $.fn.button.defaults, options) + } + + Button.prototype = { + + constructor: Button + + , setState: function ( state ) { + var d = 'disabled' + , $el = this.$element + , data = $el.data() + , val = $el.is('input') ? 'val' : 'html' + + state = state + 'Text' + data.resetText || $el.data('resetText', $el[val]()) + + $el[val](data[state] || this.options[state]) + + // push to event loop to allow forms to submit + setTimeout(function () { + state == 'loadingText' ? + $el.addClass(d).attr(d, d) : + $el.removeClass(d).removeAttr(d) + }, 0) + } + + , toggle: function () { + var $parent = this.$element.parent('[data-toggle="buttons-radio"]') + + $parent && $parent + .find('.active') + .removeClass('active') + + this.$element.toggleClass('active') + } + + } + + + /* BUTTON PLUGIN DEFINITION + * ======================== */ + + $.fn.button = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('button') + , options = typeof option == 'object' && option + if (!data) $this.data('button', (data = new Button(this, options))) + if (option == 'toggle') data.toggle() + else if (option) data.setState(option) + }) + } + + $.fn.button.defaults = { + loadingText: 'loading...' + } + + $.fn.button.Constructor = Button + + + /* BUTTON DATA-API + * =============== */ + + $(function () { + $('body').on('click.button.data-api', '[data-toggle^=button]', function ( e ) { + var $btn = $(e.target) + if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') + $btn.button('toggle') + }) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-carousel.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-carousel.js new file mode 100644 index 0000000..810256e --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-carousel.js @@ -0,0 +1,157 @@ +/* ========================================================== + * bootstrap-carousel.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#carousel + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function( $ ){ + + "use strict" + + /* CAROUSEL CLASS DEFINITION + * ========================= */ + + var Carousel = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, $.fn.carousel.defaults, options) + this.options.slide && this.slide(this.options.slide) + } + + Carousel.prototype = { + + cycle: function () { + this.interval = setInterval($.proxy(this.next, this), this.options.interval) + return this + } + + , to: function (pos) { + var $active = this.$element.find('.active') + , children = $active.parent().children() + , activePos = children.index($active) + , that = this + + if (pos > (children.length - 1) || pos < 0) return + + if (this.sliding) { + return this.$element.one('slid', function () { + that.to(pos) + }) + } + + if (activePos == pos) { + return this.pause().cycle() + } + + return this.slide(pos > activePos ? 'next' : 'prev', $(children[pos])) + } + + , pause: function () { + clearInterval(this.interval) + this.interval = null + return this + } + + , next: function () { + if (this.sliding) return + return this.slide('next') + } + + , prev: function () { + if (this.sliding) return + return this.slide('prev') + } + + , slide: function (type, next) { + var $active = this.$element.find('.active') + , $next = next || $active[type]() + , isCycling = this.interval + , direction = type == 'next' ? 'left' : 'right' + , fallback = type == 'next' ? 'first' : 'last' + , that = this + + if (!$next.length) return + + this.sliding = true + + isCycling && this.pause() + + $next = $next.length ? $next : this.$element.find('.item')[fallback]() + + if (!$.support.transition && this.$element.hasClass('slide')) { + this.$element.trigger('slide') + $active.removeClass('active') + $next.addClass('active') + this.sliding = false + this.$element.trigger('slid') + } else { + $next.addClass(type) + $next[0].offsetWidth // force reflow + $active.addClass(direction) + $next.addClass(direction) + this.$element.trigger('slide') + this.$element.one($.support.transition.end, function () { + $next.removeClass([type, direction].join(' ')).addClass('active') + $active.removeClass(['active', direction].join(' ')) + that.sliding = false + setTimeout(function () { that.$element.trigger('slid') }, 0) + }) + } + + isCycling && this.cycle() + + return this + } + + } + + + /* CAROUSEL PLUGIN DEFINITION + * ========================== */ + + $.fn.carousel = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('carousel') + , options = typeof option == 'object' && option + if (!data) $this.data('carousel', (data = new Carousel(this, options))) + if (typeof option == 'number') data.to(option) + else if (typeof option == 'string' || (option = options.slide)) data[option]() + else data.cycle() + }) + } + + $.fn.carousel.defaults = { + interval: 5000 + } + + $.fn.carousel.Constructor = Carousel + + + /* CAROUSEL DATA-API + * ================= */ + + $(function () { + $('body').on('click.carousel.data-api', '[data-slide]', function ( e ) { + var $this = $(this), href + , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 + , options = !$target.data('modal') && $.extend({}, $target.data(), $this.data()) + $target.carousel(options) + e.preventDefault() + }) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-collapse.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-collapse.js new file mode 100644 index 0000000..d195efc --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-collapse.js @@ -0,0 +1,136 @@ +/* ============================================================= + * bootstrap-collapse.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#collapse + * ============================================================= + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + +!function( $ ){ + + "use strict" + + var Collapse = function ( element, options ) { + this.$element = $(element) + this.options = $.extend({}, $.fn.collapse.defaults, options) + + if (this.options["parent"]) { + this.$parent = $(this.options["parent"]) + } + + this.options.toggle && this.toggle() + } + + Collapse.prototype = { + + constructor: Collapse + + , dimension: function () { + var hasWidth = this.$element.hasClass('width') + return hasWidth ? 'width' : 'height' + } + + , show: function () { + var dimension = this.dimension() + , scroll = $.camelCase(['scroll', dimension].join('-')) + , actives = this.$parent && this.$parent.find('.in') + , hasData + + if (actives && actives.length) { + hasData = actives.data('collapse') + actives.collapse('hide') + hasData || actives.data('collapse', null) + } + + this.$element[dimension](0) + this.transition('addClass', 'show', 'shown') + this.$element[dimension](this.$element[0][scroll]) + + } + + , hide: function () { + var dimension = this.dimension() + this.reset(this.$element[dimension]()) + this.transition('removeClass', 'hide', 'hidden') + this.$element[dimension](0) + } + + , reset: function ( size ) { + var dimension = this.dimension() + + this.$element + .removeClass('collapse') + [dimension](size || 'auto') + [0].offsetWidth + + this.$element.addClass('collapse') + } + + , transition: function ( method, startEvent, completeEvent ) { + var that = this + , complete = function () { + if (startEvent == 'show') that.reset() + that.$element.trigger(completeEvent) + } + + this.$element + .trigger(startEvent) + [method]('in') + + $.support.transition && this.$element.hasClass('collapse') ? + this.$element.one($.support.transition.end, complete) : + complete() + } + + , toggle: function () { + this[this.$element.hasClass('in') ? 'hide' : 'show']() + } + + } + + /* COLLAPSIBLE PLUGIN DEFINITION + * ============================== */ + + $.fn.collapse = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('collapse') + , options = typeof option == 'object' && option + if (!data) $this.data('collapse', (data = new Collapse(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.collapse.defaults = { + toggle: true + } + + $.fn.collapse.Constructor = Collapse + + + /* COLLAPSIBLE DATA-API + * ==================== */ + + $(function () { + $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function ( e ) { + var $this = $(this), href + , target = $this.attr('data-target') + || e.preventDefault() + || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 + , option = $(target).data('collapse') ? 'toggle' : $this.data() + $(target).collapse(option) + }) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-dropdown.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-dropdown.js new file mode 100644 index 0000000..f1f6c33 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-dropdown.js @@ -0,0 +1,92 @@ +/* ============================================================ + * bootstrap-dropdown.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#dropdowns + * ============================================================ + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + + +!function( $ ){ + + "use strict" + + /* DROPDOWN CLASS DEFINITION + * ========================= */ + + var toggle = '[data-toggle="dropdown"]' + , Dropdown = function ( element ) { + var $el = $(element).on('click.dropdown.data-api', this.toggle) + $('html').on('click.dropdown.data-api', function () { + $el.parent().removeClass('open') + }) + } + + Dropdown.prototype = { + + constructor: Dropdown + + , toggle: function ( e ) { + var $this = $(this) + , selector = $this.attr('data-target') + , $parent + , isActive + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = $(selector) + $parent.length || ($parent = $this.parent()) + + isActive = $parent.hasClass('open') + + clearMenus() + !isActive && $parent.toggleClass('open') + + return false + } + + } + + function clearMenus() { + $(toggle).parent().removeClass('open') + } + + + /* DROPDOWN PLUGIN DEFINITION + * ========================== */ + + $.fn.dropdown = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('dropdown') + if (!data) $this.data('dropdown', (data = new Dropdown(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.dropdown.Constructor = Dropdown + + + /* APPLY TO STANDARD DROPDOWN ELEMENTS + * =================================== */ + + $(function () { + $('html').on('click.dropdown.data-api', clearMenus) + $('body').on('click.dropdown.data-api', toggle, Dropdown.prototype.toggle) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-modal.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-modal.js new file mode 100644 index 0000000..bceb303 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-modal.js @@ -0,0 +1,210 @@ +/* ========================================================= + * bootstrap-modal.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#modals + * ========================================================= + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================= */ + + +!function( $ ){ + + "use strict" + + /* MODAL CLASS DEFINITION + * ====================== */ + + var Modal = function ( content, options ) { + this.options = options + this.$element = $(content) + .delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this)) + } + + Modal.prototype = { + + constructor: Modal + + , toggle: function () { + return this[!this.isShown ? 'show' : 'hide']() + } + + , show: function () { + var that = this + + if (this.isShown) return + + $('body').addClass('modal-open') + + this.isShown = true + this.$element.trigger('show') + + escape.call(this) + backdrop.call(this, function () { + var transition = $.support.transition && that.$element.hasClass('fade') + + !that.$element.parent().length && that.$element.appendTo(document.body) //don't move modals dom position + + that.$element + .show() + + if (transition) { + that.$element[0].offsetWidth // force reflow + } + + that.$element.addClass('in') + + transition ? + that.$element.one($.support.transition.end, function () { that.$element.trigger('shown') }) : + that.$element.trigger('shown') + + }) + } + + , hide: function ( e ) { + e && e.preventDefault() + + if (!this.isShown) return + + var that = this + this.isShown = false + + $('body').removeClass('modal-open') + + escape.call(this) + + this.$element + .trigger('hide') + .removeClass('in') + + $.support.transition && this.$element.hasClass('fade') ? + hideWithTransition.call(this) : + hideModal.call(this) + } + + } + + + /* MODAL PRIVATE METHODS + * ===================== */ + + function hideWithTransition() { + var that = this + , timeout = setTimeout(function () { + that.$element.off($.support.transition.end) + hideModal.call(that) + }, 500) + + this.$element.one($.support.transition.end, function () { + clearTimeout(timeout) + hideModal.call(that) + }) + } + + function hideModal( that ) { + this.$element + .hide() + .trigger('hidden') + + backdrop.call(this) + } + + function backdrop( callback ) { + var that = this + , animate = this.$element.hasClass('fade') ? 'fade' : '' + + if (this.isShown && this.options.backdrop) { + var doAnimate = $.support.transition && animate + + this.$backdrop = $(' + + + + + \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/head.html b/src/nl/astraeus/jdbc/web/head.html new file mode 100644 index 0000000..0f8f6a3 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/head.html @@ -0,0 +1,96 @@ + + + + + + + Simple JDBC Statistics + + + + + + + + + + + + + + + + + + + +
+
+ +
+ diff --git a/src/nl/astraeus/jdbc/web/page/Menu.html b/src/nl/astraeus/jdbc/web/page/Menu.html new file mode 100644 index 0000000..505c7c2 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.html @@ -0,0 +1,42 @@ + diff --git a/src/nl/astraeus/jdbc/web/page/Menu.java b/src/nl/astraeus/jdbc/web/page/Menu.java new file mode 100644 index 0000000..f0a349a --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.java @@ -0,0 +1,27 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 9:07 PM + */ +public class Menu extends TemplatePage { + + @Override + public Page processRequest(HttpServletRequest request) { + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + result.put("user", request.getSession().getAttribute("user")); + + return result; + } +} diff --git a/src/nl/astraeus/jdbc/web/page/Page.java b/src/nl/astraeus/jdbc/web/page/Page.java new file mode 100644 index 0000000..9d526d6 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Page.java @@ -0,0 +1,17 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:20 PM + */ +public abstract class Page { + + public abstract Page processRequest(HttpServletRequest request); + public abstract Map defineModel(HttpServletRequest request); + public abstract String render(HttpServletRequest request); + +} diff --git a/src/nl/astraeus/jdbc/web/page/QueryOverview.html b/src/nl/astraeus/jdbc/web/page/QueryOverview.html new file mode 100644 index 0000000..64a88fb --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/QueryOverview.html @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + {foreach(queries as q)} + + + + + + + {eachend} + +
Total timeAvg. time# CallsSql
{q.total}{q.nano}{q.count}{q.sql}
diff --git a/src/nl/astraeus/jdbc/web/page/QueryOverview.java b/src/nl/astraeus/jdbc/web/page/QueryOverview.java new file mode 100644 index 0000000..02982f1 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/QueryOverview.java @@ -0,0 +1,92 @@ +package nl.astraeus.jdbc.web.page; + +import nl.astraeus.jdbc.JdbcLogger; + +import javax.servlet.http.HttpServletRequest; +import java.util.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 9:16 PM + */ +public class QueryOverview extends TemplatePage { + + boolean sortTotalCalls = true; + boolean sortAvgTime = false; + boolean sortTotalTime = false; + + @Override + public Page processRequest(HttpServletRequest request) { + if ("sortTotalCalls".equals(request.getParameter("action"))) { + sortTotalCalls = true; + sortAvgTime = false; + sortTotalTime = false; + } else if ("sortAvgTime".equals(request.getParameter("action"))) { + sortTotalCalls = false; + sortAvgTime = true; + sortTotalTime = false; + } else if ("sortTotalTime".equals(request.getParameter("action"))) { + sortTotalCalls = false; + sortAvgTime = false; + sortTotalTime = true; + } + + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + List entries = new ArrayList(JdbcLogger.get().getEntries()); + + if (sortTotalCalls) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + return o2.count - o1.count; + } + }); + } else if (sortAvgTime) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + long n1 = o1.nano / o1.count; + long n2 = o2.nano / o2.count; + + if (n2 > n1) { + return 1; + } else if (n2 < n1) { + return -1; + } else { + return 0; + } + } + }); + } else if (sortTotalTime) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + if (o2.nano > o1.nano) { + return 1; + } else if (o2.nano < o1.nano) { + return -1; + } else { + return 0; + } + } + }); + } + + result.put("queries", entries); + result.put("count", entries.size()); + + result.put("sortTotalCalls", sortTotalCalls); + result.put("sortAvgTime", sortAvgTime); + result.put("sortTotalTime", sortTotalTime); + + return result; + } + +} diff --git a/src/nl/astraeus/jdbc/web/page/TemplatePage.java b/src/nl/astraeus/jdbc/web/page/TemplatePage.java new file mode 100644 index 0000000..33e2641 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/TemplatePage.java @@ -0,0 +1,58 @@ +package nl.astraeus.jdbc.web.page; + +import nl.astraeus.template.EscapeMode; +import nl.astraeus.template.SimpleTemplate; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:20 PM + */ +public abstract class TemplatePage extends Page { + + private SimpleTemplate template; + + protected TemplatePage() { + template = getSimpleTemplate(this.getClass()); + } + + public String render(HttpServletRequest request) { + return template.render(defineModel(request)); + } + + private static Map templateCache = new HashMap(); + + public synchronized static SimpleTemplate getSimpleTemplate(Class cls) { + SimpleTemplate result = templateCache.get(cls); + + if (result == null) { + InputStream in = null; + + try { + in = cls.getResourceAsStream(cls.getSimpleName() + ".html"); + + result = SimpleTemplate.readTemplate('{','}', EscapeMode.HTML, in); + + templateCache.put(cls, result); + } catch (IOException e) { + throw new IllegalStateException(e); + } finally { + if (in != null) { + try { + in.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + + return result; + } +} diff --git a/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css b/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css new file mode 100644 index 0000000..0e0056f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css @@ -0,0 +1,581 @@ +/*! + * Bootstrap Responsive v2.0.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ +.clearfix { + *zoom: 1; +} +.clearfix:before, .clearfix:after { + display: table; + content: ""; +} +.clearfix:after { + clear: both; +} +.hidden { + display: none; + visibility: hidden; +} +@media (max-width: 480px) { + .nav-collapse { + -webkit-transform: translate3d(0, 0, 0); + } + .page-header h1 small { + display: block; + line-height: 18px; + } + input[class*="span"], + select[class*="span"], + textarea[class*="span"], + .uneditable-input { + display: block; + width: 100%; + min-height: 28px; + /* Make inputs at least the height of their button counterpart */ + + /* Makes inputs behave like true block-level elements */ + + -webkit-box-sizing: border-box; + /* Older Webkit */ + + -moz-box-sizing: border-box; + /* Older FF */ + + -ms-box-sizing: border-box; + /* IE8 */ + + box-sizing: border-box; + /* CSS3 spec*/ + + } + .input-prepend input[class*="span"], .input-append input[class*="span"] { + width: auto; + } + input[type="checkbox"], input[type="radio"] { + border: 1px solid #ccc; + } + .form-horizontal .control-group > label { + float: none; + width: auto; + padding-top: 0; + text-align: left; + } + .form-horizontal .controls { + margin-left: 0; + } + .form-horizontal .control-list { + padding-top: 0; + } + .form-horizontal .form-actions { + padding-left: 10px; + padding-right: 10px; + } + .modal { + position: absolute; + top: 10px; + left: 10px; + right: 10px; + width: auto; + margin: 0; + } + .modal.fade.in { + top: auto; + } + .modal-header .close { + padding: 10px; + margin: -10px; + } + .carousel-caption { + position: static; + } +} +@media (max-width: 767px) { + .container { + width: auto; + padding: 0 20px; + } + .row-fluid { + width: 100%; + } + .row { + margin-left: 0; + } + .row > [class*="span"], .row-fluid > [class*="span"] { + float: none; + display: block; + width: auto; + margin: 0; + } +} +@media (min-width: 768px) and (max-width: 979px) { + .row { + margin-left: -20px; + *zoom: 1; + } + .row:before, .row:after { + display: table; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + margin-left: 20px; + } + .span1 { + width: 42px; + } + .span2 { + width: 104px; + } + .span3 { + width: 166px; + } + .span4 { + width: 228px; + } + .span5 { + width: 290px; + } + .span6 { + width: 352px; + } + .span7 { + width: 414px; + } + .span8 { + width: 476px; + } + .span9 { + width: 538px; + } + .span10 { + width: 600px; + } + .span11 { + width: 662px; + } + .span12, .container { + width: 724px; + } + .offset1 { + margin-left: 82px; + } + .offset2 { + margin-left: 144px; + } + .offset3 { + margin-left: 206px; + } + .offset4 { + margin-left: 268px; + } + .offset5 { + margin-left: 330px; + } + .offset6 { + margin-left: 392px; + } + .offset7 { + margin-left: 454px; + } + .offset8 { + margin-left: 516px; + } + .offset9 { + margin-left: 578px; + } + .offset10 { + margin-left: 640px; + } + .offset11 { + margin-left: 702px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, .row-fluid:after { + display: table; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid > [class*="span"] { + float: left; + margin-left: 2.762430939%; + } + .row-fluid > [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid > .span1 { + width: 5.801104972%; + } + .row-fluid > .span2 { + width: 14.364640883%; + } + .row-fluid > .span3 { + width: 22.928176794%; + } + .row-fluid > .span4 { + width: 31.491712705%; + } + .row-fluid > .span5 { + width: 40.055248616%; + } + .row-fluid > .span6 { + width: 48.618784527%; + } + .row-fluid > .span7 { + width: 57.182320438000005%; + } + .row-fluid > .span8 { + width: 65.74585634900001%; + } + .row-fluid > .span9 { + width: 74.30939226%; + } + .row-fluid > .span10 { + width: 82.87292817100001%; + } + .row-fluid > .span11 { + width: 91.436464082%; + } + .row-fluid > .span12 { + width: 99.999999993%; + } + input.span1, textarea.span1, .uneditable-input.span1 { + width: 32px; + } + input.span2, textarea.span2, .uneditable-input.span2 { + width: 94px; + } + input.span3, textarea.span3, .uneditable-input.span3 { + width: 156px; + } + input.span4, textarea.span4, .uneditable-input.span4 { + width: 218px; + } + input.span5, textarea.span5, .uneditable-input.span5 { + width: 280px; + } + input.span6, textarea.span6, .uneditable-input.span6 { + width: 342px; + } + input.span7, textarea.span7, .uneditable-input.span7 { + width: 404px; + } + input.span8, textarea.span8, .uneditable-input.span8 { + width: 466px; + } + input.span9, textarea.span9, .uneditable-input.span9 { + width: 528px; + } + input.span10, textarea.span10, .uneditable-input.span10 { + width: 590px; + } + input.span11, textarea.span11, .uneditable-input.span11 { + width: 652px; + } + input.span12, textarea.span12, .uneditable-input.span12 { + width: 714px; + } +} +@media (max-width: 979px) { + body { + padding-top: 0; + } + .navbar-fixed-top { + position: static; + margin-bottom: 18px; + } + .navbar-fixed-top .navbar-inner { + padding: 5px; + } + .navbar .container { + width: auto; + padding: 0; + } + .navbar .brand { + padding-left: 10px; + padding-right: 10px; + margin: 0 0 0 -5px; + } + .navbar .nav-collapse { + clear: left; + } + .navbar .nav { + float: none; + margin: 0 0 9px; + } + .navbar .nav > li { + float: none; + } + .navbar .nav > li > a { + margin-bottom: 2px; + } + .navbar .nav > .divider-vertical { + display: none; + } + .navbar .nav .nav-header { + color: #999999; + text-shadow: none; + } + .navbar .nav > li > a, .navbar .dropdown-menu a { + padding: 6px 15px; + font-weight: bold; + color: #999999; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + } + .navbar .dropdown-menu li + li a { + margin-bottom: 2px; + } + .navbar .nav > li > a:hover, .navbar .dropdown-menu a:hover { + background-color: #222222; + } + .navbar .dropdown-menu { + position: static; + top: auto; + left: auto; + float: none; + display: block; + max-width: none; + margin: 0 15px; + padding: 0; + background-color: transparent; + border: none; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + } + .navbar .dropdown-menu:before, .navbar .dropdown-menu:after { + display: none; + } + .navbar .dropdown-menu .divider { + display: none; + } + .navbar-form, .navbar-search { + float: none; + padding: 9px 15px; + margin: 9px 0; + border-top: 1px solid #222222; + border-bottom: 1px solid #222222; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + } + .navbar .nav.pull-right { + float: none; + margin-left: 0; + } + .navbar-static .navbar-inner { + padding-left: 10px; + padding-right: 10px; + } + .btn-navbar { + display: block; + } + .nav-collapse { + overflow: hidden; + height: 0; + } +} +@media (min-width: 980px) { + .nav-collapse.collapse { + height: auto !important; + } +} +@media (min-width: 1200px) { + .row { + margin-left: -30px; + *zoom: 1; + } + .row:before, .row:after { + display: table; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + margin-left: 30px; + } + .span1 { + width: 70px; + } + .span2 { + width: 170px; + } + .span3 { + width: 270px; + } + .span4 { + width: 370px; + } + .span5 { + width: 470px; + } + .span6 { + width: 570px; + } + .span7 { + width: 670px; + } + .span8 { + width: 770px; + } + .span9 { + width: 870px; + } + .span10 { + width: 970px; + } + .span11 { + width: 1070px; + } + .span12, .container { + width: 1170px; + } + .offset1 { + margin-left: 130px; + } + .offset2 { + margin-left: 230px; + } + .offset3 { + margin-left: 330px; + } + .offset4 { + margin-left: 430px; + } + .offset5 { + margin-left: 530px; + } + .offset6 { + margin-left: 630px; + } + .offset7 { + margin-left: 730px; + } + .offset8 { + margin-left: 830px; + } + .offset9 { + margin-left: 930px; + } + .offset10 { + margin-left: 1030px; + } + .offset11 { + margin-left: 1130px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, .row-fluid:after { + display: table; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid > [class*="span"] { + float: left; + margin-left: 2.564102564%; + } + .row-fluid > [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid > .span1 { + width: 5.982905983%; + } + .row-fluid > .span2 { + width: 14.529914530000001%; + } + .row-fluid > .span3 { + width: 23.076923077%; + } + .row-fluid > .span4 { + width: 31.623931624%; + } + .row-fluid > .span5 { + width: 40.170940171000005%; + } + .row-fluid > .span6 { + width: 48.717948718%; + } + .row-fluid > .span7 { + width: 57.264957265%; + } + .row-fluid > .span8 { + width: 65.81196581200001%; + } + .row-fluid > .span9 { + width: 74.358974359%; + } + .row-fluid > .span10 { + width: 82.905982906%; + } + .row-fluid > .span11 { + width: 91.45299145300001%; + } + .row-fluid > .span12 { + width: 100%; + } + input.span1, textarea.span1, .uneditable-input.span1 { + width: 60px; + } + input.span2, textarea.span2, .uneditable-input.span2 { + width: 160px; + } + input.span3, textarea.span3, .uneditable-input.span3 { + width: 260px; + } + input.span4, textarea.span4, .uneditable-input.span4 { + width: 360px; + } + input.span5, textarea.span5, .uneditable-input.span5 { + width: 460px; + } + input.span6, textarea.span6, .uneditable-input.span6 { + width: 560px; + } + input.span7, textarea.span7, .uneditable-input.span7 { + width: 660px; + } + input.span8, textarea.span8, .uneditable-input.span8 { + width: 760px; + } + input.span9, textarea.span9, .uneditable-input.span9 { + width: 860px; + } + input.span10, textarea.span10, .uneditable-input.span10 { + width: 960px; + } + input.span11, textarea.span11, .uneditable-input.span11 { + width: 1060px; + } + input.span12, textarea.span12, .uneditable-input.span12 { + width: 1160px; + } + .thumbnails { + margin-left: -30px; + } + .thumbnails > li { + margin-left: 30px; + } +} diff --git a/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css b/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css new file mode 100644 index 0000000..6229c12 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css @@ -0,0 +1,3521 @@ +/*! + * Bootstrap v2.0.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +nav, +section { + display: block; +} +audio, canvas, video { + display: inline-block; + *display: inline; + *zoom: 1; +} +audio:not([controls]) { + display: none; +} +html { + font-size: 100%; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} +a:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +a:hover, a:active { + outline: 0; +} +sub, sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} +sup { + top: -0.5em; +} +sub { + bottom: -0.25em; +} +img { + max-width: 100%; + height: auto; + border: 0; + -ms-interpolation-mode: bicubic; +} +button, +input, +select, +textarea { + margin: 0; + font-size: 100%; + vertical-align: middle; +} +button, input { + *overflow: visible; + line-height: normal; +} +button::-moz-focus-inner, input::-moz-focus-inner { + padding: 0; + border: 0; +} +button, +input[type="button"], +input[type="reset"], +input[type="submit"] { + cursor: pointer; + -webkit-appearance: button; +} +input[type="search"] { + -webkit-appearance: textfield; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +input[type="search"]::-webkit-search-decoration, input[type="search"]::-webkit-search-cancel-button { + -webkit-appearance: none; +} +textarea { + overflow: auto; + vertical-align: top; +} +.clearfix { + *zoom: 1; +} +.clearfix:before, .clearfix:after { + display: table; + content: ""; +} +.clearfix:after { + clear: both; +} +body { + margin: 0; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 18px; + color: #333333; + background-color: #ffffff; +} +a { + color: #0088cc; + text-decoration: none; +} +a:hover { + color: #005580; + text-decoration: underline; +} +.row { + margin-left: -20px; + *zoom: 1; +} +.row:before, .row:after { + display: table; + content: ""; +} +.row:after { + clear: both; +} +[class*="span"] { + float: left; + margin-left: 20px; +} +.span1 { + width: 60px; +} +.span2 { + width: 140px; +} +.span3 { + width: 220px; +} +.span4 { + width: 300px; +} +.span5 { + width: 380px; +} +.span6 { + width: 460px; +} +.span7 { + width: 540px; +} +.span8 { + width: 620px; +} +.span9 { + width: 700px; +} +.span10 { + width: 780px; +} +.span11 { + width: 860px; +} +.span12, .container { + width: 940px; +} +.offset1 { + margin-left: 100px; +} +.offset2 { + margin-left: 180px; +} +.offset3 { + margin-left: 260px; +} +.offset4 { + margin-left: 340px; +} +.offset5 { + margin-left: 420px; +} +.offset6 { + margin-left: 500px; +} +.offset7 { + margin-left: 580px; +} +.offset8 { + margin-left: 660px; +} +.offset9 { + margin-left: 740px; +} +.offset10 { + margin-left: 820px; +} +.offset11 { + margin-left: 900px; +} +.row-fluid { + width: 100%; + *zoom: 1; +} +.row-fluid:before, .row-fluid:after { + display: table; + content: ""; +} +.row-fluid:after { + clear: both; +} +.row-fluid > [class*="span"] { + float: left; + margin-left: 2.127659574%; +} +.row-fluid > [class*="span"]:first-child { + margin-left: 0; +} +.row-fluid > .span1 { + width: 6.382978723%; +} +.row-fluid > .span2 { + width: 14.89361702%; +} +.row-fluid > .span3 { + width: 23.404255317%; +} +.row-fluid > .span4 { + width: 31.914893614%; +} +.row-fluid > .span5 { + width: 40.425531911%; +} +.row-fluid > .span6 { + width: 48.93617020799999%; +} +.row-fluid > .span7 { + width: 57.446808505%; +} +.row-fluid > .span8 { + width: 65.95744680199999%; +} +.row-fluid > .span9 { + width: 74.468085099%; +} +.row-fluid > .span10 { + width: 82.97872339599999%; +} +.row-fluid > .span11 { + width: 91.489361693%; +} +.row-fluid > .span12 { + width: 99.99999998999999%; +} +.container { + width: 940px; + margin-left: auto; + margin-right: auto; + *zoom: 1; +} +.container:before, .container:after { + display: table; + content: ""; +} +.container:after { + clear: both; +} +.container-fluid { + padding-left: 20px; + padding-right: 20px; + *zoom: 1; +} +.container-fluid:before, .container-fluid:after { + display: table; + content: ""; +} +.container-fluid:after { + clear: both; +} +p { + margin: 0 0 9px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 18px; +} +p small { + font-size: 11px; + color: #999999; +} +.lead { + margin-bottom: 18px; + font-size: 20px; + font-weight: 200; + line-height: 27px; +} +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 0; + font-weight: bold; + color: #333333; + text-rendering: optimizelegibility; +} +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small { + font-weight: normal; + color: #999999; +} +h1 { + font-size: 30px; + line-height: 36px; +} +h1 small { + font-size: 18px; +} +h2 { + font-size: 24px; + line-height: 36px; +} +h2 small { + font-size: 18px; +} +h3 { + line-height: 27px; + font-size: 18px; +} +h3 small { + font-size: 14px; +} +h4, h5, h6 { + line-height: 18px; +} +h4 { + font-size: 14px; +} +h4 small { + font-size: 12px; +} +h5 { + font-size: 12px; +} +h6 { + font-size: 11px; + color: #999999; + text-transform: uppercase; +} +.page-header { + padding-bottom: 17px; + margin: 18px 0; + border-bottom: 1px solid #eeeeee; +} +.page-header h1 { + line-height: 1; +} +ul, ol { + padding: 0; + margin: 0 0 9px 25px; +} +ul ul, +ul ol, +ol ol, +ol ul { + margin-bottom: 0; +} +ul { + list-style: disc; +} +ol { + list-style: decimal; +} +li { + line-height: 18px; +} +ul.unstyled, ol.unstyled { + margin-left: 0; + list-style: none; +} +dl { + margin-bottom: 18px; +} +dt, dd { + line-height: 18px; +} +dt { + font-weight: bold; +} +dd { + margin-left: 9px; +} +hr { + margin: 18px 0; + border: 0; + border-top: 1px solid #eeeeee; + border-bottom: 1px solid #ffffff; +} +strong { + font-weight: bold; +} +em { + font-style: italic; +} +.muted { + color: #999999; +} +abbr { + font-size: 90%; + text-transform: uppercase; + border-bottom: 1px dotted #ddd; + cursor: help; +} +blockquote { + padding: 0 0 0 15px; + margin: 0 0 18px; + border-left: 5px solid #eeeeee; +} +blockquote p { + margin-bottom: 0; + font-size: 16px; + font-weight: 300; + line-height: 22.5px; +} +blockquote small { + display: block; + line-height: 18px; + color: #999999; +} +blockquote small:before { + content: '\2014 \00A0'; +} +blockquote.pull-right { + float: right; + padding-left: 0; + padding-right: 15px; + border-left: 0; + border-right: 5px solid #eeeeee; +} +blockquote.pull-right p, blockquote.pull-right small { + text-align: right; +} +q:before, +q:after, +blockquote:before, +blockquote:after { + content: ""; +} +address { + display: block; + margin-bottom: 18px; + line-height: 18px; + font-style: normal; +} +small { + font-size: 100%; +} +cite { + font-style: normal; +} +code, pre { + padding: 0 3px 2px; + font-family: Menlo, Monaco, "Courier New", monospace; + font-size: 12px; + color: #333333; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +code { + padding: 3px 4px; + color: #d14; + background-color: #f7f7f9; + border: 1px solid #e1e1e8; +} +pre { + display: block; + padding: 8.5px; + margin: 0 0 9px; + font-size: 12px; + line-height: 18px; + background-color: #f5f5f5; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.15); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + white-space: pre; + white-space: pre-wrap; + word-break: break-all; + word-wrap: break-word; +} +pre.prettyprint { + margin-bottom: 18px; +} +pre code { + padding: 0; + color: inherit; + background-color: transparent; + border: 0; +} +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} +form { + margin: 0 0 18px; +} +fieldset { + padding: 0; + margin: 0; + border: 0; +} +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 27px; + font-size: 19.5px; + line-height: 36px; + color: #333333; + border: 0; + border-bottom: 1px solid #eee; +} +legend small { + font-size: 13.5px; + color: #999999; +} +label, +input, +button, +select, +textarea { + font-size: 13px; + font-weight: normal; + line-height: 18px; +} +input, +button, +select, +textarea { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; +} +label { + display: block; + margin-bottom: 5px; + color: #333333; +} +input, +textarea, +select, +.uneditable-input { + display: inline-block; + width: 210px; + height: 18px; + padding: 4px; + margin-bottom: 9px; + font-size: 13px; + line-height: 18px; + color: #555555; + border: 1px solid #ccc; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.uneditable-textarea { + width: auto; + height: auto; +} +label input, label textarea, label select { + display: block; +} +input[type="image"], input[type="checkbox"], input[type="radio"] { + width: auto; + height: auto; + padding: 0; + margin: 3px 0; + *margin-top: 0; + /* IE7 */ + + line-height: normal; + cursor: pointer; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + border: 0 \9; + /* IE9 and down */ + +} +input[type="image"] { + border: 0; +} +input[type="file"] { + width: auto; + padding: initial; + line-height: initial; + border: initial; + background-color: #ffffff; + background-color: initial; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +input[type="button"], input[type="reset"], input[type="submit"] { + width: auto; + height: auto; +} +select, input[type="file"] { + height: 28px; + /* In IE7, the height of the select element cannot be changed by height, only font-size */ + + *margin-top: 4px; + /* For IE7, add top margin to align select with labels */ + + line-height: 28px; +} +input[type="file"] { + line-height: 18px \9; +} +select { + width: 220px; + background-color: #ffffff; +} +select[multiple], select[size] { + height: auto; +} +input[type="image"] { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +textarea { + height: auto; +} +input[type="hidden"] { + display: none; +} +.radio, .checkbox { + padding-left: 18px; +} +.radio input[type="radio"], .checkbox input[type="checkbox"] { + float: left; + margin-left: -18px; +} +.controls > .radio:first-child, .controls > .checkbox:first-child { + padding-top: 5px; +} +.radio.inline, .checkbox.inline { + display: inline-block; + padding-top: 5px; + margin-bottom: 0; + vertical-align: middle; +} +.radio.inline + .radio.inline, .checkbox.inline + .checkbox.inline { + margin-left: 10px; +} +input, textarea { + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; + -moz-transition: border linear 0.2s, box-shadow linear 0.2s; + -ms-transition: border linear 0.2s, box-shadow linear 0.2s; + -o-transition: border linear 0.2s, box-shadow linear 0.2s; + transition: border linear 0.2s, box-shadow linear 0.2s; +} +input:focus, textarea:focus { + border-color: rgba(82, 168, 236, 0.8); + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + outline: 0; + outline: thin dotted \9; + /* IE6-9 */ + +} +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus, +select:focus { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.input-mini { + width: 60px; +} +.input-small { + width: 90px; +} +.input-medium { + width: 150px; +} +.input-large { + width: 210px; +} +.input-xlarge { + width: 270px; +} +.input-xxlarge { + width: 530px; +} +input[class*="span"], +select[class*="span"], +textarea[class*="span"], +.uneditable-input { + float: none; + margin-left: 0; +} +input.span1, textarea.span1, .uneditable-input.span1 { + width: 50px; +} +input.span2, textarea.span2, .uneditable-input.span2 { + width: 130px; +} +input.span3, textarea.span3, .uneditable-input.span3 { + width: 210px; +} +input.span4, textarea.span4, .uneditable-input.span4 { + width: 290px; +} +input.span5, textarea.span5, .uneditable-input.span5 { + width: 370px; +} +input.span6, textarea.span6, .uneditable-input.span6 { + width: 450px; +} +input.span7, textarea.span7, .uneditable-input.span7 { + width: 530px; +} +input.span8, textarea.span8, .uneditable-input.span8 { + width: 610px; +} +input.span9, textarea.span9, .uneditable-input.span9 { + width: 690px; +} +input.span10, textarea.span10, .uneditable-input.span10 { + width: 770px; +} +input.span11, textarea.span11, .uneditable-input.span11 { + width: 850px; +} +input.span12, textarea.span12, .uneditable-input.span12 { + width: 930px; +} +input[disabled], +select[disabled], +textarea[disabled], +input[readonly], +select[readonly], +textarea[readonly] { + background-color: #f5f5f5; + border-color: #ddd; + cursor: not-allowed; +} +.control-group.warning > label, .control-group.warning .help-block, .control-group.warning .help-inline { + color: #c09853; +} +.control-group.warning input, .control-group.warning select, .control-group.warning textarea { + color: #c09853; + border-color: #c09853; +} +.control-group.warning input:focus, .control-group.warning select:focus, .control-group.warning textarea:focus { + border-color: #a47e3c; + -webkit-box-shadow: 0 0 6px #dbc59e; + -moz-box-shadow: 0 0 6px #dbc59e; + box-shadow: 0 0 6px #dbc59e; +} +.control-group.warning .input-prepend .add-on, .control-group.warning .input-append .add-on { + color: #c09853; + background-color: #fcf8e3; + border-color: #c09853; +} +.control-group.error > label, .control-group.error .help-block, .control-group.error .help-inline { + color: #b94a48; +} +.control-group.error input, .control-group.error select, .control-group.error textarea { + color: #b94a48; + border-color: #b94a48; +} +.control-group.error input:focus, .control-group.error select:focus, .control-group.error textarea:focus { + border-color: #953b39; + -webkit-box-shadow: 0 0 6px #d59392; + -moz-box-shadow: 0 0 6px #d59392; + box-shadow: 0 0 6px #d59392; +} +.control-group.error .input-prepend .add-on, .control-group.error .input-append .add-on { + color: #b94a48; + background-color: #f2dede; + border-color: #b94a48; +} +.control-group.success > label, .control-group.success .help-block, .control-group.success .help-inline { + color: #468847; +} +.control-group.success input, .control-group.success select, .control-group.success textarea { + color: #468847; + border-color: #468847; +} +.control-group.success input:focus, .control-group.success select:focus, .control-group.success textarea:focus { + border-color: #356635; + -webkit-box-shadow: 0 0 6px #7aba7b; + -moz-box-shadow: 0 0 6px #7aba7b; + box-shadow: 0 0 6px #7aba7b; +} +.control-group.success .input-prepend .add-on, .control-group.success .input-append .add-on { + color: #468847; + background-color: #dff0d8; + border-color: #468847; +} +input:focus:required:invalid, textarea:focus:required:invalid, select:focus:required:invalid { + color: #b94a48; + border-color: #ee5f5b; +} +input:focus:required:invalid:focus, textarea:focus:required:invalid:focus, select:focus:required:invalid:focus { + border-color: #e9322d; + -webkit-box-shadow: 0 0 6px #f8b9b7; + -moz-box-shadow: 0 0 6px #f8b9b7; + box-shadow: 0 0 6px #f8b9b7; +} +.form-actions { + padding: 17px 20px 18px; + margin-top: 18px; + margin-bottom: 18px; + background-color: #f5f5f5; + border-top: 1px solid #ddd; +} +.uneditable-input { + display: block; + background-color: #ffffff; + border-color: #eee; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + cursor: not-allowed; +} +:-moz-placeholder { + color: #999999; +} +::-webkit-input-placeholder { + color: #999999; +} +.help-block { + display: block; + margin-top: 5px; + margin-bottom: 0; + color: #999999; +} +.help-inline { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; + margin-bottom: 9px; + vertical-align: middle; + padding-left: 5px; +} +.input-prepend, .input-append { + margin-bottom: 5px; + *zoom: 1; +} +.input-prepend:before, +.input-append:before, +.input-prepend:after, +.input-append:after { + display: table; + content: ""; +} +.input-prepend:after, .input-append:after { + clear: both; +} +.input-prepend input, +.input-append input, +.input-prepend .uneditable-input, +.input-append .uneditable-input { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.input-prepend input:focus, +.input-append input:focus, +.input-prepend .uneditable-input:focus, +.input-append .uneditable-input:focus { + position: relative; + z-index: 2; +} +.input-prepend .uneditable-input, .input-append .uneditable-input { + border-left-color: #ccc; +} +.input-prepend .add-on, .input-append .add-on { + float: left; + display: block; + width: auto; + min-width: 16px; + height: 18px; + margin-right: -1px; + padding: 4px 5px; + font-weight: normal; + line-height: 18px; + color: #999999; + text-align: center; + text-shadow: 0 1px 0 #ffffff; + background-color: #f5f5f5; + border: 1px solid #ccc; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.input-prepend .active, .input-append .active { + background-color: #a9dba9; + border-color: #46a546; +} +.input-prepend .add-on { + *margin-top: 1px; + /* IE6-7 */ + +} +.input-append input, .input-append .uneditable-input { + float: left; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.input-append .uneditable-input { + border-left-color: #eee; + border-right-color: #ccc; +} +.input-append .add-on { + margin-right: 0; + margin-left: -1px; + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.input-append input:first-child { + *margin-left: -160px; +} +.input-append input:first-child + .add-on { + *margin-left: -21px; +} +.search-query { + padding-left: 14px; + padding-right: 14px; + margin-bottom: 0; + -webkit-border-radius: 14px; + -moz-border-radius: 14px; + border-radius: 14px; +} +.form-search input, +.form-inline input, +.form-horizontal input, +.form-search textarea, +.form-inline textarea, +.form-horizontal textarea, +.form-search select, +.form-inline select, +.form-horizontal select, +.form-search .help-inline, +.form-inline .help-inline, +.form-horizontal .help-inline, +.form-search .uneditable-input, +.form-inline .uneditable-input, +.form-horizontal .uneditable-input { + display: inline-block; + margin-bottom: 0; +} +.form-search .hide, .form-inline .hide, .form-horizontal .hide { + display: none; +} +.form-search label, +.form-inline label, +.form-search .input-append, +.form-inline .input-append, +.form-search .input-prepend, +.form-inline .input-prepend { + display: inline-block; +} +.form-search .input-append .add-on, +.form-inline .input-prepend .add-on, +.form-search .input-append .add-on, +.form-inline .input-prepend .add-on { + vertical-align: middle; +} +.form-search .radio, +.form-inline .radio, +.form-search .checkbox, +.form-inline .checkbox { + margin-bottom: 0; + vertical-align: middle; +} +.control-group { + margin-bottom: 9px; +} +legend + .control-group { + margin-top: 18px; + -webkit-margin-top-collapse: separate; +} +.form-horizontal .control-group { + margin-bottom: 18px; + *zoom: 1; +} +.form-horizontal .control-group:before, .form-horizontal .control-group:after { + display: table; + content: ""; +} +.form-horizontal .control-group:after { + clear: both; +} +.form-horizontal .control-label { + float: left; + width: 140px; + padding-top: 5px; + text-align: right; +} +.form-horizontal .controls { + margin-left: 160px; +} +.form-horizontal .form-actions { + padding-left: 160px; +} +table { + max-width: 100%; + border-collapse: collapse; + border-spacing: 0; +} +.table { + width: 100%; + margin-bottom: 18px; +} +.table th, .table td { + padding: 8px; + line-height: 18px; + text-align: left; + vertical-align: top; + border-top: 1px solid #ddd; +} +.table th { + font-weight: bold; +} +.table thead th { + vertical-align: bottom; +} +.table thead:first-child tr th, .table thead:first-child tr td { + border-top: 0; +} +.table tbody + tbody { + border-top: 2px solid #ddd; +} +.table-condensed th, .table-condensed td { + padding: 4px 5px; +} +.table-bordered { + border: 1px solid #ddd; + border-collapse: separate; + *border-collapse: collapsed; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.table-bordered th + th, +.table-bordered td + td, +.table-bordered th + td, +.table-bordered td + th { + border-left: 1px solid #ddd; +} +.table-bordered thead:first-child tr:first-child th, .table-bordered tbody:first-child tr:first-child th, .table-bordered tbody:first-child tr:first-child td { + border-top: 0; +} +.table-bordered thead:first-child tr:first-child th:first-child, .table-bordered tbody:first-child tr:first-child td:first-child { + -webkit-border-radius: 4px 0 0 0; + -moz-border-radius: 4px 0 0 0; + border-radius: 4px 0 0 0; +} +.table-bordered thead:first-child tr:first-child th:last-child, .table-bordered tbody:first-child tr:first-child td:last-child { + -webkit-border-radius: 0 4px 0 0; + -moz-border-radius: 0 4px 0 0; + border-radius: 0 4px 0 0; +} +.table-bordered thead:last-child tr:last-child th:first-child, .table-bordered tbody:last-child tr:last-child td:first-child { + -webkit-border-radius: 0 0 0 4px; + -moz-border-radius: 0 0 0 4px; + border-radius: 0 0 0 4px; +} +.table-bordered thead:last-child tr:last-child th:last-child, .table-bordered tbody:last-child tr:last-child td:last-child { + -webkit-border-radius: 0 0 4px 0; + -moz-border-radius: 0 0 4px 0; + border-radius: 0 0 4px 0; +} +.table-striped tbody tr:nth-child(odd) td, .table-striped tbody tr:nth-child(odd) th { + background-color: #f9f9f9; +} +.table tbody tr:hover td, .table tbody tr:hover th { + background-color: #f5f5f5; +} +table .span1 { + float: none; + width: 44px; + margin-left: 0; +} +table .span2 { + float: none; + width: 124px; + margin-left: 0; +} +table .span3 { + float: none; + width: 204px; + margin-left: 0; +} +table .span4 { + float: none; + width: 284px; + margin-left: 0; +} +table .span5 { + float: none; + width: 364px; + margin-left: 0; +} +table .span6 { + float: none; + width: 444px; + margin-left: 0; +} +table .span7 { + float: none; + width: 524px; + margin-left: 0; +} +table .span8 { + float: none; + width: 604px; + margin-left: 0; +} +table .span9 { + float: none; + width: 684px; + margin-left: 0; +} +table .span10 { + float: none; + width: 764px; + margin-left: 0; +} +table .span11 { + float: none; + width: 844px; + margin-left: 0; +} +table .span12 { + float: none; + width: 924px; + margin-left: 0; +} +[class^="icon-"], [class*=" icon-"] { + display: inline-block; + width: 14px; + height: 14px; + line-height: 14px; + vertical-align: text-top; + background-image: url("../img/glyphicons-halflings.png"); + background-position: 14px 14px; + background-repeat: no-repeat; + *margin-right: .3em; +} +[class^="icon-"]:last-child, [class*=" icon-"]:last-child { + *margin-left: 0; +} +.icon-white { + background-image: url("../img/glyphicons-halflings-white.png"); +} +.icon-glass { + background-position: 0 0; +} +.icon-music { + background-position: -24px 0; +} +.icon-search { + background-position: -48px 0; +} +.icon-envelope { + background-position: -72px 0; +} +.icon-heart { + background-position: -96px 0; +} +.icon-star { + background-position: -120px 0; +} +.icon-star-empty { + background-position: -144px 0; +} +.icon-user { + background-position: -168px 0; +} +.icon-film { + background-position: -192px 0; +} +.icon-th-large { + background-position: -216px 0; +} +.icon-th { + background-position: -240px 0; +} +.icon-th-list { + background-position: -264px 0; +} +.icon-ok { + background-position: -288px 0; +} +.icon-remove { + background-position: -312px 0; +} +.icon-zoom-in { + background-position: -336px 0; +} +.icon-zoom-out { + background-position: -360px 0; +} +.icon-off { + background-position: -384px 0; +} +.icon-signal { + background-position: -408px 0; +} +.icon-cog { + background-position: -432px 0; +} +.icon-trash { + background-position: -456px 0; +} +.icon-home { + background-position: 0 -24px; +} +.icon-file { + background-position: -24px -24px; +} +.icon-time { + background-position: -48px -24px; +} +.icon-road { + background-position: -72px -24px; +} +.icon-download-alt { + background-position: -96px -24px; +} +.icon-download { + background-position: -120px -24px; +} +.icon-upload { + background-position: -144px -24px; +} +.icon-inbox { + background-position: -168px -24px; +} +.icon-play-circle { + background-position: -192px -24px; +} +.icon-repeat { + background-position: -216px -24px; +} +.icon-refresh { + background-position: -240px -24px; +} +.icon-list-alt { + background-position: -264px -24px; +} +.icon-lock { + background-position: -287px -24px; +} +.icon-flag { + background-position: -312px -24px; +} +.icon-headphones { + background-position: -336px -24px; +} +.icon-volume-off { + background-position: -360px -24px; +} +.icon-volume-down { + background-position: -384px -24px; +} +.icon-volume-up { + background-position: -408px -24px; +} +.icon-qrcode { + background-position: -432px -24px; +} +.icon-barcode { + background-position: -456px -24px; +} +.icon-tag { + background-position: 0 -48px; +} +.icon-tags { + background-position: -25px -48px; +} +.icon-book { + background-position: -48px -48px; +} +.icon-bookmark { + background-position: -72px -48px; +} +.icon-print { + background-position: -96px -48px; +} +.icon-camera { + background-position: -120px -48px; +} +.icon-font { + background-position: -144px -48px; +} +.icon-bold { + background-position: -167px -48px; +} +.icon-italic { + background-position: -192px -48px; +} +.icon-text-height { + background-position: -216px -48px; +} +.icon-text-width { + background-position: -240px -48px; +} +.icon-align-left { + background-position: -264px -48px; +} +.icon-align-center { + background-position: -288px -48px; +} +.icon-align-right { + background-position: -312px -48px; +} +.icon-align-justify { + background-position: -336px -48px; +} +.icon-list { + background-position: -360px -48px; +} +.icon-indent-left { + background-position: -384px -48px; +} +.icon-indent-right { + background-position: -408px -48px; +} +.icon-facetime-video { + background-position: -432px -48px; +} +.icon-picture { + background-position: -456px -48px; +} +.icon-pencil { + background-position: 0 -72px; +} +.icon-map-marker { + background-position: -24px -72px; +} +.icon-adjust { + background-position: -48px -72px; +} +.icon-tint { + background-position: -72px -72px; +} +.icon-edit { + background-position: -96px -72px; +} +.icon-share { + background-position: -120px -72px; +} +.icon-check { + background-position: -144px -72px; +} +.icon-move { + background-position: -168px -72px; +} +.icon-step-backward { + background-position: -192px -72px; +} +.icon-fast-backward { + background-position: -216px -72px; +} +.icon-backward { + background-position: -240px -72px; +} +.icon-play { + background-position: -264px -72px; +} +.icon-pause { + background-position: -288px -72px; +} +.icon-stop { + background-position: -312px -72px; +} +.icon-forward { + background-position: -336px -72px; +} +.icon-fast-forward { + background-position: -360px -72px; +} +.icon-step-forward { + background-position: -384px -72px; +} +.icon-eject { + background-position: -408px -72px; +} +.icon-chevron-left { + background-position: -432px -72px; +} +.icon-chevron-right { + background-position: -456px -72px; +} +.icon-plus-sign { + background-position: 0 -96px; +} +.icon-minus-sign { + background-position: -24px -96px; +} +.icon-remove-sign { + background-position: -48px -96px; +} +.icon-ok-sign { + background-position: -72px -96px; +} +.icon-question-sign { + background-position: -96px -96px; +} +.icon-info-sign { + background-position: -120px -96px; +} +.icon-screenshot { + background-position: -144px -96px; +} +.icon-remove-circle { + background-position: -168px -96px; +} +.icon-ok-circle { + background-position: -192px -96px; +} +.icon-ban-circle { + background-position: -216px -96px; +} +.icon-arrow-left { + background-position: -240px -96px; +} +.icon-arrow-right { + background-position: -264px -96px; +} +.icon-arrow-up { + background-position: -289px -96px; +} +.icon-arrow-down { + background-position: -312px -96px; +} +.icon-share-alt { + background-position: -336px -96px; +} +.icon-resize-full { + background-position: -360px -96px; +} +.icon-resize-small { + background-position: -384px -96px; +} +.icon-plus { + background-position: -408px -96px; +} +.icon-minus { + background-position: -433px -96px; +} +.icon-asterisk { + background-position: -456px -96px; +} +.icon-exclamation-sign { + background-position: 0 -120px; +} +.icon-gift { + background-position: -24px -120px; +} +.icon-leaf { + background-position: -48px -120px; +} +.icon-fire { + background-position: -72px -120px; +} +.icon-eye-open { + background-position: -96px -120px; +} +.icon-eye-close { + background-position: -120px -120px; +} +.icon-warning-sign { + background-position: -144px -120px; +} +.icon-plane { + background-position: -168px -120px; +} +.icon-calendar { + background-position: -192px -120px; +} +.icon-random { + background-position: -216px -120px; +} +.icon-comment { + background-position: -240px -120px; +} +.icon-magnet { + background-position: -264px -120px; +} +.icon-chevron-up { + background-position: -288px -120px; +} +.icon-chevron-down { + background-position: -313px -119px; +} +.icon-retweet { + background-position: -336px -120px; +} +.icon-shopping-cart { + background-position: -360px -120px; +} +.icon-folder-close { + background-position: -384px -120px; +} +.icon-folder-open { + background-position: -408px -120px; +} +.icon-resize-vertical { + background-position: -432px -119px; +} +.icon-resize-horizontal { + background-position: -456px -118px; +} +.dropdown { + position: relative; +} +.dropdown-toggle { + *margin-bottom: -3px; +} +.dropdown-toggle:active, .open .dropdown-toggle { + outline: 0; +} +.caret { + display: inline-block; + width: 0; + height: 0; + text-indent: -99999px; + *text-indent: 0; + vertical-align: top; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 4px solid #000000; + opacity: 0.3; + filter: alpha(opacity=30); + content: "\2193"; +} +.dropdown .caret { + margin-top: 8px; + margin-left: 2px; +} +.dropdown:hover .caret, .open.dropdown .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + float: left; + display: none; + min-width: 160px; + _width: 160px; + padding: 4px 0; + margin: 0; + list-style: none; + background-color: #ffffff; + border-color: #ccc; + border-color: rgba(0, 0, 0, 0.2); + border-style: solid; + border-width: 1px; + -webkit-border-radius: 0 0 5px 5px; + -moz-border-radius: 0 0 5px 5px; + border-radius: 0 0 5px 5px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; + *border-right-width: 2px; + *border-bottom-width: 2px; +} +.dropdown-menu.bottom-up { + top: auto; + bottom: 100%; + margin-bottom: 2px; +} +.dropdown-menu .divider { + height: 1px; + margin: 5px 1px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #ffffff; + *width: 100%; + *margin: -5px 0 5px; +} +.dropdown-menu a { + display: block; + padding: 3px 15px; + clear: both; + font-weight: normal; + line-height: 18px; + color: #555555; + white-space: nowrap; +} +.dropdown-menu li > a:hover, .dropdown-menu .active > a, .dropdown-menu .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #0088cc; +} +.dropdown.open { + *z-index: 1000; +} +.dropdown.open .dropdown-toggle { + color: #ffffff; + background: #ccc; + background: rgba(0, 0, 0, 0.3); +} +.dropdown.open .dropdown-menu { + display: block; +} +.typeahead { + margin-top: 2px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #f5f5f5; + border: 1px solid #eee; + border: 1px solid rgba(0, 0, 0, 0.05); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 0, 0, 0.15); +} +.fade { + -webkit-transition: opacity 0.15s linear; + -moz-transition: opacity 0.15s linear; + -ms-transition: opacity 0.15s linear; + -o-transition: opacity 0.15s linear; + transition: opacity 0.15s linear; + opacity: 0; +} +.fade.in { + opacity: 1; +} +.collapse { + -webkit-transition: height 0.35s ease; + -moz-transition: height 0.35s ease; + -ms-transition: height 0.35s ease; + -o-transition: height 0.35s ease; + transition: height 0.35s ease; + position: relative; + overflow: hidden; + height: 0; +} +.collapse.in { + height: auto; +} +.close { + float: right; + font-size: 20px; + font-weight: bold; + line-height: 18px; + color: #000000; + text-shadow: 0 1px 0 #ffffff; + opacity: 0.2; + filter: alpha(opacity=20); +} +.close:hover { + color: #000000; + text-decoration: none; + opacity: 0.4; + filter: alpha(opacity=40); + cursor: pointer; +} +.btn { + display: inline-block; + padding: 4px 10px 4px; + margin-bottom: 0; + font-size: 13px; + line-height: 18px; + color: #333333; + text-align: center; + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); + vertical-align: middle; + background-color: #f5f5f5; + background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); + background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); + background-image: linear-gradient(top, #ffffff, #e6e6e6); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0); + border-color: #e6e6e6 #e6e6e6 #bfbfbf; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + border: 1px solid #ccc; + border-bottom-color: #bbb; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + cursor: pointer; + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + *margin-left: .3em; +} +.btn:hover, +.btn:active, +.btn.active, +.btn.disabled, +.btn[disabled] { + background-color: #e6e6e6; +} +.btn:active, .btn.active { + background-color: #cccccc \9; +} +.btn:first-child { + *margin-left: 0; +} +.btn:hover { + color: #333333; + text-decoration: none; + background-color: #e6e6e6; + background-position: 0 -15px; + -webkit-transition: background-position 0.1s linear; + -moz-transition: background-position 0.1s linear; + -ms-transition: background-position 0.1s linear; + -o-transition: background-position 0.1s linear; + transition: background-position 0.1s linear; +} +.btn:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.btn.active, .btn:active { + background-image: none; + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + background-color: #e6e6e6; + background-color: #d9d9d9 \9; + outline: 0; +} +.btn.disabled, .btn[disabled] { + cursor: default; + background-image: none; + background-color: #e6e6e6; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +.btn-large { + padding: 9px 14px; + font-size: 15px; + line-height: normal; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.btn-large [class^="icon-"] { + margin-top: 1px; +} +.btn-small { + padding: 5px 9px; + font-size: 11px; + line-height: 16px; +} +.btn-small [class^="icon-"] { + margin-top: -1px; +} +.btn-mini { + padding: 2px 6px; + font-size: 11px; + line-height: 14px; +} +.btn-primary, +.btn-primary:hover, +.btn-warning, +.btn-warning:hover, +.btn-danger, +.btn-danger:hover, +.btn-success, +.btn-success:hover, +.btn-info, +.btn-info:hover, +.btn-inverse, +.btn-inverse:hover { + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + color: #ffffff; +} +.btn-primary.active, +.btn-warning.active, +.btn-danger.active, +.btn-success.active, +.btn-info.active, +.btn-dark.active { + color: rgba(255, 255, 255, 0.75); +} +.btn-primary { + background-color: #006dcc; + background-image: -moz-linear-gradient(top, #0088cc, #0044cc); + background-image: -ms-linear-gradient(top, #0088cc, #0044cc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); + background-image: -o-linear-gradient(top, #0088cc, #0044cc); + background-image: linear-gradient(top, #0088cc, #0044cc); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); + border-color: #0044cc #0044cc #002a80; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-primary:hover, +.btn-primary:active, +.btn-primary.active, +.btn-primary.disabled, +.btn-primary[disabled] { + background-color: #0044cc; +} +.btn-primary:active, .btn-primary.active { + background-color: #003399 \9; +} +.btn-warning { + background-color: #faa732; + background-image: -moz-linear-gradient(top, #fbb450, #f89406); + background-image: -ms-linear-gradient(top, #fbb450, #f89406); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); + background-image: -webkit-linear-gradient(top, #fbb450, #f89406); + background-image: -o-linear-gradient(top, #fbb450, #f89406); + background-image: linear-gradient(top, #fbb450, #f89406); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0); + border-color: #f89406 #f89406 #ad6704; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-warning:hover, +.btn-warning:active, +.btn-warning.active, +.btn-warning.disabled, +.btn-warning[disabled] { + background-color: #f89406; +} +.btn-warning:active, .btn-warning.active { + background-color: #c67605 \9; +} +.btn-danger { + background-color: #da4f49; + background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -ms-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -o-linear-gradient(top, #ee5f5b, #bd362f); + background-image: linear-gradient(top, #ee5f5b, #bd362f); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0); + border-color: #bd362f #bd362f #802420; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-danger:hover, +.btn-danger:active, +.btn-danger.active, +.btn-danger.disabled, +.btn-danger[disabled] { + background-color: #bd362f; +} +.btn-danger:active, .btn-danger.active { + background-color: #942a25 \9; +} +.btn-success { + background-color: #5bb75b; + background-image: -moz-linear-gradient(top, #62c462, #51a351); + background-image: -ms-linear-gradient(top, #62c462, #51a351); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351)); + background-image: -webkit-linear-gradient(top, #62c462, #51a351); + background-image: -o-linear-gradient(top, #62c462, #51a351); + background-image: linear-gradient(top, #62c462, #51a351); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0); + border-color: #51a351 #51a351 #387038; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-success:hover, +.btn-success:active, +.btn-success.active, +.btn-success.disabled, +.btn-success[disabled] { + background-color: #51a351; +} +.btn-success:active, .btn-success.active { + background-color: #408140 \9; +} +.btn-info { + background-color: #49afcd; + background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -ms-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4)); + background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -o-linear-gradient(top, #5bc0de, #2f96b4); + background-image: linear-gradient(top, #5bc0de, #2f96b4); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0); + border-color: #2f96b4 #2f96b4 #1f6377; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-info:hover, +.btn-info:active, +.btn-info.active, +.btn-info.disabled, +.btn-info[disabled] { + background-color: #2f96b4; +} +.btn-info:active, .btn-info.active { + background-color: #24748c \9; +} +.btn-inverse { + background-color: #393939; + background-image: -moz-linear-gradient(top, #454545, #262626); + background-image: -ms-linear-gradient(top, #454545, #262626); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#454545), to(#262626)); + background-image: -webkit-linear-gradient(top, #454545, #262626); + background-image: -o-linear-gradient(top, #454545, #262626); + background-image: linear-gradient(top, #454545, #262626); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#454545', endColorstr='#262626', GradientType=0); + border-color: #262626 #262626 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-inverse:hover, +.btn-inverse:active, +.btn-inverse.active, +.btn-inverse.disabled, +.btn-inverse[disabled] { + background-color: #262626; +} +.btn-inverse:active, .btn-inverse.active { + background-color: #0c0c0c \9; +} +button.btn, input[type="submit"].btn { + *padding-top: 2px; + *padding-bottom: 2px; +} +button.btn::-moz-focus-inner, input[type="submit"].btn::-moz-focus-inner { + padding: 0; + border: 0; +} +button.btn.large, input[type="submit"].btn.large { + *padding-top: 7px; + *padding-bottom: 7px; +} +button.btn.small, input[type="submit"].btn.small { + *padding-top: 3px; + *padding-bottom: 3px; +} +.btn-group { + position: relative; + *zoom: 1; + *margin-left: .3em; +} +.btn-group:before, .btn-group:after { + display: table; + content: ""; +} +.btn-group:after { + clear: both; +} +.btn-group:first-child { + *margin-left: 0; +} +.btn-group + .btn-group { + margin-left: 5px; +} +.btn-toolbar { + margin-top: 9px; + margin-bottom: 9px; +} +.btn-toolbar .btn-group { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; +} +.btn-group .btn { + position: relative; + float: left; + margin-left: -1px; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.btn-group .btn:first-child { + margin-left: 0; + -webkit-border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; + border-top-left-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + border-bottom-left-radius: 4px; +} +.btn-group .btn:last-child, .btn-group .dropdown-toggle { + -webkit-border-top-right-radius: 4px; + -moz-border-radius-topright: 4px; + border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -moz-border-radius-bottomright: 4px; + border-bottom-right-radius: 4px; +} +.btn-group .btn.large:first-child { + margin-left: 0; + -webkit-border-top-left-radius: 6px; + -moz-border-radius-topleft: 6px; + border-top-left-radius: 6px; + -webkit-border-bottom-left-radius: 6px; + -moz-border-radius-bottomleft: 6px; + border-bottom-left-radius: 6px; +} +.btn-group .btn.large:last-child, .btn-group .large.dropdown-toggle { + -webkit-border-top-right-radius: 6px; + -moz-border-radius-topright: 6px; + border-top-right-radius: 6px; + -webkit-border-bottom-right-radius: 6px; + -moz-border-radius-bottomright: 6px; + border-bottom-right-radius: 6px; +} +.btn-group .btn:hover, +.btn-group .btn:focus, +.btn-group .btn:active, +.btn-group .btn.active { + z-index: 2; +} +.btn-group .dropdown-toggle:active, .btn-group.open .dropdown-toggle { + outline: 0; +} +.btn-group .dropdown-toggle { + padding-left: 8px; + padding-right: 8px; + -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + *padding-top: 5px; + *padding-bottom: 5px; +} +.btn-group.open { + *z-index: 1000; +} +.btn-group.open .dropdown-menu { + display: block; + margin-top: 1px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.btn-group.open .dropdown-toggle { + background-image: none; + -webkit-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); +} +.btn .caret { + margin-top: 7px; + margin-left: 0; +} +.btn:hover .caret, .open.btn-group .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.btn-primary .caret, +.btn-danger .caret, +.btn-info .caret, +.btn-success .caret, +.btn-inverse .caret { + border-top-color: #ffffff; + opacity: 0.75; + filter: alpha(opacity=75); +} +.btn-small .caret { + margin-top: 4px; +} +.alert { + padding: 8px 35px 8px 14px; + margin-bottom: 18px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + background-color: #fcf8e3; + border: 1px solid #fbeed5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.alert, .alert-heading { + color: #c09853; +} +.alert .close { + position: relative; + top: -2px; + right: -21px; + line-height: 18px; +} +.alert-success { + background-color: #dff0d8; + border-color: #d6e9c6; +} +.alert-success, .alert-success .alert-heading { + color: #468847; +} +.alert-danger, .alert-error { + background-color: #f2dede; + border-color: #eed3d7; +} +.alert-danger, +.alert-error, +.alert-danger .alert-heading, +.alert-error .alert-heading { + color: #b94a48; +} +.alert-info { + background-color: #d9edf7; + border-color: #bce8f1; +} +.alert-info, .alert-info .alert-heading { + color: #3a87ad; +} +.alert-block { + padding-top: 14px; + padding-bottom: 14px; +} +.alert-block > p, .alert-block > ul { + margin-bottom: 0; +} +.alert-block p + p { + margin-top: 5px; +} +.nav { + margin-left: 0; + margin-bottom: 18px; + list-style: none; +} +.nav > li > a { + display: block; +} +.nav > li > a:hover { + text-decoration: none; + background-color: #eeeeee; +} +.nav .nav-header { + display: block; + padding: 3px 15px; + font-size: 11px; + font-weight: bold; + line-height: 18px; + color: #999999; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + text-transform: uppercase; +} +.nav li + .nav-header { + margin-top: 9px; +} +.nav-list { + padding-left: 14px; + padding-right: 14px; + margin-bottom: 0; +} +.nav-list > li > a, .nav-list .nav-header { + margin-left: -15px; + margin-right: -15px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); +} +.nav-list > li > a { + padding: 3px 15px; +} +.nav-list .active > a, .nav-list .active > a:hover { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); + background-color: #0088cc; +} +.nav-list [class^="icon-"] { + margin-right: 2px; +} +.nav-tabs, .nav-pills { + *zoom: 1; +} +.nav-tabs:before, +.nav-pills:before, +.nav-tabs:after, +.nav-pills:after { + display: table; + content: ""; +} +.nav-tabs:after, .nav-pills:after { + clear: both; +} +.nav-tabs > li, .nav-pills > li { + float: left; +} +.nav-tabs > li > a, .nav-pills > li > a { + padding-right: 12px; + padding-left: 12px; + margin-right: 2px; + line-height: 14px; +} +.nav-tabs { + border-bottom: 1px solid #ddd; +} +.nav-tabs > li { + margin-bottom: -1px; +} +.nav-tabs > li > a { + padding-top: 9px; + padding-bottom: 9px; + border: 1px solid transparent; + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} +.nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #dddddd; +} +.nav-tabs > .active > a, .nav-tabs > .active > a:hover { + color: #555555; + background-color: #ffffff; + border: 1px solid #ddd; + border-bottom-color: transparent; + cursor: default; +} +.nav-pills > li > a { + padding-top: 8px; + padding-bottom: 8px; + margin-top: 2px; + margin-bottom: 2px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.nav-pills .active > a, .nav-pills .active > a:hover { + color: #ffffff; + background-color: #0088cc; +} +.nav-stacked > li { + float: none; +} +.nav-stacked > li > a { + margin-right: 0; +} +.nav-tabs.nav-stacked { + border-bottom: 0; +} +.nav-tabs.nav-stacked > li > a { + border: 1px solid #ddd; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.nav-tabs.nav-stacked > li:first-child > a { + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} +.nav-tabs.nav-stacked > li:last-child > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} +.nav-tabs.nav-stacked > li > a:hover { + border-color: #ddd; + z-index: 2; +} +.nav-pills.nav-stacked > li > a { + margin-bottom: 3px; +} +.nav-pills.nav-stacked > li:last-child > a { + margin-bottom: 1px; +} +.nav-tabs .dropdown-menu, .nav-pills .dropdown-menu { + margin-top: 1px; + border-width: 1px; +} +.nav-pills .dropdown-menu { + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.nav-tabs .dropdown-toggle .caret, .nav-pills .dropdown-toggle .caret { + border-top-color: #0088cc; + margin-top: 6px; +} +.nav-tabs .dropdown-toggle:hover .caret, .nav-pills .dropdown-toggle:hover .caret { + border-top-color: #005580; +} +.nav-tabs .active .dropdown-toggle .caret, .nav-pills .active .dropdown-toggle .caret { + border-top-color: #333333; +} +.nav > .dropdown.active > a:hover { + color: #000000; + cursor: pointer; +} +.nav-tabs .open .dropdown-toggle, .nav-pills .open .dropdown-toggle, .nav > .open.active > a:hover { + color: #ffffff; + background-color: #999999; + border-color: #999999; +} +.nav .open .caret, .nav .open.active .caret, .nav .open a:hover .caret { + border-top-color: #ffffff; + opacity: 1; + filter: alpha(opacity=100); +} +.tabs-stacked .open > a:hover { + border-color: #999999; +} +.tabbable { + *zoom: 1; +} +.tabbable:before, .tabbable:after { + display: table; + content: ""; +} +.tabbable:after { + clear: both; +} +.tab-content { + overflow: hidden; +} +.tabs-below .nav-tabs, .tabs-right .nav-tabs, .tabs-left .nav-tabs { + border-bottom: 0; +} +.tab-content > .tab-pane, .pill-content > .pill-pane { + display: none; +} +.tab-content > .active, .pill-content > .active { + display: block; +} +.tabs-below .nav-tabs { + border-top: 1px solid #ddd; +} +.tabs-below .nav-tabs > li { + margin-top: -1px; + margin-bottom: 0; +} +.tabs-below .nav-tabs > li > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} +.tabs-below .nav-tabs > li > a:hover { + border-bottom-color: transparent; + border-top-color: #ddd; +} +.tabs-below .nav-tabs .active > a, .tabs-below .nav-tabs .active > a:hover { + border-color: transparent #ddd #ddd #ddd; +} +.tabs-left .nav-tabs > li, .tabs-right .nav-tabs > li { + float: none; +} +.tabs-left .nav-tabs > li > a, .tabs-right .nav-tabs > li > a { + min-width: 74px; + margin-right: 0; + margin-bottom: 3px; +} +.tabs-left .nav-tabs { + float: left; + margin-right: 19px; + border-right: 1px solid #ddd; +} +.tabs-left .nav-tabs > li > a { + margin-right: -1px; + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} +.tabs-left .nav-tabs > li > a:hover { + border-color: #eeeeee #dddddd #eeeeee #eeeeee; +} +.tabs-left .nav-tabs .active > a, .tabs-left .nav-tabs .active > a:hover { + border-color: #ddd transparent #ddd #ddd; + *border-right-color: #ffffff; +} +.tabs-right .nav-tabs { + float: right; + margin-left: 19px; + border-left: 1px solid #ddd; +} +.tabs-right .nav-tabs > li > a { + margin-left: -1px; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} +.tabs-right .nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #eeeeee #dddddd; +} +.tabs-right .nav-tabs .active > a, .tabs-right .nav-tabs .active > a:hover { + border-color: #ddd #ddd #ddd transparent; + *border-left-color: #ffffff; +} +.navbar { + overflow: visible; + margin-bottom: 18px; +} +.navbar-inner { + padding-left: 20px; + padding-right: 20px; + background-color: #2c2c2c; + background-image: -moz-linear-gradient(top, #333333, #222222); + background-image: -ms-linear-gradient(top, #333333, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); + background-image: -webkit-linear-gradient(top, #333333, #222222); + background-image: -o-linear-gradient(top, #333333, #222222); + background-image: linear-gradient(top, #333333, #222222); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); +} +.btn-navbar { + display: none; + float: right; + padding: 7px 10px; + margin-left: 5px; + margin-right: 5px; + background-color: #2c2c2c; + background-image: -moz-linear-gradient(top, #333333, #222222); + background-image: -ms-linear-gradient(top, #333333, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); + background-image: -webkit-linear-gradient(top, #333333, #222222); + background-image: -o-linear-gradient(top, #333333, #222222); + background-image: linear-gradient(top, #333333, #222222); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); + border-color: #222222 #222222 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); +} +.btn-navbar:hover, +.btn-navbar:active, +.btn-navbar.active, +.btn-navbar.disabled, +.btn-navbar[disabled] { + background-color: #222222; +} +.btn-navbar:active, .btn-navbar.active { + background-color: #080808 \9; +} +.btn-navbar .icon-bar { + display: block; + width: 18px; + height: 2px; + background-color: #f5f5f5; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; + -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); +} +.btn-navbar .icon-bar + .icon-bar { + margin-top: 3px; +} +.nav-collapse.collapse { + height: auto; +} +.navbar .brand:hover { + text-decoration: none; +} +.navbar .brand { + float: left; + display: block; + padding: 8px 20px 12px; + margin-left: -20px; + font-size: 20px; + font-weight: 200; + line-height: 1; + color: #ffffff; +} +.navbar .navbar-text { + margin-bottom: 0; + line-height: 40px; + color: #999999; +} +.navbar .navbar-text a:hover { + color: #ffffff; + background-color: transparent; +} +.navbar .btn, .navbar .btn-group { + margin-top: 5px; +} +.navbar .btn-group .btn { + margin-top: 0; +} +.navbar-form { + margin-bottom: 0; + *zoom: 1; +} +.navbar-form:before, .navbar-form:after { + display: table; + content: ""; +} +.navbar-form:after { + clear: both; +} +.navbar-form input, .navbar-form select { + display: inline-block; + margin-top: 5px; + margin-bottom: 0; +} +.navbar-form .radio, .navbar-form .checkbox { + margin-top: 5px; +} +.navbar-form input[type="image"], .navbar-form input[type="checkbox"], .navbar-form input[type="radio"] { + margin-top: 3px; +} +.navbar-form .input-append, .navbar-form .input-prepend { + margin-top: 6px; + white-space: nowrap; +} +.navbar-form .input-append input, .navbar-form .input-prepend input { + margin-top: 0; +} +.navbar-search { + position: relative; + float: left; + margin-top: 6px; + margin-bottom: 0; +} +.navbar-search .search-query { + padding: 4px 9px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + font-weight: normal; + line-height: 1; + color: #ffffff; + color: rgba(255, 255, 255, 0.75); + background: #666; + background: rgba(255, 255, 255, 0.3); + border: 1px solid #111; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + -webkit-transition: none; + -moz-transition: none; + -ms-transition: none; + -o-transition: none; + transition: none; +} +.navbar-search .search-query :-moz-placeholder { + color: #eeeeee; +} +.navbar-search .search-query::-webkit-input-placeholder { + color: #eeeeee; +} +.navbar-search .search-query:hover { + color: #ffffff; + background-color: #999999; + background-color: rgba(255, 255, 255, 0.5); +} +.navbar-search .search-query:focus, .navbar-search .search-query.focused { + padding: 5px 10px; + color: #333333; + text-shadow: 0 1px 0 #ffffff; + background-color: #ffffff; + border: 0; + -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + outline: 0; +} +.navbar-fixed-top { + position: fixed; + top: 0; + right: 0; + left: 0; + z-index: 1030; +} +.navbar-fixed-top .navbar-inner { + padding-left: 0; + padding-right: 0; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.navbar .nav { + position: relative; + left: 0; + display: block; + float: left; + margin: 0 10px 0 0; +} +.navbar .nav.pull-right { + float: right; +} +.navbar .nav > li { + display: block; + float: left; +} +.navbar .nav > li > a { + float: none; + padding: 10px 10px 11px; + line-height: 19px; + color: #999999; + text-decoration: none; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.navbar .nav > li > a:hover { + background-color: transparent; + color: #ffffff; + text-decoration: none; +} +.navbar .nav .active > a, .navbar .nav .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #222222; +} +.navbar .divider-vertical { + height: 40px; + width: 1px; + margin: 0 9px; + overflow: hidden; + background-color: #222222; + border-right: 1px solid #333333; +} +.navbar .nav.pull-right { + margin-left: 10px; + margin-right: 0; +} +.navbar .dropdown-menu { + margin-top: 1px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.navbar .dropdown-menu:before { + content: ''; + display: inline-block; + border-left: 7px solid transparent; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-bottom-color: rgba(0, 0, 0, 0.2); + position: absolute; + top: -7px; + left: 9px; +} +.navbar .dropdown-menu:after { + content: ''; + display: inline-block; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid #ffffff; + position: absolute; + top: -6px; + left: 10px; +} +.navbar .nav .dropdown-toggle .caret, .navbar .nav .open.dropdown .caret { + border-top-color: #ffffff; +} +.navbar .nav .active .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.navbar .nav .open > .dropdown-toggle, .navbar .nav .active > .dropdown-toggle, .navbar .nav .open.active > .dropdown-toggle { + background-color: transparent; +} +.navbar .nav .active > .dropdown-toggle:hover { + color: #ffffff; +} +.navbar .nav.pull-right .dropdown-menu { + left: auto; + right: 0; +} +.navbar .nav.pull-right .dropdown-menu:before { + left: auto; + right: 12px; +} +.navbar .nav.pull-right .dropdown-menu:after { + left: auto; + right: 13px; +} +.breadcrumb { + padding: 7px 14px; + margin: 0 0 18px; + background-color: #fbfbfb; + background-image: -moz-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -ms-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5)); + background-image: -webkit-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -o-linear-gradient(top, #ffffff, #f5f5f5); + background-image: linear-gradient(top, #ffffff, #f5f5f5); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0); + border: 1px solid #ddd; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; +} +.breadcrumb li { + display: inline-block; + text-shadow: 0 1px 0 #ffffff; +} +.breadcrumb .divider { + padding: 0 5px; + color: #999999; +} +.breadcrumb .active a { + color: #333333; +} +.pagination { + height: 36px; + margin: 18px 0; +} +.pagination ul { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; + margin-left: 0; + margin-bottom: 0; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); +} +.pagination li { + display: inline; +} +.pagination a { + float: left; + padding: 0 14px; + line-height: 34px; + text-decoration: none; + border: 1px solid #ddd; + border-left-width: 0; +} +.pagination a:hover, .pagination .active a { + background-color: #f5f5f5; +} +.pagination .active a { + color: #999999; + cursor: default; +} +.pagination .disabled a, .pagination .disabled a:hover { + color: #999999; + background-color: transparent; + cursor: default; +} +.pagination li:first-child a { + border-left-width: 1px; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.pagination li:last-child a { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.pagination-centered { + text-align: center; +} +.pagination-right { + text-align: right; +} +.pager { + margin-left: 0; + margin-bottom: 18px; + list-style: none; + text-align: center; + *zoom: 1; +} +.pager:before, .pager:after { + display: table; + content: ""; +} +.pager:after { + clear: both; +} +.pager li { + display: inline; +} +.pager a { + display: inline-block; + padding: 5px 14px; + background-color: #fff; + border: 1px solid #ddd; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} +.pager a:hover { + text-decoration: none; + background-color: #f5f5f5; +} +.pager .next a { + float: right; +} +.pager .previous a { + float: left; +} +.modal-open .dropdown-menu { + z-index: 2050; +} +.modal-open .dropdown.open { + *z-index: 2050; +} +.modal-open .popover { + z-index: 2060; +} +.modal-open .tooltip { + z-index: 2070; +} +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + background-color: #000000; +} +.modal-backdrop.fade { + opacity: 0; +} +.modal-backdrop, .modal-backdrop.fade.in { + opacity: 0.8; + filter: alpha(opacity=80); +} +.modal { + position: fixed; + top: 50%; + left: 50%; + z-index: 1050; + max-height: 500px; + overflow: auto; + width: 560px; + margin: -250px 0 0 -280px; + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + /* IE6-7 */ + + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.wide-modal { + position: fixed; + top: 5%; + left: 5%; + z-index: 1050; + max-height: 90%; + overflow: auto; + width: 90%; + /*margin: -50px 0 0 -80px;*/ + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + /* IE6-7 */ + + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.modal.fade { + -webkit-transition: opacity .3s linear, top .3s ease-out; + -moz-transition: opacity .3s linear, top .3s ease-out; + -ms-transition: opacity .3s linear, top .3s ease-out; + -o-transition: opacity .3s linear, top .3s ease-out; + transition: opacity .3s linear, top .3s ease-out; + top: -25%; +} +.modal.fade.in { + top: 50%; +} +.modal-header { + padding: 9px 15px; + border-bottom: 1px solid #eee; +} +.modal-header .close { + margin-top: 2px; +} +.modal-body { + padding: 15px; +} +.modal-body .modal-form { + margin-bottom: 0; +} +.modal-footer { + padding: 14px 15px 15px; + margin-bottom: 0; + background-color: #f5f5f5; + border-top: 1px solid #ddd; + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; + *zoom: 1; +} +.modal-footer:before, .modal-footer:after { + display: table; + content: ""; +} +.modal-footer:after { + clear: both; +} +.modal-footer .btn { + float: right; + margin-left: 5px; + margin-bottom: 0; +} +.tooltip { + position: absolute; + z-index: 1020; + display: block; + visibility: visible; + padding: 5px; + font-size: 11px; + opacity: 0; + filter: alpha(opacity=0); +} +.tooltip.in { + opacity: 0.8; + filter: alpha(opacity=80); +} +.tooltip.top { + margin-top: -2px; +} +.tooltip.right { + margin-left: 2px; +} +.tooltip.bottom { + margin-top: 2px; +} +.tooltip.left { + margin-left: -2px; +} +.tooltip.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid #000000; +} +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #000000; +} +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-bottom: 5px solid #000000; +} +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-right: 5px solid #000000; +} +.tooltip-inner { + max-width: 200px; + padding: 3px 8px; + color: #ffffff; + text-align: center; + text-decoration: none; + background-color: #000000; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; +} +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1010; + display: none; + padding: 5px; +} +.popover.top { + margin-top: -5px; +} +.popover.right { + margin-left: 5px; +} +.popover.bottom { + margin-top: 5px; +} +.popover.left { + margin-left: -5px; +} +.popover.top .arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid #000000; +} +.popover.right .arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-right: 5px solid #000000; +} +.popover.bottom .arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-bottom: 5px solid #000000; +} +.popover.left .arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #000000; +} +.popover .arrow { + position: absolute; + width: 0; + height: 0; +} +.popover-inner { + padding: 3px; + width: 280px; + overflow: hidden; + background: #000000; + background: rgba(0, 0, 0, 0.8); + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); +} +.popover-title { + padding: 9px 15px; + line-height: 1; + background-color: #f5f5f5; + border-bottom: 1px solid #eee; + -webkit-border-radius: 3px 3px 0 0; + -moz-border-radius: 3px 3px 0 0; + border-radius: 3px 3px 0 0; +} +.popover-content { + padding: 14px; + background-color: #ffffff; + -webkit-border-radius: 0 0 3px 3px; + -moz-border-radius: 0 0 3px 3px; + border-radius: 0 0 3px 3px; + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.popover-content p, .popover-content ul, .popover-content ol { + margin-bottom: 0; +} +.thumbnails { + margin-left: -20px; + list-style: none; + *zoom: 1; +} +.thumbnails:before, .thumbnails:after { + display: table; + content: ""; +} +.thumbnails:after { + clear: both; +} +.thumbnails > li { + float: left; + margin: 0 0 18px 20px; +} +.thumbnail { + display: block; + padding: 4px; + line-height: 1; + border: 1px solid #ddd; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); +} +a.thumbnail:hover { + border-color: #0088cc; + -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); +} +.thumbnail > img { + display: block; + max-width: 100%; + margin-left: auto; + margin-right: auto; +} +.thumbnail .caption { + padding: 9px; +} +.label { + padding: 2px 4px 3px; + font-size: 11.049999999999999px; + font-weight: bold; + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #999999; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.label:hover { + color: #ffffff; + text-decoration: none; +} +.label-important { + background-color: #b94a48; +} +.label-important:hover { + background-color: #953b39; +} +.label-warning { + background-color: #f89406; +} +.label-warning:hover { + background-color: #c67605; +} +.label-success { + background-color: #468847; +} +.label-success:hover { + background-color: #356635; +} +.label-info { + background-color: #3a87ad; +} +.label-info:hover { + background-color: #2d6987; +} +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +@-moz-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +@keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +.progress { + overflow: hidden; + height: 18px; + margin-bottom: 18px; + background-color: #f7f7f7; + background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -ms-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9)); + background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: linear-gradient(top, #f5f5f5, #f9f9f9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0); + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.progress .bar { + width: 0%; + height: 18px; + color: #ffffff; + font-size: 12px; + text-align: center; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #0e90d2; + background-image: -moz-linear-gradient(top, #149bdf, #0480be); + background-image: -ms-linear-gradient(top, #149bdf, #0480be); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be)); + background-image: -webkit-linear-gradient(top, #149bdf, #0480be); + background-image: -o-linear-gradient(top, #149bdf, #0480be); + background-image: linear-gradient(top, #149bdf, #0480be); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0); + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition: width 0.6s ease; + -moz-transition: width 0.6s ease; + -ms-transition: width 0.6s ease; + -o-transition: width 0.6s ease; + transition: width 0.6s ease; +} +.progress-striped .bar { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + -webkit-background-size: 40px 40px; + -moz-background-size: 40px 40px; + -o-background-size: 40px 40px; + background-size: 40px 40px; +} +.progress.active .bar { + -webkit-animation: progress-bar-stripes 2s linear infinite; + -moz-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} +.progress-danger .bar { + background-color: #dd514c; + background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -o-linear-gradient(top, #ee5f5b, #c43c35); + background-image: linear-gradient(top, #ee5f5b, #c43c35); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0); +} +.progress-danger.progress-striped .bar { + background-color: #ee5f5b; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-success .bar { + background-color: #5eb95e; + background-image: -moz-linear-gradient(top, #62c462, #57a957); + background-image: -ms-linear-gradient(top, #62c462, #57a957); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957)); + background-image: -webkit-linear-gradient(top, #62c462, #57a957); + background-image: -o-linear-gradient(top, #62c462, #57a957); + background-image: linear-gradient(top, #62c462, #57a957); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0); +} +.progress-success.progress-striped .bar { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-info .bar { + background-color: #4bb1cf; + background-image: -moz-linear-gradient(top, #5bc0de, #339bb9); + background-image: -ms-linear-gradient(top, #5bc0de, #339bb9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9)); + background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9); + background-image: -o-linear-gradient(top, #5bc0de, #339bb9); + background-image: linear-gradient(top, #5bc0de, #339bb9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0); +} +.progress-info.progress-striped .bar { + background-color: #5bc0de; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.accordion { + margin-bottom: 18px; +} +.accordion-group { + margin-bottom: 2px; + border: 1px solid #e5e5e5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.accordion-heading { + border-bottom: 0; +} +.accordion-heading .accordion-toggle { + display: block; + padding: 8px 15px; +} +.accordion-inner { + padding: 9px 15px; + border-top: 1px solid #e5e5e5; +} +.carousel { + position: relative; + margin-bottom: 18px; + line-height: 1; +} +.carousel-inner { + overflow: hidden; + width: 100%; + position: relative; +} +.carousel .item { + display: none; + position: relative; + -webkit-transition: 0.6s ease-in-out left; + -moz-transition: 0.6s ease-in-out left; + -ms-transition: 0.6s ease-in-out left; + -o-transition: 0.6s ease-in-out left; + transition: 0.6s ease-in-out left; +} +.carousel .item > img { + display: block; + line-height: 1; +} +.carousel .active, .carousel .next, .carousel .prev { + display: block; +} +.carousel .active { + left: 0; +} +.carousel .next, .carousel .prev { + position: absolute; + top: 0; + width: 100%; +} +.carousel .next { + left: 100%; +} +.carousel .prev { + left: -100%; +} +.carousel .next.left, .carousel .prev.right { + left: 0; +} +.carousel .active.left { + left: -100%; +} +.carousel .active.right { + left: 100%; +} +.carousel-control { + position: absolute; + top: 40%; + left: 15px; + width: 40px; + height: 40px; + margin-top: -20px; + font-size: 60px; + font-weight: 100; + line-height: 30px; + color: #ffffff; + text-align: center; + background: #222222; + border: 3px solid #ffffff; + -webkit-border-radius: 23px; + -moz-border-radius: 23px; + border-radius: 23px; + opacity: 0.5; + filter: alpha(opacity=50); +} +.carousel-control.right { + left: auto; + right: 15px; +} +.carousel-control:hover { + color: #ffffff; + text-decoration: none; + opacity: 0.9; + filter: alpha(opacity=90); +} +.carousel-caption { + position: absolute; + left: 0; + right: 0; + bottom: 0; + padding: 10px 15px 5px; + background: #333333; + background: rgba(0, 0, 0, 0.75); +} +.carousel-caption h4, .carousel-caption p { + color: #ffffff; +} +.hero-unit { + padding: 60px; + margin-bottom: 30px; + background-color: #f5f5f5; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} +.hero-unit h1 { + margin-bottom: 0; + font-size: 60px; + line-height: 1; + letter-spacing: -1px; +} +.hero-unit p { + font-size: 18px; + font-weight: 200; + line-height: 27px; +} +.pull-right { + float: right; +} +.pull-left { + float: left; +} +.hide { + display: none; +} +.show { + display: block; +} +.invisible { + visibility: hidden; +} diff --git a/src/nl/astraeus/jdbc/web/resources/images/loading.gif b/src/nl/astraeus/jdbc/web/resources/images/loading.gif new file mode 100644 index 0000000..21c7e74 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/images/loading.gif Binary files differ diff --git a/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png b/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png new file mode 100644 index 0000000..92d4445 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png Binary files differ diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-alert.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-alert.js new file mode 100644 index 0000000..2242ddd --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-alert.js @@ -0,0 +1,94 @@ +/* ========================================================== + * bootstrap-alert.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#alerts + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function( $ ){ + + "use strict" + + /* ALERT CLASS DEFINITION + * ====================== */ + + var dismiss = '[data-dismiss="alert"]' + , Alert = function ( el ) { + $(el).on('click', dismiss, this.close) + } + + Alert.prototype = { + + constructor: Alert + + , close: function ( e ) { + var $this = $(this) + , selector = $this.attr('data-target') + , $parent + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = $(selector) + $parent.trigger('close') + + e && e.preventDefault() + + $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent()) + + $parent + .trigger('close') + .removeClass('in') + + function removeElement() { + $parent + .trigger('closed') + .remove() + } + + $.support.transition && $parent.hasClass('fade') ? + $parent.on($.support.transition.end, removeElement) : + removeElement() + } + + } + + + /* ALERT PLUGIN DEFINITION + * ======================= */ + + $.fn.alert = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('alert') + if (!data) $this.data('alert', (data = new Alert(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.alert.Constructor = Alert + + + /* ALERT DATA-API + * ============== */ + + $(function () { + $('body').on('click.alert.data-api', dismiss, Alert.prototype.close) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-button.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-button.js new file mode 100644 index 0000000..0238ca3 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-button.js @@ -0,0 +1,100 @@ +/* ============================================================ + * bootstrap-button.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#buttons + * ============================================================ + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + +!function( $ ){ + + "use strict" + + /* BUTTON PUBLIC CLASS DEFINITION + * ============================== */ + + var Button = function ( element, options ) { + this.$element = $(element) + this.options = $.extend({}, $.fn.button.defaults, options) + } + + Button.prototype = { + + constructor: Button + + , setState: function ( state ) { + var d = 'disabled' + , $el = this.$element + , data = $el.data() + , val = $el.is('input') ? 'val' : 'html' + + state = state + 'Text' + data.resetText || $el.data('resetText', $el[val]()) + + $el[val](data[state] || this.options[state]) + + // push to event loop to allow forms to submit + setTimeout(function () { + state == 'loadingText' ? + $el.addClass(d).attr(d, d) : + $el.removeClass(d).removeAttr(d) + }, 0) + } + + , toggle: function () { + var $parent = this.$element.parent('[data-toggle="buttons-radio"]') + + $parent && $parent + .find('.active') + .removeClass('active') + + this.$element.toggleClass('active') + } + + } + + + /* BUTTON PLUGIN DEFINITION + * ======================== */ + + $.fn.button = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('button') + , options = typeof option == 'object' && option + if (!data) $this.data('button', (data = new Button(this, options))) + if (option == 'toggle') data.toggle() + else if (option) data.setState(option) + }) + } + + $.fn.button.defaults = { + loadingText: 'loading...' + } + + $.fn.button.Constructor = Button + + + /* BUTTON DATA-API + * =============== */ + + $(function () { + $('body').on('click.button.data-api', '[data-toggle^=button]', function ( e ) { + var $btn = $(e.target) + if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') + $btn.button('toggle') + }) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-carousel.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-carousel.js new file mode 100644 index 0000000..810256e --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-carousel.js @@ -0,0 +1,157 @@ +/* ========================================================== + * bootstrap-carousel.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#carousel + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function( $ ){ + + "use strict" + + /* CAROUSEL CLASS DEFINITION + * ========================= */ + + var Carousel = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, $.fn.carousel.defaults, options) + this.options.slide && this.slide(this.options.slide) + } + + Carousel.prototype = { + + cycle: function () { + this.interval = setInterval($.proxy(this.next, this), this.options.interval) + return this + } + + , to: function (pos) { + var $active = this.$element.find('.active') + , children = $active.parent().children() + , activePos = children.index($active) + , that = this + + if (pos > (children.length - 1) || pos < 0) return + + if (this.sliding) { + return this.$element.one('slid', function () { + that.to(pos) + }) + } + + if (activePos == pos) { + return this.pause().cycle() + } + + return this.slide(pos > activePos ? 'next' : 'prev', $(children[pos])) + } + + , pause: function () { + clearInterval(this.interval) + this.interval = null + return this + } + + , next: function () { + if (this.sliding) return + return this.slide('next') + } + + , prev: function () { + if (this.sliding) return + return this.slide('prev') + } + + , slide: function (type, next) { + var $active = this.$element.find('.active') + , $next = next || $active[type]() + , isCycling = this.interval + , direction = type == 'next' ? 'left' : 'right' + , fallback = type == 'next' ? 'first' : 'last' + , that = this + + if (!$next.length) return + + this.sliding = true + + isCycling && this.pause() + + $next = $next.length ? $next : this.$element.find('.item')[fallback]() + + if (!$.support.transition && this.$element.hasClass('slide')) { + this.$element.trigger('slide') + $active.removeClass('active') + $next.addClass('active') + this.sliding = false + this.$element.trigger('slid') + } else { + $next.addClass(type) + $next[0].offsetWidth // force reflow + $active.addClass(direction) + $next.addClass(direction) + this.$element.trigger('slide') + this.$element.one($.support.transition.end, function () { + $next.removeClass([type, direction].join(' ')).addClass('active') + $active.removeClass(['active', direction].join(' ')) + that.sliding = false + setTimeout(function () { that.$element.trigger('slid') }, 0) + }) + } + + isCycling && this.cycle() + + return this + } + + } + + + /* CAROUSEL PLUGIN DEFINITION + * ========================== */ + + $.fn.carousel = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('carousel') + , options = typeof option == 'object' && option + if (!data) $this.data('carousel', (data = new Carousel(this, options))) + if (typeof option == 'number') data.to(option) + else if (typeof option == 'string' || (option = options.slide)) data[option]() + else data.cycle() + }) + } + + $.fn.carousel.defaults = { + interval: 5000 + } + + $.fn.carousel.Constructor = Carousel + + + /* CAROUSEL DATA-API + * ================= */ + + $(function () { + $('body').on('click.carousel.data-api', '[data-slide]', function ( e ) { + var $this = $(this), href + , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 + , options = !$target.data('modal') && $.extend({}, $target.data(), $this.data()) + $target.carousel(options) + e.preventDefault() + }) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-collapse.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-collapse.js new file mode 100644 index 0000000..d195efc --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-collapse.js @@ -0,0 +1,136 @@ +/* ============================================================= + * bootstrap-collapse.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#collapse + * ============================================================= + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + +!function( $ ){ + + "use strict" + + var Collapse = function ( element, options ) { + this.$element = $(element) + this.options = $.extend({}, $.fn.collapse.defaults, options) + + if (this.options["parent"]) { + this.$parent = $(this.options["parent"]) + } + + this.options.toggle && this.toggle() + } + + Collapse.prototype = { + + constructor: Collapse + + , dimension: function () { + var hasWidth = this.$element.hasClass('width') + return hasWidth ? 'width' : 'height' + } + + , show: function () { + var dimension = this.dimension() + , scroll = $.camelCase(['scroll', dimension].join('-')) + , actives = this.$parent && this.$parent.find('.in') + , hasData + + if (actives && actives.length) { + hasData = actives.data('collapse') + actives.collapse('hide') + hasData || actives.data('collapse', null) + } + + this.$element[dimension](0) + this.transition('addClass', 'show', 'shown') + this.$element[dimension](this.$element[0][scroll]) + + } + + , hide: function () { + var dimension = this.dimension() + this.reset(this.$element[dimension]()) + this.transition('removeClass', 'hide', 'hidden') + this.$element[dimension](0) + } + + , reset: function ( size ) { + var dimension = this.dimension() + + this.$element + .removeClass('collapse') + [dimension](size || 'auto') + [0].offsetWidth + + this.$element.addClass('collapse') + } + + , transition: function ( method, startEvent, completeEvent ) { + var that = this + , complete = function () { + if (startEvent == 'show') that.reset() + that.$element.trigger(completeEvent) + } + + this.$element + .trigger(startEvent) + [method]('in') + + $.support.transition && this.$element.hasClass('collapse') ? + this.$element.one($.support.transition.end, complete) : + complete() + } + + , toggle: function () { + this[this.$element.hasClass('in') ? 'hide' : 'show']() + } + + } + + /* COLLAPSIBLE PLUGIN DEFINITION + * ============================== */ + + $.fn.collapse = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('collapse') + , options = typeof option == 'object' && option + if (!data) $this.data('collapse', (data = new Collapse(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.collapse.defaults = { + toggle: true + } + + $.fn.collapse.Constructor = Collapse + + + /* COLLAPSIBLE DATA-API + * ==================== */ + + $(function () { + $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function ( e ) { + var $this = $(this), href + , target = $this.attr('data-target') + || e.preventDefault() + || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 + , option = $(target).data('collapse') ? 'toggle' : $this.data() + $(target).collapse(option) + }) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-dropdown.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-dropdown.js new file mode 100644 index 0000000..f1f6c33 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-dropdown.js @@ -0,0 +1,92 @@ +/* ============================================================ + * bootstrap-dropdown.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#dropdowns + * ============================================================ + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + + +!function( $ ){ + + "use strict" + + /* DROPDOWN CLASS DEFINITION + * ========================= */ + + var toggle = '[data-toggle="dropdown"]' + , Dropdown = function ( element ) { + var $el = $(element).on('click.dropdown.data-api', this.toggle) + $('html').on('click.dropdown.data-api', function () { + $el.parent().removeClass('open') + }) + } + + Dropdown.prototype = { + + constructor: Dropdown + + , toggle: function ( e ) { + var $this = $(this) + , selector = $this.attr('data-target') + , $parent + , isActive + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = $(selector) + $parent.length || ($parent = $this.parent()) + + isActive = $parent.hasClass('open') + + clearMenus() + !isActive && $parent.toggleClass('open') + + return false + } + + } + + function clearMenus() { + $(toggle).parent().removeClass('open') + } + + + /* DROPDOWN PLUGIN DEFINITION + * ========================== */ + + $.fn.dropdown = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('dropdown') + if (!data) $this.data('dropdown', (data = new Dropdown(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.dropdown.Constructor = Dropdown + + + /* APPLY TO STANDARD DROPDOWN ELEMENTS + * =================================== */ + + $(function () { + $('html').on('click.dropdown.data-api', clearMenus) + $('body').on('click.dropdown.data-api', toggle, Dropdown.prototype.toggle) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-modal.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-modal.js new file mode 100644 index 0000000..bceb303 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-modal.js @@ -0,0 +1,210 @@ +/* ========================================================= + * bootstrap-modal.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#modals + * ========================================================= + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================= */ + + +!function( $ ){ + + "use strict" + + /* MODAL CLASS DEFINITION + * ====================== */ + + var Modal = function ( content, options ) { + this.options = options + this.$element = $(content) + .delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this)) + } + + Modal.prototype = { + + constructor: Modal + + , toggle: function () { + return this[!this.isShown ? 'show' : 'hide']() + } + + , show: function () { + var that = this + + if (this.isShown) return + + $('body').addClass('modal-open') + + this.isShown = true + this.$element.trigger('show') + + escape.call(this) + backdrop.call(this, function () { + var transition = $.support.transition && that.$element.hasClass('fade') + + !that.$element.parent().length && that.$element.appendTo(document.body) //don't move modals dom position + + that.$element + .show() + + if (transition) { + that.$element[0].offsetWidth // force reflow + } + + that.$element.addClass('in') + + transition ? + that.$element.one($.support.transition.end, function () { that.$element.trigger('shown') }) : + that.$element.trigger('shown') + + }) + } + + , hide: function ( e ) { + e && e.preventDefault() + + if (!this.isShown) return + + var that = this + this.isShown = false + + $('body').removeClass('modal-open') + + escape.call(this) + + this.$element + .trigger('hide') + .removeClass('in') + + $.support.transition && this.$element.hasClass('fade') ? + hideWithTransition.call(this) : + hideModal.call(this) + } + + } + + + /* MODAL PRIVATE METHODS + * ===================== */ + + function hideWithTransition() { + var that = this + , timeout = setTimeout(function () { + that.$element.off($.support.transition.end) + hideModal.call(that) + }, 500) + + this.$element.one($.support.transition.end, function () { + clearTimeout(timeout) + hideModal.call(that) + }) + } + + function hideModal( that ) { + this.$element + .hide() + .trigger('hidden') + + backdrop.call(this) + } + + function backdrop( callback ) { + var that = this + , animate = this.$element.hasClass('fade') ? 'fade' : '' + + if (this.isShown && this.options.backdrop) { + var doAnimate = $.support.transition && animate + + this.$backdrop = $(' + + + + + \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/head.html b/src/nl/astraeus/jdbc/web/head.html new file mode 100644 index 0000000..0f8f6a3 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/head.html @@ -0,0 +1,96 @@ + + + + + + + Simple JDBC Statistics + + + + + + + + + + + + + + + + + + + +
+
+ +
+ diff --git a/src/nl/astraeus/jdbc/web/page/Menu.html b/src/nl/astraeus/jdbc/web/page/Menu.html new file mode 100644 index 0000000..505c7c2 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.html @@ -0,0 +1,42 @@ + diff --git a/src/nl/astraeus/jdbc/web/page/Menu.java b/src/nl/astraeus/jdbc/web/page/Menu.java new file mode 100644 index 0000000..f0a349a --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.java @@ -0,0 +1,27 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 9:07 PM + */ +public class Menu extends TemplatePage { + + @Override + public Page processRequest(HttpServletRequest request) { + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + result.put("user", request.getSession().getAttribute("user")); + + return result; + } +} diff --git a/src/nl/astraeus/jdbc/web/page/Page.java b/src/nl/astraeus/jdbc/web/page/Page.java new file mode 100644 index 0000000..9d526d6 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Page.java @@ -0,0 +1,17 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:20 PM + */ +public abstract class Page { + + public abstract Page processRequest(HttpServletRequest request); + public abstract Map defineModel(HttpServletRequest request); + public abstract String render(HttpServletRequest request); + +} diff --git a/src/nl/astraeus/jdbc/web/page/QueryOverview.html b/src/nl/astraeus/jdbc/web/page/QueryOverview.html new file mode 100644 index 0000000..64a88fb --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/QueryOverview.html @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + {foreach(queries as q)} + + + + + + + {eachend} + +
Total timeAvg. time# CallsSql
{q.total}{q.nano}{q.count}{q.sql}
diff --git a/src/nl/astraeus/jdbc/web/page/QueryOverview.java b/src/nl/astraeus/jdbc/web/page/QueryOverview.java new file mode 100644 index 0000000..02982f1 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/QueryOverview.java @@ -0,0 +1,92 @@ +package nl.astraeus.jdbc.web.page; + +import nl.astraeus.jdbc.JdbcLogger; + +import javax.servlet.http.HttpServletRequest; +import java.util.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 9:16 PM + */ +public class QueryOverview extends TemplatePage { + + boolean sortTotalCalls = true; + boolean sortAvgTime = false; + boolean sortTotalTime = false; + + @Override + public Page processRequest(HttpServletRequest request) { + if ("sortTotalCalls".equals(request.getParameter("action"))) { + sortTotalCalls = true; + sortAvgTime = false; + sortTotalTime = false; + } else if ("sortAvgTime".equals(request.getParameter("action"))) { + sortTotalCalls = false; + sortAvgTime = true; + sortTotalTime = false; + } else if ("sortTotalTime".equals(request.getParameter("action"))) { + sortTotalCalls = false; + sortAvgTime = false; + sortTotalTime = true; + } + + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + List entries = new ArrayList(JdbcLogger.get().getEntries()); + + if (sortTotalCalls) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + return o2.count - o1.count; + } + }); + } else if (sortAvgTime) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + long n1 = o1.nano / o1.count; + long n2 = o2.nano / o2.count; + + if (n2 > n1) { + return 1; + } else if (n2 < n1) { + return -1; + } else { + return 0; + } + } + }); + } else if (sortTotalTime) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + if (o2.nano > o1.nano) { + return 1; + } else if (o2.nano < o1.nano) { + return -1; + } else { + return 0; + } + } + }); + } + + result.put("queries", entries); + result.put("count", entries.size()); + + result.put("sortTotalCalls", sortTotalCalls); + result.put("sortAvgTime", sortAvgTime); + result.put("sortTotalTime", sortTotalTime); + + return result; + } + +} diff --git a/src/nl/astraeus/jdbc/web/page/TemplatePage.java b/src/nl/astraeus/jdbc/web/page/TemplatePage.java new file mode 100644 index 0000000..33e2641 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/TemplatePage.java @@ -0,0 +1,58 @@ +package nl.astraeus.jdbc.web.page; + +import nl.astraeus.template.EscapeMode; +import nl.astraeus.template.SimpleTemplate; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:20 PM + */ +public abstract class TemplatePage extends Page { + + private SimpleTemplate template; + + protected TemplatePage() { + template = getSimpleTemplate(this.getClass()); + } + + public String render(HttpServletRequest request) { + return template.render(defineModel(request)); + } + + private static Map templateCache = new HashMap(); + + public synchronized static SimpleTemplate getSimpleTemplate(Class cls) { + SimpleTemplate result = templateCache.get(cls); + + if (result == null) { + InputStream in = null; + + try { + in = cls.getResourceAsStream(cls.getSimpleName() + ".html"); + + result = SimpleTemplate.readTemplate('{','}', EscapeMode.HTML, in); + + templateCache.put(cls, result); + } catch (IOException e) { + throw new IllegalStateException(e); + } finally { + if (in != null) { + try { + in.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + + return result; + } +} diff --git a/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css b/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css new file mode 100644 index 0000000..0e0056f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css @@ -0,0 +1,581 @@ +/*! + * Bootstrap Responsive v2.0.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ +.clearfix { + *zoom: 1; +} +.clearfix:before, .clearfix:after { + display: table; + content: ""; +} +.clearfix:after { + clear: both; +} +.hidden { + display: none; + visibility: hidden; +} +@media (max-width: 480px) { + .nav-collapse { + -webkit-transform: translate3d(0, 0, 0); + } + .page-header h1 small { + display: block; + line-height: 18px; + } + input[class*="span"], + select[class*="span"], + textarea[class*="span"], + .uneditable-input { + display: block; + width: 100%; + min-height: 28px; + /* Make inputs at least the height of their button counterpart */ + + /* Makes inputs behave like true block-level elements */ + + -webkit-box-sizing: border-box; + /* Older Webkit */ + + -moz-box-sizing: border-box; + /* Older FF */ + + -ms-box-sizing: border-box; + /* IE8 */ + + box-sizing: border-box; + /* CSS3 spec*/ + + } + .input-prepend input[class*="span"], .input-append input[class*="span"] { + width: auto; + } + input[type="checkbox"], input[type="radio"] { + border: 1px solid #ccc; + } + .form-horizontal .control-group > label { + float: none; + width: auto; + padding-top: 0; + text-align: left; + } + .form-horizontal .controls { + margin-left: 0; + } + .form-horizontal .control-list { + padding-top: 0; + } + .form-horizontal .form-actions { + padding-left: 10px; + padding-right: 10px; + } + .modal { + position: absolute; + top: 10px; + left: 10px; + right: 10px; + width: auto; + margin: 0; + } + .modal.fade.in { + top: auto; + } + .modal-header .close { + padding: 10px; + margin: -10px; + } + .carousel-caption { + position: static; + } +} +@media (max-width: 767px) { + .container { + width: auto; + padding: 0 20px; + } + .row-fluid { + width: 100%; + } + .row { + margin-left: 0; + } + .row > [class*="span"], .row-fluid > [class*="span"] { + float: none; + display: block; + width: auto; + margin: 0; + } +} +@media (min-width: 768px) and (max-width: 979px) { + .row { + margin-left: -20px; + *zoom: 1; + } + .row:before, .row:after { + display: table; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + margin-left: 20px; + } + .span1 { + width: 42px; + } + .span2 { + width: 104px; + } + .span3 { + width: 166px; + } + .span4 { + width: 228px; + } + .span5 { + width: 290px; + } + .span6 { + width: 352px; + } + .span7 { + width: 414px; + } + .span8 { + width: 476px; + } + .span9 { + width: 538px; + } + .span10 { + width: 600px; + } + .span11 { + width: 662px; + } + .span12, .container { + width: 724px; + } + .offset1 { + margin-left: 82px; + } + .offset2 { + margin-left: 144px; + } + .offset3 { + margin-left: 206px; + } + .offset4 { + margin-left: 268px; + } + .offset5 { + margin-left: 330px; + } + .offset6 { + margin-left: 392px; + } + .offset7 { + margin-left: 454px; + } + .offset8 { + margin-left: 516px; + } + .offset9 { + margin-left: 578px; + } + .offset10 { + margin-left: 640px; + } + .offset11 { + margin-left: 702px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, .row-fluid:after { + display: table; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid > [class*="span"] { + float: left; + margin-left: 2.762430939%; + } + .row-fluid > [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid > .span1 { + width: 5.801104972%; + } + .row-fluid > .span2 { + width: 14.364640883%; + } + .row-fluid > .span3 { + width: 22.928176794%; + } + .row-fluid > .span4 { + width: 31.491712705%; + } + .row-fluid > .span5 { + width: 40.055248616%; + } + .row-fluid > .span6 { + width: 48.618784527%; + } + .row-fluid > .span7 { + width: 57.182320438000005%; + } + .row-fluid > .span8 { + width: 65.74585634900001%; + } + .row-fluid > .span9 { + width: 74.30939226%; + } + .row-fluid > .span10 { + width: 82.87292817100001%; + } + .row-fluid > .span11 { + width: 91.436464082%; + } + .row-fluid > .span12 { + width: 99.999999993%; + } + input.span1, textarea.span1, .uneditable-input.span1 { + width: 32px; + } + input.span2, textarea.span2, .uneditable-input.span2 { + width: 94px; + } + input.span3, textarea.span3, .uneditable-input.span3 { + width: 156px; + } + input.span4, textarea.span4, .uneditable-input.span4 { + width: 218px; + } + input.span5, textarea.span5, .uneditable-input.span5 { + width: 280px; + } + input.span6, textarea.span6, .uneditable-input.span6 { + width: 342px; + } + input.span7, textarea.span7, .uneditable-input.span7 { + width: 404px; + } + input.span8, textarea.span8, .uneditable-input.span8 { + width: 466px; + } + input.span9, textarea.span9, .uneditable-input.span9 { + width: 528px; + } + input.span10, textarea.span10, .uneditable-input.span10 { + width: 590px; + } + input.span11, textarea.span11, .uneditable-input.span11 { + width: 652px; + } + input.span12, textarea.span12, .uneditable-input.span12 { + width: 714px; + } +} +@media (max-width: 979px) { + body { + padding-top: 0; + } + .navbar-fixed-top { + position: static; + margin-bottom: 18px; + } + .navbar-fixed-top .navbar-inner { + padding: 5px; + } + .navbar .container { + width: auto; + padding: 0; + } + .navbar .brand { + padding-left: 10px; + padding-right: 10px; + margin: 0 0 0 -5px; + } + .navbar .nav-collapse { + clear: left; + } + .navbar .nav { + float: none; + margin: 0 0 9px; + } + .navbar .nav > li { + float: none; + } + .navbar .nav > li > a { + margin-bottom: 2px; + } + .navbar .nav > .divider-vertical { + display: none; + } + .navbar .nav .nav-header { + color: #999999; + text-shadow: none; + } + .navbar .nav > li > a, .navbar .dropdown-menu a { + padding: 6px 15px; + font-weight: bold; + color: #999999; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + } + .navbar .dropdown-menu li + li a { + margin-bottom: 2px; + } + .navbar .nav > li > a:hover, .navbar .dropdown-menu a:hover { + background-color: #222222; + } + .navbar .dropdown-menu { + position: static; + top: auto; + left: auto; + float: none; + display: block; + max-width: none; + margin: 0 15px; + padding: 0; + background-color: transparent; + border: none; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + } + .navbar .dropdown-menu:before, .navbar .dropdown-menu:after { + display: none; + } + .navbar .dropdown-menu .divider { + display: none; + } + .navbar-form, .navbar-search { + float: none; + padding: 9px 15px; + margin: 9px 0; + border-top: 1px solid #222222; + border-bottom: 1px solid #222222; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + } + .navbar .nav.pull-right { + float: none; + margin-left: 0; + } + .navbar-static .navbar-inner { + padding-left: 10px; + padding-right: 10px; + } + .btn-navbar { + display: block; + } + .nav-collapse { + overflow: hidden; + height: 0; + } +} +@media (min-width: 980px) { + .nav-collapse.collapse { + height: auto !important; + } +} +@media (min-width: 1200px) { + .row { + margin-left: -30px; + *zoom: 1; + } + .row:before, .row:after { + display: table; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + margin-left: 30px; + } + .span1 { + width: 70px; + } + .span2 { + width: 170px; + } + .span3 { + width: 270px; + } + .span4 { + width: 370px; + } + .span5 { + width: 470px; + } + .span6 { + width: 570px; + } + .span7 { + width: 670px; + } + .span8 { + width: 770px; + } + .span9 { + width: 870px; + } + .span10 { + width: 970px; + } + .span11 { + width: 1070px; + } + .span12, .container { + width: 1170px; + } + .offset1 { + margin-left: 130px; + } + .offset2 { + margin-left: 230px; + } + .offset3 { + margin-left: 330px; + } + .offset4 { + margin-left: 430px; + } + .offset5 { + margin-left: 530px; + } + .offset6 { + margin-left: 630px; + } + .offset7 { + margin-left: 730px; + } + .offset8 { + margin-left: 830px; + } + .offset9 { + margin-left: 930px; + } + .offset10 { + margin-left: 1030px; + } + .offset11 { + margin-left: 1130px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, .row-fluid:after { + display: table; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid > [class*="span"] { + float: left; + margin-left: 2.564102564%; + } + .row-fluid > [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid > .span1 { + width: 5.982905983%; + } + .row-fluid > .span2 { + width: 14.529914530000001%; + } + .row-fluid > .span3 { + width: 23.076923077%; + } + .row-fluid > .span4 { + width: 31.623931624%; + } + .row-fluid > .span5 { + width: 40.170940171000005%; + } + .row-fluid > .span6 { + width: 48.717948718%; + } + .row-fluid > .span7 { + width: 57.264957265%; + } + .row-fluid > .span8 { + width: 65.81196581200001%; + } + .row-fluid > .span9 { + width: 74.358974359%; + } + .row-fluid > .span10 { + width: 82.905982906%; + } + .row-fluid > .span11 { + width: 91.45299145300001%; + } + .row-fluid > .span12 { + width: 100%; + } + input.span1, textarea.span1, .uneditable-input.span1 { + width: 60px; + } + input.span2, textarea.span2, .uneditable-input.span2 { + width: 160px; + } + input.span3, textarea.span3, .uneditable-input.span3 { + width: 260px; + } + input.span4, textarea.span4, .uneditable-input.span4 { + width: 360px; + } + input.span5, textarea.span5, .uneditable-input.span5 { + width: 460px; + } + input.span6, textarea.span6, .uneditable-input.span6 { + width: 560px; + } + input.span7, textarea.span7, .uneditable-input.span7 { + width: 660px; + } + input.span8, textarea.span8, .uneditable-input.span8 { + width: 760px; + } + input.span9, textarea.span9, .uneditable-input.span9 { + width: 860px; + } + input.span10, textarea.span10, .uneditable-input.span10 { + width: 960px; + } + input.span11, textarea.span11, .uneditable-input.span11 { + width: 1060px; + } + input.span12, textarea.span12, .uneditable-input.span12 { + width: 1160px; + } + .thumbnails { + margin-left: -30px; + } + .thumbnails > li { + margin-left: 30px; + } +} diff --git a/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css b/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css new file mode 100644 index 0000000..6229c12 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css @@ -0,0 +1,3521 @@ +/*! + * Bootstrap v2.0.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +nav, +section { + display: block; +} +audio, canvas, video { + display: inline-block; + *display: inline; + *zoom: 1; +} +audio:not([controls]) { + display: none; +} +html { + font-size: 100%; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} +a:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +a:hover, a:active { + outline: 0; +} +sub, sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} +sup { + top: -0.5em; +} +sub { + bottom: -0.25em; +} +img { + max-width: 100%; + height: auto; + border: 0; + -ms-interpolation-mode: bicubic; +} +button, +input, +select, +textarea { + margin: 0; + font-size: 100%; + vertical-align: middle; +} +button, input { + *overflow: visible; + line-height: normal; +} +button::-moz-focus-inner, input::-moz-focus-inner { + padding: 0; + border: 0; +} +button, +input[type="button"], +input[type="reset"], +input[type="submit"] { + cursor: pointer; + -webkit-appearance: button; +} +input[type="search"] { + -webkit-appearance: textfield; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +input[type="search"]::-webkit-search-decoration, input[type="search"]::-webkit-search-cancel-button { + -webkit-appearance: none; +} +textarea { + overflow: auto; + vertical-align: top; +} +.clearfix { + *zoom: 1; +} +.clearfix:before, .clearfix:after { + display: table; + content: ""; +} +.clearfix:after { + clear: both; +} +body { + margin: 0; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 18px; + color: #333333; + background-color: #ffffff; +} +a { + color: #0088cc; + text-decoration: none; +} +a:hover { + color: #005580; + text-decoration: underline; +} +.row { + margin-left: -20px; + *zoom: 1; +} +.row:before, .row:after { + display: table; + content: ""; +} +.row:after { + clear: both; +} +[class*="span"] { + float: left; + margin-left: 20px; +} +.span1 { + width: 60px; +} +.span2 { + width: 140px; +} +.span3 { + width: 220px; +} +.span4 { + width: 300px; +} +.span5 { + width: 380px; +} +.span6 { + width: 460px; +} +.span7 { + width: 540px; +} +.span8 { + width: 620px; +} +.span9 { + width: 700px; +} +.span10 { + width: 780px; +} +.span11 { + width: 860px; +} +.span12, .container { + width: 940px; +} +.offset1 { + margin-left: 100px; +} +.offset2 { + margin-left: 180px; +} +.offset3 { + margin-left: 260px; +} +.offset4 { + margin-left: 340px; +} +.offset5 { + margin-left: 420px; +} +.offset6 { + margin-left: 500px; +} +.offset7 { + margin-left: 580px; +} +.offset8 { + margin-left: 660px; +} +.offset9 { + margin-left: 740px; +} +.offset10 { + margin-left: 820px; +} +.offset11 { + margin-left: 900px; +} +.row-fluid { + width: 100%; + *zoom: 1; +} +.row-fluid:before, .row-fluid:after { + display: table; + content: ""; +} +.row-fluid:after { + clear: both; +} +.row-fluid > [class*="span"] { + float: left; + margin-left: 2.127659574%; +} +.row-fluid > [class*="span"]:first-child { + margin-left: 0; +} +.row-fluid > .span1 { + width: 6.382978723%; +} +.row-fluid > .span2 { + width: 14.89361702%; +} +.row-fluid > .span3 { + width: 23.404255317%; +} +.row-fluid > .span4 { + width: 31.914893614%; +} +.row-fluid > .span5 { + width: 40.425531911%; +} +.row-fluid > .span6 { + width: 48.93617020799999%; +} +.row-fluid > .span7 { + width: 57.446808505%; +} +.row-fluid > .span8 { + width: 65.95744680199999%; +} +.row-fluid > .span9 { + width: 74.468085099%; +} +.row-fluid > .span10 { + width: 82.97872339599999%; +} +.row-fluid > .span11 { + width: 91.489361693%; +} +.row-fluid > .span12 { + width: 99.99999998999999%; +} +.container { + width: 940px; + margin-left: auto; + margin-right: auto; + *zoom: 1; +} +.container:before, .container:after { + display: table; + content: ""; +} +.container:after { + clear: both; +} +.container-fluid { + padding-left: 20px; + padding-right: 20px; + *zoom: 1; +} +.container-fluid:before, .container-fluid:after { + display: table; + content: ""; +} +.container-fluid:after { + clear: both; +} +p { + margin: 0 0 9px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 18px; +} +p small { + font-size: 11px; + color: #999999; +} +.lead { + margin-bottom: 18px; + font-size: 20px; + font-weight: 200; + line-height: 27px; +} +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 0; + font-weight: bold; + color: #333333; + text-rendering: optimizelegibility; +} +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small { + font-weight: normal; + color: #999999; +} +h1 { + font-size: 30px; + line-height: 36px; +} +h1 small { + font-size: 18px; +} +h2 { + font-size: 24px; + line-height: 36px; +} +h2 small { + font-size: 18px; +} +h3 { + line-height: 27px; + font-size: 18px; +} +h3 small { + font-size: 14px; +} +h4, h5, h6 { + line-height: 18px; +} +h4 { + font-size: 14px; +} +h4 small { + font-size: 12px; +} +h5 { + font-size: 12px; +} +h6 { + font-size: 11px; + color: #999999; + text-transform: uppercase; +} +.page-header { + padding-bottom: 17px; + margin: 18px 0; + border-bottom: 1px solid #eeeeee; +} +.page-header h1 { + line-height: 1; +} +ul, ol { + padding: 0; + margin: 0 0 9px 25px; +} +ul ul, +ul ol, +ol ol, +ol ul { + margin-bottom: 0; +} +ul { + list-style: disc; +} +ol { + list-style: decimal; +} +li { + line-height: 18px; +} +ul.unstyled, ol.unstyled { + margin-left: 0; + list-style: none; +} +dl { + margin-bottom: 18px; +} +dt, dd { + line-height: 18px; +} +dt { + font-weight: bold; +} +dd { + margin-left: 9px; +} +hr { + margin: 18px 0; + border: 0; + border-top: 1px solid #eeeeee; + border-bottom: 1px solid #ffffff; +} +strong { + font-weight: bold; +} +em { + font-style: italic; +} +.muted { + color: #999999; +} +abbr { + font-size: 90%; + text-transform: uppercase; + border-bottom: 1px dotted #ddd; + cursor: help; +} +blockquote { + padding: 0 0 0 15px; + margin: 0 0 18px; + border-left: 5px solid #eeeeee; +} +blockquote p { + margin-bottom: 0; + font-size: 16px; + font-weight: 300; + line-height: 22.5px; +} +blockquote small { + display: block; + line-height: 18px; + color: #999999; +} +blockquote small:before { + content: '\2014 \00A0'; +} +blockquote.pull-right { + float: right; + padding-left: 0; + padding-right: 15px; + border-left: 0; + border-right: 5px solid #eeeeee; +} +blockquote.pull-right p, blockquote.pull-right small { + text-align: right; +} +q:before, +q:after, +blockquote:before, +blockquote:after { + content: ""; +} +address { + display: block; + margin-bottom: 18px; + line-height: 18px; + font-style: normal; +} +small { + font-size: 100%; +} +cite { + font-style: normal; +} +code, pre { + padding: 0 3px 2px; + font-family: Menlo, Monaco, "Courier New", monospace; + font-size: 12px; + color: #333333; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +code { + padding: 3px 4px; + color: #d14; + background-color: #f7f7f9; + border: 1px solid #e1e1e8; +} +pre { + display: block; + padding: 8.5px; + margin: 0 0 9px; + font-size: 12px; + line-height: 18px; + background-color: #f5f5f5; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.15); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + white-space: pre; + white-space: pre-wrap; + word-break: break-all; + word-wrap: break-word; +} +pre.prettyprint { + margin-bottom: 18px; +} +pre code { + padding: 0; + color: inherit; + background-color: transparent; + border: 0; +} +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} +form { + margin: 0 0 18px; +} +fieldset { + padding: 0; + margin: 0; + border: 0; +} +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 27px; + font-size: 19.5px; + line-height: 36px; + color: #333333; + border: 0; + border-bottom: 1px solid #eee; +} +legend small { + font-size: 13.5px; + color: #999999; +} +label, +input, +button, +select, +textarea { + font-size: 13px; + font-weight: normal; + line-height: 18px; +} +input, +button, +select, +textarea { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; +} +label { + display: block; + margin-bottom: 5px; + color: #333333; +} +input, +textarea, +select, +.uneditable-input { + display: inline-block; + width: 210px; + height: 18px; + padding: 4px; + margin-bottom: 9px; + font-size: 13px; + line-height: 18px; + color: #555555; + border: 1px solid #ccc; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.uneditable-textarea { + width: auto; + height: auto; +} +label input, label textarea, label select { + display: block; +} +input[type="image"], input[type="checkbox"], input[type="radio"] { + width: auto; + height: auto; + padding: 0; + margin: 3px 0; + *margin-top: 0; + /* IE7 */ + + line-height: normal; + cursor: pointer; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + border: 0 \9; + /* IE9 and down */ + +} +input[type="image"] { + border: 0; +} +input[type="file"] { + width: auto; + padding: initial; + line-height: initial; + border: initial; + background-color: #ffffff; + background-color: initial; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +input[type="button"], input[type="reset"], input[type="submit"] { + width: auto; + height: auto; +} +select, input[type="file"] { + height: 28px; + /* In IE7, the height of the select element cannot be changed by height, only font-size */ + + *margin-top: 4px; + /* For IE7, add top margin to align select with labels */ + + line-height: 28px; +} +input[type="file"] { + line-height: 18px \9; +} +select { + width: 220px; + background-color: #ffffff; +} +select[multiple], select[size] { + height: auto; +} +input[type="image"] { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +textarea { + height: auto; +} +input[type="hidden"] { + display: none; +} +.radio, .checkbox { + padding-left: 18px; +} +.radio input[type="radio"], .checkbox input[type="checkbox"] { + float: left; + margin-left: -18px; +} +.controls > .radio:first-child, .controls > .checkbox:first-child { + padding-top: 5px; +} +.radio.inline, .checkbox.inline { + display: inline-block; + padding-top: 5px; + margin-bottom: 0; + vertical-align: middle; +} +.radio.inline + .radio.inline, .checkbox.inline + .checkbox.inline { + margin-left: 10px; +} +input, textarea { + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; + -moz-transition: border linear 0.2s, box-shadow linear 0.2s; + -ms-transition: border linear 0.2s, box-shadow linear 0.2s; + -o-transition: border linear 0.2s, box-shadow linear 0.2s; + transition: border linear 0.2s, box-shadow linear 0.2s; +} +input:focus, textarea:focus { + border-color: rgba(82, 168, 236, 0.8); + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + outline: 0; + outline: thin dotted \9; + /* IE6-9 */ + +} +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus, +select:focus { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.input-mini { + width: 60px; +} +.input-small { + width: 90px; +} +.input-medium { + width: 150px; +} +.input-large { + width: 210px; +} +.input-xlarge { + width: 270px; +} +.input-xxlarge { + width: 530px; +} +input[class*="span"], +select[class*="span"], +textarea[class*="span"], +.uneditable-input { + float: none; + margin-left: 0; +} +input.span1, textarea.span1, .uneditable-input.span1 { + width: 50px; +} +input.span2, textarea.span2, .uneditable-input.span2 { + width: 130px; +} +input.span3, textarea.span3, .uneditable-input.span3 { + width: 210px; +} +input.span4, textarea.span4, .uneditable-input.span4 { + width: 290px; +} +input.span5, textarea.span5, .uneditable-input.span5 { + width: 370px; +} +input.span6, textarea.span6, .uneditable-input.span6 { + width: 450px; +} +input.span7, textarea.span7, .uneditable-input.span7 { + width: 530px; +} +input.span8, textarea.span8, .uneditable-input.span8 { + width: 610px; +} +input.span9, textarea.span9, .uneditable-input.span9 { + width: 690px; +} +input.span10, textarea.span10, .uneditable-input.span10 { + width: 770px; +} +input.span11, textarea.span11, .uneditable-input.span11 { + width: 850px; +} +input.span12, textarea.span12, .uneditable-input.span12 { + width: 930px; +} +input[disabled], +select[disabled], +textarea[disabled], +input[readonly], +select[readonly], +textarea[readonly] { + background-color: #f5f5f5; + border-color: #ddd; + cursor: not-allowed; +} +.control-group.warning > label, .control-group.warning .help-block, .control-group.warning .help-inline { + color: #c09853; +} +.control-group.warning input, .control-group.warning select, .control-group.warning textarea { + color: #c09853; + border-color: #c09853; +} +.control-group.warning input:focus, .control-group.warning select:focus, .control-group.warning textarea:focus { + border-color: #a47e3c; + -webkit-box-shadow: 0 0 6px #dbc59e; + -moz-box-shadow: 0 0 6px #dbc59e; + box-shadow: 0 0 6px #dbc59e; +} +.control-group.warning .input-prepend .add-on, .control-group.warning .input-append .add-on { + color: #c09853; + background-color: #fcf8e3; + border-color: #c09853; +} +.control-group.error > label, .control-group.error .help-block, .control-group.error .help-inline { + color: #b94a48; +} +.control-group.error input, .control-group.error select, .control-group.error textarea { + color: #b94a48; + border-color: #b94a48; +} +.control-group.error input:focus, .control-group.error select:focus, .control-group.error textarea:focus { + border-color: #953b39; + -webkit-box-shadow: 0 0 6px #d59392; + -moz-box-shadow: 0 0 6px #d59392; + box-shadow: 0 0 6px #d59392; +} +.control-group.error .input-prepend .add-on, .control-group.error .input-append .add-on { + color: #b94a48; + background-color: #f2dede; + border-color: #b94a48; +} +.control-group.success > label, .control-group.success .help-block, .control-group.success .help-inline { + color: #468847; +} +.control-group.success input, .control-group.success select, .control-group.success textarea { + color: #468847; + border-color: #468847; +} +.control-group.success input:focus, .control-group.success select:focus, .control-group.success textarea:focus { + border-color: #356635; + -webkit-box-shadow: 0 0 6px #7aba7b; + -moz-box-shadow: 0 0 6px #7aba7b; + box-shadow: 0 0 6px #7aba7b; +} +.control-group.success .input-prepend .add-on, .control-group.success .input-append .add-on { + color: #468847; + background-color: #dff0d8; + border-color: #468847; +} +input:focus:required:invalid, textarea:focus:required:invalid, select:focus:required:invalid { + color: #b94a48; + border-color: #ee5f5b; +} +input:focus:required:invalid:focus, textarea:focus:required:invalid:focus, select:focus:required:invalid:focus { + border-color: #e9322d; + -webkit-box-shadow: 0 0 6px #f8b9b7; + -moz-box-shadow: 0 0 6px #f8b9b7; + box-shadow: 0 0 6px #f8b9b7; +} +.form-actions { + padding: 17px 20px 18px; + margin-top: 18px; + margin-bottom: 18px; + background-color: #f5f5f5; + border-top: 1px solid #ddd; +} +.uneditable-input { + display: block; + background-color: #ffffff; + border-color: #eee; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + cursor: not-allowed; +} +:-moz-placeholder { + color: #999999; +} +::-webkit-input-placeholder { + color: #999999; +} +.help-block { + display: block; + margin-top: 5px; + margin-bottom: 0; + color: #999999; +} +.help-inline { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; + margin-bottom: 9px; + vertical-align: middle; + padding-left: 5px; +} +.input-prepend, .input-append { + margin-bottom: 5px; + *zoom: 1; +} +.input-prepend:before, +.input-append:before, +.input-prepend:after, +.input-append:after { + display: table; + content: ""; +} +.input-prepend:after, .input-append:after { + clear: both; +} +.input-prepend input, +.input-append input, +.input-prepend .uneditable-input, +.input-append .uneditable-input { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.input-prepend input:focus, +.input-append input:focus, +.input-prepend .uneditable-input:focus, +.input-append .uneditable-input:focus { + position: relative; + z-index: 2; +} +.input-prepend .uneditable-input, .input-append .uneditable-input { + border-left-color: #ccc; +} +.input-prepend .add-on, .input-append .add-on { + float: left; + display: block; + width: auto; + min-width: 16px; + height: 18px; + margin-right: -1px; + padding: 4px 5px; + font-weight: normal; + line-height: 18px; + color: #999999; + text-align: center; + text-shadow: 0 1px 0 #ffffff; + background-color: #f5f5f5; + border: 1px solid #ccc; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.input-prepend .active, .input-append .active { + background-color: #a9dba9; + border-color: #46a546; +} +.input-prepend .add-on { + *margin-top: 1px; + /* IE6-7 */ + +} +.input-append input, .input-append .uneditable-input { + float: left; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.input-append .uneditable-input { + border-left-color: #eee; + border-right-color: #ccc; +} +.input-append .add-on { + margin-right: 0; + margin-left: -1px; + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.input-append input:first-child { + *margin-left: -160px; +} +.input-append input:first-child + .add-on { + *margin-left: -21px; +} +.search-query { + padding-left: 14px; + padding-right: 14px; + margin-bottom: 0; + -webkit-border-radius: 14px; + -moz-border-radius: 14px; + border-radius: 14px; +} +.form-search input, +.form-inline input, +.form-horizontal input, +.form-search textarea, +.form-inline textarea, +.form-horizontal textarea, +.form-search select, +.form-inline select, +.form-horizontal select, +.form-search .help-inline, +.form-inline .help-inline, +.form-horizontal .help-inline, +.form-search .uneditable-input, +.form-inline .uneditable-input, +.form-horizontal .uneditable-input { + display: inline-block; + margin-bottom: 0; +} +.form-search .hide, .form-inline .hide, .form-horizontal .hide { + display: none; +} +.form-search label, +.form-inline label, +.form-search .input-append, +.form-inline .input-append, +.form-search .input-prepend, +.form-inline .input-prepend { + display: inline-block; +} +.form-search .input-append .add-on, +.form-inline .input-prepend .add-on, +.form-search .input-append .add-on, +.form-inline .input-prepend .add-on { + vertical-align: middle; +} +.form-search .radio, +.form-inline .radio, +.form-search .checkbox, +.form-inline .checkbox { + margin-bottom: 0; + vertical-align: middle; +} +.control-group { + margin-bottom: 9px; +} +legend + .control-group { + margin-top: 18px; + -webkit-margin-top-collapse: separate; +} +.form-horizontal .control-group { + margin-bottom: 18px; + *zoom: 1; +} +.form-horizontal .control-group:before, .form-horizontal .control-group:after { + display: table; + content: ""; +} +.form-horizontal .control-group:after { + clear: both; +} +.form-horizontal .control-label { + float: left; + width: 140px; + padding-top: 5px; + text-align: right; +} +.form-horizontal .controls { + margin-left: 160px; +} +.form-horizontal .form-actions { + padding-left: 160px; +} +table { + max-width: 100%; + border-collapse: collapse; + border-spacing: 0; +} +.table { + width: 100%; + margin-bottom: 18px; +} +.table th, .table td { + padding: 8px; + line-height: 18px; + text-align: left; + vertical-align: top; + border-top: 1px solid #ddd; +} +.table th { + font-weight: bold; +} +.table thead th { + vertical-align: bottom; +} +.table thead:first-child tr th, .table thead:first-child tr td { + border-top: 0; +} +.table tbody + tbody { + border-top: 2px solid #ddd; +} +.table-condensed th, .table-condensed td { + padding: 4px 5px; +} +.table-bordered { + border: 1px solid #ddd; + border-collapse: separate; + *border-collapse: collapsed; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.table-bordered th + th, +.table-bordered td + td, +.table-bordered th + td, +.table-bordered td + th { + border-left: 1px solid #ddd; +} +.table-bordered thead:first-child tr:first-child th, .table-bordered tbody:first-child tr:first-child th, .table-bordered tbody:first-child tr:first-child td { + border-top: 0; +} +.table-bordered thead:first-child tr:first-child th:first-child, .table-bordered tbody:first-child tr:first-child td:first-child { + -webkit-border-radius: 4px 0 0 0; + -moz-border-radius: 4px 0 0 0; + border-radius: 4px 0 0 0; +} +.table-bordered thead:first-child tr:first-child th:last-child, .table-bordered tbody:first-child tr:first-child td:last-child { + -webkit-border-radius: 0 4px 0 0; + -moz-border-radius: 0 4px 0 0; + border-radius: 0 4px 0 0; +} +.table-bordered thead:last-child tr:last-child th:first-child, .table-bordered tbody:last-child tr:last-child td:first-child { + -webkit-border-radius: 0 0 0 4px; + -moz-border-radius: 0 0 0 4px; + border-radius: 0 0 0 4px; +} +.table-bordered thead:last-child tr:last-child th:last-child, .table-bordered tbody:last-child tr:last-child td:last-child { + -webkit-border-radius: 0 0 4px 0; + -moz-border-radius: 0 0 4px 0; + border-radius: 0 0 4px 0; +} +.table-striped tbody tr:nth-child(odd) td, .table-striped tbody tr:nth-child(odd) th { + background-color: #f9f9f9; +} +.table tbody tr:hover td, .table tbody tr:hover th { + background-color: #f5f5f5; +} +table .span1 { + float: none; + width: 44px; + margin-left: 0; +} +table .span2 { + float: none; + width: 124px; + margin-left: 0; +} +table .span3 { + float: none; + width: 204px; + margin-left: 0; +} +table .span4 { + float: none; + width: 284px; + margin-left: 0; +} +table .span5 { + float: none; + width: 364px; + margin-left: 0; +} +table .span6 { + float: none; + width: 444px; + margin-left: 0; +} +table .span7 { + float: none; + width: 524px; + margin-left: 0; +} +table .span8 { + float: none; + width: 604px; + margin-left: 0; +} +table .span9 { + float: none; + width: 684px; + margin-left: 0; +} +table .span10 { + float: none; + width: 764px; + margin-left: 0; +} +table .span11 { + float: none; + width: 844px; + margin-left: 0; +} +table .span12 { + float: none; + width: 924px; + margin-left: 0; +} +[class^="icon-"], [class*=" icon-"] { + display: inline-block; + width: 14px; + height: 14px; + line-height: 14px; + vertical-align: text-top; + background-image: url("../img/glyphicons-halflings.png"); + background-position: 14px 14px; + background-repeat: no-repeat; + *margin-right: .3em; +} +[class^="icon-"]:last-child, [class*=" icon-"]:last-child { + *margin-left: 0; +} +.icon-white { + background-image: url("../img/glyphicons-halflings-white.png"); +} +.icon-glass { + background-position: 0 0; +} +.icon-music { + background-position: -24px 0; +} +.icon-search { + background-position: -48px 0; +} +.icon-envelope { + background-position: -72px 0; +} +.icon-heart { + background-position: -96px 0; +} +.icon-star { + background-position: -120px 0; +} +.icon-star-empty { + background-position: -144px 0; +} +.icon-user { + background-position: -168px 0; +} +.icon-film { + background-position: -192px 0; +} +.icon-th-large { + background-position: -216px 0; +} +.icon-th { + background-position: -240px 0; +} +.icon-th-list { + background-position: -264px 0; +} +.icon-ok { + background-position: -288px 0; +} +.icon-remove { + background-position: -312px 0; +} +.icon-zoom-in { + background-position: -336px 0; +} +.icon-zoom-out { + background-position: -360px 0; +} +.icon-off { + background-position: -384px 0; +} +.icon-signal { + background-position: -408px 0; +} +.icon-cog { + background-position: -432px 0; +} +.icon-trash { + background-position: -456px 0; +} +.icon-home { + background-position: 0 -24px; +} +.icon-file { + background-position: -24px -24px; +} +.icon-time { + background-position: -48px -24px; +} +.icon-road { + background-position: -72px -24px; +} +.icon-download-alt { + background-position: -96px -24px; +} +.icon-download { + background-position: -120px -24px; +} +.icon-upload { + background-position: -144px -24px; +} +.icon-inbox { + background-position: -168px -24px; +} +.icon-play-circle { + background-position: -192px -24px; +} +.icon-repeat { + background-position: -216px -24px; +} +.icon-refresh { + background-position: -240px -24px; +} +.icon-list-alt { + background-position: -264px -24px; +} +.icon-lock { + background-position: -287px -24px; +} +.icon-flag { + background-position: -312px -24px; +} +.icon-headphones { + background-position: -336px -24px; +} +.icon-volume-off { + background-position: -360px -24px; +} +.icon-volume-down { + background-position: -384px -24px; +} +.icon-volume-up { + background-position: -408px -24px; +} +.icon-qrcode { + background-position: -432px -24px; +} +.icon-barcode { + background-position: -456px -24px; +} +.icon-tag { + background-position: 0 -48px; +} +.icon-tags { + background-position: -25px -48px; +} +.icon-book { + background-position: -48px -48px; +} +.icon-bookmark { + background-position: -72px -48px; +} +.icon-print { + background-position: -96px -48px; +} +.icon-camera { + background-position: -120px -48px; +} +.icon-font { + background-position: -144px -48px; +} +.icon-bold { + background-position: -167px -48px; +} +.icon-italic { + background-position: -192px -48px; +} +.icon-text-height { + background-position: -216px -48px; +} +.icon-text-width { + background-position: -240px -48px; +} +.icon-align-left { + background-position: -264px -48px; +} +.icon-align-center { + background-position: -288px -48px; +} +.icon-align-right { + background-position: -312px -48px; +} +.icon-align-justify { + background-position: -336px -48px; +} +.icon-list { + background-position: -360px -48px; +} +.icon-indent-left { + background-position: -384px -48px; +} +.icon-indent-right { + background-position: -408px -48px; +} +.icon-facetime-video { + background-position: -432px -48px; +} +.icon-picture { + background-position: -456px -48px; +} +.icon-pencil { + background-position: 0 -72px; +} +.icon-map-marker { + background-position: -24px -72px; +} +.icon-adjust { + background-position: -48px -72px; +} +.icon-tint { + background-position: -72px -72px; +} +.icon-edit { + background-position: -96px -72px; +} +.icon-share { + background-position: -120px -72px; +} +.icon-check { + background-position: -144px -72px; +} +.icon-move { + background-position: -168px -72px; +} +.icon-step-backward { + background-position: -192px -72px; +} +.icon-fast-backward { + background-position: -216px -72px; +} +.icon-backward { + background-position: -240px -72px; +} +.icon-play { + background-position: -264px -72px; +} +.icon-pause { + background-position: -288px -72px; +} +.icon-stop { + background-position: -312px -72px; +} +.icon-forward { + background-position: -336px -72px; +} +.icon-fast-forward { + background-position: -360px -72px; +} +.icon-step-forward { + background-position: -384px -72px; +} +.icon-eject { + background-position: -408px -72px; +} +.icon-chevron-left { + background-position: -432px -72px; +} +.icon-chevron-right { + background-position: -456px -72px; +} +.icon-plus-sign { + background-position: 0 -96px; +} +.icon-minus-sign { + background-position: -24px -96px; +} +.icon-remove-sign { + background-position: -48px -96px; +} +.icon-ok-sign { + background-position: -72px -96px; +} +.icon-question-sign { + background-position: -96px -96px; +} +.icon-info-sign { + background-position: -120px -96px; +} +.icon-screenshot { + background-position: -144px -96px; +} +.icon-remove-circle { + background-position: -168px -96px; +} +.icon-ok-circle { + background-position: -192px -96px; +} +.icon-ban-circle { + background-position: -216px -96px; +} +.icon-arrow-left { + background-position: -240px -96px; +} +.icon-arrow-right { + background-position: -264px -96px; +} +.icon-arrow-up { + background-position: -289px -96px; +} +.icon-arrow-down { + background-position: -312px -96px; +} +.icon-share-alt { + background-position: -336px -96px; +} +.icon-resize-full { + background-position: -360px -96px; +} +.icon-resize-small { + background-position: -384px -96px; +} +.icon-plus { + background-position: -408px -96px; +} +.icon-minus { + background-position: -433px -96px; +} +.icon-asterisk { + background-position: -456px -96px; +} +.icon-exclamation-sign { + background-position: 0 -120px; +} +.icon-gift { + background-position: -24px -120px; +} +.icon-leaf { + background-position: -48px -120px; +} +.icon-fire { + background-position: -72px -120px; +} +.icon-eye-open { + background-position: -96px -120px; +} +.icon-eye-close { + background-position: -120px -120px; +} +.icon-warning-sign { + background-position: -144px -120px; +} +.icon-plane { + background-position: -168px -120px; +} +.icon-calendar { + background-position: -192px -120px; +} +.icon-random { + background-position: -216px -120px; +} +.icon-comment { + background-position: -240px -120px; +} +.icon-magnet { + background-position: -264px -120px; +} +.icon-chevron-up { + background-position: -288px -120px; +} +.icon-chevron-down { + background-position: -313px -119px; +} +.icon-retweet { + background-position: -336px -120px; +} +.icon-shopping-cart { + background-position: -360px -120px; +} +.icon-folder-close { + background-position: -384px -120px; +} +.icon-folder-open { + background-position: -408px -120px; +} +.icon-resize-vertical { + background-position: -432px -119px; +} +.icon-resize-horizontal { + background-position: -456px -118px; +} +.dropdown { + position: relative; +} +.dropdown-toggle { + *margin-bottom: -3px; +} +.dropdown-toggle:active, .open .dropdown-toggle { + outline: 0; +} +.caret { + display: inline-block; + width: 0; + height: 0; + text-indent: -99999px; + *text-indent: 0; + vertical-align: top; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 4px solid #000000; + opacity: 0.3; + filter: alpha(opacity=30); + content: "\2193"; +} +.dropdown .caret { + margin-top: 8px; + margin-left: 2px; +} +.dropdown:hover .caret, .open.dropdown .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + float: left; + display: none; + min-width: 160px; + _width: 160px; + padding: 4px 0; + margin: 0; + list-style: none; + background-color: #ffffff; + border-color: #ccc; + border-color: rgba(0, 0, 0, 0.2); + border-style: solid; + border-width: 1px; + -webkit-border-radius: 0 0 5px 5px; + -moz-border-radius: 0 0 5px 5px; + border-radius: 0 0 5px 5px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; + *border-right-width: 2px; + *border-bottom-width: 2px; +} +.dropdown-menu.bottom-up { + top: auto; + bottom: 100%; + margin-bottom: 2px; +} +.dropdown-menu .divider { + height: 1px; + margin: 5px 1px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #ffffff; + *width: 100%; + *margin: -5px 0 5px; +} +.dropdown-menu a { + display: block; + padding: 3px 15px; + clear: both; + font-weight: normal; + line-height: 18px; + color: #555555; + white-space: nowrap; +} +.dropdown-menu li > a:hover, .dropdown-menu .active > a, .dropdown-menu .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #0088cc; +} +.dropdown.open { + *z-index: 1000; +} +.dropdown.open .dropdown-toggle { + color: #ffffff; + background: #ccc; + background: rgba(0, 0, 0, 0.3); +} +.dropdown.open .dropdown-menu { + display: block; +} +.typeahead { + margin-top: 2px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #f5f5f5; + border: 1px solid #eee; + border: 1px solid rgba(0, 0, 0, 0.05); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 0, 0, 0.15); +} +.fade { + -webkit-transition: opacity 0.15s linear; + -moz-transition: opacity 0.15s linear; + -ms-transition: opacity 0.15s linear; + -o-transition: opacity 0.15s linear; + transition: opacity 0.15s linear; + opacity: 0; +} +.fade.in { + opacity: 1; +} +.collapse { + -webkit-transition: height 0.35s ease; + -moz-transition: height 0.35s ease; + -ms-transition: height 0.35s ease; + -o-transition: height 0.35s ease; + transition: height 0.35s ease; + position: relative; + overflow: hidden; + height: 0; +} +.collapse.in { + height: auto; +} +.close { + float: right; + font-size: 20px; + font-weight: bold; + line-height: 18px; + color: #000000; + text-shadow: 0 1px 0 #ffffff; + opacity: 0.2; + filter: alpha(opacity=20); +} +.close:hover { + color: #000000; + text-decoration: none; + opacity: 0.4; + filter: alpha(opacity=40); + cursor: pointer; +} +.btn { + display: inline-block; + padding: 4px 10px 4px; + margin-bottom: 0; + font-size: 13px; + line-height: 18px; + color: #333333; + text-align: center; + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); + vertical-align: middle; + background-color: #f5f5f5; + background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); + background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); + background-image: linear-gradient(top, #ffffff, #e6e6e6); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0); + border-color: #e6e6e6 #e6e6e6 #bfbfbf; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + border: 1px solid #ccc; + border-bottom-color: #bbb; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + cursor: pointer; + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + *margin-left: .3em; +} +.btn:hover, +.btn:active, +.btn.active, +.btn.disabled, +.btn[disabled] { + background-color: #e6e6e6; +} +.btn:active, .btn.active { + background-color: #cccccc \9; +} +.btn:first-child { + *margin-left: 0; +} +.btn:hover { + color: #333333; + text-decoration: none; + background-color: #e6e6e6; + background-position: 0 -15px; + -webkit-transition: background-position 0.1s linear; + -moz-transition: background-position 0.1s linear; + -ms-transition: background-position 0.1s linear; + -o-transition: background-position 0.1s linear; + transition: background-position 0.1s linear; +} +.btn:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.btn.active, .btn:active { + background-image: none; + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + background-color: #e6e6e6; + background-color: #d9d9d9 \9; + outline: 0; +} +.btn.disabled, .btn[disabled] { + cursor: default; + background-image: none; + background-color: #e6e6e6; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +.btn-large { + padding: 9px 14px; + font-size: 15px; + line-height: normal; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.btn-large [class^="icon-"] { + margin-top: 1px; +} +.btn-small { + padding: 5px 9px; + font-size: 11px; + line-height: 16px; +} +.btn-small [class^="icon-"] { + margin-top: -1px; +} +.btn-mini { + padding: 2px 6px; + font-size: 11px; + line-height: 14px; +} +.btn-primary, +.btn-primary:hover, +.btn-warning, +.btn-warning:hover, +.btn-danger, +.btn-danger:hover, +.btn-success, +.btn-success:hover, +.btn-info, +.btn-info:hover, +.btn-inverse, +.btn-inverse:hover { + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + color: #ffffff; +} +.btn-primary.active, +.btn-warning.active, +.btn-danger.active, +.btn-success.active, +.btn-info.active, +.btn-dark.active { + color: rgba(255, 255, 255, 0.75); +} +.btn-primary { + background-color: #006dcc; + background-image: -moz-linear-gradient(top, #0088cc, #0044cc); + background-image: -ms-linear-gradient(top, #0088cc, #0044cc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); + background-image: -o-linear-gradient(top, #0088cc, #0044cc); + background-image: linear-gradient(top, #0088cc, #0044cc); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); + border-color: #0044cc #0044cc #002a80; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-primary:hover, +.btn-primary:active, +.btn-primary.active, +.btn-primary.disabled, +.btn-primary[disabled] { + background-color: #0044cc; +} +.btn-primary:active, .btn-primary.active { + background-color: #003399 \9; +} +.btn-warning { + background-color: #faa732; + background-image: -moz-linear-gradient(top, #fbb450, #f89406); + background-image: -ms-linear-gradient(top, #fbb450, #f89406); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); + background-image: -webkit-linear-gradient(top, #fbb450, #f89406); + background-image: -o-linear-gradient(top, #fbb450, #f89406); + background-image: linear-gradient(top, #fbb450, #f89406); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0); + border-color: #f89406 #f89406 #ad6704; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-warning:hover, +.btn-warning:active, +.btn-warning.active, +.btn-warning.disabled, +.btn-warning[disabled] { + background-color: #f89406; +} +.btn-warning:active, .btn-warning.active { + background-color: #c67605 \9; +} +.btn-danger { + background-color: #da4f49; + background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -ms-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -o-linear-gradient(top, #ee5f5b, #bd362f); + background-image: linear-gradient(top, #ee5f5b, #bd362f); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0); + border-color: #bd362f #bd362f #802420; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-danger:hover, +.btn-danger:active, +.btn-danger.active, +.btn-danger.disabled, +.btn-danger[disabled] { + background-color: #bd362f; +} +.btn-danger:active, .btn-danger.active { + background-color: #942a25 \9; +} +.btn-success { + background-color: #5bb75b; + background-image: -moz-linear-gradient(top, #62c462, #51a351); + background-image: -ms-linear-gradient(top, #62c462, #51a351); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351)); + background-image: -webkit-linear-gradient(top, #62c462, #51a351); + background-image: -o-linear-gradient(top, #62c462, #51a351); + background-image: linear-gradient(top, #62c462, #51a351); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0); + border-color: #51a351 #51a351 #387038; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-success:hover, +.btn-success:active, +.btn-success.active, +.btn-success.disabled, +.btn-success[disabled] { + background-color: #51a351; +} +.btn-success:active, .btn-success.active { + background-color: #408140 \9; +} +.btn-info { + background-color: #49afcd; + background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -ms-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4)); + background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -o-linear-gradient(top, #5bc0de, #2f96b4); + background-image: linear-gradient(top, #5bc0de, #2f96b4); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0); + border-color: #2f96b4 #2f96b4 #1f6377; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-info:hover, +.btn-info:active, +.btn-info.active, +.btn-info.disabled, +.btn-info[disabled] { + background-color: #2f96b4; +} +.btn-info:active, .btn-info.active { + background-color: #24748c \9; +} +.btn-inverse { + background-color: #393939; + background-image: -moz-linear-gradient(top, #454545, #262626); + background-image: -ms-linear-gradient(top, #454545, #262626); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#454545), to(#262626)); + background-image: -webkit-linear-gradient(top, #454545, #262626); + background-image: -o-linear-gradient(top, #454545, #262626); + background-image: linear-gradient(top, #454545, #262626); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#454545', endColorstr='#262626', GradientType=0); + border-color: #262626 #262626 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-inverse:hover, +.btn-inverse:active, +.btn-inverse.active, +.btn-inverse.disabled, +.btn-inverse[disabled] { + background-color: #262626; +} +.btn-inverse:active, .btn-inverse.active { + background-color: #0c0c0c \9; +} +button.btn, input[type="submit"].btn { + *padding-top: 2px; + *padding-bottom: 2px; +} +button.btn::-moz-focus-inner, input[type="submit"].btn::-moz-focus-inner { + padding: 0; + border: 0; +} +button.btn.large, input[type="submit"].btn.large { + *padding-top: 7px; + *padding-bottom: 7px; +} +button.btn.small, input[type="submit"].btn.small { + *padding-top: 3px; + *padding-bottom: 3px; +} +.btn-group { + position: relative; + *zoom: 1; + *margin-left: .3em; +} +.btn-group:before, .btn-group:after { + display: table; + content: ""; +} +.btn-group:after { + clear: both; +} +.btn-group:first-child { + *margin-left: 0; +} +.btn-group + .btn-group { + margin-left: 5px; +} +.btn-toolbar { + margin-top: 9px; + margin-bottom: 9px; +} +.btn-toolbar .btn-group { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; +} +.btn-group .btn { + position: relative; + float: left; + margin-left: -1px; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.btn-group .btn:first-child { + margin-left: 0; + -webkit-border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; + border-top-left-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + border-bottom-left-radius: 4px; +} +.btn-group .btn:last-child, .btn-group .dropdown-toggle { + -webkit-border-top-right-radius: 4px; + -moz-border-radius-topright: 4px; + border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -moz-border-radius-bottomright: 4px; + border-bottom-right-radius: 4px; +} +.btn-group .btn.large:first-child { + margin-left: 0; + -webkit-border-top-left-radius: 6px; + -moz-border-radius-topleft: 6px; + border-top-left-radius: 6px; + -webkit-border-bottom-left-radius: 6px; + -moz-border-radius-bottomleft: 6px; + border-bottom-left-radius: 6px; +} +.btn-group .btn.large:last-child, .btn-group .large.dropdown-toggle { + -webkit-border-top-right-radius: 6px; + -moz-border-radius-topright: 6px; + border-top-right-radius: 6px; + -webkit-border-bottom-right-radius: 6px; + -moz-border-radius-bottomright: 6px; + border-bottom-right-radius: 6px; +} +.btn-group .btn:hover, +.btn-group .btn:focus, +.btn-group .btn:active, +.btn-group .btn.active { + z-index: 2; +} +.btn-group .dropdown-toggle:active, .btn-group.open .dropdown-toggle { + outline: 0; +} +.btn-group .dropdown-toggle { + padding-left: 8px; + padding-right: 8px; + -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + *padding-top: 5px; + *padding-bottom: 5px; +} +.btn-group.open { + *z-index: 1000; +} +.btn-group.open .dropdown-menu { + display: block; + margin-top: 1px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.btn-group.open .dropdown-toggle { + background-image: none; + -webkit-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); +} +.btn .caret { + margin-top: 7px; + margin-left: 0; +} +.btn:hover .caret, .open.btn-group .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.btn-primary .caret, +.btn-danger .caret, +.btn-info .caret, +.btn-success .caret, +.btn-inverse .caret { + border-top-color: #ffffff; + opacity: 0.75; + filter: alpha(opacity=75); +} +.btn-small .caret { + margin-top: 4px; +} +.alert { + padding: 8px 35px 8px 14px; + margin-bottom: 18px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + background-color: #fcf8e3; + border: 1px solid #fbeed5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.alert, .alert-heading { + color: #c09853; +} +.alert .close { + position: relative; + top: -2px; + right: -21px; + line-height: 18px; +} +.alert-success { + background-color: #dff0d8; + border-color: #d6e9c6; +} +.alert-success, .alert-success .alert-heading { + color: #468847; +} +.alert-danger, .alert-error { + background-color: #f2dede; + border-color: #eed3d7; +} +.alert-danger, +.alert-error, +.alert-danger .alert-heading, +.alert-error .alert-heading { + color: #b94a48; +} +.alert-info { + background-color: #d9edf7; + border-color: #bce8f1; +} +.alert-info, .alert-info .alert-heading { + color: #3a87ad; +} +.alert-block { + padding-top: 14px; + padding-bottom: 14px; +} +.alert-block > p, .alert-block > ul { + margin-bottom: 0; +} +.alert-block p + p { + margin-top: 5px; +} +.nav { + margin-left: 0; + margin-bottom: 18px; + list-style: none; +} +.nav > li > a { + display: block; +} +.nav > li > a:hover { + text-decoration: none; + background-color: #eeeeee; +} +.nav .nav-header { + display: block; + padding: 3px 15px; + font-size: 11px; + font-weight: bold; + line-height: 18px; + color: #999999; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + text-transform: uppercase; +} +.nav li + .nav-header { + margin-top: 9px; +} +.nav-list { + padding-left: 14px; + padding-right: 14px; + margin-bottom: 0; +} +.nav-list > li > a, .nav-list .nav-header { + margin-left: -15px; + margin-right: -15px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); +} +.nav-list > li > a { + padding: 3px 15px; +} +.nav-list .active > a, .nav-list .active > a:hover { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); + background-color: #0088cc; +} +.nav-list [class^="icon-"] { + margin-right: 2px; +} +.nav-tabs, .nav-pills { + *zoom: 1; +} +.nav-tabs:before, +.nav-pills:before, +.nav-tabs:after, +.nav-pills:after { + display: table; + content: ""; +} +.nav-tabs:after, .nav-pills:after { + clear: both; +} +.nav-tabs > li, .nav-pills > li { + float: left; +} +.nav-tabs > li > a, .nav-pills > li > a { + padding-right: 12px; + padding-left: 12px; + margin-right: 2px; + line-height: 14px; +} +.nav-tabs { + border-bottom: 1px solid #ddd; +} +.nav-tabs > li { + margin-bottom: -1px; +} +.nav-tabs > li > a { + padding-top: 9px; + padding-bottom: 9px; + border: 1px solid transparent; + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} +.nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #dddddd; +} +.nav-tabs > .active > a, .nav-tabs > .active > a:hover { + color: #555555; + background-color: #ffffff; + border: 1px solid #ddd; + border-bottom-color: transparent; + cursor: default; +} +.nav-pills > li > a { + padding-top: 8px; + padding-bottom: 8px; + margin-top: 2px; + margin-bottom: 2px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.nav-pills .active > a, .nav-pills .active > a:hover { + color: #ffffff; + background-color: #0088cc; +} +.nav-stacked > li { + float: none; +} +.nav-stacked > li > a { + margin-right: 0; +} +.nav-tabs.nav-stacked { + border-bottom: 0; +} +.nav-tabs.nav-stacked > li > a { + border: 1px solid #ddd; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.nav-tabs.nav-stacked > li:first-child > a { + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} +.nav-tabs.nav-stacked > li:last-child > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} +.nav-tabs.nav-stacked > li > a:hover { + border-color: #ddd; + z-index: 2; +} +.nav-pills.nav-stacked > li > a { + margin-bottom: 3px; +} +.nav-pills.nav-stacked > li:last-child > a { + margin-bottom: 1px; +} +.nav-tabs .dropdown-menu, .nav-pills .dropdown-menu { + margin-top: 1px; + border-width: 1px; +} +.nav-pills .dropdown-menu { + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.nav-tabs .dropdown-toggle .caret, .nav-pills .dropdown-toggle .caret { + border-top-color: #0088cc; + margin-top: 6px; +} +.nav-tabs .dropdown-toggle:hover .caret, .nav-pills .dropdown-toggle:hover .caret { + border-top-color: #005580; +} +.nav-tabs .active .dropdown-toggle .caret, .nav-pills .active .dropdown-toggle .caret { + border-top-color: #333333; +} +.nav > .dropdown.active > a:hover { + color: #000000; + cursor: pointer; +} +.nav-tabs .open .dropdown-toggle, .nav-pills .open .dropdown-toggle, .nav > .open.active > a:hover { + color: #ffffff; + background-color: #999999; + border-color: #999999; +} +.nav .open .caret, .nav .open.active .caret, .nav .open a:hover .caret { + border-top-color: #ffffff; + opacity: 1; + filter: alpha(opacity=100); +} +.tabs-stacked .open > a:hover { + border-color: #999999; +} +.tabbable { + *zoom: 1; +} +.tabbable:before, .tabbable:after { + display: table; + content: ""; +} +.tabbable:after { + clear: both; +} +.tab-content { + overflow: hidden; +} +.tabs-below .nav-tabs, .tabs-right .nav-tabs, .tabs-left .nav-tabs { + border-bottom: 0; +} +.tab-content > .tab-pane, .pill-content > .pill-pane { + display: none; +} +.tab-content > .active, .pill-content > .active { + display: block; +} +.tabs-below .nav-tabs { + border-top: 1px solid #ddd; +} +.tabs-below .nav-tabs > li { + margin-top: -1px; + margin-bottom: 0; +} +.tabs-below .nav-tabs > li > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} +.tabs-below .nav-tabs > li > a:hover { + border-bottom-color: transparent; + border-top-color: #ddd; +} +.tabs-below .nav-tabs .active > a, .tabs-below .nav-tabs .active > a:hover { + border-color: transparent #ddd #ddd #ddd; +} +.tabs-left .nav-tabs > li, .tabs-right .nav-tabs > li { + float: none; +} +.tabs-left .nav-tabs > li > a, .tabs-right .nav-tabs > li > a { + min-width: 74px; + margin-right: 0; + margin-bottom: 3px; +} +.tabs-left .nav-tabs { + float: left; + margin-right: 19px; + border-right: 1px solid #ddd; +} +.tabs-left .nav-tabs > li > a { + margin-right: -1px; + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} +.tabs-left .nav-tabs > li > a:hover { + border-color: #eeeeee #dddddd #eeeeee #eeeeee; +} +.tabs-left .nav-tabs .active > a, .tabs-left .nav-tabs .active > a:hover { + border-color: #ddd transparent #ddd #ddd; + *border-right-color: #ffffff; +} +.tabs-right .nav-tabs { + float: right; + margin-left: 19px; + border-left: 1px solid #ddd; +} +.tabs-right .nav-tabs > li > a { + margin-left: -1px; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} +.tabs-right .nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #eeeeee #dddddd; +} +.tabs-right .nav-tabs .active > a, .tabs-right .nav-tabs .active > a:hover { + border-color: #ddd #ddd #ddd transparent; + *border-left-color: #ffffff; +} +.navbar { + overflow: visible; + margin-bottom: 18px; +} +.navbar-inner { + padding-left: 20px; + padding-right: 20px; + background-color: #2c2c2c; + background-image: -moz-linear-gradient(top, #333333, #222222); + background-image: -ms-linear-gradient(top, #333333, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); + background-image: -webkit-linear-gradient(top, #333333, #222222); + background-image: -o-linear-gradient(top, #333333, #222222); + background-image: linear-gradient(top, #333333, #222222); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); +} +.btn-navbar { + display: none; + float: right; + padding: 7px 10px; + margin-left: 5px; + margin-right: 5px; + background-color: #2c2c2c; + background-image: -moz-linear-gradient(top, #333333, #222222); + background-image: -ms-linear-gradient(top, #333333, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); + background-image: -webkit-linear-gradient(top, #333333, #222222); + background-image: -o-linear-gradient(top, #333333, #222222); + background-image: linear-gradient(top, #333333, #222222); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); + border-color: #222222 #222222 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); +} +.btn-navbar:hover, +.btn-navbar:active, +.btn-navbar.active, +.btn-navbar.disabled, +.btn-navbar[disabled] { + background-color: #222222; +} +.btn-navbar:active, .btn-navbar.active { + background-color: #080808 \9; +} +.btn-navbar .icon-bar { + display: block; + width: 18px; + height: 2px; + background-color: #f5f5f5; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; + -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); +} +.btn-navbar .icon-bar + .icon-bar { + margin-top: 3px; +} +.nav-collapse.collapse { + height: auto; +} +.navbar .brand:hover { + text-decoration: none; +} +.navbar .brand { + float: left; + display: block; + padding: 8px 20px 12px; + margin-left: -20px; + font-size: 20px; + font-weight: 200; + line-height: 1; + color: #ffffff; +} +.navbar .navbar-text { + margin-bottom: 0; + line-height: 40px; + color: #999999; +} +.navbar .navbar-text a:hover { + color: #ffffff; + background-color: transparent; +} +.navbar .btn, .navbar .btn-group { + margin-top: 5px; +} +.navbar .btn-group .btn { + margin-top: 0; +} +.navbar-form { + margin-bottom: 0; + *zoom: 1; +} +.navbar-form:before, .navbar-form:after { + display: table; + content: ""; +} +.navbar-form:after { + clear: both; +} +.navbar-form input, .navbar-form select { + display: inline-block; + margin-top: 5px; + margin-bottom: 0; +} +.navbar-form .radio, .navbar-form .checkbox { + margin-top: 5px; +} +.navbar-form input[type="image"], .navbar-form input[type="checkbox"], .navbar-form input[type="radio"] { + margin-top: 3px; +} +.navbar-form .input-append, .navbar-form .input-prepend { + margin-top: 6px; + white-space: nowrap; +} +.navbar-form .input-append input, .navbar-form .input-prepend input { + margin-top: 0; +} +.navbar-search { + position: relative; + float: left; + margin-top: 6px; + margin-bottom: 0; +} +.navbar-search .search-query { + padding: 4px 9px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + font-weight: normal; + line-height: 1; + color: #ffffff; + color: rgba(255, 255, 255, 0.75); + background: #666; + background: rgba(255, 255, 255, 0.3); + border: 1px solid #111; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + -webkit-transition: none; + -moz-transition: none; + -ms-transition: none; + -o-transition: none; + transition: none; +} +.navbar-search .search-query :-moz-placeholder { + color: #eeeeee; +} +.navbar-search .search-query::-webkit-input-placeholder { + color: #eeeeee; +} +.navbar-search .search-query:hover { + color: #ffffff; + background-color: #999999; + background-color: rgba(255, 255, 255, 0.5); +} +.navbar-search .search-query:focus, .navbar-search .search-query.focused { + padding: 5px 10px; + color: #333333; + text-shadow: 0 1px 0 #ffffff; + background-color: #ffffff; + border: 0; + -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + outline: 0; +} +.navbar-fixed-top { + position: fixed; + top: 0; + right: 0; + left: 0; + z-index: 1030; +} +.navbar-fixed-top .navbar-inner { + padding-left: 0; + padding-right: 0; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.navbar .nav { + position: relative; + left: 0; + display: block; + float: left; + margin: 0 10px 0 0; +} +.navbar .nav.pull-right { + float: right; +} +.navbar .nav > li { + display: block; + float: left; +} +.navbar .nav > li > a { + float: none; + padding: 10px 10px 11px; + line-height: 19px; + color: #999999; + text-decoration: none; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.navbar .nav > li > a:hover { + background-color: transparent; + color: #ffffff; + text-decoration: none; +} +.navbar .nav .active > a, .navbar .nav .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #222222; +} +.navbar .divider-vertical { + height: 40px; + width: 1px; + margin: 0 9px; + overflow: hidden; + background-color: #222222; + border-right: 1px solid #333333; +} +.navbar .nav.pull-right { + margin-left: 10px; + margin-right: 0; +} +.navbar .dropdown-menu { + margin-top: 1px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.navbar .dropdown-menu:before { + content: ''; + display: inline-block; + border-left: 7px solid transparent; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-bottom-color: rgba(0, 0, 0, 0.2); + position: absolute; + top: -7px; + left: 9px; +} +.navbar .dropdown-menu:after { + content: ''; + display: inline-block; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid #ffffff; + position: absolute; + top: -6px; + left: 10px; +} +.navbar .nav .dropdown-toggle .caret, .navbar .nav .open.dropdown .caret { + border-top-color: #ffffff; +} +.navbar .nav .active .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.navbar .nav .open > .dropdown-toggle, .navbar .nav .active > .dropdown-toggle, .navbar .nav .open.active > .dropdown-toggle { + background-color: transparent; +} +.navbar .nav .active > .dropdown-toggle:hover { + color: #ffffff; +} +.navbar .nav.pull-right .dropdown-menu { + left: auto; + right: 0; +} +.navbar .nav.pull-right .dropdown-menu:before { + left: auto; + right: 12px; +} +.navbar .nav.pull-right .dropdown-menu:after { + left: auto; + right: 13px; +} +.breadcrumb { + padding: 7px 14px; + margin: 0 0 18px; + background-color: #fbfbfb; + background-image: -moz-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -ms-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5)); + background-image: -webkit-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -o-linear-gradient(top, #ffffff, #f5f5f5); + background-image: linear-gradient(top, #ffffff, #f5f5f5); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0); + border: 1px solid #ddd; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; +} +.breadcrumb li { + display: inline-block; + text-shadow: 0 1px 0 #ffffff; +} +.breadcrumb .divider { + padding: 0 5px; + color: #999999; +} +.breadcrumb .active a { + color: #333333; +} +.pagination { + height: 36px; + margin: 18px 0; +} +.pagination ul { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; + margin-left: 0; + margin-bottom: 0; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); +} +.pagination li { + display: inline; +} +.pagination a { + float: left; + padding: 0 14px; + line-height: 34px; + text-decoration: none; + border: 1px solid #ddd; + border-left-width: 0; +} +.pagination a:hover, .pagination .active a { + background-color: #f5f5f5; +} +.pagination .active a { + color: #999999; + cursor: default; +} +.pagination .disabled a, .pagination .disabled a:hover { + color: #999999; + background-color: transparent; + cursor: default; +} +.pagination li:first-child a { + border-left-width: 1px; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.pagination li:last-child a { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.pagination-centered { + text-align: center; +} +.pagination-right { + text-align: right; +} +.pager { + margin-left: 0; + margin-bottom: 18px; + list-style: none; + text-align: center; + *zoom: 1; +} +.pager:before, .pager:after { + display: table; + content: ""; +} +.pager:after { + clear: both; +} +.pager li { + display: inline; +} +.pager a { + display: inline-block; + padding: 5px 14px; + background-color: #fff; + border: 1px solid #ddd; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} +.pager a:hover { + text-decoration: none; + background-color: #f5f5f5; +} +.pager .next a { + float: right; +} +.pager .previous a { + float: left; +} +.modal-open .dropdown-menu { + z-index: 2050; +} +.modal-open .dropdown.open { + *z-index: 2050; +} +.modal-open .popover { + z-index: 2060; +} +.modal-open .tooltip { + z-index: 2070; +} +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + background-color: #000000; +} +.modal-backdrop.fade { + opacity: 0; +} +.modal-backdrop, .modal-backdrop.fade.in { + opacity: 0.8; + filter: alpha(opacity=80); +} +.modal { + position: fixed; + top: 50%; + left: 50%; + z-index: 1050; + max-height: 500px; + overflow: auto; + width: 560px; + margin: -250px 0 0 -280px; + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + /* IE6-7 */ + + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.wide-modal { + position: fixed; + top: 5%; + left: 5%; + z-index: 1050; + max-height: 90%; + overflow: auto; + width: 90%; + /*margin: -50px 0 0 -80px;*/ + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + /* IE6-7 */ + + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.modal.fade { + -webkit-transition: opacity .3s linear, top .3s ease-out; + -moz-transition: opacity .3s linear, top .3s ease-out; + -ms-transition: opacity .3s linear, top .3s ease-out; + -o-transition: opacity .3s linear, top .3s ease-out; + transition: opacity .3s linear, top .3s ease-out; + top: -25%; +} +.modal.fade.in { + top: 50%; +} +.modal-header { + padding: 9px 15px; + border-bottom: 1px solid #eee; +} +.modal-header .close { + margin-top: 2px; +} +.modal-body { + padding: 15px; +} +.modal-body .modal-form { + margin-bottom: 0; +} +.modal-footer { + padding: 14px 15px 15px; + margin-bottom: 0; + background-color: #f5f5f5; + border-top: 1px solid #ddd; + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; + *zoom: 1; +} +.modal-footer:before, .modal-footer:after { + display: table; + content: ""; +} +.modal-footer:after { + clear: both; +} +.modal-footer .btn { + float: right; + margin-left: 5px; + margin-bottom: 0; +} +.tooltip { + position: absolute; + z-index: 1020; + display: block; + visibility: visible; + padding: 5px; + font-size: 11px; + opacity: 0; + filter: alpha(opacity=0); +} +.tooltip.in { + opacity: 0.8; + filter: alpha(opacity=80); +} +.tooltip.top { + margin-top: -2px; +} +.tooltip.right { + margin-left: 2px; +} +.tooltip.bottom { + margin-top: 2px; +} +.tooltip.left { + margin-left: -2px; +} +.tooltip.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid #000000; +} +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #000000; +} +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-bottom: 5px solid #000000; +} +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-right: 5px solid #000000; +} +.tooltip-inner { + max-width: 200px; + padding: 3px 8px; + color: #ffffff; + text-align: center; + text-decoration: none; + background-color: #000000; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; +} +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1010; + display: none; + padding: 5px; +} +.popover.top { + margin-top: -5px; +} +.popover.right { + margin-left: 5px; +} +.popover.bottom { + margin-top: 5px; +} +.popover.left { + margin-left: -5px; +} +.popover.top .arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid #000000; +} +.popover.right .arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-right: 5px solid #000000; +} +.popover.bottom .arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-bottom: 5px solid #000000; +} +.popover.left .arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #000000; +} +.popover .arrow { + position: absolute; + width: 0; + height: 0; +} +.popover-inner { + padding: 3px; + width: 280px; + overflow: hidden; + background: #000000; + background: rgba(0, 0, 0, 0.8); + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); +} +.popover-title { + padding: 9px 15px; + line-height: 1; + background-color: #f5f5f5; + border-bottom: 1px solid #eee; + -webkit-border-radius: 3px 3px 0 0; + -moz-border-radius: 3px 3px 0 0; + border-radius: 3px 3px 0 0; +} +.popover-content { + padding: 14px; + background-color: #ffffff; + -webkit-border-radius: 0 0 3px 3px; + -moz-border-radius: 0 0 3px 3px; + border-radius: 0 0 3px 3px; + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.popover-content p, .popover-content ul, .popover-content ol { + margin-bottom: 0; +} +.thumbnails { + margin-left: -20px; + list-style: none; + *zoom: 1; +} +.thumbnails:before, .thumbnails:after { + display: table; + content: ""; +} +.thumbnails:after { + clear: both; +} +.thumbnails > li { + float: left; + margin: 0 0 18px 20px; +} +.thumbnail { + display: block; + padding: 4px; + line-height: 1; + border: 1px solid #ddd; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); +} +a.thumbnail:hover { + border-color: #0088cc; + -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); +} +.thumbnail > img { + display: block; + max-width: 100%; + margin-left: auto; + margin-right: auto; +} +.thumbnail .caption { + padding: 9px; +} +.label { + padding: 2px 4px 3px; + font-size: 11.049999999999999px; + font-weight: bold; + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #999999; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.label:hover { + color: #ffffff; + text-decoration: none; +} +.label-important { + background-color: #b94a48; +} +.label-important:hover { + background-color: #953b39; +} +.label-warning { + background-color: #f89406; +} +.label-warning:hover { + background-color: #c67605; +} +.label-success { + background-color: #468847; +} +.label-success:hover { + background-color: #356635; +} +.label-info { + background-color: #3a87ad; +} +.label-info:hover { + background-color: #2d6987; +} +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +@-moz-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +@keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +.progress { + overflow: hidden; + height: 18px; + margin-bottom: 18px; + background-color: #f7f7f7; + background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -ms-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9)); + background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: linear-gradient(top, #f5f5f5, #f9f9f9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0); + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.progress .bar { + width: 0%; + height: 18px; + color: #ffffff; + font-size: 12px; + text-align: center; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #0e90d2; + background-image: -moz-linear-gradient(top, #149bdf, #0480be); + background-image: -ms-linear-gradient(top, #149bdf, #0480be); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be)); + background-image: -webkit-linear-gradient(top, #149bdf, #0480be); + background-image: -o-linear-gradient(top, #149bdf, #0480be); + background-image: linear-gradient(top, #149bdf, #0480be); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0); + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition: width 0.6s ease; + -moz-transition: width 0.6s ease; + -ms-transition: width 0.6s ease; + -o-transition: width 0.6s ease; + transition: width 0.6s ease; +} +.progress-striped .bar { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + -webkit-background-size: 40px 40px; + -moz-background-size: 40px 40px; + -o-background-size: 40px 40px; + background-size: 40px 40px; +} +.progress.active .bar { + -webkit-animation: progress-bar-stripes 2s linear infinite; + -moz-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} +.progress-danger .bar { + background-color: #dd514c; + background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -o-linear-gradient(top, #ee5f5b, #c43c35); + background-image: linear-gradient(top, #ee5f5b, #c43c35); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0); +} +.progress-danger.progress-striped .bar { + background-color: #ee5f5b; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-success .bar { + background-color: #5eb95e; + background-image: -moz-linear-gradient(top, #62c462, #57a957); + background-image: -ms-linear-gradient(top, #62c462, #57a957); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957)); + background-image: -webkit-linear-gradient(top, #62c462, #57a957); + background-image: -o-linear-gradient(top, #62c462, #57a957); + background-image: linear-gradient(top, #62c462, #57a957); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0); +} +.progress-success.progress-striped .bar { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-info .bar { + background-color: #4bb1cf; + background-image: -moz-linear-gradient(top, #5bc0de, #339bb9); + background-image: -ms-linear-gradient(top, #5bc0de, #339bb9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9)); + background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9); + background-image: -o-linear-gradient(top, #5bc0de, #339bb9); + background-image: linear-gradient(top, #5bc0de, #339bb9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0); +} +.progress-info.progress-striped .bar { + background-color: #5bc0de; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.accordion { + margin-bottom: 18px; +} +.accordion-group { + margin-bottom: 2px; + border: 1px solid #e5e5e5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.accordion-heading { + border-bottom: 0; +} +.accordion-heading .accordion-toggle { + display: block; + padding: 8px 15px; +} +.accordion-inner { + padding: 9px 15px; + border-top: 1px solid #e5e5e5; +} +.carousel { + position: relative; + margin-bottom: 18px; + line-height: 1; +} +.carousel-inner { + overflow: hidden; + width: 100%; + position: relative; +} +.carousel .item { + display: none; + position: relative; + -webkit-transition: 0.6s ease-in-out left; + -moz-transition: 0.6s ease-in-out left; + -ms-transition: 0.6s ease-in-out left; + -o-transition: 0.6s ease-in-out left; + transition: 0.6s ease-in-out left; +} +.carousel .item > img { + display: block; + line-height: 1; +} +.carousel .active, .carousel .next, .carousel .prev { + display: block; +} +.carousel .active { + left: 0; +} +.carousel .next, .carousel .prev { + position: absolute; + top: 0; + width: 100%; +} +.carousel .next { + left: 100%; +} +.carousel .prev { + left: -100%; +} +.carousel .next.left, .carousel .prev.right { + left: 0; +} +.carousel .active.left { + left: -100%; +} +.carousel .active.right { + left: 100%; +} +.carousel-control { + position: absolute; + top: 40%; + left: 15px; + width: 40px; + height: 40px; + margin-top: -20px; + font-size: 60px; + font-weight: 100; + line-height: 30px; + color: #ffffff; + text-align: center; + background: #222222; + border: 3px solid #ffffff; + -webkit-border-radius: 23px; + -moz-border-radius: 23px; + border-radius: 23px; + opacity: 0.5; + filter: alpha(opacity=50); +} +.carousel-control.right { + left: auto; + right: 15px; +} +.carousel-control:hover { + color: #ffffff; + text-decoration: none; + opacity: 0.9; + filter: alpha(opacity=90); +} +.carousel-caption { + position: absolute; + left: 0; + right: 0; + bottom: 0; + padding: 10px 15px 5px; + background: #333333; + background: rgba(0, 0, 0, 0.75); +} +.carousel-caption h4, .carousel-caption p { + color: #ffffff; +} +.hero-unit { + padding: 60px; + margin-bottom: 30px; + background-color: #f5f5f5; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} +.hero-unit h1 { + margin-bottom: 0; + font-size: 60px; + line-height: 1; + letter-spacing: -1px; +} +.hero-unit p { + font-size: 18px; + font-weight: 200; + line-height: 27px; +} +.pull-right { + float: right; +} +.pull-left { + float: left; +} +.hide { + display: none; +} +.show { + display: block; +} +.invisible { + visibility: hidden; +} diff --git a/src/nl/astraeus/jdbc/web/resources/images/loading.gif b/src/nl/astraeus/jdbc/web/resources/images/loading.gif new file mode 100644 index 0000000..21c7e74 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/images/loading.gif Binary files differ diff --git a/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png b/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png new file mode 100644 index 0000000..92d4445 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png Binary files differ diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-alert.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-alert.js new file mode 100644 index 0000000..2242ddd --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-alert.js @@ -0,0 +1,94 @@ +/* ========================================================== + * bootstrap-alert.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#alerts + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function( $ ){ + + "use strict" + + /* ALERT CLASS DEFINITION + * ====================== */ + + var dismiss = '[data-dismiss="alert"]' + , Alert = function ( el ) { + $(el).on('click', dismiss, this.close) + } + + Alert.prototype = { + + constructor: Alert + + , close: function ( e ) { + var $this = $(this) + , selector = $this.attr('data-target') + , $parent + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = $(selector) + $parent.trigger('close') + + e && e.preventDefault() + + $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent()) + + $parent + .trigger('close') + .removeClass('in') + + function removeElement() { + $parent + .trigger('closed') + .remove() + } + + $.support.transition && $parent.hasClass('fade') ? + $parent.on($.support.transition.end, removeElement) : + removeElement() + } + + } + + + /* ALERT PLUGIN DEFINITION + * ======================= */ + + $.fn.alert = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('alert') + if (!data) $this.data('alert', (data = new Alert(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.alert.Constructor = Alert + + + /* ALERT DATA-API + * ============== */ + + $(function () { + $('body').on('click.alert.data-api', dismiss, Alert.prototype.close) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-button.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-button.js new file mode 100644 index 0000000..0238ca3 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-button.js @@ -0,0 +1,100 @@ +/* ============================================================ + * bootstrap-button.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#buttons + * ============================================================ + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + +!function( $ ){ + + "use strict" + + /* BUTTON PUBLIC CLASS DEFINITION + * ============================== */ + + var Button = function ( element, options ) { + this.$element = $(element) + this.options = $.extend({}, $.fn.button.defaults, options) + } + + Button.prototype = { + + constructor: Button + + , setState: function ( state ) { + var d = 'disabled' + , $el = this.$element + , data = $el.data() + , val = $el.is('input') ? 'val' : 'html' + + state = state + 'Text' + data.resetText || $el.data('resetText', $el[val]()) + + $el[val](data[state] || this.options[state]) + + // push to event loop to allow forms to submit + setTimeout(function () { + state == 'loadingText' ? + $el.addClass(d).attr(d, d) : + $el.removeClass(d).removeAttr(d) + }, 0) + } + + , toggle: function () { + var $parent = this.$element.parent('[data-toggle="buttons-radio"]') + + $parent && $parent + .find('.active') + .removeClass('active') + + this.$element.toggleClass('active') + } + + } + + + /* BUTTON PLUGIN DEFINITION + * ======================== */ + + $.fn.button = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('button') + , options = typeof option == 'object' && option + if (!data) $this.data('button', (data = new Button(this, options))) + if (option == 'toggle') data.toggle() + else if (option) data.setState(option) + }) + } + + $.fn.button.defaults = { + loadingText: 'loading...' + } + + $.fn.button.Constructor = Button + + + /* BUTTON DATA-API + * =============== */ + + $(function () { + $('body').on('click.button.data-api', '[data-toggle^=button]', function ( e ) { + var $btn = $(e.target) + if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') + $btn.button('toggle') + }) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-carousel.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-carousel.js new file mode 100644 index 0000000..810256e --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-carousel.js @@ -0,0 +1,157 @@ +/* ========================================================== + * bootstrap-carousel.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#carousel + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function( $ ){ + + "use strict" + + /* CAROUSEL CLASS DEFINITION + * ========================= */ + + var Carousel = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, $.fn.carousel.defaults, options) + this.options.slide && this.slide(this.options.slide) + } + + Carousel.prototype = { + + cycle: function () { + this.interval = setInterval($.proxy(this.next, this), this.options.interval) + return this + } + + , to: function (pos) { + var $active = this.$element.find('.active') + , children = $active.parent().children() + , activePos = children.index($active) + , that = this + + if (pos > (children.length - 1) || pos < 0) return + + if (this.sliding) { + return this.$element.one('slid', function () { + that.to(pos) + }) + } + + if (activePos == pos) { + return this.pause().cycle() + } + + return this.slide(pos > activePos ? 'next' : 'prev', $(children[pos])) + } + + , pause: function () { + clearInterval(this.interval) + this.interval = null + return this + } + + , next: function () { + if (this.sliding) return + return this.slide('next') + } + + , prev: function () { + if (this.sliding) return + return this.slide('prev') + } + + , slide: function (type, next) { + var $active = this.$element.find('.active') + , $next = next || $active[type]() + , isCycling = this.interval + , direction = type == 'next' ? 'left' : 'right' + , fallback = type == 'next' ? 'first' : 'last' + , that = this + + if (!$next.length) return + + this.sliding = true + + isCycling && this.pause() + + $next = $next.length ? $next : this.$element.find('.item')[fallback]() + + if (!$.support.transition && this.$element.hasClass('slide')) { + this.$element.trigger('slide') + $active.removeClass('active') + $next.addClass('active') + this.sliding = false + this.$element.trigger('slid') + } else { + $next.addClass(type) + $next[0].offsetWidth // force reflow + $active.addClass(direction) + $next.addClass(direction) + this.$element.trigger('slide') + this.$element.one($.support.transition.end, function () { + $next.removeClass([type, direction].join(' ')).addClass('active') + $active.removeClass(['active', direction].join(' ')) + that.sliding = false + setTimeout(function () { that.$element.trigger('slid') }, 0) + }) + } + + isCycling && this.cycle() + + return this + } + + } + + + /* CAROUSEL PLUGIN DEFINITION + * ========================== */ + + $.fn.carousel = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('carousel') + , options = typeof option == 'object' && option + if (!data) $this.data('carousel', (data = new Carousel(this, options))) + if (typeof option == 'number') data.to(option) + else if (typeof option == 'string' || (option = options.slide)) data[option]() + else data.cycle() + }) + } + + $.fn.carousel.defaults = { + interval: 5000 + } + + $.fn.carousel.Constructor = Carousel + + + /* CAROUSEL DATA-API + * ================= */ + + $(function () { + $('body').on('click.carousel.data-api', '[data-slide]', function ( e ) { + var $this = $(this), href + , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 + , options = !$target.data('modal') && $.extend({}, $target.data(), $this.data()) + $target.carousel(options) + e.preventDefault() + }) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-collapse.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-collapse.js new file mode 100644 index 0000000..d195efc --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-collapse.js @@ -0,0 +1,136 @@ +/* ============================================================= + * bootstrap-collapse.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#collapse + * ============================================================= + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + +!function( $ ){ + + "use strict" + + var Collapse = function ( element, options ) { + this.$element = $(element) + this.options = $.extend({}, $.fn.collapse.defaults, options) + + if (this.options["parent"]) { + this.$parent = $(this.options["parent"]) + } + + this.options.toggle && this.toggle() + } + + Collapse.prototype = { + + constructor: Collapse + + , dimension: function () { + var hasWidth = this.$element.hasClass('width') + return hasWidth ? 'width' : 'height' + } + + , show: function () { + var dimension = this.dimension() + , scroll = $.camelCase(['scroll', dimension].join('-')) + , actives = this.$parent && this.$parent.find('.in') + , hasData + + if (actives && actives.length) { + hasData = actives.data('collapse') + actives.collapse('hide') + hasData || actives.data('collapse', null) + } + + this.$element[dimension](0) + this.transition('addClass', 'show', 'shown') + this.$element[dimension](this.$element[0][scroll]) + + } + + , hide: function () { + var dimension = this.dimension() + this.reset(this.$element[dimension]()) + this.transition('removeClass', 'hide', 'hidden') + this.$element[dimension](0) + } + + , reset: function ( size ) { + var dimension = this.dimension() + + this.$element + .removeClass('collapse') + [dimension](size || 'auto') + [0].offsetWidth + + this.$element.addClass('collapse') + } + + , transition: function ( method, startEvent, completeEvent ) { + var that = this + , complete = function () { + if (startEvent == 'show') that.reset() + that.$element.trigger(completeEvent) + } + + this.$element + .trigger(startEvent) + [method]('in') + + $.support.transition && this.$element.hasClass('collapse') ? + this.$element.one($.support.transition.end, complete) : + complete() + } + + , toggle: function () { + this[this.$element.hasClass('in') ? 'hide' : 'show']() + } + + } + + /* COLLAPSIBLE PLUGIN DEFINITION + * ============================== */ + + $.fn.collapse = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('collapse') + , options = typeof option == 'object' && option + if (!data) $this.data('collapse', (data = new Collapse(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.collapse.defaults = { + toggle: true + } + + $.fn.collapse.Constructor = Collapse + + + /* COLLAPSIBLE DATA-API + * ==================== */ + + $(function () { + $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function ( e ) { + var $this = $(this), href + , target = $this.attr('data-target') + || e.preventDefault() + || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 + , option = $(target).data('collapse') ? 'toggle' : $this.data() + $(target).collapse(option) + }) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-dropdown.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-dropdown.js new file mode 100644 index 0000000..f1f6c33 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-dropdown.js @@ -0,0 +1,92 @@ +/* ============================================================ + * bootstrap-dropdown.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#dropdowns + * ============================================================ + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + + +!function( $ ){ + + "use strict" + + /* DROPDOWN CLASS DEFINITION + * ========================= */ + + var toggle = '[data-toggle="dropdown"]' + , Dropdown = function ( element ) { + var $el = $(element).on('click.dropdown.data-api', this.toggle) + $('html').on('click.dropdown.data-api', function () { + $el.parent().removeClass('open') + }) + } + + Dropdown.prototype = { + + constructor: Dropdown + + , toggle: function ( e ) { + var $this = $(this) + , selector = $this.attr('data-target') + , $parent + , isActive + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = $(selector) + $parent.length || ($parent = $this.parent()) + + isActive = $parent.hasClass('open') + + clearMenus() + !isActive && $parent.toggleClass('open') + + return false + } + + } + + function clearMenus() { + $(toggle).parent().removeClass('open') + } + + + /* DROPDOWN PLUGIN DEFINITION + * ========================== */ + + $.fn.dropdown = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('dropdown') + if (!data) $this.data('dropdown', (data = new Dropdown(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.dropdown.Constructor = Dropdown + + + /* APPLY TO STANDARD DROPDOWN ELEMENTS + * =================================== */ + + $(function () { + $('html').on('click.dropdown.data-api', clearMenus) + $('body').on('click.dropdown.data-api', toggle, Dropdown.prototype.toggle) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-modal.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-modal.js new file mode 100644 index 0000000..bceb303 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-modal.js @@ -0,0 +1,210 @@ +/* ========================================================= + * bootstrap-modal.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#modals + * ========================================================= + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================= */ + + +!function( $ ){ + + "use strict" + + /* MODAL CLASS DEFINITION + * ====================== */ + + var Modal = function ( content, options ) { + this.options = options + this.$element = $(content) + .delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this)) + } + + Modal.prototype = { + + constructor: Modal + + , toggle: function () { + return this[!this.isShown ? 'show' : 'hide']() + } + + , show: function () { + var that = this + + if (this.isShown) return + + $('body').addClass('modal-open') + + this.isShown = true + this.$element.trigger('show') + + escape.call(this) + backdrop.call(this, function () { + var transition = $.support.transition && that.$element.hasClass('fade') + + !that.$element.parent().length && that.$element.appendTo(document.body) //don't move modals dom position + + that.$element + .show() + + if (transition) { + that.$element[0].offsetWidth // force reflow + } + + that.$element.addClass('in') + + transition ? + that.$element.one($.support.transition.end, function () { that.$element.trigger('shown') }) : + that.$element.trigger('shown') + + }) + } + + , hide: function ( e ) { + e && e.preventDefault() + + if (!this.isShown) return + + var that = this + this.isShown = false + + $('body').removeClass('modal-open') + + escape.call(this) + + this.$element + .trigger('hide') + .removeClass('in') + + $.support.transition && this.$element.hasClass('fade') ? + hideWithTransition.call(this) : + hideModal.call(this) + } + + } + + + /* MODAL PRIVATE METHODS + * ===================== */ + + function hideWithTransition() { + var that = this + , timeout = setTimeout(function () { + that.$element.off($.support.transition.end) + hideModal.call(that) + }, 500) + + this.$element.one($.support.transition.end, function () { + clearTimeout(timeout) + hideModal.call(that) + }) + } + + function hideModal( that ) { + this.$element + .hide() + .trigger('hidden') + + backdrop.call(this) + } + + function backdrop( callback ) { + var that = this + , animate = this.$element.hasClass('fade') ? 'fade' : '' + + if (this.isShown && this.options.backdrop) { + var doAnimate = $.support.transition && animate + + this.$backdrop = $(' + + + + + \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/head.html b/src/nl/astraeus/jdbc/web/head.html new file mode 100644 index 0000000..0f8f6a3 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/head.html @@ -0,0 +1,96 @@ + + + + + + + Simple JDBC Statistics + + + + + + + + + + + + + + + + + + + +
+
+ +
+ diff --git a/src/nl/astraeus/jdbc/web/page/Menu.html b/src/nl/astraeus/jdbc/web/page/Menu.html new file mode 100644 index 0000000..505c7c2 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.html @@ -0,0 +1,42 @@ + diff --git a/src/nl/astraeus/jdbc/web/page/Menu.java b/src/nl/astraeus/jdbc/web/page/Menu.java new file mode 100644 index 0000000..f0a349a --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.java @@ -0,0 +1,27 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 9:07 PM + */ +public class Menu extends TemplatePage { + + @Override + public Page processRequest(HttpServletRequest request) { + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + result.put("user", request.getSession().getAttribute("user")); + + return result; + } +} diff --git a/src/nl/astraeus/jdbc/web/page/Page.java b/src/nl/astraeus/jdbc/web/page/Page.java new file mode 100644 index 0000000..9d526d6 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Page.java @@ -0,0 +1,17 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:20 PM + */ +public abstract class Page { + + public abstract Page processRequest(HttpServletRequest request); + public abstract Map defineModel(HttpServletRequest request); + public abstract String render(HttpServletRequest request); + +} diff --git a/src/nl/astraeus/jdbc/web/page/QueryOverview.html b/src/nl/astraeus/jdbc/web/page/QueryOverview.html new file mode 100644 index 0000000..64a88fb --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/QueryOverview.html @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + {foreach(queries as q)} + + + + + + + {eachend} + +
Total timeAvg. time# CallsSql
{q.total}{q.nano}{q.count}{q.sql}
diff --git a/src/nl/astraeus/jdbc/web/page/QueryOverview.java b/src/nl/astraeus/jdbc/web/page/QueryOverview.java new file mode 100644 index 0000000..02982f1 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/QueryOverview.java @@ -0,0 +1,92 @@ +package nl.astraeus.jdbc.web.page; + +import nl.astraeus.jdbc.JdbcLogger; + +import javax.servlet.http.HttpServletRequest; +import java.util.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 9:16 PM + */ +public class QueryOverview extends TemplatePage { + + boolean sortTotalCalls = true; + boolean sortAvgTime = false; + boolean sortTotalTime = false; + + @Override + public Page processRequest(HttpServletRequest request) { + if ("sortTotalCalls".equals(request.getParameter("action"))) { + sortTotalCalls = true; + sortAvgTime = false; + sortTotalTime = false; + } else if ("sortAvgTime".equals(request.getParameter("action"))) { + sortTotalCalls = false; + sortAvgTime = true; + sortTotalTime = false; + } else if ("sortTotalTime".equals(request.getParameter("action"))) { + sortTotalCalls = false; + sortAvgTime = false; + sortTotalTime = true; + } + + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + List entries = new ArrayList(JdbcLogger.get().getEntries()); + + if (sortTotalCalls) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + return o2.count - o1.count; + } + }); + } else if (sortAvgTime) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + long n1 = o1.nano / o1.count; + long n2 = o2.nano / o2.count; + + if (n2 > n1) { + return 1; + } else if (n2 < n1) { + return -1; + } else { + return 0; + } + } + }); + } else if (sortTotalTime) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + if (o2.nano > o1.nano) { + return 1; + } else if (o2.nano < o1.nano) { + return -1; + } else { + return 0; + } + } + }); + } + + result.put("queries", entries); + result.put("count", entries.size()); + + result.put("sortTotalCalls", sortTotalCalls); + result.put("sortAvgTime", sortAvgTime); + result.put("sortTotalTime", sortTotalTime); + + return result; + } + +} diff --git a/src/nl/astraeus/jdbc/web/page/TemplatePage.java b/src/nl/astraeus/jdbc/web/page/TemplatePage.java new file mode 100644 index 0000000..33e2641 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/TemplatePage.java @@ -0,0 +1,58 @@ +package nl.astraeus.jdbc.web.page; + +import nl.astraeus.template.EscapeMode; +import nl.astraeus.template.SimpleTemplate; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:20 PM + */ +public abstract class TemplatePage extends Page { + + private SimpleTemplate template; + + protected TemplatePage() { + template = getSimpleTemplate(this.getClass()); + } + + public String render(HttpServletRequest request) { + return template.render(defineModel(request)); + } + + private static Map templateCache = new HashMap(); + + public synchronized static SimpleTemplate getSimpleTemplate(Class cls) { + SimpleTemplate result = templateCache.get(cls); + + if (result == null) { + InputStream in = null; + + try { + in = cls.getResourceAsStream(cls.getSimpleName() + ".html"); + + result = SimpleTemplate.readTemplate('{','}', EscapeMode.HTML, in); + + templateCache.put(cls, result); + } catch (IOException e) { + throw new IllegalStateException(e); + } finally { + if (in != null) { + try { + in.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + + return result; + } +} diff --git a/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css b/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css new file mode 100644 index 0000000..0e0056f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css @@ -0,0 +1,581 @@ +/*! + * Bootstrap Responsive v2.0.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ +.clearfix { + *zoom: 1; +} +.clearfix:before, .clearfix:after { + display: table; + content: ""; +} +.clearfix:after { + clear: both; +} +.hidden { + display: none; + visibility: hidden; +} +@media (max-width: 480px) { + .nav-collapse { + -webkit-transform: translate3d(0, 0, 0); + } + .page-header h1 small { + display: block; + line-height: 18px; + } + input[class*="span"], + select[class*="span"], + textarea[class*="span"], + .uneditable-input { + display: block; + width: 100%; + min-height: 28px; + /* Make inputs at least the height of their button counterpart */ + + /* Makes inputs behave like true block-level elements */ + + -webkit-box-sizing: border-box; + /* Older Webkit */ + + -moz-box-sizing: border-box; + /* Older FF */ + + -ms-box-sizing: border-box; + /* IE8 */ + + box-sizing: border-box; + /* CSS3 spec*/ + + } + .input-prepend input[class*="span"], .input-append input[class*="span"] { + width: auto; + } + input[type="checkbox"], input[type="radio"] { + border: 1px solid #ccc; + } + .form-horizontal .control-group > label { + float: none; + width: auto; + padding-top: 0; + text-align: left; + } + .form-horizontal .controls { + margin-left: 0; + } + .form-horizontal .control-list { + padding-top: 0; + } + .form-horizontal .form-actions { + padding-left: 10px; + padding-right: 10px; + } + .modal { + position: absolute; + top: 10px; + left: 10px; + right: 10px; + width: auto; + margin: 0; + } + .modal.fade.in { + top: auto; + } + .modal-header .close { + padding: 10px; + margin: -10px; + } + .carousel-caption { + position: static; + } +} +@media (max-width: 767px) { + .container { + width: auto; + padding: 0 20px; + } + .row-fluid { + width: 100%; + } + .row { + margin-left: 0; + } + .row > [class*="span"], .row-fluid > [class*="span"] { + float: none; + display: block; + width: auto; + margin: 0; + } +} +@media (min-width: 768px) and (max-width: 979px) { + .row { + margin-left: -20px; + *zoom: 1; + } + .row:before, .row:after { + display: table; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + margin-left: 20px; + } + .span1 { + width: 42px; + } + .span2 { + width: 104px; + } + .span3 { + width: 166px; + } + .span4 { + width: 228px; + } + .span5 { + width: 290px; + } + .span6 { + width: 352px; + } + .span7 { + width: 414px; + } + .span8 { + width: 476px; + } + .span9 { + width: 538px; + } + .span10 { + width: 600px; + } + .span11 { + width: 662px; + } + .span12, .container { + width: 724px; + } + .offset1 { + margin-left: 82px; + } + .offset2 { + margin-left: 144px; + } + .offset3 { + margin-left: 206px; + } + .offset4 { + margin-left: 268px; + } + .offset5 { + margin-left: 330px; + } + .offset6 { + margin-left: 392px; + } + .offset7 { + margin-left: 454px; + } + .offset8 { + margin-left: 516px; + } + .offset9 { + margin-left: 578px; + } + .offset10 { + margin-left: 640px; + } + .offset11 { + margin-left: 702px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, .row-fluid:after { + display: table; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid > [class*="span"] { + float: left; + margin-left: 2.762430939%; + } + .row-fluid > [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid > .span1 { + width: 5.801104972%; + } + .row-fluid > .span2 { + width: 14.364640883%; + } + .row-fluid > .span3 { + width: 22.928176794%; + } + .row-fluid > .span4 { + width: 31.491712705%; + } + .row-fluid > .span5 { + width: 40.055248616%; + } + .row-fluid > .span6 { + width: 48.618784527%; + } + .row-fluid > .span7 { + width: 57.182320438000005%; + } + .row-fluid > .span8 { + width: 65.74585634900001%; + } + .row-fluid > .span9 { + width: 74.30939226%; + } + .row-fluid > .span10 { + width: 82.87292817100001%; + } + .row-fluid > .span11 { + width: 91.436464082%; + } + .row-fluid > .span12 { + width: 99.999999993%; + } + input.span1, textarea.span1, .uneditable-input.span1 { + width: 32px; + } + input.span2, textarea.span2, .uneditable-input.span2 { + width: 94px; + } + input.span3, textarea.span3, .uneditable-input.span3 { + width: 156px; + } + input.span4, textarea.span4, .uneditable-input.span4 { + width: 218px; + } + input.span5, textarea.span5, .uneditable-input.span5 { + width: 280px; + } + input.span6, textarea.span6, .uneditable-input.span6 { + width: 342px; + } + input.span7, textarea.span7, .uneditable-input.span7 { + width: 404px; + } + input.span8, textarea.span8, .uneditable-input.span8 { + width: 466px; + } + input.span9, textarea.span9, .uneditable-input.span9 { + width: 528px; + } + input.span10, textarea.span10, .uneditable-input.span10 { + width: 590px; + } + input.span11, textarea.span11, .uneditable-input.span11 { + width: 652px; + } + input.span12, textarea.span12, .uneditable-input.span12 { + width: 714px; + } +} +@media (max-width: 979px) { + body { + padding-top: 0; + } + .navbar-fixed-top { + position: static; + margin-bottom: 18px; + } + .navbar-fixed-top .navbar-inner { + padding: 5px; + } + .navbar .container { + width: auto; + padding: 0; + } + .navbar .brand { + padding-left: 10px; + padding-right: 10px; + margin: 0 0 0 -5px; + } + .navbar .nav-collapse { + clear: left; + } + .navbar .nav { + float: none; + margin: 0 0 9px; + } + .navbar .nav > li { + float: none; + } + .navbar .nav > li > a { + margin-bottom: 2px; + } + .navbar .nav > .divider-vertical { + display: none; + } + .navbar .nav .nav-header { + color: #999999; + text-shadow: none; + } + .navbar .nav > li > a, .navbar .dropdown-menu a { + padding: 6px 15px; + font-weight: bold; + color: #999999; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + } + .navbar .dropdown-menu li + li a { + margin-bottom: 2px; + } + .navbar .nav > li > a:hover, .navbar .dropdown-menu a:hover { + background-color: #222222; + } + .navbar .dropdown-menu { + position: static; + top: auto; + left: auto; + float: none; + display: block; + max-width: none; + margin: 0 15px; + padding: 0; + background-color: transparent; + border: none; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + } + .navbar .dropdown-menu:before, .navbar .dropdown-menu:after { + display: none; + } + .navbar .dropdown-menu .divider { + display: none; + } + .navbar-form, .navbar-search { + float: none; + padding: 9px 15px; + margin: 9px 0; + border-top: 1px solid #222222; + border-bottom: 1px solid #222222; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + } + .navbar .nav.pull-right { + float: none; + margin-left: 0; + } + .navbar-static .navbar-inner { + padding-left: 10px; + padding-right: 10px; + } + .btn-navbar { + display: block; + } + .nav-collapse { + overflow: hidden; + height: 0; + } +} +@media (min-width: 980px) { + .nav-collapse.collapse { + height: auto !important; + } +} +@media (min-width: 1200px) { + .row { + margin-left: -30px; + *zoom: 1; + } + .row:before, .row:after { + display: table; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + margin-left: 30px; + } + .span1 { + width: 70px; + } + .span2 { + width: 170px; + } + .span3 { + width: 270px; + } + .span4 { + width: 370px; + } + .span5 { + width: 470px; + } + .span6 { + width: 570px; + } + .span7 { + width: 670px; + } + .span8 { + width: 770px; + } + .span9 { + width: 870px; + } + .span10 { + width: 970px; + } + .span11 { + width: 1070px; + } + .span12, .container { + width: 1170px; + } + .offset1 { + margin-left: 130px; + } + .offset2 { + margin-left: 230px; + } + .offset3 { + margin-left: 330px; + } + .offset4 { + margin-left: 430px; + } + .offset5 { + margin-left: 530px; + } + .offset6 { + margin-left: 630px; + } + .offset7 { + margin-left: 730px; + } + .offset8 { + margin-left: 830px; + } + .offset9 { + margin-left: 930px; + } + .offset10 { + margin-left: 1030px; + } + .offset11 { + margin-left: 1130px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, .row-fluid:after { + display: table; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid > [class*="span"] { + float: left; + margin-left: 2.564102564%; + } + .row-fluid > [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid > .span1 { + width: 5.982905983%; + } + .row-fluid > .span2 { + width: 14.529914530000001%; + } + .row-fluid > .span3 { + width: 23.076923077%; + } + .row-fluid > .span4 { + width: 31.623931624%; + } + .row-fluid > .span5 { + width: 40.170940171000005%; + } + .row-fluid > .span6 { + width: 48.717948718%; + } + .row-fluid > .span7 { + width: 57.264957265%; + } + .row-fluid > .span8 { + width: 65.81196581200001%; + } + .row-fluid > .span9 { + width: 74.358974359%; + } + .row-fluid > .span10 { + width: 82.905982906%; + } + .row-fluid > .span11 { + width: 91.45299145300001%; + } + .row-fluid > .span12 { + width: 100%; + } + input.span1, textarea.span1, .uneditable-input.span1 { + width: 60px; + } + input.span2, textarea.span2, .uneditable-input.span2 { + width: 160px; + } + input.span3, textarea.span3, .uneditable-input.span3 { + width: 260px; + } + input.span4, textarea.span4, .uneditable-input.span4 { + width: 360px; + } + input.span5, textarea.span5, .uneditable-input.span5 { + width: 460px; + } + input.span6, textarea.span6, .uneditable-input.span6 { + width: 560px; + } + input.span7, textarea.span7, .uneditable-input.span7 { + width: 660px; + } + input.span8, textarea.span8, .uneditable-input.span8 { + width: 760px; + } + input.span9, textarea.span9, .uneditable-input.span9 { + width: 860px; + } + input.span10, textarea.span10, .uneditable-input.span10 { + width: 960px; + } + input.span11, textarea.span11, .uneditable-input.span11 { + width: 1060px; + } + input.span12, textarea.span12, .uneditable-input.span12 { + width: 1160px; + } + .thumbnails { + margin-left: -30px; + } + .thumbnails > li { + margin-left: 30px; + } +} diff --git a/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css b/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css new file mode 100644 index 0000000..6229c12 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css @@ -0,0 +1,3521 @@ +/*! + * Bootstrap v2.0.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +nav, +section { + display: block; +} +audio, canvas, video { + display: inline-block; + *display: inline; + *zoom: 1; +} +audio:not([controls]) { + display: none; +} +html { + font-size: 100%; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} +a:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +a:hover, a:active { + outline: 0; +} +sub, sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} +sup { + top: -0.5em; +} +sub { + bottom: -0.25em; +} +img { + max-width: 100%; + height: auto; + border: 0; + -ms-interpolation-mode: bicubic; +} +button, +input, +select, +textarea { + margin: 0; + font-size: 100%; + vertical-align: middle; +} +button, input { + *overflow: visible; + line-height: normal; +} +button::-moz-focus-inner, input::-moz-focus-inner { + padding: 0; + border: 0; +} +button, +input[type="button"], +input[type="reset"], +input[type="submit"] { + cursor: pointer; + -webkit-appearance: button; +} +input[type="search"] { + -webkit-appearance: textfield; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +input[type="search"]::-webkit-search-decoration, input[type="search"]::-webkit-search-cancel-button { + -webkit-appearance: none; +} +textarea { + overflow: auto; + vertical-align: top; +} +.clearfix { + *zoom: 1; +} +.clearfix:before, .clearfix:after { + display: table; + content: ""; +} +.clearfix:after { + clear: both; +} +body { + margin: 0; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 18px; + color: #333333; + background-color: #ffffff; +} +a { + color: #0088cc; + text-decoration: none; +} +a:hover { + color: #005580; + text-decoration: underline; +} +.row { + margin-left: -20px; + *zoom: 1; +} +.row:before, .row:after { + display: table; + content: ""; +} +.row:after { + clear: both; +} +[class*="span"] { + float: left; + margin-left: 20px; +} +.span1 { + width: 60px; +} +.span2 { + width: 140px; +} +.span3 { + width: 220px; +} +.span4 { + width: 300px; +} +.span5 { + width: 380px; +} +.span6 { + width: 460px; +} +.span7 { + width: 540px; +} +.span8 { + width: 620px; +} +.span9 { + width: 700px; +} +.span10 { + width: 780px; +} +.span11 { + width: 860px; +} +.span12, .container { + width: 940px; +} +.offset1 { + margin-left: 100px; +} +.offset2 { + margin-left: 180px; +} +.offset3 { + margin-left: 260px; +} +.offset4 { + margin-left: 340px; +} +.offset5 { + margin-left: 420px; +} +.offset6 { + margin-left: 500px; +} +.offset7 { + margin-left: 580px; +} +.offset8 { + margin-left: 660px; +} +.offset9 { + margin-left: 740px; +} +.offset10 { + margin-left: 820px; +} +.offset11 { + margin-left: 900px; +} +.row-fluid { + width: 100%; + *zoom: 1; +} +.row-fluid:before, .row-fluid:after { + display: table; + content: ""; +} +.row-fluid:after { + clear: both; +} +.row-fluid > [class*="span"] { + float: left; + margin-left: 2.127659574%; +} +.row-fluid > [class*="span"]:first-child { + margin-left: 0; +} +.row-fluid > .span1 { + width: 6.382978723%; +} +.row-fluid > .span2 { + width: 14.89361702%; +} +.row-fluid > .span3 { + width: 23.404255317%; +} +.row-fluid > .span4 { + width: 31.914893614%; +} +.row-fluid > .span5 { + width: 40.425531911%; +} +.row-fluid > .span6 { + width: 48.93617020799999%; +} +.row-fluid > .span7 { + width: 57.446808505%; +} +.row-fluid > .span8 { + width: 65.95744680199999%; +} +.row-fluid > .span9 { + width: 74.468085099%; +} +.row-fluid > .span10 { + width: 82.97872339599999%; +} +.row-fluid > .span11 { + width: 91.489361693%; +} +.row-fluid > .span12 { + width: 99.99999998999999%; +} +.container { + width: 940px; + margin-left: auto; + margin-right: auto; + *zoom: 1; +} +.container:before, .container:after { + display: table; + content: ""; +} +.container:after { + clear: both; +} +.container-fluid { + padding-left: 20px; + padding-right: 20px; + *zoom: 1; +} +.container-fluid:before, .container-fluid:after { + display: table; + content: ""; +} +.container-fluid:after { + clear: both; +} +p { + margin: 0 0 9px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 18px; +} +p small { + font-size: 11px; + color: #999999; +} +.lead { + margin-bottom: 18px; + font-size: 20px; + font-weight: 200; + line-height: 27px; +} +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 0; + font-weight: bold; + color: #333333; + text-rendering: optimizelegibility; +} +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small { + font-weight: normal; + color: #999999; +} +h1 { + font-size: 30px; + line-height: 36px; +} +h1 small { + font-size: 18px; +} +h2 { + font-size: 24px; + line-height: 36px; +} +h2 small { + font-size: 18px; +} +h3 { + line-height: 27px; + font-size: 18px; +} +h3 small { + font-size: 14px; +} +h4, h5, h6 { + line-height: 18px; +} +h4 { + font-size: 14px; +} +h4 small { + font-size: 12px; +} +h5 { + font-size: 12px; +} +h6 { + font-size: 11px; + color: #999999; + text-transform: uppercase; +} +.page-header { + padding-bottom: 17px; + margin: 18px 0; + border-bottom: 1px solid #eeeeee; +} +.page-header h1 { + line-height: 1; +} +ul, ol { + padding: 0; + margin: 0 0 9px 25px; +} +ul ul, +ul ol, +ol ol, +ol ul { + margin-bottom: 0; +} +ul { + list-style: disc; +} +ol { + list-style: decimal; +} +li { + line-height: 18px; +} +ul.unstyled, ol.unstyled { + margin-left: 0; + list-style: none; +} +dl { + margin-bottom: 18px; +} +dt, dd { + line-height: 18px; +} +dt { + font-weight: bold; +} +dd { + margin-left: 9px; +} +hr { + margin: 18px 0; + border: 0; + border-top: 1px solid #eeeeee; + border-bottom: 1px solid #ffffff; +} +strong { + font-weight: bold; +} +em { + font-style: italic; +} +.muted { + color: #999999; +} +abbr { + font-size: 90%; + text-transform: uppercase; + border-bottom: 1px dotted #ddd; + cursor: help; +} +blockquote { + padding: 0 0 0 15px; + margin: 0 0 18px; + border-left: 5px solid #eeeeee; +} +blockquote p { + margin-bottom: 0; + font-size: 16px; + font-weight: 300; + line-height: 22.5px; +} +blockquote small { + display: block; + line-height: 18px; + color: #999999; +} +blockquote small:before { + content: '\2014 \00A0'; +} +blockquote.pull-right { + float: right; + padding-left: 0; + padding-right: 15px; + border-left: 0; + border-right: 5px solid #eeeeee; +} +blockquote.pull-right p, blockquote.pull-right small { + text-align: right; +} +q:before, +q:after, +blockquote:before, +blockquote:after { + content: ""; +} +address { + display: block; + margin-bottom: 18px; + line-height: 18px; + font-style: normal; +} +small { + font-size: 100%; +} +cite { + font-style: normal; +} +code, pre { + padding: 0 3px 2px; + font-family: Menlo, Monaco, "Courier New", monospace; + font-size: 12px; + color: #333333; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +code { + padding: 3px 4px; + color: #d14; + background-color: #f7f7f9; + border: 1px solid #e1e1e8; +} +pre { + display: block; + padding: 8.5px; + margin: 0 0 9px; + font-size: 12px; + line-height: 18px; + background-color: #f5f5f5; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.15); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + white-space: pre; + white-space: pre-wrap; + word-break: break-all; + word-wrap: break-word; +} +pre.prettyprint { + margin-bottom: 18px; +} +pre code { + padding: 0; + color: inherit; + background-color: transparent; + border: 0; +} +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} +form { + margin: 0 0 18px; +} +fieldset { + padding: 0; + margin: 0; + border: 0; +} +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 27px; + font-size: 19.5px; + line-height: 36px; + color: #333333; + border: 0; + border-bottom: 1px solid #eee; +} +legend small { + font-size: 13.5px; + color: #999999; +} +label, +input, +button, +select, +textarea { + font-size: 13px; + font-weight: normal; + line-height: 18px; +} +input, +button, +select, +textarea { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; +} +label { + display: block; + margin-bottom: 5px; + color: #333333; +} +input, +textarea, +select, +.uneditable-input { + display: inline-block; + width: 210px; + height: 18px; + padding: 4px; + margin-bottom: 9px; + font-size: 13px; + line-height: 18px; + color: #555555; + border: 1px solid #ccc; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.uneditable-textarea { + width: auto; + height: auto; +} +label input, label textarea, label select { + display: block; +} +input[type="image"], input[type="checkbox"], input[type="radio"] { + width: auto; + height: auto; + padding: 0; + margin: 3px 0; + *margin-top: 0; + /* IE7 */ + + line-height: normal; + cursor: pointer; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + border: 0 \9; + /* IE9 and down */ + +} +input[type="image"] { + border: 0; +} +input[type="file"] { + width: auto; + padding: initial; + line-height: initial; + border: initial; + background-color: #ffffff; + background-color: initial; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +input[type="button"], input[type="reset"], input[type="submit"] { + width: auto; + height: auto; +} +select, input[type="file"] { + height: 28px; + /* In IE7, the height of the select element cannot be changed by height, only font-size */ + + *margin-top: 4px; + /* For IE7, add top margin to align select with labels */ + + line-height: 28px; +} +input[type="file"] { + line-height: 18px \9; +} +select { + width: 220px; + background-color: #ffffff; +} +select[multiple], select[size] { + height: auto; +} +input[type="image"] { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +textarea { + height: auto; +} +input[type="hidden"] { + display: none; +} +.radio, .checkbox { + padding-left: 18px; +} +.radio input[type="radio"], .checkbox input[type="checkbox"] { + float: left; + margin-left: -18px; +} +.controls > .radio:first-child, .controls > .checkbox:first-child { + padding-top: 5px; +} +.radio.inline, .checkbox.inline { + display: inline-block; + padding-top: 5px; + margin-bottom: 0; + vertical-align: middle; +} +.radio.inline + .radio.inline, .checkbox.inline + .checkbox.inline { + margin-left: 10px; +} +input, textarea { + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; + -moz-transition: border linear 0.2s, box-shadow linear 0.2s; + -ms-transition: border linear 0.2s, box-shadow linear 0.2s; + -o-transition: border linear 0.2s, box-shadow linear 0.2s; + transition: border linear 0.2s, box-shadow linear 0.2s; +} +input:focus, textarea:focus { + border-color: rgba(82, 168, 236, 0.8); + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + outline: 0; + outline: thin dotted \9; + /* IE6-9 */ + +} +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus, +select:focus { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.input-mini { + width: 60px; +} +.input-small { + width: 90px; +} +.input-medium { + width: 150px; +} +.input-large { + width: 210px; +} +.input-xlarge { + width: 270px; +} +.input-xxlarge { + width: 530px; +} +input[class*="span"], +select[class*="span"], +textarea[class*="span"], +.uneditable-input { + float: none; + margin-left: 0; +} +input.span1, textarea.span1, .uneditable-input.span1 { + width: 50px; +} +input.span2, textarea.span2, .uneditable-input.span2 { + width: 130px; +} +input.span3, textarea.span3, .uneditable-input.span3 { + width: 210px; +} +input.span4, textarea.span4, .uneditable-input.span4 { + width: 290px; +} +input.span5, textarea.span5, .uneditable-input.span5 { + width: 370px; +} +input.span6, textarea.span6, .uneditable-input.span6 { + width: 450px; +} +input.span7, textarea.span7, .uneditable-input.span7 { + width: 530px; +} +input.span8, textarea.span8, .uneditable-input.span8 { + width: 610px; +} +input.span9, textarea.span9, .uneditable-input.span9 { + width: 690px; +} +input.span10, textarea.span10, .uneditable-input.span10 { + width: 770px; +} +input.span11, textarea.span11, .uneditable-input.span11 { + width: 850px; +} +input.span12, textarea.span12, .uneditable-input.span12 { + width: 930px; +} +input[disabled], +select[disabled], +textarea[disabled], +input[readonly], +select[readonly], +textarea[readonly] { + background-color: #f5f5f5; + border-color: #ddd; + cursor: not-allowed; +} +.control-group.warning > label, .control-group.warning .help-block, .control-group.warning .help-inline { + color: #c09853; +} +.control-group.warning input, .control-group.warning select, .control-group.warning textarea { + color: #c09853; + border-color: #c09853; +} +.control-group.warning input:focus, .control-group.warning select:focus, .control-group.warning textarea:focus { + border-color: #a47e3c; + -webkit-box-shadow: 0 0 6px #dbc59e; + -moz-box-shadow: 0 0 6px #dbc59e; + box-shadow: 0 0 6px #dbc59e; +} +.control-group.warning .input-prepend .add-on, .control-group.warning .input-append .add-on { + color: #c09853; + background-color: #fcf8e3; + border-color: #c09853; +} +.control-group.error > label, .control-group.error .help-block, .control-group.error .help-inline { + color: #b94a48; +} +.control-group.error input, .control-group.error select, .control-group.error textarea { + color: #b94a48; + border-color: #b94a48; +} +.control-group.error input:focus, .control-group.error select:focus, .control-group.error textarea:focus { + border-color: #953b39; + -webkit-box-shadow: 0 0 6px #d59392; + -moz-box-shadow: 0 0 6px #d59392; + box-shadow: 0 0 6px #d59392; +} +.control-group.error .input-prepend .add-on, .control-group.error .input-append .add-on { + color: #b94a48; + background-color: #f2dede; + border-color: #b94a48; +} +.control-group.success > label, .control-group.success .help-block, .control-group.success .help-inline { + color: #468847; +} +.control-group.success input, .control-group.success select, .control-group.success textarea { + color: #468847; + border-color: #468847; +} +.control-group.success input:focus, .control-group.success select:focus, .control-group.success textarea:focus { + border-color: #356635; + -webkit-box-shadow: 0 0 6px #7aba7b; + -moz-box-shadow: 0 0 6px #7aba7b; + box-shadow: 0 0 6px #7aba7b; +} +.control-group.success .input-prepend .add-on, .control-group.success .input-append .add-on { + color: #468847; + background-color: #dff0d8; + border-color: #468847; +} +input:focus:required:invalid, textarea:focus:required:invalid, select:focus:required:invalid { + color: #b94a48; + border-color: #ee5f5b; +} +input:focus:required:invalid:focus, textarea:focus:required:invalid:focus, select:focus:required:invalid:focus { + border-color: #e9322d; + -webkit-box-shadow: 0 0 6px #f8b9b7; + -moz-box-shadow: 0 0 6px #f8b9b7; + box-shadow: 0 0 6px #f8b9b7; +} +.form-actions { + padding: 17px 20px 18px; + margin-top: 18px; + margin-bottom: 18px; + background-color: #f5f5f5; + border-top: 1px solid #ddd; +} +.uneditable-input { + display: block; + background-color: #ffffff; + border-color: #eee; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + cursor: not-allowed; +} +:-moz-placeholder { + color: #999999; +} +::-webkit-input-placeholder { + color: #999999; +} +.help-block { + display: block; + margin-top: 5px; + margin-bottom: 0; + color: #999999; +} +.help-inline { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; + margin-bottom: 9px; + vertical-align: middle; + padding-left: 5px; +} +.input-prepend, .input-append { + margin-bottom: 5px; + *zoom: 1; +} +.input-prepend:before, +.input-append:before, +.input-prepend:after, +.input-append:after { + display: table; + content: ""; +} +.input-prepend:after, .input-append:after { + clear: both; +} +.input-prepend input, +.input-append input, +.input-prepend .uneditable-input, +.input-append .uneditable-input { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.input-prepend input:focus, +.input-append input:focus, +.input-prepend .uneditable-input:focus, +.input-append .uneditable-input:focus { + position: relative; + z-index: 2; +} +.input-prepend .uneditable-input, .input-append .uneditable-input { + border-left-color: #ccc; +} +.input-prepend .add-on, .input-append .add-on { + float: left; + display: block; + width: auto; + min-width: 16px; + height: 18px; + margin-right: -1px; + padding: 4px 5px; + font-weight: normal; + line-height: 18px; + color: #999999; + text-align: center; + text-shadow: 0 1px 0 #ffffff; + background-color: #f5f5f5; + border: 1px solid #ccc; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.input-prepend .active, .input-append .active { + background-color: #a9dba9; + border-color: #46a546; +} +.input-prepend .add-on { + *margin-top: 1px; + /* IE6-7 */ + +} +.input-append input, .input-append .uneditable-input { + float: left; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.input-append .uneditable-input { + border-left-color: #eee; + border-right-color: #ccc; +} +.input-append .add-on { + margin-right: 0; + margin-left: -1px; + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.input-append input:first-child { + *margin-left: -160px; +} +.input-append input:first-child + .add-on { + *margin-left: -21px; +} +.search-query { + padding-left: 14px; + padding-right: 14px; + margin-bottom: 0; + -webkit-border-radius: 14px; + -moz-border-radius: 14px; + border-radius: 14px; +} +.form-search input, +.form-inline input, +.form-horizontal input, +.form-search textarea, +.form-inline textarea, +.form-horizontal textarea, +.form-search select, +.form-inline select, +.form-horizontal select, +.form-search .help-inline, +.form-inline .help-inline, +.form-horizontal .help-inline, +.form-search .uneditable-input, +.form-inline .uneditable-input, +.form-horizontal .uneditable-input { + display: inline-block; + margin-bottom: 0; +} +.form-search .hide, .form-inline .hide, .form-horizontal .hide { + display: none; +} +.form-search label, +.form-inline label, +.form-search .input-append, +.form-inline .input-append, +.form-search .input-prepend, +.form-inline .input-prepend { + display: inline-block; +} +.form-search .input-append .add-on, +.form-inline .input-prepend .add-on, +.form-search .input-append .add-on, +.form-inline .input-prepend .add-on { + vertical-align: middle; +} +.form-search .radio, +.form-inline .radio, +.form-search .checkbox, +.form-inline .checkbox { + margin-bottom: 0; + vertical-align: middle; +} +.control-group { + margin-bottom: 9px; +} +legend + .control-group { + margin-top: 18px; + -webkit-margin-top-collapse: separate; +} +.form-horizontal .control-group { + margin-bottom: 18px; + *zoom: 1; +} +.form-horizontal .control-group:before, .form-horizontal .control-group:after { + display: table; + content: ""; +} +.form-horizontal .control-group:after { + clear: both; +} +.form-horizontal .control-label { + float: left; + width: 140px; + padding-top: 5px; + text-align: right; +} +.form-horizontal .controls { + margin-left: 160px; +} +.form-horizontal .form-actions { + padding-left: 160px; +} +table { + max-width: 100%; + border-collapse: collapse; + border-spacing: 0; +} +.table { + width: 100%; + margin-bottom: 18px; +} +.table th, .table td { + padding: 8px; + line-height: 18px; + text-align: left; + vertical-align: top; + border-top: 1px solid #ddd; +} +.table th { + font-weight: bold; +} +.table thead th { + vertical-align: bottom; +} +.table thead:first-child tr th, .table thead:first-child tr td { + border-top: 0; +} +.table tbody + tbody { + border-top: 2px solid #ddd; +} +.table-condensed th, .table-condensed td { + padding: 4px 5px; +} +.table-bordered { + border: 1px solid #ddd; + border-collapse: separate; + *border-collapse: collapsed; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.table-bordered th + th, +.table-bordered td + td, +.table-bordered th + td, +.table-bordered td + th { + border-left: 1px solid #ddd; +} +.table-bordered thead:first-child tr:first-child th, .table-bordered tbody:first-child tr:first-child th, .table-bordered tbody:first-child tr:first-child td { + border-top: 0; +} +.table-bordered thead:first-child tr:first-child th:first-child, .table-bordered tbody:first-child tr:first-child td:first-child { + -webkit-border-radius: 4px 0 0 0; + -moz-border-radius: 4px 0 0 0; + border-radius: 4px 0 0 0; +} +.table-bordered thead:first-child tr:first-child th:last-child, .table-bordered tbody:first-child tr:first-child td:last-child { + -webkit-border-radius: 0 4px 0 0; + -moz-border-radius: 0 4px 0 0; + border-radius: 0 4px 0 0; +} +.table-bordered thead:last-child tr:last-child th:first-child, .table-bordered tbody:last-child tr:last-child td:first-child { + -webkit-border-radius: 0 0 0 4px; + -moz-border-radius: 0 0 0 4px; + border-radius: 0 0 0 4px; +} +.table-bordered thead:last-child tr:last-child th:last-child, .table-bordered tbody:last-child tr:last-child td:last-child { + -webkit-border-radius: 0 0 4px 0; + -moz-border-radius: 0 0 4px 0; + border-radius: 0 0 4px 0; +} +.table-striped tbody tr:nth-child(odd) td, .table-striped tbody tr:nth-child(odd) th { + background-color: #f9f9f9; +} +.table tbody tr:hover td, .table tbody tr:hover th { + background-color: #f5f5f5; +} +table .span1 { + float: none; + width: 44px; + margin-left: 0; +} +table .span2 { + float: none; + width: 124px; + margin-left: 0; +} +table .span3 { + float: none; + width: 204px; + margin-left: 0; +} +table .span4 { + float: none; + width: 284px; + margin-left: 0; +} +table .span5 { + float: none; + width: 364px; + margin-left: 0; +} +table .span6 { + float: none; + width: 444px; + margin-left: 0; +} +table .span7 { + float: none; + width: 524px; + margin-left: 0; +} +table .span8 { + float: none; + width: 604px; + margin-left: 0; +} +table .span9 { + float: none; + width: 684px; + margin-left: 0; +} +table .span10 { + float: none; + width: 764px; + margin-left: 0; +} +table .span11 { + float: none; + width: 844px; + margin-left: 0; +} +table .span12 { + float: none; + width: 924px; + margin-left: 0; +} +[class^="icon-"], [class*=" icon-"] { + display: inline-block; + width: 14px; + height: 14px; + line-height: 14px; + vertical-align: text-top; + background-image: url("../img/glyphicons-halflings.png"); + background-position: 14px 14px; + background-repeat: no-repeat; + *margin-right: .3em; +} +[class^="icon-"]:last-child, [class*=" icon-"]:last-child { + *margin-left: 0; +} +.icon-white { + background-image: url("../img/glyphicons-halflings-white.png"); +} +.icon-glass { + background-position: 0 0; +} +.icon-music { + background-position: -24px 0; +} +.icon-search { + background-position: -48px 0; +} +.icon-envelope { + background-position: -72px 0; +} +.icon-heart { + background-position: -96px 0; +} +.icon-star { + background-position: -120px 0; +} +.icon-star-empty { + background-position: -144px 0; +} +.icon-user { + background-position: -168px 0; +} +.icon-film { + background-position: -192px 0; +} +.icon-th-large { + background-position: -216px 0; +} +.icon-th { + background-position: -240px 0; +} +.icon-th-list { + background-position: -264px 0; +} +.icon-ok { + background-position: -288px 0; +} +.icon-remove { + background-position: -312px 0; +} +.icon-zoom-in { + background-position: -336px 0; +} +.icon-zoom-out { + background-position: -360px 0; +} +.icon-off { + background-position: -384px 0; +} +.icon-signal { + background-position: -408px 0; +} +.icon-cog { + background-position: -432px 0; +} +.icon-trash { + background-position: -456px 0; +} +.icon-home { + background-position: 0 -24px; +} +.icon-file { + background-position: -24px -24px; +} +.icon-time { + background-position: -48px -24px; +} +.icon-road { + background-position: -72px -24px; +} +.icon-download-alt { + background-position: -96px -24px; +} +.icon-download { + background-position: -120px -24px; +} +.icon-upload { + background-position: -144px -24px; +} +.icon-inbox { + background-position: -168px -24px; +} +.icon-play-circle { + background-position: -192px -24px; +} +.icon-repeat { + background-position: -216px -24px; +} +.icon-refresh { + background-position: -240px -24px; +} +.icon-list-alt { + background-position: -264px -24px; +} +.icon-lock { + background-position: -287px -24px; +} +.icon-flag { + background-position: -312px -24px; +} +.icon-headphones { + background-position: -336px -24px; +} +.icon-volume-off { + background-position: -360px -24px; +} +.icon-volume-down { + background-position: -384px -24px; +} +.icon-volume-up { + background-position: -408px -24px; +} +.icon-qrcode { + background-position: -432px -24px; +} +.icon-barcode { + background-position: -456px -24px; +} +.icon-tag { + background-position: 0 -48px; +} +.icon-tags { + background-position: -25px -48px; +} +.icon-book { + background-position: -48px -48px; +} +.icon-bookmark { + background-position: -72px -48px; +} +.icon-print { + background-position: -96px -48px; +} +.icon-camera { + background-position: -120px -48px; +} +.icon-font { + background-position: -144px -48px; +} +.icon-bold { + background-position: -167px -48px; +} +.icon-italic { + background-position: -192px -48px; +} +.icon-text-height { + background-position: -216px -48px; +} +.icon-text-width { + background-position: -240px -48px; +} +.icon-align-left { + background-position: -264px -48px; +} +.icon-align-center { + background-position: -288px -48px; +} +.icon-align-right { + background-position: -312px -48px; +} +.icon-align-justify { + background-position: -336px -48px; +} +.icon-list { + background-position: -360px -48px; +} +.icon-indent-left { + background-position: -384px -48px; +} +.icon-indent-right { + background-position: -408px -48px; +} +.icon-facetime-video { + background-position: -432px -48px; +} +.icon-picture { + background-position: -456px -48px; +} +.icon-pencil { + background-position: 0 -72px; +} +.icon-map-marker { + background-position: -24px -72px; +} +.icon-adjust { + background-position: -48px -72px; +} +.icon-tint { + background-position: -72px -72px; +} +.icon-edit { + background-position: -96px -72px; +} +.icon-share { + background-position: -120px -72px; +} +.icon-check { + background-position: -144px -72px; +} +.icon-move { + background-position: -168px -72px; +} +.icon-step-backward { + background-position: -192px -72px; +} +.icon-fast-backward { + background-position: -216px -72px; +} +.icon-backward { + background-position: -240px -72px; +} +.icon-play { + background-position: -264px -72px; +} +.icon-pause { + background-position: -288px -72px; +} +.icon-stop { + background-position: -312px -72px; +} +.icon-forward { + background-position: -336px -72px; +} +.icon-fast-forward { + background-position: -360px -72px; +} +.icon-step-forward { + background-position: -384px -72px; +} +.icon-eject { + background-position: -408px -72px; +} +.icon-chevron-left { + background-position: -432px -72px; +} +.icon-chevron-right { + background-position: -456px -72px; +} +.icon-plus-sign { + background-position: 0 -96px; +} +.icon-minus-sign { + background-position: -24px -96px; +} +.icon-remove-sign { + background-position: -48px -96px; +} +.icon-ok-sign { + background-position: -72px -96px; +} +.icon-question-sign { + background-position: -96px -96px; +} +.icon-info-sign { + background-position: -120px -96px; +} +.icon-screenshot { + background-position: -144px -96px; +} +.icon-remove-circle { + background-position: -168px -96px; +} +.icon-ok-circle { + background-position: -192px -96px; +} +.icon-ban-circle { + background-position: -216px -96px; +} +.icon-arrow-left { + background-position: -240px -96px; +} +.icon-arrow-right { + background-position: -264px -96px; +} +.icon-arrow-up { + background-position: -289px -96px; +} +.icon-arrow-down { + background-position: -312px -96px; +} +.icon-share-alt { + background-position: -336px -96px; +} +.icon-resize-full { + background-position: -360px -96px; +} +.icon-resize-small { + background-position: -384px -96px; +} +.icon-plus { + background-position: -408px -96px; +} +.icon-minus { + background-position: -433px -96px; +} +.icon-asterisk { + background-position: -456px -96px; +} +.icon-exclamation-sign { + background-position: 0 -120px; +} +.icon-gift { + background-position: -24px -120px; +} +.icon-leaf { + background-position: -48px -120px; +} +.icon-fire { + background-position: -72px -120px; +} +.icon-eye-open { + background-position: -96px -120px; +} +.icon-eye-close { + background-position: -120px -120px; +} +.icon-warning-sign { + background-position: -144px -120px; +} +.icon-plane { + background-position: -168px -120px; +} +.icon-calendar { + background-position: -192px -120px; +} +.icon-random { + background-position: -216px -120px; +} +.icon-comment { + background-position: -240px -120px; +} +.icon-magnet { + background-position: -264px -120px; +} +.icon-chevron-up { + background-position: -288px -120px; +} +.icon-chevron-down { + background-position: -313px -119px; +} +.icon-retweet { + background-position: -336px -120px; +} +.icon-shopping-cart { + background-position: -360px -120px; +} +.icon-folder-close { + background-position: -384px -120px; +} +.icon-folder-open { + background-position: -408px -120px; +} +.icon-resize-vertical { + background-position: -432px -119px; +} +.icon-resize-horizontal { + background-position: -456px -118px; +} +.dropdown { + position: relative; +} +.dropdown-toggle { + *margin-bottom: -3px; +} +.dropdown-toggle:active, .open .dropdown-toggle { + outline: 0; +} +.caret { + display: inline-block; + width: 0; + height: 0; + text-indent: -99999px; + *text-indent: 0; + vertical-align: top; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 4px solid #000000; + opacity: 0.3; + filter: alpha(opacity=30); + content: "\2193"; +} +.dropdown .caret { + margin-top: 8px; + margin-left: 2px; +} +.dropdown:hover .caret, .open.dropdown .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + float: left; + display: none; + min-width: 160px; + _width: 160px; + padding: 4px 0; + margin: 0; + list-style: none; + background-color: #ffffff; + border-color: #ccc; + border-color: rgba(0, 0, 0, 0.2); + border-style: solid; + border-width: 1px; + -webkit-border-radius: 0 0 5px 5px; + -moz-border-radius: 0 0 5px 5px; + border-radius: 0 0 5px 5px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; + *border-right-width: 2px; + *border-bottom-width: 2px; +} +.dropdown-menu.bottom-up { + top: auto; + bottom: 100%; + margin-bottom: 2px; +} +.dropdown-menu .divider { + height: 1px; + margin: 5px 1px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #ffffff; + *width: 100%; + *margin: -5px 0 5px; +} +.dropdown-menu a { + display: block; + padding: 3px 15px; + clear: both; + font-weight: normal; + line-height: 18px; + color: #555555; + white-space: nowrap; +} +.dropdown-menu li > a:hover, .dropdown-menu .active > a, .dropdown-menu .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #0088cc; +} +.dropdown.open { + *z-index: 1000; +} +.dropdown.open .dropdown-toggle { + color: #ffffff; + background: #ccc; + background: rgba(0, 0, 0, 0.3); +} +.dropdown.open .dropdown-menu { + display: block; +} +.typeahead { + margin-top: 2px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #f5f5f5; + border: 1px solid #eee; + border: 1px solid rgba(0, 0, 0, 0.05); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 0, 0, 0.15); +} +.fade { + -webkit-transition: opacity 0.15s linear; + -moz-transition: opacity 0.15s linear; + -ms-transition: opacity 0.15s linear; + -o-transition: opacity 0.15s linear; + transition: opacity 0.15s linear; + opacity: 0; +} +.fade.in { + opacity: 1; +} +.collapse { + -webkit-transition: height 0.35s ease; + -moz-transition: height 0.35s ease; + -ms-transition: height 0.35s ease; + -o-transition: height 0.35s ease; + transition: height 0.35s ease; + position: relative; + overflow: hidden; + height: 0; +} +.collapse.in { + height: auto; +} +.close { + float: right; + font-size: 20px; + font-weight: bold; + line-height: 18px; + color: #000000; + text-shadow: 0 1px 0 #ffffff; + opacity: 0.2; + filter: alpha(opacity=20); +} +.close:hover { + color: #000000; + text-decoration: none; + opacity: 0.4; + filter: alpha(opacity=40); + cursor: pointer; +} +.btn { + display: inline-block; + padding: 4px 10px 4px; + margin-bottom: 0; + font-size: 13px; + line-height: 18px; + color: #333333; + text-align: center; + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); + vertical-align: middle; + background-color: #f5f5f5; + background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); + background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); + background-image: linear-gradient(top, #ffffff, #e6e6e6); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0); + border-color: #e6e6e6 #e6e6e6 #bfbfbf; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + border: 1px solid #ccc; + border-bottom-color: #bbb; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + cursor: pointer; + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + *margin-left: .3em; +} +.btn:hover, +.btn:active, +.btn.active, +.btn.disabled, +.btn[disabled] { + background-color: #e6e6e6; +} +.btn:active, .btn.active { + background-color: #cccccc \9; +} +.btn:first-child { + *margin-left: 0; +} +.btn:hover { + color: #333333; + text-decoration: none; + background-color: #e6e6e6; + background-position: 0 -15px; + -webkit-transition: background-position 0.1s linear; + -moz-transition: background-position 0.1s linear; + -ms-transition: background-position 0.1s linear; + -o-transition: background-position 0.1s linear; + transition: background-position 0.1s linear; +} +.btn:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.btn.active, .btn:active { + background-image: none; + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + background-color: #e6e6e6; + background-color: #d9d9d9 \9; + outline: 0; +} +.btn.disabled, .btn[disabled] { + cursor: default; + background-image: none; + background-color: #e6e6e6; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +.btn-large { + padding: 9px 14px; + font-size: 15px; + line-height: normal; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.btn-large [class^="icon-"] { + margin-top: 1px; +} +.btn-small { + padding: 5px 9px; + font-size: 11px; + line-height: 16px; +} +.btn-small [class^="icon-"] { + margin-top: -1px; +} +.btn-mini { + padding: 2px 6px; + font-size: 11px; + line-height: 14px; +} +.btn-primary, +.btn-primary:hover, +.btn-warning, +.btn-warning:hover, +.btn-danger, +.btn-danger:hover, +.btn-success, +.btn-success:hover, +.btn-info, +.btn-info:hover, +.btn-inverse, +.btn-inverse:hover { + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + color: #ffffff; +} +.btn-primary.active, +.btn-warning.active, +.btn-danger.active, +.btn-success.active, +.btn-info.active, +.btn-dark.active { + color: rgba(255, 255, 255, 0.75); +} +.btn-primary { + background-color: #006dcc; + background-image: -moz-linear-gradient(top, #0088cc, #0044cc); + background-image: -ms-linear-gradient(top, #0088cc, #0044cc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); + background-image: -o-linear-gradient(top, #0088cc, #0044cc); + background-image: linear-gradient(top, #0088cc, #0044cc); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); + border-color: #0044cc #0044cc #002a80; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-primary:hover, +.btn-primary:active, +.btn-primary.active, +.btn-primary.disabled, +.btn-primary[disabled] { + background-color: #0044cc; +} +.btn-primary:active, .btn-primary.active { + background-color: #003399 \9; +} +.btn-warning { + background-color: #faa732; + background-image: -moz-linear-gradient(top, #fbb450, #f89406); + background-image: -ms-linear-gradient(top, #fbb450, #f89406); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); + background-image: -webkit-linear-gradient(top, #fbb450, #f89406); + background-image: -o-linear-gradient(top, #fbb450, #f89406); + background-image: linear-gradient(top, #fbb450, #f89406); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0); + border-color: #f89406 #f89406 #ad6704; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-warning:hover, +.btn-warning:active, +.btn-warning.active, +.btn-warning.disabled, +.btn-warning[disabled] { + background-color: #f89406; +} +.btn-warning:active, .btn-warning.active { + background-color: #c67605 \9; +} +.btn-danger { + background-color: #da4f49; + background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -ms-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -o-linear-gradient(top, #ee5f5b, #bd362f); + background-image: linear-gradient(top, #ee5f5b, #bd362f); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0); + border-color: #bd362f #bd362f #802420; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-danger:hover, +.btn-danger:active, +.btn-danger.active, +.btn-danger.disabled, +.btn-danger[disabled] { + background-color: #bd362f; +} +.btn-danger:active, .btn-danger.active { + background-color: #942a25 \9; +} +.btn-success { + background-color: #5bb75b; + background-image: -moz-linear-gradient(top, #62c462, #51a351); + background-image: -ms-linear-gradient(top, #62c462, #51a351); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351)); + background-image: -webkit-linear-gradient(top, #62c462, #51a351); + background-image: -o-linear-gradient(top, #62c462, #51a351); + background-image: linear-gradient(top, #62c462, #51a351); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0); + border-color: #51a351 #51a351 #387038; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-success:hover, +.btn-success:active, +.btn-success.active, +.btn-success.disabled, +.btn-success[disabled] { + background-color: #51a351; +} +.btn-success:active, .btn-success.active { + background-color: #408140 \9; +} +.btn-info { + background-color: #49afcd; + background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -ms-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4)); + background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -o-linear-gradient(top, #5bc0de, #2f96b4); + background-image: linear-gradient(top, #5bc0de, #2f96b4); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0); + border-color: #2f96b4 #2f96b4 #1f6377; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-info:hover, +.btn-info:active, +.btn-info.active, +.btn-info.disabled, +.btn-info[disabled] { + background-color: #2f96b4; +} +.btn-info:active, .btn-info.active { + background-color: #24748c \9; +} +.btn-inverse { + background-color: #393939; + background-image: -moz-linear-gradient(top, #454545, #262626); + background-image: -ms-linear-gradient(top, #454545, #262626); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#454545), to(#262626)); + background-image: -webkit-linear-gradient(top, #454545, #262626); + background-image: -o-linear-gradient(top, #454545, #262626); + background-image: linear-gradient(top, #454545, #262626); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#454545', endColorstr='#262626', GradientType=0); + border-color: #262626 #262626 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-inverse:hover, +.btn-inverse:active, +.btn-inverse.active, +.btn-inverse.disabled, +.btn-inverse[disabled] { + background-color: #262626; +} +.btn-inverse:active, .btn-inverse.active { + background-color: #0c0c0c \9; +} +button.btn, input[type="submit"].btn { + *padding-top: 2px; + *padding-bottom: 2px; +} +button.btn::-moz-focus-inner, input[type="submit"].btn::-moz-focus-inner { + padding: 0; + border: 0; +} +button.btn.large, input[type="submit"].btn.large { + *padding-top: 7px; + *padding-bottom: 7px; +} +button.btn.small, input[type="submit"].btn.small { + *padding-top: 3px; + *padding-bottom: 3px; +} +.btn-group { + position: relative; + *zoom: 1; + *margin-left: .3em; +} +.btn-group:before, .btn-group:after { + display: table; + content: ""; +} +.btn-group:after { + clear: both; +} +.btn-group:first-child { + *margin-left: 0; +} +.btn-group + .btn-group { + margin-left: 5px; +} +.btn-toolbar { + margin-top: 9px; + margin-bottom: 9px; +} +.btn-toolbar .btn-group { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; +} +.btn-group .btn { + position: relative; + float: left; + margin-left: -1px; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.btn-group .btn:first-child { + margin-left: 0; + -webkit-border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; + border-top-left-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + border-bottom-left-radius: 4px; +} +.btn-group .btn:last-child, .btn-group .dropdown-toggle { + -webkit-border-top-right-radius: 4px; + -moz-border-radius-topright: 4px; + border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -moz-border-radius-bottomright: 4px; + border-bottom-right-radius: 4px; +} +.btn-group .btn.large:first-child { + margin-left: 0; + -webkit-border-top-left-radius: 6px; + -moz-border-radius-topleft: 6px; + border-top-left-radius: 6px; + -webkit-border-bottom-left-radius: 6px; + -moz-border-radius-bottomleft: 6px; + border-bottom-left-radius: 6px; +} +.btn-group .btn.large:last-child, .btn-group .large.dropdown-toggle { + -webkit-border-top-right-radius: 6px; + -moz-border-radius-topright: 6px; + border-top-right-radius: 6px; + -webkit-border-bottom-right-radius: 6px; + -moz-border-radius-bottomright: 6px; + border-bottom-right-radius: 6px; +} +.btn-group .btn:hover, +.btn-group .btn:focus, +.btn-group .btn:active, +.btn-group .btn.active { + z-index: 2; +} +.btn-group .dropdown-toggle:active, .btn-group.open .dropdown-toggle { + outline: 0; +} +.btn-group .dropdown-toggle { + padding-left: 8px; + padding-right: 8px; + -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + *padding-top: 5px; + *padding-bottom: 5px; +} +.btn-group.open { + *z-index: 1000; +} +.btn-group.open .dropdown-menu { + display: block; + margin-top: 1px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.btn-group.open .dropdown-toggle { + background-image: none; + -webkit-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); +} +.btn .caret { + margin-top: 7px; + margin-left: 0; +} +.btn:hover .caret, .open.btn-group .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.btn-primary .caret, +.btn-danger .caret, +.btn-info .caret, +.btn-success .caret, +.btn-inverse .caret { + border-top-color: #ffffff; + opacity: 0.75; + filter: alpha(opacity=75); +} +.btn-small .caret { + margin-top: 4px; +} +.alert { + padding: 8px 35px 8px 14px; + margin-bottom: 18px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + background-color: #fcf8e3; + border: 1px solid #fbeed5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.alert, .alert-heading { + color: #c09853; +} +.alert .close { + position: relative; + top: -2px; + right: -21px; + line-height: 18px; +} +.alert-success { + background-color: #dff0d8; + border-color: #d6e9c6; +} +.alert-success, .alert-success .alert-heading { + color: #468847; +} +.alert-danger, .alert-error { + background-color: #f2dede; + border-color: #eed3d7; +} +.alert-danger, +.alert-error, +.alert-danger .alert-heading, +.alert-error .alert-heading { + color: #b94a48; +} +.alert-info { + background-color: #d9edf7; + border-color: #bce8f1; +} +.alert-info, .alert-info .alert-heading { + color: #3a87ad; +} +.alert-block { + padding-top: 14px; + padding-bottom: 14px; +} +.alert-block > p, .alert-block > ul { + margin-bottom: 0; +} +.alert-block p + p { + margin-top: 5px; +} +.nav { + margin-left: 0; + margin-bottom: 18px; + list-style: none; +} +.nav > li > a { + display: block; +} +.nav > li > a:hover { + text-decoration: none; + background-color: #eeeeee; +} +.nav .nav-header { + display: block; + padding: 3px 15px; + font-size: 11px; + font-weight: bold; + line-height: 18px; + color: #999999; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + text-transform: uppercase; +} +.nav li + .nav-header { + margin-top: 9px; +} +.nav-list { + padding-left: 14px; + padding-right: 14px; + margin-bottom: 0; +} +.nav-list > li > a, .nav-list .nav-header { + margin-left: -15px; + margin-right: -15px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); +} +.nav-list > li > a { + padding: 3px 15px; +} +.nav-list .active > a, .nav-list .active > a:hover { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); + background-color: #0088cc; +} +.nav-list [class^="icon-"] { + margin-right: 2px; +} +.nav-tabs, .nav-pills { + *zoom: 1; +} +.nav-tabs:before, +.nav-pills:before, +.nav-tabs:after, +.nav-pills:after { + display: table; + content: ""; +} +.nav-tabs:after, .nav-pills:after { + clear: both; +} +.nav-tabs > li, .nav-pills > li { + float: left; +} +.nav-tabs > li > a, .nav-pills > li > a { + padding-right: 12px; + padding-left: 12px; + margin-right: 2px; + line-height: 14px; +} +.nav-tabs { + border-bottom: 1px solid #ddd; +} +.nav-tabs > li { + margin-bottom: -1px; +} +.nav-tabs > li > a { + padding-top: 9px; + padding-bottom: 9px; + border: 1px solid transparent; + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} +.nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #dddddd; +} +.nav-tabs > .active > a, .nav-tabs > .active > a:hover { + color: #555555; + background-color: #ffffff; + border: 1px solid #ddd; + border-bottom-color: transparent; + cursor: default; +} +.nav-pills > li > a { + padding-top: 8px; + padding-bottom: 8px; + margin-top: 2px; + margin-bottom: 2px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.nav-pills .active > a, .nav-pills .active > a:hover { + color: #ffffff; + background-color: #0088cc; +} +.nav-stacked > li { + float: none; +} +.nav-stacked > li > a { + margin-right: 0; +} +.nav-tabs.nav-stacked { + border-bottom: 0; +} +.nav-tabs.nav-stacked > li > a { + border: 1px solid #ddd; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.nav-tabs.nav-stacked > li:first-child > a { + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} +.nav-tabs.nav-stacked > li:last-child > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} +.nav-tabs.nav-stacked > li > a:hover { + border-color: #ddd; + z-index: 2; +} +.nav-pills.nav-stacked > li > a { + margin-bottom: 3px; +} +.nav-pills.nav-stacked > li:last-child > a { + margin-bottom: 1px; +} +.nav-tabs .dropdown-menu, .nav-pills .dropdown-menu { + margin-top: 1px; + border-width: 1px; +} +.nav-pills .dropdown-menu { + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.nav-tabs .dropdown-toggle .caret, .nav-pills .dropdown-toggle .caret { + border-top-color: #0088cc; + margin-top: 6px; +} +.nav-tabs .dropdown-toggle:hover .caret, .nav-pills .dropdown-toggle:hover .caret { + border-top-color: #005580; +} +.nav-tabs .active .dropdown-toggle .caret, .nav-pills .active .dropdown-toggle .caret { + border-top-color: #333333; +} +.nav > .dropdown.active > a:hover { + color: #000000; + cursor: pointer; +} +.nav-tabs .open .dropdown-toggle, .nav-pills .open .dropdown-toggle, .nav > .open.active > a:hover { + color: #ffffff; + background-color: #999999; + border-color: #999999; +} +.nav .open .caret, .nav .open.active .caret, .nav .open a:hover .caret { + border-top-color: #ffffff; + opacity: 1; + filter: alpha(opacity=100); +} +.tabs-stacked .open > a:hover { + border-color: #999999; +} +.tabbable { + *zoom: 1; +} +.tabbable:before, .tabbable:after { + display: table; + content: ""; +} +.tabbable:after { + clear: both; +} +.tab-content { + overflow: hidden; +} +.tabs-below .nav-tabs, .tabs-right .nav-tabs, .tabs-left .nav-tabs { + border-bottom: 0; +} +.tab-content > .tab-pane, .pill-content > .pill-pane { + display: none; +} +.tab-content > .active, .pill-content > .active { + display: block; +} +.tabs-below .nav-tabs { + border-top: 1px solid #ddd; +} +.tabs-below .nav-tabs > li { + margin-top: -1px; + margin-bottom: 0; +} +.tabs-below .nav-tabs > li > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} +.tabs-below .nav-tabs > li > a:hover { + border-bottom-color: transparent; + border-top-color: #ddd; +} +.tabs-below .nav-tabs .active > a, .tabs-below .nav-tabs .active > a:hover { + border-color: transparent #ddd #ddd #ddd; +} +.tabs-left .nav-tabs > li, .tabs-right .nav-tabs > li { + float: none; +} +.tabs-left .nav-tabs > li > a, .tabs-right .nav-tabs > li > a { + min-width: 74px; + margin-right: 0; + margin-bottom: 3px; +} +.tabs-left .nav-tabs { + float: left; + margin-right: 19px; + border-right: 1px solid #ddd; +} +.tabs-left .nav-tabs > li > a { + margin-right: -1px; + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} +.tabs-left .nav-tabs > li > a:hover { + border-color: #eeeeee #dddddd #eeeeee #eeeeee; +} +.tabs-left .nav-tabs .active > a, .tabs-left .nav-tabs .active > a:hover { + border-color: #ddd transparent #ddd #ddd; + *border-right-color: #ffffff; +} +.tabs-right .nav-tabs { + float: right; + margin-left: 19px; + border-left: 1px solid #ddd; +} +.tabs-right .nav-tabs > li > a { + margin-left: -1px; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} +.tabs-right .nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #eeeeee #dddddd; +} +.tabs-right .nav-tabs .active > a, .tabs-right .nav-tabs .active > a:hover { + border-color: #ddd #ddd #ddd transparent; + *border-left-color: #ffffff; +} +.navbar { + overflow: visible; + margin-bottom: 18px; +} +.navbar-inner { + padding-left: 20px; + padding-right: 20px; + background-color: #2c2c2c; + background-image: -moz-linear-gradient(top, #333333, #222222); + background-image: -ms-linear-gradient(top, #333333, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); + background-image: -webkit-linear-gradient(top, #333333, #222222); + background-image: -o-linear-gradient(top, #333333, #222222); + background-image: linear-gradient(top, #333333, #222222); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); +} +.btn-navbar { + display: none; + float: right; + padding: 7px 10px; + margin-left: 5px; + margin-right: 5px; + background-color: #2c2c2c; + background-image: -moz-linear-gradient(top, #333333, #222222); + background-image: -ms-linear-gradient(top, #333333, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); + background-image: -webkit-linear-gradient(top, #333333, #222222); + background-image: -o-linear-gradient(top, #333333, #222222); + background-image: linear-gradient(top, #333333, #222222); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); + border-color: #222222 #222222 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); +} +.btn-navbar:hover, +.btn-navbar:active, +.btn-navbar.active, +.btn-navbar.disabled, +.btn-navbar[disabled] { + background-color: #222222; +} +.btn-navbar:active, .btn-navbar.active { + background-color: #080808 \9; +} +.btn-navbar .icon-bar { + display: block; + width: 18px; + height: 2px; + background-color: #f5f5f5; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; + -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); +} +.btn-navbar .icon-bar + .icon-bar { + margin-top: 3px; +} +.nav-collapse.collapse { + height: auto; +} +.navbar .brand:hover { + text-decoration: none; +} +.navbar .brand { + float: left; + display: block; + padding: 8px 20px 12px; + margin-left: -20px; + font-size: 20px; + font-weight: 200; + line-height: 1; + color: #ffffff; +} +.navbar .navbar-text { + margin-bottom: 0; + line-height: 40px; + color: #999999; +} +.navbar .navbar-text a:hover { + color: #ffffff; + background-color: transparent; +} +.navbar .btn, .navbar .btn-group { + margin-top: 5px; +} +.navbar .btn-group .btn { + margin-top: 0; +} +.navbar-form { + margin-bottom: 0; + *zoom: 1; +} +.navbar-form:before, .navbar-form:after { + display: table; + content: ""; +} +.navbar-form:after { + clear: both; +} +.navbar-form input, .navbar-form select { + display: inline-block; + margin-top: 5px; + margin-bottom: 0; +} +.navbar-form .radio, .navbar-form .checkbox { + margin-top: 5px; +} +.navbar-form input[type="image"], .navbar-form input[type="checkbox"], .navbar-form input[type="radio"] { + margin-top: 3px; +} +.navbar-form .input-append, .navbar-form .input-prepend { + margin-top: 6px; + white-space: nowrap; +} +.navbar-form .input-append input, .navbar-form .input-prepend input { + margin-top: 0; +} +.navbar-search { + position: relative; + float: left; + margin-top: 6px; + margin-bottom: 0; +} +.navbar-search .search-query { + padding: 4px 9px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + font-weight: normal; + line-height: 1; + color: #ffffff; + color: rgba(255, 255, 255, 0.75); + background: #666; + background: rgba(255, 255, 255, 0.3); + border: 1px solid #111; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + -webkit-transition: none; + -moz-transition: none; + -ms-transition: none; + -o-transition: none; + transition: none; +} +.navbar-search .search-query :-moz-placeholder { + color: #eeeeee; +} +.navbar-search .search-query::-webkit-input-placeholder { + color: #eeeeee; +} +.navbar-search .search-query:hover { + color: #ffffff; + background-color: #999999; + background-color: rgba(255, 255, 255, 0.5); +} +.navbar-search .search-query:focus, .navbar-search .search-query.focused { + padding: 5px 10px; + color: #333333; + text-shadow: 0 1px 0 #ffffff; + background-color: #ffffff; + border: 0; + -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + outline: 0; +} +.navbar-fixed-top { + position: fixed; + top: 0; + right: 0; + left: 0; + z-index: 1030; +} +.navbar-fixed-top .navbar-inner { + padding-left: 0; + padding-right: 0; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.navbar .nav { + position: relative; + left: 0; + display: block; + float: left; + margin: 0 10px 0 0; +} +.navbar .nav.pull-right { + float: right; +} +.navbar .nav > li { + display: block; + float: left; +} +.navbar .nav > li > a { + float: none; + padding: 10px 10px 11px; + line-height: 19px; + color: #999999; + text-decoration: none; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.navbar .nav > li > a:hover { + background-color: transparent; + color: #ffffff; + text-decoration: none; +} +.navbar .nav .active > a, .navbar .nav .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #222222; +} +.navbar .divider-vertical { + height: 40px; + width: 1px; + margin: 0 9px; + overflow: hidden; + background-color: #222222; + border-right: 1px solid #333333; +} +.navbar .nav.pull-right { + margin-left: 10px; + margin-right: 0; +} +.navbar .dropdown-menu { + margin-top: 1px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.navbar .dropdown-menu:before { + content: ''; + display: inline-block; + border-left: 7px solid transparent; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-bottom-color: rgba(0, 0, 0, 0.2); + position: absolute; + top: -7px; + left: 9px; +} +.navbar .dropdown-menu:after { + content: ''; + display: inline-block; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid #ffffff; + position: absolute; + top: -6px; + left: 10px; +} +.navbar .nav .dropdown-toggle .caret, .navbar .nav .open.dropdown .caret { + border-top-color: #ffffff; +} +.navbar .nav .active .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.navbar .nav .open > .dropdown-toggle, .navbar .nav .active > .dropdown-toggle, .navbar .nav .open.active > .dropdown-toggle { + background-color: transparent; +} +.navbar .nav .active > .dropdown-toggle:hover { + color: #ffffff; +} +.navbar .nav.pull-right .dropdown-menu { + left: auto; + right: 0; +} +.navbar .nav.pull-right .dropdown-menu:before { + left: auto; + right: 12px; +} +.navbar .nav.pull-right .dropdown-menu:after { + left: auto; + right: 13px; +} +.breadcrumb { + padding: 7px 14px; + margin: 0 0 18px; + background-color: #fbfbfb; + background-image: -moz-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -ms-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5)); + background-image: -webkit-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -o-linear-gradient(top, #ffffff, #f5f5f5); + background-image: linear-gradient(top, #ffffff, #f5f5f5); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0); + border: 1px solid #ddd; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; +} +.breadcrumb li { + display: inline-block; + text-shadow: 0 1px 0 #ffffff; +} +.breadcrumb .divider { + padding: 0 5px; + color: #999999; +} +.breadcrumb .active a { + color: #333333; +} +.pagination { + height: 36px; + margin: 18px 0; +} +.pagination ul { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; + margin-left: 0; + margin-bottom: 0; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); +} +.pagination li { + display: inline; +} +.pagination a { + float: left; + padding: 0 14px; + line-height: 34px; + text-decoration: none; + border: 1px solid #ddd; + border-left-width: 0; +} +.pagination a:hover, .pagination .active a { + background-color: #f5f5f5; +} +.pagination .active a { + color: #999999; + cursor: default; +} +.pagination .disabled a, .pagination .disabled a:hover { + color: #999999; + background-color: transparent; + cursor: default; +} +.pagination li:first-child a { + border-left-width: 1px; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.pagination li:last-child a { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.pagination-centered { + text-align: center; +} +.pagination-right { + text-align: right; +} +.pager { + margin-left: 0; + margin-bottom: 18px; + list-style: none; + text-align: center; + *zoom: 1; +} +.pager:before, .pager:after { + display: table; + content: ""; +} +.pager:after { + clear: both; +} +.pager li { + display: inline; +} +.pager a { + display: inline-block; + padding: 5px 14px; + background-color: #fff; + border: 1px solid #ddd; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} +.pager a:hover { + text-decoration: none; + background-color: #f5f5f5; +} +.pager .next a { + float: right; +} +.pager .previous a { + float: left; +} +.modal-open .dropdown-menu { + z-index: 2050; +} +.modal-open .dropdown.open { + *z-index: 2050; +} +.modal-open .popover { + z-index: 2060; +} +.modal-open .tooltip { + z-index: 2070; +} +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + background-color: #000000; +} +.modal-backdrop.fade { + opacity: 0; +} +.modal-backdrop, .modal-backdrop.fade.in { + opacity: 0.8; + filter: alpha(opacity=80); +} +.modal { + position: fixed; + top: 50%; + left: 50%; + z-index: 1050; + max-height: 500px; + overflow: auto; + width: 560px; + margin: -250px 0 0 -280px; + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + /* IE6-7 */ + + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.wide-modal { + position: fixed; + top: 5%; + left: 5%; + z-index: 1050; + max-height: 90%; + overflow: auto; + width: 90%; + /*margin: -50px 0 0 -80px;*/ + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + /* IE6-7 */ + + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.modal.fade { + -webkit-transition: opacity .3s linear, top .3s ease-out; + -moz-transition: opacity .3s linear, top .3s ease-out; + -ms-transition: opacity .3s linear, top .3s ease-out; + -o-transition: opacity .3s linear, top .3s ease-out; + transition: opacity .3s linear, top .3s ease-out; + top: -25%; +} +.modal.fade.in { + top: 50%; +} +.modal-header { + padding: 9px 15px; + border-bottom: 1px solid #eee; +} +.modal-header .close { + margin-top: 2px; +} +.modal-body { + padding: 15px; +} +.modal-body .modal-form { + margin-bottom: 0; +} +.modal-footer { + padding: 14px 15px 15px; + margin-bottom: 0; + background-color: #f5f5f5; + border-top: 1px solid #ddd; + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; + *zoom: 1; +} +.modal-footer:before, .modal-footer:after { + display: table; + content: ""; +} +.modal-footer:after { + clear: both; +} +.modal-footer .btn { + float: right; + margin-left: 5px; + margin-bottom: 0; +} +.tooltip { + position: absolute; + z-index: 1020; + display: block; + visibility: visible; + padding: 5px; + font-size: 11px; + opacity: 0; + filter: alpha(opacity=0); +} +.tooltip.in { + opacity: 0.8; + filter: alpha(opacity=80); +} +.tooltip.top { + margin-top: -2px; +} +.tooltip.right { + margin-left: 2px; +} +.tooltip.bottom { + margin-top: 2px; +} +.tooltip.left { + margin-left: -2px; +} +.tooltip.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid #000000; +} +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #000000; +} +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-bottom: 5px solid #000000; +} +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-right: 5px solid #000000; +} +.tooltip-inner { + max-width: 200px; + padding: 3px 8px; + color: #ffffff; + text-align: center; + text-decoration: none; + background-color: #000000; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; +} +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1010; + display: none; + padding: 5px; +} +.popover.top { + margin-top: -5px; +} +.popover.right { + margin-left: 5px; +} +.popover.bottom { + margin-top: 5px; +} +.popover.left { + margin-left: -5px; +} +.popover.top .arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid #000000; +} +.popover.right .arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-right: 5px solid #000000; +} +.popover.bottom .arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-bottom: 5px solid #000000; +} +.popover.left .arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #000000; +} +.popover .arrow { + position: absolute; + width: 0; + height: 0; +} +.popover-inner { + padding: 3px; + width: 280px; + overflow: hidden; + background: #000000; + background: rgba(0, 0, 0, 0.8); + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); +} +.popover-title { + padding: 9px 15px; + line-height: 1; + background-color: #f5f5f5; + border-bottom: 1px solid #eee; + -webkit-border-radius: 3px 3px 0 0; + -moz-border-radius: 3px 3px 0 0; + border-radius: 3px 3px 0 0; +} +.popover-content { + padding: 14px; + background-color: #ffffff; + -webkit-border-radius: 0 0 3px 3px; + -moz-border-radius: 0 0 3px 3px; + border-radius: 0 0 3px 3px; + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.popover-content p, .popover-content ul, .popover-content ol { + margin-bottom: 0; +} +.thumbnails { + margin-left: -20px; + list-style: none; + *zoom: 1; +} +.thumbnails:before, .thumbnails:after { + display: table; + content: ""; +} +.thumbnails:after { + clear: both; +} +.thumbnails > li { + float: left; + margin: 0 0 18px 20px; +} +.thumbnail { + display: block; + padding: 4px; + line-height: 1; + border: 1px solid #ddd; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); +} +a.thumbnail:hover { + border-color: #0088cc; + -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); +} +.thumbnail > img { + display: block; + max-width: 100%; + margin-left: auto; + margin-right: auto; +} +.thumbnail .caption { + padding: 9px; +} +.label { + padding: 2px 4px 3px; + font-size: 11.049999999999999px; + font-weight: bold; + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #999999; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.label:hover { + color: #ffffff; + text-decoration: none; +} +.label-important { + background-color: #b94a48; +} +.label-important:hover { + background-color: #953b39; +} +.label-warning { + background-color: #f89406; +} +.label-warning:hover { + background-color: #c67605; +} +.label-success { + background-color: #468847; +} +.label-success:hover { + background-color: #356635; +} +.label-info { + background-color: #3a87ad; +} +.label-info:hover { + background-color: #2d6987; +} +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +@-moz-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +@keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +.progress { + overflow: hidden; + height: 18px; + margin-bottom: 18px; + background-color: #f7f7f7; + background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -ms-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9)); + background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: linear-gradient(top, #f5f5f5, #f9f9f9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0); + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.progress .bar { + width: 0%; + height: 18px; + color: #ffffff; + font-size: 12px; + text-align: center; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #0e90d2; + background-image: -moz-linear-gradient(top, #149bdf, #0480be); + background-image: -ms-linear-gradient(top, #149bdf, #0480be); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be)); + background-image: -webkit-linear-gradient(top, #149bdf, #0480be); + background-image: -o-linear-gradient(top, #149bdf, #0480be); + background-image: linear-gradient(top, #149bdf, #0480be); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0); + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition: width 0.6s ease; + -moz-transition: width 0.6s ease; + -ms-transition: width 0.6s ease; + -o-transition: width 0.6s ease; + transition: width 0.6s ease; +} +.progress-striped .bar { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + -webkit-background-size: 40px 40px; + -moz-background-size: 40px 40px; + -o-background-size: 40px 40px; + background-size: 40px 40px; +} +.progress.active .bar { + -webkit-animation: progress-bar-stripes 2s linear infinite; + -moz-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} +.progress-danger .bar { + background-color: #dd514c; + background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -o-linear-gradient(top, #ee5f5b, #c43c35); + background-image: linear-gradient(top, #ee5f5b, #c43c35); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0); +} +.progress-danger.progress-striped .bar { + background-color: #ee5f5b; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-success .bar { + background-color: #5eb95e; + background-image: -moz-linear-gradient(top, #62c462, #57a957); + background-image: -ms-linear-gradient(top, #62c462, #57a957); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957)); + background-image: -webkit-linear-gradient(top, #62c462, #57a957); + background-image: -o-linear-gradient(top, #62c462, #57a957); + background-image: linear-gradient(top, #62c462, #57a957); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0); +} +.progress-success.progress-striped .bar { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-info .bar { + background-color: #4bb1cf; + background-image: -moz-linear-gradient(top, #5bc0de, #339bb9); + background-image: -ms-linear-gradient(top, #5bc0de, #339bb9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9)); + background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9); + background-image: -o-linear-gradient(top, #5bc0de, #339bb9); + background-image: linear-gradient(top, #5bc0de, #339bb9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0); +} +.progress-info.progress-striped .bar { + background-color: #5bc0de; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.accordion { + margin-bottom: 18px; +} +.accordion-group { + margin-bottom: 2px; + border: 1px solid #e5e5e5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.accordion-heading { + border-bottom: 0; +} +.accordion-heading .accordion-toggle { + display: block; + padding: 8px 15px; +} +.accordion-inner { + padding: 9px 15px; + border-top: 1px solid #e5e5e5; +} +.carousel { + position: relative; + margin-bottom: 18px; + line-height: 1; +} +.carousel-inner { + overflow: hidden; + width: 100%; + position: relative; +} +.carousel .item { + display: none; + position: relative; + -webkit-transition: 0.6s ease-in-out left; + -moz-transition: 0.6s ease-in-out left; + -ms-transition: 0.6s ease-in-out left; + -o-transition: 0.6s ease-in-out left; + transition: 0.6s ease-in-out left; +} +.carousel .item > img { + display: block; + line-height: 1; +} +.carousel .active, .carousel .next, .carousel .prev { + display: block; +} +.carousel .active { + left: 0; +} +.carousel .next, .carousel .prev { + position: absolute; + top: 0; + width: 100%; +} +.carousel .next { + left: 100%; +} +.carousel .prev { + left: -100%; +} +.carousel .next.left, .carousel .prev.right { + left: 0; +} +.carousel .active.left { + left: -100%; +} +.carousel .active.right { + left: 100%; +} +.carousel-control { + position: absolute; + top: 40%; + left: 15px; + width: 40px; + height: 40px; + margin-top: -20px; + font-size: 60px; + font-weight: 100; + line-height: 30px; + color: #ffffff; + text-align: center; + background: #222222; + border: 3px solid #ffffff; + -webkit-border-radius: 23px; + -moz-border-radius: 23px; + border-radius: 23px; + opacity: 0.5; + filter: alpha(opacity=50); +} +.carousel-control.right { + left: auto; + right: 15px; +} +.carousel-control:hover { + color: #ffffff; + text-decoration: none; + opacity: 0.9; + filter: alpha(opacity=90); +} +.carousel-caption { + position: absolute; + left: 0; + right: 0; + bottom: 0; + padding: 10px 15px 5px; + background: #333333; + background: rgba(0, 0, 0, 0.75); +} +.carousel-caption h4, .carousel-caption p { + color: #ffffff; +} +.hero-unit { + padding: 60px; + margin-bottom: 30px; + background-color: #f5f5f5; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} +.hero-unit h1 { + margin-bottom: 0; + font-size: 60px; + line-height: 1; + letter-spacing: -1px; +} +.hero-unit p { + font-size: 18px; + font-weight: 200; + line-height: 27px; +} +.pull-right { + float: right; +} +.pull-left { + float: left; +} +.hide { + display: none; +} +.show { + display: block; +} +.invisible { + visibility: hidden; +} diff --git a/src/nl/astraeus/jdbc/web/resources/images/loading.gif b/src/nl/astraeus/jdbc/web/resources/images/loading.gif new file mode 100644 index 0000000..21c7e74 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/images/loading.gif Binary files differ diff --git a/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png b/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png new file mode 100644 index 0000000..92d4445 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png Binary files differ diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-alert.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-alert.js new file mode 100644 index 0000000..2242ddd --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-alert.js @@ -0,0 +1,94 @@ +/* ========================================================== + * bootstrap-alert.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#alerts + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function( $ ){ + + "use strict" + + /* ALERT CLASS DEFINITION + * ====================== */ + + var dismiss = '[data-dismiss="alert"]' + , Alert = function ( el ) { + $(el).on('click', dismiss, this.close) + } + + Alert.prototype = { + + constructor: Alert + + , close: function ( e ) { + var $this = $(this) + , selector = $this.attr('data-target') + , $parent + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = $(selector) + $parent.trigger('close') + + e && e.preventDefault() + + $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent()) + + $parent + .trigger('close') + .removeClass('in') + + function removeElement() { + $parent + .trigger('closed') + .remove() + } + + $.support.transition && $parent.hasClass('fade') ? + $parent.on($.support.transition.end, removeElement) : + removeElement() + } + + } + + + /* ALERT PLUGIN DEFINITION + * ======================= */ + + $.fn.alert = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('alert') + if (!data) $this.data('alert', (data = new Alert(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.alert.Constructor = Alert + + + /* ALERT DATA-API + * ============== */ + + $(function () { + $('body').on('click.alert.data-api', dismiss, Alert.prototype.close) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-button.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-button.js new file mode 100644 index 0000000..0238ca3 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-button.js @@ -0,0 +1,100 @@ +/* ============================================================ + * bootstrap-button.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#buttons + * ============================================================ + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + +!function( $ ){ + + "use strict" + + /* BUTTON PUBLIC CLASS DEFINITION + * ============================== */ + + var Button = function ( element, options ) { + this.$element = $(element) + this.options = $.extend({}, $.fn.button.defaults, options) + } + + Button.prototype = { + + constructor: Button + + , setState: function ( state ) { + var d = 'disabled' + , $el = this.$element + , data = $el.data() + , val = $el.is('input') ? 'val' : 'html' + + state = state + 'Text' + data.resetText || $el.data('resetText', $el[val]()) + + $el[val](data[state] || this.options[state]) + + // push to event loop to allow forms to submit + setTimeout(function () { + state == 'loadingText' ? + $el.addClass(d).attr(d, d) : + $el.removeClass(d).removeAttr(d) + }, 0) + } + + , toggle: function () { + var $parent = this.$element.parent('[data-toggle="buttons-radio"]') + + $parent && $parent + .find('.active') + .removeClass('active') + + this.$element.toggleClass('active') + } + + } + + + /* BUTTON PLUGIN DEFINITION + * ======================== */ + + $.fn.button = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('button') + , options = typeof option == 'object' && option + if (!data) $this.data('button', (data = new Button(this, options))) + if (option == 'toggle') data.toggle() + else if (option) data.setState(option) + }) + } + + $.fn.button.defaults = { + loadingText: 'loading...' + } + + $.fn.button.Constructor = Button + + + /* BUTTON DATA-API + * =============== */ + + $(function () { + $('body').on('click.button.data-api', '[data-toggle^=button]', function ( e ) { + var $btn = $(e.target) + if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') + $btn.button('toggle') + }) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-carousel.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-carousel.js new file mode 100644 index 0000000..810256e --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-carousel.js @@ -0,0 +1,157 @@ +/* ========================================================== + * bootstrap-carousel.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#carousel + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function( $ ){ + + "use strict" + + /* CAROUSEL CLASS DEFINITION + * ========================= */ + + var Carousel = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, $.fn.carousel.defaults, options) + this.options.slide && this.slide(this.options.slide) + } + + Carousel.prototype = { + + cycle: function () { + this.interval = setInterval($.proxy(this.next, this), this.options.interval) + return this + } + + , to: function (pos) { + var $active = this.$element.find('.active') + , children = $active.parent().children() + , activePos = children.index($active) + , that = this + + if (pos > (children.length - 1) || pos < 0) return + + if (this.sliding) { + return this.$element.one('slid', function () { + that.to(pos) + }) + } + + if (activePos == pos) { + return this.pause().cycle() + } + + return this.slide(pos > activePos ? 'next' : 'prev', $(children[pos])) + } + + , pause: function () { + clearInterval(this.interval) + this.interval = null + return this + } + + , next: function () { + if (this.sliding) return + return this.slide('next') + } + + , prev: function () { + if (this.sliding) return + return this.slide('prev') + } + + , slide: function (type, next) { + var $active = this.$element.find('.active') + , $next = next || $active[type]() + , isCycling = this.interval + , direction = type == 'next' ? 'left' : 'right' + , fallback = type == 'next' ? 'first' : 'last' + , that = this + + if (!$next.length) return + + this.sliding = true + + isCycling && this.pause() + + $next = $next.length ? $next : this.$element.find('.item')[fallback]() + + if (!$.support.transition && this.$element.hasClass('slide')) { + this.$element.trigger('slide') + $active.removeClass('active') + $next.addClass('active') + this.sliding = false + this.$element.trigger('slid') + } else { + $next.addClass(type) + $next[0].offsetWidth // force reflow + $active.addClass(direction) + $next.addClass(direction) + this.$element.trigger('slide') + this.$element.one($.support.transition.end, function () { + $next.removeClass([type, direction].join(' ')).addClass('active') + $active.removeClass(['active', direction].join(' ')) + that.sliding = false + setTimeout(function () { that.$element.trigger('slid') }, 0) + }) + } + + isCycling && this.cycle() + + return this + } + + } + + + /* CAROUSEL PLUGIN DEFINITION + * ========================== */ + + $.fn.carousel = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('carousel') + , options = typeof option == 'object' && option + if (!data) $this.data('carousel', (data = new Carousel(this, options))) + if (typeof option == 'number') data.to(option) + else if (typeof option == 'string' || (option = options.slide)) data[option]() + else data.cycle() + }) + } + + $.fn.carousel.defaults = { + interval: 5000 + } + + $.fn.carousel.Constructor = Carousel + + + /* CAROUSEL DATA-API + * ================= */ + + $(function () { + $('body').on('click.carousel.data-api', '[data-slide]', function ( e ) { + var $this = $(this), href + , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 + , options = !$target.data('modal') && $.extend({}, $target.data(), $this.data()) + $target.carousel(options) + e.preventDefault() + }) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-collapse.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-collapse.js new file mode 100644 index 0000000..d195efc --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-collapse.js @@ -0,0 +1,136 @@ +/* ============================================================= + * bootstrap-collapse.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#collapse + * ============================================================= + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + +!function( $ ){ + + "use strict" + + var Collapse = function ( element, options ) { + this.$element = $(element) + this.options = $.extend({}, $.fn.collapse.defaults, options) + + if (this.options["parent"]) { + this.$parent = $(this.options["parent"]) + } + + this.options.toggle && this.toggle() + } + + Collapse.prototype = { + + constructor: Collapse + + , dimension: function () { + var hasWidth = this.$element.hasClass('width') + return hasWidth ? 'width' : 'height' + } + + , show: function () { + var dimension = this.dimension() + , scroll = $.camelCase(['scroll', dimension].join('-')) + , actives = this.$parent && this.$parent.find('.in') + , hasData + + if (actives && actives.length) { + hasData = actives.data('collapse') + actives.collapse('hide') + hasData || actives.data('collapse', null) + } + + this.$element[dimension](0) + this.transition('addClass', 'show', 'shown') + this.$element[dimension](this.$element[0][scroll]) + + } + + , hide: function () { + var dimension = this.dimension() + this.reset(this.$element[dimension]()) + this.transition('removeClass', 'hide', 'hidden') + this.$element[dimension](0) + } + + , reset: function ( size ) { + var dimension = this.dimension() + + this.$element + .removeClass('collapse') + [dimension](size || 'auto') + [0].offsetWidth + + this.$element.addClass('collapse') + } + + , transition: function ( method, startEvent, completeEvent ) { + var that = this + , complete = function () { + if (startEvent == 'show') that.reset() + that.$element.trigger(completeEvent) + } + + this.$element + .trigger(startEvent) + [method]('in') + + $.support.transition && this.$element.hasClass('collapse') ? + this.$element.one($.support.transition.end, complete) : + complete() + } + + , toggle: function () { + this[this.$element.hasClass('in') ? 'hide' : 'show']() + } + + } + + /* COLLAPSIBLE PLUGIN DEFINITION + * ============================== */ + + $.fn.collapse = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('collapse') + , options = typeof option == 'object' && option + if (!data) $this.data('collapse', (data = new Collapse(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.collapse.defaults = { + toggle: true + } + + $.fn.collapse.Constructor = Collapse + + + /* COLLAPSIBLE DATA-API + * ==================== */ + + $(function () { + $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function ( e ) { + var $this = $(this), href + , target = $this.attr('data-target') + || e.preventDefault() + || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 + , option = $(target).data('collapse') ? 'toggle' : $this.data() + $(target).collapse(option) + }) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-dropdown.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-dropdown.js new file mode 100644 index 0000000..f1f6c33 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-dropdown.js @@ -0,0 +1,92 @@ +/* ============================================================ + * bootstrap-dropdown.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#dropdowns + * ============================================================ + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + + +!function( $ ){ + + "use strict" + + /* DROPDOWN CLASS DEFINITION + * ========================= */ + + var toggle = '[data-toggle="dropdown"]' + , Dropdown = function ( element ) { + var $el = $(element).on('click.dropdown.data-api', this.toggle) + $('html').on('click.dropdown.data-api', function () { + $el.parent().removeClass('open') + }) + } + + Dropdown.prototype = { + + constructor: Dropdown + + , toggle: function ( e ) { + var $this = $(this) + , selector = $this.attr('data-target') + , $parent + , isActive + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = $(selector) + $parent.length || ($parent = $this.parent()) + + isActive = $parent.hasClass('open') + + clearMenus() + !isActive && $parent.toggleClass('open') + + return false + } + + } + + function clearMenus() { + $(toggle).parent().removeClass('open') + } + + + /* DROPDOWN PLUGIN DEFINITION + * ========================== */ + + $.fn.dropdown = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('dropdown') + if (!data) $this.data('dropdown', (data = new Dropdown(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.dropdown.Constructor = Dropdown + + + /* APPLY TO STANDARD DROPDOWN ELEMENTS + * =================================== */ + + $(function () { + $('html').on('click.dropdown.data-api', clearMenus) + $('body').on('click.dropdown.data-api', toggle, Dropdown.prototype.toggle) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-modal.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-modal.js new file mode 100644 index 0000000..bceb303 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-modal.js @@ -0,0 +1,210 @@ +/* ========================================================= + * bootstrap-modal.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#modals + * ========================================================= + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================= */ + + +!function( $ ){ + + "use strict" + + /* MODAL CLASS DEFINITION + * ====================== */ + + var Modal = function ( content, options ) { + this.options = options + this.$element = $(content) + .delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this)) + } + + Modal.prototype = { + + constructor: Modal + + , toggle: function () { + return this[!this.isShown ? 'show' : 'hide']() + } + + , show: function () { + var that = this + + if (this.isShown) return + + $('body').addClass('modal-open') + + this.isShown = true + this.$element.trigger('show') + + escape.call(this) + backdrop.call(this, function () { + var transition = $.support.transition && that.$element.hasClass('fade') + + !that.$element.parent().length && that.$element.appendTo(document.body) //don't move modals dom position + + that.$element + .show() + + if (transition) { + that.$element[0].offsetWidth // force reflow + } + + that.$element.addClass('in') + + transition ? + that.$element.one($.support.transition.end, function () { that.$element.trigger('shown') }) : + that.$element.trigger('shown') + + }) + } + + , hide: function ( e ) { + e && e.preventDefault() + + if (!this.isShown) return + + var that = this + this.isShown = false + + $('body').removeClass('modal-open') + + escape.call(this) + + this.$element + .trigger('hide') + .removeClass('in') + + $.support.transition && this.$element.hasClass('fade') ? + hideWithTransition.call(this) : + hideModal.call(this) + } + + } + + + /* MODAL PRIVATE METHODS + * ===================== */ + + function hideWithTransition() { + var that = this + , timeout = setTimeout(function () { + that.$element.off($.support.transition.end) + hideModal.call(that) + }, 500) + + this.$element.one($.support.transition.end, function () { + clearTimeout(timeout) + hideModal.call(that) + }) + } + + function hideModal( that ) { + this.$element + .hide() + .trigger('hidden') + + backdrop.call(this) + } + + function backdrop( callback ) { + var that = this + , animate = this.$element.hasClass('fade') ? 'fade' : '' + + if (this.isShown && this.options.backdrop) { + var doAnimate = $.support.transition && animate + + this.$backdrop = $(' + + + + + \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/head.html b/src/nl/astraeus/jdbc/web/head.html new file mode 100644 index 0000000..0f8f6a3 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/head.html @@ -0,0 +1,96 @@ + + + + + + + Simple JDBC Statistics + + + + + + + + + + + + + + + + + + + +
+
+ +
+ diff --git a/src/nl/astraeus/jdbc/web/page/Menu.html b/src/nl/astraeus/jdbc/web/page/Menu.html new file mode 100644 index 0000000..505c7c2 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.html @@ -0,0 +1,42 @@ + diff --git a/src/nl/astraeus/jdbc/web/page/Menu.java b/src/nl/astraeus/jdbc/web/page/Menu.java new file mode 100644 index 0000000..f0a349a --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.java @@ -0,0 +1,27 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 9:07 PM + */ +public class Menu extends TemplatePage { + + @Override + public Page processRequest(HttpServletRequest request) { + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + result.put("user", request.getSession().getAttribute("user")); + + return result; + } +} diff --git a/src/nl/astraeus/jdbc/web/page/Page.java b/src/nl/astraeus/jdbc/web/page/Page.java new file mode 100644 index 0000000..9d526d6 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Page.java @@ -0,0 +1,17 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:20 PM + */ +public abstract class Page { + + public abstract Page processRequest(HttpServletRequest request); + public abstract Map defineModel(HttpServletRequest request); + public abstract String render(HttpServletRequest request); + +} diff --git a/src/nl/astraeus/jdbc/web/page/QueryOverview.html b/src/nl/astraeus/jdbc/web/page/QueryOverview.html new file mode 100644 index 0000000..64a88fb --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/QueryOverview.html @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + {foreach(queries as q)} + + + + + + + {eachend} + +
Total timeAvg. time# CallsSql
{q.total}{q.nano}{q.count}{q.sql}
diff --git a/src/nl/astraeus/jdbc/web/page/QueryOverview.java b/src/nl/astraeus/jdbc/web/page/QueryOverview.java new file mode 100644 index 0000000..02982f1 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/QueryOverview.java @@ -0,0 +1,92 @@ +package nl.astraeus.jdbc.web.page; + +import nl.astraeus.jdbc.JdbcLogger; + +import javax.servlet.http.HttpServletRequest; +import java.util.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 9:16 PM + */ +public class QueryOverview extends TemplatePage { + + boolean sortTotalCalls = true; + boolean sortAvgTime = false; + boolean sortTotalTime = false; + + @Override + public Page processRequest(HttpServletRequest request) { + if ("sortTotalCalls".equals(request.getParameter("action"))) { + sortTotalCalls = true; + sortAvgTime = false; + sortTotalTime = false; + } else if ("sortAvgTime".equals(request.getParameter("action"))) { + sortTotalCalls = false; + sortAvgTime = true; + sortTotalTime = false; + } else if ("sortTotalTime".equals(request.getParameter("action"))) { + sortTotalCalls = false; + sortAvgTime = false; + sortTotalTime = true; + } + + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + List entries = new ArrayList(JdbcLogger.get().getEntries()); + + if (sortTotalCalls) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + return o2.count - o1.count; + } + }); + } else if (sortAvgTime) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + long n1 = o1.nano / o1.count; + long n2 = o2.nano / o2.count; + + if (n2 > n1) { + return 1; + } else if (n2 < n1) { + return -1; + } else { + return 0; + } + } + }); + } else if (sortTotalTime) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + if (o2.nano > o1.nano) { + return 1; + } else if (o2.nano < o1.nano) { + return -1; + } else { + return 0; + } + } + }); + } + + result.put("queries", entries); + result.put("count", entries.size()); + + result.put("sortTotalCalls", sortTotalCalls); + result.put("sortAvgTime", sortAvgTime); + result.put("sortTotalTime", sortTotalTime); + + return result; + } + +} diff --git a/src/nl/astraeus/jdbc/web/page/TemplatePage.java b/src/nl/astraeus/jdbc/web/page/TemplatePage.java new file mode 100644 index 0000000..33e2641 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/TemplatePage.java @@ -0,0 +1,58 @@ +package nl.astraeus.jdbc.web.page; + +import nl.astraeus.template.EscapeMode; +import nl.astraeus.template.SimpleTemplate; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:20 PM + */ +public abstract class TemplatePage extends Page { + + private SimpleTemplate template; + + protected TemplatePage() { + template = getSimpleTemplate(this.getClass()); + } + + public String render(HttpServletRequest request) { + return template.render(defineModel(request)); + } + + private static Map templateCache = new HashMap(); + + public synchronized static SimpleTemplate getSimpleTemplate(Class cls) { + SimpleTemplate result = templateCache.get(cls); + + if (result == null) { + InputStream in = null; + + try { + in = cls.getResourceAsStream(cls.getSimpleName() + ".html"); + + result = SimpleTemplate.readTemplate('{','}', EscapeMode.HTML, in); + + templateCache.put(cls, result); + } catch (IOException e) { + throw new IllegalStateException(e); + } finally { + if (in != null) { + try { + in.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + + return result; + } +} diff --git a/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css b/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css new file mode 100644 index 0000000..0e0056f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css @@ -0,0 +1,581 @@ +/*! + * Bootstrap Responsive v2.0.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ +.clearfix { + *zoom: 1; +} +.clearfix:before, .clearfix:after { + display: table; + content: ""; +} +.clearfix:after { + clear: both; +} +.hidden { + display: none; + visibility: hidden; +} +@media (max-width: 480px) { + .nav-collapse { + -webkit-transform: translate3d(0, 0, 0); + } + .page-header h1 small { + display: block; + line-height: 18px; + } + input[class*="span"], + select[class*="span"], + textarea[class*="span"], + .uneditable-input { + display: block; + width: 100%; + min-height: 28px; + /* Make inputs at least the height of their button counterpart */ + + /* Makes inputs behave like true block-level elements */ + + -webkit-box-sizing: border-box; + /* Older Webkit */ + + -moz-box-sizing: border-box; + /* Older FF */ + + -ms-box-sizing: border-box; + /* IE8 */ + + box-sizing: border-box; + /* CSS3 spec*/ + + } + .input-prepend input[class*="span"], .input-append input[class*="span"] { + width: auto; + } + input[type="checkbox"], input[type="radio"] { + border: 1px solid #ccc; + } + .form-horizontal .control-group > label { + float: none; + width: auto; + padding-top: 0; + text-align: left; + } + .form-horizontal .controls { + margin-left: 0; + } + .form-horizontal .control-list { + padding-top: 0; + } + .form-horizontal .form-actions { + padding-left: 10px; + padding-right: 10px; + } + .modal { + position: absolute; + top: 10px; + left: 10px; + right: 10px; + width: auto; + margin: 0; + } + .modal.fade.in { + top: auto; + } + .modal-header .close { + padding: 10px; + margin: -10px; + } + .carousel-caption { + position: static; + } +} +@media (max-width: 767px) { + .container { + width: auto; + padding: 0 20px; + } + .row-fluid { + width: 100%; + } + .row { + margin-left: 0; + } + .row > [class*="span"], .row-fluid > [class*="span"] { + float: none; + display: block; + width: auto; + margin: 0; + } +} +@media (min-width: 768px) and (max-width: 979px) { + .row { + margin-left: -20px; + *zoom: 1; + } + .row:before, .row:after { + display: table; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + margin-left: 20px; + } + .span1 { + width: 42px; + } + .span2 { + width: 104px; + } + .span3 { + width: 166px; + } + .span4 { + width: 228px; + } + .span5 { + width: 290px; + } + .span6 { + width: 352px; + } + .span7 { + width: 414px; + } + .span8 { + width: 476px; + } + .span9 { + width: 538px; + } + .span10 { + width: 600px; + } + .span11 { + width: 662px; + } + .span12, .container { + width: 724px; + } + .offset1 { + margin-left: 82px; + } + .offset2 { + margin-left: 144px; + } + .offset3 { + margin-left: 206px; + } + .offset4 { + margin-left: 268px; + } + .offset5 { + margin-left: 330px; + } + .offset6 { + margin-left: 392px; + } + .offset7 { + margin-left: 454px; + } + .offset8 { + margin-left: 516px; + } + .offset9 { + margin-left: 578px; + } + .offset10 { + margin-left: 640px; + } + .offset11 { + margin-left: 702px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, .row-fluid:after { + display: table; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid > [class*="span"] { + float: left; + margin-left: 2.762430939%; + } + .row-fluid > [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid > .span1 { + width: 5.801104972%; + } + .row-fluid > .span2 { + width: 14.364640883%; + } + .row-fluid > .span3 { + width: 22.928176794%; + } + .row-fluid > .span4 { + width: 31.491712705%; + } + .row-fluid > .span5 { + width: 40.055248616%; + } + .row-fluid > .span6 { + width: 48.618784527%; + } + .row-fluid > .span7 { + width: 57.182320438000005%; + } + .row-fluid > .span8 { + width: 65.74585634900001%; + } + .row-fluid > .span9 { + width: 74.30939226%; + } + .row-fluid > .span10 { + width: 82.87292817100001%; + } + .row-fluid > .span11 { + width: 91.436464082%; + } + .row-fluid > .span12 { + width: 99.999999993%; + } + input.span1, textarea.span1, .uneditable-input.span1 { + width: 32px; + } + input.span2, textarea.span2, .uneditable-input.span2 { + width: 94px; + } + input.span3, textarea.span3, .uneditable-input.span3 { + width: 156px; + } + input.span4, textarea.span4, .uneditable-input.span4 { + width: 218px; + } + input.span5, textarea.span5, .uneditable-input.span5 { + width: 280px; + } + input.span6, textarea.span6, .uneditable-input.span6 { + width: 342px; + } + input.span7, textarea.span7, .uneditable-input.span7 { + width: 404px; + } + input.span8, textarea.span8, .uneditable-input.span8 { + width: 466px; + } + input.span9, textarea.span9, .uneditable-input.span9 { + width: 528px; + } + input.span10, textarea.span10, .uneditable-input.span10 { + width: 590px; + } + input.span11, textarea.span11, .uneditable-input.span11 { + width: 652px; + } + input.span12, textarea.span12, .uneditable-input.span12 { + width: 714px; + } +} +@media (max-width: 979px) { + body { + padding-top: 0; + } + .navbar-fixed-top { + position: static; + margin-bottom: 18px; + } + .navbar-fixed-top .navbar-inner { + padding: 5px; + } + .navbar .container { + width: auto; + padding: 0; + } + .navbar .brand { + padding-left: 10px; + padding-right: 10px; + margin: 0 0 0 -5px; + } + .navbar .nav-collapse { + clear: left; + } + .navbar .nav { + float: none; + margin: 0 0 9px; + } + .navbar .nav > li { + float: none; + } + .navbar .nav > li > a { + margin-bottom: 2px; + } + .navbar .nav > .divider-vertical { + display: none; + } + .navbar .nav .nav-header { + color: #999999; + text-shadow: none; + } + .navbar .nav > li > a, .navbar .dropdown-menu a { + padding: 6px 15px; + font-weight: bold; + color: #999999; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + } + .navbar .dropdown-menu li + li a { + margin-bottom: 2px; + } + .navbar .nav > li > a:hover, .navbar .dropdown-menu a:hover { + background-color: #222222; + } + .navbar .dropdown-menu { + position: static; + top: auto; + left: auto; + float: none; + display: block; + max-width: none; + margin: 0 15px; + padding: 0; + background-color: transparent; + border: none; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + } + .navbar .dropdown-menu:before, .navbar .dropdown-menu:after { + display: none; + } + .navbar .dropdown-menu .divider { + display: none; + } + .navbar-form, .navbar-search { + float: none; + padding: 9px 15px; + margin: 9px 0; + border-top: 1px solid #222222; + border-bottom: 1px solid #222222; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + } + .navbar .nav.pull-right { + float: none; + margin-left: 0; + } + .navbar-static .navbar-inner { + padding-left: 10px; + padding-right: 10px; + } + .btn-navbar { + display: block; + } + .nav-collapse { + overflow: hidden; + height: 0; + } +} +@media (min-width: 980px) { + .nav-collapse.collapse { + height: auto !important; + } +} +@media (min-width: 1200px) { + .row { + margin-left: -30px; + *zoom: 1; + } + .row:before, .row:after { + display: table; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + margin-left: 30px; + } + .span1 { + width: 70px; + } + .span2 { + width: 170px; + } + .span3 { + width: 270px; + } + .span4 { + width: 370px; + } + .span5 { + width: 470px; + } + .span6 { + width: 570px; + } + .span7 { + width: 670px; + } + .span8 { + width: 770px; + } + .span9 { + width: 870px; + } + .span10 { + width: 970px; + } + .span11 { + width: 1070px; + } + .span12, .container { + width: 1170px; + } + .offset1 { + margin-left: 130px; + } + .offset2 { + margin-left: 230px; + } + .offset3 { + margin-left: 330px; + } + .offset4 { + margin-left: 430px; + } + .offset5 { + margin-left: 530px; + } + .offset6 { + margin-left: 630px; + } + .offset7 { + margin-left: 730px; + } + .offset8 { + margin-left: 830px; + } + .offset9 { + margin-left: 930px; + } + .offset10 { + margin-left: 1030px; + } + .offset11 { + margin-left: 1130px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, .row-fluid:after { + display: table; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid > [class*="span"] { + float: left; + margin-left: 2.564102564%; + } + .row-fluid > [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid > .span1 { + width: 5.982905983%; + } + .row-fluid > .span2 { + width: 14.529914530000001%; + } + .row-fluid > .span3 { + width: 23.076923077%; + } + .row-fluid > .span4 { + width: 31.623931624%; + } + .row-fluid > .span5 { + width: 40.170940171000005%; + } + .row-fluid > .span6 { + width: 48.717948718%; + } + .row-fluid > .span7 { + width: 57.264957265%; + } + .row-fluid > .span8 { + width: 65.81196581200001%; + } + .row-fluid > .span9 { + width: 74.358974359%; + } + .row-fluid > .span10 { + width: 82.905982906%; + } + .row-fluid > .span11 { + width: 91.45299145300001%; + } + .row-fluid > .span12 { + width: 100%; + } + input.span1, textarea.span1, .uneditable-input.span1 { + width: 60px; + } + input.span2, textarea.span2, .uneditable-input.span2 { + width: 160px; + } + input.span3, textarea.span3, .uneditable-input.span3 { + width: 260px; + } + input.span4, textarea.span4, .uneditable-input.span4 { + width: 360px; + } + input.span5, textarea.span5, .uneditable-input.span5 { + width: 460px; + } + input.span6, textarea.span6, .uneditable-input.span6 { + width: 560px; + } + input.span7, textarea.span7, .uneditable-input.span7 { + width: 660px; + } + input.span8, textarea.span8, .uneditable-input.span8 { + width: 760px; + } + input.span9, textarea.span9, .uneditable-input.span9 { + width: 860px; + } + input.span10, textarea.span10, .uneditable-input.span10 { + width: 960px; + } + input.span11, textarea.span11, .uneditable-input.span11 { + width: 1060px; + } + input.span12, textarea.span12, .uneditable-input.span12 { + width: 1160px; + } + .thumbnails { + margin-left: -30px; + } + .thumbnails > li { + margin-left: 30px; + } +} diff --git a/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css b/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css new file mode 100644 index 0000000..6229c12 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css @@ -0,0 +1,3521 @@ +/*! + * Bootstrap v2.0.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +nav, +section { + display: block; +} +audio, canvas, video { + display: inline-block; + *display: inline; + *zoom: 1; +} +audio:not([controls]) { + display: none; +} +html { + font-size: 100%; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} +a:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +a:hover, a:active { + outline: 0; +} +sub, sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} +sup { + top: -0.5em; +} +sub { + bottom: -0.25em; +} +img { + max-width: 100%; + height: auto; + border: 0; + -ms-interpolation-mode: bicubic; +} +button, +input, +select, +textarea { + margin: 0; + font-size: 100%; + vertical-align: middle; +} +button, input { + *overflow: visible; + line-height: normal; +} +button::-moz-focus-inner, input::-moz-focus-inner { + padding: 0; + border: 0; +} +button, +input[type="button"], +input[type="reset"], +input[type="submit"] { + cursor: pointer; + -webkit-appearance: button; +} +input[type="search"] { + -webkit-appearance: textfield; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +input[type="search"]::-webkit-search-decoration, input[type="search"]::-webkit-search-cancel-button { + -webkit-appearance: none; +} +textarea { + overflow: auto; + vertical-align: top; +} +.clearfix { + *zoom: 1; +} +.clearfix:before, .clearfix:after { + display: table; + content: ""; +} +.clearfix:after { + clear: both; +} +body { + margin: 0; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 18px; + color: #333333; + background-color: #ffffff; +} +a { + color: #0088cc; + text-decoration: none; +} +a:hover { + color: #005580; + text-decoration: underline; +} +.row { + margin-left: -20px; + *zoom: 1; +} +.row:before, .row:after { + display: table; + content: ""; +} +.row:after { + clear: both; +} +[class*="span"] { + float: left; + margin-left: 20px; +} +.span1 { + width: 60px; +} +.span2 { + width: 140px; +} +.span3 { + width: 220px; +} +.span4 { + width: 300px; +} +.span5 { + width: 380px; +} +.span6 { + width: 460px; +} +.span7 { + width: 540px; +} +.span8 { + width: 620px; +} +.span9 { + width: 700px; +} +.span10 { + width: 780px; +} +.span11 { + width: 860px; +} +.span12, .container { + width: 940px; +} +.offset1 { + margin-left: 100px; +} +.offset2 { + margin-left: 180px; +} +.offset3 { + margin-left: 260px; +} +.offset4 { + margin-left: 340px; +} +.offset5 { + margin-left: 420px; +} +.offset6 { + margin-left: 500px; +} +.offset7 { + margin-left: 580px; +} +.offset8 { + margin-left: 660px; +} +.offset9 { + margin-left: 740px; +} +.offset10 { + margin-left: 820px; +} +.offset11 { + margin-left: 900px; +} +.row-fluid { + width: 100%; + *zoom: 1; +} +.row-fluid:before, .row-fluid:after { + display: table; + content: ""; +} +.row-fluid:after { + clear: both; +} +.row-fluid > [class*="span"] { + float: left; + margin-left: 2.127659574%; +} +.row-fluid > [class*="span"]:first-child { + margin-left: 0; +} +.row-fluid > .span1 { + width: 6.382978723%; +} +.row-fluid > .span2 { + width: 14.89361702%; +} +.row-fluid > .span3 { + width: 23.404255317%; +} +.row-fluid > .span4 { + width: 31.914893614%; +} +.row-fluid > .span5 { + width: 40.425531911%; +} +.row-fluid > .span6 { + width: 48.93617020799999%; +} +.row-fluid > .span7 { + width: 57.446808505%; +} +.row-fluid > .span8 { + width: 65.95744680199999%; +} +.row-fluid > .span9 { + width: 74.468085099%; +} +.row-fluid > .span10 { + width: 82.97872339599999%; +} +.row-fluid > .span11 { + width: 91.489361693%; +} +.row-fluid > .span12 { + width: 99.99999998999999%; +} +.container { + width: 940px; + margin-left: auto; + margin-right: auto; + *zoom: 1; +} +.container:before, .container:after { + display: table; + content: ""; +} +.container:after { + clear: both; +} +.container-fluid { + padding-left: 20px; + padding-right: 20px; + *zoom: 1; +} +.container-fluid:before, .container-fluid:after { + display: table; + content: ""; +} +.container-fluid:after { + clear: both; +} +p { + margin: 0 0 9px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 18px; +} +p small { + font-size: 11px; + color: #999999; +} +.lead { + margin-bottom: 18px; + font-size: 20px; + font-weight: 200; + line-height: 27px; +} +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 0; + font-weight: bold; + color: #333333; + text-rendering: optimizelegibility; +} +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small { + font-weight: normal; + color: #999999; +} +h1 { + font-size: 30px; + line-height: 36px; +} +h1 small { + font-size: 18px; +} +h2 { + font-size: 24px; + line-height: 36px; +} +h2 small { + font-size: 18px; +} +h3 { + line-height: 27px; + font-size: 18px; +} +h3 small { + font-size: 14px; +} +h4, h5, h6 { + line-height: 18px; +} +h4 { + font-size: 14px; +} +h4 small { + font-size: 12px; +} +h5 { + font-size: 12px; +} +h6 { + font-size: 11px; + color: #999999; + text-transform: uppercase; +} +.page-header { + padding-bottom: 17px; + margin: 18px 0; + border-bottom: 1px solid #eeeeee; +} +.page-header h1 { + line-height: 1; +} +ul, ol { + padding: 0; + margin: 0 0 9px 25px; +} +ul ul, +ul ol, +ol ol, +ol ul { + margin-bottom: 0; +} +ul { + list-style: disc; +} +ol { + list-style: decimal; +} +li { + line-height: 18px; +} +ul.unstyled, ol.unstyled { + margin-left: 0; + list-style: none; +} +dl { + margin-bottom: 18px; +} +dt, dd { + line-height: 18px; +} +dt { + font-weight: bold; +} +dd { + margin-left: 9px; +} +hr { + margin: 18px 0; + border: 0; + border-top: 1px solid #eeeeee; + border-bottom: 1px solid #ffffff; +} +strong { + font-weight: bold; +} +em { + font-style: italic; +} +.muted { + color: #999999; +} +abbr { + font-size: 90%; + text-transform: uppercase; + border-bottom: 1px dotted #ddd; + cursor: help; +} +blockquote { + padding: 0 0 0 15px; + margin: 0 0 18px; + border-left: 5px solid #eeeeee; +} +blockquote p { + margin-bottom: 0; + font-size: 16px; + font-weight: 300; + line-height: 22.5px; +} +blockquote small { + display: block; + line-height: 18px; + color: #999999; +} +blockquote small:before { + content: '\2014 \00A0'; +} +blockquote.pull-right { + float: right; + padding-left: 0; + padding-right: 15px; + border-left: 0; + border-right: 5px solid #eeeeee; +} +blockquote.pull-right p, blockquote.pull-right small { + text-align: right; +} +q:before, +q:after, +blockquote:before, +blockquote:after { + content: ""; +} +address { + display: block; + margin-bottom: 18px; + line-height: 18px; + font-style: normal; +} +small { + font-size: 100%; +} +cite { + font-style: normal; +} +code, pre { + padding: 0 3px 2px; + font-family: Menlo, Monaco, "Courier New", monospace; + font-size: 12px; + color: #333333; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +code { + padding: 3px 4px; + color: #d14; + background-color: #f7f7f9; + border: 1px solid #e1e1e8; +} +pre { + display: block; + padding: 8.5px; + margin: 0 0 9px; + font-size: 12px; + line-height: 18px; + background-color: #f5f5f5; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.15); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + white-space: pre; + white-space: pre-wrap; + word-break: break-all; + word-wrap: break-word; +} +pre.prettyprint { + margin-bottom: 18px; +} +pre code { + padding: 0; + color: inherit; + background-color: transparent; + border: 0; +} +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} +form { + margin: 0 0 18px; +} +fieldset { + padding: 0; + margin: 0; + border: 0; +} +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 27px; + font-size: 19.5px; + line-height: 36px; + color: #333333; + border: 0; + border-bottom: 1px solid #eee; +} +legend small { + font-size: 13.5px; + color: #999999; +} +label, +input, +button, +select, +textarea { + font-size: 13px; + font-weight: normal; + line-height: 18px; +} +input, +button, +select, +textarea { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; +} +label { + display: block; + margin-bottom: 5px; + color: #333333; +} +input, +textarea, +select, +.uneditable-input { + display: inline-block; + width: 210px; + height: 18px; + padding: 4px; + margin-bottom: 9px; + font-size: 13px; + line-height: 18px; + color: #555555; + border: 1px solid #ccc; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.uneditable-textarea { + width: auto; + height: auto; +} +label input, label textarea, label select { + display: block; +} +input[type="image"], input[type="checkbox"], input[type="radio"] { + width: auto; + height: auto; + padding: 0; + margin: 3px 0; + *margin-top: 0; + /* IE7 */ + + line-height: normal; + cursor: pointer; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + border: 0 \9; + /* IE9 and down */ + +} +input[type="image"] { + border: 0; +} +input[type="file"] { + width: auto; + padding: initial; + line-height: initial; + border: initial; + background-color: #ffffff; + background-color: initial; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +input[type="button"], input[type="reset"], input[type="submit"] { + width: auto; + height: auto; +} +select, input[type="file"] { + height: 28px; + /* In IE7, the height of the select element cannot be changed by height, only font-size */ + + *margin-top: 4px; + /* For IE7, add top margin to align select with labels */ + + line-height: 28px; +} +input[type="file"] { + line-height: 18px \9; +} +select { + width: 220px; + background-color: #ffffff; +} +select[multiple], select[size] { + height: auto; +} +input[type="image"] { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +textarea { + height: auto; +} +input[type="hidden"] { + display: none; +} +.radio, .checkbox { + padding-left: 18px; +} +.radio input[type="radio"], .checkbox input[type="checkbox"] { + float: left; + margin-left: -18px; +} +.controls > .radio:first-child, .controls > .checkbox:first-child { + padding-top: 5px; +} +.radio.inline, .checkbox.inline { + display: inline-block; + padding-top: 5px; + margin-bottom: 0; + vertical-align: middle; +} +.radio.inline + .radio.inline, .checkbox.inline + .checkbox.inline { + margin-left: 10px; +} +input, textarea { + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; + -moz-transition: border linear 0.2s, box-shadow linear 0.2s; + -ms-transition: border linear 0.2s, box-shadow linear 0.2s; + -o-transition: border linear 0.2s, box-shadow linear 0.2s; + transition: border linear 0.2s, box-shadow linear 0.2s; +} +input:focus, textarea:focus { + border-color: rgba(82, 168, 236, 0.8); + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + outline: 0; + outline: thin dotted \9; + /* IE6-9 */ + +} +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus, +select:focus { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.input-mini { + width: 60px; +} +.input-small { + width: 90px; +} +.input-medium { + width: 150px; +} +.input-large { + width: 210px; +} +.input-xlarge { + width: 270px; +} +.input-xxlarge { + width: 530px; +} +input[class*="span"], +select[class*="span"], +textarea[class*="span"], +.uneditable-input { + float: none; + margin-left: 0; +} +input.span1, textarea.span1, .uneditable-input.span1 { + width: 50px; +} +input.span2, textarea.span2, .uneditable-input.span2 { + width: 130px; +} +input.span3, textarea.span3, .uneditable-input.span3 { + width: 210px; +} +input.span4, textarea.span4, .uneditable-input.span4 { + width: 290px; +} +input.span5, textarea.span5, .uneditable-input.span5 { + width: 370px; +} +input.span6, textarea.span6, .uneditable-input.span6 { + width: 450px; +} +input.span7, textarea.span7, .uneditable-input.span7 { + width: 530px; +} +input.span8, textarea.span8, .uneditable-input.span8 { + width: 610px; +} +input.span9, textarea.span9, .uneditable-input.span9 { + width: 690px; +} +input.span10, textarea.span10, .uneditable-input.span10 { + width: 770px; +} +input.span11, textarea.span11, .uneditable-input.span11 { + width: 850px; +} +input.span12, textarea.span12, .uneditable-input.span12 { + width: 930px; +} +input[disabled], +select[disabled], +textarea[disabled], +input[readonly], +select[readonly], +textarea[readonly] { + background-color: #f5f5f5; + border-color: #ddd; + cursor: not-allowed; +} +.control-group.warning > label, .control-group.warning .help-block, .control-group.warning .help-inline { + color: #c09853; +} +.control-group.warning input, .control-group.warning select, .control-group.warning textarea { + color: #c09853; + border-color: #c09853; +} +.control-group.warning input:focus, .control-group.warning select:focus, .control-group.warning textarea:focus { + border-color: #a47e3c; + -webkit-box-shadow: 0 0 6px #dbc59e; + -moz-box-shadow: 0 0 6px #dbc59e; + box-shadow: 0 0 6px #dbc59e; +} +.control-group.warning .input-prepend .add-on, .control-group.warning .input-append .add-on { + color: #c09853; + background-color: #fcf8e3; + border-color: #c09853; +} +.control-group.error > label, .control-group.error .help-block, .control-group.error .help-inline { + color: #b94a48; +} +.control-group.error input, .control-group.error select, .control-group.error textarea { + color: #b94a48; + border-color: #b94a48; +} +.control-group.error input:focus, .control-group.error select:focus, .control-group.error textarea:focus { + border-color: #953b39; + -webkit-box-shadow: 0 0 6px #d59392; + -moz-box-shadow: 0 0 6px #d59392; + box-shadow: 0 0 6px #d59392; +} +.control-group.error .input-prepend .add-on, .control-group.error .input-append .add-on { + color: #b94a48; + background-color: #f2dede; + border-color: #b94a48; +} +.control-group.success > label, .control-group.success .help-block, .control-group.success .help-inline { + color: #468847; +} +.control-group.success input, .control-group.success select, .control-group.success textarea { + color: #468847; + border-color: #468847; +} +.control-group.success input:focus, .control-group.success select:focus, .control-group.success textarea:focus { + border-color: #356635; + -webkit-box-shadow: 0 0 6px #7aba7b; + -moz-box-shadow: 0 0 6px #7aba7b; + box-shadow: 0 0 6px #7aba7b; +} +.control-group.success .input-prepend .add-on, .control-group.success .input-append .add-on { + color: #468847; + background-color: #dff0d8; + border-color: #468847; +} +input:focus:required:invalid, textarea:focus:required:invalid, select:focus:required:invalid { + color: #b94a48; + border-color: #ee5f5b; +} +input:focus:required:invalid:focus, textarea:focus:required:invalid:focus, select:focus:required:invalid:focus { + border-color: #e9322d; + -webkit-box-shadow: 0 0 6px #f8b9b7; + -moz-box-shadow: 0 0 6px #f8b9b7; + box-shadow: 0 0 6px #f8b9b7; +} +.form-actions { + padding: 17px 20px 18px; + margin-top: 18px; + margin-bottom: 18px; + background-color: #f5f5f5; + border-top: 1px solid #ddd; +} +.uneditable-input { + display: block; + background-color: #ffffff; + border-color: #eee; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + cursor: not-allowed; +} +:-moz-placeholder { + color: #999999; +} +::-webkit-input-placeholder { + color: #999999; +} +.help-block { + display: block; + margin-top: 5px; + margin-bottom: 0; + color: #999999; +} +.help-inline { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; + margin-bottom: 9px; + vertical-align: middle; + padding-left: 5px; +} +.input-prepend, .input-append { + margin-bottom: 5px; + *zoom: 1; +} +.input-prepend:before, +.input-append:before, +.input-prepend:after, +.input-append:after { + display: table; + content: ""; +} +.input-prepend:after, .input-append:after { + clear: both; +} +.input-prepend input, +.input-append input, +.input-prepend .uneditable-input, +.input-append .uneditable-input { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.input-prepend input:focus, +.input-append input:focus, +.input-prepend .uneditable-input:focus, +.input-append .uneditable-input:focus { + position: relative; + z-index: 2; +} +.input-prepend .uneditable-input, .input-append .uneditable-input { + border-left-color: #ccc; +} +.input-prepend .add-on, .input-append .add-on { + float: left; + display: block; + width: auto; + min-width: 16px; + height: 18px; + margin-right: -1px; + padding: 4px 5px; + font-weight: normal; + line-height: 18px; + color: #999999; + text-align: center; + text-shadow: 0 1px 0 #ffffff; + background-color: #f5f5f5; + border: 1px solid #ccc; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.input-prepend .active, .input-append .active { + background-color: #a9dba9; + border-color: #46a546; +} +.input-prepend .add-on { + *margin-top: 1px; + /* IE6-7 */ + +} +.input-append input, .input-append .uneditable-input { + float: left; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.input-append .uneditable-input { + border-left-color: #eee; + border-right-color: #ccc; +} +.input-append .add-on { + margin-right: 0; + margin-left: -1px; + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.input-append input:first-child { + *margin-left: -160px; +} +.input-append input:first-child + .add-on { + *margin-left: -21px; +} +.search-query { + padding-left: 14px; + padding-right: 14px; + margin-bottom: 0; + -webkit-border-radius: 14px; + -moz-border-radius: 14px; + border-radius: 14px; +} +.form-search input, +.form-inline input, +.form-horizontal input, +.form-search textarea, +.form-inline textarea, +.form-horizontal textarea, +.form-search select, +.form-inline select, +.form-horizontal select, +.form-search .help-inline, +.form-inline .help-inline, +.form-horizontal .help-inline, +.form-search .uneditable-input, +.form-inline .uneditable-input, +.form-horizontal .uneditable-input { + display: inline-block; + margin-bottom: 0; +} +.form-search .hide, .form-inline .hide, .form-horizontal .hide { + display: none; +} +.form-search label, +.form-inline label, +.form-search .input-append, +.form-inline .input-append, +.form-search .input-prepend, +.form-inline .input-prepend { + display: inline-block; +} +.form-search .input-append .add-on, +.form-inline .input-prepend .add-on, +.form-search .input-append .add-on, +.form-inline .input-prepend .add-on { + vertical-align: middle; +} +.form-search .radio, +.form-inline .radio, +.form-search .checkbox, +.form-inline .checkbox { + margin-bottom: 0; + vertical-align: middle; +} +.control-group { + margin-bottom: 9px; +} +legend + .control-group { + margin-top: 18px; + -webkit-margin-top-collapse: separate; +} +.form-horizontal .control-group { + margin-bottom: 18px; + *zoom: 1; +} +.form-horizontal .control-group:before, .form-horizontal .control-group:after { + display: table; + content: ""; +} +.form-horizontal .control-group:after { + clear: both; +} +.form-horizontal .control-label { + float: left; + width: 140px; + padding-top: 5px; + text-align: right; +} +.form-horizontal .controls { + margin-left: 160px; +} +.form-horizontal .form-actions { + padding-left: 160px; +} +table { + max-width: 100%; + border-collapse: collapse; + border-spacing: 0; +} +.table { + width: 100%; + margin-bottom: 18px; +} +.table th, .table td { + padding: 8px; + line-height: 18px; + text-align: left; + vertical-align: top; + border-top: 1px solid #ddd; +} +.table th { + font-weight: bold; +} +.table thead th { + vertical-align: bottom; +} +.table thead:first-child tr th, .table thead:first-child tr td { + border-top: 0; +} +.table tbody + tbody { + border-top: 2px solid #ddd; +} +.table-condensed th, .table-condensed td { + padding: 4px 5px; +} +.table-bordered { + border: 1px solid #ddd; + border-collapse: separate; + *border-collapse: collapsed; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.table-bordered th + th, +.table-bordered td + td, +.table-bordered th + td, +.table-bordered td + th { + border-left: 1px solid #ddd; +} +.table-bordered thead:first-child tr:first-child th, .table-bordered tbody:first-child tr:first-child th, .table-bordered tbody:first-child tr:first-child td { + border-top: 0; +} +.table-bordered thead:first-child tr:first-child th:first-child, .table-bordered tbody:first-child tr:first-child td:first-child { + -webkit-border-radius: 4px 0 0 0; + -moz-border-radius: 4px 0 0 0; + border-radius: 4px 0 0 0; +} +.table-bordered thead:first-child tr:first-child th:last-child, .table-bordered tbody:first-child tr:first-child td:last-child { + -webkit-border-radius: 0 4px 0 0; + -moz-border-radius: 0 4px 0 0; + border-radius: 0 4px 0 0; +} +.table-bordered thead:last-child tr:last-child th:first-child, .table-bordered tbody:last-child tr:last-child td:first-child { + -webkit-border-radius: 0 0 0 4px; + -moz-border-radius: 0 0 0 4px; + border-radius: 0 0 0 4px; +} +.table-bordered thead:last-child tr:last-child th:last-child, .table-bordered tbody:last-child tr:last-child td:last-child { + -webkit-border-radius: 0 0 4px 0; + -moz-border-radius: 0 0 4px 0; + border-radius: 0 0 4px 0; +} +.table-striped tbody tr:nth-child(odd) td, .table-striped tbody tr:nth-child(odd) th { + background-color: #f9f9f9; +} +.table tbody tr:hover td, .table tbody tr:hover th { + background-color: #f5f5f5; +} +table .span1 { + float: none; + width: 44px; + margin-left: 0; +} +table .span2 { + float: none; + width: 124px; + margin-left: 0; +} +table .span3 { + float: none; + width: 204px; + margin-left: 0; +} +table .span4 { + float: none; + width: 284px; + margin-left: 0; +} +table .span5 { + float: none; + width: 364px; + margin-left: 0; +} +table .span6 { + float: none; + width: 444px; + margin-left: 0; +} +table .span7 { + float: none; + width: 524px; + margin-left: 0; +} +table .span8 { + float: none; + width: 604px; + margin-left: 0; +} +table .span9 { + float: none; + width: 684px; + margin-left: 0; +} +table .span10 { + float: none; + width: 764px; + margin-left: 0; +} +table .span11 { + float: none; + width: 844px; + margin-left: 0; +} +table .span12 { + float: none; + width: 924px; + margin-left: 0; +} +[class^="icon-"], [class*=" icon-"] { + display: inline-block; + width: 14px; + height: 14px; + line-height: 14px; + vertical-align: text-top; + background-image: url("../img/glyphicons-halflings.png"); + background-position: 14px 14px; + background-repeat: no-repeat; + *margin-right: .3em; +} +[class^="icon-"]:last-child, [class*=" icon-"]:last-child { + *margin-left: 0; +} +.icon-white { + background-image: url("../img/glyphicons-halflings-white.png"); +} +.icon-glass { + background-position: 0 0; +} +.icon-music { + background-position: -24px 0; +} +.icon-search { + background-position: -48px 0; +} +.icon-envelope { + background-position: -72px 0; +} +.icon-heart { + background-position: -96px 0; +} +.icon-star { + background-position: -120px 0; +} +.icon-star-empty { + background-position: -144px 0; +} +.icon-user { + background-position: -168px 0; +} +.icon-film { + background-position: -192px 0; +} +.icon-th-large { + background-position: -216px 0; +} +.icon-th { + background-position: -240px 0; +} +.icon-th-list { + background-position: -264px 0; +} +.icon-ok { + background-position: -288px 0; +} +.icon-remove { + background-position: -312px 0; +} +.icon-zoom-in { + background-position: -336px 0; +} +.icon-zoom-out { + background-position: -360px 0; +} +.icon-off { + background-position: -384px 0; +} +.icon-signal { + background-position: -408px 0; +} +.icon-cog { + background-position: -432px 0; +} +.icon-trash { + background-position: -456px 0; +} +.icon-home { + background-position: 0 -24px; +} +.icon-file { + background-position: -24px -24px; +} +.icon-time { + background-position: -48px -24px; +} +.icon-road { + background-position: -72px -24px; +} +.icon-download-alt { + background-position: -96px -24px; +} +.icon-download { + background-position: -120px -24px; +} +.icon-upload { + background-position: -144px -24px; +} +.icon-inbox { + background-position: -168px -24px; +} +.icon-play-circle { + background-position: -192px -24px; +} +.icon-repeat { + background-position: -216px -24px; +} +.icon-refresh { + background-position: -240px -24px; +} +.icon-list-alt { + background-position: -264px -24px; +} +.icon-lock { + background-position: -287px -24px; +} +.icon-flag { + background-position: -312px -24px; +} +.icon-headphones { + background-position: -336px -24px; +} +.icon-volume-off { + background-position: -360px -24px; +} +.icon-volume-down { + background-position: -384px -24px; +} +.icon-volume-up { + background-position: -408px -24px; +} +.icon-qrcode { + background-position: -432px -24px; +} +.icon-barcode { + background-position: -456px -24px; +} +.icon-tag { + background-position: 0 -48px; +} +.icon-tags { + background-position: -25px -48px; +} +.icon-book { + background-position: -48px -48px; +} +.icon-bookmark { + background-position: -72px -48px; +} +.icon-print { + background-position: -96px -48px; +} +.icon-camera { + background-position: -120px -48px; +} +.icon-font { + background-position: -144px -48px; +} +.icon-bold { + background-position: -167px -48px; +} +.icon-italic { + background-position: -192px -48px; +} +.icon-text-height { + background-position: -216px -48px; +} +.icon-text-width { + background-position: -240px -48px; +} +.icon-align-left { + background-position: -264px -48px; +} +.icon-align-center { + background-position: -288px -48px; +} +.icon-align-right { + background-position: -312px -48px; +} +.icon-align-justify { + background-position: -336px -48px; +} +.icon-list { + background-position: -360px -48px; +} +.icon-indent-left { + background-position: -384px -48px; +} +.icon-indent-right { + background-position: -408px -48px; +} +.icon-facetime-video { + background-position: -432px -48px; +} +.icon-picture { + background-position: -456px -48px; +} +.icon-pencil { + background-position: 0 -72px; +} +.icon-map-marker { + background-position: -24px -72px; +} +.icon-adjust { + background-position: -48px -72px; +} +.icon-tint { + background-position: -72px -72px; +} +.icon-edit { + background-position: -96px -72px; +} +.icon-share { + background-position: -120px -72px; +} +.icon-check { + background-position: -144px -72px; +} +.icon-move { + background-position: -168px -72px; +} +.icon-step-backward { + background-position: -192px -72px; +} +.icon-fast-backward { + background-position: -216px -72px; +} +.icon-backward { + background-position: -240px -72px; +} +.icon-play { + background-position: -264px -72px; +} +.icon-pause { + background-position: -288px -72px; +} +.icon-stop { + background-position: -312px -72px; +} +.icon-forward { + background-position: -336px -72px; +} +.icon-fast-forward { + background-position: -360px -72px; +} +.icon-step-forward { + background-position: -384px -72px; +} +.icon-eject { + background-position: -408px -72px; +} +.icon-chevron-left { + background-position: -432px -72px; +} +.icon-chevron-right { + background-position: -456px -72px; +} +.icon-plus-sign { + background-position: 0 -96px; +} +.icon-minus-sign { + background-position: -24px -96px; +} +.icon-remove-sign { + background-position: -48px -96px; +} +.icon-ok-sign { + background-position: -72px -96px; +} +.icon-question-sign { + background-position: -96px -96px; +} +.icon-info-sign { + background-position: -120px -96px; +} +.icon-screenshot { + background-position: -144px -96px; +} +.icon-remove-circle { + background-position: -168px -96px; +} +.icon-ok-circle { + background-position: -192px -96px; +} +.icon-ban-circle { + background-position: -216px -96px; +} +.icon-arrow-left { + background-position: -240px -96px; +} +.icon-arrow-right { + background-position: -264px -96px; +} +.icon-arrow-up { + background-position: -289px -96px; +} +.icon-arrow-down { + background-position: -312px -96px; +} +.icon-share-alt { + background-position: -336px -96px; +} +.icon-resize-full { + background-position: -360px -96px; +} +.icon-resize-small { + background-position: -384px -96px; +} +.icon-plus { + background-position: -408px -96px; +} +.icon-minus { + background-position: -433px -96px; +} +.icon-asterisk { + background-position: -456px -96px; +} +.icon-exclamation-sign { + background-position: 0 -120px; +} +.icon-gift { + background-position: -24px -120px; +} +.icon-leaf { + background-position: -48px -120px; +} +.icon-fire { + background-position: -72px -120px; +} +.icon-eye-open { + background-position: -96px -120px; +} +.icon-eye-close { + background-position: -120px -120px; +} +.icon-warning-sign { + background-position: -144px -120px; +} +.icon-plane { + background-position: -168px -120px; +} +.icon-calendar { + background-position: -192px -120px; +} +.icon-random { + background-position: -216px -120px; +} +.icon-comment { + background-position: -240px -120px; +} +.icon-magnet { + background-position: -264px -120px; +} +.icon-chevron-up { + background-position: -288px -120px; +} +.icon-chevron-down { + background-position: -313px -119px; +} +.icon-retweet { + background-position: -336px -120px; +} +.icon-shopping-cart { + background-position: -360px -120px; +} +.icon-folder-close { + background-position: -384px -120px; +} +.icon-folder-open { + background-position: -408px -120px; +} +.icon-resize-vertical { + background-position: -432px -119px; +} +.icon-resize-horizontal { + background-position: -456px -118px; +} +.dropdown { + position: relative; +} +.dropdown-toggle { + *margin-bottom: -3px; +} +.dropdown-toggle:active, .open .dropdown-toggle { + outline: 0; +} +.caret { + display: inline-block; + width: 0; + height: 0; + text-indent: -99999px; + *text-indent: 0; + vertical-align: top; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 4px solid #000000; + opacity: 0.3; + filter: alpha(opacity=30); + content: "\2193"; +} +.dropdown .caret { + margin-top: 8px; + margin-left: 2px; +} +.dropdown:hover .caret, .open.dropdown .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + float: left; + display: none; + min-width: 160px; + _width: 160px; + padding: 4px 0; + margin: 0; + list-style: none; + background-color: #ffffff; + border-color: #ccc; + border-color: rgba(0, 0, 0, 0.2); + border-style: solid; + border-width: 1px; + -webkit-border-radius: 0 0 5px 5px; + -moz-border-radius: 0 0 5px 5px; + border-radius: 0 0 5px 5px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; + *border-right-width: 2px; + *border-bottom-width: 2px; +} +.dropdown-menu.bottom-up { + top: auto; + bottom: 100%; + margin-bottom: 2px; +} +.dropdown-menu .divider { + height: 1px; + margin: 5px 1px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #ffffff; + *width: 100%; + *margin: -5px 0 5px; +} +.dropdown-menu a { + display: block; + padding: 3px 15px; + clear: both; + font-weight: normal; + line-height: 18px; + color: #555555; + white-space: nowrap; +} +.dropdown-menu li > a:hover, .dropdown-menu .active > a, .dropdown-menu .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #0088cc; +} +.dropdown.open { + *z-index: 1000; +} +.dropdown.open .dropdown-toggle { + color: #ffffff; + background: #ccc; + background: rgba(0, 0, 0, 0.3); +} +.dropdown.open .dropdown-menu { + display: block; +} +.typeahead { + margin-top: 2px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #f5f5f5; + border: 1px solid #eee; + border: 1px solid rgba(0, 0, 0, 0.05); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 0, 0, 0.15); +} +.fade { + -webkit-transition: opacity 0.15s linear; + -moz-transition: opacity 0.15s linear; + -ms-transition: opacity 0.15s linear; + -o-transition: opacity 0.15s linear; + transition: opacity 0.15s linear; + opacity: 0; +} +.fade.in { + opacity: 1; +} +.collapse { + -webkit-transition: height 0.35s ease; + -moz-transition: height 0.35s ease; + -ms-transition: height 0.35s ease; + -o-transition: height 0.35s ease; + transition: height 0.35s ease; + position: relative; + overflow: hidden; + height: 0; +} +.collapse.in { + height: auto; +} +.close { + float: right; + font-size: 20px; + font-weight: bold; + line-height: 18px; + color: #000000; + text-shadow: 0 1px 0 #ffffff; + opacity: 0.2; + filter: alpha(opacity=20); +} +.close:hover { + color: #000000; + text-decoration: none; + opacity: 0.4; + filter: alpha(opacity=40); + cursor: pointer; +} +.btn { + display: inline-block; + padding: 4px 10px 4px; + margin-bottom: 0; + font-size: 13px; + line-height: 18px; + color: #333333; + text-align: center; + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); + vertical-align: middle; + background-color: #f5f5f5; + background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); + background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); + background-image: linear-gradient(top, #ffffff, #e6e6e6); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0); + border-color: #e6e6e6 #e6e6e6 #bfbfbf; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + border: 1px solid #ccc; + border-bottom-color: #bbb; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + cursor: pointer; + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + *margin-left: .3em; +} +.btn:hover, +.btn:active, +.btn.active, +.btn.disabled, +.btn[disabled] { + background-color: #e6e6e6; +} +.btn:active, .btn.active { + background-color: #cccccc \9; +} +.btn:first-child { + *margin-left: 0; +} +.btn:hover { + color: #333333; + text-decoration: none; + background-color: #e6e6e6; + background-position: 0 -15px; + -webkit-transition: background-position 0.1s linear; + -moz-transition: background-position 0.1s linear; + -ms-transition: background-position 0.1s linear; + -o-transition: background-position 0.1s linear; + transition: background-position 0.1s linear; +} +.btn:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.btn.active, .btn:active { + background-image: none; + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + background-color: #e6e6e6; + background-color: #d9d9d9 \9; + outline: 0; +} +.btn.disabled, .btn[disabled] { + cursor: default; + background-image: none; + background-color: #e6e6e6; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +.btn-large { + padding: 9px 14px; + font-size: 15px; + line-height: normal; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.btn-large [class^="icon-"] { + margin-top: 1px; +} +.btn-small { + padding: 5px 9px; + font-size: 11px; + line-height: 16px; +} +.btn-small [class^="icon-"] { + margin-top: -1px; +} +.btn-mini { + padding: 2px 6px; + font-size: 11px; + line-height: 14px; +} +.btn-primary, +.btn-primary:hover, +.btn-warning, +.btn-warning:hover, +.btn-danger, +.btn-danger:hover, +.btn-success, +.btn-success:hover, +.btn-info, +.btn-info:hover, +.btn-inverse, +.btn-inverse:hover { + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + color: #ffffff; +} +.btn-primary.active, +.btn-warning.active, +.btn-danger.active, +.btn-success.active, +.btn-info.active, +.btn-dark.active { + color: rgba(255, 255, 255, 0.75); +} +.btn-primary { + background-color: #006dcc; + background-image: -moz-linear-gradient(top, #0088cc, #0044cc); + background-image: -ms-linear-gradient(top, #0088cc, #0044cc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); + background-image: -o-linear-gradient(top, #0088cc, #0044cc); + background-image: linear-gradient(top, #0088cc, #0044cc); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); + border-color: #0044cc #0044cc #002a80; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-primary:hover, +.btn-primary:active, +.btn-primary.active, +.btn-primary.disabled, +.btn-primary[disabled] { + background-color: #0044cc; +} +.btn-primary:active, .btn-primary.active { + background-color: #003399 \9; +} +.btn-warning { + background-color: #faa732; + background-image: -moz-linear-gradient(top, #fbb450, #f89406); + background-image: -ms-linear-gradient(top, #fbb450, #f89406); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); + background-image: -webkit-linear-gradient(top, #fbb450, #f89406); + background-image: -o-linear-gradient(top, #fbb450, #f89406); + background-image: linear-gradient(top, #fbb450, #f89406); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0); + border-color: #f89406 #f89406 #ad6704; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-warning:hover, +.btn-warning:active, +.btn-warning.active, +.btn-warning.disabled, +.btn-warning[disabled] { + background-color: #f89406; +} +.btn-warning:active, .btn-warning.active { + background-color: #c67605 \9; +} +.btn-danger { + background-color: #da4f49; + background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -ms-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -o-linear-gradient(top, #ee5f5b, #bd362f); + background-image: linear-gradient(top, #ee5f5b, #bd362f); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0); + border-color: #bd362f #bd362f #802420; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-danger:hover, +.btn-danger:active, +.btn-danger.active, +.btn-danger.disabled, +.btn-danger[disabled] { + background-color: #bd362f; +} +.btn-danger:active, .btn-danger.active { + background-color: #942a25 \9; +} +.btn-success { + background-color: #5bb75b; + background-image: -moz-linear-gradient(top, #62c462, #51a351); + background-image: -ms-linear-gradient(top, #62c462, #51a351); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351)); + background-image: -webkit-linear-gradient(top, #62c462, #51a351); + background-image: -o-linear-gradient(top, #62c462, #51a351); + background-image: linear-gradient(top, #62c462, #51a351); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0); + border-color: #51a351 #51a351 #387038; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-success:hover, +.btn-success:active, +.btn-success.active, +.btn-success.disabled, +.btn-success[disabled] { + background-color: #51a351; +} +.btn-success:active, .btn-success.active { + background-color: #408140 \9; +} +.btn-info { + background-color: #49afcd; + background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -ms-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4)); + background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -o-linear-gradient(top, #5bc0de, #2f96b4); + background-image: linear-gradient(top, #5bc0de, #2f96b4); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0); + border-color: #2f96b4 #2f96b4 #1f6377; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-info:hover, +.btn-info:active, +.btn-info.active, +.btn-info.disabled, +.btn-info[disabled] { + background-color: #2f96b4; +} +.btn-info:active, .btn-info.active { + background-color: #24748c \9; +} +.btn-inverse { + background-color: #393939; + background-image: -moz-linear-gradient(top, #454545, #262626); + background-image: -ms-linear-gradient(top, #454545, #262626); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#454545), to(#262626)); + background-image: -webkit-linear-gradient(top, #454545, #262626); + background-image: -o-linear-gradient(top, #454545, #262626); + background-image: linear-gradient(top, #454545, #262626); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#454545', endColorstr='#262626', GradientType=0); + border-color: #262626 #262626 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-inverse:hover, +.btn-inverse:active, +.btn-inverse.active, +.btn-inverse.disabled, +.btn-inverse[disabled] { + background-color: #262626; +} +.btn-inverse:active, .btn-inverse.active { + background-color: #0c0c0c \9; +} +button.btn, input[type="submit"].btn { + *padding-top: 2px; + *padding-bottom: 2px; +} +button.btn::-moz-focus-inner, input[type="submit"].btn::-moz-focus-inner { + padding: 0; + border: 0; +} +button.btn.large, input[type="submit"].btn.large { + *padding-top: 7px; + *padding-bottom: 7px; +} +button.btn.small, input[type="submit"].btn.small { + *padding-top: 3px; + *padding-bottom: 3px; +} +.btn-group { + position: relative; + *zoom: 1; + *margin-left: .3em; +} +.btn-group:before, .btn-group:after { + display: table; + content: ""; +} +.btn-group:after { + clear: both; +} +.btn-group:first-child { + *margin-left: 0; +} +.btn-group + .btn-group { + margin-left: 5px; +} +.btn-toolbar { + margin-top: 9px; + margin-bottom: 9px; +} +.btn-toolbar .btn-group { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; +} +.btn-group .btn { + position: relative; + float: left; + margin-left: -1px; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.btn-group .btn:first-child { + margin-left: 0; + -webkit-border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; + border-top-left-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + border-bottom-left-radius: 4px; +} +.btn-group .btn:last-child, .btn-group .dropdown-toggle { + -webkit-border-top-right-radius: 4px; + -moz-border-radius-topright: 4px; + border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -moz-border-radius-bottomright: 4px; + border-bottom-right-radius: 4px; +} +.btn-group .btn.large:first-child { + margin-left: 0; + -webkit-border-top-left-radius: 6px; + -moz-border-radius-topleft: 6px; + border-top-left-radius: 6px; + -webkit-border-bottom-left-radius: 6px; + -moz-border-radius-bottomleft: 6px; + border-bottom-left-radius: 6px; +} +.btn-group .btn.large:last-child, .btn-group .large.dropdown-toggle { + -webkit-border-top-right-radius: 6px; + -moz-border-radius-topright: 6px; + border-top-right-radius: 6px; + -webkit-border-bottom-right-radius: 6px; + -moz-border-radius-bottomright: 6px; + border-bottom-right-radius: 6px; +} +.btn-group .btn:hover, +.btn-group .btn:focus, +.btn-group .btn:active, +.btn-group .btn.active { + z-index: 2; +} +.btn-group .dropdown-toggle:active, .btn-group.open .dropdown-toggle { + outline: 0; +} +.btn-group .dropdown-toggle { + padding-left: 8px; + padding-right: 8px; + -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + *padding-top: 5px; + *padding-bottom: 5px; +} +.btn-group.open { + *z-index: 1000; +} +.btn-group.open .dropdown-menu { + display: block; + margin-top: 1px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.btn-group.open .dropdown-toggle { + background-image: none; + -webkit-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); +} +.btn .caret { + margin-top: 7px; + margin-left: 0; +} +.btn:hover .caret, .open.btn-group .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.btn-primary .caret, +.btn-danger .caret, +.btn-info .caret, +.btn-success .caret, +.btn-inverse .caret { + border-top-color: #ffffff; + opacity: 0.75; + filter: alpha(opacity=75); +} +.btn-small .caret { + margin-top: 4px; +} +.alert { + padding: 8px 35px 8px 14px; + margin-bottom: 18px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + background-color: #fcf8e3; + border: 1px solid #fbeed5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.alert, .alert-heading { + color: #c09853; +} +.alert .close { + position: relative; + top: -2px; + right: -21px; + line-height: 18px; +} +.alert-success { + background-color: #dff0d8; + border-color: #d6e9c6; +} +.alert-success, .alert-success .alert-heading { + color: #468847; +} +.alert-danger, .alert-error { + background-color: #f2dede; + border-color: #eed3d7; +} +.alert-danger, +.alert-error, +.alert-danger .alert-heading, +.alert-error .alert-heading { + color: #b94a48; +} +.alert-info { + background-color: #d9edf7; + border-color: #bce8f1; +} +.alert-info, .alert-info .alert-heading { + color: #3a87ad; +} +.alert-block { + padding-top: 14px; + padding-bottom: 14px; +} +.alert-block > p, .alert-block > ul { + margin-bottom: 0; +} +.alert-block p + p { + margin-top: 5px; +} +.nav { + margin-left: 0; + margin-bottom: 18px; + list-style: none; +} +.nav > li > a { + display: block; +} +.nav > li > a:hover { + text-decoration: none; + background-color: #eeeeee; +} +.nav .nav-header { + display: block; + padding: 3px 15px; + font-size: 11px; + font-weight: bold; + line-height: 18px; + color: #999999; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + text-transform: uppercase; +} +.nav li + .nav-header { + margin-top: 9px; +} +.nav-list { + padding-left: 14px; + padding-right: 14px; + margin-bottom: 0; +} +.nav-list > li > a, .nav-list .nav-header { + margin-left: -15px; + margin-right: -15px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); +} +.nav-list > li > a { + padding: 3px 15px; +} +.nav-list .active > a, .nav-list .active > a:hover { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); + background-color: #0088cc; +} +.nav-list [class^="icon-"] { + margin-right: 2px; +} +.nav-tabs, .nav-pills { + *zoom: 1; +} +.nav-tabs:before, +.nav-pills:before, +.nav-tabs:after, +.nav-pills:after { + display: table; + content: ""; +} +.nav-tabs:after, .nav-pills:after { + clear: both; +} +.nav-tabs > li, .nav-pills > li { + float: left; +} +.nav-tabs > li > a, .nav-pills > li > a { + padding-right: 12px; + padding-left: 12px; + margin-right: 2px; + line-height: 14px; +} +.nav-tabs { + border-bottom: 1px solid #ddd; +} +.nav-tabs > li { + margin-bottom: -1px; +} +.nav-tabs > li > a { + padding-top: 9px; + padding-bottom: 9px; + border: 1px solid transparent; + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} +.nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #dddddd; +} +.nav-tabs > .active > a, .nav-tabs > .active > a:hover { + color: #555555; + background-color: #ffffff; + border: 1px solid #ddd; + border-bottom-color: transparent; + cursor: default; +} +.nav-pills > li > a { + padding-top: 8px; + padding-bottom: 8px; + margin-top: 2px; + margin-bottom: 2px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.nav-pills .active > a, .nav-pills .active > a:hover { + color: #ffffff; + background-color: #0088cc; +} +.nav-stacked > li { + float: none; +} +.nav-stacked > li > a { + margin-right: 0; +} +.nav-tabs.nav-stacked { + border-bottom: 0; +} +.nav-tabs.nav-stacked > li > a { + border: 1px solid #ddd; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.nav-tabs.nav-stacked > li:first-child > a { + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} +.nav-tabs.nav-stacked > li:last-child > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} +.nav-tabs.nav-stacked > li > a:hover { + border-color: #ddd; + z-index: 2; +} +.nav-pills.nav-stacked > li > a { + margin-bottom: 3px; +} +.nav-pills.nav-stacked > li:last-child > a { + margin-bottom: 1px; +} +.nav-tabs .dropdown-menu, .nav-pills .dropdown-menu { + margin-top: 1px; + border-width: 1px; +} +.nav-pills .dropdown-menu { + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.nav-tabs .dropdown-toggle .caret, .nav-pills .dropdown-toggle .caret { + border-top-color: #0088cc; + margin-top: 6px; +} +.nav-tabs .dropdown-toggle:hover .caret, .nav-pills .dropdown-toggle:hover .caret { + border-top-color: #005580; +} +.nav-tabs .active .dropdown-toggle .caret, .nav-pills .active .dropdown-toggle .caret { + border-top-color: #333333; +} +.nav > .dropdown.active > a:hover { + color: #000000; + cursor: pointer; +} +.nav-tabs .open .dropdown-toggle, .nav-pills .open .dropdown-toggle, .nav > .open.active > a:hover { + color: #ffffff; + background-color: #999999; + border-color: #999999; +} +.nav .open .caret, .nav .open.active .caret, .nav .open a:hover .caret { + border-top-color: #ffffff; + opacity: 1; + filter: alpha(opacity=100); +} +.tabs-stacked .open > a:hover { + border-color: #999999; +} +.tabbable { + *zoom: 1; +} +.tabbable:before, .tabbable:after { + display: table; + content: ""; +} +.tabbable:after { + clear: both; +} +.tab-content { + overflow: hidden; +} +.tabs-below .nav-tabs, .tabs-right .nav-tabs, .tabs-left .nav-tabs { + border-bottom: 0; +} +.tab-content > .tab-pane, .pill-content > .pill-pane { + display: none; +} +.tab-content > .active, .pill-content > .active { + display: block; +} +.tabs-below .nav-tabs { + border-top: 1px solid #ddd; +} +.tabs-below .nav-tabs > li { + margin-top: -1px; + margin-bottom: 0; +} +.tabs-below .nav-tabs > li > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} +.tabs-below .nav-tabs > li > a:hover { + border-bottom-color: transparent; + border-top-color: #ddd; +} +.tabs-below .nav-tabs .active > a, .tabs-below .nav-tabs .active > a:hover { + border-color: transparent #ddd #ddd #ddd; +} +.tabs-left .nav-tabs > li, .tabs-right .nav-tabs > li { + float: none; +} +.tabs-left .nav-tabs > li > a, .tabs-right .nav-tabs > li > a { + min-width: 74px; + margin-right: 0; + margin-bottom: 3px; +} +.tabs-left .nav-tabs { + float: left; + margin-right: 19px; + border-right: 1px solid #ddd; +} +.tabs-left .nav-tabs > li > a { + margin-right: -1px; + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} +.tabs-left .nav-tabs > li > a:hover { + border-color: #eeeeee #dddddd #eeeeee #eeeeee; +} +.tabs-left .nav-tabs .active > a, .tabs-left .nav-tabs .active > a:hover { + border-color: #ddd transparent #ddd #ddd; + *border-right-color: #ffffff; +} +.tabs-right .nav-tabs { + float: right; + margin-left: 19px; + border-left: 1px solid #ddd; +} +.tabs-right .nav-tabs > li > a { + margin-left: -1px; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} +.tabs-right .nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #eeeeee #dddddd; +} +.tabs-right .nav-tabs .active > a, .tabs-right .nav-tabs .active > a:hover { + border-color: #ddd #ddd #ddd transparent; + *border-left-color: #ffffff; +} +.navbar { + overflow: visible; + margin-bottom: 18px; +} +.navbar-inner { + padding-left: 20px; + padding-right: 20px; + background-color: #2c2c2c; + background-image: -moz-linear-gradient(top, #333333, #222222); + background-image: -ms-linear-gradient(top, #333333, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); + background-image: -webkit-linear-gradient(top, #333333, #222222); + background-image: -o-linear-gradient(top, #333333, #222222); + background-image: linear-gradient(top, #333333, #222222); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); +} +.btn-navbar { + display: none; + float: right; + padding: 7px 10px; + margin-left: 5px; + margin-right: 5px; + background-color: #2c2c2c; + background-image: -moz-linear-gradient(top, #333333, #222222); + background-image: -ms-linear-gradient(top, #333333, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); + background-image: -webkit-linear-gradient(top, #333333, #222222); + background-image: -o-linear-gradient(top, #333333, #222222); + background-image: linear-gradient(top, #333333, #222222); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); + border-color: #222222 #222222 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); +} +.btn-navbar:hover, +.btn-navbar:active, +.btn-navbar.active, +.btn-navbar.disabled, +.btn-navbar[disabled] { + background-color: #222222; +} +.btn-navbar:active, .btn-navbar.active { + background-color: #080808 \9; +} +.btn-navbar .icon-bar { + display: block; + width: 18px; + height: 2px; + background-color: #f5f5f5; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; + -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); +} +.btn-navbar .icon-bar + .icon-bar { + margin-top: 3px; +} +.nav-collapse.collapse { + height: auto; +} +.navbar .brand:hover { + text-decoration: none; +} +.navbar .brand { + float: left; + display: block; + padding: 8px 20px 12px; + margin-left: -20px; + font-size: 20px; + font-weight: 200; + line-height: 1; + color: #ffffff; +} +.navbar .navbar-text { + margin-bottom: 0; + line-height: 40px; + color: #999999; +} +.navbar .navbar-text a:hover { + color: #ffffff; + background-color: transparent; +} +.navbar .btn, .navbar .btn-group { + margin-top: 5px; +} +.navbar .btn-group .btn { + margin-top: 0; +} +.navbar-form { + margin-bottom: 0; + *zoom: 1; +} +.navbar-form:before, .navbar-form:after { + display: table; + content: ""; +} +.navbar-form:after { + clear: both; +} +.navbar-form input, .navbar-form select { + display: inline-block; + margin-top: 5px; + margin-bottom: 0; +} +.navbar-form .radio, .navbar-form .checkbox { + margin-top: 5px; +} +.navbar-form input[type="image"], .navbar-form input[type="checkbox"], .navbar-form input[type="radio"] { + margin-top: 3px; +} +.navbar-form .input-append, .navbar-form .input-prepend { + margin-top: 6px; + white-space: nowrap; +} +.navbar-form .input-append input, .navbar-form .input-prepend input { + margin-top: 0; +} +.navbar-search { + position: relative; + float: left; + margin-top: 6px; + margin-bottom: 0; +} +.navbar-search .search-query { + padding: 4px 9px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + font-weight: normal; + line-height: 1; + color: #ffffff; + color: rgba(255, 255, 255, 0.75); + background: #666; + background: rgba(255, 255, 255, 0.3); + border: 1px solid #111; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + -webkit-transition: none; + -moz-transition: none; + -ms-transition: none; + -o-transition: none; + transition: none; +} +.navbar-search .search-query :-moz-placeholder { + color: #eeeeee; +} +.navbar-search .search-query::-webkit-input-placeholder { + color: #eeeeee; +} +.navbar-search .search-query:hover { + color: #ffffff; + background-color: #999999; + background-color: rgba(255, 255, 255, 0.5); +} +.navbar-search .search-query:focus, .navbar-search .search-query.focused { + padding: 5px 10px; + color: #333333; + text-shadow: 0 1px 0 #ffffff; + background-color: #ffffff; + border: 0; + -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + outline: 0; +} +.navbar-fixed-top { + position: fixed; + top: 0; + right: 0; + left: 0; + z-index: 1030; +} +.navbar-fixed-top .navbar-inner { + padding-left: 0; + padding-right: 0; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.navbar .nav { + position: relative; + left: 0; + display: block; + float: left; + margin: 0 10px 0 0; +} +.navbar .nav.pull-right { + float: right; +} +.navbar .nav > li { + display: block; + float: left; +} +.navbar .nav > li > a { + float: none; + padding: 10px 10px 11px; + line-height: 19px; + color: #999999; + text-decoration: none; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.navbar .nav > li > a:hover { + background-color: transparent; + color: #ffffff; + text-decoration: none; +} +.navbar .nav .active > a, .navbar .nav .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #222222; +} +.navbar .divider-vertical { + height: 40px; + width: 1px; + margin: 0 9px; + overflow: hidden; + background-color: #222222; + border-right: 1px solid #333333; +} +.navbar .nav.pull-right { + margin-left: 10px; + margin-right: 0; +} +.navbar .dropdown-menu { + margin-top: 1px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.navbar .dropdown-menu:before { + content: ''; + display: inline-block; + border-left: 7px solid transparent; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-bottom-color: rgba(0, 0, 0, 0.2); + position: absolute; + top: -7px; + left: 9px; +} +.navbar .dropdown-menu:after { + content: ''; + display: inline-block; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid #ffffff; + position: absolute; + top: -6px; + left: 10px; +} +.navbar .nav .dropdown-toggle .caret, .navbar .nav .open.dropdown .caret { + border-top-color: #ffffff; +} +.navbar .nav .active .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.navbar .nav .open > .dropdown-toggle, .navbar .nav .active > .dropdown-toggle, .navbar .nav .open.active > .dropdown-toggle { + background-color: transparent; +} +.navbar .nav .active > .dropdown-toggle:hover { + color: #ffffff; +} +.navbar .nav.pull-right .dropdown-menu { + left: auto; + right: 0; +} +.navbar .nav.pull-right .dropdown-menu:before { + left: auto; + right: 12px; +} +.navbar .nav.pull-right .dropdown-menu:after { + left: auto; + right: 13px; +} +.breadcrumb { + padding: 7px 14px; + margin: 0 0 18px; + background-color: #fbfbfb; + background-image: -moz-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -ms-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5)); + background-image: -webkit-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -o-linear-gradient(top, #ffffff, #f5f5f5); + background-image: linear-gradient(top, #ffffff, #f5f5f5); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0); + border: 1px solid #ddd; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; +} +.breadcrumb li { + display: inline-block; + text-shadow: 0 1px 0 #ffffff; +} +.breadcrumb .divider { + padding: 0 5px; + color: #999999; +} +.breadcrumb .active a { + color: #333333; +} +.pagination { + height: 36px; + margin: 18px 0; +} +.pagination ul { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; + margin-left: 0; + margin-bottom: 0; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); +} +.pagination li { + display: inline; +} +.pagination a { + float: left; + padding: 0 14px; + line-height: 34px; + text-decoration: none; + border: 1px solid #ddd; + border-left-width: 0; +} +.pagination a:hover, .pagination .active a { + background-color: #f5f5f5; +} +.pagination .active a { + color: #999999; + cursor: default; +} +.pagination .disabled a, .pagination .disabled a:hover { + color: #999999; + background-color: transparent; + cursor: default; +} +.pagination li:first-child a { + border-left-width: 1px; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.pagination li:last-child a { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.pagination-centered { + text-align: center; +} +.pagination-right { + text-align: right; +} +.pager { + margin-left: 0; + margin-bottom: 18px; + list-style: none; + text-align: center; + *zoom: 1; +} +.pager:before, .pager:after { + display: table; + content: ""; +} +.pager:after { + clear: both; +} +.pager li { + display: inline; +} +.pager a { + display: inline-block; + padding: 5px 14px; + background-color: #fff; + border: 1px solid #ddd; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} +.pager a:hover { + text-decoration: none; + background-color: #f5f5f5; +} +.pager .next a { + float: right; +} +.pager .previous a { + float: left; +} +.modal-open .dropdown-menu { + z-index: 2050; +} +.modal-open .dropdown.open { + *z-index: 2050; +} +.modal-open .popover { + z-index: 2060; +} +.modal-open .tooltip { + z-index: 2070; +} +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + background-color: #000000; +} +.modal-backdrop.fade { + opacity: 0; +} +.modal-backdrop, .modal-backdrop.fade.in { + opacity: 0.8; + filter: alpha(opacity=80); +} +.modal { + position: fixed; + top: 50%; + left: 50%; + z-index: 1050; + max-height: 500px; + overflow: auto; + width: 560px; + margin: -250px 0 0 -280px; + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + /* IE6-7 */ + + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.wide-modal { + position: fixed; + top: 5%; + left: 5%; + z-index: 1050; + max-height: 90%; + overflow: auto; + width: 90%; + /*margin: -50px 0 0 -80px;*/ + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + /* IE6-7 */ + + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.modal.fade { + -webkit-transition: opacity .3s linear, top .3s ease-out; + -moz-transition: opacity .3s linear, top .3s ease-out; + -ms-transition: opacity .3s linear, top .3s ease-out; + -o-transition: opacity .3s linear, top .3s ease-out; + transition: opacity .3s linear, top .3s ease-out; + top: -25%; +} +.modal.fade.in { + top: 50%; +} +.modal-header { + padding: 9px 15px; + border-bottom: 1px solid #eee; +} +.modal-header .close { + margin-top: 2px; +} +.modal-body { + padding: 15px; +} +.modal-body .modal-form { + margin-bottom: 0; +} +.modal-footer { + padding: 14px 15px 15px; + margin-bottom: 0; + background-color: #f5f5f5; + border-top: 1px solid #ddd; + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; + *zoom: 1; +} +.modal-footer:before, .modal-footer:after { + display: table; + content: ""; +} +.modal-footer:after { + clear: both; +} +.modal-footer .btn { + float: right; + margin-left: 5px; + margin-bottom: 0; +} +.tooltip { + position: absolute; + z-index: 1020; + display: block; + visibility: visible; + padding: 5px; + font-size: 11px; + opacity: 0; + filter: alpha(opacity=0); +} +.tooltip.in { + opacity: 0.8; + filter: alpha(opacity=80); +} +.tooltip.top { + margin-top: -2px; +} +.tooltip.right { + margin-left: 2px; +} +.tooltip.bottom { + margin-top: 2px; +} +.tooltip.left { + margin-left: -2px; +} +.tooltip.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid #000000; +} +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #000000; +} +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-bottom: 5px solid #000000; +} +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-right: 5px solid #000000; +} +.tooltip-inner { + max-width: 200px; + padding: 3px 8px; + color: #ffffff; + text-align: center; + text-decoration: none; + background-color: #000000; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; +} +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1010; + display: none; + padding: 5px; +} +.popover.top { + margin-top: -5px; +} +.popover.right { + margin-left: 5px; +} +.popover.bottom { + margin-top: 5px; +} +.popover.left { + margin-left: -5px; +} +.popover.top .arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid #000000; +} +.popover.right .arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-right: 5px solid #000000; +} +.popover.bottom .arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-bottom: 5px solid #000000; +} +.popover.left .arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #000000; +} +.popover .arrow { + position: absolute; + width: 0; + height: 0; +} +.popover-inner { + padding: 3px; + width: 280px; + overflow: hidden; + background: #000000; + background: rgba(0, 0, 0, 0.8); + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); +} +.popover-title { + padding: 9px 15px; + line-height: 1; + background-color: #f5f5f5; + border-bottom: 1px solid #eee; + -webkit-border-radius: 3px 3px 0 0; + -moz-border-radius: 3px 3px 0 0; + border-radius: 3px 3px 0 0; +} +.popover-content { + padding: 14px; + background-color: #ffffff; + -webkit-border-radius: 0 0 3px 3px; + -moz-border-radius: 0 0 3px 3px; + border-radius: 0 0 3px 3px; + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.popover-content p, .popover-content ul, .popover-content ol { + margin-bottom: 0; +} +.thumbnails { + margin-left: -20px; + list-style: none; + *zoom: 1; +} +.thumbnails:before, .thumbnails:after { + display: table; + content: ""; +} +.thumbnails:after { + clear: both; +} +.thumbnails > li { + float: left; + margin: 0 0 18px 20px; +} +.thumbnail { + display: block; + padding: 4px; + line-height: 1; + border: 1px solid #ddd; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); +} +a.thumbnail:hover { + border-color: #0088cc; + -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); +} +.thumbnail > img { + display: block; + max-width: 100%; + margin-left: auto; + margin-right: auto; +} +.thumbnail .caption { + padding: 9px; +} +.label { + padding: 2px 4px 3px; + font-size: 11.049999999999999px; + font-weight: bold; + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #999999; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.label:hover { + color: #ffffff; + text-decoration: none; +} +.label-important { + background-color: #b94a48; +} +.label-important:hover { + background-color: #953b39; +} +.label-warning { + background-color: #f89406; +} +.label-warning:hover { + background-color: #c67605; +} +.label-success { + background-color: #468847; +} +.label-success:hover { + background-color: #356635; +} +.label-info { + background-color: #3a87ad; +} +.label-info:hover { + background-color: #2d6987; +} +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +@-moz-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +@keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +.progress { + overflow: hidden; + height: 18px; + margin-bottom: 18px; + background-color: #f7f7f7; + background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -ms-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9)); + background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: linear-gradient(top, #f5f5f5, #f9f9f9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0); + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.progress .bar { + width: 0%; + height: 18px; + color: #ffffff; + font-size: 12px; + text-align: center; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #0e90d2; + background-image: -moz-linear-gradient(top, #149bdf, #0480be); + background-image: -ms-linear-gradient(top, #149bdf, #0480be); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be)); + background-image: -webkit-linear-gradient(top, #149bdf, #0480be); + background-image: -o-linear-gradient(top, #149bdf, #0480be); + background-image: linear-gradient(top, #149bdf, #0480be); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0); + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition: width 0.6s ease; + -moz-transition: width 0.6s ease; + -ms-transition: width 0.6s ease; + -o-transition: width 0.6s ease; + transition: width 0.6s ease; +} +.progress-striped .bar { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + -webkit-background-size: 40px 40px; + -moz-background-size: 40px 40px; + -o-background-size: 40px 40px; + background-size: 40px 40px; +} +.progress.active .bar { + -webkit-animation: progress-bar-stripes 2s linear infinite; + -moz-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} +.progress-danger .bar { + background-color: #dd514c; + background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -o-linear-gradient(top, #ee5f5b, #c43c35); + background-image: linear-gradient(top, #ee5f5b, #c43c35); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0); +} +.progress-danger.progress-striped .bar { + background-color: #ee5f5b; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-success .bar { + background-color: #5eb95e; + background-image: -moz-linear-gradient(top, #62c462, #57a957); + background-image: -ms-linear-gradient(top, #62c462, #57a957); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957)); + background-image: -webkit-linear-gradient(top, #62c462, #57a957); + background-image: -o-linear-gradient(top, #62c462, #57a957); + background-image: linear-gradient(top, #62c462, #57a957); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0); +} +.progress-success.progress-striped .bar { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-info .bar { + background-color: #4bb1cf; + background-image: -moz-linear-gradient(top, #5bc0de, #339bb9); + background-image: -ms-linear-gradient(top, #5bc0de, #339bb9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9)); + background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9); + background-image: -o-linear-gradient(top, #5bc0de, #339bb9); + background-image: linear-gradient(top, #5bc0de, #339bb9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0); +} +.progress-info.progress-striped .bar { + background-color: #5bc0de; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.accordion { + margin-bottom: 18px; +} +.accordion-group { + margin-bottom: 2px; + border: 1px solid #e5e5e5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.accordion-heading { + border-bottom: 0; +} +.accordion-heading .accordion-toggle { + display: block; + padding: 8px 15px; +} +.accordion-inner { + padding: 9px 15px; + border-top: 1px solid #e5e5e5; +} +.carousel { + position: relative; + margin-bottom: 18px; + line-height: 1; +} +.carousel-inner { + overflow: hidden; + width: 100%; + position: relative; +} +.carousel .item { + display: none; + position: relative; + -webkit-transition: 0.6s ease-in-out left; + -moz-transition: 0.6s ease-in-out left; + -ms-transition: 0.6s ease-in-out left; + -o-transition: 0.6s ease-in-out left; + transition: 0.6s ease-in-out left; +} +.carousel .item > img { + display: block; + line-height: 1; +} +.carousel .active, .carousel .next, .carousel .prev { + display: block; +} +.carousel .active { + left: 0; +} +.carousel .next, .carousel .prev { + position: absolute; + top: 0; + width: 100%; +} +.carousel .next { + left: 100%; +} +.carousel .prev { + left: -100%; +} +.carousel .next.left, .carousel .prev.right { + left: 0; +} +.carousel .active.left { + left: -100%; +} +.carousel .active.right { + left: 100%; +} +.carousel-control { + position: absolute; + top: 40%; + left: 15px; + width: 40px; + height: 40px; + margin-top: -20px; + font-size: 60px; + font-weight: 100; + line-height: 30px; + color: #ffffff; + text-align: center; + background: #222222; + border: 3px solid #ffffff; + -webkit-border-radius: 23px; + -moz-border-radius: 23px; + border-radius: 23px; + opacity: 0.5; + filter: alpha(opacity=50); +} +.carousel-control.right { + left: auto; + right: 15px; +} +.carousel-control:hover { + color: #ffffff; + text-decoration: none; + opacity: 0.9; + filter: alpha(opacity=90); +} +.carousel-caption { + position: absolute; + left: 0; + right: 0; + bottom: 0; + padding: 10px 15px 5px; + background: #333333; + background: rgba(0, 0, 0, 0.75); +} +.carousel-caption h4, .carousel-caption p { + color: #ffffff; +} +.hero-unit { + padding: 60px; + margin-bottom: 30px; + background-color: #f5f5f5; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} +.hero-unit h1 { + margin-bottom: 0; + font-size: 60px; + line-height: 1; + letter-spacing: -1px; +} +.hero-unit p { + font-size: 18px; + font-weight: 200; + line-height: 27px; +} +.pull-right { + float: right; +} +.pull-left { + float: left; +} +.hide { + display: none; +} +.show { + display: block; +} +.invisible { + visibility: hidden; +} diff --git a/src/nl/astraeus/jdbc/web/resources/images/loading.gif b/src/nl/astraeus/jdbc/web/resources/images/loading.gif new file mode 100644 index 0000000..21c7e74 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/images/loading.gif Binary files differ diff --git a/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png b/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png new file mode 100644 index 0000000..92d4445 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png Binary files differ diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-alert.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-alert.js new file mode 100644 index 0000000..2242ddd --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-alert.js @@ -0,0 +1,94 @@ +/* ========================================================== + * bootstrap-alert.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#alerts + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function( $ ){ + + "use strict" + + /* ALERT CLASS DEFINITION + * ====================== */ + + var dismiss = '[data-dismiss="alert"]' + , Alert = function ( el ) { + $(el).on('click', dismiss, this.close) + } + + Alert.prototype = { + + constructor: Alert + + , close: function ( e ) { + var $this = $(this) + , selector = $this.attr('data-target') + , $parent + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = $(selector) + $parent.trigger('close') + + e && e.preventDefault() + + $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent()) + + $parent + .trigger('close') + .removeClass('in') + + function removeElement() { + $parent + .trigger('closed') + .remove() + } + + $.support.transition && $parent.hasClass('fade') ? + $parent.on($.support.transition.end, removeElement) : + removeElement() + } + + } + + + /* ALERT PLUGIN DEFINITION + * ======================= */ + + $.fn.alert = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('alert') + if (!data) $this.data('alert', (data = new Alert(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.alert.Constructor = Alert + + + /* ALERT DATA-API + * ============== */ + + $(function () { + $('body').on('click.alert.data-api', dismiss, Alert.prototype.close) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-button.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-button.js new file mode 100644 index 0000000..0238ca3 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-button.js @@ -0,0 +1,100 @@ +/* ============================================================ + * bootstrap-button.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#buttons + * ============================================================ + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + +!function( $ ){ + + "use strict" + + /* BUTTON PUBLIC CLASS DEFINITION + * ============================== */ + + var Button = function ( element, options ) { + this.$element = $(element) + this.options = $.extend({}, $.fn.button.defaults, options) + } + + Button.prototype = { + + constructor: Button + + , setState: function ( state ) { + var d = 'disabled' + , $el = this.$element + , data = $el.data() + , val = $el.is('input') ? 'val' : 'html' + + state = state + 'Text' + data.resetText || $el.data('resetText', $el[val]()) + + $el[val](data[state] || this.options[state]) + + // push to event loop to allow forms to submit + setTimeout(function () { + state == 'loadingText' ? + $el.addClass(d).attr(d, d) : + $el.removeClass(d).removeAttr(d) + }, 0) + } + + , toggle: function () { + var $parent = this.$element.parent('[data-toggle="buttons-radio"]') + + $parent && $parent + .find('.active') + .removeClass('active') + + this.$element.toggleClass('active') + } + + } + + + /* BUTTON PLUGIN DEFINITION + * ======================== */ + + $.fn.button = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('button') + , options = typeof option == 'object' && option + if (!data) $this.data('button', (data = new Button(this, options))) + if (option == 'toggle') data.toggle() + else if (option) data.setState(option) + }) + } + + $.fn.button.defaults = { + loadingText: 'loading...' + } + + $.fn.button.Constructor = Button + + + /* BUTTON DATA-API + * =============== */ + + $(function () { + $('body').on('click.button.data-api', '[data-toggle^=button]', function ( e ) { + var $btn = $(e.target) + if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') + $btn.button('toggle') + }) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-carousel.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-carousel.js new file mode 100644 index 0000000..810256e --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-carousel.js @@ -0,0 +1,157 @@ +/* ========================================================== + * bootstrap-carousel.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#carousel + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function( $ ){ + + "use strict" + + /* CAROUSEL CLASS DEFINITION + * ========================= */ + + var Carousel = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, $.fn.carousel.defaults, options) + this.options.slide && this.slide(this.options.slide) + } + + Carousel.prototype = { + + cycle: function () { + this.interval = setInterval($.proxy(this.next, this), this.options.interval) + return this + } + + , to: function (pos) { + var $active = this.$element.find('.active') + , children = $active.parent().children() + , activePos = children.index($active) + , that = this + + if (pos > (children.length - 1) || pos < 0) return + + if (this.sliding) { + return this.$element.one('slid', function () { + that.to(pos) + }) + } + + if (activePos == pos) { + return this.pause().cycle() + } + + return this.slide(pos > activePos ? 'next' : 'prev', $(children[pos])) + } + + , pause: function () { + clearInterval(this.interval) + this.interval = null + return this + } + + , next: function () { + if (this.sliding) return + return this.slide('next') + } + + , prev: function () { + if (this.sliding) return + return this.slide('prev') + } + + , slide: function (type, next) { + var $active = this.$element.find('.active') + , $next = next || $active[type]() + , isCycling = this.interval + , direction = type == 'next' ? 'left' : 'right' + , fallback = type == 'next' ? 'first' : 'last' + , that = this + + if (!$next.length) return + + this.sliding = true + + isCycling && this.pause() + + $next = $next.length ? $next : this.$element.find('.item')[fallback]() + + if (!$.support.transition && this.$element.hasClass('slide')) { + this.$element.trigger('slide') + $active.removeClass('active') + $next.addClass('active') + this.sliding = false + this.$element.trigger('slid') + } else { + $next.addClass(type) + $next[0].offsetWidth // force reflow + $active.addClass(direction) + $next.addClass(direction) + this.$element.trigger('slide') + this.$element.one($.support.transition.end, function () { + $next.removeClass([type, direction].join(' ')).addClass('active') + $active.removeClass(['active', direction].join(' ')) + that.sliding = false + setTimeout(function () { that.$element.trigger('slid') }, 0) + }) + } + + isCycling && this.cycle() + + return this + } + + } + + + /* CAROUSEL PLUGIN DEFINITION + * ========================== */ + + $.fn.carousel = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('carousel') + , options = typeof option == 'object' && option + if (!data) $this.data('carousel', (data = new Carousel(this, options))) + if (typeof option == 'number') data.to(option) + else if (typeof option == 'string' || (option = options.slide)) data[option]() + else data.cycle() + }) + } + + $.fn.carousel.defaults = { + interval: 5000 + } + + $.fn.carousel.Constructor = Carousel + + + /* CAROUSEL DATA-API + * ================= */ + + $(function () { + $('body').on('click.carousel.data-api', '[data-slide]', function ( e ) { + var $this = $(this), href + , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 + , options = !$target.data('modal') && $.extend({}, $target.data(), $this.data()) + $target.carousel(options) + e.preventDefault() + }) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-collapse.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-collapse.js new file mode 100644 index 0000000..d195efc --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-collapse.js @@ -0,0 +1,136 @@ +/* ============================================================= + * bootstrap-collapse.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#collapse + * ============================================================= + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + +!function( $ ){ + + "use strict" + + var Collapse = function ( element, options ) { + this.$element = $(element) + this.options = $.extend({}, $.fn.collapse.defaults, options) + + if (this.options["parent"]) { + this.$parent = $(this.options["parent"]) + } + + this.options.toggle && this.toggle() + } + + Collapse.prototype = { + + constructor: Collapse + + , dimension: function () { + var hasWidth = this.$element.hasClass('width') + return hasWidth ? 'width' : 'height' + } + + , show: function () { + var dimension = this.dimension() + , scroll = $.camelCase(['scroll', dimension].join('-')) + , actives = this.$parent && this.$parent.find('.in') + , hasData + + if (actives && actives.length) { + hasData = actives.data('collapse') + actives.collapse('hide') + hasData || actives.data('collapse', null) + } + + this.$element[dimension](0) + this.transition('addClass', 'show', 'shown') + this.$element[dimension](this.$element[0][scroll]) + + } + + , hide: function () { + var dimension = this.dimension() + this.reset(this.$element[dimension]()) + this.transition('removeClass', 'hide', 'hidden') + this.$element[dimension](0) + } + + , reset: function ( size ) { + var dimension = this.dimension() + + this.$element + .removeClass('collapse') + [dimension](size || 'auto') + [0].offsetWidth + + this.$element.addClass('collapse') + } + + , transition: function ( method, startEvent, completeEvent ) { + var that = this + , complete = function () { + if (startEvent == 'show') that.reset() + that.$element.trigger(completeEvent) + } + + this.$element + .trigger(startEvent) + [method]('in') + + $.support.transition && this.$element.hasClass('collapse') ? + this.$element.one($.support.transition.end, complete) : + complete() + } + + , toggle: function () { + this[this.$element.hasClass('in') ? 'hide' : 'show']() + } + + } + + /* COLLAPSIBLE PLUGIN DEFINITION + * ============================== */ + + $.fn.collapse = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('collapse') + , options = typeof option == 'object' && option + if (!data) $this.data('collapse', (data = new Collapse(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.collapse.defaults = { + toggle: true + } + + $.fn.collapse.Constructor = Collapse + + + /* COLLAPSIBLE DATA-API + * ==================== */ + + $(function () { + $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function ( e ) { + var $this = $(this), href + , target = $this.attr('data-target') + || e.preventDefault() + || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 + , option = $(target).data('collapse') ? 'toggle' : $this.data() + $(target).collapse(option) + }) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-dropdown.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-dropdown.js new file mode 100644 index 0000000..f1f6c33 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-dropdown.js @@ -0,0 +1,92 @@ +/* ============================================================ + * bootstrap-dropdown.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#dropdowns + * ============================================================ + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + + +!function( $ ){ + + "use strict" + + /* DROPDOWN CLASS DEFINITION + * ========================= */ + + var toggle = '[data-toggle="dropdown"]' + , Dropdown = function ( element ) { + var $el = $(element).on('click.dropdown.data-api', this.toggle) + $('html').on('click.dropdown.data-api', function () { + $el.parent().removeClass('open') + }) + } + + Dropdown.prototype = { + + constructor: Dropdown + + , toggle: function ( e ) { + var $this = $(this) + , selector = $this.attr('data-target') + , $parent + , isActive + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = $(selector) + $parent.length || ($parent = $this.parent()) + + isActive = $parent.hasClass('open') + + clearMenus() + !isActive && $parent.toggleClass('open') + + return false + } + + } + + function clearMenus() { + $(toggle).parent().removeClass('open') + } + + + /* DROPDOWN PLUGIN DEFINITION + * ========================== */ + + $.fn.dropdown = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('dropdown') + if (!data) $this.data('dropdown', (data = new Dropdown(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.dropdown.Constructor = Dropdown + + + /* APPLY TO STANDARD DROPDOWN ELEMENTS + * =================================== */ + + $(function () { + $('html').on('click.dropdown.data-api', clearMenus) + $('body').on('click.dropdown.data-api', toggle, Dropdown.prototype.toggle) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-modal.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-modal.js new file mode 100644 index 0000000..bceb303 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-modal.js @@ -0,0 +1,210 @@ +/* ========================================================= + * bootstrap-modal.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#modals + * ========================================================= + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================= */ + + +!function( $ ){ + + "use strict" + + /* MODAL CLASS DEFINITION + * ====================== */ + + var Modal = function ( content, options ) { + this.options = options + this.$element = $(content) + .delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this)) + } + + Modal.prototype = { + + constructor: Modal + + , toggle: function () { + return this[!this.isShown ? 'show' : 'hide']() + } + + , show: function () { + var that = this + + if (this.isShown) return + + $('body').addClass('modal-open') + + this.isShown = true + this.$element.trigger('show') + + escape.call(this) + backdrop.call(this, function () { + var transition = $.support.transition && that.$element.hasClass('fade') + + !that.$element.parent().length && that.$element.appendTo(document.body) //don't move modals dom position + + that.$element + .show() + + if (transition) { + that.$element[0].offsetWidth // force reflow + } + + that.$element.addClass('in') + + transition ? + that.$element.one($.support.transition.end, function () { that.$element.trigger('shown') }) : + that.$element.trigger('shown') + + }) + } + + , hide: function ( e ) { + e && e.preventDefault() + + if (!this.isShown) return + + var that = this + this.isShown = false + + $('body').removeClass('modal-open') + + escape.call(this) + + this.$element + .trigger('hide') + .removeClass('in') + + $.support.transition && this.$element.hasClass('fade') ? + hideWithTransition.call(this) : + hideModal.call(this) + } + + } + + + /* MODAL PRIVATE METHODS + * ===================== */ + + function hideWithTransition() { + var that = this + , timeout = setTimeout(function () { + that.$element.off($.support.transition.end) + hideModal.call(that) + }, 500) + + this.$element.one($.support.transition.end, function () { + clearTimeout(timeout) + hideModal.call(that) + }) + } + + function hideModal( that ) { + this.$element + .hide() + .trigger('hidden') + + backdrop.call(this) + } + + function backdrop( callback ) { + var that = this + , animate = this.$element.hasClass('fade') ? 'fade' : '' + + if (this.isShown && this.options.backdrop) { + var doAnimate = $.support.transition && animate + + this.$backdrop = $(' + + + + + \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/head.html b/src/nl/astraeus/jdbc/web/head.html new file mode 100644 index 0000000..0f8f6a3 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/head.html @@ -0,0 +1,96 @@ + + + + + + + Simple JDBC Statistics + + + + + + + + + + + + + + + + + + + +
+
+ +
+ diff --git a/src/nl/astraeus/jdbc/web/page/Menu.html b/src/nl/astraeus/jdbc/web/page/Menu.html new file mode 100644 index 0000000..505c7c2 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.html @@ -0,0 +1,42 @@ + diff --git a/src/nl/astraeus/jdbc/web/page/Menu.java b/src/nl/astraeus/jdbc/web/page/Menu.java new file mode 100644 index 0000000..f0a349a --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.java @@ -0,0 +1,27 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 9:07 PM + */ +public class Menu extends TemplatePage { + + @Override + public Page processRequest(HttpServletRequest request) { + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + result.put("user", request.getSession().getAttribute("user")); + + return result; + } +} diff --git a/src/nl/astraeus/jdbc/web/page/Page.java b/src/nl/astraeus/jdbc/web/page/Page.java new file mode 100644 index 0000000..9d526d6 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Page.java @@ -0,0 +1,17 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:20 PM + */ +public abstract class Page { + + public abstract Page processRequest(HttpServletRequest request); + public abstract Map defineModel(HttpServletRequest request); + public abstract String render(HttpServletRequest request); + +} diff --git a/src/nl/astraeus/jdbc/web/page/QueryOverview.html b/src/nl/astraeus/jdbc/web/page/QueryOverview.html new file mode 100644 index 0000000..64a88fb --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/QueryOverview.html @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + {foreach(queries as q)} + + + + + + + {eachend} + +
Total timeAvg. time# CallsSql
{q.total}{q.nano}{q.count}{q.sql}
diff --git a/src/nl/astraeus/jdbc/web/page/QueryOverview.java b/src/nl/astraeus/jdbc/web/page/QueryOverview.java new file mode 100644 index 0000000..02982f1 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/QueryOverview.java @@ -0,0 +1,92 @@ +package nl.astraeus.jdbc.web.page; + +import nl.astraeus.jdbc.JdbcLogger; + +import javax.servlet.http.HttpServletRequest; +import java.util.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 9:16 PM + */ +public class QueryOverview extends TemplatePage { + + boolean sortTotalCalls = true; + boolean sortAvgTime = false; + boolean sortTotalTime = false; + + @Override + public Page processRequest(HttpServletRequest request) { + if ("sortTotalCalls".equals(request.getParameter("action"))) { + sortTotalCalls = true; + sortAvgTime = false; + sortTotalTime = false; + } else if ("sortAvgTime".equals(request.getParameter("action"))) { + sortTotalCalls = false; + sortAvgTime = true; + sortTotalTime = false; + } else if ("sortTotalTime".equals(request.getParameter("action"))) { + sortTotalCalls = false; + sortAvgTime = false; + sortTotalTime = true; + } + + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + List entries = new ArrayList(JdbcLogger.get().getEntries()); + + if (sortTotalCalls) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + return o2.count - o1.count; + } + }); + } else if (sortAvgTime) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + long n1 = o1.nano / o1.count; + long n2 = o2.nano / o2.count; + + if (n2 > n1) { + return 1; + } else if (n2 < n1) { + return -1; + } else { + return 0; + } + } + }); + } else if (sortTotalTime) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + if (o2.nano > o1.nano) { + return 1; + } else if (o2.nano < o1.nano) { + return -1; + } else { + return 0; + } + } + }); + } + + result.put("queries", entries); + result.put("count", entries.size()); + + result.put("sortTotalCalls", sortTotalCalls); + result.put("sortAvgTime", sortAvgTime); + result.put("sortTotalTime", sortTotalTime); + + return result; + } + +} diff --git a/src/nl/astraeus/jdbc/web/page/TemplatePage.java b/src/nl/astraeus/jdbc/web/page/TemplatePage.java new file mode 100644 index 0000000..33e2641 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/TemplatePage.java @@ -0,0 +1,58 @@ +package nl.astraeus.jdbc.web.page; + +import nl.astraeus.template.EscapeMode; +import nl.astraeus.template.SimpleTemplate; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:20 PM + */ +public abstract class TemplatePage extends Page { + + private SimpleTemplate template; + + protected TemplatePage() { + template = getSimpleTemplate(this.getClass()); + } + + public String render(HttpServletRequest request) { + return template.render(defineModel(request)); + } + + private static Map templateCache = new HashMap(); + + public synchronized static SimpleTemplate getSimpleTemplate(Class cls) { + SimpleTemplate result = templateCache.get(cls); + + if (result == null) { + InputStream in = null; + + try { + in = cls.getResourceAsStream(cls.getSimpleName() + ".html"); + + result = SimpleTemplate.readTemplate('{','}', EscapeMode.HTML, in); + + templateCache.put(cls, result); + } catch (IOException e) { + throw new IllegalStateException(e); + } finally { + if (in != null) { + try { + in.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + + return result; + } +} diff --git a/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css b/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css new file mode 100644 index 0000000..0e0056f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css @@ -0,0 +1,581 @@ +/*! + * Bootstrap Responsive v2.0.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ +.clearfix { + *zoom: 1; +} +.clearfix:before, .clearfix:after { + display: table; + content: ""; +} +.clearfix:after { + clear: both; +} +.hidden { + display: none; + visibility: hidden; +} +@media (max-width: 480px) { + .nav-collapse { + -webkit-transform: translate3d(0, 0, 0); + } + .page-header h1 small { + display: block; + line-height: 18px; + } + input[class*="span"], + select[class*="span"], + textarea[class*="span"], + .uneditable-input { + display: block; + width: 100%; + min-height: 28px; + /* Make inputs at least the height of their button counterpart */ + + /* Makes inputs behave like true block-level elements */ + + -webkit-box-sizing: border-box; + /* Older Webkit */ + + -moz-box-sizing: border-box; + /* Older FF */ + + -ms-box-sizing: border-box; + /* IE8 */ + + box-sizing: border-box; + /* CSS3 spec*/ + + } + .input-prepend input[class*="span"], .input-append input[class*="span"] { + width: auto; + } + input[type="checkbox"], input[type="radio"] { + border: 1px solid #ccc; + } + .form-horizontal .control-group > label { + float: none; + width: auto; + padding-top: 0; + text-align: left; + } + .form-horizontal .controls { + margin-left: 0; + } + .form-horizontal .control-list { + padding-top: 0; + } + .form-horizontal .form-actions { + padding-left: 10px; + padding-right: 10px; + } + .modal { + position: absolute; + top: 10px; + left: 10px; + right: 10px; + width: auto; + margin: 0; + } + .modal.fade.in { + top: auto; + } + .modal-header .close { + padding: 10px; + margin: -10px; + } + .carousel-caption { + position: static; + } +} +@media (max-width: 767px) { + .container { + width: auto; + padding: 0 20px; + } + .row-fluid { + width: 100%; + } + .row { + margin-left: 0; + } + .row > [class*="span"], .row-fluid > [class*="span"] { + float: none; + display: block; + width: auto; + margin: 0; + } +} +@media (min-width: 768px) and (max-width: 979px) { + .row { + margin-left: -20px; + *zoom: 1; + } + .row:before, .row:after { + display: table; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + margin-left: 20px; + } + .span1 { + width: 42px; + } + .span2 { + width: 104px; + } + .span3 { + width: 166px; + } + .span4 { + width: 228px; + } + .span5 { + width: 290px; + } + .span6 { + width: 352px; + } + .span7 { + width: 414px; + } + .span8 { + width: 476px; + } + .span9 { + width: 538px; + } + .span10 { + width: 600px; + } + .span11 { + width: 662px; + } + .span12, .container { + width: 724px; + } + .offset1 { + margin-left: 82px; + } + .offset2 { + margin-left: 144px; + } + .offset3 { + margin-left: 206px; + } + .offset4 { + margin-left: 268px; + } + .offset5 { + margin-left: 330px; + } + .offset6 { + margin-left: 392px; + } + .offset7 { + margin-left: 454px; + } + .offset8 { + margin-left: 516px; + } + .offset9 { + margin-left: 578px; + } + .offset10 { + margin-left: 640px; + } + .offset11 { + margin-left: 702px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, .row-fluid:after { + display: table; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid > [class*="span"] { + float: left; + margin-left: 2.762430939%; + } + .row-fluid > [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid > .span1 { + width: 5.801104972%; + } + .row-fluid > .span2 { + width: 14.364640883%; + } + .row-fluid > .span3 { + width: 22.928176794%; + } + .row-fluid > .span4 { + width: 31.491712705%; + } + .row-fluid > .span5 { + width: 40.055248616%; + } + .row-fluid > .span6 { + width: 48.618784527%; + } + .row-fluid > .span7 { + width: 57.182320438000005%; + } + .row-fluid > .span8 { + width: 65.74585634900001%; + } + .row-fluid > .span9 { + width: 74.30939226%; + } + .row-fluid > .span10 { + width: 82.87292817100001%; + } + .row-fluid > .span11 { + width: 91.436464082%; + } + .row-fluid > .span12 { + width: 99.999999993%; + } + input.span1, textarea.span1, .uneditable-input.span1 { + width: 32px; + } + input.span2, textarea.span2, .uneditable-input.span2 { + width: 94px; + } + input.span3, textarea.span3, .uneditable-input.span3 { + width: 156px; + } + input.span4, textarea.span4, .uneditable-input.span4 { + width: 218px; + } + input.span5, textarea.span5, .uneditable-input.span5 { + width: 280px; + } + input.span6, textarea.span6, .uneditable-input.span6 { + width: 342px; + } + input.span7, textarea.span7, .uneditable-input.span7 { + width: 404px; + } + input.span8, textarea.span8, .uneditable-input.span8 { + width: 466px; + } + input.span9, textarea.span9, .uneditable-input.span9 { + width: 528px; + } + input.span10, textarea.span10, .uneditable-input.span10 { + width: 590px; + } + input.span11, textarea.span11, .uneditable-input.span11 { + width: 652px; + } + input.span12, textarea.span12, .uneditable-input.span12 { + width: 714px; + } +} +@media (max-width: 979px) { + body { + padding-top: 0; + } + .navbar-fixed-top { + position: static; + margin-bottom: 18px; + } + .navbar-fixed-top .navbar-inner { + padding: 5px; + } + .navbar .container { + width: auto; + padding: 0; + } + .navbar .brand { + padding-left: 10px; + padding-right: 10px; + margin: 0 0 0 -5px; + } + .navbar .nav-collapse { + clear: left; + } + .navbar .nav { + float: none; + margin: 0 0 9px; + } + .navbar .nav > li { + float: none; + } + .navbar .nav > li > a { + margin-bottom: 2px; + } + .navbar .nav > .divider-vertical { + display: none; + } + .navbar .nav .nav-header { + color: #999999; + text-shadow: none; + } + .navbar .nav > li > a, .navbar .dropdown-menu a { + padding: 6px 15px; + font-weight: bold; + color: #999999; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + } + .navbar .dropdown-menu li + li a { + margin-bottom: 2px; + } + .navbar .nav > li > a:hover, .navbar .dropdown-menu a:hover { + background-color: #222222; + } + .navbar .dropdown-menu { + position: static; + top: auto; + left: auto; + float: none; + display: block; + max-width: none; + margin: 0 15px; + padding: 0; + background-color: transparent; + border: none; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + } + .navbar .dropdown-menu:before, .navbar .dropdown-menu:after { + display: none; + } + .navbar .dropdown-menu .divider { + display: none; + } + .navbar-form, .navbar-search { + float: none; + padding: 9px 15px; + margin: 9px 0; + border-top: 1px solid #222222; + border-bottom: 1px solid #222222; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + } + .navbar .nav.pull-right { + float: none; + margin-left: 0; + } + .navbar-static .navbar-inner { + padding-left: 10px; + padding-right: 10px; + } + .btn-navbar { + display: block; + } + .nav-collapse { + overflow: hidden; + height: 0; + } +} +@media (min-width: 980px) { + .nav-collapse.collapse { + height: auto !important; + } +} +@media (min-width: 1200px) { + .row { + margin-left: -30px; + *zoom: 1; + } + .row:before, .row:after { + display: table; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + margin-left: 30px; + } + .span1 { + width: 70px; + } + .span2 { + width: 170px; + } + .span3 { + width: 270px; + } + .span4 { + width: 370px; + } + .span5 { + width: 470px; + } + .span6 { + width: 570px; + } + .span7 { + width: 670px; + } + .span8 { + width: 770px; + } + .span9 { + width: 870px; + } + .span10 { + width: 970px; + } + .span11 { + width: 1070px; + } + .span12, .container { + width: 1170px; + } + .offset1 { + margin-left: 130px; + } + .offset2 { + margin-left: 230px; + } + .offset3 { + margin-left: 330px; + } + .offset4 { + margin-left: 430px; + } + .offset5 { + margin-left: 530px; + } + .offset6 { + margin-left: 630px; + } + .offset7 { + margin-left: 730px; + } + .offset8 { + margin-left: 830px; + } + .offset9 { + margin-left: 930px; + } + .offset10 { + margin-left: 1030px; + } + .offset11 { + margin-left: 1130px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, .row-fluid:after { + display: table; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid > [class*="span"] { + float: left; + margin-left: 2.564102564%; + } + .row-fluid > [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid > .span1 { + width: 5.982905983%; + } + .row-fluid > .span2 { + width: 14.529914530000001%; + } + .row-fluid > .span3 { + width: 23.076923077%; + } + .row-fluid > .span4 { + width: 31.623931624%; + } + .row-fluid > .span5 { + width: 40.170940171000005%; + } + .row-fluid > .span6 { + width: 48.717948718%; + } + .row-fluid > .span7 { + width: 57.264957265%; + } + .row-fluid > .span8 { + width: 65.81196581200001%; + } + .row-fluid > .span9 { + width: 74.358974359%; + } + .row-fluid > .span10 { + width: 82.905982906%; + } + .row-fluid > .span11 { + width: 91.45299145300001%; + } + .row-fluid > .span12 { + width: 100%; + } + input.span1, textarea.span1, .uneditable-input.span1 { + width: 60px; + } + input.span2, textarea.span2, .uneditable-input.span2 { + width: 160px; + } + input.span3, textarea.span3, .uneditable-input.span3 { + width: 260px; + } + input.span4, textarea.span4, .uneditable-input.span4 { + width: 360px; + } + input.span5, textarea.span5, .uneditable-input.span5 { + width: 460px; + } + input.span6, textarea.span6, .uneditable-input.span6 { + width: 560px; + } + input.span7, textarea.span7, .uneditable-input.span7 { + width: 660px; + } + input.span8, textarea.span8, .uneditable-input.span8 { + width: 760px; + } + input.span9, textarea.span9, .uneditable-input.span9 { + width: 860px; + } + input.span10, textarea.span10, .uneditable-input.span10 { + width: 960px; + } + input.span11, textarea.span11, .uneditable-input.span11 { + width: 1060px; + } + input.span12, textarea.span12, .uneditable-input.span12 { + width: 1160px; + } + .thumbnails { + margin-left: -30px; + } + .thumbnails > li { + margin-left: 30px; + } +} diff --git a/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css b/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css new file mode 100644 index 0000000..6229c12 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css @@ -0,0 +1,3521 @@ +/*! + * Bootstrap v2.0.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +nav, +section { + display: block; +} +audio, canvas, video { + display: inline-block; + *display: inline; + *zoom: 1; +} +audio:not([controls]) { + display: none; +} +html { + font-size: 100%; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} +a:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +a:hover, a:active { + outline: 0; +} +sub, sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} +sup { + top: -0.5em; +} +sub { + bottom: -0.25em; +} +img { + max-width: 100%; + height: auto; + border: 0; + -ms-interpolation-mode: bicubic; +} +button, +input, +select, +textarea { + margin: 0; + font-size: 100%; + vertical-align: middle; +} +button, input { + *overflow: visible; + line-height: normal; +} +button::-moz-focus-inner, input::-moz-focus-inner { + padding: 0; + border: 0; +} +button, +input[type="button"], +input[type="reset"], +input[type="submit"] { + cursor: pointer; + -webkit-appearance: button; +} +input[type="search"] { + -webkit-appearance: textfield; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +input[type="search"]::-webkit-search-decoration, input[type="search"]::-webkit-search-cancel-button { + -webkit-appearance: none; +} +textarea { + overflow: auto; + vertical-align: top; +} +.clearfix { + *zoom: 1; +} +.clearfix:before, .clearfix:after { + display: table; + content: ""; +} +.clearfix:after { + clear: both; +} +body { + margin: 0; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 18px; + color: #333333; + background-color: #ffffff; +} +a { + color: #0088cc; + text-decoration: none; +} +a:hover { + color: #005580; + text-decoration: underline; +} +.row { + margin-left: -20px; + *zoom: 1; +} +.row:before, .row:after { + display: table; + content: ""; +} +.row:after { + clear: both; +} +[class*="span"] { + float: left; + margin-left: 20px; +} +.span1 { + width: 60px; +} +.span2 { + width: 140px; +} +.span3 { + width: 220px; +} +.span4 { + width: 300px; +} +.span5 { + width: 380px; +} +.span6 { + width: 460px; +} +.span7 { + width: 540px; +} +.span8 { + width: 620px; +} +.span9 { + width: 700px; +} +.span10 { + width: 780px; +} +.span11 { + width: 860px; +} +.span12, .container { + width: 940px; +} +.offset1 { + margin-left: 100px; +} +.offset2 { + margin-left: 180px; +} +.offset3 { + margin-left: 260px; +} +.offset4 { + margin-left: 340px; +} +.offset5 { + margin-left: 420px; +} +.offset6 { + margin-left: 500px; +} +.offset7 { + margin-left: 580px; +} +.offset8 { + margin-left: 660px; +} +.offset9 { + margin-left: 740px; +} +.offset10 { + margin-left: 820px; +} +.offset11 { + margin-left: 900px; +} +.row-fluid { + width: 100%; + *zoom: 1; +} +.row-fluid:before, .row-fluid:after { + display: table; + content: ""; +} +.row-fluid:after { + clear: both; +} +.row-fluid > [class*="span"] { + float: left; + margin-left: 2.127659574%; +} +.row-fluid > [class*="span"]:first-child { + margin-left: 0; +} +.row-fluid > .span1 { + width: 6.382978723%; +} +.row-fluid > .span2 { + width: 14.89361702%; +} +.row-fluid > .span3 { + width: 23.404255317%; +} +.row-fluid > .span4 { + width: 31.914893614%; +} +.row-fluid > .span5 { + width: 40.425531911%; +} +.row-fluid > .span6 { + width: 48.93617020799999%; +} +.row-fluid > .span7 { + width: 57.446808505%; +} +.row-fluid > .span8 { + width: 65.95744680199999%; +} +.row-fluid > .span9 { + width: 74.468085099%; +} +.row-fluid > .span10 { + width: 82.97872339599999%; +} +.row-fluid > .span11 { + width: 91.489361693%; +} +.row-fluid > .span12 { + width: 99.99999998999999%; +} +.container { + width: 940px; + margin-left: auto; + margin-right: auto; + *zoom: 1; +} +.container:before, .container:after { + display: table; + content: ""; +} +.container:after { + clear: both; +} +.container-fluid { + padding-left: 20px; + padding-right: 20px; + *zoom: 1; +} +.container-fluid:before, .container-fluid:after { + display: table; + content: ""; +} +.container-fluid:after { + clear: both; +} +p { + margin: 0 0 9px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 18px; +} +p small { + font-size: 11px; + color: #999999; +} +.lead { + margin-bottom: 18px; + font-size: 20px; + font-weight: 200; + line-height: 27px; +} +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 0; + font-weight: bold; + color: #333333; + text-rendering: optimizelegibility; +} +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small { + font-weight: normal; + color: #999999; +} +h1 { + font-size: 30px; + line-height: 36px; +} +h1 small { + font-size: 18px; +} +h2 { + font-size: 24px; + line-height: 36px; +} +h2 small { + font-size: 18px; +} +h3 { + line-height: 27px; + font-size: 18px; +} +h3 small { + font-size: 14px; +} +h4, h5, h6 { + line-height: 18px; +} +h4 { + font-size: 14px; +} +h4 small { + font-size: 12px; +} +h5 { + font-size: 12px; +} +h6 { + font-size: 11px; + color: #999999; + text-transform: uppercase; +} +.page-header { + padding-bottom: 17px; + margin: 18px 0; + border-bottom: 1px solid #eeeeee; +} +.page-header h1 { + line-height: 1; +} +ul, ol { + padding: 0; + margin: 0 0 9px 25px; +} +ul ul, +ul ol, +ol ol, +ol ul { + margin-bottom: 0; +} +ul { + list-style: disc; +} +ol { + list-style: decimal; +} +li { + line-height: 18px; +} +ul.unstyled, ol.unstyled { + margin-left: 0; + list-style: none; +} +dl { + margin-bottom: 18px; +} +dt, dd { + line-height: 18px; +} +dt { + font-weight: bold; +} +dd { + margin-left: 9px; +} +hr { + margin: 18px 0; + border: 0; + border-top: 1px solid #eeeeee; + border-bottom: 1px solid #ffffff; +} +strong { + font-weight: bold; +} +em { + font-style: italic; +} +.muted { + color: #999999; +} +abbr { + font-size: 90%; + text-transform: uppercase; + border-bottom: 1px dotted #ddd; + cursor: help; +} +blockquote { + padding: 0 0 0 15px; + margin: 0 0 18px; + border-left: 5px solid #eeeeee; +} +blockquote p { + margin-bottom: 0; + font-size: 16px; + font-weight: 300; + line-height: 22.5px; +} +blockquote small { + display: block; + line-height: 18px; + color: #999999; +} +blockquote small:before { + content: '\2014 \00A0'; +} +blockquote.pull-right { + float: right; + padding-left: 0; + padding-right: 15px; + border-left: 0; + border-right: 5px solid #eeeeee; +} +blockquote.pull-right p, blockquote.pull-right small { + text-align: right; +} +q:before, +q:after, +blockquote:before, +blockquote:after { + content: ""; +} +address { + display: block; + margin-bottom: 18px; + line-height: 18px; + font-style: normal; +} +small { + font-size: 100%; +} +cite { + font-style: normal; +} +code, pre { + padding: 0 3px 2px; + font-family: Menlo, Monaco, "Courier New", monospace; + font-size: 12px; + color: #333333; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +code { + padding: 3px 4px; + color: #d14; + background-color: #f7f7f9; + border: 1px solid #e1e1e8; +} +pre { + display: block; + padding: 8.5px; + margin: 0 0 9px; + font-size: 12px; + line-height: 18px; + background-color: #f5f5f5; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.15); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + white-space: pre; + white-space: pre-wrap; + word-break: break-all; + word-wrap: break-word; +} +pre.prettyprint { + margin-bottom: 18px; +} +pre code { + padding: 0; + color: inherit; + background-color: transparent; + border: 0; +} +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} +form { + margin: 0 0 18px; +} +fieldset { + padding: 0; + margin: 0; + border: 0; +} +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 27px; + font-size: 19.5px; + line-height: 36px; + color: #333333; + border: 0; + border-bottom: 1px solid #eee; +} +legend small { + font-size: 13.5px; + color: #999999; +} +label, +input, +button, +select, +textarea { + font-size: 13px; + font-weight: normal; + line-height: 18px; +} +input, +button, +select, +textarea { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; +} +label { + display: block; + margin-bottom: 5px; + color: #333333; +} +input, +textarea, +select, +.uneditable-input { + display: inline-block; + width: 210px; + height: 18px; + padding: 4px; + margin-bottom: 9px; + font-size: 13px; + line-height: 18px; + color: #555555; + border: 1px solid #ccc; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.uneditable-textarea { + width: auto; + height: auto; +} +label input, label textarea, label select { + display: block; +} +input[type="image"], input[type="checkbox"], input[type="radio"] { + width: auto; + height: auto; + padding: 0; + margin: 3px 0; + *margin-top: 0; + /* IE7 */ + + line-height: normal; + cursor: pointer; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + border: 0 \9; + /* IE9 and down */ + +} +input[type="image"] { + border: 0; +} +input[type="file"] { + width: auto; + padding: initial; + line-height: initial; + border: initial; + background-color: #ffffff; + background-color: initial; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +input[type="button"], input[type="reset"], input[type="submit"] { + width: auto; + height: auto; +} +select, input[type="file"] { + height: 28px; + /* In IE7, the height of the select element cannot be changed by height, only font-size */ + + *margin-top: 4px; + /* For IE7, add top margin to align select with labels */ + + line-height: 28px; +} +input[type="file"] { + line-height: 18px \9; +} +select { + width: 220px; + background-color: #ffffff; +} +select[multiple], select[size] { + height: auto; +} +input[type="image"] { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +textarea { + height: auto; +} +input[type="hidden"] { + display: none; +} +.radio, .checkbox { + padding-left: 18px; +} +.radio input[type="radio"], .checkbox input[type="checkbox"] { + float: left; + margin-left: -18px; +} +.controls > .radio:first-child, .controls > .checkbox:first-child { + padding-top: 5px; +} +.radio.inline, .checkbox.inline { + display: inline-block; + padding-top: 5px; + margin-bottom: 0; + vertical-align: middle; +} +.radio.inline + .radio.inline, .checkbox.inline + .checkbox.inline { + margin-left: 10px; +} +input, textarea { + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; + -moz-transition: border linear 0.2s, box-shadow linear 0.2s; + -ms-transition: border linear 0.2s, box-shadow linear 0.2s; + -o-transition: border linear 0.2s, box-shadow linear 0.2s; + transition: border linear 0.2s, box-shadow linear 0.2s; +} +input:focus, textarea:focus { + border-color: rgba(82, 168, 236, 0.8); + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + outline: 0; + outline: thin dotted \9; + /* IE6-9 */ + +} +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus, +select:focus { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.input-mini { + width: 60px; +} +.input-small { + width: 90px; +} +.input-medium { + width: 150px; +} +.input-large { + width: 210px; +} +.input-xlarge { + width: 270px; +} +.input-xxlarge { + width: 530px; +} +input[class*="span"], +select[class*="span"], +textarea[class*="span"], +.uneditable-input { + float: none; + margin-left: 0; +} +input.span1, textarea.span1, .uneditable-input.span1 { + width: 50px; +} +input.span2, textarea.span2, .uneditable-input.span2 { + width: 130px; +} +input.span3, textarea.span3, .uneditable-input.span3 { + width: 210px; +} +input.span4, textarea.span4, .uneditable-input.span4 { + width: 290px; +} +input.span5, textarea.span5, .uneditable-input.span5 { + width: 370px; +} +input.span6, textarea.span6, .uneditable-input.span6 { + width: 450px; +} +input.span7, textarea.span7, .uneditable-input.span7 { + width: 530px; +} +input.span8, textarea.span8, .uneditable-input.span8 { + width: 610px; +} +input.span9, textarea.span9, .uneditable-input.span9 { + width: 690px; +} +input.span10, textarea.span10, .uneditable-input.span10 { + width: 770px; +} +input.span11, textarea.span11, .uneditable-input.span11 { + width: 850px; +} +input.span12, textarea.span12, .uneditable-input.span12 { + width: 930px; +} +input[disabled], +select[disabled], +textarea[disabled], +input[readonly], +select[readonly], +textarea[readonly] { + background-color: #f5f5f5; + border-color: #ddd; + cursor: not-allowed; +} +.control-group.warning > label, .control-group.warning .help-block, .control-group.warning .help-inline { + color: #c09853; +} +.control-group.warning input, .control-group.warning select, .control-group.warning textarea { + color: #c09853; + border-color: #c09853; +} +.control-group.warning input:focus, .control-group.warning select:focus, .control-group.warning textarea:focus { + border-color: #a47e3c; + -webkit-box-shadow: 0 0 6px #dbc59e; + -moz-box-shadow: 0 0 6px #dbc59e; + box-shadow: 0 0 6px #dbc59e; +} +.control-group.warning .input-prepend .add-on, .control-group.warning .input-append .add-on { + color: #c09853; + background-color: #fcf8e3; + border-color: #c09853; +} +.control-group.error > label, .control-group.error .help-block, .control-group.error .help-inline { + color: #b94a48; +} +.control-group.error input, .control-group.error select, .control-group.error textarea { + color: #b94a48; + border-color: #b94a48; +} +.control-group.error input:focus, .control-group.error select:focus, .control-group.error textarea:focus { + border-color: #953b39; + -webkit-box-shadow: 0 0 6px #d59392; + -moz-box-shadow: 0 0 6px #d59392; + box-shadow: 0 0 6px #d59392; +} +.control-group.error .input-prepend .add-on, .control-group.error .input-append .add-on { + color: #b94a48; + background-color: #f2dede; + border-color: #b94a48; +} +.control-group.success > label, .control-group.success .help-block, .control-group.success .help-inline { + color: #468847; +} +.control-group.success input, .control-group.success select, .control-group.success textarea { + color: #468847; + border-color: #468847; +} +.control-group.success input:focus, .control-group.success select:focus, .control-group.success textarea:focus { + border-color: #356635; + -webkit-box-shadow: 0 0 6px #7aba7b; + -moz-box-shadow: 0 0 6px #7aba7b; + box-shadow: 0 0 6px #7aba7b; +} +.control-group.success .input-prepend .add-on, .control-group.success .input-append .add-on { + color: #468847; + background-color: #dff0d8; + border-color: #468847; +} +input:focus:required:invalid, textarea:focus:required:invalid, select:focus:required:invalid { + color: #b94a48; + border-color: #ee5f5b; +} +input:focus:required:invalid:focus, textarea:focus:required:invalid:focus, select:focus:required:invalid:focus { + border-color: #e9322d; + -webkit-box-shadow: 0 0 6px #f8b9b7; + -moz-box-shadow: 0 0 6px #f8b9b7; + box-shadow: 0 0 6px #f8b9b7; +} +.form-actions { + padding: 17px 20px 18px; + margin-top: 18px; + margin-bottom: 18px; + background-color: #f5f5f5; + border-top: 1px solid #ddd; +} +.uneditable-input { + display: block; + background-color: #ffffff; + border-color: #eee; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + cursor: not-allowed; +} +:-moz-placeholder { + color: #999999; +} +::-webkit-input-placeholder { + color: #999999; +} +.help-block { + display: block; + margin-top: 5px; + margin-bottom: 0; + color: #999999; +} +.help-inline { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; + margin-bottom: 9px; + vertical-align: middle; + padding-left: 5px; +} +.input-prepend, .input-append { + margin-bottom: 5px; + *zoom: 1; +} +.input-prepend:before, +.input-append:before, +.input-prepend:after, +.input-append:after { + display: table; + content: ""; +} +.input-prepend:after, .input-append:after { + clear: both; +} +.input-prepend input, +.input-append input, +.input-prepend .uneditable-input, +.input-append .uneditable-input { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.input-prepend input:focus, +.input-append input:focus, +.input-prepend .uneditable-input:focus, +.input-append .uneditable-input:focus { + position: relative; + z-index: 2; +} +.input-prepend .uneditable-input, .input-append .uneditable-input { + border-left-color: #ccc; +} +.input-prepend .add-on, .input-append .add-on { + float: left; + display: block; + width: auto; + min-width: 16px; + height: 18px; + margin-right: -1px; + padding: 4px 5px; + font-weight: normal; + line-height: 18px; + color: #999999; + text-align: center; + text-shadow: 0 1px 0 #ffffff; + background-color: #f5f5f5; + border: 1px solid #ccc; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.input-prepend .active, .input-append .active { + background-color: #a9dba9; + border-color: #46a546; +} +.input-prepend .add-on { + *margin-top: 1px; + /* IE6-7 */ + +} +.input-append input, .input-append .uneditable-input { + float: left; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.input-append .uneditable-input { + border-left-color: #eee; + border-right-color: #ccc; +} +.input-append .add-on { + margin-right: 0; + margin-left: -1px; + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.input-append input:first-child { + *margin-left: -160px; +} +.input-append input:first-child + .add-on { + *margin-left: -21px; +} +.search-query { + padding-left: 14px; + padding-right: 14px; + margin-bottom: 0; + -webkit-border-radius: 14px; + -moz-border-radius: 14px; + border-radius: 14px; +} +.form-search input, +.form-inline input, +.form-horizontal input, +.form-search textarea, +.form-inline textarea, +.form-horizontal textarea, +.form-search select, +.form-inline select, +.form-horizontal select, +.form-search .help-inline, +.form-inline .help-inline, +.form-horizontal .help-inline, +.form-search .uneditable-input, +.form-inline .uneditable-input, +.form-horizontal .uneditable-input { + display: inline-block; + margin-bottom: 0; +} +.form-search .hide, .form-inline .hide, .form-horizontal .hide { + display: none; +} +.form-search label, +.form-inline label, +.form-search .input-append, +.form-inline .input-append, +.form-search .input-prepend, +.form-inline .input-prepend { + display: inline-block; +} +.form-search .input-append .add-on, +.form-inline .input-prepend .add-on, +.form-search .input-append .add-on, +.form-inline .input-prepend .add-on { + vertical-align: middle; +} +.form-search .radio, +.form-inline .radio, +.form-search .checkbox, +.form-inline .checkbox { + margin-bottom: 0; + vertical-align: middle; +} +.control-group { + margin-bottom: 9px; +} +legend + .control-group { + margin-top: 18px; + -webkit-margin-top-collapse: separate; +} +.form-horizontal .control-group { + margin-bottom: 18px; + *zoom: 1; +} +.form-horizontal .control-group:before, .form-horizontal .control-group:after { + display: table; + content: ""; +} +.form-horizontal .control-group:after { + clear: both; +} +.form-horizontal .control-label { + float: left; + width: 140px; + padding-top: 5px; + text-align: right; +} +.form-horizontal .controls { + margin-left: 160px; +} +.form-horizontal .form-actions { + padding-left: 160px; +} +table { + max-width: 100%; + border-collapse: collapse; + border-spacing: 0; +} +.table { + width: 100%; + margin-bottom: 18px; +} +.table th, .table td { + padding: 8px; + line-height: 18px; + text-align: left; + vertical-align: top; + border-top: 1px solid #ddd; +} +.table th { + font-weight: bold; +} +.table thead th { + vertical-align: bottom; +} +.table thead:first-child tr th, .table thead:first-child tr td { + border-top: 0; +} +.table tbody + tbody { + border-top: 2px solid #ddd; +} +.table-condensed th, .table-condensed td { + padding: 4px 5px; +} +.table-bordered { + border: 1px solid #ddd; + border-collapse: separate; + *border-collapse: collapsed; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.table-bordered th + th, +.table-bordered td + td, +.table-bordered th + td, +.table-bordered td + th { + border-left: 1px solid #ddd; +} +.table-bordered thead:first-child tr:first-child th, .table-bordered tbody:first-child tr:first-child th, .table-bordered tbody:first-child tr:first-child td { + border-top: 0; +} +.table-bordered thead:first-child tr:first-child th:first-child, .table-bordered tbody:first-child tr:first-child td:first-child { + -webkit-border-radius: 4px 0 0 0; + -moz-border-radius: 4px 0 0 0; + border-radius: 4px 0 0 0; +} +.table-bordered thead:first-child tr:first-child th:last-child, .table-bordered tbody:first-child tr:first-child td:last-child { + -webkit-border-radius: 0 4px 0 0; + -moz-border-radius: 0 4px 0 0; + border-radius: 0 4px 0 0; +} +.table-bordered thead:last-child tr:last-child th:first-child, .table-bordered tbody:last-child tr:last-child td:first-child { + -webkit-border-radius: 0 0 0 4px; + -moz-border-radius: 0 0 0 4px; + border-radius: 0 0 0 4px; +} +.table-bordered thead:last-child tr:last-child th:last-child, .table-bordered tbody:last-child tr:last-child td:last-child { + -webkit-border-radius: 0 0 4px 0; + -moz-border-radius: 0 0 4px 0; + border-radius: 0 0 4px 0; +} +.table-striped tbody tr:nth-child(odd) td, .table-striped tbody tr:nth-child(odd) th { + background-color: #f9f9f9; +} +.table tbody tr:hover td, .table tbody tr:hover th { + background-color: #f5f5f5; +} +table .span1 { + float: none; + width: 44px; + margin-left: 0; +} +table .span2 { + float: none; + width: 124px; + margin-left: 0; +} +table .span3 { + float: none; + width: 204px; + margin-left: 0; +} +table .span4 { + float: none; + width: 284px; + margin-left: 0; +} +table .span5 { + float: none; + width: 364px; + margin-left: 0; +} +table .span6 { + float: none; + width: 444px; + margin-left: 0; +} +table .span7 { + float: none; + width: 524px; + margin-left: 0; +} +table .span8 { + float: none; + width: 604px; + margin-left: 0; +} +table .span9 { + float: none; + width: 684px; + margin-left: 0; +} +table .span10 { + float: none; + width: 764px; + margin-left: 0; +} +table .span11 { + float: none; + width: 844px; + margin-left: 0; +} +table .span12 { + float: none; + width: 924px; + margin-left: 0; +} +[class^="icon-"], [class*=" icon-"] { + display: inline-block; + width: 14px; + height: 14px; + line-height: 14px; + vertical-align: text-top; + background-image: url("../img/glyphicons-halflings.png"); + background-position: 14px 14px; + background-repeat: no-repeat; + *margin-right: .3em; +} +[class^="icon-"]:last-child, [class*=" icon-"]:last-child { + *margin-left: 0; +} +.icon-white { + background-image: url("../img/glyphicons-halflings-white.png"); +} +.icon-glass { + background-position: 0 0; +} +.icon-music { + background-position: -24px 0; +} +.icon-search { + background-position: -48px 0; +} +.icon-envelope { + background-position: -72px 0; +} +.icon-heart { + background-position: -96px 0; +} +.icon-star { + background-position: -120px 0; +} +.icon-star-empty { + background-position: -144px 0; +} +.icon-user { + background-position: -168px 0; +} +.icon-film { + background-position: -192px 0; +} +.icon-th-large { + background-position: -216px 0; +} +.icon-th { + background-position: -240px 0; +} +.icon-th-list { + background-position: -264px 0; +} +.icon-ok { + background-position: -288px 0; +} +.icon-remove { + background-position: -312px 0; +} +.icon-zoom-in { + background-position: -336px 0; +} +.icon-zoom-out { + background-position: -360px 0; +} +.icon-off { + background-position: -384px 0; +} +.icon-signal { + background-position: -408px 0; +} +.icon-cog { + background-position: -432px 0; +} +.icon-trash { + background-position: -456px 0; +} +.icon-home { + background-position: 0 -24px; +} +.icon-file { + background-position: -24px -24px; +} +.icon-time { + background-position: -48px -24px; +} +.icon-road { + background-position: -72px -24px; +} +.icon-download-alt { + background-position: -96px -24px; +} +.icon-download { + background-position: -120px -24px; +} +.icon-upload { + background-position: -144px -24px; +} +.icon-inbox { + background-position: -168px -24px; +} +.icon-play-circle { + background-position: -192px -24px; +} +.icon-repeat { + background-position: -216px -24px; +} +.icon-refresh { + background-position: -240px -24px; +} +.icon-list-alt { + background-position: -264px -24px; +} +.icon-lock { + background-position: -287px -24px; +} +.icon-flag { + background-position: -312px -24px; +} +.icon-headphones { + background-position: -336px -24px; +} +.icon-volume-off { + background-position: -360px -24px; +} +.icon-volume-down { + background-position: -384px -24px; +} +.icon-volume-up { + background-position: -408px -24px; +} +.icon-qrcode { + background-position: -432px -24px; +} +.icon-barcode { + background-position: -456px -24px; +} +.icon-tag { + background-position: 0 -48px; +} +.icon-tags { + background-position: -25px -48px; +} +.icon-book { + background-position: -48px -48px; +} +.icon-bookmark { + background-position: -72px -48px; +} +.icon-print { + background-position: -96px -48px; +} +.icon-camera { + background-position: -120px -48px; +} +.icon-font { + background-position: -144px -48px; +} +.icon-bold { + background-position: -167px -48px; +} +.icon-italic { + background-position: -192px -48px; +} +.icon-text-height { + background-position: -216px -48px; +} +.icon-text-width { + background-position: -240px -48px; +} +.icon-align-left { + background-position: -264px -48px; +} +.icon-align-center { + background-position: -288px -48px; +} +.icon-align-right { + background-position: -312px -48px; +} +.icon-align-justify { + background-position: -336px -48px; +} +.icon-list { + background-position: -360px -48px; +} +.icon-indent-left { + background-position: -384px -48px; +} +.icon-indent-right { + background-position: -408px -48px; +} +.icon-facetime-video { + background-position: -432px -48px; +} +.icon-picture { + background-position: -456px -48px; +} +.icon-pencil { + background-position: 0 -72px; +} +.icon-map-marker { + background-position: -24px -72px; +} +.icon-adjust { + background-position: -48px -72px; +} +.icon-tint { + background-position: -72px -72px; +} +.icon-edit { + background-position: -96px -72px; +} +.icon-share { + background-position: -120px -72px; +} +.icon-check { + background-position: -144px -72px; +} +.icon-move { + background-position: -168px -72px; +} +.icon-step-backward { + background-position: -192px -72px; +} +.icon-fast-backward { + background-position: -216px -72px; +} +.icon-backward { + background-position: -240px -72px; +} +.icon-play { + background-position: -264px -72px; +} +.icon-pause { + background-position: -288px -72px; +} +.icon-stop { + background-position: -312px -72px; +} +.icon-forward { + background-position: -336px -72px; +} +.icon-fast-forward { + background-position: -360px -72px; +} +.icon-step-forward { + background-position: -384px -72px; +} +.icon-eject { + background-position: -408px -72px; +} +.icon-chevron-left { + background-position: -432px -72px; +} +.icon-chevron-right { + background-position: -456px -72px; +} +.icon-plus-sign { + background-position: 0 -96px; +} +.icon-minus-sign { + background-position: -24px -96px; +} +.icon-remove-sign { + background-position: -48px -96px; +} +.icon-ok-sign { + background-position: -72px -96px; +} +.icon-question-sign { + background-position: -96px -96px; +} +.icon-info-sign { + background-position: -120px -96px; +} +.icon-screenshot { + background-position: -144px -96px; +} +.icon-remove-circle { + background-position: -168px -96px; +} +.icon-ok-circle { + background-position: -192px -96px; +} +.icon-ban-circle { + background-position: -216px -96px; +} +.icon-arrow-left { + background-position: -240px -96px; +} +.icon-arrow-right { + background-position: -264px -96px; +} +.icon-arrow-up { + background-position: -289px -96px; +} +.icon-arrow-down { + background-position: -312px -96px; +} +.icon-share-alt { + background-position: -336px -96px; +} +.icon-resize-full { + background-position: -360px -96px; +} +.icon-resize-small { + background-position: -384px -96px; +} +.icon-plus { + background-position: -408px -96px; +} +.icon-minus { + background-position: -433px -96px; +} +.icon-asterisk { + background-position: -456px -96px; +} +.icon-exclamation-sign { + background-position: 0 -120px; +} +.icon-gift { + background-position: -24px -120px; +} +.icon-leaf { + background-position: -48px -120px; +} +.icon-fire { + background-position: -72px -120px; +} +.icon-eye-open { + background-position: -96px -120px; +} +.icon-eye-close { + background-position: -120px -120px; +} +.icon-warning-sign { + background-position: -144px -120px; +} +.icon-plane { + background-position: -168px -120px; +} +.icon-calendar { + background-position: -192px -120px; +} +.icon-random { + background-position: -216px -120px; +} +.icon-comment { + background-position: -240px -120px; +} +.icon-magnet { + background-position: -264px -120px; +} +.icon-chevron-up { + background-position: -288px -120px; +} +.icon-chevron-down { + background-position: -313px -119px; +} +.icon-retweet { + background-position: -336px -120px; +} +.icon-shopping-cart { + background-position: -360px -120px; +} +.icon-folder-close { + background-position: -384px -120px; +} +.icon-folder-open { + background-position: -408px -120px; +} +.icon-resize-vertical { + background-position: -432px -119px; +} +.icon-resize-horizontal { + background-position: -456px -118px; +} +.dropdown { + position: relative; +} +.dropdown-toggle { + *margin-bottom: -3px; +} +.dropdown-toggle:active, .open .dropdown-toggle { + outline: 0; +} +.caret { + display: inline-block; + width: 0; + height: 0; + text-indent: -99999px; + *text-indent: 0; + vertical-align: top; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 4px solid #000000; + opacity: 0.3; + filter: alpha(opacity=30); + content: "\2193"; +} +.dropdown .caret { + margin-top: 8px; + margin-left: 2px; +} +.dropdown:hover .caret, .open.dropdown .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + float: left; + display: none; + min-width: 160px; + _width: 160px; + padding: 4px 0; + margin: 0; + list-style: none; + background-color: #ffffff; + border-color: #ccc; + border-color: rgba(0, 0, 0, 0.2); + border-style: solid; + border-width: 1px; + -webkit-border-radius: 0 0 5px 5px; + -moz-border-radius: 0 0 5px 5px; + border-radius: 0 0 5px 5px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; + *border-right-width: 2px; + *border-bottom-width: 2px; +} +.dropdown-menu.bottom-up { + top: auto; + bottom: 100%; + margin-bottom: 2px; +} +.dropdown-menu .divider { + height: 1px; + margin: 5px 1px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #ffffff; + *width: 100%; + *margin: -5px 0 5px; +} +.dropdown-menu a { + display: block; + padding: 3px 15px; + clear: both; + font-weight: normal; + line-height: 18px; + color: #555555; + white-space: nowrap; +} +.dropdown-menu li > a:hover, .dropdown-menu .active > a, .dropdown-menu .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #0088cc; +} +.dropdown.open { + *z-index: 1000; +} +.dropdown.open .dropdown-toggle { + color: #ffffff; + background: #ccc; + background: rgba(0, 0, 0, 0.3); +} +.dropdown.open .dropdown-menu { + display: block; +} +.typeahead { + margin-top: 2px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #f5f5f5; + border: 1px solid #eee; + border: 1px solid rgba(0, 0, 0, 0.05); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 0, 0, 0.15); +} +.fade { + -webkit-transition: opacity 0.15s linear; + -moz-transition: opacity 0.15s linear; + -ms-transition: opacity 0.15s linear; + -o-transition: opacity 0.15s linear; + transition: opacity 0.15s linear; + opacity: 0; +} +.fade.in { + opacity: 1; +} +.collapse { + -webkit-transition: height 0.35s ease; + -moz-transition: height 0.35s ease; + -ms-transition: height 0.35s ease; + -o-transition: height 0.35s ease; + transition: height 0.35s ease; + position: relative; + overflow: hidden; + height: 0; +} +.collapse.in { + height: auto; +} +.close { + float: right; + font-size: 20px; + font-weight: bold; + line-height: 18px; + color: #000000; + text-shadow: 0 1px 0 #ffffff; + opacity: 0.2; + filter: alpha(opacity=20); +} +.close:hover { + color: #000000; + text-decoration: none; + opacity: 0.4; + filter: alpha(opacity=40); + cursor: pointer; +} +.btn { + display: inline-block; + padding: 4px 10px 4px; + margin-bottom: 0; + font-size: 13px; + line-height: 18px; + color: #333333; + text-align: center; + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); + vertical-align: middle; + background-color: #f5f5f5; + background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); + background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); + background-image: linear-gradient(top, #ffffff, #e6e6e6); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0); + border-color: #e6e6e6 #e6e6e6 #bfbfbf; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + border: 1px solid #ccc; + border-bottom-color: #bbb; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + cursor: pointer; + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + *margin-left: .3em; +} +.btn:hover, +.btn:active, +.btn.active, +.btn.disabled, +.btn[disabled] { + background-color: #e6e6e6; +} +.btn:active, .btn.active { + background-color: #cccccc \9; +} +.btn:first-child { + *margin-left: 0; +} +.btn:hover { + color: #333333; + text-decoration: none; + background-color: #e6e6e6; + background-position: 0 -15px; + -webkit-transition: background-position 0.1s linear; + -moz-transition: background-position 0.1s linear; + -ms-transition: background-position 0.1s linear; + -o-transition: background-position 0.1s linear; + transition: background-position 0.1s linear; +} +.btn:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.btn.active, .btn:active { + background-image: none; + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + background-color: #e6e6e6; + background-color: #d9d9d9 \9; + outline: 0; +} +.btn.disabled, .btn[disabled] { + cursor: default; + background-image: none; + background-color: #e6e6e6; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +.btn-large { + padding: 9px 14px; + font-size: 15px; + line-height: normal; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.btn-large [class^="icon-"] { + margin-top: 1px; +} +.btn-small { + padding: 5px 9px; + font-size: 11px; + line-height: 16px; +} +.btn-small [class^="icon-"] { + margin-top: -1px; +} +.btn-mini { + padding: 2px 6px; + font-size: 11px; + line-height: 14px; +} +.btn-primary, +.btn-primary:hover, +.btn-warning, +.btn-warning:hover, +.btn-danger, +.btn-danger:hover, +.btn-success, +.btn-success:hover, +.btn-info, +.btn-info:hover, +.btn-inverse, +.btn-inverse:hover { + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + color: #ffffff; +} +.btn-primary.active, +.btn-warning.active, +.btn-danger.active, +.btn-success.active, +.btn-info.active, +.btn-dark.active { + color: rgba(255, 255, 255, 0.75); +} +.btn-primary { + background-color: #006dcc; + background-image: -moz-linear-gradient(top, #0088cc, #0044cc); + background-image: -ms-linear-gradient(top, #0088cc, #0044cc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); + background-image: -o-linear-gradient(top, #0088cc, #0044cc); + background-image: linear-gradient(top, #0088cc, #0044cc); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); + border-color: #0044cc #0044cc #002a80; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-primary:hover, +.btn-primary:active, +.btn-primary.active, +.btn-primary.disabled, +.btn-primary[disabled] { + background-color: #0044cc; +} +.btn-primary:active, .btn-primary.active { + background-color: #003399 \9; +} +.btn-warning { + background-color: #faa732; + background-image: -moz-linear-gradient(top, #fbb450, #f89406); + background-image: -ms-linear-gradient(top, #fbb450, #f89406); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); + background-image: -webkit-linear-gradient(top, #fbb450, #f89406); + background-image: -o-linear-gradient(top, #fbb450, #f89406); + background-image: linear-gradient(top, #fbb450, #f89406); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0); + border-color: #f89406 #f89406 #ad6704; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-warning:hover, +.btn-warning:active, +.btn-warning.active, +.btn-warning.disabled, +.btn-warning[disabled] { + background-color: #f89406; +} +.btn-warning:active, .btn-warning.active { + background-color: #c67605 \9; +} +.btn-danger { + background-color: #da4f49; + background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -ms-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -o-linear-gradient(top, #ee5f5b, #bd362f); + background-image: linear-gradient(top, #ee5f5b, #bd362f); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0); + border-color: #bd362f #bd362f #802420; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-danger:hover, +.btn-danger:active, +.btn-danger.active, +.btn-danger.disabled, +.btn-danger[disabled] { + background-color: #bd362f; +} +.btn-danger:active, .btn-danger.active { + background-color: #942a25 \9; +} +.btn-success { + background-color: #5bb75b; + background-image: -moz-linear-gradient(top, #62c462, #51a351); + background-image: -ms-linear-gradient(top, #62c462, #51a351); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351)); + background-image: -webkit-linear-gradient(top, #62c462, #51a351); + background-image: -o-linear-gradient(top, #62c462, #51a351); + background-image: linear-gradient(top, #62c462, #51a351); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0); + border-color: #51a351 #51a351 #387038; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-success:hover, +.btn-success:active, +.btn-success.active, +.btn-success.disabled, +.btn-success[disabled] { + background-color: #51a351; +} +.btn-success:active, .btn-success.active { + background-color: #408140 \9; +} +.btn-info { + background-color: #49afcd; + background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -ms-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4)); + background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -o-linear-gradient(top, #5bc0de, #2f96b4); + background-image: linear-gradient(top, #5bc0de, #2f96b4); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0); + border-color: #2f96b4 #2f96b4 #1f6377; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-info:hover, +.btn-info:active, +.btn-info.active, +.btn-info.disabled, +.btn-info[disabled] { + background-color: #2f96b4; +} +.btn-info:active, .btn-info.active { + background-color: #24748c \9; +} +.btn-inverse { + background-color: #393939; + background-image: -moz-linear-gradient(top, #454545, #262626); + background-image: -ms-linear-gradient(top, #454545, #262626); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#454545), to(#262626)); + background-image: -webkit-linear-gradient(top, #454545, #262626); + background-image: -o-linear-gradient(top, #454545, #262626); + background-image: linear-gradient(top, #454545, #262626); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#454545', endColorstr='#262626', GradientType=0); + border-color: #262626 #262626 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-inverse:hover, +.btn-inverse:active, +.btn-inverse.active, +.btn-inverse.disabled, +.btn-inverse[disabled] { + background-color: #262626; +} +.btn-inverse:active, .btn-inverse.active { + background-color: #0c0c0c \9; +} +button.btn, input[type="submit"].btn { + *padding-top: 2px; + *padding-bottom: 2px; +} +button.btn::-moz-focus-inner, input[type="submit"].btn::-moz-focus-inner { + padding: 0; + border: 0; +} +button.btn.large, input[type="submit"].btn.large { + *padding-top: 7px; + *padding-bottom: 7px; +} +button.btn.small, input[type="submit"].btn.small { + *padding-top: 3px; + *padding-bottom: 3px; +} +.btn-group { + position: relative; + *zoom: 1; + *margin-left: .3em; +} +.btn-group:before, .btn-group:after { + display: table; + content: ""; +} +.btn-group:after { + clear: both; +} +.btn-group:first-child { + *margin-left: 0; +} +.btn-group + .btn-group { + margin-left: 5px; +} +.btn-toolbar { + margin-top: 9px; + margin-bottom: 9px; +} +.btn-toolbar .btn-group { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; +} +.btn-group .btn { + position: relative; + float: left; + margin-left: -1px; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.btn-group .btn:first-child { + margin-left: 0; + -webkit-border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; + border-top-left-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + border-bottom-left-radius: 4px; +} +.btn-group .btn:last-child, .btn-group .dropdown-toggle { + -webkit-border-top-right-radius: 4px; + -moz-border-radius-topright: 4px; + border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -moz-border-radius-bottomright: 4px; + border-bottom-right-radius: 4px; +} +.btn-group .btn.large:first-child { + margin-left: 0; + -webkit-border-top-left-radius: 6px; + -moz-border-radius-topleft: 6px; + border-top-left-radius: 6px; + -webkit-border-bottom-left-radius: 6px; + -moz-border-radius-bottomleft: 6px; + border-bottom-left-radius: 6px; +} +.btn-group .btn.large:last-child, .btn-group .large.dropdown-toggle { + -webkit-border-top-right-radius: 6px; + -moz-border-radius-topright: 6px; + border-top-right-radius: 6px; + -webkit-border-bottom-right-radius: 6px; + -moz-border-radius-bottomright: 6px; + border-bottom-right-radius: 6px; +} +.btn-group .btn:hover, +.btn-group .btn:focus, +.btn-group .btn:active, +.btn-group .btn.active { + z-index: 2; +} +.btn-group .dropdown-toggle:active, .btn-group.open .dropdown-toggle { + outline: 0; +} +.btn-group .dropdown-toggle { + padding-left: 8px; + padding-right: 8px; + -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + *padding-top: 5px; + *padding-bottom: 5px; +} +.btn-group.open { + *z-index: 1000; +} +.btn-group.open .dropdown-menu { + display: block; + margin-top: 1px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.btn-group.open .dropdown-toggle { + background-image: none; + -webkit-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); +} +.btn .caret { + margin-top: 7px; + margin-left: 0; +} +.btn:hover .caret, .open.btn-group .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.btn-primary .caret, +.btn-danger .caret, +.btn-info .caret, +.btn-success .caret, +.btn-inverse .caret { + border-top-color: #ffffff; + opacity: 0.75; + filter: alpha(opacity=75); +} +.btn-small .caret { + margin-top: 4px; +} +.alert { + padding: 8px 35px 8px 14px; + margin-bottom: 18px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + background-color: #fcf8e3; + border: 1px solid #fbeed5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.alert, .alert-heading { + color: #c09853; +} +.alert .close { + position: relative; + top: -2px; + right: -21px; + line-height: 18px; +} +.alert-success { + background-color: #dff0d8; + border-color: #d6e9c6; +} +.alert-success, .alert-success .alert-heading { + color: #468847; +} +.alert-danger, .alert-error { + background-color: #f2dede; + border-color: #eed3d7; +} +.alert-danger, +.alert-error, +.alert-danger .alert-heading, +.alert-error .alert-heading { + color: #b94a48; +} +.alert-info { + background-color: #d9edf7; + border-color: #bce8f1; +} +.alert-info, .alert-info .alert-heading { + color: #3a87ad; +} +.alert-block { + padding-top: 14px; + padding-bottom: 14px; +} +.alert-block > p, .alert-block > ul { + margin-bottom: 0; +} +.alert-block p + p { + margin-top: 5px; +} +.nav { + margin-left: 0; + margin-bottom: 18px; + list-style: none; +} +.nav > li > a { + display: block; +} +.nav > li > a:hover { + text-decoration: none; + background-color: #eeeeee; +} +.nav .nav-header { + display: block; + padding: 3px 15px; + font-size: 11px; + font-weight: bold; + line-height: 18px; + color: #999999; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + text-transform: uppercase; +} +.nav li + .nav-header { + margin-top: 9px; +} +.nav-list { + padding-left: 14px; + padding-right: 14px; + margin-bottom: 0; +} +.nav-list > li > a, .nav-list .nav-header { + margin-left: -15px; + margin-right: -15px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); +} +.nav-list > li > a { + padding: 3px 15px; +} +.nav-list .active > a, .nav-list .active > a:hover { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); + background-color: #0088cc; +} +.nav-list [class^="icon-"] { + margin-right: 2px; +} +.nav-tabs, .nav-pills { + *zoom: 1; +} +.nav-tabs:before, +.nav-pills:before, +.nav-tabs:after, +.nav-pills:after { + display: table; + content: ""; +} +.nav-tabs:after, .nav-pills:after { + clear: both; +} +.nav-tabs > li, .nav-pills > li { + float: left; +} +.nav-tabs > li > a, .nav-pills > li > a { + padding-right: 12px; + padding-left: 12px; + margin-right: 2px; + line-height: 14px; +} +.nav-tabs { + border-bottom: 1px solid #ddd; +} +.nav-tabs > li { + margin-bottom: -1px; +} +.nav-tabs > li > a { + padding-top: 9px; + padding-bottom: 9px; + border: 1px solid transparent; + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} +.nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #dddddd; +} +.nav-tabs > .active > a, .nav-tabs > .active > a:hover { + color: #555555; + background-color: #ffffff; + border: 1px solid #ddd; + border-bottom-color: transparent; + cursor: default; +} +.nav-pills > li > a { + padding-top: 8px; + padding-bottom: 8px; + margin-top: 2px; + margin-bottom: 2px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.nav-pills .active > a, .nav-pills .active > a:hover { + color: #ffffff; + background-color: #0088cc; +} +.nav-stacked > li { + float: none; +} +.nav-stacked > li > a { + margin-right: 0; +} +.nav-tabs.nav-stacked { + border-bottom: 0; +} +.nav-tabs.nav-stacked > li > a { + border: 1px solid #ddd; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.nav-tabs.nav-stacked > li:first-child > a { + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} +.nav-tabs.nav-stacked > li:last-child > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} +.nav-tabs.nav-stacked > li > a:hover { + border-color: #ddd; + z-index: 2; +} +.nav-pills.nav-stacked > li > a { + margin-bottom: 3px; +} +.nav-pills.nav-stacked > li:last-child > a { + margin-bottom: 1px; +} +.nav-tabs .dropdown-menu, .nav-pills .dropdown-menu { + margin-top: 1px; + border-width: 1px; +} +.nav-pills .dropdown-menu { + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.nav-tabs .dropdown-toggle .caret, .nav-pills .dropdown-toggle .caret { + border-top-color: #0088cc; + margin-top: 6px; +} +.nav-tabs .dropdown-toggle:hover .caret, .nav-pills .dropdown-toggle:hover .caret { + border-top-color: #005580; +} +.nav-tabs .active .dropdown-toggle .caret, .nav-pills .active .dropdown-toggle .caret { + border-top-color: #333333; +} +.nav > .dropdown.active > a:hover { + color: #000000; + cursor: pointer; +} +.nav-tabs .open .dropdown-toggle, .nav-pills .open .dropdown-toggle, .nav > .open.active > a:hover { + color: #ffffff; + background-color: #999999; + border-color: #999999; +} +.nav .open .caret, .nav .open.active .caret, .nav .open a:hover .caret { + border-top-color: #ffffff; + opacity: 1; + filter: alpha(opacity=100); +} +.tabs-stacked .open > a:hover { + border-color: #999999; +} +.tabbable { + *zoom: 1; +} +.tabbable:before, .tabbable:after { + display: table; + content: ""; +} +.tabbable:after { + clear: both; +} +.tab-content { + overflow: hidden; +} +.tabs-below .nav-tabs, .tabs-right .nav-tabs, .tabs-left .nav-tabs { + border-bottom: 0; +} +.tab-content > .tab-pane, .pill-content > .pill-pane { + display: none; +} +.tab-content > .active, .pill-content > .active { + display: block; +} +.tabs-below .nav-tabs { + border-top: 1px solid #ddd; +} +.tabs-below .nav-tabs > li { + margin-top: -1px; + margin-bottom: 0; +} +.tabs-below .nav-tabs > li > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} +.tabs-below .nav-tabs > li > a:hover { + border-bottom-color: transparent; + border-top-color: #ddd; +} +.tabs-below .nav-tabs .active > a, .tabs-below .nav-tabs .active > a:hover { + border-color: transparent #ddd #ddd #ddd; +} +.tabs-left .nav-tabs > li, .tabs-right .nav-tabs > li { + float: none; +} +.tabs-left .nav-tabs > li > a, .tabs-right .nav-tabs > li > a { + min-width: 74px; + margin-right: 0; + margin-bottom: 3px; +} +.tabs-left .nav-tabs { + float: left; + margin-right: 19px; + border-right: 1px solid #ddd; +} +.tabs-left .nav-tabs > li > a { + margin-right: -1px; + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} +.tabs-left .nav-tabs > li > a:hover { + border-color: #eeeeee #dddddd #eeeeee #eeeeee; +} +.tabs-left .nav-tabs .active > a, .tabs-left .nav-tabs .active > a:hover { + border-color: #ddd transparent #ddd #ddd; + *border-right-color: #ffffff; +} +.tabs-right .nav-tabs { + float: right; + margin-left: 19px; + border-left: 1px solid #ddd; +} +.tabs-right .nav-tabs > li > a { + margin-left: -1px; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} +.tabs-right .nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #eeeeee #dddddd; +} +.tabs-right .nav-tabs .active > a, .tabs-right .nav-tabs .active > a:hover { + border-color: #ddd #ddd #ddd transparent; + *border-left-color: #ffffff; +} +.navbar { + overflow: visible; + margin-bottom: 18px; +} +.navbar-inner { + padding-left: 20px; + padding-right: 20px; + background-color: #2c2c2c; + background-image: -moz-linear-gradient(top, #333333, #222222); + background-image: -ms-linear-gradient(top, #333333, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); + background-image: -webkit-linear-gradient(top, #333333, #222222); + background-image: -o-linear-gradient(top, #333333, #222222); + background-image: linear-gradient(top, #333333, #222222); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); +} +.btn-navbar { + display: none; + float: right; + padding: 7px 10px; + margin-left: 5px; + margin-right: 5px; + background-color: #2c2c2c; + background-image: -moz-linear-gradient(top, #333333, #222222); + background-image: -ms-linear-gradient(top, #333333, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); + background-image: -webkit-linear-gradient(top, #333333, #222222); + background-image: -o-linear-gradient(top, #333333, #222222); + background-image: linear-gradient(top, #333333, #222222); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); + border-color: #222222 #222222 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); +} +.btn-navbar:hover, +.btn-navbar:active, +.btn-navbar.active, +.btn-navbar.disabled, +.btn-navbar[disabled] { + background-color: #222222; +} +.btn-navbar:active, .btn-navbar.active { + background-color: #080808 \9; +} +.btn-navbar .icon-bar { + display: block; + width: 18px; + height: 2px; + background-color: #f5f5f5; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; + -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); +} +.btn-navbar .icon-bar + .icon-bar { + margin-top: 3px; +} +.nav-collapse.collapse { + height: auto; +} +.navbar .brand:hover { + text-decoration: none; +} +.navbar .brand { + float: left; + display: block; + padding: 8px 20px 12px; + margin-left: -20px; + font-size: 20px; + font-weight: 200; + line-height: 1; + color: #ffffff; +} +.navbar .navbar-text { + margin-bottom: 0; + line-height: 40px; + color: #999999; +} +.navbar .navbar-text a:hover { + color: #ffffff; + background-color: transparent; +} +.navbar .btn, .navbar .btn-group { + margin-top: 5px; +} +.navbar .btn-group .btn { + margin-top: 0; +} +.navbar-form { + margin-bottom: 0; + *zoom: 1; +} +.navbar-form:before, .navbar-form:after { + display: table; + content: ""; +} +.navbar-form:after { + clear: both; +} +.navbar-form input, .navbar-form select { + display: inline-block; + margin-top: 5px; + margin-bottom: 0; +} +.navbar-form .radio, .navbar-form .checkbox { + margin-top: 5px; +} +.navbar-form input[type="image"], .navbar-form input[type="checkbox"], .navbar-form input[type="radio"] { + margin-top: 3px; +} +.navbar-form .input-append, .navbar-form .input-prepend { + margin-top: 6px; + white-space: nowrap; +} +.navbar-form .input-append input, .navbar-form .input-prepend input { + margin-top: 0; +} +.navbar-search { + position: relative; + float: left; + margin-top: 6px; + margin-bottom: 0; +} +.navbar-search .search-query { + padding: 4px 9px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + font-weight: normal; + line-height: 1; + color: #ffffff; + color: rgba(255, 255, 255, 0.75); + background: #666; + background: rgba(255, 255, 255, 0.3); + border: 1px solid #111; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + -webkit-transition: none; + -moz-transition: none; + -ms-transition: none; + -o-transition: none; + transition: none; +} +.navbar-search .search-query :-moz-placeholder { + color: #eeeeee; +} +.navbar-search .search-query::-webkit-input-placeholder { + color: #eeeeee; +} +.navbar-search .search-query:hover { + color: #ffffff; + background-color: #999999; + background-color: rgba(255, 255, 255, 0.5); +} +.navbar-search .search-query:focus, .navbar-search .search-query.focused { + padding: 5px 10px; + color: #333333; + text-shadow: 0 1px 0 #ffffff; + background-color: #ffffff; + border: 0; + -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + outline: 0; +} +.navbar-fixed-top { + position: fixed; + top: 0; + right: 0; + left: 0; + z-index: 1030; +} +.navbar-fixed-top .navbar-inner { + padding-left: 0; + padding-right: 0; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.navbar .nav { + position: relative; + left: 0; + display: block; + float: left; + margin: 0 10px 0 0; +} +.navbar .nav.pull-right { + float: right; +} +.navbar .nav > li { + display: block; + float: left; +} +.navbar .nav > li > a { + float: none; + padding: 10px 10px 11px; + line-height: 19px; + color: #999999; + text-decoration: none; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.navbar .nav > li > a:hover { + background-color: transparent; + color: #ffffff; + text-decoration: none; +} +.navbar .nav .active > a, .navbar .nav .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #222222; +} +.navbar .divider-vertical { + height: 40px; + width: 1px; + margin: 0 9px; + overflow: hidden; + background-color: #222222; + border-right: 1px solid #333333; +} +.navbar .nav.pull-right { + margin-left: 10px; + margin-right: 0; +} +.navbar .dropdown-menu { + margin-top: 1px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.navbar .dropdown-menu:before { + content: ''; + display: inline-block; + border-left: 7px solid transparent; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-bottom-color: rgba(0, 0, 0, 0.2); + position: absolute; + top: -7px; + left: 9px; +} +.navbar .dropdown-menu:after { + content: ''; + display: inline-block; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid #ffffff; + position: absolute; + top: -6px; + left: 10px; +} +.navbar .nav .dropdown-toggle .caret, .navbar .nav .open.dropdown .caret { + border-top-color: #ffffff; +} +.navbar .nav .active .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.navbar .nav .open > .dropdown-toggle, .navbar .nav .active > .dropdown-toggle, .navbar .nav .open.active > .dropdown-toggle { + background-color: transparent; +} +.navbar .nav .active > .dropdown-toggle:hover { + color: #ffffff; +} +.navbar .nav.pull-right .dropdown-menu { + left: auto; + right: 0; +} +.navbar .nav.pull-right .dropdown-menu:before { + left: auto; + right: 12px; +} +.navbar .nav.pull-right .dropdown-menu:after { + left: auto; + right: 13px; +} +.breadcrumb { + padding: 7px 14px; + margin: 0 0 18px; + background-color: #fbfbfb; + background-image: -moz-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -ms-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5)); + background-image: -webkit-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -o-linear-gradient(top, #ffffff, #f5f5f5); + background-image: linear-gradient(top, #ffffff, #f5f5f5); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0); + border: 1px solid #ddd; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; +} +.breadcrumb li { + display: inline-block; + text-shadow: 0 1px 0 #ffffff; +} +.breadcrumb .divider { + padding: 0 5px; + color: #999999; +} +.breadcrumb .active a { + color: #333333; +} +.pagination { + height: 36px; + margin: 18px 0; +} +.pagination ul { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; + margin-left: 0; + margin-bottom: 0; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); +} +.pagination li { + display: inline; +} +.pagination a { + float: left; + padding: 0 14px; + line-height: 34px; + text-decoration: none; + border: 1px solid #ddd; + border-left-width: 0; +} +.pagination a:hover, .pagination .active a { + background-color: #f5f5f5; +} +.pagination .active a { + color: #999999; + cursor: default; +} +.pagination .disabled a, .pagination .disabled a:hover { + color: #999999; + background-color: transparent; + cursor: default; +} +.pagination li:first-child a { + border-left-width: 1px; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.pagination li:last-child a { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.pagination-centered { + text-align: center; +} +.pagination-right { + text-align: right; +} +.pager { + margin-left: 0; + margin-bottom: 18px; + list-style: none; + text-align: center; + *zoom: 1; +} +.pager:before, .pager:after { + display: table; + content: ""; +} +.pager:after { + clear: both; +} +.pager li { + display: inline; +} +.pager a { + display: inline-block; + padding: 5px 14px; + background-color: #fff; + border: 1px solid #ddd; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} +.pager a:hover { + text-decoration: none; + background-color: #f5f5f5; +} +.pager .next a { + float: right; +} +.pager .previous a { + float: left; +} +.modal-open .dropdown-menu { + z-index: 2050; +} +.modal-open .dropdown.open { + *z-index: 2050; +} +.modal-open .popover { + z-index: 2060; +} +.modal-open .tooltip { + z-index: 2070; +} +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + background-color: #000000; +} +.modal-backdrop.fade { + opacity: 0; +} +.modal-backdrop, .modal-backdrop.fade.in { + opacity: 0.8; + filter: alpha(opacity=80); +} +.modal { + position: fixed; + top: 50%; + left: 50%; + z-index: 1050; + max-height: 500px; + overflow: auto; + width: 560px; + margin: -250px 0 0 -280px; + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + /* IE6-7 */ + + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.wide-modal { + position: fixed; + top: 5%; + left: 5%; + z-index: 1050; + max-height: 90%; + overflow: auto; + width: 90%; + /*margin: -50px 0 0 -80px;*/ + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + /* IE6-7 */ + + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.modal.fade { + -webkit-transition: opacity .3s linear, top .3s ease-out; + -moz-transition: opacity .3s linear, top .3s ease-out; + -ms-transition: opacity .3s linear, top .3s ease-out; + -o-transition: opacity .3s linear, top .3s ease-out; + transition: opacity .3s linear, top .3s ease-out; + top: -25%; +} +.modal.fade.in { + top: 50%; +} +.modal-header { + padding: 9px 15px; + border-bottom: 1px solid #eee; +} +.modal-header .close { + margin-top: 2px; +} +.modal-body { + padding: 15px; +} +.modal-body .modal-form { + margin-bottom: 0; +} +.modal-footer { + padding: 14px 15px 15px; + margin-bottom: 0; + background-color: #f5f5f5; + border-top: 1px solid #ddd; + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; + *zoom: 1; +} +.modal-footer:before, .modal-footer:after { + display: table; + content: ""; +} +.modal-footer:after { + clear: both; +} +.modal-footer .btn { + float: right; + margin-left: 5px; + margin-bottom: 0; +} +.tooltip { + position: absolute; + z-index: 1020; + display: block; + visibility: visible; + padding: 5px; + font-size: 11px; + opacity: 0; + filter: alpha(opacity=0); +} +.tooltip.in { + opacity: 0.8; + filter: alpha(opacity=80); +} +.tooltip.top { + margin-top: -2px; +} +.tooltip.right { + margin-left: 2px; +} +.tooltip.bottom { + margin-top: 2px; +} +.tooltip.left { + margin-left: -2px; +} +.tooltip.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid #000000; +} +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #000000; +} +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-bottom: 5px solid #000000; +} +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-right: 5px solid #000000; +} +.tooltip-inner { + max-width: 200px; + padding: 3px 8px; + color: #ffffff; + text-align: center; + text-decoration: none; + background-color: #000000; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; +} +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1010; + display: none; + padding: 5px; +} +.popover.top { + margin-top: -5px; +} +.popover.right { + margin-left: 5px; +} +.popover.bottom { + margin-top: 5px; +} +.popover.left { + margin-left: -5px; +} +.popover.top .arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid #000000; +} +.popover.right .arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-right: 5px solid #000000; +} +.popover.bottom .arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-bottom: 5px solid #000000; +} +.popover.left .arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #000000; +} +.popover .arrow { + position: absolute; + width: 0; + height: 0; +} +.popover-inner { + padding: 3px; + width: 280px; + overflow: hidden; + background: #000000; + background: rgba(0, 0, 0, 0.8); + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); +} +.popover-title { + padding: 9px 15px; + line-height: 1; + background-color: #f5f5f5; + border-bottom: 1px solid #eee; + -webkit-border-radius: 3px 3px 0 0; + -moz-border-radius: 3px 3px 0 0; + border-radius: 3px 3px 0 0; +} +.popover-content { + padding: 14px; + background-color: #ffffff; + -webkit-border-radius: 0 0 3px 3px; + -moz-border-radius: 0 0 3px 3px; + border-radius: 0 0 3px 3px; + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.popover-content p, .popover-content ul, .popover-content ol { + margin-bottom: 0; +} +.thumbnails { + margin-left: -20px; + list-style: none; + *zoom: 1; +} +.thumbnails:before, .thumbnails:after { + display: table; + content: ""; +} +.thumbnails:after { + clear: both; +} +.thumbnails > li { + float: left; + margin: 0 0 18px 20px; +} +.thumbnail { + display: block; + padding: 4px; + line-height: 1; + border: 1px solid #ddd; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); +} +a.thumbnail:hover { + border-color: #0088cc; + -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); +} +.thumbnail > img { + display: block; + max-width: 100%; + margin-left: auto; + margin-right: auto; +} +.thumbnail .caption { + padding: 9px; +} +.label { + padding: 2px 4px 3px; + font-size: 11.049999999999999px; + font-weight: bold; + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #999999; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.label:hover { + color: #ffffff; + text-decoration: none; +} +.label-important { + background-color: #b94a48; +} +.label-important:hover { + background-color: #953b39; +} +.label-warning { + background-color: #f89406; +} +.label-warning:hover { + background-color: #c67605; +} +.label-success { + background-color: #468847; +} +.label-success:hover { + background-color: #356635; +} +.label-info { + background-color: #3a87ad; +} +.label-info:hover { + background-color: #2d6987; +} +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +@-moz-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +@keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +.progress { + overflow: hidden; + height: 18px; + margin-bottom: 18px; + background-color: #f7f7f7; + background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -ms-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9)); + background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: linear-gradient(top, #f5f5f5, #f9f9f9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0); + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.progress .bar { + width: 0%; + height: 18px; + color: #ffffff; + font-size: 12px; + text-align: center; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #0e90d2; + background-image: -moz-linear-gradient(top, #149bdf, #0480be); + background-image: -ms-linear-gradient(top, #149bdf, #0480be); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be)); + background-image: -webkit-linear-gradient(top, #149bdf, #0480be); + background-image: -o-linear-gradient(top, #149bdf, #0480be); + background-image: linear-gradient(top, #149bdf, #0480be); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0); + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition: width 0.6s ease; + -moz-transition: width 0.6s ease; + -ms-transition: width 0.6s ease; + -o-transition: width 0.6s ease; + transition: width 0.6s ease; +} +.progress-striped .bar { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + -webkit-background-size: 40px 40px; + -moz-background-size: 40px 40px; + -o-background-size: 40px 40px; + background-size: 40px 40px; +} +.progress.active .bar { + -webkit-animation: progress-bar-stripes 2s linear infinite; + -moz-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} +.progress-danger .bar { + background-color: #dd514c; + background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -o-linear-gradient(top, #ee5f5b, #c43c35); + background-image: linear-gradient(top, #ee5f5b, #c43c35); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0); +} +.progress-danger.progress-striped .bar { + background-color: #ee5f5b; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-success .bar { + background-color: #5eb95e; + background-image: -moz-linear-gradient(top, #62c462, #57a957); + background-image: -ms-linear-gradient(top, #62c462, #57a957); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957)); + background-image: -webkit-linear-gradient(top, #62c462, #57a957); + background-image: -o-linear-gradient(top, #62c462, #57a957); + background-image: linear-gradient(top, #62c462, #57a957); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0); +} +.progress-success.progress-striped .bar { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-info .bar { + background-color: #4bb1cf; + background-image: -moz-linear-gradient(top, #5bc0de, #339bb9); + background-image: -ms-linear-gradient(top, #5bc0de, #339bb9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9)); + background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9); + background-image: -o-linear-gradient(top, #5bc0de, #339bb9); + background-image: linear-gradient(top, #5bc0de, #339bb9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0); +} +.progress-info.progress-striped .bar { + background-color: #5bc0de; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.accordion { + margin-bottom: 18px; +} +.accordion-group { + margin-bottom: 2px; + border: 1px solid #e5e5e5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.accordion-heading { + border-bottom: 0; +} +.accordion-heading .accordion-toggle { + display: block; + padding: 8px 15px; +} +.accordion-inner { + padding: 9px 15px; + border-top: 1px solid #e5e5e5; +} +.carousel { + position: relative; + margin-bottom: 18px; + line-height: 1; +} +.carousel-inner { + overflow: hidden; + width: 100%; + position: relative; +} +.carousel .item { + display: none; + position: relative; + -webkit-transition: 0.6s ease-in-out left; + -moz-transition: 0.6s ease-in-out left; + -ms-transition: 0.6s ease-in-out left; + -o-transition: 0.6s ease-in-out left; + transition: 0.6s ease-in-out left; +} +.carousel .item > img { + display: block; + line-height: 1; +} +.carousel .active, .carousel .next, .carousel .prev { + display: block; +} +.carousel .active { + left: 0; +} +.carousel .next, .carousel .prev { + position: absolute; + top: 0; + width: 100%; +} +.carousel .next { + left: 100%; +} +.carousel .prev { + left: -100%; +} +.carousel .next.left, .carousel .prev.right { + left: 0; +} +.carousel .active.left { + left: -100%; +} +.carousel .active.right { + left: 100%; +} +.carousel-control { + position: absolute; + top: 40%; + left: 15px; + width: 40px; + height: 40px; + margin-top: -20px; + font-size: 60px; + font-weight: 100; + line-height: 30px; + color: #ffffff; + text-align: center; + background: #222222; + border: 3px solid #ffffff; + -webkit-border-radius: 23px; + -moz-border-radius: 23px; + border-radius: 23px; + opacity: 0.5; + filter: alpha(opacity=50); +} +.carousel-control.right { + left: auto; + right: 15px; +} +.carousel-control:hover { + color: #ffffff; + text-decoration: none; + opacity: 0.9; + filter: alpha(opacity=90); +} +.carousel-caption { + position: absolute; + left: 0; + right: 0; + bottom: 0; + padding: 10px 15px 5px; + background: #333333; + background: rgba(0, 0, 0, 0.75); +} +.carousel-caption h4, .carousel-caption p { + color: #ffffff; +} +.hero-unit { + padding: 60px; + margin-bottom: 30px; + background-color: #f5f5f5; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} +.hero-unit h1 { + margin-bottom: 0; + font-size: 60px; + line-height: 1; + letter-spacing: -1px; +} +.hero-unit p { + font-size: 18px; + font-weight: 200; + line-height: 27px; +} +.pull-right { + float: right; +} +.pull-left { + float: left; +} +.hide { + display: none; +} +.show { + display: block; +} +.invisible { + visibility: hidden; +} diff --git a/src/nl/astraeus/jdbc/web/resources/images/loading.gif b/src/nl/astraeus/jdbc/web/resources/images/loading.gif new file mode 100644 index 0000000..21c7e74 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/images/loading.gif Binary files differ diff --git a/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png b/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png new file mode 100644 index 0000000..92d4445 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png Binary files differ diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-alert.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-alert.js new file mode 100644 index 0000000..2242ddd --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-alert.js @@ -0,0 +1,94 @@ +/* ========================================================== + * bootstrap-alert.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#alerts + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function( $ ){ + + "use strict" + + /* ALERT CLASS DEFINITION + * ====================== */ + + var dismiss = '[data-dismiss="alert"]' + , Alert = function ( el ) { + $(el).on('click', dismiss, this.close) + } + + Alert.prototype = { + + constructor: Alert + + , close: function ( e ) { + var $this = $(this) + , selector = $this.attr('data-target') + , $parent + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = $(selector) + $parent.trigger('close') + + e && e.preventDefault() + + $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent()) + + $parent + .trigger('close') + .removeClass('in') + + function removeElement() { + $parent + .trigger('closed') + .remove() + } + + $.support.transition && $parent.hasClass('fade') ? + $parent.on($.support.transition.end, removeElement) : + removeElement() + } + + } + + + /* ALERT PLUGIN DEFINITION + * ======================= */ + + $.fn.alert = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('alert') + if (!data) $this.data('alert', (data = new Alert(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.alert.Constructor = Alert + + + /* ALERT DATA-API + * ============== */ + + $(function () { + $('body').on('click.alert.data-api', dismiss, Alert.prototype.close) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-button.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-button.js new file mode 100644 index 0000000..0238ca3 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-button.js @@ -0,0 +1,100 @@ +/* ============================================================ + * bootstrap-button.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#buttons + * ============================================================ + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + +!function( $ ){ + + "use strict" + + /* BUTTON PUBLIC CLASS DEFINITION + * ============================== */ + + var Button = function ( element, options ) { + this.$element = $(element) + this.options = $.extend({}, $.fn.button.defaults, options) + } + + Button.prototype = { + + constructor: Button + + , setState: function ( state ) { + var d = 'disabled' + , $el = this.$element + , data = $el.data() + , val = $el.is('input') ? 'val' : 'html' + + state = state + 'Text' + data.resetText || $el.data('resetText', $el[val]()) + + $el[val](data[state] || this.options[state]) + + // push to event loop to allow forms to submit + setTimeout(function () { + state == 'loadingText' ? + $el.addClass(d).attr(d, d) : + $el.removeClass(d).removeAttr(d) + }, 0) + } + + , toggle: function () { + var $parent = this.$element.parent('[data-toggle="buttons-radio"]') + + $parent && $parent + .find('.active') + .removeClass('active') + + this.$element.toggleClass('active') + } + + } + + + /* BUTTON PLUGIN DEFINITION + * ======================== */ + + $.fn.button = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('button') + , options = typeof option == 'object' && option + if (!data) $this.data('button', (data = new Button(this, options))) + if (option == 'toggle') data.toggle() + else if (option) data.setState(option) + }) + } + + $.fn.button.defaults = { + loadingText: 'loading...' + } + + $.fn.button.Constructor = Button + + + /* BUTTON DATA-API + * =============== */ + + $(function () { + $('body').on('click.button.data-api', '[data-toggle^=button]', function ( e ) { + var $btn = $(e.target) + if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') + $btn.button('toggle') + }) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-carousel.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-carousel.js new file mode 100644 index 0000000..810256e --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-carousel.js @@ -0,0 +1,157 @@ +/* ========================================================== + * bootstrap-carousel.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#carousel + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function( $ ){ + + "use strict" + + /* CAROUSEL CLASS DEFINITION + * ========================= */ + + var Carousel = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, $.fn.carousel.defaults, options) + this.options.slide && this.slide(this.options.slide) + } + + Carousel.prototype = { + + cycle: function () { + this.interval = setInterval($.proxy(this.next, this), this.options.interval) + return this + } + + , to: function (pos) { + var $active = this.$element.find('.active') + , children = $active.parent().children() + , activePos = children.index($active) + , that = this + + if (pos > (children.length - 1) || pos < 0) return + + if (this.sliding) { + return this.$element.one('slid', function () { + that.to(pos) + }) + } + + if (activePos == pos) { + return this.pause().cycle() + } + + return this.slide(pos > activePos ? 'next' : 'prev', $(children[pos])) + } + + , pause: function () { + clearInterval(this.interval) + this.interval = null + return this + } + + , next: function () { + if (this.sliding) return + return this.slide('next') + } + + , prev: function () { + if (this.sliding) return + return this.slide('prev') + } + + , slide: function (type, next) { + var $active = this.$element.find('.active') + , $next = next || $active[type]() + , isCycling = this.interval + , direction = type == 'next' ? 'left' : 'right' + , fallback = type == 'next' ? 'first' : 'last' + , that = this + + if (!$next.length) return + + this.sliding = true + + isCycling && this.pause() + + $next = $next.length ? $next : this.$element.find('.item')[fallback]() + + if (!$.support.transition && this.$element.hasClass('slide')) { + this.$element.trigger('slide') + $active.removeClass('active') + $next.addClass('active') + this.sliding = false + this.$element.trigger('slid') + } else { + $next.addClass(type) + $next[0].offsetWidth // force reflow + $active.addClass(direction) + $next.addClass(direction) + this.$element.trigger('slide') + this.$element.one($.support.transition.end, function () { + $next.removeClass([type, direction].join(' ')).addClass('active') + $active.removeClass(['active', direction].join(' ')) + that.sliding = false + setTimeout(function () { that.$element.trigger('slid') }, 0) + }) + } + + isCycling && this.cycle() + + return this + } + + } + + + /* CAROUSEL PLUGIN DEFINITION + * ========================== */ + + $.fn.carousel = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('carousel') + , options = typeof option == 'object' && option + if (!data) $this.data('carousel', (data = new Carousel(this, options))) + if (typeof option == 'number') data.to(option) + else if (typeof option == 'string' || (option = options.slide)) data[option]() + else data.cycle() + }) + } + + $.fn.carousel.defaults = { + interval: 5000 + } + + $.fn.carousel.Constructor = Carousel + + + /* CAROUSEL DATA-API + * ================= */ + + $(function () { + $('body').on('click.carousel.data-api', '[data-slide]', function ( e ) { + var $this = $(this), href + , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 + , options = !$target.data('modal') && $.extend({}, $target.data(), $this.data()) + $target.carousel(options) + e.preventDefault() + }) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-collapse.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-collapse.js new file mode 100644 index 0000000..d195efc --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-collapse.js @@ -0,0 +1,136 @@ +/* ============================================================= + * bootstrap-collapse.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#collapse + * ============================================================= + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + +!function( $ ){ + + "use strict" + + var Collapse = function ( element, options ) { + this.$element = $(element) + this.options = $.extend({}, $.fn.collapse.defaults, options) + + if (this.options["parent"]) { + this.$parent = $(this.options["parent"]) + } + + this.options.toggle && this.toggle() + } + + Collapse.prototype = { + + constructor: Collapse + + , dimension: function () { + var hasWidth = this.$element.hasClass('width') + return hasWidth ? 'width' : 'height' + } + + , show: function () { + var dimension = this.dimension() + , scroll = $.camelCase(['scroll', dimension].join('-')) + , actives = this.$parent && this.$parent.find('.in') + , hasData + + if (actives && actives.length) { + hasData = actives.data('collapse') + actives.collapse('hide') + hasData || actives.data('collapse', null) + } + + this.$element[dimension](0) + this.transition('addClass', 'show', 'shown') + this.$element[dimension](this.$element[0][scroll]) + + } + + , hide: function () { + var dimension = this.dimension() + this.reset(this.$element[dimension]()) + this.transition('removeClass', 'hide', 'hidden') + this.$element[dimension](0) + } + + , reset: function ( size ) { + var dimension = this.dimension() + + this.$element + .removeClass('collapse') + [dimension](size || 'auto') + [0].offsetWidth + + this.$element.addClass('collapse') + } + + , transition: function ( method, startEvent, completeEvent ) { + var that = this + , complete = function () { + if (startEvent == 'show') that.reset() + that.$element.trigger(completeEvent) + } + + this.$element + .trigger(startEvent) + [method]('in') + + $.support.transition && this.$element.hasClass('collapse') ? + this.$element.one($.support.transition.end, complete) : + complete() + } + + , toggle: function () { + this[this.$element.hasClass('in') ? 'hide' : 'show']() + } + + } + + /* COLLAPSIBLE PLUGIN DEFINITION + * ============================== */ + + $.fn.collapse = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('collapse') + , options = typeof option == 'object' && option + if (!data) $this.data('collapse', (data = new Collapse(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.collapse.defaults = { + toggle: true + } + + $.fn.collapse.Constructor = Collapse + + + /* COLLAPSIBLE DATA-API + * ==================== */ + + $(function () { + $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function ( e ) { + var $this = $(this), href + , target = $this.attr('data-target') + || e.preventDefault() + || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 + , option = $(target).data('collapse') ? 'toggle' : $this.data() + $(target).collapse(option) + }) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-dropdown.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-dropdown.js new file mode 100644 index 0000000..f1f6c33 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-dropdown.js @@ -0,0 +1,92 @@ +/* ============================================================ + * bootstrap-dropdown.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#dropdowns + * ============================================================ + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + + +!function( $ ){ + + "use strict" + + /* DROPDOWN CLASS DEFINITION + * ========================= */ + + var toggle = '[data-toggle="dropdown"]' + , Dropdown = function ( element ) { + var $el = $(element).on('click.dropdown.data-api', this.toggle) + $('html').on('click.dropdown.data-api', function () { + $el.parent().removeClass('open') + }) + } + + Dropdown.prototype = { + + constructor: Dropdown + + , toggle: function ( e ) { + var $this = $(this) + , selector = $this.attr('data-target') + , $parent + , isActive + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = $(selector) + $parent.length || ($parent = $this.parent()) + + isActive = $parent.hasClass('open') + + clearMenus() + !isActive && $parent.toggleClass('open') + + return false + } + + } + + function clearMenus() { + $(toggle).parent().removeClass('open') + } + + + /* DROPDOWN PLUGIN DEFINITION + * ========================== */ + + $.fn.dropdown = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('dropdown') + if (!data) $this.data('dropdown', (data = new Dropdown(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.dropdown.Constructor = Dropdown + + + /* APPLY TO STANDARD DROPDOWN ELEMENTS + * =================================== */ + + $(function () { + $('html').on('click.dropdown.data-api', clearMenus) + $('body').on('click.dropdown.data-api', toggle, Dropdown.prototype.toggle) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-modal.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-modal.js new file mode 100644 index 0000000..bceb303 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-modal.js @@ -0,0 +1,210 @@ +/* ========================================================= + * bootstrap-modal.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#modals + * ========================================================= + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================= */ + + +!function( $ ){ + + "use strict" + + /* MODAL CLASS DEFINITION + * ====================== */ + + var Modal = function ( content, options ) { + this.options = options + this.$element = $(content) + .delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this)) + } + + Modal.prototype = { + + constructor: Modal + + , toggle: function () { + return this[!this.isShown ? 'show' : 'hide']() + } + + , show: function () { + var that = this + + if (this.isShown) return + + $('body').addClass('modal-open') + + this.isShown = true + this.$element.trigger('show') + + escape.call(this) + backdrop.call(this, function () { + var transition = $.support.transition && that.$element.hasClass('fade') + + !that.$element.parent().length && that.$element.appendTo(document.body) //don't move modals dom position + + that.$element + .show() + + if (transition) { + that.$element[0].offsetWidth // force reflow + } + + that.$element.addClass('in') + + transition ? + that.$element.one($.support.transition.end, function () { that.$element.trigger('shown') }) : + that.$element.trigger('shown') + + }) + } + + , hide: function ( e ) { + e && e.preventDefault() + + if (!this.isShown) return + + var that = this + this.isShown = false + + $('body').removeClass('modal-open') + + escape.call(this) + + this.$element + .trigger('hide') + .removeClass('in') + + $.support.transition && this.$element.hasClass('fade') ? + hideWithTransition.call(this) : + hideModal.call(this) + } + + } + + + /* MODAL PRIVATE METHODS + * ===================== */ + + function hideWithTransition() { + var that = this + , timeout = setTimeout(function () { + that.$element.off($.support.transition.end) + hideModal.call(that) + }, 500) + + this.$element.one($.support.transition.end, function () { + clearTimeout(timeout) + hideModal.call(that) + }) + } + + function hideModal( that ) { + this.$element + .hide() + .trigger('hidden') + + backdrop.call(this) + } + + function backdrop( callback ) { + var that = this + , animate = this.$element.hasClass('fade') ? 'fade' : '' + + if (this.isShown && this.options.backdrop) { + var doAnimate = $.support.transition && animate + + this.$backdrop = $(' + + + + + \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/head.html b/src/nl/astraeus/jdbc/web/head.html new file mode 100644 index 0000000..0f8f6a3 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/head.html @@ -0,0 +1,96 @@ + + + + + + + Simple JDBC Statistics + + + + + + + + + + + + + + + + + + + +
+
+ +
+ diff --git a/src/nl/astraeus/jdbc/web/page/Menu.html b/src/nl/astraeus/jdbc/web/page/Menu.html new file mode 100644 index 0000000..505c7c2 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.html @@ -0,0 +1,42 @@ + diff --git a/src/nl/astraeus/jdbc/web/page/Menu.java b/src/nl/astraeus/jdbc/web/page/Menu.java new file mode 100644 index 0000000..f0a349a --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.java @@ -0,0 +1,27 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 9:07 PM + */ +public class Menu extends TemplatePage { + + @Override + public Page processRequest(HttpServletRequest request) { + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + result.put("user", request.getSession().getAttribute("user")); + + return result; + } +} diff --git a/src/nl/astraeus/jdbc/web/page/Page.java b/src/nl/astraeus/jdbc/web/page/Page.java new file mode 100644 index 0000000..9d526d6 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Page.java @@ -0,0 +1,17 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:20 PM + */ +public abstract class Page { + + public abstract Page processRequest(HttpServletRequest request); + public abstract Map defineModel(HttpServletRequest request); + public abstract String render(HttpServletRequest request); + +} diff --git a/src/nl/astraeus/jdbc/web/page/QueryOverview.html b/src/nl/astraeus/jdbc/web/page/QueryOverview.html new file mode 100644 index 0000000..64a88fb --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/QueryOverview.html @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + {foreach(queries as q)} + + + + + + + {eachend} + +
Total timeAvg. time# CallsSql
{q.total}{q.nano}{q.count}{q.sql}
diff --git a/src/nl/astraeus/jdbc/web/page/QueryOverview.java b/src/nl/astraeus/jdbc/web/page/QueryOverview.java new file mode 100644 index 0000000..02982f1 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/QueryOverview.java @@ -0,0 +1,92 @@ +package nl.astraeus.jdbc.web.page; + +import nl.astraeus.jdbc.JdbcLogger; + +import javax.servlet.http.HttpServletRequest; +import java.util.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 9:16 PM + */ +public class QueryOverview extends TemplatePage { + + boolean sortTotalCalls = true; + boolean sortAvgTime = false; + boolean sortTotalTime = false; + + @Override + public Page processRequest(HttpServletRequest request) { + if ("sortTotalCalls".equals(request.getParameter("action"))) { + sortTotalCalls = true; + sortAvgTime = false; + sortTotalTime = false; + } else if ("sortAvgTime".equals(request.getParameter("action"))) { + sortTotalCalls = false; + sortAvgTime = true; + sortTotalTime = false; + } else if ("sortTotalTime".equals(request.getParameter("action"))) { + sortTotalCalls = false; + sortAvgTime = false; + sortTotalTime = true; + } + + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + List entries = new ArrayList(JdbcLogger.get().getEntries()); + + if (sortTotalCalls) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + return o2.count - o1.count; + } + }); + } else if (sortAvgTime) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + long n1 = o1.nano / o1.count; + long n2 = o2.nano / o2.count; + + if (n2 > n1) { + return 1; + } else if (n2 < n1) { + return -1; + } else { + return 0; + } + } + }); + } else if (sortTotalTime) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + if (o2.nano > o1.nano) { + return 1; + } else if (o2.nano < o1.nano) { + return -1; + } else { + return 0; + } + } + }); + } + + result.put("queries", entries); + result.put("count", entries.size()); + + result.put("sortTotalCalls", sortTotalCalls); + result.put("sortAvgTime", sortAvgTime); + result.put("sortTotalTime", sortTotalTime); + + return result; + } + +} diff --git a/src/nl/astraeus/jdbc/web/page/TemplatePage.java b/src/nl/astraeus/jdbc/web/page/TemplatePage.java new file mode 100644 index 0000000..33e2641 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/TemplatePage.java @@ -0,0 +1,58 @@ +package nl.astraeus.jdbc.web.page; + +import nl.astraeus.template.EscapeMode; +import nl.astraeus.template.SimpleTemplate; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:20 PM + */ +public abstract class TemplatePage extends Page { + + private SimpleTemplate template; + + protected TemplatePage() { + template = getSimpleTemplate(this.getClass()); + } + + public String render(HttpServletRequest request) { + return template.render(defineModel(request)); + } + + private static Map templateCache = new HashMap(); + + public synchronized static SimpleTemplate getSimpleTemplate(Class cls) { + SimpleTemplate result = templateCache.get(cls); + + if (result == null) { + InputStream in = null; + + try { + in = cls.getResourceAsStream(cls.getSimpleName() + ".html"); + + result = SimpleTemplate.readTemplate('{','}', EscapeMode.HTML, in); + + templateCache.put(cls, result); + } catch (IOException e) { + throw new IllegalStateException(e); + } finally { + if (in != null) { + try { + in.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + + return result; + } +} diff --git a/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css b/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css new file mode 100644 index 0000000..0e0056f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css @@ -0,0 +1,581 @@ +/*! + * Bootstrap Responsive v2.0.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ +.clearfix { + *zoom: 1; +} +.clearfix:before, .clearfix:after { + display: table; + content: ""; +} +.clearfix:after { + clear: both; +} +.hidden { + display: none; + visibility: hidden; +} +@media (max-width: 480px) { + .nav-collapse { + -webkit-transform: translate3d(0, 0, 0); + } + .page-header h1 small { + display: block; + line-height: 18px; + } + input[class*="span"], + select[class*="span"], + textarea[class*="span"], + .uneditable-input { + display: block; + width: 100%; + min-height: 28px; + /* Make inputs at least the height of their button counterpart */ + + /* Makes inputs behave like true block-level elements */ + + -webkit-box-sizing: border-box; + /* Older Webkit */ + + -moz-box-sizing: border-box; + /* Older FF */ + + -ms-box-sizing: border-box; + /* IE8 */ + + box-sizing: border-box; + /* CSS3 spec*/ + + } + .input-prepend input[class*="span"], .input-append input[class*="span"] { + width: auto; + } + input[type="checkbox"], input[type="radio"] { + border: 1px solid #ccc; + } + .form-horizontal .control-group > label { + float: none; + width: auto; + padding-top: 0; + text-align: left; + } + .form-horizontal .controls { + margin-left: 0; + } + .form-horizontal .control-list { + padding-top: 0; + } + .form-horizontal .form-actions { + padding-left: 10px; + padding-right: 10px; + } + .modal { + position: absolute; + top: 10px; + left: 10px; + right: 10px; + width: auto; + margin: 0; + } + .modal.fade.in { + top: auto; + } + .modal-header .close { + padding: 10px; + margin: -10px; + } + .carousel-caption { + position: static; + } +} +@media (max-width: 767px) { + .container { + width: auto; + padding: 0 20px; + } + .row-fluid { + width: 100%; + } + .row { + margin-left: 0; + } + .row > [class*="span"], .row-fluid > [class*="span"] { + float: none; + display: block; + width: auto; + margin: 0; + } +} +@media (min-width: 768px) and (max-width: 979px) { + .row { + margin-left: -20px; + *zoom: 1; + } + .row:before, .row:after { + display: table; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + margin-left: 20px; + } + .span1 { + width: 42px; + } + .span2 { + width: 104px; + } + .span3 { + width: 166px; + } + .span4 { + width: 228px; + } + .span5 { + width: 290px; + } + .span6 { + width: 352px; + } + .span7 { + width: 414px; + } + .span8 { + width: 476px; + } + .span9 { + width: 538px; + } + .span10 { + width: 600px; + } + .span11 { + width: 662px; + } + .span12, .container { + width: 724px; + } + .offset1 { + margin-left: 82px; + } + .offset2 { + margin-left: 144px; + } + .offset3 { + margin-left: 206px; + } + .offset4 { + margin-left: 268px; + } + .offset5 { + margin-left: 330px; + } + .offset6 { + margin-left: 392px; + } + .offset7 { + margin-left: 454px; + } + .offset8 { + margin-left: 516px; + } + .offset9 { + margin-left: 578px; + } + .offset10 { + margin-left: 640px; + } + .offset11 { + margin-left: 702px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, .row-fluid:after { + display: table; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid > [class*="span"] { + float: left; + margin-left: 2.762430939%; + } + .row-fluid > [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid > .span1 { + width: 5.801104972%; + } + .row-fluid > .span2 { + width: 14.364640883%; + } + .row-fluid > .span3 { + width: 22.928176794%; + } + .row-fluid > .span4 { + width: 31.491712705%; + } + .row-fluid > .span5 { + width: 40.055248616%; + } + .row-fluid > .span6 { + width: 48.618784527%; + } + .row-fluid > .span7 { + width: 57.182320438000005%; + } + .row-fluid > .span8 { + width: 65.74585634900001%; + } + .row-fluid > .span9 { + width: 74.30939226%; + } + .row-fluid > .span10 { + width: 82.87292817100001%; + } + .row-fluid > .span11 { + width: 91.436464082%; + } + .row-fluid > .span12 { + width: 99.999999993%; + } + input.span1, textarea.span1, .uneditable-input.span1 { + width: 32px; + } + input.span2, textarea.span2, .uneditable-input.span2 { + width: 94px; + } + input.span3, textarea.span3, .uneditable-input.span3 { + width: 156px; + } + input.span4, textarea.span4, .uneditable-input.span4 { + width: 218px; + } + input.span5, textarea.span5, .uneditable-input.span5 { + width: 280px; + } + input.span6, textarea.span6, .uneditable-input.span6 { + width: 342px; + } + input.span7, textarea.span7, .uneditable-input.span7 { + width: 404px; + } + input.span8, textarea.span8, .uneditable-input.span8 { + width: 466px; + } + input.span9, textarea.span9, .uneditable-input.span9 { + width: 528px; + } + input.span10, textarea.span10, .uneditable-input.span10 { + width: 590px; + } + input.span11, textarea.span11, .uneditable-input.span11 { + width: 652px; + } + input.span12, textarea.span12, .uneditable-input.span12 { + width: 714px; + } +} +@media (max-width: 979px) { + body { + padding-top: 0; + } + .navbar-fixed-top { + position: static; + margin-bottom: 18px; + } + .navbar-fixed-top .navbar-inner { + padding: 5px; + } + .navbar .container { + width: auto; + padding: 0; + } + .navbar .brand { + padding-left: 10px; + padding-right: 10px; + margin: 0 0 0 -5px; + } + .navbar .nav-collapse { + clear: left; + } + .navbar .nav { + float: none; + margin: 0 0 9px; + } + .navbar .nav > li { + float: none; + } + .navbar .nav > li > a { + margin-bottom: 2px; + } + .navbar .nav > .divider-vertical { + display: none; + } + .navbar .nav .nav-header { + color: #999999; + text-shadow: none; + } + .navbar .nav > li > a, .navbar .dropdown-menu a { + padding: 6px 15px; + font-weight: bold; + color: #999999; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + } + .navbar .dropdown-menu li + li a { + margin-bottom: 2px; + } + .navbar .nav > li > a:hover, .navbar .dropdown-menu a:hover { + background-color: #222222; + } + .navbar .dropdown-menu { + position: static; + top: auto; + left: auto; + float: none; + display: block; + max-width: none; + margin: 0 15px; + padding: 0; + background-color: transparent; + border: none; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + } + .navbar .dropdown-menu:before, .navbar .dropdown-menu:after { + display: none; + } + .navbar .dropdown-menu .divider { + display: none; + } + .navbar-form, .navbar-search { + float: none; + padding: 9px 15px; + margin: 9px 0; + border-top: 1px solid #222222; + border-bottom: 1px solid #222222; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + } + .navbar .nav.pull-right { + float: none; + margin-left: 0; + } + .navbar-static .navbar-inner { + padding-left: 10px; + padding-right: 10px; + } + .btn-navbar { + display: block; + } + .nav-collapse { + overflow: hidden; + height: 0; + } +} +@media (min-width: 980px) { + .nav-collapse.collapse { + height: auto !important; + } +} +@media (min-width: 1200px) { + .row { + margin-left: -30px; + *zoom: 1; + } + .row:before, .row:after { + display: table; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + margin-left: 30px; + } + .span1 { + width: 70px; + } + .span2 { + width: 170px; + } + .span3 { + width: 270px; + } + .span4 { + width: 370px; + } + .span5 { + width: 470px; + } + .span6 { + width: 570px; + } + .span7 { + width: 670px; + } + .span8 { + width: 770px; + } + .span9 { + width: 870px; + } + .span10 { + width: 970px; + } + .span11 { + width: 1070px; + } + .span12, .container { + width: 1170px; + } + .offset1 { + margin-left: 130px; + } + .offset2 { + margin-left: 230px; + } + .offset3 { + margin-left: 330px; + } + .offset4 { + margin-left: 430px; + } + .offset5 { + margin-left: 530px; + } + .offset6 { + margin-left: 630px; + } + .offset7 { + margin-left: 730px; + } + .offset8 { + margin-left: 830px; + } + .offset9 { + margin-left: 930px; + } + .offset10 { + margin-left: 1030px; + } + .offset11 { + margin-left: 1130px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, .row-fluid:after { + display: table; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid > [class*="span"] { + float: left; + margin-left: 2.564102564%; + } + .row-fluid > [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid > .span1 { + width: 5.982905983%; + } + .row-fluid > .span2 { + width: 14.529914530000001%; + } + .row-fluid > .span3 { + width: 23.076923077%; + } + .row-fluid > .span4 { + width: 31.623931624%; + } + .row-fluid > .span5 { + width: 40.170940171000005%; + } + .row-fluid > .span6 { + width: 48.717948718%; + } + .row-fluid > .span7 { + width: 57.264957265%; + } + .row-fluid > .span8 { + width: 65.81196581200001%; + } + .row-fluid > .span9 { + width: 74.358974359%; + } + .row-fluid > .span10 { + width: 82.905982906%; + } + .row-fluid > .span11 { + width: 91.45299145300001%; + } + .row-fluid > .span12 { + width: 100%; + } + input.span1, textarea.span1, .uneditable-input.span1 { + width: 60px; + } + input.span2, textarea.span2, .uneditable-input.span2 { + width: 160px; + } + input.span3, textarea.span3, .uneditable-input.span3 { + width: 260px; + } + input.span4, textarea.span4, .uneditable-input.span4 { + width: 360px; + } + input.span5, textarea.span5, .uneditable-input.span5 { + width: 460px; + } + input.span6, textarea.span6, .uneditable-input.span6 { + width: 560px; + } + input.span7, textarea.span7, .uneditable-input.span7 { + width: 660px; + } + input.span8, textarea.span8, .uneditable-input.span8 { + width: 760px; + } + input.span9, textarea.span9, .uneditable-input.span9 { + width: 860px; + } + input.span10, textarea.span10, .uneditable-input.span10 { + width: 960px; + } + input.span11, textarea.span11, .uneditable-input.span11 { + width: 1060px; + } + input.span12, textarea.span12, .uneditable-input.span12 { + width: 1160px; + } + .thumbnails { + margin-left: -30px; + } + .thumbnails > li { + margin-left: 30px; + } +} diff --git a/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css b/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css new file mode 100644 index 0000000..6229c12 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css @@ -0,0 +1,3521 @@ +/*! + * Bootstrap v2.0.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +nav, +section { + display: block; +} +audio, canvas, video { + display: inline-block; + *display: inline; + *zoom: 1; +} +audio:not([controls]) { + display: none; +} +html { + font-size: 100%; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} +a:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +a:hover, a:active { + outline: 0; +} +sub, sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} +sup { + top: -0.5em; +} +sub { + bottom: -0.25em; +} +img { + max-width: 100%; + height: auto; + border: 0; + -ms-interpolation-mode: bicubic; +} +button, +input, +select, +textarea { + margin: 0; + font-size: 100%; + vertical-align: middle; +} +button, input { + *overflow: visible; + line-height: normal; +} +button::-moz-focus-inner, input::-moz-focus-inner { + padding: 0; + border: 0; +} +button, +input[type="button"], +input[type="reset"], +input[type="submit"] { + cursor: pointer; + -webkit-appearance: button; +} +input[type="search"] { + -webkit-appearance: textfield; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +input[type="search"]::-webkit-search-decoration, input[type="search"]::-webkit-search-cancel-button { + -webkit-appearance: none; +} +textarea { + overflow: auto; + vertical-align: top; +} +.clearfix { + *zoom: 1; +} +.clearfix:before, .clearfix:after { + display: table; + content: ""; +} +.clearfix:after { + clear: both; +} +body { + margin: 0; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 18px; + color: #333333; + background-color: #ffffff; +} +a { + color: #0088cc; + text-decoration: none; +} +a:hover { + color: #005580; + text-decoration: underline; +} +.row { + margin-left: -20px; + *zoom: 1; +} +.row:before, .row:after { + display: table; + content: ""; +} +.row:after { + clear: both; +} +[class*="span"] { + float: left; + margin-left: 20px; +} +.span1 { + width: 60px; +} +.span2 { + width: 140px; +} +.span3 { + width: 220px; +} +.span4 { + width: 300px; +} +.span5 { + width: 380px; +} +.span6 { + width: 460px; +} +.span7 { + width: 540px; +} +.span8 { + width: 620px; +} +.span9 { + width: 700px; +} +.span10 { + width: 780px; +} +.span11 { + width: 860px; +} +.span12, .container { + width: 940px; +} +.offset1 { + margin-left: 100px; +} +.offset2 { + margin-left: 180px; +} +.offset3 { + margin-left: 260px; +} +.offset4 { + margin-left: 340px; +} +.offset5 { + margin-left: 420px; +} +.offset6 { + margin-left: 500px; +} +.offset7 { + margin-left: 580px; +} +.offset8 { + margin-left: 660px; +} +.offset9 { + margin-left: 740px; +} +.offset10 { + margin-left: 820px; +} +.offset11 { + margin-left: 900px; +} +.row-fluid { + width: 100%; + *zoom: 1; +} +.row-fluid:before, .row-fluid:after { + display: table; + content: ""; +} +.row-fluid:after { + clear: both; +} +.row-fluid > [class*="span"] { + float: left; + margin-left: 2.127659574%; +} +.row-fluid > [class*="span"]:first-child { + margin-left: 0; +} +.row-fluid > .span1 { + width: 6.382978723%; +} +.row-fluid > .span2 { + width: 14.89361702%; +} +.row-fluid > .span3 { + width: 23.404255317%; +} +.row-fluid > .span4 { + width: 31.914893614%; +} +.row-fluid > .span5 { + width: 40.425531911%; +} +.row-fluid > .span6 { + width: 48.93617020799999%; +} +.row-fluid > .span7 { + width: 57.446808505%; +} +.row-fluid > .span8 { + width: 65.95744680199999%; +} +.row-fluid > .span9 { + width: 74.468085099%; +} +.row-fluid > .span10 { + width: 82.97872339599999%; +} +.row-fluid > .span11 { + width: 91.489361693%; +} +.row-fluid > .span12 { + width: 99.99999998999999%; +} +.container { + width: 940px; + margin-left: auto; + margin-right: auto; + *zoom: 1; +} +.container:before, .container:after { + display: table; + content: ""; +} +.container:after { + clear: both; +} +.container-fluid { + padding-left: 20px; + padding-right: 20px; + *zoom: 1; +} +.container-fluid:before, .container-fluid:after { + display: table; + content: ""; +} +.container-fluid:after { + clear: both; +} +p { + margin: 0 0 9px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 18px; +} +p small { + font-size: 11px; + color: #999999; +} +.lead { + margin-bottom: 18px; + font-size: 20px; + font-weight: 200; + line-height: 27px; +} +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 0; + font-weight: bold; + color: #333333; + text-rendering: optimizelegibility; +} +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small { + font-weight: normal; + color: #999999; +} +h1 { + font-size: 30px; + line-height: 36px; +} +h1 small { + font-size: 18px; +} +h2 { + font-size: 24px; + line-height: 36px; +} +h2 small { + font-size: 18px; +} +h3 { + line-height: 27px; + font-size: 18px; +} +h3 small { + font-size: 14px; +} +h4, h5, h6 { + line-height: 18px; +} +h4 { + font-size: 14px; +} +h4 small { + font-size: 12px; +} +h5 { + font-size: 12px; +} +h6 { + font-size: 11px; + color: #999999; + text-transform: uppercase; +} +.page-header { + padding-bottom: 17px; + margin: 18px 0; + border-bottom: 1px solid #eeeeee; +} +.page-header h1 { + line-height: 1; +} +ul, ol { + padding: 0; + margin: 0 0 9px 25px; +} +ul ul, +ul ol, +ol ol, +ol ul { + margin-bottom: 0; +} +ul { + list-style: disc; +} +ol { + list-style: decimal; +} +li { + line-height: 18px; +} +ul.unstyled, ol.unstyled { + margin-left: 0; + list-style: none; +} +dl { + margin-bottom: 18px; +} +dt, dd { + line-height: 18px; +} +dt { + font-weight: bold; +} +dd { + margin-left: 9px; +} +hr { + margin: 18px 0; + border: 0; + border-top: 1px solid #eeeeee; + border-bottom: 1px solid #ffffff; +} +strong { + font-weight: bold; +} +em { + font-style: italic; +} +.muted { + color: #999999; +} +abbr { + font-size: 90%; + text-transform: uppercase; + border-bottom: 1px dotted #ddd; + cursor: help; +} +blockquote { + padding: 0 0 0 15px; + margin: 0 0 18px; + border-left: 5px solid #eeeeee; +} +blockquote p { + margin-bottom: 0; + font-size: 16px; + font-weight: 300; + line-height: 22.5px; +} +blockquote small { + display: block; + line-height: 18px; + color: #999999; +} +blockquote small:before { + content: '\2014 \00A0'; +} +blockquote.pull-right { + float: right; + padding-left: 0; + padding-right: 15px; + border-left: 0; + border-right: 5px solid #eeeeee; +} +blockquote.pull-right p, blockquote.pull-right small { + text-align: right; +} +q:before, +q:after, +blockquote:before, +blockquote:after { + content: ""; +} +address { + display: block; + margin-bottom: 18px; + line-height: 18px; + font-style: normal; +} +small { + font-size: 100%; +} +cite { + font-style: normal; +} +code, pre { + padding: 0 3px 2px; + font-family: Menlo, Monaco, "Courier New", monospace; + font-size: 12px; + color: #333333; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +code { + padding: 3px 4px; + color: #d14; + background-color: #f7f7f9; + border: 1px solid #e1e1e8; +} +pre { + display: block; + padding: 8.5px; + margin: 0 0 9px; + font-size: 12px; + line-height: 18px; + background-color: #f5f5f5; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.15); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + white-space: pre; + white-space: pre-wrap; + word-break: break-all; + word-wrap: break-word; +} +pre.prettyprint { + margin-bottom: 18px; +} +pre code { + padding: 0; + color: inherit; + background-color: transparent; + border: 0; +} +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} +form { + margin: 0 0 18px; +} +fieldset { + padding: 0; + margin: 0; + border: 0; +} +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 27px; + font-size: 19.5px; + line-height: 36px; + color: #333333; + border: 0; + border-bottom: 1px solid #eee; +} +legend small { + font-size: 13.5px; + color: #999999; +} +label, +input, +button, +select, +textarea { + font-size: 13px; + font-weight: normal; + line-height: 18px; +} +input, +button, +select, +textarea { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; +} +label { + display: block; + margin-bottom: 5px; + color: #333333; +} +input, +textarea, +select, +.uneditable-input { + display: inline-block; + width: 210px; + height: 18px; + padding: 4px; + margin-bottom: 9px; + font-size: 13px; + line-height: 18px; + color: #555555; + border: 1px solid #ccc; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.uneditable-textarea { + width: auto; + height: auto; +} +label input, label textarea, label select { + display: block; +} +input[type="image"], input[type="checkbox"], input[type="radio"] { + width: auto; + height: auto; + padding: 0; + margin: 3px 0; + *margin-top: 0; + /* IE7 */ + + line-height: normal; + cursor: pointer; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + border: 0 \9; + /* IE9 and down */ + +} +input[type="image"] { + border: 0; +} +input[type="file"] { + width: auto; + padding: initial; + line-height: initial; + border: initial; + background-color: #ffffff; + background-color: initial; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +input[type="button"], input[type="reset"], input[type="submit"] { + width: auto; + height: auto; +} +select, input[type="file"] { + height: 28px; + /* In IE7, the height of the select element cannot be changed by height, only font-size */ + + *margin-top: 4px; + /* For IE7, add top margin to align select with labels */ + + line-height: 28px; +} +input[type="file"] { + line-height: 18px \9; +} +select { + width: 220px; + background-color: #ffffff; +} +select[multiple], select[size] { + height: auto; +} +input[type="image"] { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +textarea { + height: auto; +} +input[type="hidden"] { + display: none; +} +.radio, .checkbox { + padding-left: 18px; +} +.radio input[type="radio"], .checkbox input[type="checkbox"] { + float: left; + margin-left: -18px; +} +.controls > .radio:first-child, .controls > .checkbox:first-child { + padding-top: 5px; +} +.radio.inline, .checkbox.inline { + display: inline-block; + padding-top: 5px; + margin-bottom: 0; + vertical-align: middle; +} +.radio.inline + .radio.inline, .checkbox.inline + .checkbox.inline { + margin-left: 10px; +} +input, textarea { + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; + -moz-transition: border linear 0.2s, box-shadow linear 0.2s; + -ms-transition: border linear 0.2s, box-shadow linear 0.2s; + -o-transition: border linear 0.2s, box-shadow linear 0.2s; + transition: border linear 0.2s, box-shadow linear 0.2s; +} +input:focus, textarea:focus { + border-color: rgba(82, 168, 236, 0.8); + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + outline: 0; + outline: thin dotted \9; + /* IE6-9 */ + +} +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus, +select:focus { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.input-mini { + width: 60px; +} +.input-small { + width: 90px; +} +.input-medium { + width: 150px; +} +.input-large { + width: 210px; +} +.input-xlarge { + width: 270px; +} +.input-xxlarge { + width: 530px; +} +input[class*="span"], +select[class*="span"], +textarea[class*="span"], +.uneditable-input { + float: none; + margin-left: 0; +} +input.span1, textarea.span1, .uneditable-input.span1 { + width: 50px; +} +input.span2, textarea.span2, .uneditable-input.span2 { + width: 130px; +} +input.span3, textarea.span3, .uneditable-input.span3 { + width: 210px; +} +input.span4, textarea.span4, .uneditable-input.span4 { + width: 290px; +} +input.span5, textarea.span5, .uneditable-input.span5 { + width: 370px; +} +input.span6, textarea.span6, .uneditable-input.span6 { + width: 450px; +} +input.span7, textarea.span7, .uneditable-input.span7 { + width: 530px; +} +input.span8, textarea.span8, .uneditable-input.span8 { + width: 610px; +} +input.span9, textarea.span9, .uneditable-input.span9 { + width: 690px; +} +input.span10, textarea.span10, .uneditable-input.span10 { + width: 770px; +} +input.span11, textarea.span11, .uneditable-input.span11 { + width: 850px; +} +input.span12, textarea.span12, .uneditable-input.span12 { + width: 930px; +} +input[disabled], +select[disabled], +textarea[disabled], +input[readonly], +select[readonly], +textarea[readonly] { + background-color: #f5f5f5; + border-color: #ddd; + cursor: not-allowed; +} +.control-group.warning > label, .control-group.warning .help-block, .control-group.warning .help-inline { + color: #c09853; +} +.control-group.warning input, .control-group.warning select, .control-group.warning textarea { + color: #c09853; + border-color: #c09853; +} +.control-group.warning input:focus, .control-group.warning select:focus, .control-group.warning textarea:focus { + border-color: #a47e3c; + -webkit-box-shadow: 0 0 6px #dbc59e; + -moz-box-shadow: 0 0 6px #dbc59e; + box-shadow: 0 0 6px #dbc59e; +} +.control-group.warning .input-prepend .add-on, .control-group.warning .input-append .add-on { + color: #c09853; + background-color: #fcf8e3; + border-color: #c09853; +} +.control-group.error > label, .control-group.error .help-block, .control-group.error .help-inline { + color: #b94a48; +} +.control-group.error input, .control-group.error select, .control-group.error textarea { + color: #b94a48; + border-color: #b94a48; +} +.control-group.error input:focus, .control-group.error select:focus, .control-group.error textarea:focus { + border-color: #953b39; + -webkit-box-shadow: 0 0 6px #d59392; + -moz-box-shadow: 0 0 6px #d59392; + box-shadow: 0 0 6px #d59392; +} +.control-group.error .input-prepend .add-on, .control-group.error .input-append .add-on { + color: #b94a48; + background-color: #f2dede; + border-color: #b94a48; +} +.control-group.success > label, .control-group.success .help-block, .control-group.success .help-inline { + color: #468847; +} +.control-group.success input, .control-group.success select, .control-group.success textarea { + color: #468847; + border-color: #468847; +} +.control-group.success input:focus, .control-group.success select:focus, .control-group.success textarea:focus { + border-color: #356635; + -webkit-box-shadow: 0 0 6px #7aba7b; + -moz-box-shadow: 0 0 6px #7aba7b; + box-shadow: 0 0 6px #7aba7b; +} +.control-group.success .input-prepend .add-on, .control-group.success .input-append .add-on { + color: #468847; + background-color: #dff0d8; + border-color: #468847; +} +input:focus:required:invalid, textarea:focus:required:invalid, select:focus:required:invalid { + color: #b94a48; + border-color: #ee5f5b; +} +input:focus:required:invalid:focus, textarea:focus:required:invalid:focus, select:focus:required:invalid:focus { + border-color: #e9322d; + -webkit-box-shadow: 0 0 6px #f8b9b7; + -moz-box-shadow: 0 0 6px #f8b9b7; + box-shadow: 0 0 6px #f8b9b7; +} +.form-actions { + padding: 17px 20px 18px; + margin-top: 18px; + margin-bottom: 18px; + background-color: #f5f5f5; + border-top: 1px solid #ddd; +} +.uneditable-input { + display: block; + background-color: #ffffff; + border-color: #eee; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + cursor: not-allowed; +} +:-moz-placeholder { + color: #999999; +} +::-webkit-input-placeholder { + color: #999999; +} +.help-block { + display: block; + margin-top: 5px; + margin-bottom: 0; + color: #999999; +} +.help-inline { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; + margin-bottom: 9px; + vertical-align: middle; + padding-left: 5px; +} +.input-prepend, .input-append { + margin-bottom: 5px; + *zoom: 1; +} +.input-prepend:before, +.input-append:before, +.input-prepend:after, +.input-append:after { + display: table; + content: ""; +} +.input-prepend:after, .input-append:after { + clear: both; +} +.input-prepend input, +.input-append input, +.input-prepend .uneditable-input, +.input-append .uneditable-input { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.input-prepend input:focus, +.input-append input:focus, +.input-prepend .uneditable-input:focus, +.input-append .uneditable-input:focus { + position: relative; + z-index: 2; +} +.input-prepend .uneditable-input, .input-append .uneditable-input { + border-left-color: #ccc; +} +.input-prepend .add-on, .input-append .add-on { + float: left; + display: block; + width: auto; + min-width: 16px; + height: 18px; + margin-right: -1px; + padding: 4px 5px; + font-weight: normal; + line-height: 18px; + color: #999999; + text-align: center; + text-shadow: 0 1px 0 #ffffff; + background-color: #f5f5f5; + border: 1px solid #ccc; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.input-prepend .active, .input-append .active { + background-color: #a9dba9; + border-color: #46a546; +} +.input-prepend .add-on { + *margin-top: 1px; + /* IE6-7 */ + +} +.input-append input, .input-append .uneditable-input { + float: left; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.input-append .uneditable-input { + border-left-color: #eee; + border-right-color: #ccc; +} +.input-append .add-on { + margin-right: 0; + margin-left: -1px; + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.input-append input:first-child { + *margin-left: -160px; +} +.input-append input:first-child + .add-on { + *margin-left: -21px; +} +.search-query { + padding-left: 14px; + padding-right: 14px; + margin-bottom: 0; + -webkit-border-radius: 14px; + -moz-border-radius: 14px; + border-radius: 14px; +} +.form-search input, +.form-inline input, +.form-horizontal input, +.form-search textarea, +.form-inline textarea, +.form-horizontal textarea, +.form-search select, +.form-inline select, +.form-horizontal select, +.form-search .help-inline, +.form-inline .help-inline, +.form-horizontal .help-inline, +.form-search .uneditable-input, +.form-inline .uneditable-input, +.form-horizontal .uneditable-input { + display: inline-block; + margin-bottom: 0; +} +.form-search .hide, .form-inline .hide, .form-horizontal .hide { + display: none; +} +.form-search label, +.form-inline label, +.form-search .input-append, +.form-inline .input-append, +.form-search .input-prepend, +.form-inline .input-prepend { + display: inline-block; +} +.form-search .input-append .add-on, +.form-inline .input-prepend .add-on, +.form-search .input-append .add-on, +.form-inline .input-prepend .add-on { + vertical-align: middle; +} +.form-search .radio, +.form-inline .radio, +.form-search .checkbox, +.form-inline .checkbox { + margin-bottom: 0; + vertical-align: middle; +} +.control-group { + margin-bottom: 9px; +} +legend + .control-group { + margin-top: 18px; + -webkit-margin-top-collapse: separate; +} +.form-horizontal .control-group { + margin-bottom: 18px; + *zoom: 1; +} +.form-horizontal .control-group:before, .form-horizontal .control-group:after { + display: table; + content: ""; +} +.form-horizontal .control-group:after { + clear: both; +} +.form-horizontal .control-label { + float: left; + width: 140px; + padding-top: 5px; + text-align: right; +} +.form-horizontal .controls { + margin-left: 160px; +} +.form-horizontal .form-actions { + padding-left: 160px; +} +table { + max-width: 100%; + border-collapse: collapse; + border-spacing: 0; +} +.table { + width: 100%; + margin-bottom: 18px; +} +.table th, .table td { + padding: 8px; + line-height: 18px; + text-align: left; + vertical-align: top; + border-top: 1px solid #ddd; +} +.table th { + font-weight: bold; +} +.table thead th { + vertical-align: bottom; +} +.table thead:first-child tr th, .table thead:first-child tr td { + border-top: 0; +} +.table tbody + tbody { + border-top: 2px solid #ddd; +} +.table-condensed th, .table-condensed td { + padding: 4px 5px; +} +.table-bordered { + border: 1px solid #ddd; + border-collapse: separate; + *border-collapse: collapsed; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.table-bordered th + th, +.table-bordered td + td, +.table-bordered th + td, +.table-bordered td + th { + border-left: 1px solid #ddd; +} +.table-bordered thead:first-child tr:first-child th, .table-bordered tbody:first-child tr:first-child th, .table-bordered tbody:first-child tr:first-child td { + border-top: 0; +} +.table-bordered thead:first-child tr:first-child th:first-child, .table-bordered tbody:first-child tr:first-child td:first-child { + -webkit-border-radius: 4px 0 0 0; + -moz-border-radius: 4px 0 0 0; + border-radius: 4px 0 0 0; +} +.table-bordered thead:first-child tr:first-child th:last-child, .table-bordered tbody:first-child tr:first-child td:last-child { + -webkit-border-radius: 0 4px 0 0; + -moz-border-radius: 0 4px 0 0; + border-radius: 0 4px 0 0; +} +.table-bordered thead:last-child tr:last-child th:first-child, .table-bordered tbody:last-child tr:last-child td:first-child { + -webkit-border-radius: 0 0 0 4px; + -moz-border-radius: 0 0 0 4px; + border-radius: 0 0 0 4px; +} +.table-bordered thead:last-child tr:last-child th:last-child, .table-bordered tbody:last-child tr:last-child td:last-child { + -webkit-border-radius: 0 0 4px 0; + -moz-border-radius: 0 0 4px 0; + border-radius: 0 0 4px 0; +} +.table-striped tbody tr:nth-child(odd) td, .table-striped tbody tr:nth-child(odd) th { + background-color: #f9f9f9; +} +.table tbody tr:hover td, .table tbody tr:hover th { + background-color: #f5f5f5; +} +table .span1 { + float: none; + width: 44px; + margin-left: 0; +} +table .span2 { + float: none; + width: 124px; + margin-left: 0; +} +table .span3 { + float: none; + width: 204px; + margin-left: 0; +} +table .span4 { + float: none; + width: 284px; + margin-left: 0; +} +table .span5 { + float: none; + width: 364px; + margin-left: 0; +} +table .span6 { + float: none; + width: 444px; + margin-left: 0; +} +table .span7 { + float: none; + width: 524px; + margin-left: 0; +} +table .span8 { + float: none; + width: 604px; + margin-left: 0; +} +table .span9 { + float: none; + width: 684px; + margin-left: 0; +} +table .span10 { + float: none; + width: 764px; + margin-left: 0; +} +table .span11 { + float: none; + width: 844px; + margin-left: 0; +} +table .span12 { + float: none; + width: 924px; + margin-left: 0; +} +[class^="icon-"], [class*=" icon-"] { + display: inline-block; + width: 14px; + height: 14px; + line-height: 14px; + vertical-align: text-top; + background-image: url("../img/glyphicons-halflings.png"); + background-position: 14px 14px; + background-repeat: no-repeat; + *margin-right: .3em; +} +[class^="icon-"]:last-child, [class*=" icon-"]:last-child { + *margin-left: 0; +} +.icon-white { + background-image: url("../img/glyphicons-halflings-white.png"); +} +.icon-glass { + background-position: 0 0; +} +.icon-music { + background-position: -24px 0; +} +.icon-search { + background-position: -48px 0; +} +.icon-envelope { + background-position: -72px 0; +} +.icon-heart { + background-position: -96px 0; +} +.icon-star { + background-position: -120px 0; +} +.icon-star-empty { + background-position: -144px 0; +} +.icon-user { + background-position: -168px 0; +} +.icon-film { + background-position: -192px 0; +} +.icon-th-large { + background-position: -216px 0; +} +.icon-th { + background-position: -240px 0; +} +.icon-th-list { + background-position: -264px 0; +} +.icon-ok { + background-position: -288px 0; +} +.icon-remove { + background-position: -312px 0; +} +.icon-zoom-in { + background-position: -336px 0; +} +.icon-zoom-out { + background-position: -360px 0; +} +.icon-off { + background-position: -384px 0; +} +.icon-signal { + background-position: -408px 0; +} +.icon-cog { + background-position: -432px 0; +} +.icon-trash { + background-position: -456px 0; +} +.icon-home { + background-position: 0 -24px; +} +.icon-file { + background-position: -24px -24px; +} +.icon-time { + background-position: -48px -24px; +} +.icon-road { + background-position: -72px -24px; +} +.icon-download-alt { + background-position: -96px -24px; +} +.icon-download { + background-position: -120px -24px; +} +.icon-upload { + background-position: -144px -24px; +} +.icon-inbox { + background-position: -168px -24px; +} +.icon-play-circle { + background-position: -192px -24px; +} +.icon-repeat { + background-position: -216px -24px; +} +.icon-refresh { + background-position: -240px -24px; +} +.icon-list-alt { + background-position: -264px -24px; +} +.icon-lock { + background-position: -287px -24px; +} +.icon-flag { + background-position: -312px -24px; +} +.icon-headphones { + background-position: -336px -24px; +} +.icon-volume-off { + background-position: -360px -24px; +} +.icon-volume-down { + background-position: -384px -24px; +} +.icon-volume-up { + background-position: -408px -24px; +} +.icon-qrcode { + background-position: -432px -24px; +} +.icon-barcode { + background-position: -456px -24px; +} +.icon-tag { + background-position: 0 -48px; +} +.icon-tags { + background-position: -25px -48px; +} +.icon-book { + background-position: -48px -48px; +} +.icon-bookmark { + background-position: -72px -48px; +} +.icon-print { + background-position: -96px -48px; +} +.icon-camera { + background-position: -120px -48px; +} +.icon-font { + background-position: -144px -48px; +} +.icon-bold { + background-position: -167px -48px; +} +.icon-italic { + background-position: -192px -48px; +} +.icon-text-height { + background-position: -216px -48px; +} +.icon-text-width { + background-position: -240px -48px; +} +.icon-align-left { + background-position: -264px -48px; +} +.icon-align-center { + background-position: -288px -48px; +} +.icon-align-right { + background-position: -312px -48px; +} +.icon-align-justify { + background-position: -336px -48px; +} +.icon-list { + background-position: -360px -48px; +} +.icon-indent-left { + background-position: -384px -48px; +} +.icon-indent-right { + background-position: -408px -48px; +} +.icon-facetime-video { + background-position: -432px -48px; +} +.icon-picture { + background-position: -456px -48px; +} +.icon-pencil { + background-position: 0 -72px; +} +.icon-map-marker { + background-position: -24px -72px; +} +.icon-adjust { + background-position: -48px -72px; +} +.icon-tint { + background-position: -72px -72px; +} +.icon-edit { + background-position: -96px -72px; +} +.icon-share { + background-position: -120px -72px; +} +.icon-check { + background-position: -144px -72px; +} +.icon-move { + background-position: -168px -72px; +} +.icon-step-backward { + background-position: -192px -72px; +} +.icon-fast-backward { + background-position: -216px -72px; +} +.icon-backward { + background-position: -240px -72px; +} +.icon-play { + background-position: -264px -72px; +} +.icon-pause { + background-position: -288px -72px; +} +.icon-stop { + background-position: -312px -72px; +} +.icon-forward { + background-position: -336px -72px; +} +.icon-fast-forward { + background-position: -360px -72px; +} +.icon-step-forward { + background-position: -384px -72px; +} +.icon-eject { + background-position: -408px -72px; +} +.icon-chevron-left { + background-position: -432px -72px; +} +.icon-chevron-right { + background-position: -456px -72px; +} +.icon-plus-sign { + background-position: 0 -96px; +} +.icon-minus-sign { + background-position: -24px -96px; +} +.icon-remove-sign { + background-position: -48px -96px; +} +.icon-ok-sign { + background-position: -72px -96px; +} +.icon-question-sign { + background-position: -96px -96px; +} +.icon-info-sign { + background-position: -120px -96px; +} +.icon-screenshot { + background-position: -144px -96px; +} +.icon-remove-circle { + background-position: -168px -96px; +} +.icon-ok-circle { + background-position: -192px -96px; +} +.icon-ban-circle { + background-position: -216px -96px; +} +.icon-arrow-left { + background-position: -240px -96px; +} +.icon-arrow-right { + background-position: -264px -96px; +} +.icon-arrow-up { + background-position: -289px -96px; +} +.icon-arrow-down { + background-position: -312px -96px; +} +.icon-share-alt { + background-position: -336px -96px; +} +.icon-resize-full { + background-position: -360px -96px; +} +.icon-resize-small { + background-position: -384px -96px; +} +.icon-plus { + background-position: -408px -96px; +} +.icon-minus { + background-position: -433px -96px; +} +.icon-asterisk { + background-position: -456px -96px; +} +.icon-exclamation-sign { + background-position: 0 -120px; +} +.icon-gift { + background-position: -24px -120px; +} +.icon-leaf { + background-position: -48px -120px; +} +.icon-fire { + background-position: -72px -120px; +} +.icon-eye-open { + background-position: -96px -120px; +} +.icon-eye-close { + background-position: -120px -120px; +} +.icon-warning-sign { + background-position: -144px -120px; +} +.icon-plane { + background-position: -168px -120px; +} +.icon-calendar { + background-position: -192px -120px; +} +.icon-random { + background-position: -216px -120px; +} +.icon-comment { + background-position: -240px -120px; +} +.icon-magnet { + background-position: -264px -120px; +} +.icon-chevron-up { + background-position: -288px -120px; +} +.icon-chevron-down { + background-position: -313px -119px; +} +.icon-retweet { + background-position: -336px -120px; +} +.icon-shopping-cart { + background-position: -360px -120px; +} +.icon-folder-close { + background-position: -384px -120px; +} +.icon-folder-open { + background-position: -408px -120px; +} +.icon-resize-vertical { + background-position: -432px -119px; +} +.icon-resize-horizontal { + background-position: -456px -118px; +} +.dropdown { + position: relative; +} +.dropdown-toggle { + *margin-bottom: -3px; +} +.dropdown-toggle:active, .open .dropdown-toggle { + outline: 0; +} +.caret { + display: inline-block; + width: 0; + height: 0; + text-indent: -99999px; + *text-indent: 0; + vertical-align: top; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 4px solid #000000; + opacity: 0.3; + filter: alpha(opacity=30); + content: "\2193"; +} +.dropdown .caret { + margin-top: 8px; + margin-left: 2px; +} +.dropdown:hover .caret, .open.dropdown .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + float: left; + display: none; + min-width: 160px; + _width: 160px; + padding: 4px 0; + margin: 0; + list-style: none; + background-color: #ffffff; + border-color: #ccc; + border-color: rgba(0, 0, 0, 0.2); + border-style: solid; + border-width: 1px; + -webkit-border-radius: 0 0 5px 5px; + -moz-border-radius: 0 0 5px 5px; + border-radius: 0 0 5px 5px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; + *border-right-width: 2px; + *border-bottom-width: 2px; +} +.dropdown-menu.bottom-up { + top: auto; + bottom: 100%; + margin-bottom: 2px; +} +.dropdown-menu .divider { + height: 1px; + margin: 5px 1px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #ffffff; + *width: 100%; + *margin: -5px 0 5px; +} +.dropdown-menu a { + display: block; + padding: 3px 15px; + clear: both; + font-weight: normal; + line-height: 18px; + color: #555555; + white-space: nowrap; +} +.dropdown-menu li > a:hover, .dropdown-menu .active > a, .dropdown-menu .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #0088cc; +} +.dropdown.open { + *z-index: 1000; +} +.dropdown.open .dropdown-toggle { + color: #ffffff; + background: #ccc; + background: rgba(0, 0, 0, 0.3); +} +.dropdown.open .dropdown-menu { + display: block; +} +.typeahead { + margin-top: 2px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #f5f5f5; + border: 1px solid #eee; + border: 1px solid rgba(0, 0, 0, 0.05); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 0, 0, 0.15); +} +.fade { + -webkit-transition: opacity 0.15s linear; + -moz-transition: opacity 0.15s linear; + -ms-transition: opacity 0.15s linear; + -o-transition: opacity 0.15s linear; + transition: opacity 0.15s linear; + opacity: 0; +} +.fade.in { + opacity: 1; +} +.collapse { + -webkit-transition: height 0.35s ease; + -moz-transition: height 0.35s ease; + -ms-transition: height 0.35s ease; + -o-transition: height 0.35s ease; + transition: height 0.35s ease; + position: relative; + overflow: hidden; + height: 0; +} +.collapse.in { + height: auto; +} +.close { + float: right; + font-size: 20px; + font-weight: bold; + line-height: 18px; + color: #000000; + text-shadow: 0 1px 0 #ffffff; + opacity: 0.2; + filter: alpha(opacity=20); +} +.close:hover { + color: #000000; + text-decoration: none; + opacity: 0.4; + filter: alpha(opacity=40); + cursor: pointer; +} +.btn { + display: inline-block; + padding: 4px 10px 4px; + margin-bottom: 0; + font-size: 13px; + line-height: 18px; + color: #333333; + text-align: center; + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); + vertical-align: middle; + background-color: #f5f5f5; + background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); + background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); + background-image: linear-gradient(top, #ffffff, #e6e6e6); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0); + border-color: #e6e6e6 #e6e6e6 #bfbfbf; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + border: 1px solid #ccc; + border-bottom-color: #bbb; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + cursor: pointer; + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + *margin-left: .3em; +} +.btn:hover, +.btn:active, +.btn.active, +.btn.disabled, +.btn[disabled] { + background-color: #e6e6e6; +} +.btn:active, .btn.active { + background-color: #cccccc \9; +} +.btn:first-child { + *margin-left: 0; +} +.btn:hover { + color: #333333; + text-decoration: none; + background-color: #e6e6e6; + background-position: 0 -15px; + -webkit-transition: background-position 0.1s linear; + -moz-transition: background-position 0.1s linear; + -ms-transition: background-position 0.1s linear; + -o-transition: background-position 0.1s linear; + transition: background-position 0.1s linear; +} +.btn:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.btn.active, .btn:active { + background-image: none; + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + background-color: #e6e6e6; + background-color: #d9d9d9 \9; + outline: 0; +} +.btn.disabled, .btn[disabled] { + cursor: default; + background-image: none; + background-color: #e6e6e6; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +.btn-large { + padding: 9px 14px; + font-size: 15px; + line-height: normal; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.btn-large [class^="icon-"] { + margin-top: 1px; +} +.btn-small { + padding: 5px 9px; + font-size: 11px; + line-height: 16px; +} +.btn-small [class^="icon-"] { + margin-top: -1px; +} +.btn-mini { + padding: 2px 6px; + font-size: 11px; + line-height: 14px; +} +.btn-primary, +.btn-primary:hover, +.btn-warning, +.btn-warning:hover, +.btn-danger, +.btn-danger:hover, +.btn-success, +.btn-success:hover, +.btn-info, +.btn-info:hover, +.btn-inverse, +.btn-inverse:hover { + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + color: #ffffff; +} +.btn-primary.active, +.btn-warning.active, +.btn-danger.active, +.btn-success.active, +.btn-info.active, +.btn-dark.active { + color: rgba(255, 255, 255, 0.75); +} +.btn-primary { + background-color: #006dcc; + background-image: -moz-linear-gradient(top, #0088cc, #0044cc); + background-image: -ms-linear-gradient(top, #0088cc, #0044cc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); + background-image: -o-linear-gradient(top, #0088cc, #0044cc); + background-image: linear-gradient(top, #0088cc, #0044cc); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); + border-color: #0044cc #0044cc #002a80; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-primary:hover, +.btn-primary:active, +.btn-primary.active, +.btn-primary.disabled, +.btn-primary[disabled] { + background-color: #0044cc; +} +.btn-primary:active, .btn-primary.active { + background-color: #003399 \9; +} +.btn-warning { + background-color: #faa732; + background-image: -moz-linear-gradient(top, #fbb450, #f89406); + background-image: -ms-linear-gradient(top, #fbb450, #f89406); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); + background-image: -webkit-linear-gradient(top, #fbb450, #f89406); + background-image: -o-linear-gradient(top, #fbb450, #f89406); + background-image: linear-gradient(top, #fbb450, #f89406); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0); + border-color: #f89406 #f89406 #ad6704; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-warning:hover, +.btn-warning:active, +.btn-warning.active, +.btn-warning.disabled, +.btn-warning[disabled] { + background-color: #f89406; +} +.btn-warning:active, .btn-warning.active { + background-color: #c67605 \9; +} +.btn-danger { + background-color: #da4f49; + background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -ms-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -o-linear-gradient(top, #ee5f5b, #bd362f); + background-image: linear-gradient(top, #ee5f5b, #bd362f); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0); + border-color: #bd362f #bd362f #802420; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-danger:hover, +.btn-danger:active, +.btn-danger.active, +.btn-danger.disabled, +.btn-danger[disabled] { + background-color: #bd362f; +} +.btn-danger:active, .btn-danger.active { + background-color: #942a25 \9; +} +.btn-success { + background-color: #5bb75b; + background-image: -moz-linear-gradient(top, #62c462, #51a351); + background-image: -ms-linear-gradient(top, #62c462, #51a351); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351)); + background-image: -webkit-linear-gradient(top, #62c462, #51a351); + background-image: -o-linear-gradient(top, #62c462, #51a351); + background-image: linear-gradient(top, #62c462, #51a351); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0); + border-color: #51a351 #51a351 #387038; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-success:hover, +.btn-success:active, +.btn-success.active, +.btn-success.disabled, +.btn-success[disabled] { + background-color: #51a351; +} +.btn-success:active, .btn-success.active { + background-color: #408140 \9; +} +.btn-info { + background-color: #49afcd; + background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -ms-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4)); + background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -o-linear-gradient(top, #5bc0de, #2f96b4); + background-image: linear-gradient(top, #5bc0de, #2f96b4); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0); + border-color: #2f96b4 #2f96b4 #1f6377; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-info:hover, +.btn-info:active, +.btn-info.active, +.btn-info.disabled, +.btn-info[disabled] { + background-color: #2f96b4; +} +.btn-info:active, .btn-info.active { + background-color: #24748c \9; +} +.btn-inverse { + background-color: #393939; + background-image: -moz-linear-gradient(top, #454545, #262626); + background-image: -ms-linear-gradient(top, #454545, #262626); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#454545), to(#262626)); + background-image: -webkit-linear-gradient(top, #454545, #262626); + background-image: -o-linear-gradient(top, #454545, #262626); + background-image: linear-gradient(top, #454545, #262626); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#454545', endColorstr='#262626', GradientType=0); + border-color: #262626 #262626 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-inverse:hover, +.btn-inverse:active, +.btn-inverse.active, +.btn-inverse.disabled, +.btn-inverse[disabled] { + background-color: #262626; +} +.btn-inverse:active, .btn-inverse.active { + background-color: #0c0c0c \9; +} +button.btn, input[type="submit"].btn { + *padding-top: 2px; + *padding-bottom: 2px; +} +button.btn::-moz-focus-inner, input[type="submit"].btn::-moz-focus-inner { + padding: 0; + border: 0; +} +button.btn.large, input[type="submit"].btn.large { + *padding-top: 7px; + *padding-bottom: 7px; +} +button.btn.small, input[type="submit"].btn.small { + *padding-top: 3px; + *padding-bottom: 3px; +} +.btn-group { + position: relative; + *zoom: 1; + *margin-left: .3em; +} +.btn-group:before, .btn-group:after { + display: table; + content: ""; +} +.btn-group:after { + clear: both; +} +.btn-group:first-child { + *margin-left: 0; +} +.btn-group + .btn-group { + margin-left: 5px; +} +.btn-toolbar { + margin-top: 9px; + margin-bottom: 9px; +} +.btn-toolbar .btn-group { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; +} +.btn-group .btn { + position: relative; + float: left; + margin-left: -1px; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.btn-group .btn:first-child { + margin-left: 0; + -webkit-border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; + border-top-left-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + border-bottom-left-radius: 4px; +} +.btn-group .btn:last-child, .btn-group .dropdown-toggle { + -webkit-border-top-right-radius: 4px; + -moz-border-radius-topright: 4px; + border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -moz-border-radius-bottomright: 4px; + border-bottom-right-radius: 4px; +} +.btn-group .btn.large:first-child { + margin-left: 0; + -webkit-border-top-left-radius: 6px; + -moz-border-radius-topleft: 6px; + border-top-left-radius: 6px; + -webkit-border-bottom-left-radius: 6px; + -moz-border-radius-bottomleft: 6px; + border-bottom-left-radius: 6px; +} +.btn-group .btn.large:last-child, .btn-group .large.dropdown-toggle { + -webkit-border-top-right-radius: 6px; + -moz-border-radius-topright: 6px; + border-top-right-radius: 6px; + -webkit-border-bottom-right-radius: 6px; + -moz-border-radius-bottomright: 6px; + border-bottom-right-radius: 6px; +} +.btn-group .btn:hover, +.btn-group .btn:focus, +.btn-group .btn:active, +.btn-group .btn.active { + z-index: 2; +} +.btn-group .dropdown-toggle:active, .btn-group.open .dropdown-toggle { + outline: 0; +} +.btn-group .dropdown-toggle { + padding-left: 8px; + padding-right: 8px; + -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + *padding-top: 5px; + *padding-bottom: 5px; +} +.btn-group.open { + *z-index: 1000; +} +.btn-group.open .dropdown-menu { + display: block; + margin-top: 1px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.btn-group.open .dropdown-toggle { + background-image: none; + -webkit-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); +} +.btn .caret { + margin-top: 7px; + margin-left: 0; +} +.btn:hover .caret, .open.btn-group .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.btn-primary .caret, +.btn-danger .caret, +.btn-info .caret, +.btn-success .caret, +.btn-inverse .caret { + border-top-color: #ffffff; + opacity: 0.75; + filter: alpha(opacity=75); +} +.btn-small .caret { + margin-top: 4px; +} +.alert { + padding: 8px 35px 8px 14px; + margin-bottom: 18px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + background-color: #fcf8e3; + border: 1px solid #fbeed5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.alert, .alert-heading { + color: #c09853; +} +.alert .close { + position: relative; + top: -2px; + right: -21px; + line-height: 18px; +} +.alert-success { + background-color: #dff0d8; + border-color: #d6e9c6; +} +.alert-success, .alert-success .alert-heading { + color: #468847; +} +.alert-danger, .alert-error { + background-color: #f2dede; + border-color: #eed3d7; +} +.alert-danger, +.alert-error, +.alert-danger .alert-heading, +.alert-error .alert-heading { + color: #b94a48; +} +.alert-info { + background-color: #d9edf7; + border-color: #bce8f1; +} +.alert-info, .alert-info .alert-heading { + color: #3a87ad; +} +.alert-block { + padding-top: 14px; + padding-bottom: 14px; +} +.alert-block > p, .alert-block > ul { + margin-bottom: 0; +} +.alert-block p + p { + margin-top: 5px; +} +.nav { + margin-left: 0; + margin-bottom: 18px; + list-style: none; +} +.nav > li > a { + display: block; +} +.nav > li > a:hover { + text-decoration: none; + background-color: #eeeeee; +} +.nav .nav-header { + display: block; + padding: 3px 15px; + font-size: 11px; + font-weight: bold; + line-height: 18px; + color: #999999; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + text-transform: uppercase; +} +.nav li + .nav-header { + margin-top: 9px; +} +.nav-list { + padding-left: 14px; + padding-right: 14px; + margin-bottom: 0; +} +.nav-list > li > a, .nav-list .nav-header { + margin-left: -15px; + margin-right: -15px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); +} +.nav-list > li > a { + padding: 3px 15px; +} +.nav-list .active > a, .nav-list .active > a:hover { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); + background-color: #0088cc; +} +.nav-list [class^="icon-"] { + margin-right: 2px; +} +.nav-tabs, .nav-pills { + *zoom: 1; +} +.nav-tabs:before, +.nav-pills:before, +.nav-tabs:after, +.nav-pills:after { + display: table; + content: ""; +} +.nav-tabs:after, .nav-pills:after { + clear: both; +} +.nav-tabs > li, .nav-pills > li { + float: left; +} +.nav-tabs > li > a, .nav-pills > li > a { + padding-right: 12px; + padding-left: 12px; + margin-right: 2px; + line-height: 14px; +} +.nav-tabs { + border-bottom: 1px solid #ddd; +} +.nav-tabs > li { + margin-bottom: -1px; +} +.nav-tabs > li > a { + padding-top: 9px; + padding-bottom: 9px; + border: 1px solid transparent; + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} +.nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #dddddd; +} +.nav-tabs > .active > a, .nav-tabs > .active > a:hover { + color: #555555; + background-color: #ffffff; + border: 1px solid #ddd; + border-bottom-color: transparent; + cursor: default; +} +.nav-pills > li > a { + padding-top: 8px; + padding-bottom: 8px; + margin-top: 2px; + margin-bottom: 2px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.nav-pills .active > a, .nav-pills .active > a:hover { + color: #ffffff; + background-color: #0088cc; +} +.nav-stacked > li { + float: none; +} +.nav-stacked > li > a { + margin-right: 0; +} +.nav-tabs.nav-stacked { + border-bottom: 0; +} +.nav-tabs.nav-stacked > li > a { + border: 1px solid #ddd; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.nav-tabs.nav-stacked > li:first-child > a { + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} +.nav-tabs.nav-stacked > li:last-child > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} +.nav-tabs.nav-stacked > li > a:hover { + border-color: #ddd; + z-index: 2; +} +.nav-pills.nav-stacked > li > a { + margin-bottom: 3px; +} +.nav-pills.nav-stacked > li:last-child > a { + margin-bottom: 1px; +} +.nav-tabs .dropdown-menu, .nav-pills .dropdown-menu { + margin-top: 1px; + border-width: 1px; +} +.nav-pills .dropdown-menu { + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.nav-tabs .dropdown-toggle .caret, .nav-pills .dropdown-toggle .caret { + border-top-color: #0088cc; + margin-top: 6px; +} +.nav-tabs .dropdown-toggle:hover .caret, .nav-pills .dropdown-toggle:hover .caret { + border-top-color: #005580; +} +.nav-tabs .active .dropdown-toggle .caret, .nav-pills .active .dropdown-toggle .caret { + border-top-color: #333333; +} +.nav > .dropdown.active > a:hover { + color: #000000; + cursor: pointer; +} +.nav-tabs .open .dropdown-toggle, .nav-pills .open .dropdown-toggle, .nav > .open.active > a:hover { + color: #ffffff; + background-color: #999999; + border-color: #999999; +} +.nav .open .caret, .nav .open.active .caret, .nav .open a:hover .caret { + border-top-color: #ffffff; + opacity: 1; + filter: alpha(opacity=100); +} +.tabs-stacked .open > a:hover { + border-color: #999999; +} +.tabbable { + *zoom: 1; +} +.tabbable:before, .tabbable:after { + display: table; + content: ""; +} +.tabbable:after { + clear: both; +} +.tab-content { + overflow: hidden; +} +.tabs-below .nav-tabs, .tabs-right .nav-tabs, .tabs-left .nav-tabs { + border-bottom: 0; +} +.tab-content > .tab-pane, .pill-content > .pill-pane { + display: none; +} +.tab-content > .active, .pill-content > .active { + display: block; +} +.tabs-below .nav-tabs { + border-top: 1px solid #ddd; +} +.tabs-below .nav-tabs > li { + margin-top: -1px; + margin-bottom: 0; +} +.tabs-below .nav-tabs > li > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} +.tabs-below .nav-tabs > li > a:hover { + border-bottom-color: transparent; + border-top-color: #ddd; +} +.tabs-below .nav-tabs .active > a, .tabs-below .nav-tabs .active > a:hover { + border-color: transparent #ddd #ddd #ddd; +} +.tabs-left .nav-tabs > li, .tabs-right .nav-tabs > li { + float: none; +} +.tabs-left .nav-tabs > li > a, .tabs-right .nav-tabs > li > a { + min-width: 74px; + margin-right: 0; + margin-bottom: 3px; +} +.tabs-left .nav-tabs { + float: left; + margin-right: 19px; + border-right: 1px solid #ddd; +} +.tabs-left .nav-tabs > li > a { + margin-right: -1px; + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} +.tabs-left .nav-tabs > li > a:hover { + border-color: #eeeeee #dddddd #eeeeee #eeeeee; +} +.tabs-left .nav-tabs .active > a, .tabs-left .nav-tabs .active > a:hover { + border-color: #ddd transparent #ddd #ddd; + *border-right-color: #ffffff; +} +.tabs-right .nav-tabs { + float: right; + margin-left: 19px; + border-left: 1px solid #ddd; +} +.tabs-right .nav-tabs > li > a { + margin-left: -1px; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} +.tabs-right .nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #eeeeee #dddddd; +} +.tabs-right .nav-tabs .active > a, .tabs-right .nav-tabs .active > a:hover { + border-color: #ddd #ddd #ddd transparent; + *border-left-color: #ffffff; +} +.navbar { + overflow: visible; + margin-bottom: 18px; +} +.navbar-inner { + padding-left: 20px; + padding-right: 20px; + background-color: #2c2c2c; + background-image: -moz-linear-gradient(top, #333333, #222222); + background-image: -ms-linear-gradient(top, #333333, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); + background-image: -webkit-linear-gradient(top, #333333, #222222); + background-image: -o-linear-gradient(top, #333333, #222222); + background-image: linear-gradient(top, #333333, #222222); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); +} +.btn-navbar { + display: none; + float: right; + padding: 7px 10px; + margin-left: 5px; + margin-right: 5px; + background-color: #2c2c2c; + background-image: -moz-linear-gradient(top, #333333, #222222); + background-image: -ms-linear-gradient(top, #333333, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); + background-image: -webkit-linear-gradient(top, #333333, #222222); + background-image: -o-linear-gradient(top, #333333, #222222); + background-image: linear-gradient(top, #333333, #222222); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); + border-color: #222222 #222222 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); +} +.btn-navbar:hover, +.btn-navbar:active, +.btn-navbar.active, +.btn-navbar.disabled, +.btn-navbar[disabled] { + background-color: #222222; +} +.btn-navbar:active, .btn-navbar.active { + background-color: #080808 \9; +} +.btn-navbar .icon-bar { + display: block; + width: 18px; + height: 2px; + background-color: #f5f5f5; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; + -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); +} +.btn-navbar .icon-bar + .icon-bar { + margin-top: 3px; +} +.nav-collapse.collapse { + height: auto; +} +.navbar .brand:hover { + text-decoration: none; +} +.navbar .brand { + float: left; + display: block; + padding: 8px 20px 12px; + margin-left: -20px; + font-size: 20px; + font-weight: 200; + line-height: 1; + color: #ffffff; +} +.navbar .navbar-text { + margin-bottom: 0; + line-height: 40px; + color: #999999; +} +.navbar .navbar-text a:hover { + color: #ffffff; + background-color: transparent; +} +.navbar .btn, .navbar .btn-group { + margin-top: 5px; +} +.navbar .btn-group .btn { + margin-top: 0; +} +.navbar-form { + margin-bottom: 0; + *zoom: 1; +} +.navbar-form:before, .navbar-form:after { + display: table; + content: ""; +} +.navbar-form:after { + clear: both; +} +.navbar-form input, .navbar-form select { + display: inline-block; + margin-top: 5px; + margin-bottom: 0; +} +.navbar-form .radio, .navbar-form .checkbox { + margin-top: 5px; +} +.navbar-form input[type="image"], .navbar-form input[type="checkbox"], .navbar-form input[type="radio"] { + margin-top: 3px; +} +.navbar-form .input-append, .navbar-form .input-prepend { + margin-top: 6px; + white-space: nowrap; +} +.navbar-form .input-append input, .navbar-form .input-prepend input { + margin-top: 0; +} +.navbar-search { + position: relative; + float: left; + margin-top: 6px; + margin-bottom: 0; +} +.navbar-search .search-query { + padding: 4px 9px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + font-weight: normal; + line-height: 1; + color: #ffffff; + color: rgba(255, 255, 255, 0.75); + background: #666; + background: rgba(255, 255, 255, 0.3); + border: 1px solid #111; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + -webkit-transition: none; + -moz-transition: none; + -ms-transition: none; + -o-transition: none; + transition: none; +} +.navbar-search .search-query :-moz-placeholder { + color: #eeeeee; +} +.navbar-search .search-query::-webkit-input-placeholder { + color: #eeeeee; +} +.navbar-search .search-query:hover { + color: #ffffff; + background-color: #999999; + background-color: rgba(255, 255, 255, 0.5); +} +.navbar-search .search-query:focus, .navbar-search .search-query.focused { + padding: 5px 10px; + color: #333333; + text-shadow: 0 1px 0 #ffffff; + background-color: #ffffff; + border: 0; + -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + outline: 0; +} +.navbar-fixed-top { + position: fixed; + top: 0; + right: 0; + left: 0; + z-index: 1030; +} +.navbar-fixed-top .navbar-inner { + padding-left: 0; + padding-right: 0; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.navbar .nav { + position: relative; + left: 0; + display: block; + float: left; + margin: 0 10px 0 0; +} +.navbar .nav.pull-right { + float: right; +} +.navbar .nav > li { + display: block; + float: left; +} +.navbar .nav > li > a { + float: none; + padding: 10px 10px 11px; + line-height: 19px; + color: #999999; + text-decoration: none; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.navbar .nav > li > a:hover { + background-color: transparent; + color: #ffffff; + text-decoration: none; +} +.navbar .nav .active > a, .navbar .nav .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #222222; +} +.navbar .divider-vertical { + height: 40px; + width: 1px; + margin: 0 9px; + overflow: hidden; + background-color: #222222; + border-right: 1px solid #333333; +} +.navbar .nav.pull-right { + margin-left: 10px; + margin-right: 0; +} +.navbar .dropdown-menu { + margin-top: 1px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.navbar .dropdown-menu:before { + content: ''; + display: inline-block; + border-left: 7px solid transparent; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-bottom-color: rgba(0, 0, 0, 0.2); + position: absolute; + top: -7px; + left: 9px; +} +.navbar .dropdown-menu:after { + content: ''; + display: inline-block; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid #ffffff; + position: absolute; + top: -6px; + left: 10px; +} +.navbar .nav .dropdown-toggle .caret, .navbar .nav .open.dropdown .caret { + border-top-color: #ffffff; +} +.navbar .nav .active .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.navbar .nav .open > .dropdown-toggle, .navbar .nav .active > .dropdown-toggle, .navbar .nav .open.active > .dropdown-toggle { + background-color: transparent; +} +.navbar .nav .active > .dropdown-toggle:hover { + color: #ffffff; +} +.navbar .nav.pull-right .dropdown-menu { + left: auto; + right: 0; +} +.navbar .nav.pull-right .dropdown-menu:before { + left: auto; + right: 12px; +} +.navbar .nav.pull-right .dropdown-menu:after { + left: auto; + right: 13px; +} +.breadcrumb { + padding: 7px 14px; + margin: 0 0 18px; + background-color: #fbfbfb; + background-image: -moz-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -ms-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5)); + background-image: -webkit-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -o-linear-gradient(top, #ffffff, #f5f5f5); + background-image: linear-gradient(top, #ffffff, #f5f5f5); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0); + border: 1px solid #ddd; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; +} +.breadcrumb li { + display: inline-block; + text-shadow: 0 1px 0 #ffffff; +} +.breadcrumb .divider { + padding: 0 5px; + color: #999999; +} +.breadcrumb .active a { + color: #333333; +} +.pagination { + height: 36px; + margin: 18px 0; +} +.pagination ul { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; + margin-left: 0; + margin-bottom: 0; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); +} +.pagination li { + display: inline; +} +.pagination a { + float: left; + padding: 0 14px; + line-height: 34px; + text-decoration: none; + border: 1px solid #ddd; + border-left-width: 0; +} +.pagination a:hover, .pagination .active a { + background-color: #f5f5f5; +} +.pagination .active a { + color: #999999; + cursor: default; +} +.pagination .disabled a, .pagination .disabled a:hover { + color: #999999; + background-color: transparent; + cursor: default; +} +.pagination li:first-child a { + border-left-width: 1px; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.pagination li:last-child a { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.pagination-centered { + text-align: center; +} +.pagination-right { + text-align: right; +} +.pager { + margin-left: 0; + margin-bottom: 18px; + list-style: none; + text-align: center; + *zoom: 1; +} +.pager:before, .pager:after { + display: table; + content: ""; +} +.pager:after { + clear: both; +} +.pager li { + display: inline; +} +.pager a { + display: inline-block; + padding: 5px 14px; + background-color: #fff; + border: 1px solid #ddd; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} +.pager a:hover { + text-decoration: none; + background-color: #f5f5f5; +} +.pager .next a { + float: right; +} +.pager .previous a { + float: left; +} +.modal-open .dropdown-menu { + z-index: 2050; +} +.modal-open .dropdown.open { + *z-index: 2050; +} +.modal-open .popover { + z-index: 2060; +} +.modal-open .tooltip { + z-index: 2070; +} +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + background-color: #000000; +} +.modal-backdrop.fade { + opacity: 0; +} +.modal-backdrop, .modal-backdrop.fade.in { + opacity: 0.8; + filter: alpha(opacity=80); +} +.modal { + position: fixed; + top: 50%; + left: 50%; + z-index: 1050; + max-height: 500px; + overflow: auto; + width: 560px; + margin: -250px 0 0 -280px; + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + /* IE6-7 */ + + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.wide-modal { + position: fixed; + top: 5%; + left: 5%; + z-index: 1050; + max-height: 90%; + overflow: auto; + width: 90%; + /*margin: -50px 0 0 -80px;*/ + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + /* IE6-7 */ + + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.modal.fade { + -webkit-transition: opacity .3s linear, top .3s ease-out; + -moz-transition: opacity .3s linear, top .3s ease-out; + -ms-transition: opacity .3s linear, top .3s ease-out; + -o-transition: opacity .3s linear, top .3s ease-out; + transition: opacity .3s linear, top .3s ease-out; + top: -25%; +} +.modal.fade.in { + top: 50%; +} +.modal-header { + padding: 9px 15px; + border-bottom: 1px solid #eee; +} +.modal-header .close { + margin-top: 2px; +} +.modal-body { + padding: 15px; +} +.modal-body .modal-form { + margin-bottom: 0; +} +.modal-footer { + padding: 14px 15px 15px; + margin-bottom: 0; + background-color: #f5f5f5; + border-top: 1px solid #ddd; + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; + *zoom: 1; +} +.modal-footer:before, .modal-footer:after { + display: table; + content: ""; +} +.modal-footer:after { + clear: both; +} +.modal-footer .btn { + float: right; + margin-left: 5px; + margin-bottom: 0; +} +.tooltip { + position: absolute; + z-index: 1020; + display: block; + visibility: visible; + padding: 5px; + font-size: 11px; + opacity: 0; + filter: alpha(opacity=0); +} +.tooltip.in { + opacity: 0.8; + filter: alpha(opacity=80); +} +.tooltip.top { + margin-top: -2px; +} +.tooltip.right { + margin-left: 2px; +} +.tooltip.bottom { + margin-top: 2px; +} +.tooltip.left { + margin-left: -2px; +} +.tooltip.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid #000000; +} +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #000000; +} +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-bottom: 5px solid #000000; +} +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-right: 5px solid #000000; +} +.tooltip-inner { + max-width: 200px; + padding: 3px 8px; + color: #ffffff; + text-align: center; + text-decoration: none; + background-color: #000000; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; +} +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1010; + display: none; + padding: 5px; +} +.popover.top { + margin-top: -5px; +} +.popover.right { + margin-left: 5px; +} +.popover.bottom { + margin-top: 5px; +} +.popover.left { + margin-left: -5px; +} +.popover.top .arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid #000000; +} +.popover.right .arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-right: 5px solid #000000; +} +.popover.bottom .arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-bottom: 5px solid #000000; +} +.popover.left .arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #000000; +} +.popover .arrow { + position: absolute; + width: 0; + height: 0; +} +.popover-inner { + padding: 3px; + width: 280px; + overflow: hidden; + background: #000000; + background: rgba(0, 0, 0, 0.8); + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); +} +.popover-title { + padding: 9px 15px; + line-height: 1; + background-color: #f5f5f5; + border-bottom: 1px solid #eee; + -webkit-border-radius: 3px 3px 0 0; + -moz-border-radius: 3px 3px 0 0; + border-radius: 3px 3px 0 0; +} +.popover-content { + padding: 14px; + background-color: #ffffff; + -webkit-border-radius: 0 0 3px 3px; + -moz-border-radius: 0 0 3px 3px; + border-radius: 0 0 3px 3px; + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.popover-content p, .popover-content ul, .popover-content ol { + margin-bottom: 0; +} +.thumbnails { + margin-left: -20px; + list-style: none; + *zoom: 1; +} +.thumbnails:before, .thumbnails:after { + display: table; + content: ""; +} +.thumbnails:after { + clear: both; +} +.thumbnails > li { + float: left; + margin: 0 0 18px 20px; +} +.thumbnail { + display: block; + padding: 4px; + line-height: 1; + border: 1px solid #ddd; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); +} +a.thumbnail:hover { + border-color: #0088cc; + -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); +} +.thumbnail > img { + display: block; + max-width: 100%; + margin-left: auto; + margin-right: auto; +} +.thumbnail .caption { + padding: 9px; +} +.label { + padding: 2px 4px 3px; + font-size: 11.049999999999999px; + font-weight: bold; + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #999999; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.label:hover { + color: #ffffff; + text-decoration: none; +} +.label-important { + background-color: #b94a48; +} +.label-important:hover { + background-color: #953b39; +} +.label-warning { + background-color: #f89406; +} +.label-warning:hover { + background-color: #c67605; +} +.label-success { + background-color: #468847; +} +.label-success:hover { + background-color: #356635; +} +.label-info { + background-color: #3a87ad; +} +.label-info:hover { + background-color: #2d6987; +} +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +@-moz-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +@keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +.progress { + overflow: hidden; + height: 18px; + margin-bottom: 18px; + background-color: #f7f7f7; + background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -ms-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9)); + background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: linear-gradient(top, #f5f5f5, #f9f9f9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0); + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.progress .bar { + width: 0%; + height: 18px; + color: #ffffff; + font-size: 12px; + text-align: center; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #0e90d2; + background-image: -moz-linear-gradient(top, #149bdf, #0480be); + background-image: -ms-linear-gradient(top, #149bdf, #0480be); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be)); + background-image: -webkit-linear-gradient(top, #149bdf, #0480be); + background-image: -o-linear-gradient(top, #149bdf, #0480be); + background-image: linear-gradient(top, #149bdf, #0480be); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0); + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition: width 0.6s ease; + -moz-transition: width 0.6s ease; + -ms-transition: width 0.6s ease; + -o-transition: width 0.6s ease; + transition: width 0.6s ease; +} +.progress-striped .bar { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + -webkit-background-size: 40px 40px; + -moz-background-size: 40px 40px; + -o-background-size: 40px 40px; + background-size: 40px 40px; +} +.progress.active .bar { + -webkit-animation: progress-bar-stripes 2s linear infinite; + -moz-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} +.progress-danger .bar { + background-color: #dd514c; + background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -o-linear-gradient(top, #ee5f5b, #c43c35); + background-image: linear-gradient(top, #ee5f5b, #c43c35); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0); +} +.progress-danger.progress-striped .bar { + background-color: #ee5f5b; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-success .bar { + background-color: #5eb95e; + background-image: -moz-linear-gradient(top, #62c462, #57a957); + background-image: -ms-linear-gradient(top, #62c462, #57a957); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957)); + background-image: -webkit-linear-gradient(top, #62c462, #57a957); + background-image: -o-linear-gradient(top, #62c462, #57a957); + background-image: linear-gradient(top, #62c462, #57a957); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0); +} +.progress-success.progress-striped .bar { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-info .bar { + background-color: #4bb1cf; + background-image: -moz-linear-gradient(top, #5bc0de, #339bb9); + background-image: -ms-linear-gradient(top, #5bc0de, #339bb9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9)); + background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9); + background-image: -o-linear-gradient(top, #5bc0de, #339bb9); + background-image: linear-gradient(top, #5bc0de, #339bb9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0); +} +.progress-info.progress-striped .bar { + background-color: #5bc0de; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.accordion { + margin-bottom: 18px; +} +.accordion-group { + margin-bottom: 2px; + border: 1px solid #e5e5e5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.accordion-heading { + border-bottom: 0; +} +.accordion-heading .accordion-toggle { + display: block; + padding: 8px 15px; +} +.accordion-inner { + padding: 9px 15px; + border-top: 1px solid #e5e5e5; +} +.carousel { + position: relative; + margin-bottom: 18px; + line-height: 1; +} +.carousel-inner { + overflow: hidden; + width: 100%; + position: relative; +} +.carousel .item { + display: none; + position: relative; + -webkit-transition: 0.6s ease-in-out left; + -moz-transition: 0.6s ease-in-out left; + -ms-transition: 0.6s ease-in-out left; + -o-transition: 0.6s ease-in-out left; + transition: 0.6s ease-in-out left; +} +.carousel .item > img { + display: block; + line-height: 1; +} +.carousel .active, .carousel .next, .carousel .prev { + display: block; +} +.carousel .active { + left: 0; +} +.carousel .next, .carousel .prev { + position: absolute; + top: 0; + width: 100%; +} +.carousel .next { + left: 100%; +} +.carousel .prev { + left: -100%; +} +.carousel .next.left, .carousel .prev.right { + left: 0; +} +.carousel .active.left { + left: -100%; +} +.carousel .active.right { + left: 100%; +} +.carousel-control { + position: absolute; + top: 40%; + left: 15px; + width: 40px; + height: 40px; + margin-top: -20px; + font-size: 60px; + font-weight: 100; + line-height: 30px; + color: #ffffff; + text-align: center; + background: #222222; + border: 3px solid #ffffff; + -webkit-border-radius: 23px; + -moz-border-radius: 23px; + border-radius: 23px; + opacity: 0.5; + filter: alpha(opacity=50); +} +.carousel-control.right { + left: auto; + right: 15px; +} +.carousel-control:hover { + color: #ffffff; + text-decoration: none; + opacity: 0.9; + filter: alpha(opacity=90); +} +.carousel-caption { + position: absolute; + left: 0; + right: 0; + bottom: 0; + padding: 10px 15px 5px; + background: #333333; + background: rgba(0, 0, 0, 0.75); +} +.carousel-caption h4, .carousel-caption p { + color: #ffffff; +} +.hero-unit { + padding: 60px; + margin-bottom: 30px; + background-color: #f5f5f5; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} +.hero-unit h1 { + margin-bottom: 0; + font-size: 60px; + line-height: 1; + letter-spacing: -1px; +} +.hero-unit p { + font-size: 18px; + font-weight: 200; + line-height: 27px; +} +.pull-right { + float: right; +} +.pull-left { + float: left; +} +.hide { + display: none; +} +.show { + display: block; +} +.invisible { + visibility: hidden; +} diff --git a/src/nl/astraeus/jdbc/web/resources/images/loading.gif b/src/nl/astraeus/jdbc/web/resources/images/loading.gif new file mode 100644 index 0000000..21c7e74 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/images/loading.gif Binary files differ diff --git a/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png b/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png new file mode 100644 index 0000000..92d4445 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png Binary files differ diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-alert.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-alert.js new file mode 100644 index 0000000..2242ddd --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-alert.js @@ -0,0 +1,94 @@ +/* ========================================================== + * bootstrap-alert.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#alerts + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function( $ ){ + + "use strict" + + /* ALERT CLASS DEFINITION + * ====================== */ + + var dismiss = '[data-dismiss="alert"]' + , Alert = function ( el ) { + $(el).on('click', dismiss, this.close) + } + + Alert.prototype = { + + constructor: Alert + + , close: function ( e ) { + var $this = $(this) + , selector = $this.attr('data-target') + , $parent + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = $(selector) + $parent.trigger('close') + + e && e.preventDefault() + + $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent()) + + $parent + .trigger('close') + .removeClass('in') + + function removeElement() { + $parent + .trigger('closed') + .remove() + } + + $.support.transition && $parent.hasClass('fade') ? + $parent.on($.support.transition.end, removeElement) : + removeElement() + } + + } + + + /* ALERT PLUGIN DEFINITION + * ======================= */ + + $.fn.alert = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('alert') + if (!data) $this.data('alert', (data = new Alert(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.alert.Constructor = Alert + + + /* ALERT DATA-API + * ============== */ + + $(function () { + $('body').on('click.alert.data-api', dismiss, Alert.prototype.close) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-button.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-button.js new file mode 100644 index 0000000..0238ca3 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-button.js @@ -0,0 +1,100 @@ +/* ============================================================ + * bootstrap-button.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#buttons + * ============================================================ + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + +!function( $ ){ + + "use strict" + + /* BUTTON PUBLIC CLASS DEFINITION + * ============================== */ + + var Button = function ( element, options ) { + this.$element = $(element) + this.options = $.extend({}, $.fn.button.defaults, options) + } + + Button.prototype = { + + constructor: Button + + , setState: function ( state ) { + var d = 'disabled' + , $el = this.$element + , data = $el.data() + , val = $el.is('input') ? 'val' : 'html' + + state = state + 'Text' + data.resetText || $el.data('resetText', $el[val]()) + + $el[val](data[state] || this.options[state]) + + // push to event loop to allow forms to submit + setTimeout(function () { + state == 'loadingText' ? + $el.addClass(d).attr(d, d) : + $el.removeClass(d).removeAttr(d) + }, 0) + } + + , toggle: function () { + var $parent = this.$element.parent('[data-toggle="buttons-radio"]') + + $parent && $parent + .find('.active') + .removeClass('active') + + this.$element.toggleClass('active') + } + + } + + + /* BUTTON PLUGIN DEFINITION + * ======================== */ + + $.fn.button = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('button') + , options = typeof option == 'object' && option + if (!data) $this.data('button', (data = new Button(this, options))) + if (option == 'toggle') data.toggle() + else if (option) data.setState(option) + }) + } + + $.fn.button.defaults = { + loadingText: 'loading...' + } + + $.fn.button.Constructor = Button + + + /* BUTTON DATA-API + * =============== */ + + $(function () { + $('body').on('click.button.data-api', '[data-toggle^=button]', function ( e ) { + var $btn = $(e.target) + if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') + $btn.button('toggle') + }) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-carousel.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-carousel.js new file mode 100644 index 0000000..810256e --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-carousel.js @@ -0,0 +1,157 @@ +/* ========================================================== + * bootstrap-carousel.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#carousel + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function( $ ){ + + "use strict" + + /* CAROUSEL CLASS DEFINITION + * ========================= */ + + var Carousel = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, $.fn.carousel.defaults, options) + this.options.slide && this.slide(this.options.slide) + } + + Carousel.prototype = { + + cycle: function () { + this.interval = setInterval($.proxy(this.next, this), this.options.interval) + return this + } + + , to: function (pos) { + var $active = this.$element.find('.active') + , children = $active.parent().children() + , activePos = children.index($active) + , that = this + + if (pos > (children.length - 1) || pos < 0) return + + if (this.sliding) { + return this.$element.one('slid', function () { + that.to(pos) + }) + } + + if (activePos == pos) { + return this.pause().cycle() + } + + return this.slide(pos > activePos ? 'next' : 'prev', $(children[pos])) + } + + , pause: function () { + clearInterval(this.interval) + this.interval = null + return this + } + + , next: function () { + if (this.sliding) return + return this.slide('next') + } + + , prev: function () { + if (this.sliding) return + return this.slide('prev') + } + + , slide: function (type, next) { + var $active = this.$element.find('.active') + , $next = next || $active[type]() + , isCycling = this.interval + , direction = type == 'next' ? 'left' : 'right' + , fallback = type == 'next' ? 'first' : 'last' + , that = this + + if (!$next.length) return + + this.sliding = true + + isCycling && this.pause() + + $next = $next.length ? $next : this.$element.find('.item')[fallback]() + + if (!$.support.transition && this.$element.hasClass('slide')) { + this.$element.trigger('slide') + $active.removeClass('active') + $next.addClass('active') + this.sliding = false + this.$element.trigger('slid') + } else { + $next.addClass(type) + $next[0].offsetWidth // force reflow + $active.addClass(direction) + $next.addClass(direction) + this.$element.trigger('slide') + this.$element.one($.support.transition.end, function () { + $next.removeClass([type, direction].join(' ')).addClass('active') + $active.removeClass(['active', direction].join(' ')) + that.sliding = false + setTimeout(function () { that.$element.trigger('slid') }, 0) + }) + } + + isCycling && this.cycle() + + return this + } + + } + + + /* CAROUSEL PLUGIN DEFINITION + * ========================== */ + + $.fn.carousel = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('carousel') + , options = typeof option == 'object' && option + if (!data) $this.data('carousel', (data = new Carousel(this, options))) + if (typeof option == 'number') data.to(option) + else if (typeof option == 'string' || (option = options.slide)) data[option]() + else data.cycle() + }) + } + + $.fn.carousel.defaults = { + interval: 5000 + } + + $.fn.carousel.Constructor = Carousel + + + /* CAROUSEL DATA-API + * ================= */ + + $(function () { + $('body').on('click.carousel.data-api', '[data-slide]', function ( e ) { + var $this = $(this), href + , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 + , options = !$target.data('modal') && $.extend({}, $target.data(), $this.data()) + $target.carousel(options) + e.preventDefault() + }) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-collapse.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-collapse.js new file mode 100644 index 0000000..d195efc --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-collapse.js @@ -0,0 +1,136 @@ +/* ============================================================= + * bootstrap-collapse.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#collapse + * ============================================================= + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + +!function( $ ){ + + "use strict" + + var Collapse = function ( element, options ) { + this.$element = $(element) + this.options = $.extend({}, $.fn.collapse.defaults, options) + + if (this.options["parent"]) { + this.$parent = $(this.options["parent"]) + } + + this.options.toggle && this.toggle() + } + + Collapse.prototype = { + + constructor: Collapse + + , dimension: function () { + var hasWidth = this.$element.hasClass('width') + return hasWidth ? 'width' : 'height' + } + + , show: function () { + var dimension = this.dimension() + , scroll = $.camelCase(['scroll', dimension].join('-')) + , actives = this.$parent && this.$parent.find('.in') + , hasData + + if (actives && actives.length) { + hasData = actives.data('collapse') + actives.collapse('hide') + hasData || actives.data('collapse', null) + } + + this.$element[dimension](0) + this.transition('addClass', 'show', 'shown') + this.$element[dimension](this.$element[0][scroll]) + + } + + , hide: function () { + var dimension = this.dimension() + this.reset(this.$element[dimension]()) + this.transition('removeClass', 'hide', 'hidden') + this.$element[dimension](0) + } + + , reset: function ( size ) { + var dimension = this.dimension() + + this.$element + .removeClass('collapse') + [dimension](size || 'auto') + [0].offsetWidth + + this.$element.addClass('collapse') + } + + , transition: function ( method, startEvent, completeEvent ) { + var that = this + , complete = function () { + if (startEvent == 'show') that.reset() + that.$element.trigger(completeEvent) + } + + this.$element + .trigger(startEvent) + [method]('in') + + $.support.transition && this.$element.hasClass('collapse') ? + this.$element.one($.support.transition.end, complete) : + complete() + } + + , toggle: function () { + this[this.$element.hasClass('in') ? 'hide' : 'show']() + } + + } + + /* COLLAPSIBLE PLUGIN DEFINITION + * ============================== */ + + $.fn.collapse = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('collapse') + , options = typeof option == 'object' && option + if (!data) $this.data('collapse', (data = new Collapse(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.collapse.defaults = { + toggle: true + } + + $.fn.collapse.Constructor = Collapse + + + /* COLLAPSIBLE DATA-API + * ==================== */ + + $(function () { + $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function ( e ) { + var $this = $(this), href + , target = $this.attr('data-target') + || e.preventDefault() + || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 + , option = $(target).data('collapse') ? 'toggle' : $this.data() + $(target).collapse(option) + }) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-dropdown.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-dropdown.js new file mode 100644 index 0000000..f1f6c33 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-dropdown.js @@ -0,0 +1,92 @@ +/* ============================================================ + * bootstrap-dropdown.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#dropdowns + * ============================================================ + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + + +!function( $ ){ + + "use strict" + + /* DROPDOWN CLASS DEFINITION + * ========================= */ + + var toggle = '[data-toggle="dropdown"]' + , Dropdown = function ( element ) { + var $el = $(element).on('click.dropdown.data-api', this.toggle) + $('html').on('click.dropdown.data-api', function () { + $el.parent().removeClass('open') + }) + } + + Dropdown.prototype = { + + constructor: Dropdown + + , toggle: function ( e ) { + var $this = $(this) + , selector = $this.attr('data-target') + , $parent + , isActive + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = $(selector) + $parent.length || ($parent = $this.parent()) + + isActive = $parent.hasClass('open') + + clearMenus() + !isActive && $parent.toggleClass('open') + + return false + } + + } + + function clearMenus() { + $(toggle).parent().removeClass('open') + } + + + /* DROPDOWN PLUGIN DEFINITION + * ========================== */ + + $.fn.dropdown = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('dropdown') + if (!data) $this.data('dropdown', (data = new Dropdown(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.dropdown.Constructor = Dropdown + + + /* APPLY TO STANDARD DROPDOWN ELEMENTS + * =================================== */ + + $(function () { + $('html').on('click.dropdown.data-api', clearMenus) + $('body').on('click.dropdown.data-api', toggle, Dropdown.prototype.toggle) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-modal.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-modal.js new file mode 100644 index 0000000..bceb303 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-modal.js @@ -0,0 +1,210 @@ +/* ========================================================= + * bootstrap-modal.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#modals + * ========================================================= + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================= */ + + +!function( $ ){ + + "use strict" + + /* MODAL CLASS DEFINITION + * ====================== */ + + var Modal = function ( content, options ) { + this.options = options + this.$element = $(content) + .delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this)) + } + + Modal.prototype = { + + constructor: Modal + + , toggle: function () { + return this[!this.isShown ? 'show' : 'hide']() + } + + , show: function () { + var that = this + + if (this.isShown) return + + $('body').addClass('modal-open') + + this.isShown = true + this.$element.trigger('show') + + escape.call(this) + backdrop.call(this, function () { + var transition = $.support.transition && that.$element.hasClass('fade') + + !that.$element.parent().length && that.$element.appendTo(document.body) //don't move modals dom position + + that.$element + .show() + + if (transition) { + that.$element[0].offsetWidth // force reflow + } + + that.$element.addClass('in') + + transition ? + that.$element.one($.support.transition.end, function () { that.$element.trigger('shown') }) : + that.$element.trigger('shown') + + }) + } + + , hide: function ( e ) { + e && e.preventDefault() + + if (!this.isShown) return + + var that = this + this.isShown = false + + $('body').removeClass('modal-open') + + escape.call(this) + + this.$element + .trigger('hide') + .removeClass('in') + + $.support.transition && this.$element.hasClass('fade') ? + hideWithTransition.call(this) : + hideModal.call(this) + } + + } + + + /* MODAL PRIVATE METHODS + * ===================== */ + + function hideWithTransition() { + var that = this + , timeout = setTimeout(function () { + that.$element.off($.support.transition.end) + hideModal.call(that) + }, 500) + + this.$element.one($.support.transition.end, function () { + clearTimeout(timeout) + hideModal.call(that) + }) + } + + function hideModal( that ) { + this.$element + .hide() + .trigger('hidden') + + backdrop.call(this) + } + + function backdrop( callback ) { + var that = this + , animate = this.$element.hasClass('fade') ? 'fade' : '' + + if (this.isShown && this.options.backdrop) { + var doAnimate = $.support.transition && animate + + this.$backdrop = $(' + + + + + \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/head.html b/src/nl/astraeus/jdbc/web/head.html new file mode 100644 index 0000000..0f8f6a3 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/head.html @@ -0,0 +1,96 @@ + + + + + + + Simple JDBC Statistics + + + + + + + + + + + + + + + + + + + +
+
+ +
+ diff --git a/src/nl/astraeus/jdbc/web/page/Menu.html b/src/nl/astraeus/jdbc/web/page/Menu.html new file mode 100644 index 0000000..505c7c2 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.html @@ -0,0 +1,42 @@ + diff --git a/src/nl/astraeus/jdbc/web/page/Menu.java b/src/nl/astraeus/jdbc/web/page/Menu.java new file mode 100644 index 0000000..f0a349a --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.java @@ -0,0 +1,27 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 9:07 PM + */ +public class Menu extends TemplatePage { + + @Override + public Page processRequest(HttpServletRequest request) { + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + result.put("user", request.getSession().getAttribute("user")); + + return result; + } +} diff --git a/src/nl/astraeus/jdbc/web/page/Page.java b/src/nl/astraeus/jdbc/web/page/Page.java new file mode 100644 index 0000000..9d526d6 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Page.java @@ -0,0 +1,17 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:20 PM + */ +public abstract class Page { + + public abstract Page processRequest(HttpServletRequest request); + public abstract Map defineModel(HttpServletRequest request); + public abstract String render(HttpServletRequest request); + +} diff --git a/src/nl/astraeus/jdbc/web/page/QueryOverview.html b/src/nl/astraeus/jdbc/web/page/QueryOverview.html new file mode 100644 index 0000000..64a88fb --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/QueryOverview.html @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + {foreach(queries as q)} + + + + + + + {eachend} + +
Total timeAvg. time# CallsSql
{q.total}{q.nano}{q.count}{q.sql}
diff --git a/src/nl/astraeus/jdbc/web/page/QueryOverview.java b/src/nl/astraeus/jdbc/web/page/QueryOverview.java new file mode 100644 index 0000000..02982f1 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/QueryOverview.java @@ -0,0 +1,92 @@ +package nl.astraeus.jdbc.web.page; + +import nl.astraeus.jdbc.JdbcLogger; + +import javax.servlet.http.HttpServletRequest; +import java.util.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 9:16 PM + */ +public class QueryOverview extends TemplatePage { + + boolean sortTotalCalls = true; + boolean sortAvgTime = false; + boolean sortTotalTime = false; + + @Override + public Page processRequest(HttpServletRequest request) { + if ("sortTotalCalls".equals(request.getParameter("action"))) { + sortTotalCalls = true; + sortAvgTime = false; + sortTotalTime = false; + } else if ("sortAvgTime".equals(request.getParameter("action"))) { + sortTotalCalls = false; + sortAvgTime = true; + sortTotalTime = false; + } else if ("sortTotalTime".equals(request.getParameter("action"))) { + sortTotalCalls = false; + sortAvgTime = false; + sortTotalTime = true; + } + + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + List entries = new ArrayList(JdbcLogger.get().getEntries()); + + if (sortTotalCalls) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + return o2.count - o1.count; + } + }); + } else if (sortAvgTime) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + long n1 = o1.nano / o1.count; + long n2 = o2.nano / o2.count; + + if (n2 > n1) { + return 1; + } else if (n2 < n1) { + return -1; + } else { + return 0; + } + } + }); + } else if (sortTotalTime) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + if (o2.nano > o1.nano) { + return 1; + } else if (o2.nano < o1.nano) { + return -1; + } else { + return 0; + } + } + }); + } + + result.put("queries", entries); + result.put("count", entries.size()); + + result.put("sortTotalCalls", sortTotalCalls); + result.put("sortAvgTime", sortAvgTime); + result.put("sortTotalTime", sortTotalTime); + + return result; + } + +} diff --git a/src/nl/astraeus/jdbc/web/page/TemplatePage.java b/src/nl/astraeus/jdbc/web/page/TemplatePage.java new file mode 100644 index 0000000..33e2641 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/TemplatePage.java @@ -0,0 +1,58 @@ +package nl.astraeus.jdbc.web.page; + +import nl.astraeus.template.EscapeMode; +import nl.astraeus.template.SimpleTemplate; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:20 PM + */ +public abstract class TemplatePage extends Page { + + private SimpleTemplate template; + + protected TemplatePage() { + template = getSimpleTemplate(this.getClass()); + } + + public String render(HttpServletRequest request) { + return template.render(defineModel(request)); + } + + private static Map templateCache = new HashMap(); + + public synchronized static SimpleTemplate getSimpleTemplate(Class cls) { + SimpleTemplate result = templateCache.get(cls); + + if (result == null) { + InputStream in = null; + + try { + in = cls.getResourceAsStream(cls.getSimpleName() + ".html"); + + result = SimpleTemplate.readTemplate('{','}', EscapeMode.HTML, in); + + templateCache.put(cls, result); + } catch (IOException e) { + throw new IllegalStateException(e); + } finally { + if (in != null) { + try { + in.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + + return result; + } +} diff --git a/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css b/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css new file mode 100644 index 0000000..0e0056f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css @@ -0,0 +1,581 @@ +/*! + * Bootstrap Responsive v2.0.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ +.clearfix { + *zoom: 1; +} +.clearfix:before, .clearfix:after { + display: table; + content: ""; +} +.clearfix:after { + clear: both; +} +.hidden { + display: none; + visibility: hidden; +} +@media (max-width: 480px) { + .nav-collapse { + -webkit-transform: translate3d(0, 0, 0); + } + .page-header h1 small { + display: block; + line-height: 18px; + } + input[class*="span"], + select[class*="span"], + textarea[class*="span"], + .uneditable-input { + display: block; + width: 100%; + min-height: 28px; + /* Make inputs at least the height of their button counterpart */ + + /* Makes inputs behave like true block-level elements */ + + -webkit-box-sizing: border-box; + /* Older Webkit */ + + -moz-box-sizing: border-box; + /* Older FF */ + + -ms-box-sizing: border-box; + /* IE8 */ + + box-sizing: border-box; + /* CSS3 spec*/ + + } + .input-prepend input[class*="span"], .input-append input[class*="span"] { + width: auto; + } + input[type="checkbox"], input[type="radio"] { + border: 1px solid #ccc; + } + .form-horizontal .control-group > label { + float: none; + width: auto; + padding-top: 0; + text-align: left; + } + .form-horizontal .controls { + margin-left: 0; + } + .form-horizontal .control-list { + padding-top: 0; + } + .form-horizontal .form-actions { + padding-left: 10px; + padding-right: 10px; + } + .modal { + position: absolute; + top: 10px; + left: 10px; + right: 10px; + width: auto; + margin: 0; + } + .modal.fade.in { + top: auto; + } + .modal-header .close { + padding: 10px; + margin: -10px; + } + .carousel-caption { + position: static; + } +} +@media (max-width: 767px) { + .container { + width: auto; + padding: 0 20px; + } + .row-fluid { + width: 100%; + } + .row { + margin-left: 0; + } + .row > [class*="span"], .row-fluid > [class*="span"] { + float: none; + display: block; + width: auto; + margin: 0; + } +} +@media (min-width: 768px) and (max-width: 979px) { + .row { + margin-left: -20px; + *zoom: 1; + } + .row:before, .row:after { + display: table; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + margin-left: 20px; + } + .span1 { + width: 42px; + } + .span2 { + width: 104px; + } + .span3 { + width: 166px; + } + .span4 { + width: 228px; + } + .span5 { + width: 290px; + } + .span6 { + width: 352px; + } + .span7 { + width: 414px; + } + .span8 { + width: 476px; + } + .span9 { + width: 538px; + } + .span10 { + width: 600px; + } + .span11 { + width: 662px; + } + .span12, .container { + width: 724px; + } + .offset1 { + margin-left: 82px; + } + .offset2 { + margin-left: 144px; + } + .offset3 { + margin-left: 206px; + } + .offset4 { + margin-left: 268px; + } + .offset5 { + margin-left: 330px; + } + .offset6 { + margin-left: 392px; + } + .offset7 { + margin-left: 454px; + } + .offset8 { + margin-left: 516px; + } + .offset9 { + margin-left: 578px; + } + .offset10 { + margin-left: 640px; + } + .offset11 { + margin-left: 702px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, .row-fluid:after { + display: table; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid > [class*="span"] { + float: left; + margin-left: 2.762430939%; + } + .row-fluid > [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid > .span1 { + width: 5.801104972%; + } + .row-fluid > .span2 { + width: 14.364640883%; + } + .row-fluid > .span3 { + width: 22.928176794%; + } + .row-fluid > .span4 { + width: 31.491712705%; + } + .row-fluid > .span5 { + width: 40.055248616%; + } + .row-fluid > .span6 { + width: 48.618784527%; + } + .row-fluid > .span7 { + width: 57.182320438000005%; + } + .row-fluid > .span8 { + width: 65.74585634900001%; + } + .row-fluid > .span9 { + width: 74.30939226%; + } + .row-fluid > .span10 { + width: 82.87292817100001%; + } + .row-fluid > .span11 { + width: 91.436464082%; + } + .row-fluid > .span12 { + width: 99.999999993%; + } + input.span1, textarea.span1, .uneditable-input.span1 { + width: 32px; + } + input.span2, textarea.span2, .uneditable-input.span2 { + width: 94px; + } + input.span3, textarea.span3, .uneditable-input.span3 { + width: 156px; + } + input.span4, textarea.span4, .uneditable-input.span4 { + width: 218px; + } + input.span5, textarea.span5, .uneditable-input.span5 { + width: 280px; + } + input.span6, textarea.span6, .uneditable-input.span6 { + width: 342px; + } + input.span7, textarea.span7, .uneditable-input.span7 { + width: 404px; + } + input.span8, textarea.span8, .uneditable-input.span8 { + width: 466px; + } + input.span9, textarea.span9, .uneditable-input.span9 { + width: 528px; + } + input.span10, textarea.span10, .uneditable-input.span10 { + width: 590px; + } + input.span11, textarea.span11, .uneditable-input.span11 { + width: 652px; + } + input.span12, textarea.span12, .uneditable-input.span12 { + width: 714px; + } +} +@media (max-width: 979px) { + body { + padding-top: 0; + } + .navbar-fixed-top { + position: static; + margin-bottom: 18px; + } + .navbar-fixed-top .navbar-inner { + padding: 5px; + } + .navbar .container { + width: auto; + padding: 0; + } + .navbar .brand { + padding-left: 10px; + padding-right: 10px; + margin: 0 0 0 -5px; + } + .navbar .nav-collapse { + clear: left; + } + .navbar .nav { + float: none; + margin: 0 0 9px; + } + .navbar .nav > li { + float: none; + } + .navbar .nav > li > a { + margin-bottom: 2px; + } + .navbar .nav > .divider-vertical { + display: none; + } + .navbar .nav .nav-header { + color: #999999; + text-shadow: none; + } + .navbar .nav > li > a, .navbar .dropdown-menu a { + padding: 6px 15px; + font-weight: bold; + color: #999999; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + } + .navbar .dropdown-menu li + li a { + margin-bottom: 2px; + } + .navbar .nav > li > a:hover, .navbar .dropdown-menu a:hover { + background-color: #222222; + } + .navbar .dropdown-menu { + position: static; + top: auto; + left: auto; + float: none; + display: block; + max-width: none; + margin: 0 15px; + padding: 0; + background-color: transparent; + border: none; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + } + .navbar .dropdown-menu:before, .navbar .dropdown-menu:after { + display: none; + } + .navbar .dropdown-menu .divider { + display: none; + } + .navbar-form, .navbar-search { + float: none; + padding: 9px 15px; + margin: 9px 0; + border-top: 1px solid #222222; + border-bottom: 1px solid #222222; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + } + .navbar .nav.pull-right { + float: none; + margin-left: 0; + } + .navbar-static .navbar-inner { + padding-left: 10px; + padding-right: 10px; + } + .btn-navbar { + display: block; + } + .nav-collapse { + overflow: hidden; + height: 0; + } +} +@media (min-width: 980px) { + .nav-collapse.collapse { + height: auto !important; + } +} +@media (min-width: 1200px) { + .row { + margin-left: -30px; + *zoom: 1; + } + .row:before, .row:after { + display: table; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + margin-left: 30px; + } + .span1 { + width: 70px; + } + .span2 { + width: 170px; + } + .span3 { + width: 270px; + } + .span4 { + width: 370px; + } + .span5 { + width: 470px; + } + .span6 { + width: 570px; + } + .span7 { + width: 670px; + } + .span8 { + width: 770px; + } + .span9 { + width: 870px; + } + .span10 { + width: 970px; + } + .span11 { + width: 1070px; + } + .span12, .container { + width: 1170px; + } + .offset1 { + margin-left: 130px; + } + .offset2 { + margin-left: 230px; + } + .offset3 { + margin-left: 330px; + } + .offset4 { + margin-left: 430px; + } + .offset5 { + margin-left: 530px; + } + .offset6 { + margin-left: 630px; + } + .offset7 { + margin-left: 730px; + } + .offset8 { + margin-left: 830px; + } + .offset9 { + margin-left: 930px; + } + .offset10 { + margin-left: 1030px; + } + .offset11 { + margin-left: 1130px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, .row-fluid:after { + display: table; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid > [class*="span"] { + float: left; + margin-left: 2.564102564%; + } + .row-fluid > [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid > .span1 { + width: 5.982905983%; + } + .row-fluid > .span2 { + width: 14.529914530000001%; + } + .row-fluid > .span3 { + width: 23.076923077%; + } + .row-fluid > .span4 { + width: 31.623931624%; + } + .row-fluid > .span5 { + width: 40.170940171000005%; + } + .row-fluid > .span6 { + width: 48.717948718%; + } + .row-fluid > .span7 { + width: 57.264957265%; + } + .row-fluid > .span8 { + width: 65.81196581200001%; + } + .row-fluid > .span9 { + width: 74.358974359%; + } + .row-fluid > .span10 { + width: 82.905982906%; + } + .row-fluid > .span11 { + width: 91.45299145300001%; + } + .row-fluid > .span12 { + width: 100%; + } + input.span1, textarea.span1, .uneditable-input.span1 { + width: 60px; + } + input.span2, textarea.span2, .uneditable-input.span2 { + width: 160px; + } + input.span3, textarea.span3, .uneditable-input.span3 { + width: 260px; + } + input.span4, textarea.span4, .uneditable-input.span4 { + width: 360px; + } + input.span5, textarea.span5, .uneditable-input.span5 { + width: 460px; + } + input.span6, textarea.span6, .uneditable-input.span6 { + width: 560px; + } + input.span7, textarea.span7, .uneditable-input.span7 { + width: 660px; + } + input.span8, textarea.span8, .uneditable-input.span8 { + width: 760px; + } + input.span9, textarea.span9, .uneditable-input.span9 { + width: 860px; + } + input.span10, textarea.span10, .uneditable-input.span10 { + width: 960px; + } + input.span11, textarea.span11, .uneditable-input.span11 { + width: 1060px; + } + input.span12, textarea.span12, .uneditable-input.span12 { + width: 1160px; + } + .thumbnails { + margin-left: -30px; + } + .thumbnails > li { + margin-left: 30px; + } +} diff --git a/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css b/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css new file mode 100644 index 0000000..6229c12 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css @@ -0,0 +1,3521 @@ +/*! + * Bootstrap v2.0.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +nav, +section { + display: block; +} +audio, canvas, video { + display: inline-block; + *display: inline; + *zoom: 1; +} +audio:not([controls]) { + display: none; +} +html { + font-size: 100%; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} +a:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +a:hover, a:active { + outline: 0; +} +sub, sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} +sup { + top: -0.5em; +} +sub { + bottom: -0.25em; +} +img { + max-width: 100%; + height: auto; + border: 0; + -ms-interpolation-mode: bicubic; +} +button, +input, +select, +textarea { + margin: 0; + font-size: 100%; + vertical-align: middle; +} +button, input { + *overflow: visible; + line-height: normal; +} +button::-moz-focus-inner, input::-moz-focus-inner { + padding: 0; + border: 0; +} +button, +input[type="button"], +input[type="reset"], +input[type="submit"] { + cursor: pointer; + -webkit-appearance: button; +} +input[type="search"] { + -webkit-appearance: textfield; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +input[type="search"]::-webkit-search-decoration, input[type="search"]::-webkit-search-cancel-button { + -webkit-appearance: none; +} +textarea { + overflow: auto; + vertical-align: top; +} +.clearfix { + *zoom: 1; +} +.clearfix:before, .clearfix:after { + display: table; + content: ""; +} +.clearfix:after { + clear: both; +} +body { + margin: 0; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 18px; + color: #333333; + background-color: #ffffff; +} +a { + color: #0088cc; + text-decoration: none; +} +a:hover { + color: #005580; + text-decoration: underline; +} +.row { + margin-left: -20px; + *zoom: 1; +} +.row:before, .row:after { + display: table; + content: ""; +} +.row:after { + clear: both; +} +[class*="span"] { + float: left; + margin-left: 20px; +} +.span1 { + width: 60px; +} +.span2 { + width: 140px; +} +.span3 { + width: 220px; +} +.span4 { + width: 300px; +} +.span5 { + width: 380px; +} +.span6 { + width: 460px; +} +.span7 { + width: 540px; +} +.span8 { + width: 620px; +} +.span9 { + width: 700px; +} +.span10 { + width: 780px; +} +.span11 { + width: 860px; +} +.span12, .container { + width: 940px; +} +.offset1 { + margin-left: 100px; +} +.offset2 { + margin-left: 180px; +} +.offset3 { + margin-left: 260px; +} +.offset4 { + margin-left: 340px; +} +.offset5 { + margin-left: 420px; +} +.offset6 { + margin-left: 500px; +} +.offset7 { + margin-left: 580px; +} +.offset8 { + margin-left: 660px; +} +.offset9 { + margin-left: 740px; +} +.offset10 { + margin-left: 820px; +} +.offset11 { + margin-left: 900px; +} +.row-fluid { + width: 100%; + *zoom: 1; +} +.row-fluid:before, .row-fluid:after { + display: table; + content: ""; +} +.row-fluid:after { + clear: both; +} +.row-fluid > [class*="span"] { + float: left; + margin-left: 2.127659574%; +} +.row-fluid > [class*="span"]:first-child { + margin-left: 0; +} +.row-fluid > .span1 { + width: 6.382978723%; +} +.row-fluid > .span2 { + width: 14.89361702%; +} +.row-fluid > .span3 { + width: 23.404255317%; +} +.row-fluid > .span4 { + width: 31.914893614%; +} +.row-fluid > .span5 { + width: 40.425531911%; +} +.row-fluid > .span6 { + width: 48.93617020799999%; +} +.row-fluid > .span7 { + width: 57.446808505%; +} +.row-fluid > .span8 { + width: 65.95744680199999%; +} +.row-fluid > .span9 { + width: 74.468085099%; +} +.row-fluid > .span10 { + width: 82.97872339599999%; +} +.row-fluid > .span11 { + width: 91.489361693%; +} +.row-fluid > .span12 { + width: 99.99999998999999%; +} +.container { + width: 940px; + margin-left: auto; + margin-right: auto; + *zoom: 1; +} +.container:before, .container:after { + display: table; + content: ""; +} +.container:after { + clear: both; +} +.container-fluid { + padding-left: 20px; + padding-right: 20px; + *zoom: 1; +} +.container-fluid:before, .container-fluid:after { + display: table; + content: ""; +} +.container-fluid:after { + clear: both; +} +p { + margin: 0 0 9px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 18px; +} +p small { + font-size: 11px; + color: #999999; +} +.lead { + margin-bottom: 18px; + font-size: 20px; + font-weight: 200; + line-height: 27px; +} +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 0; + font-weight: bold; + color: #333333; + text-rendering: optimizelegibility; +} +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small { + font-weight: normal; + color: #999999; +} +h1 { + font-size: 30px; + line-height: 36px; +} +h1 small { + font-size: 18px; +} +h2 { + font-size: 24px; + line-height: 36px; +} +h2 small { + font-size: 18px; +} +h3 { + line-height: 27px; + font-size: 18px; +} +h3 small { + font-size: 14px; +} +h4, h5, h6 { + line-height: 18px; +} +h4 { + font-size: 14px; +} +h4 small { + font-size: 12px; +} +h5 { + font-size: 12px; +} +h6 { + font-size: 11px; + color: #999999; + text-transform: uppercase; +} +.page-header { + padding-bottom: 17px; + margin: 18px 0; + border-bottom: 1px solid #eeeeee; +} +.page-header h1 { + line-height: 1; +} +ul, ol { + padding: 0; + margin: 0 0 9px 25px; +} +ul ul, +ul ol, +ol ol, +ol ul { + margin-bottom: 0; +} +ul { + list-style: disc; +} +ol { + list-style: decimal; +} +li { + line-height: 18px; +} +ul.unstyled, ol.unstyled { + margin-left: 0; + list-style: none; +} +dl { + margin-bottom: 18px; +} +dt, dd { + line-height: 18px; +} +dt { + font-weight: bold; +} +dd { + margin-left: 9px; +} +hr { + margin: 18px 0; + border: 0; + border-top: 1px solid #eeeeee; + border-bottom: 1px solid #ffffff; +} +strong { + font-weight: bold; +} +em { + font-style: italic; +} +.muted { + color: #999999; +} +abbr { + font-size: 90%; + text-transform: uppercase; + border-bottom: 1px dotted #ddd; + cursor: help; +} +blockquote { + padding: 0 0 0 15px; + margin: 0 0 18px; + border-left: 5px solid #eeeeee; +} +blockquote p { + margin-bottom: 0; + font-size: 16px; + font-weight: 300; + line-height: 22.5px; +} +blockquote small { + display: block; + line-height: 18px; + color: #999999; +} +blockquote small:before { + content: '\2014 \00A0'; +} +blockquote.pull-right { + float: right; + padding-left: 0; + padding-right: 15px; + border-left: 0; + border-right: 5px solid #eeeeee; +} +blockquote.pull-right p, blockquote.pull-right small { + text-align: right; +} +q:before, +q:after, +blockquote:before, +blockquote:after { + content: ""; +} +address { + display: block; + margin-bottom: 18px; + line-height: 18px; + font-style: normal; +} +small { + font-size: 100%; +} +cite { + font-style: normal; +} +code, pre { + padding: 0 3px 2px; + font-family: Menlo, Monaco, "Courier New", monospace; + font-size: 12px; + color: #333333; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +code { + padding: 3px 4px; + color: #d14; + background-color: #f7f7f9; + border: 1px solid #e1e1e8; +} +pre { + display: block; + padding: 8.5px; + margin: 0 0 9px; + font-size: 12px; + line-height: 18px; + background-color: #f5f5f5; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.15); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + white-space: pre; + white-space: pre-wrap; + word-break: break-all; + word-wrap: break-word; +} +pre.prettyprint { + margin-bottom: 18px; +} +pre code { + padding: 0; + color: inherit; + background-color: transparent; + border: 0; +} +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} +form { + margin: 0 0 18px; +} +fieldset { + padding: 0; + margin: 0; + border: 0; +} +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 27px; + font-size: 19.5px; + line-height: 36px; + color: #333333; + border: 0; + border-bottom: 1px solid #eee; +} +legend small { + font-size: 13.5px; + color: #999999; +} +label, +input, +button, +select, +textarea { + font-size: 13px; + font-weight: normal; + line-height: 18px; +} +input, +button, +select, +textarea { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; +} +label { + display: block; + margin-bottom: 5px; + color: #333333; +} +input, +textarea, +select, +.uneditable-input { + display: inline-block; + width: 210px; + height: 18px; + padding: 4px; + margin-bottom: 9px; + font-size: 13px; + line-height: 18px; + color: #555555; + border: 1px solid #ccc; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.uneditable-textarea { + width: auto; + height: auto; +} +label input, label textarea, label select { + display: block; +} +input[type="image"], input[type="checkbox"], input[type="radio"] { + width: auto; + height: auto; + padding: 0; + margin: 3px 0; + *margin-top: 0; + /* IE7 */ + + line-height: normal; + cursor: pointer; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + border: 0 \9; + /* IE9 and down */ + +} +input[type="image"] { + border: 0; +} +input[type="file"] { + width: auto; + padding: initial; + line-height: initial; + border: initial; + background-color: #ffffff; + background-color: initial; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +input[type="button"], input[type="reset"], input[type="submit"] { + width: auto; + height: auto; +} +select, input[type="file"] { + height: 28px; + /* In IE7, the height of the select element cannot be changed by height, only font-size */ + + *margin-top: 4px; + /* For IE7, add top margin to align select with labels */ + + line-height: 28px; +} +input[type="file"] { + line-height: 18px \9; +} +select { + width: 220px; + background-color: #ffffff; +} +select[multiple], select[size] { + height: auto; +} +input[type="image"] { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +textarea { + height: auto; +} +input[type="hidden"] { + display: none; +} +.radio, .checkbox { + padding-left: 18px; +} +.radio input[type="radio"], .checkbox input[type="checkbox"] { + float: left; + margin-left: -18px; +} +.controls > .radio:first-child, .controls > .checkbox:first-child { + padding-top: 5px; +} +.radio.inline, .checkbox.inline { + display: inline-block; + padding-top: 5px; + margin-bottom: 0; + vertical-align: middle; +} +.radio.inline + .radio.inline, .checkbox.inline + .checkbox.inline { + margin-left: 10px; +} +input, textarea { + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; + -moz-transition: border linear 0.2s, box-shadow linear 0.2s; + -ms-transition: border linear 0.2s, box-shadow linear 0.2s; + -o-transition: border linear 0.2s, box-shadow linear 0.2s; + transition: border linear 0.2s, box-shadow linear 0.2s; +} +input:focus, textarea:focus { + border-color: rgba(82, 168, 236, 0.8); + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + outline: 0; + outline: thin dotted \9; + /* IE6-9 */ + +} +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus, +select:focus { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.input-mini { + width: 60px; +} +.input-small { + width: 90px; +} +.input-medium { + width: 150px; +} +.input-large { + width: 210px; +} +.input-xlarge { + width: 270px; +} +.input-xxlarge { + width: 530px; +} +input[class*="span"], +select[class*="span"], +textarea[class*="span"], +.uneditable-input { + float: none; + margin-left: 0; +} +input.span1, textarea.span1, .uneditable-input.span1 { + width: 50px; +} +input.span2, textarea.span2, .uneditable-input.span2 { + width: 130px; +} +input.span3, textarea.span3, .uneditable-input.span3 { + width: 210px; +} +input.span4, textarea.span4, .uneditable-input.span4 { + width: 290px; +} +input.span5, textarea.span5, .uneditable-input.span5 { + width: 370px; +} +input.span6, textarea.span6, .uneditable-input.span6 { + width: 450px; +} +input.span7, textarea.span7, .uneditable-input.span7 { + width: 530px; +} +input.span8, textarea.span8, .uneditable-input.span8 { + width: 610px; +} +input.span9, textarea.span9, .uneditable-input.span9 { + width: 690px; +} +input.span10, textarea.span10, .uneditable-input.span10 { + width: 770px; +} +input.span11, textarea.span11, .uneditable-input.span11 { + width: 850px; +} +input.span12, textarea.span12, .uneditable-input.span12 { + width: 930px; +} +input[disabled], +select[disabled], +textarea[disabled], +input[readonly], +select[readonly], +textarea[readonly] { + background-color: #f5f5f5; + border-color: #ddd; + cursor: not-allowed; +} +.control-group.warning > label, .control-group.warning .help-block, .control-group.warning .help-inline { + color: #c09853; +} +.control-group.warning input, .control-group.warning select, .control-group.warning textarea { + color: #c09853; + border-color: #c09853; +} +.control-group.warning input:focus, .control-group.warning select:focus, .control-group.warning textarea:focus { + border-color: #a47e3c; + -webkit-box-shadow: 0 0 6px #dbc59e; + -moz-box-shadow: 0 0 6px #dbc59e; + box-shadow: 0 0 6px #dbc59e; +} +.control-group.warning .input-prepend .add-on, .control-group.warning .input-append .add-on { + color: #c09853; + background-color: #fcf8e3; + border-color: #c09853; +} +.control-group.error > label, .control-group.error .help-block, .control-group.error .help-inline { + color: #b94a48; +} +.control-group.error input, .control-group.error select, .control-group.error textarea { + color: #b94a48; + border-color: #b94a48; +} +.control-group.error input:focus, .control-group.error select:focus, .control-group.error textarea:focus { + border-color: #953b39; + -webkit-box-shadow: 0 0 6px #d59392; + -moz-box-shadow: 0 0 6px #d59392; + box-shadow: 0 0 6px #d59392; +} +.control-group.error .input-prepend .add-on, .control-group.error .input-append .add-on { + color: #b94a48; + background-color: #f2dede; + border-color: #b94a48; +} +.control-group.success > label, .control-group.success .help-block, .control-group.success .help-inline { + color: #468847; +} +.control-group.success input, .control-group.success select, .control-group.success textarea { + color: #468847; + border-color: #468847; +} +.control-group.success input:focus, .control-group.success select:focus, .control-group.success textarea:focus { + border-color: #356635; + -webkit-box-shadow: 0 0 6px #7aba7b; + -moz-box-shadow: 0 0 6px #7aba7b; + box-shadow: 0 0 6px #7aba7b; +} +.control-group.success .input-prepend .add-on, .control-group.success .input-append .add-on { + color: #468847; + background-color: #dff0d8; + border-color: #468847; +} +input:focus:required:invalid, textarea:focus:required:invalid, select:focus:required:invalid { + color: #b94a48; + border-color: #ee5f5b; +} +input:focus:required:invalid:focus, textarea:focus:required:invalid:focus, select:focus:required:invalid:focus { + border-color: #e9322d; + -webkit-box-shadow: 0 0 6px #f8b9b7; + -moz-box-shadow: 0 0 6px #f8b9b7; + box-shadow: 0 0 6px #f8b9b7; +} +.form-actions { + padding: 17px 20px 18px; + margin-top: 18px; + margin-bottom: 18px; + background-color: #f5f5f5; + border-top: 1px solid #ddd; +} +.uneditable-input { + display: block; + background-color: #ffffff; + border-color: #eee; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + cursor: not-allowed; +} +:-moz-placeholder { + color: #999999; +} +::-webkit-input-placeholder { + color: #999999; +} +.help-block { + display: block; + margin-top: 5px; + margin-bottom: 0; + color: #999999; +} +.help-inline { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; + margin-bottom: 9px; + vertical-align: middle; + padding-left: 5px; +} +.input-prepend, .input-append { + margin-bottom: 5px; + *zoom: 1; +} +.input-prepend:before, +.input-append:before, +.input-prepend:after, +.input-append:after { + display: table; + content: ""; +} +.input-prepend:after, .input-append:after { + clear: both; +} +.input-prepend input, +.input-append input, +.input-prepend .uneditable-input, +.input-append .uneditable-input { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.input-prepend input:focus, +.input-append input:focus, +.input-prepend .uneditable-input:focus, +.input-append .uneditable-input:focus { + position: relative; + z-index: 2; +} +.input-prepend .uneditable-input, .input-append .uneditable-input { + border-left-color: #ccc; +} +.input-prepend .add-on, .input-append .add-on { + float: left; + display: block; + width: auto; + min-width: 16px; + height: 18px; + margin-right: -1px; + padding: 4px 5px; + font-weight: normal; + line-height: 18px; + color: #999999; + text-align: center; + text-shadow: 0 1px 0 #ffffff; + background-color: #f5f5f5; + border: 1px solid #ccc; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.input-prepend .active, .input-append .active { + background-color: #a9dba9; + border-color: #46a546; +} +.input-prepend .add-on { + *margin-top: 1px; + /* IE6-7 */ + +} +.input-append input, .input-append .uneditable-input { + float: left; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.input-append .uneditable-input { + border-left-color: #eee; + border-right-color: #ccc; +} +.input-append .add-on { + margin-right: 0; + margin-left: -1px; + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.input-append input:first-child { + *margin-left: -160px; +} +.input-append input:first-child + .add-on { + *margin-left: -21px; +} +.search-query { + padding-left: 14px; + padding-right: 14px; + margin-bottom: 0; + -webkit-border-radius: 14px; + -moz-border-radius: 14px; + border-radius: 14px; +} +.form-search input, +.form-inline input, +.form-horizontal input, +.form-search textarea, +.form-inline textarea, +.form-horizontal textarea, +.form-search select, +.form-inline select, +.form-horizontal select, +.form-search .help-inline, +.form-inline .help-inline, +.form-horizontal .help-inline, +.form-search .uneditable-input, +.form-inline .uneditable-input, +.form-horizontal .uneditable-input { + display: inline-block; + margin-bottom: 0; +} +.form-search .hide, .form-inline .hide, .form-horizontal .hide { + display: none; +} +.form-search label, +.form-inline label, +.form-search .input-append, +.form-inline .input-append, +.form-search .input-prepend, +.form-inline .input-prepend { + display: inline-block; +} +.form-search .input-append .add-on, +.form-inline .input-prepend .add-on, +.form-search .input-append .add-on, +.form-inline .input-prepend .add-on { + vertical-align: middle; +} +.form-search .radio, +.form-inline .radio, +.form-search .checkbox, +.form-inline .checkbox { + margin-bottom: 0; + vertical-align: middle; +} +.control-group { + margin-bottom: 9px; +} +legend + .control-group { + margin-top: 18px; + -webkit-margin-top-collapse: separate; +} +.form-horizontal .control-group { + margin-bottom: 18px; + *zoom: 1; +} +.form-horizontal .control-group:before, .form-horizontal .control-group:after { + display: table; + content: ""; +} +.form-horizontal .control-group:after { + clear: both; +} +.form-horizontal .control-label { + float: left; + width: 140px; + padding-top: 5px; + text-align: right; +} +.form-horizontal .controls { + margin-left: 160px; +} +.form-horizontal .form-actions { + padding-left: 160px; +} +table { + max-width: 100%; + border-collapse: collapse; + border-spacing: 0; +} +.table { + width: 100%; + margin-bottom: 18px; +} +.table th, .table td { + padding: 8px; + line-height: 18px; + text-align: left; + vertical-align: top; + border-top: 1px solid #ddd; +} +.table th { + font-weight: bold; +} +.table thead th { + vertical-align: bottom; +} +.table thead:first-child tr th, .table thead:first-child tr td { + border-top: 0; +} +.table tbody + tbody { + border-top: 2px solid #ddd; +} +.table-condensed th, .table-condensed td { + padding: 4px 5px; +} +.table-bordered { + border: 1px solid #ddd; + border-collapse: separate; + *border-collapse: collapsed; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.table-bordered th + th, +.table-bordered td + td, +.table-bordered th + td, +.table-bordered td + th { + border-left: 1px solid #ddd; +} +.table-bordered thead:first-child tr:first-child th, .table-bordered tbody:first-child tr:first-child th, .table-bordered tbody:first-child tr:first-child td { + border-top: 0; +} +.table-bordered thead:first-child tr:first-child th:first-child, .table-bordered tbody:first-child tr:first-child td:first-child { + -webkit-border-radius: 4px 0 0 0; + -moz-border-radius: 4px 0 0 0; + border-radius: 4px 0 0 0; +} +.table-bordered thead:first-child tr:first-child th:last-child, .table-bordered tbody:first-child tr:first-child td:last-child { + -webkit-border-radius: 0 4px 0 0; + -moz-border-radius: 0 4px 0 0; + border-radius: 0 4px 0 0; +} +.table-bordered thead:last-child tr:last-child th:first-child, .table-bordered tbody:last-child tr:last-child td:first-child { + -webkit-border-radius: 0 0 0 4px; + -moz-border-radius: 0 0 0 4px; + border-radius: 0 0 0 4px; +} +.table-bordered thead:last-child tr:last-child th:last-child, .table-bordered tbody:last-child tr:last-child td:last-child { + -webkit-border-radius: 0 0 4px 0; + -moz-border-radius: 0 0 4px 0; + border-radius: 0 0 4px 0; +} +.table-striped tbody tr:nth-child(odd) td, .table-striped tbody tr:nth-child(odd) th { + background-color: #f9f9f9; +} +.table tbody tr:hover td, .table tbody tr:hover th { + background-color: #f5f5f5; +} +table .span1 { + float: none; + width: 44px; + margin-left: 0; +} +table .span2 { + float: none; + width: 124px; + margin-left: 0; +} +table .span3 { + float: none; + width: 204px; + margin-left: 0; +} +table .span4 { + float: none; + width: 284px; + margin-left: 0; +} +table .span5 { + float: none; + width: 364px; + margin-left: 0; +} +table .span6 { + float: none; + width: 444px; + margin-left: 0; +} +table .span7 { + float: none; + width: 524px; + margin-left: 0; +} +table .span8 { + float: none; + width: 604px; + margin-left: 0; +} +table .span9 { + float: none; + width: 684px; + margin-left: 0; +} +table .span10 { + float: none; + width: 764px; + margin-left: 0; +} +table .span11 { + float: none; + width: 844px; + margin-left: 0; +} +table .span12 { + float: none; + width: 924px; + margin-left: 0; +} +[class^="icon-"], [class*=" icon-"] { + display: inline-block; + width: 14px; + height: 14px; + line-height: 14px; + vertical-align: text-top; + background-image: url("../img/glyphicons-halflings.png"); + background-position: 14px 14px; + background-repeat: no-repeat; + *margin-right: .3em; +} +[class^="icon-"]:last-child, [class*=" icon-"]:last-child { + *margin-left: 0; +} +.icon-white { + background-image: url("../img/glyphicons-halflings-white.png"); +} +.icon-glass { + background-position: 0 0; +} +.icon-music { + background-position: -24px 0; +} +.icon-search { + background-position: -48px 0; +} +.icon-envelope { + background-position: -72px 0; +} +.icon-heart { + background-position: -96px 0; +} +.icon-star { + background-position: -120px 0; +} +.icon-star-empty { + background-position: -144px 0; +} +.icon-user { + background-position: -168px 0; +} +.icon-film { + background-position: -192px 0; +} +.icon-th-large { + background-position: -216px 0; +} +.icon-th { + background-position: -240px 0; +} +.icon-th-list { + background-position: -264px 0; +} +.icon-ok { + background-position: -288px 0; +} +.icon-remove { + background-position: -312px 0; +} +.icon-zoom-in { + background-position: -336px 0; +} +.icon-zoom-out { + background-position: -360px 0; +} +.icon-off { + background-position: -384px 0; +} +.icon-signal { + background-position: -408px 0; +} +.icon-cog { + background-position: -432px 0; +} +.icon-trash { + background-position: -456px 0; +} +.icon-home { + background-position: 0 -24px; +} +.icon-file { + background-position: -24px -24px; +} +.icon-time { + background-position: -48px -24px; +} +.icon-road { + background-position: -72px -24px; +} +.icon-download-alt { + background-position: -96px -24px; +} +.icon-download { + background-position: -120px -24px; +} +.icon-upload { + background-position: -144px -24px; +} +.icon-inbox { + background-position: -168px -24px; +} +.icon-play-circle { + background-position: -192px -24px; +} +.icon-repeat { + background-position: -216px -24px; +} +.icon-refresh { + background-position: -240px -24px; +} +.icon-list-alt { + background-position: -264px -24px; +} +.icon-lock { + background-position: -287px -24px; +} +.icon-flag { + background-position: -312px -24px; +} +.icon-headphones { + background-position: -336px -24px; +} +.icon-volume-off { + background-position: -360px -24px; +} +.icon-volume-down { + background-position: -384px -24px; +} +.icon-volume-up { + background-position: -408px -24px; +} +.icon-qrcode { + background-position: -432px -24px; +} +.icon-barcode { + background-position: -456px -24px; +} +.icon-tag { + background-position: 0 -48px; +} +.icon-tags { + background-position: -25px -48px; +} +.icon-book { + background-position: -48px -48px; +} +.icon-bookmark { + background-position: -72px -48px; +} +.icon-print { + background-position: -96px -48px; +} +.icon-camera { + background-position: -120px -48px; +} +.icon-font { + background-position: -144px -48px; +} +.icon-bold { + background-position: -167px -48px; +} +.icon-italic { + background-position: -192px -48px; +} +.icon-text-height { + background-position: -216px -48px; +} +.icon-text-width { + background-position: -240px -48px; +} +.icon-align-left { + background-position: -264px -48px; +} +.icon-align-center { + background-position: -288px -48px; +} +.icon-align-right { + background-position: -312px -48px; +} +.icon-align-justify { + background-position: -336px -48px; +} +.icon-list { + background-position: -360px -48px; +} +.icon-indent-left { + background-position: -384px -48px; +} +.icon-indent-right { + background-position: -408px -48px; +} +.icon-facetime-video { + background-position: -432px -48px; +} +.icon-picture { + background-position: -456px -48px; +} +.icon-pencil { + background-position: 0 -72px; +} +.icon-map-marker { + background-position: -24px -72px; +} +.icon-adjust { + background-position: -48px -72px; +} +.icon-tint { + background-position: -72px -72px; +} +.icon-edit { + background-position: -96px -72px; +} +.icon-share { + background-position: -120px -72px; +} +.icon-check { + background-position: -144px -72px; +} +.icon-move { + background-position: -168px -72px; +} +.icon-step-backward { + background-position: -192px -72px; +} +.icon-fast-backward { + background-position: -216px -72px; +} +.icon-backward { + background-position: -240px -72px; +} +.icon-play { + background-position: -264px -72px; +} +.icon-pause { + background-position: -288px -72px; +} +.icon-stop { + background-position: -312px -72px; +} +.icon-forward { + background-position: -336px -72px; +} +.icon-fast-forward { + background-position: -360px -72px; +} +.icon-step-forward { + background-position: -384px -72px; +} +.icon-eject { + background-position: -408px -72px; +} +.icon-chevron-left { + background-position: -432px -72px; +} +.icon-chevron-right { + background-position: -456px -72px; +} +.icon-plus-sign { + background-position: 0 -96px; +} +.icon-minus-sign { + background-position: -24px -96px; +} +.icon-remove-sign { + background-position: -48px -96px; +} +.icon-ok-sign { + background-position: -72px -96px; +} +.icon-question-sign { + background-position: -96px -96px; +} +.icon-info-sign { + background-position: -120px -96px; +} +.icon-screenshot { + background-position: -144px -96px; +} +.icon-remove-circle { + background-position: -168px -96px; +} +.icon-ok-circle { + background-position: -192px -96px; +} +.icon-ban-circle { + background-position: -216px -96px; +} +.icon-arrow-left { + background-position: -240px -96px; +} +.icon-arrow-right { + background-position: -264px -96px; +} +.icon-arrow-up { + background-position: -289px -96px; +} +.icon-arrow-down { + background-position: -312px -96px; +} +.icon-share-alt { + background-position: -336px -96px; +} +.icon-resize-full { + background-position: -360px -96px; +} +.icon-resize-small { + background-position: -384px -96px; +} +.icon-plus { + background-position: -408px -96px; +} +.icon-minus { + background-position: -433px -96px; +} +.icon-asterisk { + background-position: -456px -96px; +} +.icon-exclamation-sign { + background-position: 0 -120px; +} +.icon-gift { + background-position: -24px -120px; +} +.icon-leaf { + background-position: -48px -120px; +} +.icon-fire { + background-position: -72px -120px; +} +.icon-eye-open { + background-position: -96px -120px; +} +.icon-eye-close { + background-position: -120px -120px; +} +.icon-warning-sign { + background-position: -144px -120px; +} +.icon-plane { + background-position: -168px -120px; +} +.icon-calendar { + background-position: -192px -120px; +} +.icon-random { + background-position: -216px -120px; +} +.icon-comment { + background-position: -240px -120px; +} +.icon-magnet { + background-position: -264px -120px; +} +.icon-chevron-up { + background-position: -288px -120px; +} +.icon-chevron-down { + background-position: -313px -119px; +} +.icon-retweet { + background-position: -336px -120px; +} +.icon-shopping-cart { + background-position: -360px -120px; +} +.icon-folder-close { + background-position: -384px -120px; +} +.icon-folder-open { + background-position: -408px -120px; +} +.icon-resize-vertical { + background-position: -432px -119px; +} +.icon-resize-horizontal { + background-position: -456px -118px; +} +.dropdown { + position: relative; +} +.dropdown-toggle { + *margin-bottom: -3px; +} +.dropdown-toggle:active, .open .dropdown-toggle { + outline: 0; +} +.caret { + display: inline-block; + width: 0; + height: 0; + text-indent: -99999px; + *text-indent: 0; + vertical-align: top; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 4px solid #000000; + opacity: 0.3; + filter: alpha(opacity=30); + content: "\2193"; +} +.dropdown .caret { + margin-top: 8px; + margin-left: 2px; +} +.dropdown:hover .caret, .open.dropdown .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + float: left; + display: none; + min-width: 160px; + _width: 160px; + padding: 4px 0; + margin: 0; + list-style: none; + background-color: #ffffff; + border-color: #ccc; + border-color: rgba(0, 0, 0, 0.2); + border-style: solid; + border-width: 1px; + -webkit-border-radius: 0 0 5px 5px; + -moz-border-radius: 0 0 5px 5px; + border-radius: 0 0 5px 5px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; + *border-right-width: 2px; + *border-bottom-width: 2px; +} +.dropdown-menu.bottom-up { + top: auto; + bottom: 100%; + margin-bottom: 2px; +} +.dropdown-menu .divider { + height: 1px; + margin: 5px 1px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #ffffff; + *width: 100%; + *margin: -5px 0 5px; +} +.dropdown-menu a { + display: block; + padding: 3px 15px; + clear: both; + font-weight: normal; + line-height: 18px; + color: #555555; + white-space: nowrap; +} +.dropdown-menu li > a:hover, .dropdown-menu .active > a, .dropdown-menu .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #0088cc; +} +.dropdown.open { + *z-index: 1000; +} +.dropdown.open .dropdown-toggle { + color: #ffffff; + background: #ccc; + background: rgba(0, 0, 0, 0.3); +} +.dropdown.open .dropdown-menu { + display: block; +} +.typeahead { + margin-top: 2px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #f5f5f5; + border: 1px solid #eee; + border: 1px solid rgba(0, 0, 0, 0.05); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 0, 0, 0.15); +} +.fade { + -webkit-transition: opacity 0.15s linear; + -moz-transition: opacity 0.15s linear; + -ms-transition: opacity 0.15s linear; + -o-transition: opacity 0.15s linear; + transition: opacity 0.15s linear; + opacity: 0; +} +.fade.in { + opacity: 1; +} +.collapse { + -webkit-transition: height 0.35s ease; + -moz-transition: height 0.35s ease; + -ms-transition: height 0.35s ease; + -o-transition: height 0.35s ease; + transition: height 0.35s ease; + position: relative; + overflow: hidden; + height: 0; +} +.collapse.in { + height: auto; +} +.close { + float: right; + font-size: 20px; + font-weight: bold; + line-height: 18px; + color: #000000; + text-shadow: 0 1px 0 #ffffff; + opacity: 0.2; + filter: alpha(opacity=20); +} +.close:hover { + color: #000000; + text-decoration: none; + opacity: 0.4; + filter: alpha(opacity=40); + cursor: pointer; +} +.btn { + display: inline-block; + padding: 4px 10px 4px; + margin-bottom: 0; + font-size: 13px; + line-height: 18px; + color: #333333; + text-align: center; + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); + vertical-align: middle; + background-color: #f5f5f5; + background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); + background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); + background-image: linear-gradient(top, #ffffff, #e6e6e6); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0); + border-color: #e6e6e6 #e6e6e6 #bfbfbf; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + border: 1px solid #ccc; + border-bottom-color: #bbb; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + cursor: pointer; + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + *margin-left: .3em; +} +.btn:hover, +.btn:active, +.btn.active, +.btn.disabled, +.btn[disabled] { + background-color: #e6e6e6; +} +.btn:active, .btn.active { + background-color: #cccccc \9; +} +.btn:first-child { + *margin-left: 0; +} +.btn:hover { + color: #333333; + text-decoration: none; + background-color: #e6e6e6; + background-position: 0 -15px; + -webkit-transition: background-position 0.1s linear; + -moz-transition: background-position 0.1s linear; + -ms-transition: background-position 0.1s linear; + -o-transition: background-position 0.1s linear; + transition: background-position 0.1s linear; +} +.btn:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.btn.active, .btn:active { + background-image: none; + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + background-color: #e6e6e6; + background-color: #d9d9d9 \9; + outline: 0; +} +.btn.disabled, .btn[disabled] { + cursor: default; + background-image: none; + background-color: #e6e6e6; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +.btn-large { + padding: 9px 14px; + font-size: 15px; + line-height: normal; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.btn-large [class^="icon-"] { + margin-top: 1px; +} +.btn-small { + padding: 5px 9px; + font-size: 11px; + line-height: 16px; +} +.btn-small [class^="icon-"] { + margin-top: -1px; +} +.btn-mini { + padding: 2px 6px; + font-size: 11px; + line-height: 14px; +} +.btn-primary, +.btn-primary:hover, +.btn-warning, +.btn-warning:hover, +.btn-danger, +.btn-danger:hover, +.btn-success, +.btn-success:hover, +.btn-info, +.btn-info:hover, +.btn-inverse, +.btn-inverse:hover { + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + color: #ffffff; +} +.btn-primary.active, +.btn-warning.active, +.btn-danger.active, +.btn-success.active, +.btn-info.active, +.btn-dark.active { + color: rgba(255, 255, 255, 0.75); +} +.btn-primary { + background-color: #006dcc; + background-image: -moz-linear-gradient(top, #0088cc, #0044cc); + background-image: -ms-linear-gradient(top, #0088cc, #0044cc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); + background-image: -o-linear-gradient(top, #0088cc, #0044cc); + background-image: linear-gradient(top, #0088cc, #0044cc); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); + border-color: #0044cc #0044cc #002a80; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-primary:hover, +.btn-primary:active, +.btn-primary.active, +.btn-primary.disabled, +.btn-primary[disabled] { + background-color: #0044cc; +} +.btn-primary:active, .btn-primary.active { + background-color: #003399 \9; +} +.btn-warning { + background-color: #faa732; + background-image: -moz-linear-gradient(top, #fbb450, #f89406); + background-image: -ms-linear-gradient(top, #fbb450, #f89406); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); + background-image: -webkit-linear-gradient(top, #fbb450, #f89406); + background-image: -o-linear-gradient(top, #fbb450, #f89406); + background-image: linear-gradient(top, #fbb450, #f89406); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0); + border-color: #f89406 #f89406 #ad6704; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-warning:hover, +.btn-warning:active, +.btn-warning.active, +.btn-warning.disabled, +.btn-warning[disabled] { + background-color: #f89406; +} +.btn-warning:active, .btn-warning.active { + background-color: #c67605 \9; +} +.btn-danger { + background-color: #da4f49; + background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -ms-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -o-linear-gradient(top, #ee5f5b, #bd362f); + background-image: linear-gradient(top, #ee5f5b, #bd362f); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0); + border-color: #bd362f #bd362f #802420; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-danger:hover, +.btn-danger:active, +.btn-danger.active, +.btn-danger.disabled, +.btn-danger[disabled] { + background-color: #bd362f; +} +.btn-danger:active, .btn-danger.active { + background-color: #942a25 \9; +} +.btn-success { + background-color: #5bb75b; + background-image: -moz-linear-gradient(top, #62c462, #51a351); + background-image: -ms-linear-gradient(top, #62c462, #51a351); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351)); + background-image: -webkit-linear-gradient(top, #62c462, #51a351); + background-image: -o-linear-gradient(top, #62c462, #51a351); + background-image: linear-gradient(top, #62c462, #51a351); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0); + border-color: #51a351 #51a351 #387038; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-success:hover, +.btn-success:active, +.btn-success.active, +.btn-success.disabled, +.btn-success[disabled] { + background-color: #51a351; +} +.btn-success:active, .btn-success.active { + background-color: #408140 \9; +} +.btn-info { + background-color: #49afcd; + background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -ms-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4)); + background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -o-linear-gradient(top, #5bc0de, #2f96b4); + background-image: linear-gradient(top, #5bc0de, #2f96b4); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0); + border-color: #2f96b4 #2f96b4 #1f6377; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-info:hover, +.btn-info:active, +.btn-info.active, +.btn-info.disabled, +.btn-info[disabled] { + background-color: #2f96b4; +} +.btn-info:active, .btn-info.active { + background-color: #24748c \9; +} +.btn-inverse { + background-color: #393939; + background-image: -moz-linear-gradient(top, #454545, #262626); + background-image: -ms-linear-gradient(top, #454545, #262626); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#454545), to(#262626)); + background-image: -webkit-linear-gradient(top, #454545, #262626); + background-image: -o-linear-gradient(top, #454545, #262626); + background-image: linear-gradient(top, #454545, #262626); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#454545', endColorstr='#262626', GradientType=0); + border-color: #262626 #262626 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-inverse:hover, +.btn-inverse:active, +.btn-inverse.active, +.btn-inverse.disabled, +.btn-inverse[disabled] { + background-color: #262626; +} +.btn-inverse:active, .btn-inverse.active { + background-color: #0c0c0c \9; +} +button.btn, input[type="submit"].btn { + *padding-top: 2px; + *padding-bottom: 2px; +} +button.btn::-moz-focus-inner, input[type="submit"].btn::-moz-focus-inner { + padding: 0; + border: 0; +} +button.btn.large, input[type="submit"].btn.large { + *padding-top: 7px; + *padding-bottom: 7px; +} +button.btn.small, input[type="submit"].btn.small { + *padding-top: 3px; + *padding-bottom: 3px; +} +.btn-group { + position: relative; + *zoom: 1; + *margin-left: .3em; +} +.btn-group:before, .btn-group:after { + display: table; + content: ""; +} +.btn-group:after { + clear: both; +} +.btn-group:first-child { + *margin-left: 0; +} +.btn-group + .btn-group { + margin-left: 5px; +} +.btn-toolbar { + margin-top: 9px; + margin-bottom: 9px; +} +.btn-toolbar .btn-group { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; +} +.btn-group .btn { + position: relative; + float: left; + margin-left: -1px; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.btn-group .btn:first-child { + margin-left: 0; + -webkit-border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; + border-top-left-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + border-bottom-left-radius: 4px; +} +.btn-group .btn:last-child, .btn-group .dropdown-toggle { + -webkit-border-top-right-radius: 4px; + -moz-border-radius-topright: 4px; + border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -moz-border-radius-bottomright: 4px; + border-bottom-right-radius: 4px; +} +.btn-group .btn.large:first-child { + margin-left: 0; + -webkit-border-top-left-radius: 6px; + -moz-border-radius-topleft: 6px; + border-top-left-radius: 6px; + -webkit-border-bottom-left-radius: 6px; + -moz-border-radius-bottomleft: 6px; + border-bottom-left-radius: 6px; +} +.btn-group .btn.large:last-child, .btn-group .large.dropdown-toggle { + -webkit-border-top-right-radius: 6px; + -moz-border-radius-topright: 6px; + border-top-right-radius: 6px; + -webkit-border-bottom-right-radius: 6px; + -moz-border-radius-bottomright: 6px; + border-bottom-right-radius: 6px; +} +.btn-group .btn:hover, +.btn-group .btn:focus, +.btn-group .btn:active, +.btn-group .btn.active { + z-index: 2; +} +.btn-group .dropdown-toggle:active, .btn-group.open .dropdown-toggle { + outline: 0; +} +.btn-group .dropdown-toggle { + padding-left: 8px; + padding-right: 8px; + -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + *padding-top: 5px; + *padding-bottom: 5px; +} +.btn-group.open { + *z-index: 1000; +} +.btn-group.open .dropdown-menu { + display: block; + margin-top: 1px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.btn-group.open .dropdown-toggle { + background-image: none; + -webkit-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); +} +.btn .caret { + margin-top: 7px; + margin-left: 0; +} +.btn:hover .caret, .open.btn-group .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.btn-primary .caret, +.btn-danger .caret, +.btn-info .caret, +.btn-success .caret, +.btn-inverse .caret { + border-top-color: #ffffff; + opacity: 0.75; + filter: alpha(opacity=75); +} +.btn-small .caret { + margin-top: 4px; +} +.alert { + padding: 8px 35px 8px 14px; + margin-bottom: 18px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + background-color: #fcf8e3; + border: 1px solid #fbeed5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.alert, .alert-heading { + color: #c09853; +} +.alert .close { + position: relative; + top: -2px; + right: -21px; + line-height: 18px; +} +.alert-success { + background-color: #dff0d8; + border-color: #d6e9c6; +} +.alert-success, .alert-success .alert-heading { + color: #468847; +} +.alert-danger, .alert-error { + background-color: #f2dede; + border-color: #eed3d7; +} +.alert-danger, +.alert-error, +.alert-danger .alert-heading, +.alert-error .alert-heading { + color: #b94a48; +} +.alert-info { + background-color: #d9edf7; + border-color: #bce8f1; +} +.alert-info, .alert-info .alert-heading { + color: #3a87ad; +} +.alert-block { + padding-top: 14px; + padding-bottom: 14px; +} +.alert-block > p, .alert-block > ul { + margin-bottom: 0; +} +.alert-block p + p { + margin-top: 5px; +} +.nav { + margin-left: 0; + margin-bottom: 18px; + list-style: none; +} +.nav > li > a { + display: block; +} +.nav > li > a:hover { + text-decoration: none; + background-color: #eeeeee; +} +.nav .nav-header { + display: block; + padding: 3px 15px; + font-size: 11px; + font-weight: bold; + line-height: 18px; + color: #999999; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + text-transform: uppercase; +} +.nav li + .nav-header { + margin-top: 9px; +} +.nav-list { + padding-left: 14px; + padding-right: 14px; + margin-bottom: 0; +} +.nav-list > li > a, .nav-list .nav-header { + margin-left: -15px; + margin-right: -15px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); +} +.nav-list > li > a { + padding: 3px 15px; +} +.nav-list .active > a, .nav-list .active > a:hover { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); + background-color: #0088cc; +} +.nav-list [class^="icon-"] { + margin-right: 2px; +} +.nav-tabs, .nav-pills { + *zoom: 1; +} +.nav-tabs:before, +.nav-pills:before, +.nav-tabs:after, +.nav-pills:after { + display: table; + content: ""; +} +.nav-tabs:after, .nav-pills:after { + clear: both; +} +.nav-tabs > li, .nav-pills > li { + float: left; +} +.nav-tabs > li > a, .nav-pills > li > a { + padding-right: 12px; + padding-left: 12px; + margin-right: 2px; + line-height: 14px; +} +.nav-tabs { + border-bottom: 1px solid #ddd; +} +.nav-tabs > li { + margin-bottom: -1px; +} +.nav-tabs > li > a { + padding-top: 9px; + padding-bottom: 9px; + border: 1px solid transparent; + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} +.nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #dddddd; +} +.nav-tabs > .active > a, .nav-tabs > .active > a:hover { + color: #555555; + background-color: #ffffff; + border: 1px solid #ddd; + border-bottom-color: transparent; + cursor: default; +} +.nav-pills > li > a { + padding-top: 8px; + padding-bottom: 8px; + margin-top: 2px; + margin-bottom: 2px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.nav-pills .active > a, .nav-pills .active > a:hover { + color: #ffffff; + background-color: #0088cc; +} +.nav-stacked > li { + float: none; +} +.nav-stacked > li > a { + margin-right: 0; +} +.nav-tabs.nav-stacked { + border-bottom: 0; +} +.nav-tabs.nav-stacked > li > a { + border: 1px solid #ddd; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.nav-tabs.nav-stacked > li:first-child > a { + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} +.nav-tabs.nav-stacked > li:last-child > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} +.nav-tabs.nav-stacked > li > a:hover { + border-color: #ddd; + z-index: 2; +} +.nav-pills.nav-stacked > li > a { + margin-bottom: 3px; +} +.nav-pills.nav-stacked > li:last-child > a { + margin-bottom: 1px; +} +.nav-tabs .dropdown-menu, .nav-pills .dropdown-menu { + margin-top: 1px; + border-width: 1px; +} +.nav-pills .dropdown-menu { + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.nav-tabs .dropdown-toggle .caret, .nav-pills .dropdown-toggle .caret { + border-top-color: #0088cc; + margin-top: 6px; +} +.nav-tabs .dropdown-toggle:hover .caret, .nav-pills .dropdown-toggle:hover .caret { + border-top-color: #005580; +} +.nav-tabs .active .dropdown-toggle .caret, .nav-pills .active .dropdown-toggle .caret { + border-top-color: #333333; +} +.nav > .dropdown.active > a:hover { + color: #000000; + cursor: pointer; +} +.nav-tabs .open .dropdown-toggle, .nav-pills .open .dropdown-toggle, .nav > .open.active > a:hover { + color: #ffffff; + background-color: #999999; + border-color: #999999; +} +.nav .open .caret, .nav .open.active .caret, .nav .open a:hover .caret { + border-top-color: #ffffff; + opacity: 1; + filter: alpha(opacity=100); +} +.tabs-stacked .open > a:hover { + border-color: #999999; +} +.tabbable { + *zoom: 1; +} +.tabbable:before, .tabbable:after { + display: table; + content: ""; +} +.tabbable:after { + clear: both; +} +.tab-content { + overflow: hidden; +} +.tabs-below .nav-tabs, .tabs-right .nav-tabs, .tabs-left .nav-tabs { + border-bottom: 0; +} +.tab-content > .tab-pane, .pill-content > .pill-pane { + display: none; +} +.tab-content > .active, .pill-content > .active { + display: block; +} +.tabs-below .nav-tabs { + border-top: 1px solid #ddd; +} +.tabs-below .nav-tabs > li { + margin-top: -1px; + margin-bottom: 0; +} +.tabs-below .nav-tabs > li > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} +.tabs-below .nav-tabs > li > a:hover { + border-bottom-color: transparent; + border-top-color: #ddd; +} +.tabs-below .nav-tabs .active > a, .tabs-below .nav-tabs .active > a:hover { + border-color: transparent #ddd #ddd #ddd; +} +.tabs-left .nav-tabs > li, .tabs-right .nav-tabs > li { + float: none; +} +.tabs-left .nav-tabs > li > a, .tabs-right .nav-tabs > li > a { + min-width: 74px; + margin-right: 0; + margin-bottom: 3px; +} +.tabs-left .nav-tabs { + float: left; + margin-right: 19px; + border-right: 1px solid #ddd; +} +.tabs-left .nav-tabs > li > a { + margin-right: -1px; + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} +.tabs-left .nav-tabs > li > a:hover { + border-color: #eeeeee #dddddd #eeeeee #eeeeee; +} +.tabs-left .nav-tabs .active > a, .tabs-left .nav-tabs .active > a:hover { + border-color: #ddd transparent #ddd #ddd; + *border-right-color: #ffffff; +} +.tabs-right .nav-tabs { + float: right; + margin-left: 19px; + border-left: 1px solid #ddd; +} +.tabs-right .nav-tabs > li > a { + margin-left: -1px; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} +.tabs-right .nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #eeeeee #dddddd; +} +.tabs-right .nav-tabs .active > a, .tabs-right .nav-tabs .active > a:hover { + border-color: #ddd #ddd #ddd transparent; + *border-left-color: #ffffff; +} +.navbar { + overflow: visible; + margin-bottom: 18px; +} +.navbar-inner { + padding-left: 20px; + padding-right: 20px; + background-color: #2c2c2c; + background-image: -moz-linear-gradient(top, #333333, #222222); + background-image: -ms-linear-gradient(top, #333333, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); + background-image: -webkit-linear-gradient(top, #333333, #222222); + background-image: -o-linear-gradient(top, #333333, #222222); + background-image: linear-gradient(top, #333333, #222222); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); +} +.btn-navbar { + display: none; + float: right; + padding: 7px 10px; + margin-left: 5px; + margin-right: 5px; + background-color: #2c2c2c; + background-image: -moz-linear-gradient(top, #333333, #222222); + background-image: -ms-linear-gradient(top, #333333, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); + background-image: -webkit-linear-gradient(top, #333333, #222222); + background-image: -o-linear-gradient(top, #333333, #222222); + background-image: linear-gradient(top, #333333, #222222); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); + border-color: #222222 #222222 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); +} +.btn-navbar:hover, +.btn-navbar:active, +.btn-navbar.active, +.btn-navbar.disabled, +.btn-navbar[disabled] { + background-color: #222222; +} +.btn-navbar:active, .btn-navbar.active { + background-color: #080808 \9; +} +.btn-navbar .icon-bar { + display: block; + width: 18px; + height: 2px; + background-color: #f5f5f5; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; + -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); +} +.btn-navbar .icon-bar + .icon-bar { + margin-top: 3px; +} +.nav-collapse.collapse { + height: auto; +} +.navbar .brand:hover { + text-decoration: none; +} +.navbar .brand { + float: left; + display: block; + padding: 8px 20px 12px; + margin-left: -20px; + font-size: 20px; + font-weight: 200; + line-height: 1; + color: #ffffff; +} +.navbar .navbar-text { + margin-bottom: 0; + line-height: 40px; + color: #999999; +} +.navbar .navbar-text a:hover { + color: #ffffff; + background-color: transparent; +} +.navbar .btn, .navbar .btn-group { + margin-top: 5px; +} +.navbar .btn-group .btn { + margin-top: 0; +} +.navbar-form { + margin-bottom: 0; + *zoom: 1; +} +.navbar-form:before, .navbar-form:after { + display: table; + content: ""; +} +.navbar-form:after { + clear: both; +} +.navbar-form input, .navbar-form select { + display: inline-block; + margin-top: 5px; + margin-bottom: 0; +} +.navbar-form .radio, .navbar-form .checkbox { + margin-top: 5px; +} +.navbar-form input[type="image"], .navbar-form input[type="checkbox"], .navbar-form input[type="radio"] { + margin-top: 3px; +} +.navbar-form .input-append, .navbar-form .input-prepend { + margin-top: 6px; + white-space: nowrap; +} +.navbar-form .input-append input, .navbar-form .input-prepend input { + margin-top: 0; +} +.navbar-search { + position: relative; + float: left; + margin-top: 6px; + margin-bottom: 0; +} +.navbar-search .search-query { + padding: 4px 9px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + font-weight: normal; + line-height: 1; + color: #ffffff; + color: rgba(255, 255, 255, 0.75); + background: #666; + background: rgba(255, 255, 255, 0.3); + border: 1px solid #111; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + -webkit-transition: none; + -moz-transition: none; + -ms-transition: none; + -o-transition: none; + transition: none; +} +.navbar-search .search-query :-moz-placeholder { + color: #eeeeee; +} +.navbar-search .search-query::-webkit-input-placeholder { + color: #eeeeee; +} +.navbar-search .search-query:hover { + color: #ffffff; + background-color: #999999; + background-color: rgba(255, 255, 255, 0.5); +} +.navbar-search .search-query:focus, .navbar-search .search-query.focused { + padding: 5px 10px; + color: #333333; + text-shadow: 0 1px 0 #ffffff; + background-color: #ffffff; + border: 0; + -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + outline: 0; +} +.navbar-fixed-top { + position: fixed; + top: 0; + right: 0; + left: 0; + z-index: 1030; +} +.navbar-fixed-top .navbar-inner { + padding-left: 0; + padding-right: 0; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.navbar .nav { + position: relative; + left: 0; + display: block; + float: left; + margin: 0 10px 0 0; +} +.navbar .nav.pull-right { + float: right; +} +.navbar .nav > li { + display: block; + float: left; +} +.navbar .nav > li > a { + float: none; + padding: 10px 10px 11px; + line-height: 19px; + color: #999999; + text-decoration: none; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.navbar .nav > li > a:hover { + background-color: transparent; + color: #ffffff; + text-decoration: none; +} +.navbar .nav .active > a, .navbar .nav .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #222222; +} +.navbar .divider-vertical { + height: 40px; + width: 1px; + margin: 0 9px; + overflow: hidden; + background-color: #222222; + border-right: 1px solid #333333; +} +.navbar .nav.pull-right { + margin-left: 10px; + margin-right: 0; +} +.navbar .dropdown-menu { + margin-top: 1px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.navbar .dropdown-menu:before { + content: ''; + display: inline-block; + border-left: 7px solid transparent; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-bottom-color: rgba(0, 0, 0, 0.2); + position: absolute; + top: -7px; + left: 9px; +} +.navbar .dropdown-menu:after { + content: ''; + display: inline-block; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid #ffffff; + position: absolute; + top: -6px; + left: 10px; +} +.navbar .nav .dropdown-toggle .caret, .navbar .nav .open.dropdown .caret { + border-top-color: #ffffff; +} +.navbar .nav .active .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.navbar .nav .open > .dropdown-toggle, .navbar .nav .active > .dropdown-toggle, .navbar .nav .open.active > .dropdown-toggle { + background-color: transparent; +} +.navbar .nav .active > .dropdown-toggle:hover { + color: #ffffff; +} +.navbar .nav.pull-right .dropdown-menu { + left: auto; + right: 0; +} +.navbar .nav.pull-right .dropdown-menu:before { + left: auto; + right: 12px; +} +.navbar .nav.pull-right .dropdown-menu:after { + left: auto; + right: 13px; +} +.breadcrumb { + padding: 7px 14px; + margin: 0 0 18px; + background-color: #fbfbfb; + background-image: -moz-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -ms-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5)); + background-image: -webkit-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -o-linear-gradient(top, #ffffff, #f5f5f5); + background-image: linear-gradient(top, #ffffff, #f5f5f5); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0); + border: 1px solid #ddd; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; +} +.breadcrumb li { + display: inline-block; + text-shadow: 0 1px 0 #ffffff; +} +.breadcrumb .divider { + padding: 0 5px; + color: #999999; +} +.breadcrumb .active a { + color: #333333; +} +.pagination { + height: 36px; + margin: 18px 0; +} +.pagination ul { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; + margin-left: 0; + margin-bottom: 0; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); +} +.pagination li { + display: inline; +} +.pagination a { + float: left; + padding: 0 14px; + line-height: 34px; + text-decoration: none; + border: 1px solid #ddd; + border-left-width: 0; +} +.pagination a:hover, .pagination .active a { + background-color: #f5f5f5; +} +.pagination .active a { + color: #999999; + cursor: default; +} +.pagination .disabled a, .pagination .disabled a:hover { + color: #999999; + background-color: transparent; + cursor: default; +} +.pagination li:first-child a { + border-left-width: 1px; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.pagination li:last-child a { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.pagination-centered { + text-align: center; +} +.pagination-right { + text-align: right; +} +.pager { + margin-left: 0; + margin-bottom: 18px; + list-style: none; + text-align: center; + *zoom: 1; +} +.pager:before, .pager:after { + display: table; + content: ""; +} +.pager:after { + clear: both; +} +.pager li { + display: inline; +} +.pager a { + display: inline-block; + padding: 5px 14px; + background-color: #fff; + border: 1px solid #ddd; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} +.pager a:hover { + text-decoration: none; + background-color: #f5f5f5; +} +.pager .next a { + float: right; +} +.pager .previous a { + float: left; +} +.modal-open .dropdown-menu { + z-index: 2050; +} +.modal-open .dropdown.open { + *z-index: 2050; +} +.modal-open .popover { + z-index: 2060; +} +.modal-open .tooltip { + z-index: 2070; +} +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + background-color: #000000; +} +.modal-backdrop.fade { + opacity: 0; +} +.modal-backdrop, .modal-backdrop.fade.in { + opacity: 0.8; + filter: alpha(opacity=80); +} +.modal { + position: fixed; + top: 50%; + left: 50%; + z-index: 1050; + max-height: 500px; + overflow: auto; + width: 560px; + margin: -250px 0 0 -280px; + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + /* IE6-7 */ + + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.wide-modal { + position: fixed; + top: 5%; + left: 5%; + z-index: 1050; + max-height: 90%; + overflow: auto; + width: 90%; + /*margin: -50px 0 0 -80px;*/ + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + /* IE6-7 */ + + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.modal.fade { + -webkit-transition: opacity .3s linear, top .3s ease-out; + -moz-transition: opacity .3s linear, top .3s ease-out; + -ms-transition: opacity .3s linear, top .3s ease-out; + -o-transition: opacity .3s linear, top .3s ease-out; + transition: opacity .3s linear, top .3s ease-out; + top: -25%; +} +.modal.fade.in { + top: 50%; +} +.modal-header { + padding: 9px 15px; + border-bottom: 1px solid #eee; +} +.modal-header .close { + margin-top: 2px; +} +.modal-body { + padding: 15px; +} +.modal-body .modal-form { + margin-bottom: 0; +} +.modal-footer { + padding: 14px 15px 15px; + margin-bottom: 0; + background-color: #f5f5f5; + border-top: 1px solid #ddd; + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; + *zoom: 1; +} +.modal-footer:before, .modal-footer:after { + display: table; + content: ""; +} +.modal-footer:after { + clear: both; +} +.modal-footer .btn { + float: right; + margin-left: 5px; + margin-bottom: 0; +} +.tooltip { + position: absolute; + z-index: 1020; + display: block; + visibility: visible; + padding: 5px; + font-size: 11px; + opacity: 0; + filter: alpha(opacity=0); +} +.tooltip.in { + opacity: 0.8; + filter: alpha(opacity=80); +} +.tooltip.top { + margin-top: -2px; +} +.tooltip.right { + margin-left: 2px; +} +.tooltip.bottom { + margin-top: 2px; +} +.tooltip.left { + margin-left: -2px; +} +.tooltip.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid #000000; +} +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #000000; +} +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-bottom: 5px solid #000000; +} +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-right: 5px solid #000000; +} +.tooltip-inner { + max-width: 200px; + padding: 3px 8px; + color: #ffffff; + text-align: center; + text-decoration: none; + background-color: #000000; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; +} +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1010; + display: none; + padding: 5px; +} +.popover.top { + margin-top: -5px; +} +.popover.right { + margin-left: 5px; +} +.popover.bottom { + margin-top: 5px; +} +.popover.left { + margin-left: -5px; +} +.popover.top .arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid #000000; +} +.popover.right .arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-right: 5px solid #000000; +} +.popover.bottom .arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-bottom: 5px solid #000000; +} +.popover.left .arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #000000; +} +.popover .arrow { + position: absolute; + width: 0; + height: 0; +} +.popover-inner { + padding: 3px; + width: 280px; + overflow: hidden; + background: #000000; + background: rgba(0, 0, 0, 0.8); + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); +} +.popover-title { + padding: 9px 15px; + line-height: 1; + background-color: #f5f5f5; + border-bottom: 1px solid #eee; + -webkit-border-radius: 3px 3px 0 0; + -moz-border-radius: 3px 3px 0 0; + border-radius: 3px 3px 0 0; +} +.popover-content { + padding: 14px; + background-color: #ffffff; + -webkit-border-radius: 0 0 3px 3px; + -moz-border-radius: 0 0 3px 3px; + border-radius: 0 0 3px 3px; + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.popover-content p, .popover-content ul, .popover-content ol { + margin-bottom: 0; +} +.thumbnails { + margin-left: -20px; + list-style: none; + *zoom: 1; +} +.thumbnails:before, .thumbnails:after { + display: table; + content: ""; +} +.thumbnails:after { + clear: both; +} +.thumbnails > li { + float: left; + margin: 0 0 18px 20px; +} +.thumbnail { + display: block; + padding: 4px; + line-height: 1; + border: 1px solid #ddd; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); +} +a.thumbnail:hover { + border-color: #0088cc; + -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); +} +.thumbnail > img { + display: block; + max-width: 100%; + margin-left: auto; + margin-right: auto; +} +.thumbnail .caption { + padding: 9px; +} +.label { + padding: 2px 4px 3px; + font-size: 11.049999999999999px; + font-weight: bold; + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #999999; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.label:hover { + color: #ffffff; + text-decoration: none; +} +.label-important { + background-color: #b94a48; +} +.label-important:hover { + background-color: #953b39; +} +.label-warning { + background-color: #f89406; +} +.label-warning:hover { + background-color: #c67605; +} +.label-success { + background-color: #468847; +} +.label-success:hover { + background-color: #356635; +} +.label-info { + background-color: #3a87ad; +} +.label-info:hover { + background-color: #2d6987; +} +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +@-moz-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +@keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +.progress { + overflow: hidden; + height: 18px; + margin-bottom: 18px; + background-color: #f7f7f7; + background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -ms-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9)); + background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: linear-gradient(top, #f5f5f5, #f9f9f9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0); + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.progress .bar { + width: 0%; + height: 18px; + color: #ffffff; + font-size: 12px; + text-align: center; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #0e90d2; + background-image: -moz-linear-gradient(top, #149bdf, #0480be); + background-image: -ms-linear-gradient(top, #149bdf, #0480be); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be)); + background-image: -webkit-linear-gradient(top, #149bdf, #0480be); + background-image: -o-linear-gradient(top, #149bdf, #0480be); + background-image: linear-gradient(top, #149bdf, #0480be); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0); + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition: width 0.6s ease; + -moz-transition: width 0.6s ease; + -ms-transition: width 0.6s ease; + -o-transition: width 0.6s ease; + transition: width 0.6s ease; +} +.progress-striped .bar { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + -webkit-background-size: 40px 40px; + -moz-background-size: 40px 40px; + -o-background-size: 40px 40px; + background-size: 40px 40px; +} +.progress.active .bar { + -webkit-animation: progress-bar-stripes 2s linear infinite; + -moz-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} +.progress-danger .bar { + background-color: #dd514c; + background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -o-linear-gradient(top, #ee5f5b, #c43c35); + background-image: linear-gradient(top, #ee5f5b, #c43c35); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0); +} +.progress-danger.progress-striped .bar { + background-color: #ee5f5b; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-success .bar { + background-color: #5eb95e; + background-image: -moz-linear-gradient(top, #62c462, #57a957); + background-image: -ms-linear-gradient(top, #62c462, #57a957); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957)); + background-image: -webkit-linear-gradient(top, #62c462, #57a957); + background-image: -o-linear-gradient(top, #62c462, #57a957); + background-image: linear-gradient(top, #62c462, #57a957); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0); +} +.progress-success.progress-striped .bar { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-info .bar { + background-color: #4bb1cf; + background-image: -moz-linear-gradient(top, #5bc0de, #339bb9); + background-image: -ms-linear-gradient(top, #5bc0de, #339bb9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9)); + background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9); + background-image: -o-linear-gradient(top, #5bc0de, #339bb9); + background-image: linear-gradient(top, #5bc0de, #339bb9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0); +} +.progress-info.progress-striped .bar { + background-color: #5bc0de; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.accordion { + margin-bottom: 18px; +} +.accordion-group { + margin-bottom: 2px; + border: 1px solid #e5e5e5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.accordion-heading { + border-bottom: 0; +} +.accordion-heading .accordion-toggle { + display: block; + padding: 8px 15px; +} +.accordion-inner { + padding: 9px 15px; + border-top: 1px solid #e5e5e5; +} +.carousel { + position: relative; + margin-bottom: 18px; + line-height: 1; +} +.carousel-inner { + overflow: hidden; + width: 100%; + position: relative; +} +.carousel .item { + display: none; + position: relative; + -webkit-transition: 0.6s ease-in-out left; + -moz-transition: 0.6s ease-in-out left; + -ms-transition: 0.6s ease-in-out left; + -o-transition: 0.6s ease-in-out left; + transition: 0.6s ease-in-out left; +} +.carousel .item > img { + display: block; + line-height: 1; +} +.carousel .active, .carousel .next, .carousel .prev { + display: block; +} +.carousel .active { + left: 0; +} +.carousel .next, .carousel .prev { + position: absolute; + top: 0; + width: 100%; +} +.carousel .next { + left: 100%; +} +.carousel .prev { + left: -100%; +} +.carousel .next.left, .carousel .prev.right { + left: 0; +} +.carousel .active.left { + left: -100%; +} +.carousel .active.right { + left: 100%; +} +.carousel-control { + position: absolute; + top: 40%; + left: 15px; + width: 40px; + height: 40px; + margin-top: -20px; + font-size: 60px; + font-weight: 100; + line-height: 30px; + color: #ffffff; + text-align: center; + background: #222222; + border: 3px solid #ffffff; + -webkit-border-radius: 23px; + -moz-border-radius: 23px; + border-radius: 23px; + opacity: 0.5; + filter: alpha(opacity=50); +} +.carousel-control.right { + left: auto; + right: 15px; +} +.carousel-control:hover { + color: #ffffff; + text-decoration: none; + opacity: 0.9; + filter: alpha(opacity=90); +} +.carousel-caption { + position: absolute; + left: 0; + right: 0; + bottom: 0; + padding: 10px 15px 5px; + background: #333333; + background: rgba(0, 0, 0, 0.75); +} +.carousel-caption h4, .carousel-caption p { + color: #ffffff; +} +.hero-unit { + padding: 60px; + margin-bottom: 30px; + background-color: #f5f5f5; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} +.hero-unit h1 { + margin-bottom: 0; + font-size: 60px; + line-height: 1; + letter-spacing: -1px; +} +.hero-unit p { + font-size: 18px; + font-weight: 200; + line-height: 27px; +} +.pull-right { + float: right; +} +.pull-left { + float: left; +} +.hide { + display: none; +} +.show { + display: block; +} +.invisible { + visibility: hidden; +} diff --git a/src/nl/astraeus/jdbc/web/resources/images/loading.gif b/src/nl/astraeus/jdbc/web/resources/images/loading.gif new file mode 100644 index 0000000..21c7e74 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/images/loading.gif Binary files differ diff --git a/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png b/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png new file mode 100644 index 0000000..92d4445 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png Binary files differ diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-alert.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-alert.js new file mode 100644 index 0000000..2242ddd --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-alert.js @@ -0,0 +1,94 @@ +/* ========================================================== + * bootstrap-alert.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#alerts + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function( $ ){ + + "use strict" + + /* ALERT CLASS DEFINITION + * ====================== */ + + var dismiss = '[data-dismiss="alert"]' + , Alert = function ( el ) { + $(el).on('click', dismiss, this.close) + } + + Alert.prototype = { + + constructor: Alert + + , close: function ( e ) { + var $this = $(this) + , selector = $this.attr('data-target') + , $parent + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = $(selector) + $parent.trigger('close') + + e && e.preventDefault() + + $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent()) + + $parent + .trigger('close') + .removeClass('in') + + function removeElement() { + $parent + .trigger('closed') + .remove() + } + + $.support.transition && $parent.hasClass('fade') ? + $parent.on($.support.transition.end, removeElement) : + removeElement() + } + + } + + + /* ALERT PLUGIN DEFINITION + * ======================= */ + + $.fn.alert = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('alert') + if (!data) $this.data('alert', (data = new Alert(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.alert.Constructor = Alert + + + /* ALERT DATA-API + * ============== */ + + $(function () { + $('body').on('click.alert.data-api', dismiss, Alert.prototype.close) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-button.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-button.js new file mode 100644 index 0000000..0238ca3 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-button.js @@ -0,0 +1,100 @@ +/* ============================================================ + * bootstrap-button.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#buttons + * ============================================================ + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + +!function( $ ){ + + "use strict" + + /* BUTTON PUBLIC CLASS DEFINITION + * ============================== */ + + var Button = function ( element, options ) { + this.$element = $(element) + this.options = $.extend({}, $.fn.button.defaults, options) + } + + Button.prototype = { + + constructor: Button + + , setState: function ( state ) { + var d = 'disabled' + , $el = this.$element + , data = $el.data() + , val = $el.is('input') ? 'val' : 'html' + + state = state + 'Text' + data.resetText || $el.data('resetText', $el[val]()) + + $el[val](data[state] || this.options[state]) + + // push to event loop to allow forms to submit + setTimeout(function () { + state == 'loadingText' ? + $el.addClass(d).attr(d, d) : + $el.removeClass(d).removeAttr(d) + }, 0) + } + + , toggle: function () { + var $parent = this.$element.parent('[data-toggle="buttons-radio"]') + + $parent && $parent + .find('.active') + .removeClass('active') + + this.$element.toggleClass('active') + } + + } + + + /* BUTTON PLUGIN DEFINITION + * ======================== */ + + $.fn.button = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('button') + , options = typeof option == 'object' && option + if (!data) $this.data('button', (data = new Button(this, options))) + if (option == 'toggle') data.toggle() + else if (option) data.setState(option) + }) + } + + $.fn.button.defaults = { + loadingText: 'loading...' + } + + $.fn.button.Constructor = Button + + + /* BUTTON DATA-API + * =============== */ + + $(function () { + $('body').on('click.button.data-api', '[data-toggle^=button]', function ( e ) { + var $btn = $(e.target) + if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') + $btn.button('toggle') + }) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-carousel.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-carousel.js new file mode 100644 index 0000000..810256e --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-carousel.js @@ -0,0 +1,157 @@ +/* ========================================================== + * bootstrap-carousel.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#carousel + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function( $ ){ + + "use strict" + + /* CAROUSEL CLASS DEFINITION + * ========================= */ + + var Carousel = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, $.fn.carousel.defaults, options) + this.options.slide && this.slide(this.options.slide) + } + + Carousel.prototype = { + + cycle: function () { + this.interval = setInterval($.proxy(this.next, this), this.options.interval) + return this + } + + , to: function (pos) { + var $active = this.$element.find('.active') + , children = $active.parent().children() + , activePos = children.index($active) + , that = this + + if (pos > (children.length - 1) || pos < 0) return + + if (this.sliding) { + return this.$element.one('slid', function () { + that.to(pos) + }) + } + + if (activePos == pos) { + return this.pause().cycle() + } + + return this.slide(pos > activePos ? 'next' : 'prev', $(children[pos])) + } + + , pause: function () { + clearInterval(this.interval) + this.interval = null + return this + } + + , next: function () { + if (this.sliding) return + return this.slide('next') + } + + , prev: function () { + if (this.sliding) return + return this.slide('prev') + } + + , slide: function (type, next) { + var $active = this.$element.find('.active') + , $next = next || $active[type]() + , isCycling = this.interval + , direction = type == 'next' ? 'left' : 'right' + , fallback = type == 'next' ? 'first' : 'last' + , that = this + + if (!$next.length) return + + this.sliding = true + + isCycling && this.pause() + + $next = $next.length ? $next : this.$element.find('.item')[fallback]() + + if (!$.support.transition && this.$element.hasClass('slide')) { + this.$element.trigger('slide') + $active.removeClass('active') + $next.addClass('active') + this.sliding = false + this.$element.trigger('slid') + } else { + $next.addClass(type) + $next[0].offsetWidth // force reflow + $active.addClass(direction) + $next.addClass(direction) + this.$element.trigger('slide') + this.$element.one($.support.transition.end, function () { + $next.removeClass([type, direction].join(' ')).addClass('active') + $active.removeClass(['active', direction].join(' ')) + that.sliding = false + setTimeout(function () { that.$element.trigger('slid') }, 0) + }) + } + + isCycling && this.cycle() + + return this + } + + } + + + /* CAROUSEL PLUGIN DEFINITION + * ========================== */ + + $.fn.carousel = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('carousel') + , options = typeof option == 'object' && option + if (!data) $this.data('carousel', (data = new Carousel(this, options))) + if (typeof option == 'number') data.to(option) + else if (typeof option == 'string' || (option = options.slide)) data[option]() + else data.cycle() + }) + } + + $.fn.carousel.defaults = { + interval: 5000 + } + + $.fn.carousel.Constructor = Carousel + + + /* CAROUSEL DATA-API + * ================= */ + + $(function () { + $('body').on('click.carousel.data-api', '[data-slide]', function ( e ) { + var $this = $(this), href + , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 + , options = !$target.data('modal') && $.extend({}, $target.data(), $this.data()) + $target.carousel(options) + e.preventDefault() + }) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-collapse.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-collapse.js new file mode 100644 index 0000000..d195efc --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-collapse.js @@ -0,0 +1,136 @@ +/* ============================================================= + * bootstrap-collapse.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#collapse + * ============================================================= + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + +!function( $ ){ + + "use strict" + + var Collapse = function ( element, options ) { + this.$element = $(element) + this.options = $.extend({}, $.fn.collapse.defaults, options) + + if (this.options["parent"]) { + this.$parent = $(this.options["parent"]) + } + + this.options.toggle && this.toggle() + } + + Collapse.prototype = { + + constructor: Collapse + + , dimension: function () { + var hasWidth = this.$element.hasClass('width') + return hasWidth ? 'width' : 'height' + } + + , show: function () { + var dimension = this.dimension() + , scroll = $.camelCase(['scroll', dimension].join('-')) + , actives = this.$parent && this.$parent.find('.in') + , hasData + + if (actives && actives.length) { + hasData = actives.data('collapse') + actives.collapse('hide') + hasData || actives.data('collapse', null) + } + + this.$element[dimension](0) + this.transition('addClass', 'show', 'shown') + this.$element[dimension](this.$element[0][scroll]) + + } + + , hide: function () { + var dimension = this.dimension() + this.reset(this.$element[dimension]()) + this.transition('removeClass', 'hide', 'hidden') + this.$element[dimension](0) + } + + , reset: function ( size ) { + var dimension = this.dimension() + + this.$element + .removeClass('collapse') + [dimension](size || 'auto') + [0].offsetWidth + + this.$element.addClass('collapse') + } + + , transition: function ( method, startEvent, completeEvent ) { + var that = this + , complete = function () { + if (startEvent == 'show') that.reset() + that.$element.trigger(completeEvent) + } + + this.$element + .trigger(startEvent) + [method]('in') + + $.support.transition && this.$element.hasClass('collapse') ? + this.$element.one($.support.transition.end, complete) : + complete() + } + + , toggle: function () { + this[this.$element.hasClass('in') ? 'hide' : 'show']() + } + + } + + /* COLLAPSIBLE PLUGIN DEFINITION + * ============================== */ + + $.fn.collapse = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('collapse') + , options = typeof option == 'object' && option + if (!data) $this.data('collapse', (data = new Collapse(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.collapse.defaults = { + toggle: true + } + + $.fn.collapse.Constructor = Collapse + + + /* COLLAPSIBLE DATA-API + * ==================== */ + + $(function () { + $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function ( e ) { + var $this = $(this), href + , target = $this.attr('data-target') + || e.preventDefault() + || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 + , option = $(target).data('collapse') ? 'toggle' : $this.data() + $(target).collapse(option) + }) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-dropdown.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-dropdown.js new file mode 100644 index 0000000..f1f6c33 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-dropdown.js @@ -0,0 +1,92 @@ +/* ============================================================ + * bootstrap-dropdown.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#dropdowns + * ============================================================ + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + + +!function( $ ){ + + "use strict" + + /* DROPDOWN CLASS DEFINITION + * ========================= */ + + var toggle = '[data-toggle="dropdown"]' + , Dropdown = function ( element ) { + var $el = $(element).on('click.dropdown.data-api', this.toggle) + $('html').on('click.dropdown.data-api', function () { + $el.parent().removeClass('open') + }) + } + + Dropdown.prototype = { + + constructor: Dropdown + + , toggle: function ( e ) { + var $this = $(this) + , selector = $this.attr('data-target') + , $parent + , isActive + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = $(selector) + $parent.length || ($parent = $this.parent()) + + isActive = $parent.hasClass('open') + + clearMenus() + !isActive && $parent.toggleClass('open') + + return false + } + + } + + function clearMenus() { + $(toggle).parent().removeClass('open') + } + + + /* DROPDOWN PLUGIN DEFINITION + * ========================== */ + + $.fn.dropdown = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('dropdown') + if (!data) $this.data('dropdown', (data = new Dropdown(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.dropdown.Constructor = Dropdown + + + /* APPLY TO STANDARD DROPDOWN ELEMENTS + * =================================== */ + + $(function () { + $('html').on('click.dropdown.data-api', clearMenus) + $('body').on('click.dropdown.data-api', toggle, Dropdown.prototype.toggle) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-modal.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-modal.js new file mode 100644 index 0000000..bceb303 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-modal.js @@ -0,0 +1,210 @@ +/* ========================================================= + * bootstrap-modal.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#modals + * ========================================================= + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================= */ + + +!function( $ ){ + + "use strict" + + /* MODAL CLASS DEFINITION + * ====================== */ + + var Modal = function ( content, options ) { + this.options = options + this.$element = $(content) + .delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this)) + } + + Modal.prototype = { + + constructor: Modal + + , toggle: function () { + return this[!this.isShown ? 'show' : 'hide']() + } + + , show: function () { + var that = this + + if (this.isShown) return + + $('body').addClass('modal-open') + + this.isShown = true + this.$element.trigger('show') + + escape.call(this) + backdrop.call(this, function () { + var transition = $.support.transition && that.$element.hasClass('fade') + + !that.$element.parent().length && that.$element.appendTo(document.body) //don't move modals dom position + + that.$element + .show() + + if (transition) { + that.$element[0].offsetWidth // force reflow + } + + that.$element.addClass('in') + + transition ? + that.$element.one($.support.transition.end, function () { that.$element.trigger('shown') }) : + that.$element.trigger('shown') + + }) + } + + , hide: function ( e ) { + e && e.preventDefault() + + if (!this.isShown) return + + var that = this + this.isShown = false + + $('body').removeClass('modal-open') + + escape.call(this) + + this.$element + .trigger('hide') + .removeClass('in') + + $.support.transition && this.$element.hasClass('fade') ? + hideWithTransition.call(this) : + hideModal.call(this) + } + + } + + + /* MODAL PRIVATE METHODS + * ===================== */ + + function hideWithTransition() { + var that = this + , timeout = setTimeout(function () { + that.$element.off($.support.transition.end) + hideModal.call(that) + }, 500) + + this.$element.one($.support.transition.end, function () { + clearTimeout(timeout) + hideModal.call(that) + }) + } + + function hideModal( that ) { + this.$element + .hide() + .trigger('hidden') + + backdrop.call(this) + } + + function backdrop( callback ) { + var that = this + , animate = this.$element.hasClass('fade') ? 'fade' : '' + + if (this.isShown && this.options.backdrop) { + var doAnimate = $.support.transition && animate + + this.$backdrop = $(' + + + + + \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/head.html b/src/nl/astraeus/jdbc/web/head.html new file mode 100644 index 0000000..0f8f6a3 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/head.html @@ -0,0 +1,96 @@ + + + + + + + Simple JDBC Statistics + + + + + + + + + + + + + + + + + + + +
+
+ +
+ diff --git a/src/nl/astraeus/jdbc/web/page/Menu.html b/src/nl/astraeus/jdbc/web/page/Menu.html new file mode 100644 index 0000000..505c7c2 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.html @@ -0,0 +1,42 @@ + diff --git a/src/nl/astraeus/jdbc/web/page/Menu.java b/src/nl/astraeus/jdbc/web/page/Menu.java new file mode 100644 index 0000000..f0a349a --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Menu.java @@ -0,0 +1,27 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 9:07 PM + */ +public class Menu extends TemplatePage { + + @Override + public Page processRequest(HttpServletRequest request) { + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + result.put("user", request.getSession().getAttribute("user")); + + return result; + } +} diff --git a/src/nl/astraeus/jdbc/web/page/Page.java b/src/nl/astraeus/jdbc/web/page/Page.java new file mode 100644 index 0000000..9d526d6 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/Page.java @@ -0,0 +1,17 @@ +package nl.astraeus.jdbc.web.page; + +import javax.servlet.http.HttpServletRequest; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:20 PM + */ +public abstract class Page { + + public abstract Page processRequest(HttpServletRequest request); + public abstract Map defineModel(HttpServletRequest request); + public abstract String render(HttpServletRequest request); + +} diff --git a/src/nl/astraeus/jdbc/web/page/QueryOverview.html b/src/nl/astraeus/jdbc/web/page/QueryOverview.html new file mode 100644 index 0000000..64a88fb --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/QueryOverview.html @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + {foreach(queries as q)} + + + + + + + {eachend} + +
Total timeAvg. time# CallsSql
{q.total}{q.nano}{q.count}{q.sql}
diff --git a/src/nl/astraeus/jdbc/web/page/QueryOverview.java b/src/nl/astraeus/jdbc/web/page/QueryOverview.java new file mode 100644 index 0000000..02982f1 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/QueryOverview.java @@ -0,0 +1,92 @@ +package nl.astraeus.jdbc.web.page; + +import nl.astraeus.jdbc.JdbcLogger; + +import javax.servlet.http.HttpServletRequest; +import java.util.*; + +/** + * User: rnentjes + * Date: 4/12/12 + * Time: 9:16 PM + */ +public class QueryOverview extends TemplatePage { + + boolean sortTotalCalls = true; + boolean sortAvgTime = false; + boolean sortTotalTime = false; + + @Override + public Page processRequest(HttpServletRequest request) { + if ("sortTotalCalls".equals(request.getParameter("action"))) { + sortTotalCalls = true; + sortAvgTime = false; + sortTotalTime = false; + } else if ("sortAvgTime".equals(request.getParameter("action"))) { + sortTotalCalls = false; + sortAvgTime = true; + sortTotalTime = false; + } else if ("sortTotalTime".equals(request.getParameter("action"))) { + sortTotalCalls = false; + sortAvgTime = false; + sortTotalTime = true; + } + + return this; + } + + @Override + public Map defineModel(HttpServletRequest request) { + Map result = new HashMap(); + + List entries = new ArrayList(JdbcLogger.get().getEntries()); + + if (sortTotalCalls) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + return o2.count - o1.count; + } + }); + } else if (sortAvgTime) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + long n1 = o1.nano / o1.count; + long n2 = o2.nano / o2.count; + + if (n2 > n1) { + return 1; + } else if (n2 < n1) { + return -1; + } else { + return 0; + } + } + }); + } else if (sortTotalTime) { + Collections.sort(entries, new Comparator() { + @Override + public int compare(JdbcLogger.LogEntry o1, JdbcLogger.LogEntry o2) { + if (o2.nano > o1.nano) { + return 1; + } else if (o2.nano < o1.nano) { + return -1; + } else { + return 0; + } + } + }); + } + + result.put("queries", entries); + result.put("count", entries.size()); + + result.put("sortTotalCalls", sortTotalCalls); + result.put("sortAvgTime", sortAvgTime); + result.put("sortTotalTime", sortTotalTime); + + return result; + } + +} diff --git a/src/nl/astraeus/jdbc/web/page/TemplatePage.java b/src/nl/astraeus/jdbc/web/page/TemplatePage.java new file mode 100644 index 0000000..33e2641 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/page/TemplatePage.java @@ -0,0 +1,58 @@ +package nl.astraeus.jdbc.web.page; + +import nl.astraeus.template.EscapeMode; +import nl.astraeus.template.SimpleTemplate; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +/** + * User: rnentjes + * Date: 3/28/12 + * Time: 3:20 PM + */ +public abstract class TemplatePage extends Page { + + private SimpleTemplate template; + + protected TemplatePage() { + template = getSimpleTemplate(this.getClass()); + } + + public String render(HttpServletRequest request) { + return template.render(defineModel(request)); + } + + private static Map templateCache = new HashMap(); + + public synchronized static SimpleTemplate getSimpleTemplate(Class cls) { + SimpleTemplate result = templateCache.get(cls); + + if (result == null) { + InputStream in = null; + + try { + in = cls.getResourceAsStream(cls.getSimpleName() + ".html"); + + result = SimpleTemplate.readTemplate('{','}', EscapeMode.HTML, in); + + templateCache.put(cls, result); + } catch (IOException e) { + throw new IllegalStateException(e); + } finally { + if (in != null) { + try { + in.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + + return result; + } +} diff --git a/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css b/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css new file mode 100644 index 0000000..0e0056f --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/css/bootstrap-responsive.css @@ -0,0 +1,581 @@ +/*! + * Bootstrap Responsive v2.0.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ +.clearfix { + *zoom: 1; +} +.clearfix:before, .clearfix:after { + display: table; + content: ""; +} +.clearfix:after { + clear: both; +} +.hidden { + display: none; + visibility: hidden; +} +@media (max-width: 480px) { + .nav-collapse { + -webkit-transform: translate3d(0, 0, 0); + } + .page-header h1 small { + display: block; + line-height: 18px; + } + input[class*="span"], + select[class*="span"], + textarea[class*="span"], + .uneditable-input { + display: block; + width: 100%; + min-height: 28px; + /* Make inputs at least the height of their button counterpart */ + + /* Makes inputs behave like true block-level elements */ + + -webkit-box-sizing: border-box; + /* Older Webkit */ + + -moz-box-sizing: border-box; + /* Older FF */ + + -ms-box-sizing: border-box; + /* IE8 */ + + box-sizing: border-box; + /* CSS3 spec*/ + + } + .input-prepend input[class*="span"], .input-append input[class*="span"] { + width: auto; + } + input[type="checkbox"], input[type="radio"] { + border: 1px solid #ccc; + } + .form-horizontal .control-group > label { + float: none; + width: auto; + padding-top: 0; + text-align: left; + } + .form-horizontal .controls { + margin-left: 0; + } + .form-horizontal .control-list { + padding-top: 0; + } + .form-horizontal .form-actions { + padding-left: 10px; + padding-right: 10px; + } + .modal { + position: absolute; + top: 10px; + left: 10px; + right: 10px; + width: auto; + margin: 0; + } + .modal.fade.in { + top: auto; + } + .modal-header .close { + padding: 10px; + margin: -10px; + } + .carousel-caption { + position: static; + } +} +@media (max-width: 767px) { + .container { + width: auto; + padding: 0 20px; + } + .row-fluid { + width: 100%; + } + .row { + margin-left: 0; + } + .row > [class*="span"], .row-fluid > [class*="span"] { + float: none; + display: block; + width: auto; + margin: 0; + } +} +@media (min-width: 768px) and (max-width: 979px) { + .row { + margin-left: -20px; + *zoom: 1; + } + .row:before, .row:after { + display: table; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + margin-left: 20px; + } + .span1 { + width: 42px; + } + .span2 { + width: 104px; + } + .span3 { + width: 166px; + } + .span4 { + width: 228px; + } + .span5 { + width: 290px; + } + .span6 { + width: 352px; + } + .span7 { + width: 414px; + } + .span8 { + width: 476px; + } + .span9 { + width: 538px; + } + .span10 { + width: 600px; + } + .span11 { + width: 662px; + } + .span12, .container { + width: 724px; + } + .offset1 { + margin-left: 82px; + } + .offset2 { + margin-left: 144px; + } + .offset3 { + margin-left: 206px; + } + .offset4 { + margin-left: 268px; + } + .offset5 { + margin-left: 330px; + } + .offset6 { + margin-left: 392px; + } + .offset7 { + margin-left: 454px; + } + .offset8 { + margin-left: 516px; + } + .offset9 { + margin-left: 578px; + } + .offset10 { + margin-left: 640px; + } + .offset11 { + margin-left: 702px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, .row-fluid:after { + display: table; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid > [class*="span"] { + float: left; + margin-left: 2.762430939%; + } + .row-fluid > [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid > .span1 { + width: 5.801104972%; + } + .row-fluid > .span2 { + width: 14.364640883%; + } + .row-fluid > .span3 { + width: 22.928176794%; + } + .row-fluid > .span4 { + width: 31.491712705%; + } + .row-fluid > .span5 { + width: 40.055248616%; + } + .row-fluid > .span6 { + width: 48.618784527%; + } + .row-fluid > .span7 { + width: 57.182320438000005%; + } + .row-fluid > .span8 { + width: 65.74585634900001%; + } + .row-fluid > .span9 { + width: 74.30939226%; + } + .row-fluid > .span10 { + width: 82.87292817100001%; + } + .row-fluid > .span11 { + width: 91.436464082%; + } + .row-fluid > .span12 { + width: 99.999999993%; + } + input.span1, textarea.span1, .uneditable-input.span1 { + width: 32px; + } + input.span2, textarea.span2, .uneditable-input.span2 { + width: 94px; + } + input.span3, textarea.span3, .uneditable-input.span3 { + width: 156px; + } + input.span4, textarea.span4, .uneditable-input.span4 { + width: 218px; + } + input.span5, textarea.span5, .uneditable-input.span5 { + width: 280px; + } + input.span6, textarea.span6, .uneditable-input.span6 { + width: 342px; + } + input.span7, textarea.span7, .uneditable-input.span7 { + width: 404px; + } + input.span8, textarea.span8, .uneditable-input.span8 { + width: 466px; + } + input.span9, textarea.span9, .uneditable-input.span9 { + width: 528px; + } + input.span10, textarea.span10, .uneditable-input.span10 { + width: 590px; + } + input.span11, textarea.span11, .uneditable-input.span11 { + width: 652px; + } + input.span12, textarea.span12, .uneditable-input.span12 { + width: 714px; + } +} +@media (max-width: 979px) { + body { + padding-top: 0; + } + .navbar-fixed-top { + position: static; + margin-bottom: 18px; + } + .navbar-fixed-top .navbar-inner { + padding: 5px; + } + .navbar .container { + width: auto; + padding: 0; + } + .navbar .brand { + padding-left: 10px; + padding-right: 10px; + margin: 0 0 0 -5px; + } + .navbar .nav-collapse { + clear: left; + } + .navbar .nav { + float: none; + margin: 0 0 9px; + } + .navbar .nav > li { + float: none; + } + .navbar .nav > li > a { + margin-bottom: 2px; + } + .navbar .nav > .divider-vertical { + display: none; + } + .navbar .nav .nav-header { + color: #999999; + text-shadow: none; + } + .navbar .nav > li > a, .navbar .dropdown-menu a { + padding: 6px 15px; + font-weight: bold; + color: #999999; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + } + .navbar .dropdown-menu li + li a { + margin-bottom: 2px; + } + .navbar .nav > li > a:hover, .navbar .dropdown-menu a:hover { + background-color: #222222; + } + .navbar .dropdown-menu { + position: static; + top: auto; + left: auto; + float: none; + display: block; + max-width: none; + margin: 0 15px; + padding: 0; + background-color: transparent; + border: none; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + } + .navbar .dropdown-menu:before, .navbar .dropdown-menu:after { + display: none; + } + .navbar .dropdown-menu .divider { + display: none; + } + .navbar-form, .navbar-search { + float: none; + padding: 9px 15px; + margin: 9px 0; + border-top: 1px solid #222222; + border-bottom: 1px solid #222222; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + } + .navbar .nav.pull-right { + float: none; + margin-left: 0; + } + .navbar-static .navbar-inner { + padding-left: 10px; + padding-right: 10px; + } + .btn-navbar { + display: block; + } + .nav-collapse { + overflow: hidden; + height: 0; + } +} +@media (min-width: 980px) { + .nav-collapse.collapse { + height: auto !important; + } +} +@media (min-width: 1200px) { + .row { + margin-left: -30px; + *zoom: 1; + } + .row:before, .row:after { + display: table; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + margin-left: 30px; + } + .span1 { + width: 70px; + } + .span2 { + width: 170px; + } + .span3 { + width: 270px; + } + .span4 { + width: 370px; + } + .span5 { + width: 470px; + } + .span6 { + width: 570px; + } + .span7 { + width: 670px; + } + .span8 { + width: 770px; + } + .span9 { + width: 870px; + } + .span10 { + width: 970px; + } + .span11 { + width: 1070px; + } + .span12, .container { + width: 1170px; + } + .offset1 { + margin-left: 130px; + } + .offset2 { + margin-left: 230px; + } + .offset3 { + margin-left: 330px; + } + .offset4 { + margin-left: 430px; + } + .offset5 { + margin-left: 530px; + } + .offset6 { + margin-left: 630px; + } + .offset7 { + margin-left: 730px; + } + .offset8 { + margin-left: 830px; + } + .offset9 { + margin-left: 930px; + } + .offset10 { + margin-left: 1030px; + } + .offset11 { + margin-left: 1130px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, .row-fluid:after { + display: table; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid > [class*="span"] { + float: left; + margin-left: 2.564102564%; + } + .row-fluid > [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid > .span1 { + width: 5.982905983%; + } + .row-fluid > .span2 { + width: 14.529914530000001%; + } + .row-fluid > .span3 { + width: 23.076923077%; + } + .row-fluid > .span4 { + width: 31.623931624%; + } + .row-fluid > .span5 { + width: 40.170940171000005%; + } + .row-fluid > .span6 { + width: 48.717948718%; + } + .row-fluid > .span7 { + width: 57.264957265%; + } + .row-fluid > .span8 { + width: 65.81196581200001%; + } + .row-fluid > .span9 { + width: 74.358974359%; + } + .row-fluid > .span10 { + width: 82.905982906%; + } + .row-fluid > .span11 { + width: 91.45299145300001%; + } + .row-fluid > .span12 { + width: 100%; + } + input.span1, textarea.span1, .uneditable-input.span1 { + width: 60px; + } + input.span2, textarea.span2, .uneditable-input.span2 { + width: 160px; + } + input.span3, textarea.span3, .uneditable-input.span3 { + width: 260px; + } + input.span4, textarea.span4, .uneditable-input.span4 { + width: 360px; + } + input.span5, textarea.span5, .uneditable-input.span5 { + width: 460px; + } + input.span6, textarea.span6, .uneditable-input.span6 { + width: 560px; + } + input.span7, textarea.span7, .uneditable-input.span7 { + width: 660px; + } + input.span8, textarea.span8, .uneditable-input.span8 { + width: 760px; + } + input.span9, textarea.span9, .uneditable-input.span9 { + width: 860px; + } + input.span10, textarea.span10, .uneditable-input.span10 { + width: 960px; + } + input.span11, textarea.span11, .uneditable-input.span11 { + width: 1060px; + } + input.span12, textarea.span12, .uneditable-input.span12 { + width: 1160px; + } + .thumbnails { + margin-left: -30px; + } + .thumbnails > li { + margin-left: 30px; + } +} diff --git a/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css b/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css new file mode 100644 index 0000000..6229c12 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/css/bootstrap.css @@ -0,0 +1,3521 @@ +/*! + * Bootstrap v2.0.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +nav, +section { + display: block; +} +audio, canvas, video { + display: inline-block; + *display: inline; + *zoom: 1; +} +audio:not([controls]) { + display: none; +} +html { + font-size: 100%; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} +a:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +a:hover, a:active { + outline: 0; +} +sub, sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} +sup { + top: -0.5em; +} +sub { + bottom: -0.25em; +} +img { + max-width: 100%; + height: auto; + border: 0; + -ms-interpolation-mode: bicubic; +} +button, +input, +select, +textarea { + margin: 0; + font-size: 100%; + vertical-align: middle; +} +button, input { + *overflow: visible; + line-height: normal; +} +button::-moz-focus-inner, input::-moz-focus-inner { + padding: 0; + border: 0; +} +button, +input[type="button"], +input[type="reset"], +input[type="submit"] { + cursor: pointer; + -webkit-appearance: button; +} +input[type="search"] { + -webkit-appearance: textfield; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +input[type="search"]::-webkit-search-decoration, input[type="search"]::-webkit-search-cancel-button { + -webkit-appearance: none; +} +textarea { + overflow: auto; + vertical-align: top; +} +.clearfix { + *zoom: 1; +} +.clearfix:before, .clearfix:after { + display: table; + content: ""; +} +.clearfix:after { + clear: both; +} +body { + margin: 0; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 18px; + color: #333333; + background-color: #ffffff; +} +a { + color: #0088cc; + text-decoration: none; +} +a:hover { + color: #005580; + text-decoration: underline; +} +.row { + margin-left: -20px; + *zoom: 1; +} +.row:before, .row:after { + display: table; + content: ""; +} +.row:after { + clear: both; +} +[class*="span"] { + float: left; + margin-left: 20px; +} +.span1 { + width: 60px; +} +.span2 { + width: 140px; +} +.span3 { + width: 220px; +} +.span4 { + width: 300px; +} +.span5 { + width: 380px; +} +.span6 { + width: 460px; +} +.span7 { + width: 540px; +} +.span8 { + width: 620px; +} +.span9 { + width: 700px; +} +.span10 { + width: 780px; +} +.span11 { + width: 860px; +} +.span12, .container { + width: 940px; +} +.offset1 { + margin-left: 100px; +} +.offset2 { + margin-left: 180px; +} +.offset3 { + margin-left: 260px; +} +.offset4 { + margin-left: 340px; +} +.offset5 { + margin-left: 420px; +} +.offset6 { + margin-left: 500px; +} +.offset7 { + margin-left: 580px; +} +.offset8 { + margin-left: 660px; +} +.offset9 { + margin-left: 740px; +} +.offset10 { + margin-left: 820px; +} +.offset11 { + margin-left: 900px; +} +.row-fluid { + width: 100%; + *zoom: 1; +} +.row-fluid:before, .row-fluid:after { + display: table; + content: ""; +} +.row-fluid:after { + clear: both; +} +.row-fluid > [class*="span"] { + float: left; + margin-left: 2.127659574%; +} +.row-fluid > [class*="span"]:first-child { + margin-left: 0; +} +.row-fluid > .span1 { + width: 6.382978723%; +} +.row-fluid > .span2 { + width: 14.89361702%; +} +.row-fluid > .span3 { + width: 23.404255317%; +} +.row-fluid > .span4 { + width: 31.914893614%; +} +.row-fluid > .span5 { + width: 40.425531911%; +} +.row-fluid > .span6 { + width: 48.93617020799999%; +} +.row-fluid > .span7 { + width: 57.446808505%; +} +.row-fluid > .span8 { + width: 65.95744680199999%; +} +.row-fluid > .span9 { + width: 74.468085099%; +} +.row-fluid > .span10 { + width: 82.97872339599999%; +} +.row-fluid > .span11 { + width: 91.489361693%; +} +.row-fluid > .span12 { + width: 99.99999998999999%; +} +.container { + width: 940px; + margin-left: auto; + margin-right: auto; + *zoom: 1; +} +.container:before, .container:after { + display: table; + content: ""; +} +.container:after { + clear: both; +} +.container-fluid { + padding-left: 20px; + padding-right: 20px; + *zoom: 1; +} +.container-fluid:before, .container-fluid:after { + display: table; + content: ""; +} +.container-fluid:after { + clear: both; +} +p { + margin: 0 0 9px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 18px; +} +p small { + font-size: 11px; + color: #999999; +} +.lead { + margin-bottom: 18px; + font-size: 20px; + font-weight: 200; + line-height: 27px; +} +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 0; + font-weight: bold; + color: #333333; + text-rendering: optimizelegibility; +} +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small { + font-weight: normal; + color: #999999; +} +h1 { + font-size: 30px; + line-height: 36px; +} +h1 small { + font-size: 18px; +} +h2 { + font-size: 24px; + line-height: 36px; +} +h2 small { + font-size: 18px; +} +h3 { + line-height: 27px; + font-size: 18px; +} +h3 small { + font-size: 14px; +} +h4, h5, h6 { + line-height: 18px; +} +h4 { + font-size: 14px; +} +h4 small { + font-size: 12px; +} +h5 { + font-size: 12px; +} +h6 { + font-size: 11px; + color: #999999; + text-transform: uppercase; +} +.page-header { + padding-bottom: 17px; + margin: 18px 0; + border-bottom: 1px solid #eeeeee; +} +.page-header h1 { + line-height: 1; +} +ul, ol { + padding: 0; + margin: 0 0 9px 25px; +} +ul ul, +ul ol, +ol ol, +ol ul { + margin-bottom: 0; +} +ul { + list-style: disc; +} +ol { + list-style: decimal; +} +li { + line-height: 18px; +} +ul.unstyled, ol.unstyled { + margin-left: 0; + list-style: none; +} +dl { + margin-bottom: 18px; +} +dt, dd { + line-height: 18px; +} +dt { + font-weight: bold; +} +dd { + margin-left: 9px; +} +hr { + margin: 18px 0; + border: 0; + border-top: 1px solid #eeeeee; + border-bottom: 1px solid #ffffff; +} +strong { + font-weight: bold; +} +em { + font-style: italic; +} +.muted { + color: #999999; +} +abbr { + font-size: 90%; + text-transform: uppercase; + border-bottom: 1px dotted #ddd; + cursor: help; +} +blockquote { + padding: 0 0 0 15px; + margin: 0 0 18px; + border-left: 5px solid #eeeeee; +} +blockquote p { + margin-bottom: 0; + font-size: 16px; + font-weight: 300; + line-height: 22.5px; +} +blockquote small { + display: block; + line-height: 18px; + color: #999999; +} +blockquote small:before { + content: '\2014 \00A0'; +} +blockquote.pull-right { + float: right; + padding-left: 0; + padding-right: 15px; + border-left: 0; + border-right: 5px solid #eeeeee; +} +blockquote.pull-right p, blockquote.pull-right small { + text-align: right; +} +q:before, +q:after, +blockquote:before, +blockquote:after { + content: ""; +} +address { + display: block; + margin-bottom: 18px; + line-height: 18px; + font-style: normal; +} +small { + font-size: 100%; +} +cite { + font-style: normal; +} +code, pre { + padding: 0 3px 2px; + font-family: Menlo, Monaco, "Courier New", monospace; + font-size: 12px; + color: #333333; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +code { + padding: 3px 4px; + color: #d14; + background-color: #f7f7f9; + border: 1px solid #e1e1e8; +} +pre { + display: block; + padding: 8.5px; + margin: 0 0 9px; + font-size: 12px; + line-height: 18px; + background-color: #f5f5f5; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.15); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + white-space: pre; + white-space: pre-wrap; + word-break: break-all; + word-wrap: break-word; +} +pre.prettyprint { + margin-bottom: 18px; +} +pre code { + padding: 0; + color: inherit; + background-color: transparent; + border: 0; +} +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} +form { + margin: 0 0 18px; +} +fieldset { + padding: 0; + margin: 0; + border: 0; +} +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 27px; + font-size: 19.5px; + line-height: 36px; + color: #333333; + border: 0; + border-bottom: 1px solid #eee; +} +legend small { + font-size: 13.5px; + color: #999999; +} +label, +input, +button, +select, +textarea { + font-size: 13px; + font-weight: normal; + line-height: 18px; +} +input, +button, +select, +textarea { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; +} +label { + display: block; + margin-bottom: 5px; + color: #333333; +} +input, +textarea, +select, +.uneditable-input { + display: inline-block; + width: 210px; + height: 18px; + padding: 4px; + margin-bottom: 9px; + font-size: 13px; + line-height: 18px; + color: #555555; + border: 1px solid #ccc; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.uneditable-textarea { + width: auto; + height: auto; +} +label input, label textarea, label select { + display: block; +} +input[type="image"], input[type="checkbox"], input[type="radio"] { + width: auto; + height: auto; + padding: 0; + margin: 3px 0; + *margin-top: 0; + /* IE7 */ + + line-height: normal; + cursor: pointer; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + border: 0 \9; + /* IE9 and down */ + +} +input[type="image"] { + border: 0; +} +input[type="file"] { + width: auto; + padding: initial; + line-height: initial; + border: initial; + background-color: #ffffff; + background-color: initial; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +input[type="button"], input[type="reset"], input[type="submit"] { + width: auto; + height: auto; +} +select, input[type="file"] { + height: 28px; + /* In IE7, the height of the select element cannot be changed by height, only font-size */ + + *margin-top: 4px; + /* For IE7, add top margin to align select with labels */ + + line-height: 28px; +} +input[type="file"] { + line-height: 18px \9; +} +select { + width: 220px; + background-color: #ffffff; +} +select[multiple], select[size] { + height: auto; +} +input[type="image"] { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +textarea { + height: auto; +} +input[type="hidden"] { + display: none; +} +.radio, .checkbox { + padding-left: 18px; +} +.radio input[type="radio"], .checkbox input[type="checkbox"] { + float: left; + margin-left: -18px; +} +.controls > .radio:first-child, .controls > .checkbox:first-child { + padding-top: 5px; +} +.radio.inline, .checkbox.inline { + display: inline-block; + padding-top: 5px; + margin-bottom: 0; + vertical-align: middle; +} +.radio.inline + .radio.inline, .checkbox.inline + .checkbox.inline { + margin-left: 10px; +} +input, textarea { + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; + -moz-transition: border linear 0.2s, box-shadow linear 0.2s; + -ms-transition: border linear 0.2s, box-shadow linear 0.2s; + -o-transition: border linear 0.2s, box-shadow linear 0.2s; + transition: border linear 0.2s, box-shadow linear 0.2s; +} +input:focus, textarea:focus { + border-color: rgba(82, 168, 236, 0.8); + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + outline: 0; + outline: thin dotted \9; + /* IE6-9 */ + +} +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus, +select:focus { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.input-mini { + width: 60px; +} +.input-small { + width: 90px; +} +.input-medium { + width: 150px; +} +.input-large { + width: 210px; +} +.input-xlarge { + width: 270px; +} +.input-xxlarge { + width: 530px; +} +input[class*="span"], +select[class*="span"], +textarea[class*="span"], +.uneditable-input { + float: none; + margin-left: 0; +} +input.span1, textarea.span1, .uneditable-input.span1 { + width: 50px; +} +input.span2, textarea.span2, .uneditable-input.span2 { + width: 130px; +} +input.span3, textarea.span3, .uneditable-input.span3 { + width: 210px; +} +input.span4, textarea.span4, .uneditable-input.span4 { + width: 290px; +} +input.span5, textarea.span5, .uneditable-input.span5 { + width: 370px; +} +input.span6, textarea.span6, .uneditable-input.span6 { + width: 450px; +} +input.span7, textarea.span7, .uneditable-input.span7 { + width: 530px; +} +input.span8, textarea.span8, .uneditable-input.span8 { + width: 610px; +} +input.span9, textarea.span9, .uneditable-input.span9 { + width: 690px; +} +input.span10, textarea.span10, .uneditable-input.span10 { + width: 770px; +} +input.span11, textarea.span11, .uneditable-input.span11 { + width: 850px; +} +input.span12, textarea.span12, .uneditable-input.span12 { + width: 930px; +} +input[disabled], +select[disabled], +textarea[disabled], +input[readonly], +select[readonly], +textarea[readonly] { + background-color: #f5f5f5; + border-color: #ddd; + cursor: not-allowed; +} +.control-group.warning > label, .control-group.warning .help-block, .control-group.warning .help-inline { + color: #c09853; +} +.control-group.warning input, .control-group.warning select, .control-group.warning textarea { + color: #c09853; + border-color: #c09853; +} +.control-group.warning input:focus, .control-group.warning select:focus, .control-group.warning textarea:focus { + border-color: #a47e3c; + -webkit-box-shadow: 0 0 6px #dbc59e; + -moz-box-shadow: 0 0 6px #dbc59e; + box-shadow: 0 0 6px #dbc59e; +} +.control-group.warning .input-prepend .add-on, .control-group.warning .input-append .add-on { + color: #c09853; + background-color: #fcf8e3; + border-color: #c09853; +} +.control-group.error > label, .control-group.error .help-block, .control-group.error .help-inline { + color: #b94a48; +} +.control-group.error input, .control-group.error select, .control-group.error textarea { + color: #b94a48; + border-color: #b94a48; +} +.control-group.error input:focus, .control-group.error select:focus, .control-group.error textarea:focus { + border-color: #953b39; + -webkit-box-shadow: 0 0 6px #d59392; + -moz-box-shadow: 0 0 6px #d59392; + box-shadow: 0 0 6px #d59392; +} +.control-group.error .input-prepend .add-on, .control-group.error .input-append .add-on { + color: #b94a48; + background-color: #f2dede; + border-color: #b94a48; +} +.control-group.success > label, .control-group.success .help-block, .control-group.success .help-inline { + color: #468847; +} +.control-group.success input, .control-group.success select, .control-group.success textarea { + color: #468847; + border-color: #468847; +} +.control-group.success input:focus, .control-group.success select:focus, .control-group.success textarea:focus { + border-color: #356635; + -webkit-box-shadow: 0 0 6px #7aba7b; + -moz-box-shadow: 0 0 6px #7aba7b; + box-shadow: 0 0 6px #7aba7b; +} +.control-group.success .input-prepend .add-on, .control-group.success .input-append .add-on { + color: #468847; + background-color: #dff0d8; + border-color: #468847; +} +input:focus:required:invalid, textarea:focus:required:invalid, select:focus:required:invalid { + color: #b94a48; + border-color: #ee5f5b; +} +input:focus:required:invalid:focus, textarea:focus:required:invalid:focus, select:focus:required:invalid:focus { + border-color: #e9322d; + -webkit-box-shadow: 0 0 6px #f8b9b7; + -moz-box-shadow: 0 0 6px #f8b9b7; + box-shadow: 0 0 6px #f8b9b7; +} +.form-actions { + padding: 17px 20px 18px; + margin-top: 18px; + margin-bottom: 18px; + background-color: #f5f5f5; + border-top: 1px solid #ddd; +} +.uneditable-input { + display: block; + background-color: #ffffff; + border-color: #eee; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + cursor: not-allowed; +} +:-moz-placeholder { + color: #999999; +} +::-webkit-input-placeholder { + color: #999999; +} +.help-block { + display: block; + margin-top: 5px; + margin-bottom: 0; + color: #999999; +} +.help-inline { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; + margin-bottom: 9px; + vertical-align: middle; + padding-left: 5px; +} +.input-prepend, .input-append { + margin-bottom: 5px; + *zoom: 1; +} +.input-prepend:before, +.input-append:before, +.input-prepend:after, +.input-append:after { + display: table; + content: ""; +} +.input-prepend:after, .input-append:after { + clear: both; +} +.input-prepend input, +.input-append input, +.input-prepend .uneditable-input, +.input-append .uneditable-input { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.input-prepend input:focus, +.input-append input:focus, +.input-prepend .uneditable-input:focus, +.input-append .uneditable-input:focus { + position: relative; + z-index: 2; +} +.input-prepend .uneditable-input, .input-append .uneditable-input { + border-left-color: #ccc; +} +.input-prepend .add-on, .input-append .add-on { + float: left; + display: block; + width: auto; + min-width: 16px; + height: 18px; + margin-right: -1px; + padding: 4px 5px; + font-weight: normal; + line-height: 18px; + color: #999999; + text-align: center; + text-shadow: 0 1px 0 #ffffff; + background-color: #f5f5f5; + border: 1px solid #ccc; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.input-prepend .active, .input-append .active { + background-color: #a9dba9; + border-color: #46a546; +} +.input-prepend .add-on { + *margin-top: 1px; + /* IE6-7 */ + +} +.input-append input, .input-append .uneditable-input { + float: left; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.input-append .uneditable-input { + border-left-color: #eee; + border-right-color: #ccc; +} +.input-append .add-on { + margin-right: 0; + margin-left: -1px; + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.input-append input:first-child { + *margin-left: -160px; +} +.input-append input:first-child + .add-on { + *margin-left: -21px; +} +.search-query { + padding-left: 14px; + padding-right: 14px; + margin-bottom: 0; + -webkit-border-radius: 14px; + -moz-border-radius: 14px; + border-radius: 14px; +} +.form-search input, +.form-inline input, +.form-horizontal input, +.form-search textarea, +.form-inline textarea, +.form-horizontal textarea, +.form-search select, +.form-inline select, +.form-horizontal select, +.form-search .help-inline, +.form-inline .help-inline, +.form-horizontal .help-inline, +.form-search .uneditable-input, +.form-inline .uneditable-input, +.form-horizontal .uneditable-input { + display: inline-block; + margin-bottom: 0; +} +.form-search .hide, .form-inline .hide, .form-horizontal .hide { + display: none; +} +.form-search label, +.form-inline label, +.form-search .input-append, +.form-inline .input-append, +.form-search .input-prepend, +.form-inline .input-prepend { + display: inline-block; +} +.form-search .input-append .add-on, +.form-inline .input-prepend .add-on, +.form-search .input-append .add-on, +.form-inline .input-prepend .add-on { + vertical-align: middle; +} +.form-search .radio, +.form-inline .radio, +.form-search .checkbox, +.form-inline .checkbox { + margin-bottom: 0; + vertical-align: middle; +} +.control-group { + margin-bottom: 9px; +} +legend + .control-group { + margin-top: 18px; + -webkit-margin-top-collapse: separate; +} +.form-horizontal .control-group { + margin-bottom: 18px; + *zoom: 1; +} +.form-horizontal .control-group:before, .form-horizontal .control-group:after { + display: table; + content: ""; +} +.form-horizontal .control-group:after { + clear: both; +} +.form-horizontal .control-label { + float: left; + width: 140px; + padding-top: 5px; + text-align: right; +} +.form-horizontal .controls { + margin-left: 160px; +} +.form-horizontal .form-actions { + padding-left: 160px; +} +table { + max-width: 100%; + border-collapse: collapse; + border-spacing: 0; +} +.table { + width: 100%; + margin-bottom: 18px; +} +.table th, .table td { + padding: 8px; + line-height: 18px; + text-align: left; + vertical-align: top; + border-top: 1px solid #ddd; +} +.table th { + font-weight: bold; +} +.table thead th { + vertical-align: bottom; +} +.table thead:first-child tr th, .table thead:first-child tr td { + border-top: 0; +} +.table tbody + tbody { + border-top: 2px solid #ddd; +} +.table-condensed th, .table-condensed td { + padding: 4px 5px; +} +.table-bordered { + border: 1px solid #ddd; + border-collapse: separate; + *border-collapse: collapsed; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.table-bordered th + th, +.table-bordered td + td, +.table-bordered th + td, +.table-bordered td + th { + border-left: 1px solid #ddd; +} +.table-bordered thead:first-child tr:first-child th, .table-bordered tbody:first-child tr:first-child th, .table-bordered tbody:first-child tr:first-child td { + border-top: 0; +} +.table-bordered thead:first-child tr:first-child th:first-child, .table-bordered tbody:first-child tr:first-child td:first-child { + -webkit-border-radius: 4px 0 0 0; + -moz-border-radius: 4px 0 0 0; + border-radius: 4px 0 0 0; +} +.table-bordered thead:first-child tr:first-child th:last-child, .table-bordered tbody:first-child tr:first-child td:last-child { + -webkit-border-radius: 0 4px 0 0; + -moz-border-radius: 0 4px 0 0; + border-radius: 0 4px 0 0; +} +.table-bordered thead:last-child tr:last-child th:first-child, .table-bordered tbody:last-child tr:last-child td:first-child { + -webkit-border-radius: 0 0 0 4px; + -moz-border-radius: 0 0 0 4px; + border-radius: 0 0 0 4px; +} +.table-bordered thead:last-child tr:last-child th:last-child, .table-bordered tbody:last-child tr:last-child td:last-child { + -webkit-border-radius: 0 0 4px 0; + -moz-border-radius: 0 0 4px 0; + border-radius: 0 0 4px 0; +} +.table-striped tbody tr:nth-child(odd) td, .table-striped tbody tr:nth-child(odd) th { + background-color: #f9f9f9; +} +.table tbody tr:hover td, .table tbody tr:hover th { + background-color: #f5f5f5; +} +table .span1 { + float: none; + width: 44px; + margin-left: 0; +} +table .span2 { + float: none; + width: 124px; + margin-left: 0; +} +table .span3 { + float: none; + width: 204px; + margin-left: 0; +} +table .span4 { + float: none; + width: 284px; + margin-left: 0; +} +table .span5 { + float: none; + width: 364px; + margin-left: 0; +} +table .span6 { + float: none; + width: 444px; + margin-left: 0; +} +table .span7 { + float: none; + width: 524px; + margin-left: 0; +} +table .span8 { + float: none; + width: 604px; + margin-left: 0; +} +table .span9 { + float: none; + width: 684px; + margin-left: 0; +} +table .span10 { + float: none; + width: 764px; + margin-left: 0; +} +table .span11 { + float: none; + width: 844px; + margin-left: 0; +} +table .span12 { + float: none; + width: 924px; + margin-left: 0; +} +[class^="icon-"], [class*=" icon-"] { + display: inline-block; + width: 14px; + height: 14px; + line-height: 14px; + vertical-align: text-top; + background-image: url("../img/glyphicons-halflings.png"); + background-position: 14px 14px; + background-repeat: no-repeat; + *margin-right: .3em; +} +[class^="icon-"]:last-child, [class*=" icon-"]:last-child { + *margin-left: 0; +} +.icon-white { + background-image: url("../img/glyphicons-halflings-white.png"); +} +.icon-glass { + background-position: 0 0; +} +.icon-music { + background-position: -24px 0; +} +.icon-search { + background-position: -48px 0; +} +.icon-envelope { + background-position: -72px 0; +} +.icon-heart { + background-position: -96px 0; +} +.icon-star { + background-position: -120px 0; +} +.icon-star-empty { + background-position: -144px 0; +} +.icon-user { + background-position: -168px 0; +} +.icon-film { + background-position: -192px 0; +} +.icon-th-large { + background-position: -216px 0; +} +.icon-th { + background-position: -240px 0; +} +.icon-th-list { + background-position: -264px 0; +} +.icon-ok { + background-position: -288px 0; +} +.icon-remove { + background-position: -312px 0; +} +.icon-zoom-in { + background-position: -336px 0; +} +.icon-zoom-out { + background-position: -360px 0; +} +.icon-off { + background-position: -384px 0; +} +.icon-signal { + background-position: -408px 0; +} +.icon-cog { + background-position: -432px 0; +} +.icon-trash { + background-position: -456px 0; +} +.icon-home { + background-position: 0 -24px; +} +.icon-file { + background-position: -24px -24px; +} +.icon-time { + background-position: -48px -24px; +} +.icon-road { + background-position: -72px -24px; +} +.icon-download-alt { + background-position: -96px -24px; +} +.icon-download { + background-position: -120px -24px; +} +.icon-upload { + background-position: -144px -24px; +} +.icon-inbox { + background-position: -168px -24px; +} +.icon-play-circle { + background-position: -192px -24px; +} +.icon-repeat { + background-position: -216px -24px; +} +.icon-refresh { + background-position: -240px -24px; +} +.icon-list-alt { + background-position: -264px -24px; +} +.icon-lock { + background-position: -287px -24px; +} +.icon-flag { + background-position: -312px -24px; +} +.icon-headphones { + background-position: -336px -24px; +} +.icon-volume-off { + background-position: -360px -24px; +} +.icon-volume-down { + background-position: -384px -24px; +} +.icon-volume-up { + background-position: -408px -24px; +} +.icon-qrcode { + background-position: -432px -24px; +} +.icon-barcode { + background-position: -456px -24px; +} +.icon-tag { + background-position: 0 -48px; +} +.icon-tags { + background-position: -25px -48px; +} +.icon-book { + background-position: -48px -48px; +} +.icon-bookmark { + background-position: -72px -48px; +} +.icon-print { + background-position: -96px -48px; +} +.icon-camera { + background-position: -120px -48px; +} +.icon-font { + background-position: -144px -48px; +} +.icon-bold { + background-position: -167px -48px; +} +.icon-italic { + background-position: -192px -48px; +} +.icon-text-height { + background-position: -216px -48px; +} +.icon-text-width { + background-position: -240px -48px; +} +.icon-align-left { + background-position: -264px -48px; +} +.icon-align-center { + background-position: -288px -48px; +} +.icon-align-right { + background-position: -312px -48px; +} +.icon-align-justify { + background-position: -336px -48px; +} +.icon-list { + background-position: -360px -48px; +} +.icon-indent-left { + background-position: -384px -48px; +} +.icon-indent-right { + background-position: -408px -48px; +} +.icon-facetime-video { + background-position: -432px -48px; +} +.icon-picture { + background-position: -456px -48px; +} +.icon-pencil { + background-position: 0 -72px; +} +.icon-map-marker { + background-position: -24px -72px; +} +.icon-adjust { + background-position: -48px -72px; +} +.icon-tint { + background-position: -72px -72px; +} +.icon-edit { + background-position: -96px -72px; +} +.icon-share { + background-position: -120px -72px; +} +.icon-check { + background-position: -144px -72px; +} +.icon-move { + background-position: -168px -72px; +} +.icon-step-backward { + background-position: -192px -72px; +} +.icon-fast-backward { + background-position: -216px -72px; +} +.icon-backward { + background-position: -240px -72px; +} +.icon-play { + background-position: -264px -72px; +} +.icon-pause { + background-position: -288px -72px; +} +.icon-stop { + background-position: -312px -72px; +} +.icon-forward { + background-position: -336px -72px; +} +.icon-fast-forward { + background-position: -360px -72px; +} +.icon-step-forward { + background-position: -384px -72px; +} +.icon-eject { + background-position: -408px -72px; +} +.icon-chevron-left { + background-position: -432px -72px; +} +.icon-chevron-right { + background-position: -456px -72px; +} +.icon-plus-sign { + background-position: 0 -96px; +} +.icon-minus-sign { + background-position: -24px -96px; +} +.icon-remove-sign { + background-position: -48px -96px; +} +.icon-ok-sign { + background-position: -72px -96px; +} +.icon-question-sign { + background-position: -96px -96px; +} +.icon-info-sign { + background-position: -120px -96px; +} +.icon-screenshot { + background-position: -144px -96px; +} +.icon-remove-circle { + background-position: -168px -96px; +} +.icon-ok-circle { + background-position: -192px -96px; +} +.icon-ban-circle { + background-position: -216px -96px; +} +.icon-arrow-left { + background-position: -240px -96px; +} +.icon-arrow-right { + background-position: -264px -96px; +} +.icon-arrow-up { + background-position: -289px -96px; +} +.icon-arrow-down { + background-position: -312px -96px; +} +.icon-share-alt { + background-position: -336px -96px; +} +.icon-resize-full { + background-position: -360px -96px; +} +.icon-resize-small { + background-position: -384px -96px; +} +.icon-plus { + background-position: -408px -96px; +} +.icon-minus { + background-position: -433px -96px; +} +.icon-asterisk { + background-position: -456px -96px; +} +.icon-exclamation-sign { + background-position: 0 -120px; +} +.icon-gift { + background-position: -24px -120px; +} +.icon-leaf { + background-position: -48px -120px; +} +.icon-fire { + background-position: -72px -120px; +} +.icon-eye-open { + background-position: -96px -120px; +} +.icon-eye-close { + background-position: -120px -120px; +} +.icon-warning-sign { + background-position: -144px -120px; +} +.icon-plane { + background-position: -168px -120px; +} +.icon-calendar { + background-position: -192px -120px; +} +.icon-random { + background-position: -216px -120px; +} +.icon-comment { + background-position: -240px -120px; +} +.icon-magnet { + background-position: -264px -120px; +} +.icon-chevron-up { + background-position: -288px -120px; +} +.icon-chevron-down { + background-position: -313px -119px; +} +.icon-retweet { + background-position: -336px -120px; +} +.icon-shopping-cart { + background-position: -360px -120px; +} +.icon-folder-close { + background-position: -384px -120px; +} +.icon-folder-open { + background-position: -408px -120px; +} +.icon-resize-vertical { + background-position: -432px -119px; +} +.icon-resize-horizontal { + background-position: -456px -118px; +} +.dropdown { + position: relative; +} +.dropdown-toggle { + *margin-bottom: -3px; +} +.dropdown-toggle:active, .open .dropdown-toggle { + outline: 0; +} +.caret { + display: inline-block; + width: 0; + height: 0; + text-indent: -99999px; + *text-indent: 0; + vertical-align: top; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 4px solid #000000; + opacity: 0.3; + filter: alpha(opacity=30); + content: "\2193"; +} +.dropdown .caret { + margin-top: 8px; + margin-left: 2px; +} +.dropdown:hover .caret, .open.dropdown .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + float: left; + display: none; + min-width: 160px; + _width: 160px; + padding: 4px 0; + margin: 0; + list-style: none; + background-color: #ffffff; + border-color: #ccc; + border-color: rgba(0, 0, 0, 0.2); + border-style: solid; + border-width: 1px; + -webkit-border-radius: 0 0 5px 5px; + -moz-border-radius: 0 0 5px 5px; + border-radius: 0 0 5px 5px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; + *border-right-width: 2px; + *border-bottom-width: 2px; +} +.dropdown-menu.bottom-up { + top: auto; + bottom: 100%; + margin-bottom: 2px; +} +.dropdown-menu .divider { + height: 1px; + margin: 5px 1px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #ffffff; + *width: 100%; + *margin: -5px 0 5px; +} +.dropdown-menu a { + display: block; + padding: 3px 15px; + clear: both; + font-weight: normal; + line-height: 18px; + color: #555555; + white-space: nowrap; +} +.dropdown-menu li > a:hover, .dropdown-menu .active > a, .dropdown-menu .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #0088cc; +} +.dropdown.open { + *z-index: 1000; +} +.dropdown.open .dropdown-toggle { + color: #ffffff; + background: #ccc; + background: rgba(0, 0, 0, 0.3); +} +.dropdown.open .dropdown-menu { + display: block; +} +.typeahead { + margin-top: 2px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #f5f5f5; + border: 1px solid #eee; + border: 1px solid rgba(0, 0, 0, 0.05); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 0, 0, 0.15); +} +.fade { + -webkit-transition: opacity 0.15s linear; + -moz-transition: opacity 0.15s linear; + -ms-transition: opacity 0.15s linear; + -o-transition: opacity 0.15s linear; + transition: opacity 0.15s linear; + opacity: 0; +} +.fade.in { + opacity: 1; +} +.collapse { + -webkit-transition: height 0.35s ease; + -moz-transition: height 0.35s ease; + -ms-transition: height 0.35s ease; + -o-transition: height 0.35s ease; + transition: height 0.35s ease; + position: relative; + overflow: hidden; + height: 0; +} +.collapse.in { + height: auto; +} +.close { + float: right; + font-size: 20px; + font-weight: bold; + line-height: 18px; + color: #000000; + text-shadow: 0 1px 0 #ffffff; + opacity: 0.2; + filter: alpha(opacity=20); +} +.close:hover { + color: #000000; + text-decoration: none; + opacity: 0.4; + filter: alpha(opacity=40); + cursor: pointer; +} +.btn { + display: inline-block; + padding: 4px 10px 4px; + margin-bottom: 0; + font-size: 13px; + line-height: 18px; + color: #333333; + text-align: center; + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); + vertical-align: middle; + background-color: #f5f5f5; + background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); + background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); + background-image: linear-gradient(top, #ffffff, #e6e6e6); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0); + border-color: #e6e6e6 #e6e6e6 #bfbfbf; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + border: 1px solid #ccc; + border-bottom-color: #bbb; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + cursor: pointer; + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + *margin-left: .3em; +} +.btn:hover, +.btn:active, +.btn.active, +.btn.disabled, +.btn[disabled] { + background-color: #e6e6e6; +} +.btn:active, .btn.active { + background-color: #cccccc \9; +} +.btn:first-child { + *margin-left: 0; +} +.btn:hover { + color: #333333; + text-decoration: none; + background-color: #e6e6e6; + background-position: 0 -15px; + -webkit-transition: background-position 0.1s linear; + -moz-transition: background-position 0.1s linear; + -ms-transition: background-position 0.1s linear; + -o-transition: background-position 0.1s linear; + transition: background-position 0.1s linear; +} +.btn:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.btn.active, .btn:active { + background-image: none; + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + background-color: #e6e6e6; + background-color: #d9d9d9 \9; + outline: 0; +} +.btn.disabled, .btn[disabled] { + cursor: default; + background-image: none; + background-color: #e6e6e6; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +.btn-large { + padding: 9px 14px; + font-size: 15px; + line-height: normal; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.btn-large [class^="icon-"] { + margin-top: 1px; +} +.btn-small { + padding: 5px 9px; + font-size: 11px; + line-height: 16px; +} +.btn-small [class^="icon-"] { + margin-top: -1px; +} +.btn-mini { + padding: 2px 6px; + font-size: 11px; + line-height: 14px; +} +.btn-primary, +.btn-primary:hover, +.btn-warning, +.btn-warning:hover, +.btn-danger, +.btn-danger:hover, +.btn-success, +.btn-success:hover, +.btn-info, +.btn-info:hover, +.btn-inverse, +.btn-inverse:hover { + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + color: #ffffff; +} +.btn-primary.active, +.btn-warning.active, +.btn-danger.active, +.btn-success.active, +.btn-info.active, +.btn-dark.active { + color: rgba(255, 255, 255, 0.75); +} +.btn-primary { + background-color: #006dcc; + background-image: -moz-linear-gradient(top, #0088cc, #0044cc); + background-image: -ms-linear-gradient(top, #0088cc, #0044cc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); + background-image: -o-linear-gradient(top, #0088cc, #0044cc); + background-image: linear-gradient(top, #0088cc, #0044cc); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); + border-color: #0044cc #0044cc #002a80; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-primary:hover, +.btn-primary:active, +.btn-primary.active, +.btn-primary.disabled, +.btn-primary[disabled] { + background-color: #0044cc; +} +.btn-primary:active, .btn-primary.active { + background-color: #003399 \9; +} +.btn-warning { + background-color: #faa732; + background-image: -moz-linear-gradient(top, #fbb450, #f89406); + background-image: -ms-linear-gradient(top, #fbb450, #f89406); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); + background-image: -webkit-linear-gradient(top, #fbb450, #f89406); + background-image: -o-linear-gradient(top, #fbb450, #f89406); + background-image: linear-gradient(top, #fbb450, #f89406); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0); + border-color: #f89406 #f89406 #ad6704; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-warning:hover, +.btn-warning:active, +.btn-warning.active, +.btn-warning.disabled, +.btn-warning[disabled] { + background-color: #f89406; +} +.btn-warning:active, .btn-warning.active { + background-color: #c67605 \9; +} +.btn-danger { + background-color: #da4f49; + background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -ms-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -o-linear-gradient(top, #ee5f5b, #bd362f); + background-image: linear-gradient(top, #ee5f5b, #bd362f); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0); + border-color: #bd362f #bd362f #802420; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-danger:hover, +.btn-danger:active, +.btn-danger.active, +.btn-danger.disabled, +.btn-danger[disabled] { + background-color: #bd362f; +} +.btn-danger:active, .btn-danger.active { + background-color: #942a25 \9; +} +.btn-success { + background-color: #5bb75b; + background-image: -moz-linear-gradient(top, #62c462, #51a351); + background-image: -ms-linear-gradient(top, #62c462, #51a351); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351)); + background-image: -webkit-linear-gradient(top, #62c462, #51a351); + background-image: -o-linear-gradient(top, #62c462, #51a351); + background-image: linear-gradient(top, #62c462, #51a351); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0); + border-color: #51a351 #51a351 #387038; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-success:hover, +.btn-success:active, +.btn-success.active, +.btn-success.disabled, +.btn-success[disabled] { + background-color: #51a351; +} +.btn-success:active, .btn-success.active { + background-color: #408140 \9; +} +.btn-info { + background-color: #49afcd; + background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -ms-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4)); + background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -o-linear-gradient(top, #5bc0de, #2f96b4); + background-image: linear-gradient(top, #5bc0de, #2f96b4); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0); + border-color: #2f96b4 #2f96b4 #1f6377; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-info:hover, +.btn-info:active, +.btn-info.active, +.btn-info.disabled, +.btn-info[disabled] { + background-color: #2f96b4; +} +.btn-info:active, .btn-info.active { + background-color: #24748c \9; +} +.btn-inverse { + background-color: #393939; + background-image: -moz-linear-gradient(top, #454545, #262626); + background-image: -ms-linear-gradient(top, #454545, #262626); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#454545), to(#262626)); + background-image: -webkit-linear-gradient(top, #454545, #262626); + background-image: -o-linear-gradient(top, #454545, #262626); + background-image: linear-gradient(top, #454545, #262626); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#454545', endColorstr='#262626', GradientType=0); + border-color: #262626 #262626 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.btn-inverse:hover, +.btn-inverse:active, +.btn-inverse.active, +.btn-inverse.disabled, +.btn-inverse[disabled] { + background-color: #262626; +} +.btn-inverse:active, .btn-inverse.active { + background-color: #0c0c0c \9; +} +button.btn, input[type="submit"].btn { + *padding-top: 2px; + *padding-bottom: 2px; +} +button.btn::-moz-focus-inner, input[type="submit"].btn::-moz-focus-inner { + padding: 0; + border: 0; +} +button.btn.large, input[type="submit"].btn.large { + *padding-top: 7px; + *padding-bottom: 7px; +} +button.btn.small, input[type="submit"].btn.small { + *padding-top: 3px; + *padding-bottom: 3px; +} +.btn-group { + position: relative; + *zoom: 1; + *margin-left: .3em; +} +.btn-group:before, .btn-group:after { + display: table; + content: ""; +} +.btn-group:after { + clear: both; +} +.btn-group:first-child { + *margin-left: 0; +} +.btn-group + .btn-group { + margin-left: 5px; +} +.btn-toolbar { + margin-top: 9px; + margin-bottom: 9px; +} +.btn-toolbar .btn-group { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; +} +.btn-group .btn { + position: relative; + float: left; + margin-left: -1px; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.btn-group .btn:first-child { + margin-left: 0; + -webkit-border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; + border-top-left-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + border-bottom-left-radius: 4px; +} +.btn-group .btn:last-child, .btn-group .dropdown-toggle { + -webkit-border-top-right-radius: 4px; + -moz-border-radius-topright: 4px; + border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -moz-border-radius-bottomright: 4px; + border-bottom-right-radius: 4px; +} +.btn-group .btn.large:first-child { + margin-left: 0; + -webkit-border-top-left-radius: 6px; + -moz-border-radius-topleft: 6px; + border-top-left-radius: 6px; + -webkit-border-bottom-left-radius: 6px; + -moz-border-radius-bottomleft: 6px; + border-bottom-left-radius: 6px; +} +.btn-group .btn.large:last-child, .btn-group .large.dropdown-toggle { + -webkit-border-top-right-radius: 6px; + -moz-border-radius-topright: 6px; + border-top-right-radius: 6px; + -webkit-border-bottom-right-radius: 6px; + -moz-border-radius-bottomright: 6px; + border-bottom-right-radius: 6px; +} +.btn-group .btn:hover, +.btn-group .btn:focus, +.btn-group .btn:active, +.btn-group .btn.active { + z-index: 2; +} +.btn-group .dropdown-toggle:active, .btn-group.open .dropdown-toggle { + outline: 0; +} +.btn-group .dropdown-toggle { + padding-left: 8px; + padding-right: 8px; + -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + *padding-top: 5px; + *padding-bottom: 5px; +} +.btn-group.open { + *z-index: 1000; +} +.btn-group.open .dropdown-menu { + display: block; + margin-top: 1px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.btn-group.open .dropdown-toggle { + background-image: none; + -webkit-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); +} +.btn .caret { + margin-top: 7px; + margin-left: 0; +} +.btn:hover .caret, .open.btn-group .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.btn-primary .caret, +.btn-danger .caret, +.btn-info .caret, +.btn-success .caret, +.btn-inverse .caret { + border-top-color: #ffffff; + opacity: 0.75; + filter: alpha(opacity=75); +} +.btn-small .caret { + margin-top: 4px; +} +.alert { + padding: 8px 35px 8px 14px; + margin-bottom: 18px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + background-color: #fcf8e3; + border: 1px solid #fbeed5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.alert, .alert-heading { + color: #c09853; +} +.alert .close { + position: relative; + top: -2px; + right: -21px; + line-height: 18px; +} +.alert-success { + background-color: #dff0d8; + border-color: #d6e9c6; +} +.alert-success, .alert-success .alert-heading { + color: #468847; +} +.alert-danger, .alert-error { + background-color: #f2dede; + border-color: #eed3d7; +} +.alert-danger, +.alert-error, +.alert-danger .alert-heading, +.alert-error .alert-heading { + color: #b94a48; +} +.alert-info { + background-color: #d9edf7; + border-color: #bce8f1; +} +.alert-info, .alert-info .alert-heading { + color: #3a87ad; +} +.alert-block { + padding-top: 14px; + padding-bottom: 14px; +} +.alert-block > p, .alert-block > ul { + margin-bottom: 0; +} +.alert-block p + p { + margin-top: 5px; +} +.nav { + margin-left: 0; + margin-bottom: 18px; + list-style: none; +} +.nav > li > a { + display: block; +} +.nav > li > a:hover { + text-decoration: none; + background-color: #eeeeee; +} +.nav .nav-header { + display: block; + padding: 3px 15px; + font-size: 11px; + font-weight: bold; + line-height: 18px; + color: #999999; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + text-transform: uppercase; +} +.nav li + .nav-header { + margin-top: 9px; +} +.nav-list { + padding-left: 14px; + padding-right: 14px; + margin-bottom: 0; +} +.nav-list > li > a, .nav-list .nav-header { + margin-left: -15px; + margin-right: -15px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); +} +.nav-list > li > a { + padding: 3px 15px; +} +.nav-list .active > a, .nav-list .active > a:hover { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); + background-color: #0088cc; +} +.nav-list [class^="icon-"] { + margin-right: 2px; +} +.nav-tabs, .nav-pills { + *zoom: 1; +} +.nav-tabs:before, +.nav-pills:before, +.nav-tabs:after, +.nav-pills:after { + display: table; + content: ""; +} +.nav-tabs:after, .nav-pills:after { + clear: both; +} +.nav-tabs > li, .nav-pills > li { + float: left; +} +.nav-tabs > li > a, .nav-pills > li > a { + padding-right: 12px; + padding-left: 12px; + margin-right: 2px; + line-height: 14px; +} +.nav-tabs { + border-bottom: 1px solid #ddd; +} +.nav-tabs > li { + margin-bottom: -1px; +} +.nav-tabs > li > a { + padding-top: 9px; + padding-bottom: 9px; + border: 1px solid transparent; + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} +.nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #dddddd; +} +.nav-tabs > .active > a, .nav-tabs > .active > a:hover { + color: #555555; + background-color: #ffffff; + border: 1px solid #ddd; + border-bottom-color: transparent; + cursor: default; +} +.nav-pills > li > a { + padding-top: 8px; + padding-bottom: 8px; + margin-top: 2px; + margin-bottom: 2px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.nav-pills .active > a, .nav-pills .active > a:hover { + color: #ffffff; + background-color: #0088cc; +} +.nav-stacked > li { + float: none; +} +.nav-stacked > li > a { + margin-right: 0; +} +.nav-tabs.nav-stacked { + border-bottom: 0; +} +.nav-tabs.nav-stacked > li > a { + border: 1px solid #ddd; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.nav-tabs.nav-stacked > li:first-child > a { + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} +.nav-tabs.nav-stacked > li:last-child > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} +.nav-tabs.nav-stacked > li > a:hover { + border-color: #ddd; + z-index: 2; +} +.nav-pills.nav-stacked > li > a { + margin-bottom: 3px; +} +.nav-pills.nav-stacked > li:last-child > a { + margin-bottom: 1px; +} +.nav-tabs .dropdown-menu, .nav-pills .dropdown-menu { + margin-top: 1px; + border-width: 1px; +} +.nav-pills .dropdown-menu { + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.nav-tabs .dropdown-toggle .caret, .nav-pills .dropdown-toggle .caret { + border-top-color: #0088cc; + margin-top: 6px; +} +.nav-tabs .dropdown-toggle:hover .caret, .nav-pills .dropdown-toggle:hover .caret { + border-top-color: #005580; +} +.nav-tabs .active .dropdown-toggle .caret, .nav-pills .active .dropdown-toggle .caret { + border-top-color: #333333; +} +.nav > .dropdown.active > a:hover { + color: #000000; + cursor: pointer; +} +.nav-tabs .open .dropdown-toggle, .nav-pills .open .dropdown-toggle, .nav > .open.active > a:hover { + color: #ffffff; + background-color: #999999; + border-color: #999999; +} +.nav .open .caret, .nav .open.active .caret, .nav .open a:hover .caret { + border-top-color: #ffffff; + opacity: 1; + filter: alpha(opacity=100); +} +.tabs-stacked .open > a:hover { + border-color: #999999; +} +.tabbable { + *zoom: 1; +} +.tabbable:before, .tabbable:after { + display: table; + content: ""; +} +.tabbable:after { + clear: both; +} +.tab-content { + overflow: hidden; +} +.tabs-below .nav-tabs, .tabs-right .nav-tabs, .tabs-left .nav-tabs { + border-bottom: 0; +} +.tab-content > .tab-pane, .pill-content > .pill-pane { + display: none; +} +.tab-content > .active, .pill-content > .active { + display: block; +} +.tabs-below .nav-tabs { + border-top: 1px solid #ddd; +} +.tabs-below .nav-tabs > li { + margin-top: -1px; + margin-bottom: 0; +} +.tabs-below .nav-tabs > li > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} +.tabs-below .nav-tabs > li > a:hover { + border-bottom-color: transparent; + border-top-color: #ddd; +} +.tabs-below .nav-tabs .active > a, .tabs-below .nav-tabs .active > a:hover { + border-color: transparent #ddd #ddd #ddd; +} +.tabs-left .nav-tabs > li, .tabs-right .nav-tabs > li { + float: none; +} +.tabs-left .nav-tabs > li > a, .tabs-right .nav-tabs > li > a { + min-width: 74px; + margin-right: 0; + margin-bottom: 3px; +} +.tabs-left .nav-tabs { + float: left; + margin-right: 19px; + border-right: 1px solid #ddd; +} +.tabs-left .nav-tabs > li > a { + margin-right: -1px; + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} +.tabs-left .nav-tabs > li > a:hover { + border-color: #eeeeee #dddddd #eeeeee #eeeeee; +} +.tabs-left .nav-tabs .active > a, .tabs-left .nav-tabs .active > a:hover { + border-color: #ddd transparent #ddd #ddd; + *border-right-color: #ffffff; +} +.tabs-right .nav-tabs { + float: right; + margin-left: 19px; + border-left: 1px solid #ddd; +} +.tabs-right .nav-tabs > li > a { + margin-left: -1px; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} +.tabs-right .nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #eeeeee #dddddd; +} +.tabs-right .nav-tabs .active > a, .tabs-right .nav-tabs .active > a:hover { + border-color: #ddd #ddd #ddd transparent; + *border-left-color: #ffffff; +} +.navbar { + overflow: visible; + margin-bottom: 18px; +} +.navbar-inner { + padding-left: 20px; + padding-right: 20px; + background-color: #2c2c2c; + background-image: -moz-linear-gradient(top, #333333, #222222); + background-image: -ms-linear-gradient(top, #333333, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); + background-image: -webkit-linear-gradient(top, #333333, #222222); + background-image: -o-linear-gradient(top, #333333, #222222); + background-image: linear-gradient(top, #333333, #222222); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); +} +.btn-navbar { + display: none; + float: right; + padding: 7px 10px; + margin-left: 5px; + margin-right: 5px; + background-color: #2c2c2c; + background-image: -moz-linear-gradient(top, #333333, #222222); + background-image: -ms-linear-gradient(top, #333333, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); + background-image: -webkit-linear-gradient(top, #333333, #222222); + background-image: -o-linear-gradient(top, #333333, #222222); + background-image: linear-gradient(top, #333333, #222222); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); + border-color: #222222 #222222 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); +} +.btn-navbar:hover, +.btn-navbar:active, +.btn-navbar.active, +.btn-navbar.disabled, +.btn-navbar[disabled] { + background-color: #222222; +} +.btn-navbar:active, .btn-navbar.active { + background-color: #080808 \9; +} +.btn-navbar .icon-bar { + display: block; + width: 18px; + height: 2px; + background-color: #f5f5f5; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; + -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); +} +.btn-navbar .icon-bar + .icon-bar { + margin-top: 3px; +} +.nav-collapse.collapse { + height: auto; +} +.navbar .brand:hover { + text-decoration: none; +} +.navbar .brand { + float: left; + display: block; + padding: 8px 20px 12px; + margin-left: -20px; + font-size: 20px; + font-weight: 200; + line-height: 1; + color: #ffffff; +} +.navbar .navbar-text { + margin-bottom: 0; + line-height: 40px; + color: #999999; +} +.navbar .navbar-text a:hover { + color: #ffffff; + background-color: transparent; +} +.navbar .btn, .navbar .btn-group { + margin-top: 5px; +} +.navbar .btn-group .btn { + margin-top: 0; +} +.navbar-form { + margin-bottom: 0; + *zoom: 1; +} +.navbar-form:before, .navbar-form:after { + display: table; + content: ""; +} +.navbar-form:after { + clear: both; +} +.navbar-form input, .navbar-form select { + display: inline-block; + margin-top: 5px; + margin-bottom: 0; +} +.navbar-form .radio, .navbar-form .checkbox { + margin-top: 5px; +} +.navbar-form input[type="image"], .navbar-form input[type="checkbox"], .navbar-form input[type="radio"] { + margin-top: 3px; +} +.navbar-form .input-append, .navbar-form .input-prepend { + margin-top: 6px; + white-space: nowrap; +} +.navbar-form .input-append input, .navbar-form .input-prepend input { + margin-top: 0; +} +.navbar-search { + position: relative; + float: left; + margin-top: 6px; + margin-bottom: 0; +} +.navbar-search .search-query { + padding: 4px 9px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + font-weight: normal; + line-height: 1; + color: #ffffff; + color: rgba(255, 255, 255, 0.75); + background: #666; + background: rgba(255, 255, 255, 0.3); + border: 1px solid #111; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15); + -webkit-transition: none; + -moz-transition: none; + -ms-transition: none; + -o-transition: none; + transition: none; +} +.navbar-search .search-query :-moz-placeholder { + color: #eeeeee; +} +.navbar-search .search-query::-webkit-input-placeholder { + color: #eeeeee; +} +.navbar-search .search-query:hover { + color: #ffffff; + background-color: #999999; + background-color: rgba(255, 255, 255, 0.5); +} +.navbar-search .search-query:focus, .navbar-search .search-query.focused { + padding: 5px 10px; + color: #333333; + text-shadow: 0 1px 0 #ffffff; + background-color: #ffffff; + border: 0; + -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + outline: 0; +} +.navbar-fixed-top { + position: fixed; + top: 0; + right: 0; + left: 0; + z-index: 1030; +} +.navbar-fixed-top .navbar-inner { + padding-left: 0; + padding-right: 0; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.navbar .nav { + position: relative; + left: 0; + display: block; + float: left; + margin: 0 10px 0 0; +} +.navbar .nav.pull-right { + float: right; +} +.navbar .nav > li { + display: block; + float: left; +} +.navbar .nav > li > a { + float: none; + padding: 10px 10px 11px; + line-height: 19px; + color: #999999; + text-decoration: none; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.navbar .nav > li > a:hover { + background-color: transparent; + color: #ffffff; + text-decoration: none; +} +.navbar .nav .active > a, .navbar .nav .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #222222; +} +.navbar .divider-vertical { + height: 40px; + width: 1px; + margin: 0 9px; + overflow: hidden; + background-color: #222222; + border-right: 1px solid #333333; +} +.navbar .nav.pull-right { + margin-left: 10px; + margin-right: 0; +} +.navbar .dropdown-menu { + margin-top: 1px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.navbar .dropdown-menu:before { + content: ''; + display: inline-block; + border-left: 7px solid transparent; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-bottom-color: rgba(0, 0, 0, 0.2); + position: absolute; + top: -7px; + left: 9px; +} +.navbar .dropdown-menu:after { + content: ''; + display: inline-block; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid #ffffff; + position: absolute; + top: -6px; + left: 10px; +} +.navbar .nav .dropdown-toggle .caret, .navbar .nav .open.dropdown .caret { + border-top-color: #ffffff; +} +.navbar .nav .active .caret { + opacity: 1; + filter: alpha(opacity=100); +} +.navbar .nav .open > .dropdown-toggle, .navbar .nav .active > .dropdown-toggle, .navbar .nav .open.active > .dropdown-toggle { + background-color: transparent; +} +.navbar .nav .active > .dropdown-toggle:hover { + color: #ffffff; +} +.navbar .nav.pull-right .dropdown-menu { + left: auto; + right: 0; +} +.navbar .nav.pull-right .dropdown-menu:before { + left: auto; + right: 12px; +} +.navbar .nav.pull-right .dropdown-menu:after { + left: auto; + right: 13px; +} +.breadcrumb { + padding: 7px 14px; + margin: 0 0 18px; + background-color: #fbfbfb; + background-image: -moz-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -ms-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5)); + background-image: -webkit-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -o-linear-gradient(top, #ffffff, #f5f5f5); + background-image: linear-gradient(top, #ffffff, #f5f5f5); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0); + border: 1px solid #ddd; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; +} +.breadcrumb li { + display: inline-block; + text-shadow: 0 1px 0 #ffffff; +} +.breadcrumb .divider { + padding: 0 5px; + color: #999999; +} +.breadcrumb .active a { + color: #333333; +} +.pagination { + height: 36px; + margin: 18px 0; +} +.pagination ul { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; + margin-left: 0; + margin-bottom: 0; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); +} +.pagination li { + display: inline; +} +.pagination a { + float: left; + padding: 0 14px; + line-height: 34px; + text-decoration: none; + border: 1px solid #ddd; + border-left-width: 0; +} +.pagination a:hover, .pagination .active a { + background-color: #f5f5f5; +} +.pagination .active a { + color: #999999; + cursor: default; +} +.pagination .disabled a, .pagination .disabled a:hover { + color: #999999; + background-color: transparent; + cursor: default; +} +.pagination li:first-child a { + border-left-width: 1px; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} +.pagination li:last-child a { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} +.pagination-centered { + text-align: center; +} +.pagination-right { + text-align: right; +} +.pager { + margin-left: 0; + margin-bottom: 18px; + list-style: none; + text-align: center; + *zoom: 1; +} +.pager:before, .pager:after { + display: table; + content: ""; +} +.pager:after { + clear: both; +} +.pager li { + display: inline; +} +.pager a { + display: inline-block; + padding: 5px 14px; + background-color: #fff; + border: 1px solid #ddd; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} +.pager a:hover { + text-decoration: none; + background-color: #f5f5f5; +} +.pager .next a { + float: right; +} +.pager .previous a { + float: left; +} +.modal-open .dropdown-menu { + z-index: 2050; +} +.modal-open .dropdown.open { + *z-index: 2050; +} +.modal-open .popover { + z-index: 2060; +} +.modal-open .tooltip { + z-index: 2070; +} +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + background-color: #000000; +} +.modal-backdrop.fade { + opacity: 0; +} +.modal-backdrop, .modal-backdrop.fade.in { + opacity: 0.8; + filter: alpha(opacity=80); +} +.modal { + position: fixed; + top: 50%; + left: 50%; + z-index: 1050; + max-height: 500px; + overflow: auto; + width: 560px; + margin: -250px 0 0 -280px; + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + /* IE6-7 */ + + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.wide-modal { + position: fixed; + top: 5%; + left: 5%; + z-index: 1050; + max-height: 90%; + overflow: auto; + width: 90%; + /*margin: -50px 0 0 -80px;*/ + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + /* IE6-7 */ + + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.modal.fade { + -webkit-transition: opacity .3s linear, top .3s ease-out; + -moz-transition: opacity .3s linear, top .3s ease-out; + -ms-transition: opacity .3s linear, top .3s ease-out; + -o-transition: opacity .3s linear, top .3s ease-out; + transition: opacity .3s linear, top .3s ease-out; + top: -25%; +} +.modal.fade.in { + top: 50%; +} +.modal-header { + padding: 9px 15px; + border-bottom: 1px solid #eee; +} +.modal-header .close { + margin-top: 2px; +} +.modal-body { + padding: 15px; +} +.modal-body .modal-form { + margin-bottom: 0; +} +.modal-footer { + padding: 14px 15px 15px; + margin-bottom: 0; + background-color: #f5f5f5; + border-top: 1px solid #ddd; + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; + *zoom: 1; +} +.modal-footer:before, .modal-footer:after { + display: table; + content: ""; +} +.modal-footer:after { + clear: both; +} +.modal-footer .btn { + float: right; + margin-left: 5px; + margin-bottom: 0; +} +.tooltip { + position: absolute; + z-index: 1020; + display: block; + visibility: visible; + padding: 5px; + font-size: 11px; + opacity: 0; + filter: alpha(opacity=0); +} +.tooltip.in { + opacity: 0.8; + filter: alpha(opacity=80); +} +.tooltip.top { + margin-top: -2px; +} +.tooltip.right { + margin-left: 2px; +} +.tooltip.bottom { + margin-top: 2px; +} +.tooltip.left { + margin-left: -2px; +} +.tooltip.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid #000000; +} +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #000000; +} +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-bottom: 5px solid #000000; +} +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-right: 5px solid #000000; +} +.tooltip-inner { + max-width: 200px; + padding: 3px 8px; + color: #ffffff; + text-align: center; + text-decoration: none; + background-color: #000000; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; +} +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1010; + display: none; + padding: 5px; +} +.popover.top { + margin-top: -5px; +} +.popover.right { + margin-left: 5px; +} +.popover.bottom { + margin-top: 5px; +} +.popover.left { + margin-left: -5px; +} +.popover.top .arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid #000000; +} +.popover.right .arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-right: 5px solid #000000; +} +.popover.bottom .arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-bottom: 5px solid #000000; +} +.popover.left .arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #000000; +} +.popover .arrow { + position: absolute; + width: 0; + height: 0; +} +.popover-inner { + padding: 3px; + width: 280px; + overflow: hidden; + background: #000000; + background: rgba(0, 0, 0, 0.8); + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); +} +.popover-title { + padding: 9px 15px; + line-height: 1; + background-color: #f5f5f5; + border-bottom: 1px solid #eee; + -webkit-border-radius: 3px 3px 0 0; + -moz-border-radius: 3px 3px 0 0; + border-radius: 3px 3px 0 0; +} +.popover-content { + padding: 14px; + background-color: #ffffff; + -webkit-border-radius: 0 0 3px 3px; + -moz-border-radius: 0 0 3px 3px; + border-radius: 0 0 3px 3px; + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} +.popover-content p, .popover-content ul, .popover-content ol { + margin-bottom: 0; +} +.thumbnails { + margin-left: -20px; + list-style: none; + *zoom: 1; +} +.thumbnails:before, .thumbnails:after { + display: table; + content: ""; +} +.thumbnails:after { + clear: both; +} +.thumbnails > li { + float: left; + margin: 0 0 18px 20px; +} +.thumbnail { + display: block; + padding: 4px; + line-height: 1; + border: 1px solid #ddd; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); +} +a.thumbnail:hover { + border-color: #0088cc; + -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); +} +.thumbnail > img { + display: block; + max-width: 100%; + margin-left: auto; + margin-right: auto; +} +.thumbnail .caption { + padding: 9px; +} +.label { + padding: 2px 4px 3px; + font-size: 11.049999999999999px; + font-weight: bold; + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #999999; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.label:hover { + color: #ffffff; + text-decoration: none; +} +.label-important { + background-color: #b94a48; +} +.label-important:hover { + background-color: #953b39; +} +.label-warning { + background-color: #f89406; +} +.label-warning:hover { + background-color: #c67605; +} +.label-success { + background-color: #468847; +} +.label-success:hover { + background-color: #356635; +} +.label-info { + background-color: #3a87ad; +} +.label-info:hover { + background-color: #2d6987; +} +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +@-moz-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +@keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} +.progress { + overflow: hidden; + height: 18px; + margin-bottom: 18px; + background-color: #f7f7f7; + background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -ms-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9)); + background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: linear-gradient(top, #f5f5f5, #f9f9f9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0); + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.progress .bar { + width: 0%; + height: 18px; + color: #ffffff; + font-size: 12px; + text-align: center; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #0e90d2; + background-image: -moz-linear-gradient(top, #149bdf, #0480be); + background-image: -ms-linear-gradient(top, #149bdf, #0480be); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be)); + background-image: -webkit-linear-gradient(top, #149bdf, #0480be); + background-image: -o-linear-gradient(top, #149bdf, #0480be); + background-image: linear-gradient(top, #149bdf, #0480be); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0); + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition: width 0.6s ease; + -moz-transition: width 0.6s ease; + -ms-transition: width 0.6s ease; + -o-transition: width 0.6s ease; + transition: width 0.6s ease; +} +.progress-striped .bar { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + -webkit-background-size: 40px 40px; + -moz-background-size: 40px 40px; + -o-background-size: 40px 40px; + background-size: 40px 40px; +} +.progress.active .bar { + -webkit-animation: progress-bar-stripes 2s linear infinite; + -moz-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} +.progress-danger .bar { + background-color: #dd514c; + background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -o-linear-gradient(top, #ee5f5b, #c43c35); + background-image: linear-gradient(top, #ee5f5b, #c43c35); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0); +} +.progress-danger.progress-striped .bar { + background-color: #ee5f5b; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-success .bar { + background-color: #5eb95e; + background-image: -moz-linear-gradient(top, #62c462, #57a957); + background-image: -ms-linear-gradient(top, #62c462, #57a957); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957)); + background-image: -webkit-linear-gradient(top, #62c462, #57a957); + background-image: -o-linear-gradient(top, #62c462, #57a957); + background-image: linear-gradient(top, #62c462, #57a957); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0); +} +.progress-success.progress-striped .bar { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-info .bar { + background-color: #4bb1cf; + background-image: -moz-linear-gradient(top, #5bc0de, #339bb9); + background-image: -ms-linear-gradient(top, #5bc0de, #339bb9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9)); + background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9); + background-image: -o-linear-gradient(top, #5bc0de, #339bb9); + background-image: linear-gradient(top, #5bc0de, #339bb9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0); +} +.progress-info.progress-striped .bar { + background-color: #5bc0de; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.accordion { + margin-bottom: 18px; +} +.accordion-group { + margin-bottom: 2px; + border: 1px solid #e5e5e5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.accordion-heading { + border-bottom: 0; +} +.accordion-heading .accordion-toggle { + display: block; + padding: 8px 15px; +} +.accordion-inner { + padding: 9px 15px; + border-top: 1px solid #e5e5e5; +} +.carousel { + position: relative; + margin-bottom: 18px; + line-height: 1; +} +.carousel-inner { + overflow: hidden; + width: 100%; + position: relative; +} +.carousel .item { + display: none; + position: relative; + -webkit-transition: 0.6s ease-in-out left; + -moz-transition: 0.6s ease-in-out left; + -ms-transition: 0.6s ease-in-out left; + -o-transition: 0.6s ease-in-out left; + transition: 0.6s ease-in-out left; +} +.carousel .item > img { + display: block; + line-height: 1; +} +.carousel .active, .carousel .next, .carousel .prev { + display: block; +} +.carousel .active { + left: 0; +} +.carousel .next, .carousel .prev { + position: absolute; + top: 0; + width: 100%; +} +.carousel .next { + left: 100%; +} +.carousel .prev { + left: -100%; +} +.carousel .next.left, .carousel .prev.right { + left: 0; +} +.carousel .active.left { + left: -100%; +} +.carousel .active.right { + left: 100%; +} +.carousel-control { + position: absolute; + top: 40%; + left: 15px; + width: 40px; + height: 40px; + margin-top: -20px; + font-size: 60px; + font-weight: 100; + line-height: 30px; + color: #ffffff; + text-align: center; + background: #222222; + border: 3px solid #ffffff; + -webkit-border-radius: 23px; + -moz-border-radius: 23px; + border-radius: 23px; + opacity: 0.5; + filter: alpha(opacity=50); +} +.carousel-control.right { + left: auto; + right: 15px; +} +.carousel-control:hover { + color: #ffffff; + text-decoration: none; + opacity: 0.9; + filter: alpha(opacity=90); +} +.carousel-caption { + position: absolute; + left: 0; + right: 0; + bottom: 0; + padding: 10px 15px 5px; + background: #333333; + background: rgba(0, 0, 0, 0.75); +} +.carousel-caption h4, .carousel-caption p { + color: #ffffff; +} +.hero-unit { + padding: 60px; + margin-bottom: 30px; + background-color: #f5f5f5; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} +.hero-unit h1 { + margin-bottom: 0; + font-size: 60px; + line-height: 1; + letter-spacing: -1px; +} +.hero-unit p { + font-size: 18px; + font-weight: 200; + line-height: 27px; +} +.pull-right { + float: right; +} +.pull-left { + float: left; +} +.hide { + display: none; +} +.show { + display: block; +} +.invisible { + visibility: hidden; +} diff --git a/src/nl/astraeus/jdbc/web/resources/images/loading.gif b/src/nl/astraeus/jdbc/web/resources/images/loading.gif new file mode 100644 index 0000000..21c7e74 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/images/loading.gif Binary files differ diff --git a/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png b/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png new file mode 100644 index 0000000..92d4445 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/img/glyphicons-halflings.png Binary files differ diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-alert.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-alert.js new file mode 100644 index 0000000..2242ddd --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-alert.js @@ -0,0 +1,94 @@ +/* ========================================================== + * bootstrap-alert.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#alerts + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function( $ ){ + + "use strict" + + /* ALERT CLASS DEFINITION + * ====================== */ + + var dismiss = '[data-dismiss="alert"]' + , Alert = function ( el ) { + $(el).on('click', dismiss, this.close) + } + + Alert.prototype = { + + constructor: Alert + + , close: function ( e ) { + var $this = $(this) + , selector = $this.attr('data-target') + , $parent + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = $(selector) + $parent.trigger('close') + + e && e.preventDefault() + + $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent()) + + $parent + .trigger('close') + .removeClass('in') + + function removeElement() { + $parent + .trigger('closed') + .remove() + } + + $.support.transition && $parent.hasClass('fade') ? + $parent.on($.support.transition.end, removeElement) : + removeElement() + } + + } + + + /* ALERT PLUGIN DEFINITION + * ======================= */ + + $.fn.alert = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('alert') + if (!data) $this.data('alert', (data = new Alert(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.alert.Constructor = Alert + + + /* ALERT DATA-API + * ============== */ + + $(function () { + $('body').on('click.alert.data-api', dismiss, Alert.prototype.close) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-button.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-button.js new file mode 100644 index 0000000..0238ca3 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-button.js @@ -0,0 +1,100 @@ +/* ============================================================ + * bootstrap-button.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#buttons + * ============================================================ + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + +!function( $ ){ + + "use strict" + + /* BUTTON PUBLIC CLASS DEFINITION + * ============================== */ + + var Button = function ( element, options ) { + this.$element = $(element) + this.options = $.extend({}, $.fn.button.defaults, options) + } + + Button.prototype = { + + constructor: Button + + , setState: function ( state ) { + var d = 'disabled' + , $el = this.$element + , data = $el.data() + , val = $el.is('input') ? 'val' : 'html' + + state = state + 'Text' + data.resetText || $el.data('resetText', $el[val]()) + + $el[val](data[state] || this.options[state]) + + // push to event loop to allow forms to submit + setTimeout(function () { + state == 'loadingText' ? + $el.addClass(d).attr(d, d) : + $el.removeClass(d).removeAttr(d) + }, 0) + } + + , toggle: function () { + var $parent = this.$element.parent('[data-toggle="buttons-radio"]') + + $parent && $parent + .find('.active') + .removeClass('active') + + this.$element.toggleClass('active') + } + + } + + + /* BUTTON PLUGIN DEFINITION + * ======================== */ + + $.fn.button = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('button') + , options = typeof option == 'object' && option + if (!data) $this.data('button', (data = new Button(this, options))) + if (option == 'toggle') data.toggle() + else if (option) data.setState(option) + }) + } + + $.fn.button.defaults = { + loadingText: 'loading...' + } + + $.fn.button.Constructor = Button + + + /* BUTTON DATA-API + * =============== */ + + $(function () { + $('body').on('click.button.data-api', '[data-toggle^=button]', function ( e ) { + var $btn = $(e.target) + if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') + $btn.button('toggle') + }) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-carousel.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-carousel.js new file mode 100644 index 0000000..810256e --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-carousel.js @@ -0,0 +1,157 @@ +/* ========================================================== + * bootstrap-carousel.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#carousel + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function( $ ){ + + "use strict" + + /* CAROUSEL CLASS DEFINITION + * ========================= */ + + var Carousel = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, $.fn.carousel.defaults, options) + this.options.slide && this.slide(this.options.slide) + } + + Carousel.prototype = { + + cycle: function () { + this.interval = setInterval($.proxy(this.next, this), this.options.interval) + return this + } + + , to: function (pos) { + var $active = this.$element.find('.active') + , children = $active.parent().children() + , activePos = children.index($active) + , that = this + + if (pos > (children.length - 1) || pos < 0) return + + if (this.sliding) { + return this.$element.one('slid', function () { + that.to(pos) + }) + } + + if (activePos == pos) { + return this.pause().cycle() + } + + return this.slide(pos > activePos ? 'next' : 'prev', $(children[pos])) + } + + , pause: function () { + clearInterval(this.interval) + this.interval = null + return this + } + + , next: function () { + if (this.sliding) return + return this.slide('next') + } + + , prev: function () { + if (this.sliding) return + return this.slide('prev') + } + + , slide: function (type, next) { + var $active = this.$element.find('.active') + , $next = next || $active[type]() + , isCycling = this.interval + , direction = type == 'next' ? 'left' : 'right' + , fallback = type == 'next' ? 'first' : 'last' + , that = this + + if (!$next.length) return + + this.sliding = true + + isCycling && this.pause() + + $next = $next.length ? $next : this.$element.find('.item')[fallback]() + + if (!$.support.transition && this.$element.hasClass('slide')) { + this.$element.trigger('slide') + $active.removeClass('active') + $next.addClass('active') + this.sliding = false + this.$element.trigger('slid') + } else { + $next.addClass(type) + $next[0].offsetWidth // force reflow + $active.addClass(direction) + $next.addClass(direction) + this.$element.trigger('slide') + this.$element.one($.support.transition.end, function () { + $next.removeClass([type, direction].join(' ')).addClass('active') + $active.removeClass(['active', direction].join(' ')) + that.sliding = false + setTimeout(function () { that.$element.trigger('slid') }, 0) + }) + } + + isCycling && this.cycle() + + return this + } + + } + + + /* CAROUSEL PLUGIN DEFINITION + * ========================== */ + + $.fn.carousel = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('carousel') + , options = typeof option == 'object' && option + if (!data) $this.data('carousel', (data = new Carousel(this, options))) + if (typeof option == 'number') data.to(option) + else if (typeof option == 'string' || (option = options.slide)) data[option]() + else data.cycle() + }) + } + + $.fn.carousel.defaults = { + interval: 5000 + } + + $.fn.carousel.Constructor = Carousel + + + /* CAROUSEL DATA-API + * ================= */ + + $(function () { + $('body').on('click.carousel.data-api', '[data-slide]', function ( e ) { + var $this = $(this), href + , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 + , options = !$target.data('modal') && $.extend({}, $target.data(), $this.data()) + $target.carousel(options) + e.preventDefault() + }) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-collapse.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-collapse.js new file mode 100644 index 0000000..d195efc --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-collapse.js @@ -0,0 +1,136 @@ +/* ============================================================= + * bootstrap-collapse.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#collapse + * ============================================================= + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + +!function( $ ){ + + "use strict" + + var Collapse = function ( element, options ) { + this.$element = $(element) + this.options = $.extend({}, $.fn.collapse.defaults, options) + + if (this.options["parent"]) { + this.$parent = $(this.options["parent"]) + } + + this.options.toggle && this.toggle() + } + + Collapse.prototype = { + + constructor: Collapse + + , dimension: function () { + var hasWidth = this.$element.hasClass('width') + return hasWidth ? 'width' : 'height' + } + + , show: function () { + var dimension = this.dimension() + , scroll = $.camelCase(['scroll', dimension].join('-')) + , actives = this.$parent && this.$parent.find('.in') + , hasData + + if (actives && actives.length) { + hasData = actives.data('collapse') + actives.collapse('hide') + hasData || actives.data('collapse', null) + } + + this.$element[dimension](0) + this.transition('addClass', 'show', 'shown') + this.$element[dimension](this.$element[0][scroll]) + + } + + , hide: function () { + var dimension = this.dimension() + this.reset(this.$element[dimension]()) + this.transition('removeClass', 'hide', 'hidden') + this.$element[dimension](0) + } + + , reset: function ( size ) { + var dimension = this.dimension() + + this.$element + .removeClass('collapse') + [dimension](size || 'auto') + [0].offsetWidth + + this.$element.addClass('collapse') + } + + , transition: function ( method, startEvent, completeEvent ) { + var that = this + , complete = function () { + if (startEvent == 'show') that.reset() + that.$element.trigger(completeEvent) + } + + this.$element + .trigger(startEvent) + [method]('in') + + $.support.transition && this.$element.hasClass('collapse') ? + this.$element.one($.support.transition.end, complete) : + complete() + } + + , toggle: function () { + this[this.$element.hasClass('in') ? 'hide' : 'show']() + } + + } + + /* COLLAPSIBLE PLUGIN DEFINITION + * ============================== */ + + $.fn.collapse = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('collapse') + , options = typeof option == 'object' && option + if (!data) $this.data('collapse', (data = new Collapse(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.collapse.defaults = { + toggle: true + } + + $.fn.collapse.Constructor = Collapse + + + /* COLLAPSIBLE DATA-API + * ==================== */ + + $(function () { + $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function ( e ) { + var $this = $(this), href + , target = $this.attr('data-target') + || e.preventDefault() + || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 + , option = $(target).data('collapse') ? 'toggle' : $this.data() + $(target).collapse(option) + }) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-dropdown.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-dropdown.js new file mode 100644 index 0000000..f1f6c33 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-dropdown.js @@ -0,0 +1,92 @@ +/* ============================================================ + * bootstrap-dropdown.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#dropdowns + * ============================================================ + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + + +!function( $ ){ + + "use strict" + + /* DROPDOWN CLASS DEFINITION + * ========================= */ + + var toggle = '[data-toggle="dropdown"]' + , Dropdown = function ( element ) { + var $el = $(element).on('click.dropdown.data-api', this.toggle) + $('html').on('click.dropdown.data-api', function () { + $el.parent().removeClass('open') + }) + } + + Dropdown.prototype = { + + constructor: Dropdown + + , toggle: function ( e ) { + var $this = $(this) + , selector = $this.attr('data-target') + , $parent + , isActive + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = $(selector) + $parent.length || ($parent = $this.parent()) + + isActive = $parent.hasClass('open') + + clearMenus() + !isActive && $parent.toggleClass('open') + + return false + } + + } + + function clearMenus() { + $(toggle).parent().removeClass('open') + } + + + /* DROPDOWN PLUGIN DEFINITION + * ========================== */ + + $.fn.dropdown = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('dropdown') + if (!data) $this.data('dropdown', (data = new Dropdown(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.dropdown.Constructor = Dropdown + + + /* APPLY TO STANDARD DROPDOWN ELEMENTS + * =================================== */ + + $(function () { + $('html').on('click.dropdown.data-api', clearMenus) + $('body').on('click.dropdown.data-api', toggle, Dropdown.prototype.toggle) + }) + +}( window.jQuery ); \ No newline at end of file diff --git a/src/nl/astraeus/jdbc/web/resources/js/bootstrap-modal.js b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-modal.js new file mode 100644 index 0000000..bceb303 --- /dev/null +++ b/src/nl/astraeus/jdbc/web/resources/js/bootstrap-modal.js @@ -0,0 +1,210 @@ +/* ========================================================= + * bootstrap-modal.js v2.0.1 + * http://twitter.github.com/bootstrap/javascript.html#modals + * ========================================================= + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================= */ + + +!function( $ ){ + + "use strict" + + /* MODAL CLASS DEFINITION + * ====================== */ + + var Modal = function ( content, options ) { + this.options = options + this.$element = $(content) + .delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this)) + } + + Modal.prototype = { + + constructor: Modal + + , toggle: function () { + return this[!this.isShown ? 'show' : 'hide']() + } + + , show: function () { + var that = this + + if (this.isShown) return + + $('body').addClass('modal-open') + + this.isShown = true + this.$element.trigger('show') + + escape.call(this) + backdrop.call(this, function () { + var transition = $.support.transition && that.$element.hasClass('fade') + + !that.$element.parent().length && that.$element.appendTo(document.body) //don't move modals dom position + + that.$element + .show() + + if (transition) { + that.$element[0].offsetWidth // force reflow + } + + that.$element.addClass('in') + + transition ? + that.$element.one($.support.transition.end, function () { that.$element.trigger('shown') }) : + that.$element.trigger('shown') + + }) + } + + , hide: function ( e ) { + e && e.preventDefault() + + if (!this.isShown) return + + var that = this + this.isShown = false + + $('body').removeClass('modal-open') + + escape.call(this) + + this.$element + .trigger('hide') + .removeClass('in') + + $.support.transition && this.$element.hasClass('fade') ? + hideWithTransition.call(this) : + hideModal.call(this) + } + + } + + + /* MODAL PRIVATE METHODS + * ===================== */ + + function hideWithTransition() { + var that = this + , timeout = setTimeout(function () { + that.$element.off($.support.transition.end) + hideModal.call(that) + }, 500) + + this.$element.one($.support.transition.end, function () { + clearTimeout(timeout) + hideModal.call(that) + }) + } + + function hideModal( that ) { + this.$element + .hide() + .trigger('hidden') + + backdrop.call(this) + } + + function backdrop( callback ) { + var that = this + , animate = this.$element.hasClass('fade') ? 'fade' : '' + + if (this.isShown && this.options.backdrop) { + var doAnimate = $.support.transition && animate + + this.$backdrop = $('