Mercurial > gemma
annotate config/config.go @ 367:7ecc4f8c895c
Merge
author | Thomas Junk <thomas.junk@intevation.de> |
---|---|
date | Thu, 09 Aug 2018 13:11:50 +0200 |
parents | dabe189369ad |
children | 3cfab707f909 |
rev | line source |
---|---|
28
714787accd26
Fetch database connection string parts from configuration.
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
diff
changeset
|
1 package config |
714787accd26
Fetch database connection string parts from configuration.
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
diff
changeset
|
2 |
332
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
3 import ( |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
4 "log" |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
5 |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
6 homedir "github.com/mitchellh/go-homedir" |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
7 "github.com/spf13/cobra" |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
8 "github.com/spf13/viper" |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
9 ) |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
10 |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
11 // This is not part of the persistent config. |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
12 var configFile string |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
13 |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
14 func ConfigFile() string { return configFile } |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
15 |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
16 func DBHost() string { return viper.GetString("dbhost") } |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
17 func DBPort() uint { return uint(viper.GetInt32("dbport")) } |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
18 func DBName() string { return viper.GetString("dbname") } |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
19 func DBSSLMode() string { return viper.GetString("dbssl") } |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
20 func SessionStore() string { return viper.GetString("sessions") } |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
21 func Web() string { return viper.GetString("web") } |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
22 func WebHost() string { return viper.GetString("host") } |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
23 func WebPort() uint { return uint(viper.GetInt32("port")) } |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
24 |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
25 func ServiceUser() string { return viper.GetString("service-user") } |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
26 func ServicePassword() string { return viper.GetString("service-password") } |
28
714787accd26
Fetch database connection string parts from configuration.
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
diff
changeset
|
27 |
332
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
28 func MailHost() string { return viper.GetString("mail-host") } |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
29 func MailPort() uint { return uint(viper.GetInt32("mail-port")) } |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
30 func MailUser() string { return viper.GetString("mail-user") } |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
31 func MailPassword() string { return viper.GetString("mail-password") } |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
32 func MailFrom() string { return viper.GetString("mail-from") } |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
33 func MailHelo() string { return viper.GetString("mail-helo") } |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
34 |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
35 func AllowedOrigins() []string { return viper.GetStringSlice("allowed-origins") } |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
36 |
335
bd292a554b6e
Made gemma a WFS proxy.
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
332
diff
changeset
|
37 func ExternalWFSs() map[string]interface{} { return viper.GetStringMap("external-wfs") } |
bd292a554b6e
Made gemma a WFS proxy.
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
332
diff
changeset
|
38 |
332
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
39 var RootCmd = &cobra.Command{ |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
40 Use: "gemma", |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
41 Short: "gemma is a server for waterway monitoring and management", |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
42 } |
119
29e56c342c9f
Added first middleware for JWT token extraction. TODO: Add second one to check against logged in users.
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
28
diff
changeset
|
43 |
332
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
44 func init() { |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
45 cobra.OnInitialize(initConfig) |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
46 fl := RootCmd.PersistentFlags() |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
47 fl.StringVarP(&configFile, "config", "c", "", "config file (default is $HOME/.gemma.toml)") |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
48 |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
49 fl.StringP("dbhost", "H", "localhost", "host of the database") |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
50 fl.UintP("dbport", "P", 5432, "port of the database") |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
51 fl.StringP("dbname", "d", "gemma", "name of the database") |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
52 fl.StringP("dbssl", "S", "prefer", "SSL mode of the database") |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
53 |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
54 fl.StringP("sessions", "s", "", "path to the sessions file") |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
55 |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
56 fl.StringP("web", "w", "", "path to the web files") |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
57 fl.StringP("host", "o", "localhost", "host of the web app") |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
58 fl.UintP("port", "p", 8000, "port of the web app") |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
59 |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
60 fl.String("service-user", "postgres", "user to do service tasks") |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
61 fl.String("service-password", "", "password of user to do service tasks") |
28
714787accd26
Fetch database connection string parts from configuration.
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
diff
changeset
|
62 |
332
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
63 fl.String("mail-host", "localhost", "server to send mail with") |
338
dabe189369ad
Configuration: Port numbers are integers. Mail port defaults to 465 (SSL).
Sascha L. Teichmann <teichmann@intevation.de>
parents:
335
diff
changeset
|
64 fl.Uint("mail-port", 465, "port of server to send mail with") |
332
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
65 fl.String("mail-user", "gemma", "user to send mail with") |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
66 fl.String("mail-password", "", "password of user to send mail with") |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
67 fl.String("mail-from", "noreplay@localhost", "from line of mails") |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
68 fl.String("mail-helo", "localhost", "name of server to send mail from.") |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
69 |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
70 fl.StringSlice("allowed-origins", []string{"foo.org"}, "allow access for remote origins") |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
71 |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
72 vbind := func(name string) { viper.BindPFlag(name, fl.Lookup(name)) } |
302
0777aa6de45b
Password reset. Part I
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
221
diff
changeset
|
73 |
332
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
74 vbind("dbhost") |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
75 vbind("dbport") |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
76 vbind("dbname") |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
77 vbind("dbssl") |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
78 |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
79 vbind("sessions") |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
80 |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
81 vbind("web") |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
82 vbind("host") |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
83 vbind("port") |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
84 |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
85 vbind("service-user") |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
86 vbind("service-password") |
302
0777aa6de45b
Password reset. Part I
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
221
diff
changeset
|
87 |
332
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
88 vbind("mail-host") |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
89 vbind("mail-port") |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
90 vbind("mail-user") |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
91 vbind("mail-password") |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
92 vbind("mail-from") |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
93 vbind("mail-helo") |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
94 |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
95 vbind("allowed-origins") |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
96 } |
325
c23eb0f34e39
Added CORS support.
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
302
diff
changeset
|
97 |
332
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
98 func initConfig() { |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
99 // Don't forget to read config either from cfgFile or from home directory! |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
100 if configFile != "" { |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
101 // Use config file from the flag. |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
102 viper.SetConfigFile(configFile) |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
103 } else { |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
104 // Find home directory. |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
105 home, err := homedir.Dir() |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
106 if err != nil { |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
107 log.Fatalf("error: %v\n", err) |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
108 } |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
109 |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
110 // Search config in home directory with name ".cobra" (without extension). |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
111 viper.AddConfigPath(home) |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
112 viper.SetConfigName(".gemma") |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
113 } |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
114 if err := viper.ReadInConfig(); err != nil { |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
115 if _, ok := err.(viper.ConfigFileNotFoundError); ok && configFile == "" { |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
116 // Don't bother if not found. |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
117 return |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
118 } |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
119 log.Fatalf("Can't read config: %v\n", err) |
394fafeb4052
Use viper as config storage (I don't like it).
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
325
diff
changeset
|
120 } |
28
714787accd26
Fetch database connection string parts from configuration.
Sascha L. Teichmann <sascha.teichmann@intevation.de>
parents:
diff
changeset
|
121 } |