@jwplayer/jwplayer-react-native 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/.github/CODEOWNERS +2 -0
  2. package/.github/ISSUE_TEMPLATE/bug_report.md +38 -0
  3. package/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  4. package/.github/ISSUE_TEMPLATE/question.md +11 -0
  5. package/.github/PULL_REQUEST_TEMPLATE.md +15 -0
  6. package/CODE_OF_CONDUCT.md +128 -0
  7. package/LICENSE +21 -0
  8. package/README.md +425 -0
  9. package/RNJWPlayer.podspec +44 -0
  10. package/android/.gradle/8.1.1/checksums/checksums.lock +0 -0
  11. package/android/.gradle/8.1.1/dependencies-accessors/dependencies-accessors.lock +0 -0
  12. package/android/.gradle/8.1.1/dependencies-accessors/gc.properties +0 -0
  13. package/android/.gradle/8.1.1/fileChanges/last-build.bin +0 -0
  14. package/android/.gradle/8.1.1/fileHashes/fileHashes.lock +0 -0
  15. package/android/.gradle/8.1.1/gc.properties +0 -0
  16. package/android/.gradle/8.2/checksums/checksums.lock +0 -0
  17. package/android/.gradle/8.2/dependencies-accessors/dependencies-accessors.lock +0 -0
  18. package/android/.gradle/8.2/dependencies-accessors/gc.properties +0 -0
  19. package/android/.gradle/8.2/fileChanges/last-build.bin +0 -0
  20. package/android/.gradle/8.2/fileHashes/fileHashes.lock +0 -0
  21. package/android/.gradle/8.2/gc.properties +0 -0
  22. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  23. package/android/.gradle/buildOutputCleanup/cache.properties +2 -0
  24. package/android/.gradle/config.properties +2 -0
  25. package/android/.gradle/vcs-1/gc.properties +0 -0
  26. package/android/.idea/gradle.xml +12 -0
  27. package/android/.idea/migrations.xml +10 -0
  28. package/android/.idea/misc.xml +10 -0
  29. package/android/.idea/vcs.xml +6 -0
  30. package/android/.idea/workspace.xml +54 -0
  31. package/android/build.gradle +110 -0
  32. package/android/local.properties +8 -0
  33. package/android/src/main/AndroidManifest.xml +25 -0
  34. package/android/src/main/java/com/jwplayer/rnjwplayer/ArrayUtil.java +129 -0
  35. package/android/src/main/java/com/jwplayer/rnjwplayer/CastOptionsProvider.java +55 -0
  36. package/android/src/main/java/com/jwplayer/rnjwplayer/MapUtil.java +136 -0
  37. package/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayer.java +76 -0
  38. package/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerAds.java +239 -0
  39. package/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerModule.java +526 -0
  40. package/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerPackage.java +30 -0
  41. package/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerView.java +1499 -0
  42. package/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerViewManager.java +171 -0
  43. package/android/src/main/java/com/jwplayer/rnjwplayer/Util.java +219 -0
  44. package/android/src/main/java/com/jwplayer/rnjwplayer/WidevineCallback.java +62 -0
  45. package/badges/license.svg +1 -0
  46. package/badges/version.svg +1 -0
  47. package/docs/legacy_readme.md +634 -0
  48. package/docs/props.md +43 -0
  49. package/docs/types.md +254 -0
  50. package/index.d.ts +564 -0
  51. package/index.js +699 -0
  52. package/ios/RNJWPlayer/RCTConvert+RNJWPlayer.swift +119 -0
  53. package/ios/RNJWPlayer/RNJWPlayer-Bridging-Header.h +5 -0
  54. package/ios/RNJWPlayer/RNJWPlayerAds.swift +260 -0
  55. package/ios/RNJWPlayer/RNJWPlayerModels.swift +149 -0
  56. package/ios/RNJWPlayer/RNJWPlayerView.swift +1837 -0
  57. package/ios/RNJWPlayer/RNJWPlayerViewController.swift +616 -0
  58. package/ios/RNJWPlayer/RNJWPlayerViewManager.m +132 -0
  59. package/ios/RNJWPlayer/RNJWPlayerViewManager.swift +500 -0
  60. package/ios/RNJWPlayer.xcodeproj/project.pbxproj +323 -0
  61. package/package.json +45 -0
@@ -0,0 +1,171 @@
1
+
2
+ package com.jwplayer.rnjwplayer;
3
+
4
+ import com.facebook.react.bridge.ReactApplicationContext;
5
+ import com.facebook.react.bridge.ReadableMap;
6
+ import com.facebook.react.common.MapBuilder;
7
+ import com.facebook.react.uimanager.SimpleViewManager;
8
+ import com.facebook.react.uimanager.ThemedReactContext;
9
+ import com.facebook.react.uimanager.annotations.ReactProp;
10
+
11
+ import java.util.Map;
12
+
13
+ import javax.annotation.Nonnull;
14
+
15
+ public class RNJWPlayerViewManager extends SimpleViewManager<RNJWPlayerView> {
16
+
17
+ public static final String REACT_CLASS = "RNJWPlayerView";
18
+
19
+ private final ReactApplicationContext mAppContext;
20
+
21
+ private static final String TAG = "RNJWPlayerViewManager";
22
+
23
+ @Override
24
+ public String getName() {
25
+ return REACT_CLASS;
26
+ }
27
+
28
+ public RNJWPlayerViewManager(ReactApplicationContext context) {
29
+ mAppContext = context;
30
+ }
31
+
32
+ @Override
33
+ public RNJWPlayerView createViewInstance(ThemedReactContext context) {
34
+ return new RNJWPlayerView(context, mAppContext);
35
+ }
36
+
37
+ @ReactProp(name = "config")
38
+ public void setConfig(RNJWPlayerView view, ReadableMap prop) {
39
+ view.setConfig(prop);
40
+ }
41
+
42
+ @ReactProp(name = "controls")
43
+ public void setControls(RNJWPlayerView view, Boolean controls) {
44
+ view.mPlayerView.getPlayer().setControls(controls);
45
+ }
46
+
47
+ public Map getExportedCustomBubblingEventTypeConstants() {
48
+ return MapBuilder.builder()
49
+ .put(
50
+ "topPlayerError",
51
+ MapBuilder.of(
52
+ "phasedRegistrationNames",
53
+ MapBuilder.of("bubbled", "onPlayerError")))
54
+ .put("topSetupPlayerError",
55
+ MapBuilder.of(
56
+ "phasedRegistrationNames",
57
+ MapBuilder.of("bubbled", "onSetupPlayerError")))
58
+ .put("topPlayerAdError",
59
+ MapBuilder.of(
60
+ "phasedRegistrationNames",
61
+ MapBuilder.of("bubbled", "onPlayerAdError")))
62
+ .put("topPlayerAdWarning",
63
+ MapBuilder.of(
64
+ "phasedRegistrationNames",
65
+ MapBuilder.of("bubbled", "onPlayerAdWarning")))
66
+ .put("topAdEvent",
67
+ MapBuilder.of(
68
+ "phasedRegistrationNames",
69
+ MapBuilder.of("bubbled", "onAdEvent")))
70
+ .put("topAdTime",
71
+ MapBuilder.of(
72
+ "phasedRegistrationNames",
73
+ MapBuilder.of("bubbled", "onAdTime")))
74
+ .put("topTime",
75
+ MapBuilder.of(
76
+ "phasedRegistrationNames",
77
+ MapBuilder.of("bubbled", "onTime")))
78
+ .put("topBuffer",
79
+ MapBuilder.of(
80
+ "phasedRegistrationNames",
81
+ MapBuilder.of("bubbled", "onBuffer")))
82
+ .put("topFullScreen",
83
+ MapBuilder.of(
84
+ "phasedRegistrationNames",
85
+ MapBuilder.of("bubbled", "onFullScreen")))
86
+ .put("topFullScreenExitRequested",
87
+ MapBuilder.of(
88
+ "phasedRegistrationNames",
89
+ MapBuilder.of("bubbled", "onFullScreenExitRequested")))
90
+ .put("topFullScreenRequested",
91
+ MapBuilder.of(
92
+ "phasedRegistrationNames",
93
+ MapBuilder.of("bubbled", "onFullScreenRequested")))
94
+ .put("topFullScreenExit",
95
+ MapBuilder.of(
96
+ "phasedRegistrationNames",
97
+ MapBuilder.of("bubbled", "onFullScreenExit")))
98
+ .put("topPause",
99
+ MapBuilder.of(
100
+ "phasedRegistrationNames",
101
+ MapBuilder.of("bubbled", "onPause")))
102
+ .put("topPlay",
103
+ MapBuilder.of(
104
+ "phasedRegistrationNames",
105
+ MapBuilder.of("bubbled", "onPlay")))
106
+ .put("topComplete",
107
+ MapBuilder.of(
108
+ "phasedRegistrationNames",
109
+ MapBuilder.of("bubbled", "onComplete")))
110
+ .put("topPlaylistComplete",
111
+ MapBuilder.of(
112
+ "phasedRegistrationNames",
113
+ MapBuilder.of("bubbled", "onPlaylistComplete")))
114
+ .put("topPlaylistItem",
115
+ MapBuilder.of(
116
+ "phasedRegistrationNames",
117
+ MapBuilder.of("bubbled", "onPlaylistItem")))
118
+ .put("topSeek",
119
+ MapBuilder.of(
120
+ "phasedRegistrationNames",
121
+ MapBuilder.of("bubbled", "onSeek")))
122
+ .put("topSeeked",
123
+ MapBuilder.of(
124
+ "phasedRegistrationNames",
125
+ MapBuilder.of("bubbled", "onSeeked")))
126
+ .put("topRateChanged",
127
+ MapBuilder.of(
128
+ "phasedRegistrationNames",
129
+ MapBuilder.of("bubbled", "onRateChanged")))
130
+ .put("topControlBarVisible",
131
+ MapBuilder.of(
132
+ "phasedRegistrationNames",
133
+ MapBuilder.of("bubbled", "onControlBarVisible")))
134
+ .put("topOnPlayerReady",
135
+ MapBuilder.of(
136
+ "phasedRegistrationNames",
137
+ MapBuilder.of("bubbled", "onPlayerReady")))
138
+ .put("topBeforePlay",
139
+ MapBuilder.of(
140
+ "phasedRegistrationNames",
141
+ MapBuilder.of("bubbled", "onBeforePlay")))
142
+ .put("topBeforeComplete",
143
+ MapBuilder.of(
144
+ "phasedRegistrationNames",
145
+ MapBuilder.of("bubbled", "onBeforeComplete")))
146
+ .put("topAdPlay",
147
+ MapBuilder.of(
148
+ "phasedRegistrationNames",
149
+ MapBuilder.of("bubbled", "onAdPlay")))
150
+ .put("topAdPause",
151
+ MapBuilder.of(
152
+ "phasedRegistrationNames",
153
+ MapBuilder.of("bubbled", "onAdPause")))
154
+ .put("topAudioTracks",
155
+ MapBuilder.of(
156
+ "phasedRegistrationNames",
157
+ MapBuilder.of("bubbled", "onAudioTracks")))
158
+ .put("topCasting",
159
+ MapBuilder.of(
160
+ "phasedRegistrationNames",
161
+ MapBuilder.of("bubbled", "onCasting")))
162
+ .build();
163
+ }
164
+
165
+ @Override
166
+ public void onDropViewInstance(@Nonnull RNJWPlayerView view) {
167
+ view.destroyPlayer();
168
+ super.onDropViewInstance(view);
169
+ view = null;
170
+ }
171
+ }
@@ -0,0 +1,219 @@
1
+ package com.jwplayer.rnjwplayer;
2
+
3
+ import static androidx.media3.common.util.Util.toByteArray;
4
+
5
+ import android.util.Patterns;
6
+ import android.webkit.URLUtil;
7
+
8
+ import com.facebook.react.bridge.ReadableArray;
9
+ import com.facebook.react.bridge.ReadableMap;
10
+ import com.jwplayer.pub.api.media.ads.AdBreak;
11
+ import com.jwplayer.pub.api.media.captions.Caption;
12
+ import com.jwplayer.pub.api.media.captions.CaptionType;
13
+ import com.jwplayer.pub.api.media.playlists.MediaSource;
14
+ import com.jwplayer.pub.api.media.playlists.PlaylistItem;
15
+
16
+ import java.io.IOException;
17
+ import java.io.InputStream;
18
+ import java.io.OutputStream;
19
+ import java.net.HttpURLConnection;
20
+ import java.net.URL;
21
+ import java.util.ArrayList;
22
+ import java.util.List;
23
+ import java.util.Map;
24
+
25
+ public class Util {
26
+
27
+ public static byte[] executePost(String url, byte[] data, Map<String, String> requestProperties)
28
+ throws IOException {
29
+ HttpURLConnection urlConnection = null;
30
+ try {
31
+ urlConnection = (HttpURLConnection) new URL(url).openConnection();
32
+ urlConnection.setRequestMethod("POST");
33
+ urlConnection.setDoOutput(data != null);
34
+ urlConnection.setDoInput(true);
35
+ if (requestProperties != null) {
36
+ for (Map.Entry<String, String> requestProperty : requestProperties.entrySet()) {
37
+ urlConnection.setRequestProperty(requestProperty.getKey(),
38
+ requestProperty.getValue());
39
+ }
40
+ }
41
+ // Write the request body, if there is one.
42
+ if (data != null) {
43
+ OutputStream out = urlConnection.getOutputStream();
44
+ try {
45
+ out.write(data);
46
+ } finally {
47
+ out.close();
48
+ }
49
+ }
50
+ // Read and return the response body.
51
+ InputStream inputStream = urlConnection.getInputStream();
52
+ try {
53
+ return toByteArray(inputStream);
54
+ } finally {
55
+ inputStream.close();
56
+ }
57
+ } finally {
58
+ if (urlConnection != null) {
59
+ urlConnection.disconnect();
60
+ }
61
+ }
62
+ }
63
+
64
+ public static boolean isValidURL(String url){
65
+ return URLUtil.isValidUrl(url) && Patterns.WEB_URL.matcher(url).matches();
66
+ }
67
+
68
+ public static List<PlaylistItem> createPlaylist(ReadableArray playlistItems) {
69
+ List<PlaylistItem> playlist = new ArrayList<>();
70
+ if (playlistItems == null || playlistItems.size() <= 0)
71
+ return playlist;
72
+
73
+ int j = 0;
74
+ while (playlistItems.size() > j) {
75
+ ReadableMap playlistItem = playlistItems.getMap(j);
76
+
77
+ PlaylistItem newPlayListItem = getPlaylistItem((playlistItem));
78
+ playlist.add(newPlayListItem);
79
+ j++;
80
+ }
81
+ return playlist;
82
+ }
83
+
84
+ public static PlaylistItem getPlaylistItem (ReadableMap playlistItem) {
85
+ PlaylistItem.Builder itemBuilder = new PlaylistItem.Builder();
86
+
87
+ if (playlistItem.hasKey("file")) {
88
+ String file = playlistItem.getString("file");
89
+ itemBuilder.file(file);
90
+ }
91
+
92
+ if (playlistItem.hasKey("sources")) {
93
+ ArrayList<MediaSource> sources = new ArrayList<>();
94
+ ReadableArray sourcesArray = playlistItem.getArray("sources");
95
+ if (sourcesArray != null) {
96
+ for (int i = 0; i < sourcesArray.size(); i++) {
97
+ ReadableMap sourceProp = sourcesArray.getMap(i);
98
+ if (sourceProp.hasKey("file")) {
99
+ String file = sourceProp.getString("file");
100
+ String label = sourceProp.getString("label");
101
+ boolean isDefault = sourceProp.getBoolean("default");
102
+ MediaSource source = new MediaSource.Builder().file(file).label(label).isDefault(isDefault).build();
103
+ sources.add(source);
104
+ }
105
+ }
106
+ }
107
+
108
+ itemBuilder.sources(sources);
109
+ }
110
+
111
+ if (playlistItem.hasKey("title")) {
112
+ String title = playlistItem.getString("title");
113
+ itemBuilder.title(title);
114
+ }
115
+
116
+ if (playlistItem.hasKey("description")) {
117
+ String desc = playlistItem.getString("description");
118
+ itemBuilder.description(desc);
119
+ }
120
+
121
+ if (playlistItem.hasKey("image")) {
122
+ String image = playlistItem.getString("image");
123
+ itemBuilder.image(image);
124
+ }
125
+
126
+ if (playlistItem.hasKey("mediaId")) {
127
+ String mediaId = playlistItem.getString("mediaId");
128
+ itemBuilder.mediaId(mediaId);
129
+ }
130
+
131
+ if (playlistItem.hasKey("startTime")) {
132
+ double startTime = playlistItem.getDouble("startTime");
133
+ itemBuilder.startTime(startTime);
134
+ }
135
+
136
+ if (playlistItem.hasKey("duration")) {
137
+ int duration = playlistItem.getInt("duration");
138
+ itemBuilder.duration(duration);
139
+ }
140
+
141
+ if (playlistItem.hasKey("tracks")) {
142
+ ArrayList<Caption> tracks = new ArrayList<>();
143
+ ReadableArray track = playlistItem.getArray("tracks");
144
+ if (track != null) {
145
+ for (int i = 0; i < track.size(); i++) {
146
+ ReadableMap trackProp = track.getMap(i);
147
+ if (trackProp.hasKey("file")) {
148
+ String file = trackProp.getString("file");
149
+ String label = trackProp.getString("label");
150
+ boolean isDefault = trackProp.getBoolean("default");
151
+ Caption caption = new Caption.Builder().file(file).label(label).kind(CaptionType.CAPTIONS).isDefault(isDefault).build();
152
+ tracks.add(caption);
153
+ }
154
+ }
155
+ }
156
+
157
+ itemBuilder.tracks(tracks);
158
+ }
159
+
160
+ if (playlistItem.hasKey("authUrl")) {
161
+ itemBuilder.mediaDrmCallback(new WidevineCallback(playlistItem.getString("authUrl")));
162
+ }
163
+
164
+ if (playlistItem.hasKey("adSchedule")) {
165
+ ArrayList<AdBreak> adSchedule = new ArrayList<>();
166
+ ReadableArray ad = playlistItem.getArray("adSchedule");
167
+
168
+ for (int i = 0; i < ad.size(); i++) {
169
+ ReadableMap adBreakProp = ad.getMap(i);
170
+ String offset = adBreakProp.hasKey("offset") ? adBreakProp.getString("offset") : "pre";
171
+ if (adBreakProp.hasKey("tag")) {
172
+ AdBreak adBreak = new AdBreak.Builder().offset(offset).tag(adBreakProp.getString("tag")).build();
173
+ adSchedule.add(adBreak);
174
+ }
175
+ }
176
+
177
+ itemBuilder.adSchedule(adSchedule);
178
+ }
179
+
180
+ String recommendations;
181
+ if (playlistItem.hasKey("recommendations")) {
182
+ recommendations = playlistItem.getString("recommendations");
183
+ itemBuilder.recommendations(recommendations);
184
+ }
185
+
186
+ return itemBuilder.build();
187
+ }
188
+
189
+ public enum AdEventType {
190
+ JWAdEventTypeAdBreakEnd(0),
191
+ JWAdEventTypeAdBreakStart(1),
192
+ JWAdEventTypeClicked(2),
193
+ JWAdEventTypeComplete(3),
194
+ JWAdEventTypeImpression(4),
195
+ JWAdEventTypeMeta(5),
196
+ JWAdEventTypePause(6),
197
+ JWAdEventTypePlay(7),
198
+ JWAdEventTypeRequest(8),
199
+ JWAdEventTypeSchedule(9),
200
+ JWAdEventTypeSkipped(10),
201
+ JWAdEventTypeStarted(11),
202
+ JWAdEventTypeCompanion(12);
203
+
204
+ private final int value;
205
+
206
+ AdEventType(int value) {
207
+ this.value = value;
208
+ }
209
+
210
+ public int getValue() {
211
+ return value;
212
+ }
213
+ }
214
+
215
+ // Method to get the event type value
216
+ public static int getEventTypeValue(AdEventType eventType) {
217
+ return eventType.getValue();
218
+ }
219
+ }
@@ -0,0 +1,62 @@
1
+ package com.jwplayer.rnjwplayer;
2
+
3
+ import android.annotation.TargetApi;
4
+ import android.os.Parcel;
5
+ import android.text.TextUtils;
6
+
7
+ import androidx.media3.exoplayer.drm.ExoMediaDrm;
8
+ import com.jwplayer.pub.api.media.drm.MediaDrmCallback;
9
+
10
+ import java.io.IOException;
11
+ import java.util.UUID;
12
+
13
+ @TargetApi(18)
14
+ public class WidevineCallback implements MediaDrmCallback {
15
+
16
+ private final String defaultUri;
17
+
18
+ public WidevineCallback(String drmAuthUrl) {
19
+ defaultUri = drmAuthUrl;
20
+ }
21
+
22
+ protected WidevineCallback(Parcel in) {
23
+ defaultUri = in.readString();
24
+ }
25
+
26
+ public static final Creator<WidevineCallback> CREATOR = new Creator<WidevineCallback>() {
27
+ @Override
28
+ public WidevineCallback createFromParcel(Parcel in) {
29
+ return new WidevineCallback(in);
30
+ }
31
+
32
+ @Override
33
+ public WidevineCallback[] newArray(int size) {
34
+ return new WidevineCallback[size];
35
+ }
36
+ };
37
+
38
+ @Override
39
+ public byte[] executeProvisionRequest(UUID uuid, ExoMediaDrm.ProvisionRequest request) throws IOException {
40
+ String url = request.getDefaultUrl() + "&signedRequest=" + new String(request.getData());
41
+ return Util.executePost(url, null, null);
42
+ }
43
+
44
+ @Override
45
+ public byte[] executeKeyRequest(UUID uuid, ExoMediaDrm.KeyRequest request) throws IOException {
46
+ String url = request.getLicenseServerUrl();
47
+ if (TextUtils.isEmpty(url)) {
48
+ url = defaultUri;
49
+ }
50
+ return Util.executePost(url, request.getData(), null);
51
+ }
52
+
53
+ @Override
54
+ public int describeContents() {
55
+ return 0;
56
+ }
57
+
58
+ @Override
59
+ public void writeToParcel(Parcel dest, int flags) {
60
+ dest.writeString(defaultUri);
61
+ }
62
+ }
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="78" height="20" role="img" aria-label="license: MIT"><title>license: MIT</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="78" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="47" height="20" fill="#555"/><rect x="47" width="31" height="20" fill="#97ca00"/><rect width="78" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text aria-hidden="true" x="245" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="370">license</text><text x="245" y="140" transform="scale(.1)" fill="#fff" textLength="370">license</text><text aria-hidden="true" x="615" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="210">MIT</text><text x="615" y="140" transform="scale(.1)" fill="#fff" textLength="210">MIT</text></g></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="90" height="20" role="img" aria-label="version: 1.0.0"><title>version: 1.0.0</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="90" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="51" height="20" fill="#555"/><rect x="51" width="39" height="20" fill="#007ec6"/><rect width="90" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text aria-hidden="true" x="265" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="410">version</text><text x="265" y="140" transform="scale(.1)" fill="#fff" textLength="410">version</text><text aria-hidden="true" x="695" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="290">1.0.0</text><text x="695" y="140" transform="scale(.1)" fill="#fff" textLength="290">1.0.0</text></g></svg>