embulk-output-oracle 0.7.10 → 0.7.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +16 -0
  3. data/build.gradle +1 -1
  4. data/classpath/{embulk-output-jdbc-0.7.10.jar → embulk-output-jdbc-0.7.11.jar} +0 -0
  5. data/classpath/{embulk-output-oracle-0.7.10.jar → embulk-output-oracle-0.7.11.jar} +0 -0
  6. data/src/test/java/org/embulk/output/oracle/BasicTest.java +450 -0
  7. data/src/test/java/org/embulk/output/oracle/DummyFileSystem.java +96 -0
  8. data/src/test/java/org/embulk/output/oracle/DummyFileSystemProvider.java +154 -0
  9. data/src/test/java/org/embulk/output/oracle/DummyPath.java +188 -0
  10. data/src/test/java/org/embulk/output/oracle/OracleTests.java +90 -0
  11. data/src/test/resources/org/embulk/output/oracle/test/expect/basic/setup.sql +54 -0
  12. data/src/test/resources/org/embulk/output/oracle/test/expect/basic/test1.csv +4 -0
  13. data/src/test/resources/org/embulk/output/oracle/test/expect/basic/test_expected.diff +2 -0
  14. data/src/test/resources/org/embulk/output/oracle/test/expect/basic/test_insert.yml +2 -0
  15. data/src/test/resources/org/embulk/output/oracle/test/expect/basic/test_insert_create_expected.csv +3 -0
  16. data/src/test/resources/org/embulk/output/oracle/test/expect/basic/test_insert_direct.yml +2 -0
  17. data/src/test/resources/org/embulk/output/oracle/test/expect/basic/test_insert_direct_direct.yml +3 -0
  18. data/src/test/resources/org/embulk/output/oracle/test/expect/basic/test_insert_direct_large.yml +5 -0
  19. data/src/test/resources/org/embulk/output/oracle/test/expect/basic/test_insert_direct_multibyte_table.yml +2 -0
  20. data/src/test/resources/org/embulk/output/oracle/test/expect/basic/test_insert_direct_oci.yml +5 -0
  21. data/src/test/resources/org/embulk/output/oracle/test/expect/basic/test_insert_direct_oci_large.yml +6 -0
  22. data/src/test/resources/org/embulk/output/oracle/test/expect/basic/test_insert_direct_oci_multibyte_table.yml +5 -0
  23. data/src/test/resources/org/embulk/output/oracle/test/expect/basic/test_insert_empty_expected.csv +1 -0
  24. data/src/test/resources/org/embulk/output/oracle/test/expect/basic/test_insert_expected.csv +4 -0
  25. data/src/test/resources/org/embulk/output/oracle/test/expect/basic/test_insert_large_expected.csv +9999 -0
  26. data/src/test/resources/org/embulk/output/oracle/test/expect/basic/test_insert_multibyte_table.yml +2 -0
  27. data/src/test/resources/{oracle/data/test3/test3.csv → org/embulk/output/oracle/test/expect/basic/test_large.csv} +3 -3
  28. data/src/test/resources/org/embulk/output/oracle/test/expect/basic/test_lower_column.csv +4 -0
  29. data/src/test/resources/org/embulk/output/oracle/test/expect/basic/test_lower_column.yml +2 -0
  30. data/src/test/resources/org/embulk/output/oracle/test/expect/basic/test_lower_column_options.csv +4 -0
  31. data/src/test/resources/org/embulk/output/oracle/test/expect/basic/test_lower_column_options.yml +5 -0
  32. data/src/test/resources/org/embulk/output/oracle/test/expect/basic/test_lower_table.yml +2 -0
  33. data/src/test/resources/org/embulk/output/oracle/test/expect/basic/test_merge.csv +6 -0
  34. data/src/test/resources/org/embulk/output/oracle/test/expect/basic/test_merge.yml +2 -0
  35. data/src/test/resources/org/embulk/output/oracle/test/expect/basic/test_merge_expected.csv +6 -0
  36. data/src/test/resources/{oracle/data/test5/test5.csv → org/embulk/output/oracle/test/expect/basic/test_merge_keys.csv} +5 -4
  37. data/src/test/resources/org/embulk/output/oracle/test/expect/basic/test_merge_keys.yml +3 -0
  38. data/src/test/resources/org/embulk/output/oracle/test/expect/basic/test_merge_keys_expected.csv +5 -0
  39. data/src/test/resources/org/embulk/output/oracle/test/expect/basic/test_merge_rule.csv +6 -0
  40. data/src/test/resources/org/embulk/output/oracle/test/expect/basic/test_merge_rule.yml +3 -0
  41. data/src/test/resources/org/embulk/output/oracle/test/expect/basic/test_merge_rule_expected.csv +6 -0
  42. data/src/test/resources/org/embulk/output/oracle/test/expect/basic/test_replace.yml +2 -0
  43. data/src/test/resources/org/embulk/output/oracle/test/expect/basic/test_replace_column_options.yml +10 -0
  44. data/src/test/resources/org/embulk/output/oracle/test/expect/basic/test_replace_longname.yml +2 -0
  45. data/src/test/resources/org/embulk/output/oracle/test/expect/basic/test_replace_longname_multibyte.yml +2 -0
  46. data/src/test/resources/org/embulk/output/oracle/test/expect/basic/test_replace_oci.yml +3 -0
  47. data/src/test/resources/org/embulk/output/oracle/test/expect/basic/test_string_timestamp.csv +4 -0
  48. data/src/test/resources/org/embulk/output/oracle/test/expect/basic/test_string_timestamp.yml +5 -0
  49. data/src/test/resources/org/embulk/output/oracle/test/expect/basic/test_string_timestamp_expected.csv +4 -0
  50. data/src/test/resources/org/embulk/output/oracle/test/expect/basic/test_truncate_insert.yml +2 -0
  51. data/src/test/resources/org/embulk/output/oracle/test/expect/basic/test_truncate_insert_expected.csv +3 -0
  52. data/src/test/resources/org/embulk/output/oracle/test/expect/basic/test_truncate_insert_oci.yml +3 -0
  53. metadata +51 -36
  54. data/src/test/java/org/embulk/input/filesplit/LocalFileSplitInputPlugin.java +0 -185
  55. data/src/test/java/org/embulk/input/filesplit/PartialFile.java +0 -50
  56. data/src/test/java/org/embulk/input/filesplit/PartialFileInputStream.java +0 -154
  57. data/src/test/java/org/embulk/output/oracle/OracleOutputPluginTest.java +0 -887
  58. data/src/test/resources/oracle/data/test1/test1.csv +0 -3
  59. data/src/test/resources/oracle/data/test4/test4.csv +0 -5
  60. data/src/test/resources/oracle/yml/test-insert-direct-direct-method.yml +0 -27
  61. data/src/test/resources/oracle/yml/test-insert-direct-empty.yml +0 -26
  62. data/src/test/resources/oracle/yml/test-insert-direct-oci-method-large.yml +0 -29
  63. data/src/test/resources/oracle/yml/test-insert-direct-oci-method-multibyte.yml +0 -29
  64. data/src/test/resources/oracle/yml/test-insert-direct-oci-method-split.yml +0 -29
  65. data/src/test/resources/oracle/yml/test-insert-direct-oci-method.yml +0 -29
  66. data/src/test/resources/oracle/yml/test-insert-direct.yml +0 -26
  67. data/src/test/resources/oracle/yml/test-insert-empty.yml +0 -28
  68. data/src/test/resources/oracle/yml/test-insert.yml +0 -26
  69. data/src/test/resources/oracle/yml/test-lower-column-options.yml +0 -29
  70. data/src/test/resources/oracle/yml/test-lower-column.yml +0 -26
  71. data/src/test/resources/oracle/yml/test-lower-table.yml +0 -26
  72. data/src/test/resources/oracle/yml/test-merge-keys.yml +0 -23
  73. data/src/test/resources/oracle/yml/test-merge-rule.yml +0 -23
  74. data/src/test/resources/oracle/yml/test-merge.yml +0 -22
  75. data/src/test/resources/oracle/yml/test-replace-empty.yml +0 -33
  76. data/src/test/resources/oracle/yml/test-replace-long-name-multibyte.yml +0 -33
  77. data/src/test/resources/oracle/yml/test-replace-long-name.yml +0 -33
  78. data/src/test/resources/oracle/yml/test-replace-oci-method.yml +0 -34
  79. data/src/test/resources/oracle/yml/test-replace.yml +0 -33
  80. data/src/test/resources/oracle/yml/test-string-timestamp.yml +0 -29
  81. data/src/test/resources/oracle/yml/test-truncate-insert-oci-method.yml +0 -27
  82. data/src/test/resources/oracle/yml/test-truncate-insert.yml +0 -26
  83. data/src/test/resources/oracle/yml/test-url.yml +0 -25
@@ -0,0 +1,96 @@
1
+ package org.embulk.output.oracle;
2
+
3
+ import java.io.IOException;
4
+ import java.nio.file.FileStore;
5
+ import java.nio.file.FileSystem;
6
+ import java.nio.file.Path;
7
+ import java.nio.file.PathMatcher;
8
+ import java.nio.file.WatchService;
9
+ import java.nio.file.attribute.UserPrincipalLookupService;
10
+ import java.nio.file.spi.FileSystemProvider;
11
+ import java.util.Set;
12
+
13
+ public class DummyFileSystem extends FileSystem
14
+ {
15
+ private final FileSystem original;
16
+ private final String fileContents;
17
+
18
+ public DummyFileSystem(FileSystem original, String fileContents)
19
+ {
20
+ this.original = original;
21
+ this.fileContents = fileContents;
22
+ }
23
+
24
+ @Override
25
+ public FileSystemProvider provider()
26
+ {
27
+ return new DummyFileSystemProvider(original.provider(), fileContents);
28
+ }
29
+
30
+ @Override
31
+ public void close() throws IOException
32
+ {
33
+ original.close();
34
+ }
35
+
36
+ @Override
37
+ public boolean isOpen()
38
+ {
39
+ return original.isOpen();
40
+ }
41
+
42
+ @Override
43
+ public boolean isReadOnly()
44
+ {
45
+ return original.isReadOnly();
46
+ }
47
+
48
+ @Override
49
+ public String getSeparator()
50
+ {
51
+ return original.getSeparator();
52
+ }
53
+
54
+ @Override
55
+ public Iterable<Path> getRootDirectories()
56
+ {
57
+ return original.getRootDirectories();
58
+ }
59
+
60
+ @Override
61
+ public Iterable<FileStore> getFileStores()
62
+ {
63
+ return original.getFileStores();
64
+ }
65
+
66
+ @Override
67
+ public Set<String> supportedFileAttributeViews()
68
+ {
69
+ return original.supportedFileAttributeViews();
70
+ }
71
+
72
+ @Override
73
+ public Path getPath(String first, String... more)
74
+ {
75
+ return original.getPath(first, more);
76
+ }
77
+
78
+ @Override
79
+ public PathMatcher getPathMatcher(String syntaxAndPattern)
80
+ {
81
+ return original.getPathMatcher(syntaxAndPattern);
82
+ }
83
+
84
+ @Override
85
+ public UserPrincipalLookupService getUserPrincipalLookupService()
86
+ {
87
+ return original.getUserPrincipalLookupService();
88
+ }
89
+
90
+ @Override
91
+ public WatchService newWatchService() throws IOException
92
+ {
93
+ return original.newWatchService();
94
+ }
95
+
96
+ }
@@ -0,0 +1,154 @@
1
+ package org.embulk.output.oracle;
2
+
3
+ import java.io.ByteArrayInputStream;
4
+ import java.io.IOException;
5
+ import java.io.InputStream;
6
+ import java.net.URI;
7
+ import java.nio.channels.SeekableByteChannel;
8
+ import java.nio.file.AccessMode;
9
+ import java.nio.file.CopyOption;
10
+ import java.nio.file.DirectoryStream;
11
+ import java.nio.file.DirectoryStream.Filter;
12
+ import java.nio.file.FileStore;
13
+ import java.nio.file.FileSystem;
14
+ import java.nio.file.LinkOption;
15
+ import java.nio.file.OpenOption;
16
+ import java.nio.file.Path;
17
+ import java.nio.file.attribute.BasicFileAttributes;
18
+ import java.nio.file.attribute.FileAttribute;
19
+ import java.nio.file.attribute.FileAttributeView;
20
+ import java.nio.file.spi.FileSystemProvider;
21
+ import java.util.Map;
22
+ import java.util.Set;
23
+
24
+ public class DummyFileSystemProvider extends FileSystemProvider
25
+ {
26
+ private final FileSystemProvider original;
27
+ private final String fileContents;
28
+
29
+ public DummyFileSystemProvider(FileSystemProvider original, String fileContents)
30
+ {
31
+ this.original = original;
32
+ this.fileContents = fileContents;
33
+ }
34
+
35
+ @Override
36
+ public String getScheme()
37
+ {
38
+ return original.getScheme();
39
+ }
40
+
41
+ @Override
42
+ public FileSystem newFileSystem(URI uri, Map<String, ?> env) throws IOException
43
+ {
44
+ return original.newFileSystem(uri, env);
45
+ }
46
+
47
+ @Override
48
+ public FileSystem getFileSystem(URI uri)
49
+ {
50
+ return original.getFileSystem(uri);
51
+ }
52
+
53
+ @Override
54
+ public Path getPath(URI uri)
55
+ {
56
+ return original.getPath(uri);
57
+ }
58
+
59
+ @Override
60
+ public SeekableByteChannel newByteChannel(Path path, Set<? extends OpenOption> options, FileAttribute<?>... attrs)
61
+ throws IOException
62
+ {
63
+ return original.newByteChannel(path, options, attrs);
64
+ }
65
+
66
+ @Override
67
+ public DirectoryStream<Path> newDirectoryStream(Path dir, Filter<? super Path> filter)
68
+ throws IOException
69
+ {
70
+ return original.newDirectoryStream(dir, filter);
71
+ }
72
+
73
+ @Override
74
+ public void createDirectory(Path dir, FileAttribute<?>... attrs) throws IOException
75
+ {
76
+ original.createDirectory(dir, attrs);
77
+ }
78
+
79
+ @Override
80
+ public void delete(Path path) throws IOException
81
+ {
82
+ original.delete(path);
83
+ }
84
+
85
+ @Override
86
+ public void copy(Path source, Path target, CopyOption... options) throws IOException
87
+ {
88
+ original.copy(source, target, options);
89
+ }
90
+
91
+ @Override
92
+ public void move(Path source, Path target, CopyOption... options) throws IOException
93
+ {
94
+ original.move(source, target, options);
95
+ }
96
+
97
+ @Override
98
+ public boolean isSameFile(Path path, Path path2) throws IOException
99
+ {
100
+ return original.isSameFile(path, path2);
101
+ }
102
+
103
+ @Override
104
+ public boolean isHidden(Path path) throws IOException
105
+ {
106
+ return original.isHidden(path);
107
+ }
108
+
109
+ @Override
110
+ public FileStore getFileStore(Path path) throws IOException
111
+ {
112
+ return original.getFileStore(path);
113
+ }
114
+
115
+ @Override
116
+ public void checkAccess(Path path, AccessMode... modes) throws IOException
117
+ {
118
+ original.checkAccess(path, modes);
119
+ }
120
+
121
+ @Override
122
+ public <V extends FileAttributeView> V getFileAttributeView(Path path, Class<V> type, LinkOption... options)
123
+ {
124
+ return original.getFileAttributeView(path, type, options);
125
+ }
126
+
127
+ @Override
128
+ public <A extends BasicFileAttributes> A readAttributes(Path path, Class<A> type, LinkOption... options)
129
+ throws IOException
130
+ {
131
+ return original.readAttributes(path, type, options);
132
+ }
133
+
134
+ @Override
135
+ public Map<String, Object> readAttributes(Path path, String attributes, LinkOption... options)
136
+ throws IOException
137
+ {
138
+ return original.readAttributes(path, attributes, options);
139
+ }
140
+
141
+ @Override
142
+ public void setAttribute(Path path, String attribute, Object value, LinkOption... options)
143
+ throws IOException
144
+ {
145
+ original.setAttribute(path, attribute, value, options);
146
+ }
147
+
148
+ @Override
149
+ public InputStream newInputStream(Path path, OpenOption... options) throws IOException
150
+ {
151
+ return new ByteArrayInputStream(fileContents.getBytes());
152
+ }
153
+
154
+ }
@@ -0,0 +1,188 @@
1
+ package org.embulk.output.oracle;
2
+
3
+ import java.io.File;
4
+ import java.io.IOException;
5
+ import java.net.URI;
6
+ import java.nio.file.FileSystem;
7
+ import java.nio.file.LinkOption;
8
+ import java.nio.file.Path;
9
+ import java.nio.file.WatchEvent.Kind;
10
+ import java.nio.file.WatchEvent.Modifier;
11
+ import java.nio.file.WatchKey;
12
+ import java.nio.file.WatchService;
13
+ import java.util.Iterator;
14
+
15
+ public class DummyPath implements Path
16
+ {
17
+ private final Path original;
18
+ private final String fileContents;
19
+
20
+ public DummyPath(Path original, String fileContents)
21
+ {
22
+ this.original = original;
23
+ this.fileContents = fileContents;
24
+ }
25
+
26
+ @Override
27
+ public int compareTo(Path other)
28
+ {
29
+ return original.compareTo(other);
30
+ }
31
+
32
+ @Override
33
+ public boolean endsWith(Path other)
34
+ {
35
+ return original.endsWith(other);
36
+ }
37
+
38
+ @Override
39
+ public boolean endsWith(String other)
40
+ {
41
+ return original.endsWith(other);
42
+ }
43
+
44
+ @Override
45
+ public Path getFileName()
46
+ {
47
+ return original.getFileName();
48
+ }
49
+
50
+ @Override
51
+ public FileSystem getFileSystem()
52
+ {
53
+ return new DummyFileSystem(original.getFileSystem(), fileContents);
54
+ }
55
+
56
+ @Override
57
+ public Path getName(int index)
58
+ {
59
+ return original.getName(index);
60
+ }
61
+
62
+ @Override
63
+ public int getNameCount()
64
+ {
65
+ return original.getNameCount();
66
+ }
67
+
68
+ @Override
69
+ public Path getParent()
70
+ {
71
+ return original.getParent();
72
+ }
73
+
74
+ @Override
75
+ public Path getRoot()
76
+ {
77
+ return original.getRoot();
78
+ }
79
+
80
+ @Override
81
+ public boolean isAbsolute()
82
+ {
83
+ return original.isAbsolute();
84
+ }
85
+
86
+ @Override
87
+ public Iterator<Path> iterator()
88
+ {
89
+ return original.iterator();
90
+ }
91
+
92
+ @Override
93
+ public Path normalize()
94
+ {
95
+ return original.normalize();
96
+ }
97
+
98
+ @Override
99
+ public WatchKey register(WatchService watcher, Kind<?>... events) throws IOException
100
+ {
101
+ return original.register(watcher, events);
102
+ }
103
+
104
+ @Override
105
+ public WatchKey register(WatchService watcher, Kind<?>[] events, Modifier... modifiers) throws IOException
106
+ {
107
+ return original.register(watcher, events, modifiers);
108
+ }
109
+
110
+ @Override
111
+ public Path relativize(Path other)
112
+ {
113
+ return original.relativize(other);
114
+ }
115
+
116
+ @Override
117
+ public Path resolve(Path other)
118
+ {
119
+ return original.resolve(other);
120
+ }
121
+
122
+ @Override
123
+ public Path resolve(String other)
124
+ {
125
+ return original.resolve(other);
126
+ }
127
+
128
+ @Override
129
+ public Path resolveSibling(Path other)
130
+ {
131
+ return original.resolveSibling(other);
132
+ }
133
+
134
+ @Override
135
+ public Path resolveSibling(String other)
136
+ {
137
+ return original.resolveSibling(other);
138
+ }
139
+
140
+ @Override
141
+ public boolean startsWith(Path other)
142
+ {
143
+ return original.startsWith(other);
144
+ }
145
+
146
+ @Override
147
+ public boolean startsWith(String other)
148
+ {
149
+ return original.startsWith(other);
150
+ }
151
+
152
+ @Override
153
+ public Path subpath(int beginIndex, int endIndex)
154
+ {
155
+ return original.subpath(beginIndex, endIndex);
156
+ }
157
+
158
+ @Override
159
+ public Path toAbsolutePath()
160
+ {
161
+ return original.toAbsolutePath();
162
+ }
163
+
164
+ @Override
165
+ public File toFile()
166
+ {
167
+ return original.toFile();
168
+ }
169
+
170
+ @Override
171
+ public Path toRealPath(LinkOption... options) throws IOException
172
+ {
173
+ return original.toRealPath(options);
174
+ }
175
+
176
+ @Override
177
+ public URI toUri()
178
+ {
179
+ return original.toUri();
180
+ }
181
+
182
+ @Override
183
+ public String toString()
184
+ {
185
+ return original.toString();
186
+ }
187
+
188
+ }
@@ -0,0 +1,90 @@
1
+ package org.embulk.output.oracle;
2
+
3
+ import com.google.common.base.Throwables;
4
+ import com.google.common.io.ByteStreams;
5
+
6
+ import org.embulk.config.ConfigSource;
7
+ import org.embulk.test.EmbulkTests;
8
+ import org.embulk.test.TestingEmbulk;
9
+
10
+ import java.io.IOException;
11
+ import java.nio.charset.Charset;
12
+ import java.nio.file.Files;
13
+ import java.nio.file.Path;
14
+ import java.util.Arrays;
15
+
16
+ import static java.util.Locale.ENGLISH;
17
+
18
+ public class OracleTests
19
+ {
20
+ public static ConfigSource baseConfig()
21
+ {
22
+ return EmbulkTests.config("EMBULK_OUTPUT_ORACLE_TEST_CONFIG");
23
+ }
24
+
25
+ public static void execute(TestingEmbulk embulk, String sql) throws IOException
26
+ {
27
+ try {
28
+ Class.forName("oracle.jdbc.OracleDriver");
29
+ } catch (ClassNotFoundException e) {
30
+ throw new RuntimeException("You should put 'ojdbc7.jar' in 'embulk-output-oracle/driver' directory in order to test.");
31
+ }
32
+
33
+ Path sqlFile = embulk.createTempFile("sql");
34
+ Files.write(sqlFile, Arrays.asList(sql), Charset.forName("UTF8"));
35
+
36
+ ConfigSource config = baseConfig();
37
+ String host = config.get(String.class, "host");
38
+ String port = config.get(String.class, "port", "1521");
39
+ String user = config.get(String.class, "user");
40
+ String password = config.get(String.class, "password");
41
+ String database = config.get(String.class, "database");
42
+
43
+ ProcessBuilder pb = new ProcessBuilder(
44
+ "sql",
45
+ user + "/" + password + "@" + host + ":" + port + "/" + database,
46
+ "@" + sqlFile.toFile().getAbsolutePath());
47
+ pb.environment().put("JAVA_TOOL_OPTIONS", "-Dfile.encoding=UTF8");
48
+ pb.redirectErrorStream(true);
49
+ int code;
50
+ try {
51
+ Process process = pb.start();
52
+ ByteStreams.copy(process.getInputStream(), System.out);
53
+ code = process.waitFor();
54
+ } catch (IOException | InterruptedException ex) {
55
+ throw Throwables.propagate(ex);
56
+ }
57
+ if (code != 0) {
58
+ throw new RuntimeException(String.format(ENGLISH,
59
+ "Command finished with non-zero exit code. Exit code is %d.", code));
60
+ }
61
+ }
62
+
63
+ public static String selectRecords(TestingEmbulk embulk, String tableName) throws IOException
64
+ {
65
+ Path temp = embulk.createTempFile("txt");
66
+ Files.delete(temp);
67
+
68
+ StringBuilder sql = new StringBuilder();
69
+ sql.append("SPOOL '" + temp.toString() + "'");
70
+ sql.append(System.lineSeparator());
71
+ sql.append("SET FEEDBACK OFF");
72
+ sql.append(System.lineSeparator());
73
+ sql.append("SET HEADING OFF");
74
+ sql.append(System.lineSeparator());
75
+ sql.append("SET PAGESIZE 0");
76
+ sql.append(System.lineSeparator());
77
+ sql.append("SET LINESIZE 1000");
78
+ sql.append(System.lineSeparator());
79
+ sql.append("SET COLSEP ','");
80
+ sql.append(System.lineSeparator());
81
+ sql.append("SET TRIMSPOOL ON");
82
+ sql.append(System.lineSeparator());
83
+ sql.append("SELECT * FROM " + tableName + ";");
84
+ sql.append(System.lineSeparator());
85
+ sql.append("EXIT;");
86
+ execute(embulk, sql.toString());
87
+
88
+ return EmbulkTests.readSortedFile(temp);
89
+ }
90
+ }