Преглед изворни кода

Merge branch 'master' into editable_false

Torkel Ödegaard пре 10 година
родитељ
комит
af277f560f
30 измењених фајлова са 55 додато и 65 уклоњено
  1. 2 0
      CHANGELOG.md
  2. 9 9
      Godeps/Godeps.json
  3. 3 7
      Godeps/_workspace/src/github.com/dalu/slug/README.md
  4. 0 0
      Godeps/_workspace/src/github.com/dalu/slug/default_substitution.go
  5. 1 5
      Godeps/_workspace/src/github.com/dalu/slug/doc.go
  6. 0 0
      Godeps/_workspace/src/github.com/dalu/slug/languages_substitution.go
  7. 1 1
      Godeps/_workspace/src/github.com/dalu/slug/slug.go
  8. 0 0
      Godeps/_workspace/src/github.com/dalu/slug/slug_test.go
  9. 0 0
      Godeps/_workspace/src/github.com/dalu/unidecode/.gitignore
  10. 0 0
      Godeps/_workspace/src/github.com/dalu/unidecode/LICENSE
  11. 0 6
      Godeps/_workspace/src/github.com/dalu/unidecode/README.md
  12. 0 0
      Godeps/_workspace/src/github.com/dalu/unidecode/decode.go
  13. 0 0
      Godeps/_workspace/src/github.com/dalu/unidecode/make_table.go
  14. 0 0
      Godeps/_workspace/src/github.com/dalu/unidecode/table.go
  15. 0 0
      Godeps/_workspace/src/github.com/dalu/unidecode/table.txt
  16. 0 0
      Godeps/_workspace/src/github.com/dalu/unidecode/unidecode.go
  17. 0 0
      Godeps/_workspace/src/github.com/dalu/unidecode/unidecode_test.go
  18. 0 2
      Godeps/_workspace/src/github.com/gosimple/slug/.gitignore
  19. 0 24
      Godeps/_workspace/src/gopkgs.com/unidecode.v1/gopkgs.go
  20. 3 2
      conf/defaults.ini
  21. 2 2
      conf/sample.ini
  22. 1 1
      docs/sources/installation/configuration.md
  23. 1 1
      docs/sources/reference/timerange.md
  24. 1 1
      package.json
  25. 1 1
      pkg/models/dashboards.go
  26. 6 0
      pkg/services/sqlstore/migrations/dashboard_mig.go
  27. 6 0
      pkg/services/sqlstore/migrations/dashboard_snapshot_mig.go
  28. 10 2
      pkg/services/sqlstore/migrator/migrations.go
  29. 6 0
      public/app/components/kbn.js
  30. 2 1
      public/css/less/search.less

+ 2 - 0
CHANGELOG.md

@@ -1,7 +1,9 @@
 # 2.0.3 (unreleased)
 # 2.0.3 (unreleased)
 
 
 **Fixes**
 **Fixes**
+- [Issue #1872](https://github.com/grafana/grafana/issues/1872). Firefox/IE issue, invisible text in dashboard search fixed
 - [Issue #1857](https://github.com/grafana/grafana/issues/1857). /api/login/ping Fix for issue when behind reverse proxy and subpath
 - [Issue #1857](https://github.com/grafana/grafana/issues/1857). /api/login/ping Fix for issue when behind reverse proxy and subpath
+- [Issue #1863](https://github.com/grafana/grafana/issues/1863). MySQL: Dashboard.data column type changed to mediumtext (sql migration added)
 
 
 # 2.0.2 (2015-04-22)
 # 2.0.2 (2015-04-22)
 
 

+ 9 - 9
Godeps/Godeps.json

@@ -1,6 +1,6 @@
 {
 {
 	"ImportPath": "github.com/grafana/grafana",
 	"ImportPath": "github.com/grafana/grafana",
-	"GoVersion": "go1.4.2",
+	"GoVersion": "go1.3",
 	"Packages": [
 	"Packages": [
 		"./pkg/..."
 		"./pkg/..."
 	],
 	],
@@ -13,6 +13,14 @@
 			"ImportPath": "github.com/Unknwon/macaron",
 			"ImportPath": "github.com/Unknwon/macaron",
 			"Rev": "93de4f3fad97bf246b838f828e2348f46f21f20a"
 			"Rev": "93de4f3fad97bf246b838f828e2348f46f21f20a"
 		},
 		},
+		{
+			"ImportPath": "github.com/dalu/slug",
+			"Rev": "6dbd13912e9be466e2c1de349a2c7d1466c97e07"
+		},
+		{
+			"ImportPath": "github.com/dalu/unidecode",
+			"Rev": "339814d47f3e32a6f7036a0a4c56ed9b373dd755"
+		},
 		{
 		{
 			"ImportPath": "github.com/go-sql-driver/mysql",
 			"ImportPath": "github.com/go-sql-driver/mysql",
 			"Comment": "v1.2-26-g9543750",
 			"Comment": "v1.2-26-g9543750",
@@ -27,10 +35,6 @@
 			"Comment": "v0.4.2-58-ge2889e5",
 			"Comment": "v0.4.2-58-ge2889e5",
 			"Rev": "e2889e5517600b82905f1d2ba8b70deb71823ffe"
 			"Rev": "e2889e5517600b82905f1d2ba8b70deb71823ffe"
 		},
 		},
-		{
-			"ImportPath": "github.com/gosimple/slug",
-			"Rev": "a2392a4a87fa0366cbff131d3fd421f83f52492f"
-		},
 		{
 		{
 			"ImportPath": "github.com/jtolds/gls",
 			"ImportPath": "github.com/jtolds/gls",
 			"Rev": "f1ac7f4f24f50328e6bc838ca4437d1612a0243c"
 			"Rev": "f1ac7f4f24f50328e6bc838ca4437d1612a0243c"
@@ -87,10 +91,6 @@
 		{
 		{
 			"ImportPath": "gopkgs.com/pool.v1",
 			"ImportPath": "gopkgs.com/pool.v1",
 			"Rev": "c850f092aad1780cbffff25f471c5cc32097932a"
 			"Rev": "c850f092aad1780cbffff25f471c5cc32097932a"
-		},
-		{
-			"ImportPath": "gopkgs.com/unidecode.v1",
-			"Rev": "4deae2c05236b41cc39f8144ac87a837ba974d40"
 		}
 		}
 	]
 	]
 }
 }

+ 3 - 7
Godeps/_workspace/src/github.com/gosimple/slug/README.md → Godeps/_workspace/src/github.com/dalu/slug/README.md

@@ -4,10 +4,9 @@ slug
 Package `slug` generate slug from unicode string, URL-friendly slugify with
 Package `slug` generate slug from unicode string, URL-friendly slugify with
 multiple languages support.
 multiple languages support.
 
 
-[![GoDoc](https://godoc.org/github.com/gosimple/slug?status.png)](https://godoc.org/github.com/gosimple/slug)
-[![Build Status](https://drone.io/github.com/gosimple/slug/status.png)](https://drone.io/github.com/gosimple/slug/latest)
+[![GoDoc](https://godoc.org/github.com/dalu/slug?status.png)](https://godoc.org/github.com/dalu/slug)
 
 
-[Documentation online](http://godoc.org/github.com/gosimple/slug)
+[Documentation online](http://godoc.org/github.com/dalu/slug)
 
 
 ## Example
 ## Example
 
 
@@ -38,12 +37,9 @@ multiple languages support.
 		fmt.Println(textSub) // Will print 'sand-is-hot'
 		fmt.Println(textSub) // Will print 'sand-is-hot'
 	}
 	}
 
 
-### Requests or bugs?
-<https://github.com/gosimple/slug/issues>
-
 ## Installation
 ## Installation
 
 
-	go get -u github.com/gosimple/slug
+	go get -u github.com/dalu/slug
 
 
 ## License
 ## License
 
 

+ 0 - 0
Godeps/_workspace/src/github.com/gosimple/slug/default_substitution.go → Godeps/_workspace/src/github.com/dalu/slug/default_substitution.go


+ 1 - 5
Godeps/_workspace/src/github.com/gosimple/slug/doc.go → Godeps/_workspace/src/github.com/dalu/slug/doc.go

@@ -12,7 +12,7 @@ Example:
 	package main
 	package main
 
 
 	import(
 	import(
-		"github.com/gosimple/slug"
+		"github.com/dalu/slug"
 		"fmt"
 		"fmt"
 	)
 	)
 
 
@@ -35,9 +35,5 @@ Example:
 		textSub := slug.Make("water is hot")
 		textSub := slug.Make("water is hot")
 		fmt.Println(textSub) // Will print 'sand-is-hot'
 		fmt.Println(textSub) // Will print 'sand-is-hot'
 	}
 	}
-
-Requests or bugs?
-
-https://github.com/gosimple/slug/issues
 */
 */
 package slug
 package slug

+ 0 - 0
Godeps/_workspace/src/github.com/gosimple/slug/languages_substitution.go → Godeps/_workspace/src/github.com/dalu/slug/languages_substitution.go


+ 1 - 1
Godeps/_workspace/src/github.com/gosimple/slug/slug.go → Godeps/_workspace/src/github.com/dalu/slug/slug.go

@@ -6,7 +6,7 @@
 package slug
 package slug
 
 
 import (
 import (
-	"gopkgs.com/unidecode.v1"
+	"github.com/dalu/unidecode"
 	"regexp"
 	"regexp"
 	"strings"
 	"strings"
 )
 )

+ 0 - 0
Godeps/_workspace/src/github.com/gosimple/slug/slug_test.go → Godeps/_workspace/src/github.com/dalu/slug/slug_test.go


+ 0 - 0
Godeps/_workspace/src/gopkgs.com/unidecode.v1/.gitignore → Godeps/_workspace/src/github.com/dalu/unidecode/.gitignore


+ 0 - 0
Godeps/_workspace/src/gopkgs.com/unidecode.v1/LICENSE → Godeps/_workspace/src/github.com/dalu/unidecode/LICENSE


+ 0 - 6
Godeps/_workspace/src/gopkgs.com/unidecode.v1/README.md → Godeps/_workspace/src/github.com/dalu/unidecode/README.md

@@ -3,10 +3,4 @@ unidecode
 
 
 Unicode transliterator in Golang - Replaces non-ASCII characters with their ASCII approximations.
 Unicode transliterator in Golang - Replaces non-ASCII characters with their ASCII approximations.
 
 
-Please, use the following import path to ensure a stable API:
-
-```go
-    import "gopkgs.com/unidecode.v1"
-```
-
 View other available versions, documentation and examples at http://gopkgs.com/unidecode
 View other available versions, documentation and examples at http://gopkgs.com/unidecode

+ 0 - 0
Godeps/_workspace/src/gopkgs.com/unidecode.v1/decode.go → Godeps/_workspace/src/github.com/dalu/unidecode/decode.go


+ 0 - 0
Godeps/_workspace/src/gopkgs.com/unidecode.v1/make_table.go → Godeps/_workspace/src/github.com/dalu/unidecode/make_table.go


+ 0 - 0
Godeps/_workspace/src/gopkgs.com/unidecode.v1/table.go → Godeps/_workspace/src/github.com/dalu/unidecode/table.go


+ 0 - 0
Godeps/_workspace/src/gopkgs.com/unidecode.v1/table.txt → Godeps/_workspace/src/github.com/dalu/unidecode/table.txt


+ 0 - 0
Godeps/_workspace/src/gopkgs.com/unidecode.v1/unidecode.go → Godeps/_workspace/src/github.com/dalu/unidecode/unidecode.go


+ 0 - 0
Godeps/_workspace/src/gopkgs.com/unidecode.v1/unidecode_test.go → Godeps/_workspace/src/github.com/dalu/unidecode/unidecode_test.go


+ 0 - 2
Godeps/_workspace/src/github.com/gosimple/slug/.gitignore

@@ -1,2 +0,0 @@
-_*
-cover*.out

+ 0 - 24
Godeps/_workspace/src/gopkgs.com/unidecode.v1/gopkgs.go

@@ -1,24 +0,0 @@
-package unidecode
-
-import (
-	"fmt"
-	"reflect"
-)
-
-// gopkgs.go: v1
-
-// NOTE: This file is autogenerated by gopkgs.com.
-const (
-	goPkgsSrcPath = "github.com/rainycape/unidecode"
-	goPkgsName    = "unidecode"
-	goPkgsErrFmt  = "invalid import path %s - please use gopkgs.com/%s.v1 or see http://gopkgs.com/%s"
-)
-
-type goPkgsCheck struct{}
-
-func init() {
-	typ := reflect.TypeOf(goPkgsCheck{})
-	if typ.PkgPath() == goPkgsSrcPath {
-		panic(fmt.Errorf(goPkgsErrFmt, typ.PkgPath(), goPkgsName, goPkgsName))
-	}
-}

+ 3 - 2
conf/defaults.ini

@@ -7,7 +7,7 @@ app_mode = production
 
 
 #################################### Paths ####################################
 #################################### Paths ####################################
 [paths]
 [paths]
-# Path to where grafana can store temp files, sessions, and the sqlite3 db (if that is useD)
+# Path to where grafana can store temp files, sessions, and the sqlite3 db (if that is used)
 #
 #
 data = data
 data = data
 #
 #
@@ -62,7 +62,7 @@ path = grafana.db
 
 
 #################################### Session ####################################
 #################################### Session ####################################
 [session]
 [session]
-# Either "memory", "file", "redis", "mysql", default is "memory"
+# Either "memory", "file", "redis", "mysql", "postgresql", default is "file"
 provider = file
 provider = file
 
 
 # Provider config options
 # Provider config options
@@ -70,6 +70,7 @@ provider = file
 # file: session dir path, is relative to grafana data_path
 # file: session dir path, is relative to grafana data_path
 # redis: config like redis server addr, poolSize, password, e.g. `127.0.0.1:6379,100,grafana`
 # redis: config like redis server addr, poolSize, password, e.g. `127.0.0.1:6379,100,grafana`
 # mysql: go-sql-driver/mysql dsn config string, e.g. `user:password@tcp(127.0.0.1)/database_name`
 # mysql: go-sql-driver/mysql dsn config string, e.g. `user:password@tcp(127.0.0.1)/database_name`
+
 provider_config = sessions
 provider_config = sessions
 
 
 # Session cookie name
 # Session cookie name

+ 2 - 2
conf/sample.ini

@@ -7,7 +7,7 @@
 
 
 #################################### Paths ####################################
 #################################### Paths ####################################
 [paths]
 [paths]
-# Path to where grafana can store temp files, sessions, and the sqlite3 db (if that is useD)
+# Path to where grafana can store temp files, sessions, and the sqlite3 db (if that is used)
 #
 #
 ;data = /var/lib/grafana
 ;data = /var/lib/grafana
 #
 #
@@ -62,7 +62,7 @@
 
 
 #################################### Session ####################################
 #################################### Session ####################################
 [session]
 [session]
-# Either "memory", "file", "redis", "mysql", default is "memory"
+# Either "memory", "file", "redis", "mysql", "postgresql", default is "file"
 ;provider = file
 ;provider = file
 
 
 # Provider config options
 # Provider config options

+ 1 - 1
docs/sources/installation/configuration.md

@@ -219,7 +219,7 @@ set to true, any user successfully authenticating via google auth will be automa
 ## [session]
 ## [session]
 
 
 ### provider
 ### provider
-Valid values are "memory", "file", "mysql", 'postgres'. Default is "memory".
+Valid values are "memory", "file", "mysql", 'postgres'. Default is "file".
 
 
 ### provider_config
 ### provider_config
 This option should be configured differently depending on what type of session provider you have configured.
 This option should be configured differently depending on what type of session provider you have configured.

+ 1 - 1
docs/sources/reference/timerange.md

@@ -24,7 +24,7 @@ All of this applies to all Panels in the Dashboard (except those with Panel Time
 
 
 It's possible to customize the options displayed for relative time and the auto-refresh options. 
 It's possible to customize the options displayed for relative time and the auto-refresh options. 
 
 
-From Dashboard setttings, click the Timepicker tab. From here you can specify the relative and auto refresh intervals. The Timepicker tab settings are saved on a per Dashboard basis.
+From Dashboard setttings, click the Timepicker tab. From here you can specify the relative and auto refresh intervals. The Timepicker tab settings are saved on a per Dashboard basis.  Entries are comma seperated and accept a number followed by one of the following units: s (seconds), m (minutes), h (hours), d (days), w (weeks), M (months), y (years).
 
 
 ![](/img/v1/timepicker_editor.png)
 ![](/img/v1/timepicker_editor.png)
 
 

+ 1 - 1
package.json

@@ -4,7 +4,7 @@
     "company": "Coding Instinct AB"
     "company": "Coding Instinct AB"
   },
   },
   "name": "grafana",
   "name": "grafana",
-  "version": "2.0.3-pre1",
+  "version": "2.1.0-pre1",
   "repository": {
   "repository": {
     "type": "git",
     "type": "git",
     "url": "http://github.com/torkelo/grafana.git"
     "url": "http://github.com/torkelo/grafana.git"

+ 1 - 1
pkg/models/dashboards.go

@@ -5,7 +5,7 @@ import (
 	"strings"
 	"strings"
 	"time"
 	"time"
 
 
-	"github.com/gosimple/slug"
+	"github.com/dalu/slug"
 )
 )
 
 
 // Typed errors
 // Typed errors

+ 6 - 0
pkg/services/sqlstore/migrations/dashboard_mig.go

@@ -86,4 +86,10 @@ func addDashboardMigration(mg *Migrator) {
 	}))
 	}))
 
 
 	mg.AddMigration("drop table dashboard_v1", NewDropTableMigration("dashboard_v1"))
 	mg.AddMigration("drop table dashboard_v1", NewDropTableMigration("dashboard_v1"))
+
+	// change column type of dashboard.data
+	mg.AddMigration("alter dashboard.data to mediumtext v1", new(RawSqlMigration).
+		Sqlite("SELECT 0 WHERE 0;").
+		Postgres("SELECT 0;").
+		Mysql("ALTER TABLE dashboard MODIFY data MEDIUMTEXT;"))
 }
 }

+ 6 - 0
pkg/services/sqlstore/migrations/dashboard_snapshot_mig.go

@@ -48,4 +48,10 @@ func addDashboardSnapshotMigrations(mg *Migrator) {
 
 
 	mg.AddMigration("create dashboard_snapshot table v5 #2", NewAddTableMigration(snapshotV5))
 	mg.AddMigration("create dashboard_snapshot table v5 #2", NewAddTableMigration(snapshotV5))
 	addTableIndicesMigrations(mg, "v5", snapshotV5)
 	addTableIndicesMigrations(mg, "v5", snapshotV5)
+
+	// change column type of dashboard
+	mg.AddMigration("alter dashboard_snapshot to mediumtext v2", new(RawSqlMigration).
+		Sqlite("SELECT 0 WHERE 0;").
+		Postgres("SELECT 0;").
+		Mysql("ALTER TABLE dashboard_snapshot MODIFY dashboard MEDIUMTEXT;"))
 }
 }

+ 10 - 2
pkg/services/sqlstore/migrator/migrations.go

@@ -25,8 +25,9 @@ func (m *MigrationBase) GetCondition() MigrationCondition {
 type RawSqlMigration struct {
 type RawSqlMigration struct {
 	MigrationBase
 	MigrationBase
 
 
-	sqlite string
-	mysql  string
+	sqlite   string
+	mysql    string
+	postgres string
 }
 }
 
 
 func (m *RawSqlMigration) Sql(dialect Dialect) string {
 func (m *RawSqlMigration) Sql(dialect Dialect) string {
@@ -35,6 +36,8 @@ func (m *RawSqlMigration) Sql(dialect Dialect) string {
 		return m.mysql
 		return m.mysql
 	case SQLITE:
 	case SQLITE:
 		return m.sqlite
 		return m.sqlite
+	case POSTGRES:
+		return m.postgres
 	}
 	}
 
 
 	panic("db type not supported")
 	panic("db type not supported")
@@ -50,6 +53,11 @@ func (m *RawSqlMigration) Mysql(sql string) *RawSqlMigration {
 	return m
 	return m
 }
 }
 
 
+func (m *RawSqlMigration) Postgres(sql string) *RawSqlMigration {
+	m.postgres = sql
+	return m
+}
+
 type AddColumnMigration struct {
 type AddColumnMigration struct {
 	MigrationBase
 	MigrationBase
 	tableName string
 	tableName string

+ 6 - 0
public/app/components/kbn.js

@@ -380,6 +380,9 @@ function($, _, moment) {
   kbn.valueFormats.Bps = kbn.formatFuncCreator(1000, [' Bps', ' KBps', ' MBps', ' GBps', ' TBps', ' PBps', ' EBps', ' ZBps', ' YBps']);
   kbn.valueFormats.Bps = kbn.formatFuncCreator(1000, [' Bps', ' KBps', ' MBps', ' GBps', ' TBps', ' PBps', ' EBps', ' ZBps', ' YBps']);
   kbn.valueFormats.short = kbn.formatFuncCreator(1000, ['', ' K', ' Mil', ' Bil', ' Tri', ' Qaudr', ' Quint', ' Sext', ' Sept']);
   kbn.valueFormats.short = kbn.formatFuncCreator(1000, ['', ' K', ' Mil', ' Bil', ' Tri', ' Qaudr', ' Quint', ' Sext', ' Sept']);
   kbn.valueFormats.joule = kbn.formatFuncCreator(1000, [' J', ' kJ', ' MJ', ' GJ', ' TJ', ' PJ', ' EJ', ' ZJ', ' YJ']);
   kbn.valueFormats.joule = kbn.formatFuncCreator(1000, [' J', ' kJ', ' MJ', ' GJ', ' TJ', ' PJ', ' EJ', ' ZJ', ' YJ']);
+  kbn.valueFormats.amp = kbn.formatFuncCreator(1000, [' A', ' kA', ' MA', ' GA', ' TA', ' PA', ' EA', ' ZA', ' YA']);
+  kbn.valueFormats.volt = kbn.formatFuncCreator(1000, [' V', ' kV', ' MV', ' GV', ' TV', ' PV', ' EV', ' ZV', ' YV']);
+  kbn.valueFormats.hertz = kbn.formatFuncCreator(1000, [' Hz', ' kHz', ' MHz', ' GHz', ' THz', ' PHz', ' EHz', ' ZHz', ' YHz']);
   kbn.valueFormats.watt = kbn.formatFuncCreator(1000, [' W', ' kW', ' MW', ' GW', ' TW', ' PW', ' EW', ' ZW', ' YW']);
   kbn.valueFormats.watt = kbn.formatFuncCreator(1000, [' W', ' kW', ' MW', ' GW', ' TW', ' PW', ' EW', ' ZW', ' YW']);
   kbn.valueFormats.kwatt = kbn.formatFuncCreator(1000, [' kW', ' MW', ' GW', ' TW', ' PW', ' EW', ' ZW', ' YW']);
   kbn.valueFormats.kwatt = kbn.formatFuncCreator(1000, [' kW', ' MW', ' GW', ' TW', ' PW', ' EW', ' ZW', ' YW']);
   kbn.valueFormats.watth = kbn.formatFuncCreator(1000, [' Wh', ' kWh', ' MWh', ' GWh', ' TWh', ' PWh', ' EWh', ' ZWh', ' YWh']);
   kbn.valueFormats.watth = kbn.formatFuncCreator(1000, [' Wh', ' kWh', ' MWh', ' GWh', ' TWh', ' PWh', ' EWh', ' ZWh', ' YWh']);
@@ -534,6 +537,7 @@ function($, _, moment) {
           {text: 'microseconds (µs)', value: 'µs'},
           {text: 'microseconds (µs)', value: 'µs'},
           {text: 'milliseconds (ms)', value: 'ms'},
           {text: 'milliseconds (ms)', value: 'ms'},
           {text: 'seconds (s)', value: 's'},
           {text: 'seconds (s)', value: 's'},
+          {text: 'Hertz (1/s)', value: 'hertz'},
         ]
         ]
       },
       },
       {
       {
@@ -561,6 +565,8 @@ function($, _, moment) {
           {text: 'kilowatt-hour (kWh)',   value: 'kwatth'},
           {text: 'kilowatt-hour (kWh)',   value: 'kwatth'},
           {text: 'joule (J)',             value: 'joule'},
           {text: 'joule (J)',             value: 'joule'},
           {text: 'electron volt (eV)',    value: 'ev'},
           {text: 'electron volt (eV)',    value: 'ev'},
+          {text: 'Ampere (A)',            value: 'amp'},
+          {text: 'Volt (V)',              value: 'volt'},
         ]
         ]
       },
       },
       {
       {

+ 2 - 1
public/css/less/search.less

@@ -22,7 +22,8 @@
   padding-bottom: 10px;
   padding-bottom: 10px;
   input {
   input {
     width: 100%;
     width: 100%;
-    padding: 18px 8px;
+    padding: 8px 8px;
+    height: 100%;
     box-sizing: border-box;
     box-sizing: border-box;
   }
   }
   button {
   button {