@josuelmm/cordova-background-geolocation 3.1.0 → 3.2.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.
- package/CHANGELOG.md +55 -0
- package/HISTORY.md +6 -0
- package/README.md +62 -9
- package/RELEASE.MD +15 -4
- package/android/CDVBackgroundGeolocation/src/main/java/com/marianhello/bgloc/cordova/ConfigMapper.java +8 -0
- package/android/CDVBackgroundGeolocation/src/main/java/com/tenforwardconsulting/bgloc/cordova/BackgroundGeolocationPlugin.java +57 -1
- package/android/common/src/main/java/com/marianhello/bgloc/BackgroundGeolocationFacade.java +26 -0
- package/android/common/src/main/java/com/marianhello/bgloc/Config.java +44 -0
- package/android/common/src/main/java/com/marianhello/bgloc/PostLocationTask.java +13 -0
- package/android/common/src/main/java/com/marianhello/bgloc/data/SessionLocationDAO.java +18 -0
- package/android/common/src/main/java/com/marianhello/bgloc/data/sqlite/SQLiteConfigurationContract.java +5 -1
- package/android/common/src/main/java/com/marianhello/bgloc/data/sqlite/SQLiteConfigurationDAO.java +13 -1
- package/android/common/src/main/java/com/marianhello/bgloc/data/sqlite/SQLiteOpenHelper.java +13 -1
- package/android/common/src/main/java/com/marianhello/bgloc/data/sqlite/SQLiteSessionContract.java +74 -0
- package/android/common/src/main/java/com/marianhello/bgloc/data/sqlite/SQLiteSessionLocationDAO.java +169 -0
- package/android/common/src/main/java/com/marianhello/bgloc/service/LocationServiceImpl.java +132 -4
- package/angular/background-geolocation.service.ts +28 -0
- package/angular/dist/background-geolocation.service.d.ts +4 -0
- package/angular/dist/esm2022/background-geolocation.service.mjs +13 -1
- package/angular/dist/fesm2022/josuelmm-cordova-background-geolocation.mjs +12 -0
- package/angular/dist/fesm2022/josuelmm-cordova-background-geolocation.mjs.map +1 -1
- package/angular/dist/public-api.d.ts +1 -1
- package/ios/CDVBackgroundGeolocation/CDVBackgroundGeolocation.h +4 -0
- package/ios/CDVBackgroundGeolocation/CDVBackgroundGeolocation.m +41 -1
- package/ios/common/BackgroundGeolocation/MAURBackgroundGeolocationFacade.h +4 -0
- package/ios/common/BackgroundGeolocation/MAURBackgroundGeolocationFacade.m +21 -0
- package/ios/common/BackgroundGeolocation/MAURGeolocationOpenHelper.m +12 -3
- package/ios/common/BackgroundGeolocation/MAURPostLocationTask.m +5 -0
- package/ios/common/BackgroundGeolocation/MAURSessionLocationContract.h +29 -0
- package/ios/common/BackgroundGeolocation/MAURSessionLocationContract.m +31 -0
- package/ios/common/BackgroundGeolocation/MAURSessionLocationDAO.h +25 -0
- package/ios/common/BackgroundGeolocation/MAURSessionLocationDAO.m +153 -0
- package/package.json +7 -3
- package/plugin.xml +8 -1
- package/www/BackgroundGeolocation.d.ts +60 -0
- package/www/BackgroundGeolocation.js +24 -0
- package/www/cordova-channel-stub.js +27 -0
- package/www/cordova-exec-stub.js +15 -0
package/android/common/src/main/java/com/marianhello/bgloc/data/sqlite/SQLiteSessionContract.java
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
package com.marianhello.bgloc.data.sqlite;
|
|
2
|
+
|
|
3
|
+
import android.provider.BaseColumns;
|
|
4
|
+
|
|
5
|
+
import static com.marianhello.bgloc.data.sqlite.SQLiteOpenHelper.COMMA_SEP;
|
|
6
|
+
import static com.marianhello.bgloc.data.sqlite.SQLiteOpenHelper.INTEGER_TYPE;
|
|
7
|
+
import static com.marianhello.bgloc.data.sqlite.SQLiteOpenHelper.REAL_TYPE;
|
|
8
|
+
import static com.marianhello.bgloc.data.sqlite.SQLiteOpenHelper.TEXT_TYPE;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Contract for the "session" location table.
|
|
12
|
+
* Stores all locations for the current recording session (route).
|
|
13
|
+
* Cleared on startSession() and clearSession(); not cleared when sync succeeds.
|
|
14
|
+
*/
|
|
15
|
+
public final class SQLiteSessionContract {
|
|
16
|
+
|
|
17
|
+
public SQLiteSessionContract() {}
|
|
18
|
+
|
|
19
|
+
public static abstract class SessionEntry implements BaseColumns {
|
|
20
|
+
public static final String TABLE_NAME = "location_session";
|
|
21
|
+
public static final String COLUMN_NAME_NULLABLE = "NULLHACK";
|
|
22
|
+
public static final String COLUMN_NAME_TIME = "time";
|
|
23
|
+
public static final String COLUMN_NAME_ACCURACY = "accuracy";
|
|
24
|
+
public static final String COLUMN_NAME_VERTICAL_ACCURACY = "vertical_accuracy";
|
|
25
|
+
public static final String COLUMN_NAME_SPEED = "speed";
|
|
26
|
+
public static final String COLUMN_NAME_BEARING = "bearing";
|
|
27
|
+
public static final String COLUMN_NAME_ALTITUDE = "altitude";
|
|
28
|
+
public static final String COLUMN_NAME_LATITUDE = "latitude";
|
|
29
|
+
public static final String COLUMN_NAME_LONGITUDE = "longitude";
|
|
30
|
+
public static final String COLUMN_NAME_RADIUS = "radius";
|
|
31
|
+
public static final String COLUMN_NAME_HAS_ACCURACY = "has_accuracy";
|
|
32
|
+
public static final String COLUMN_NAME_HAS_VERTICAL_ACCURACY = "has_vertical_accuracy";
|
|
33
|
+
public static final String COLUMN_NAME_HAS_SPEED = "has_speed";
|
|
34
|
+
public static final String COLUMN_NAME_HAS_BEARING = "has_bearing";
|
|
35
|
+
public static final String COLUMN_NAME_HAS_ALTITUDE = "has_altitude";
|
|
36
|
+
public static final String COLUMN_NAME_HAS_RADIUS = "has_radius";
|
|
37
|
+
public static final String COLUMN_NAME_PROVIDER = "provider";
|
|
38
|
+
public static final String COLUMN_NAME_LOCATION_PROVIDER = "service_provider";
|
|
39
|
+
public static final String COLUMN_NAME_STATUS = "valid";
|
|
40
|
+
public static final String COLUMN_NAME_BATCH_START_MILLIS = "batch_start";
|
|
41
|
+
public static final String COLUMN_NAME_MOCK_FLAGS = "mock_flags";
|
|
42
|
+
|
|
43
|
+
public static final String SQL_CREATE_SESSION_TABLE =
|
|
44
|
+
"CREATE TABLE " + SessionEntry.TABLE_NAME + " (" +
|
|
45
|
+
SessionEntry._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
|
|
46
|
+
SessionEntry.COLUMN_NAME_TIME + INTEGER_TYPE + COMMA_SEP +
|
|
47
|
+
SessionEntry.COLUMN_NAME_ACCURACY + REAL_TYPE + COMMA_SEP +
|
|
48
|
+
SessionEntry.COLUMN_NAME_VERTICAL_ACCURACY + REAL_TYPE + COMMA_SEP +
|
|
49
|
+
SessionEntry.COLUMN_NAME_SPEED + REAL_TYPE + COMMA_SEP +
|
|
50
|
+
SessionEntry.COLUMN_NAME_BEARING + REAL_TYPE + COMMA_SEP +
|
|
51
|
+
SessionEntry.COLUMN_NAME_ALTITUDE + REAL_TYPE + COMMA_SEP +
|
|
52
|
+
SessionEntry.COLUMN_NAME_LATITUDE + REAL_TYPE + COMMA_SEP +
|
|
53
|
+
SessionEntry.COLUMN_NAME_LONGITUDE + REAL_TYPE + COMMA_SEP +
|
|
54
|
+
SessionEntry.COLUMN_NAME_RADIUS + REAL_TYPE + COMMA_SEP +
|
|
55
|
+
SessionEntry.COLUMN_NAME_HAS_ACCURACY + INTEGER_TYPE + COMMA_SEP +
|
|
56
|
+
SessionEntry.COLUMN_NAME_HAS_VERTICAL_ACCURACY + INTEGER_TYPE + COMMA_SEP +
|
|
57
|
+
SessionEntry.COLUMN_NAME_HAS_SPEED + INTEGER_TYPE + COMMA_SEP +
|
|
58
|
+
SessionEntry.COLUMN_NAME_HAS_BEARING + INTEGER_TYPE + COMMA_SEP +
|
|
59
|
+
SessionEntry.COLUMN_NAME_HAS_ALTITUDE + INTEGER_TYPE + COMMA_SEP +
|
|
60
|
+
SessionEntry.COLUMN_NAME_HAS_RADIUS + INTEGER_TYPE + COMMA_SEP +
|
|
61
|
+
SessionEntry.COLUMN_NAME_PROVIDER + TEXT_TYPE + COMMA_SEP +
|
|
62
|
+
SessionEntry.COLUMN_NAME_LOCATION_PROVIDER + INTEGER_TYPE + COMMA_SEP +
|
|
63
|
+
SessionEntry.COLUMN_NAME_STATUS + INTEGER_TYPE + COMMA_SEP +
|
|
64
|
+
SessionEntry.COLUMN_NAME_BATCH_START_MILLIS + INTEGER_TYPE + COMMA_SEP +
|
|
65
|
+
SessionEntry.COLUMN_NAME_MOCK_FLAGS + INTEGER_TYPE +
|
|
66
|
+
" )";
|
|
67
|
+
|
|
68
|
+
public static final String SQL_DROP_SESSION_TABLE =
|
|
69
|
+
"DROP TABLE IF EXISTS " + SessionEntry.TABLE_NAME;
|
|
70
|
+
|
|
71
|
+
public static final String SQL_CREATE_SESSION_TABLE_TIME_IDX =
|
|
72
|
+
"CREATE INDEX session_time_idx ON " + SessionEntry.TABLE_NAME + " (" + SessionEntry.COLUMN_NAME_TIME + ")";
|
|
73
|
+
}
|
|
74
|
+
}
|
package/android/common/src/main/java/com/marianhello/bgloc/data/sqlite/SQLiteSessionLocationDAO.java
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
package com.marianhello.bgloc.data.sqlite;
|
|
2
|
+
|
|
3
|
+
import android.content.ContentValues;
|
|
4
|
+
import android.content.Context;
|
|
5
|
+
import android.database.Cursor;
|
|
6
|
+
import android.database.sqlite.SQLiteDatabase;
|
|
7
|
+
import com.marianhello.bgloc.data.BackgroundLocation;
|
|
8
|
+
import com.marianhello.bgloc.data.SessionLocationDAO;
|
|
9
|
+
|
|
10
|
+
import java.util.ArrayList;
|
|
11
|
+
import java.util.Collection;
|
|
12
|
+
|
|
13
|
+
public class SQLiteSessionLocationDAO implements SessionLocationDAO {
|
|
14
|
+
|
|
15
|
+
private static final String PREFS_NAME = "bgloc_session";
|
|
16
|
+
private static final String KEY_SESSION_ACTIVE = "session_active";
|
|
17
|
+
|
|
18
|
+
private final SQLiteDatabase db;
|
|
19
|
+
private final Context context;
|
|
20
|
+
|
|
21
|
+
public SQLiteSessionLocationDAO(Context context) {
|
|
22
|
+
this.context = context.getApplicationContext();
|
|
23
|
+
SQLiteOpenHelper helper = SQLiteOpenHelper.getHelper(this.context);
|
|
24
|
+
this.db = helper.getWritableDatabase();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@Override
|
|
28
|
+
public void startSession() {
|
|
29
|
+
db.delete(SQLiteSessionContract.SessionEntry.TABLE_NAME, null, null);
|
|
30
|
+
setSessionActive(true);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@Override
|
|
34
|
+
public void clearSession() {
|
|
35
|
+
db.delete(SQLiteSessionContract.SessionEntry.TABLE_NAME, null, null);
|
|
36
|
+
setSessionActive(false);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
@Override
|
|
40
|
+
public boolean isSessionActive() {
|
|
41
|
+
return context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
|
42
|
+
.getBoolean(KEY_SESSION_ACTIVE, false);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
private void setSessionActive(boolean active) {
|
|
46
|
+
context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
|
47
|
+
.edit()
|
|
48
|
+
.putBoolean(KEY_SESSION_ACTIVE, active)
|
|
49
|
+
.apply();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
@Override
|
|
53
|
+
public void persistSessionLocation(BackgroundLocation location) {
|
|
54
|
+
if (!isSessionActive() || location == null) return;
|
|
55
|
+
ContentValues values = getContentValues(location);
|
|
56
|
+
db.insertOrThrow(SQLiteSessionContract.SessionEntry.TABLE_NAME,
|
|
57
|
+
SQLiteSessionContract.SessionEntry.COLUMN_NAME_NULLABLE, values);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
@Override
|
|
61
|
+
public Collection<BackgroundLocation> getSessionLocations() {
|
|
62
|
+
Collection<BackgroundLocation> locations = new ArrayList<>();
|
|
63
|
+
String orderBy = SQLiteSessionContract.SessionEntry.COLUMN_NAME_TIME + " ASC";
|
|
64
|
+
Cursor cursor = null;
|
|
65
|
+
try {
|
|
66
|
+
cursor = db.query(
|
|
67
|
+
SQLiteSessionContract.SessionEntry.TABLE_NAME,
|
|
68
|
+
queryColumns(),
|
|
69
|
+
null, null, null, null, orderBy);
|
|
70
|
+
while (cursor.moveToNext()) {
|
|
71
|
+
locations.add(hydrate(cursor));
|
|
72
|
+
}
|
|
73
|
+
} finally {
|
|
74
|
+
if (cursor != null) cursor.close();
|
|
75
|
+
}
|
|
76
|
+
return locations;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
@Override
|
|
80
|
+
public int getSessionLocationsCount() {
|
|
81
|
+
Cursor cursor = null;
|
|
82
|
+
try {
|
|
83
|
+
cursor = db.rawQuery("SELECT COUNT(*) FROM " + SQLiteSessionContract.SessionEntry.TABLE_NAME, null);
|
|
84
|
+
return cursor.moveToFirst() ? cursor.getInt(0) : 0;
|
|
85
|
+
} finally {
|
|
86
|
+
if (cursor != null) cursor.close();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
private BackgroundLocation hydrate(Cursor c) {
|
|
91
|
+
BackgroundLocation l = new BackgroundLocation(c.getString(c.getColumnIndex(SQLiteSessionContract.SessionEntry.COLUMN_NAME_PROVIDER)));
|
|
92
|
+
l.setTime(c.getLong(c.getColumnIndex(SQLiteSessionContract.SessionEntry.COLUMN_NAME_TIME)));
|
|
93
|
+
if (c.getInt(c.getColumnIndex(SQLiteSessionContract.SessionEntry.COLUMN_NAME_HAS_ACCURACY)) == 1) {
|
|
94
|
+
l.setAccuracy(c.getFloat(c.getColumnIndex(SQLiteSessionContract.SessionEntry.COLUMN_NAME_ACCURACY)));
|
|
95
|
+
}
|
|
96
|
+
if (c.getInt(c.getColumnIndex(SQLiteSessionContract.SessionEntry.COLUMN_NAME_HAS_VERTICAL_ACCURACY)) == 1) {
|
|
97
|
+
l.setVerticalAccuracy(c.getFloat(c.getColumnIndex(SQLiteSessionContract.SessionEntry.COLUMN_NAME_VERTICAL_ACCURACY)));
|
|
98
|
+
}
|
|
99
|
+
if (c.getInt(c.getColumnIndex(SQLiteSessionContract.SessionEntry.COLUMN_NAME_HAS_SPEED)) == 1) {
|
|
100
|
+
l.setSpeed(c.getFloat(c.getColumnIndex(SQLiteSessionContract.SessionEntry.COLUMN_NAME_SPEED)));
|
|
101
|
+
}
|
|
102
|
+
if (c.getInt(c.getColumnIndex(SQLiteSessionContract.SessionEntry.COLUMN_NAME_HAS_BEARING)) == 1) {
|
|
103
|
+
l.setBearing(c.getFloat(c.getColumnIndex(SQLiteSessionContract.SessionEntry.COLUMN_NAME_BEARING)));
|
|
104
|
+
}
|
|
105
|
+
if (c.getInt(c.getColumnIndex(SQLiteSessionContract.SessionEntry.COLUMN_NAME_HAS_ALTITUDE)) == 1) {
|
|
106
|
+
l.setAltitude(c.getDouble(c.getColumnIndex(SQLiteSessionContract.SessionEntry.COLUMN_NAME_ALTITUDE)));
|
|
107
|
+
}
|
|
108
|
+
if (c.getInt(c.getColumnIndex(SQLiteSessionContract.SessionEntry.COLUMN_NAME_HAS_RADIUS)) == 1) {
|
|
109
|
+
l.setRadius(c.getFloat(c.getColumnIndex(SQLiteSessionContract.SessionEntry.COLUMN_NAME_RADIUS)));
|
|
110
|
+
}
|
|
111
|
+
l.setLatitude(c.getDouble(c.getColumnIndex(SQLiteSessionContract.SessionEntry.COLUMN_NAME_LATITUDE)));
|
|
112
|
+
l.setLongitude(c.getDouble(c.getColumnIndex(SQLiteSessionContract.SessionEntry.COLUMN_NAME_LONGITUDE)));
|
|
113
|
+
l.setLocationProvider(c.getInt(c.getColumnIndex(SQLiteSessionContract.SessionEntry.COLUMN_NAME_LOCATION_PROVIDER)));
|
|
114
|
+
l.setLocationId(c.getLong(c.getColumnIndex(SQLiteSessionContract.SessionEntry._ID)));
|
|
115
|
+
l.setMockFlags(c.getInt(c.getColumnIndex(SQLiteSessionContract.SessionEntry.COLUMN_NAME_MOCK_FLAGS)));
|
|
116
|
+
return l;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
private ContentValues getContentValues(BackgroundLocation l) {
|
|
120
|
+
ContentValues values = new ContentValues();
|
|
121
|
+
values.put(SQLiteSessionContract.SessionEntry.COLUMN_NAME_PROVIDER, l.getProvider());
|
|
122
|
+
values.put(SQLiteSessionContract.SessionEntry.COLUMN_NAME_TIME, l.getTime());
|
|
123
|
+
values.put(SQLiteSessionContract.SessionEntry.COLUMN_NAME_ACCURACY, l.getAccuracy());
|
|
124
|
+
values.put(SQLiteSessionContract.SessionEntry.COLUMN_NAME_VERTICAL_ACCURACY, l.getVerticalAccuracy());
|
|
125
|
+
values.put(SQLiteSessionContract.SessionEntry.COLUMN_NAME_SPEED, l.getSpeed());
|
|
126
|
+
values.put(SQLiteSessionContract.SessionEntry.COLUMN_NAME_BEARING, l.getBearing());
|
|
127
|
+
values.put(SQLiteSessionContract.SessionEntry.COLUMN_NAME_ALTITUDE, l.getAltitude());
|
|
128
|
+
values.put(SQLiteSessionContract.SessionEntry.COLUMN_NAME_RADIUS, l.getRadius());
|
|
129
|
+
values.put(SQLiteSessionContract.SessionEntry.COLUMN_NAME_LATITUDE, l.getLatitude());
|
|
130
|
+
values.put(SQLiteSessionContract.SessionEntry.COLUMN_NAME_LONGITUDE, l.getLongitude());
|
|
131
|
+
values.put(SQLiteSessionContract.SessionEntry.COLUMN_NAME_HAS_ACCURACY, l.hasAccuracy() ? 1 : 0);
|
|
132
|
+
values.put(SQLiteSessionContract.SessionEntry.COLUMN_NAME_HAS_VERTICAL_ACCURACY, l.hasVerticalAccuracy() ? 1 : 0);
|
|
133
|
+
values.put(SQLiteSessionContract.SessionEntry.COLUMN_NAME_HAS_SPEED, l.hasSpeed() ? 1 : 0);
|
|
134
|
+
values.put(SQLiteSessionContract.SessionEntry.COLUMN_NAME_HAS_BEARING, l.hasBearing() ? 1 : 0);
|
|
135
|
+
values.put(SQLiteSessionContract.SessionEntry.COLUMN_NAME_HAS_ALTITUDE, l.hasAltitude() ? 1 : 0);
|
|
136
|
+
values.put(SQLiteSessionContract.SessionEntry.COLUMN_NAME_HAS_RADIUS, l.hasRadius() ? 1 : 0);
|
|
137
|
+
values.put(SQLiteSessionContract.SessionEntry.COLUMN_NAME_LOCATION_PROVIDER, l.getLocationProvider());
|
|
138
|
+
values.put(SQLiteSessionContract.SessionEntry.COLUMN_NAME_STATUS, 0);
|
|
139
|
+
values.put(SQLiteSessionContract.SessionEntry.COLUMN_NAME_BATCH_START_MILLIS, 0L);
|
|
140
|
+
values.put(SQLiteSessionContract.SessionEntry.COLUMN_NAME_MOCK_FLAGS, l.getMockFlags());
|
|
141
|
+
return values;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
private String[] queryColumns() {
|
|
145
|
+
return new String[]{
|
|
146
|
+
SQLiteSessionContract.SessionEntry._ID,
|
|
147
|
+
SQLiteSessionContract.SessionEntry.COLUMN_NAME_PROVIDER,
|
|
148
|
+
SQLiteSessionContract.SessionEntry.COLUMN_NAME_TIME,
|
|
149
|
+
SQLiteSessionContract.SessionEntry.COLUMN_NAME_ACCURACY,
|
|
150
|
+
SQLiteSessionContract.SessionEntry.COLUMN_NAME_VERTICAL_ACCURACY,
|
|
151
|
+
SQLiteSessionContract.SessionEntry.COLUMN_NAME_SPEED,
|
|
152
|
+
SQLiteSessionContract.SessionEntry.COLUMN_NAME_BEARING,
|
|
153
|
+
SQLiteSessionContract.SessionEntry.COLUMN_NAME_ALTITUDE,
|
|
154
|
+
SQLiteSessionContract.SessionEntry.COLUMN_NAME_RADIUS,
|
|
155
|
+
SQLiteSessionContract.SessionEntry.COLUMN_NAME_LATITUDE,
|
|
156
|
+
SQLiteSessionContract.SessionEntry.COLUMN_NAME_LONGITUDE,
|
|
157
|
+
SQLiteSessionContract.SessionEntry.COLUMN_NAME_HAS_ACCURACY,
|
|
158
|
+
SQLiteSessionContract.SessionEntry.COLUMN_NAME_HAS_VERTICAL_ACCURACY,
|
|
159
|
+
SQLiteSessionContract.SessionEntry.COLUMN_NAME_HAS_SPEED,
|
|
160
|
+
SQLiteSessionContract.SessionEntry.COLUMN_NAME_HAS_BEARING,
|
|
161
|
+
SQLiteSessionContract.SessionEntry.COLUMN_NAME_HAS_ALTITUDE,
|
|
162
|
+
SQLiteSessionContract.SessionEntry.COLUMN_NAME_HAS_RADIUS,
|
|
163
|
+
SQLiteSessionContract.SessionEntry.COLUMN_NAME_LOCATION_PROVIDER,
|
|
164
|
+
SQLiteSessionContract.SessionEntry.COLUMN_NAME_STATUS,
|
|
165
|
+
SQLiteSessionContract.SessionEntry.COLUMN_NAME_BATCH_START_MILLIS,
|
|
166
|
+
SQLiteSessionContract.SessionEntry.COLUMN_NAME_MOCK_FLAGS
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
}
|
|
@@ -22,6 +22,7 @@ import android.content.ComponentName;
|
|
|
22
22
|
import android.content.pm.PackageManager;
|
|
23
23
|
import android.content.pm.ServiceInfo;
|
|
24
24
|
import android.Manifest;
|
|
25
|
+
import android.location.Location;
|
|
25
26
|
import android.net.ConnectivityManager;
|
|
26
27
|
import android.net.NetworkInfo;
|
|
27
28
|
import android.os.Binder;
|
|
@@ -48,7 +49,9 @@ import com.marianhello.bgloc.data.BackgroundLocation;
|
|
|
48
49
|
import com.marianhello.bgloc.data.ConfigurationDAO;
|
|
49
50
|
import com.marianhello.bgloc.data.DAOFactory;
|
|
50
51
|
import com.marianhello.bgloc.data.LocationDAO;
|
|
52
|
+
import com.marianhello.bgloc.data.SessionLocationDAO;
|
|
51
53
|
import com.marianhello.bgloc.data.LocationTransform;
|
|
54
|
+
import com.marianhello.bgloc.data.sqlite.SQLiteSessionLocationDAO;
|
|
52
55
|
import com.marianhello.bgloc.headless.AbstractTaskRunner;
|
|
53
56
|
import com.marianhello.bgloc.headless.ActivityTask;
|
|
54
57
|
import com.marianhello.bgloc.headless.LocationTask;
|
|
@@ -67,6 +70,8 @@ import com.marianhello.logging.UncaughtExceptionLogger;
|
|
|
67
70
|
import org.chromium.content.browser.ThreadUtils;
|
|
68
71
|
import org.json.JSONException;
|
|
69
72
|
|
|
73
|
+
import java.util.Locale;
|
|
74
|
+
|
|
70
75
|
import static com.marianhello.bgloc.service.LocationServiceIntentBuilder.containsCommand;
|
|
71
76
|
import static com.marianhello.bgloc.service.LocationServiceIntentBuilder.containsMessage;
|
|
72
77
|
import static com.marianhello.bgloc.service.LocationServiceIntentBuilder.getCommand;
|
|
@@ -122,6 +127,7 @@ public class LocationServiceImpl extends Service implements ProviderDelegate, Lo
|
|
|
122
127
|
private HandlerThread mHandlerThread;
|
|
123
128
|
private ServiceHandler mServiceHandler;
|
|
124
129
|
private LocationDAO mLocationDAO;
|
|
130
|
+
private SessionLocationDAO mSessionDAO;
|
|
125
131
|
private PostLocationTask mPostLocationTask;
|
|
126
132
|
private String mHeadlessTaskRunnerClass;
|
|
127
133
|
private TaskRunner mHeadlessTaskRunner;
|
|
@@ -156,6 +162,30 @@ public class LocationServiceImpl extends Service implements ProviderDelegate, Lo
|
|
|
156
162
|
}
|
|
157
163
|
};
|
|
158
164
|
|
|
165
|
+
/** Session start time for notification elapsed time (showTime). */
|
|
166
|
+
private volatile long mSessionStartTime = 0L;
|
|
167
|
+
/** Accumulated distance in meters for notification (showDistance). */
|
|
168
|
+
private volatile double mSessionDistanceMeters = 0.0;
|
|
169
|
+
private volatile double mLastLat = 0.0;
|
|
170
|
+
private volatile double mLastLon = 0.0;
|
|
171
|
+
private volatile boolean mHasLastLocation = false;
|
|
172
|
+
private static final long NOTIFICATION_UPDATE_INTERVAL_MS = 1000L;
|
|
173
|
+
private final Runnable mNotificationUpdateRunnable = new Runnable() {
|
|
174
|
+
@Override
|
|
175
|
+
public void run() {
|
|
176
|
+
if (!sIsRunning || !mIsInForeground || mConfig == null) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
boolean showTime = Boolean.TRUE.equals(mConfig.getShowTime());
|
|
180
|
+
boolean showDistance = Boolean.TRUE.equals(mConfig.getShowDistance());
|
|
181
|
+
if (!showTime && !showDistance) {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
updateForegroundNotification();
|
|
185
|
+
mMainHandler.postDelayed(this, NOTIFICATION_UPDATE_INTERVAL_MS);
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
|
|
159
189
|
private static LocationTransform sLocationTransform;
|
|
160
190
|
private static LocationProviderFactory sLocationProviderFactory;
|
|
161
191
|
|
|
@@ -228,8 +258,9 @@ public class LocationServiceImpl extends Service implements ProviderDelegate, Lo
|
|
|
228
258
|
ContentResolver.setSyncAutomatically(mSyncAccount, authority, true);
|
|
229
259
|
|
|
230
260
|
mLocationDAO = DAOFactory.createLocationDAO(this);
|
|
261
|
+
mSessionDAO = new SQLiteSessionLocationDAO(this);
|
|
231
262
|
|
|
232
|
-
mPostLocationTask = new PostLocationTask(mLocationDAO,
|
|
263
|
+
mPostLocationTask = new PostLocationTask(mLocationDAO, mSessionDAO,
|
|
233
264
|
new PostLocationTask.PostLocationTaskListener() {
|
|
234
265
|
@Override
|
|
235
266
|
public void onRequestedAbortUpdates() {
|
|
@@ -418,6 +449,12 @@ public class LocationServiceImpl extends Service implements ProviderDelegate, Lo
|
|
|
418
449
|
mMainHandler.postDelayed(mWatchdogRunnable, WATCHDOG_INTERVAL_MS);
|
|
419
450
|
}
|
|
420
451
|
|
|
452
|
+
mSessionStartTime = System.currentTimeMillis();
|
|
453
|
+
mSessionDistanceMeters = 0.0;
|
|
454
|
+
mLastLat = 0.0;
|
|
455
|
+
mLastLon = 0.0;
|
|
456
|
+
mHasLastLocation = false;
|
|
457
|
+
|
|
421
458
|
ThreadUtils.runOnUiThreadBlocking(new Runnable() {
|
|
422
459
|
@Override
|
|
423
460
|
public void run() {
|
|
@@ -447,6 +484,7 @@ public class LocationServiceImpl extends Service implements ProviderDelegate, Lo
|
|
|
447
484
|
}
|
|
448
485
|
|
|
449
486
|
mMainHandler.removeCallbacks(mWatchdogRunnable);
|
|
487
|
+
mMainHandler.removeCallbacks(mNotificationUpdateRunnable);
|
|
450
488
|
|
|
451
489
|
if (mWakeLock != null && mWakeLock.isHeld()) {
|
|
452
490
|
try {
|
|
@@ -461,6 +499,7 @@ public class LocationServiceImpl extends Service implements ProviderDelegate, Lo
|
|
|
461
499
|
mProvider.onStop();
|
|
462
500
|
}
|
|
463
501
|
|
|
502
|
+
mIsInForeground = false;
|
|
464
503
|
stopForeground(true);
|
|
465
504
|
stopSelf();
|
|
466
505
|
|
|
@@ -530,9 +569,10 @@ public class LocationServiceImpl extends Service implements ProviderDelegate, Lo
|
|
|
530
569
|
return;
|
|
531
570
|
}
|
|
532
571
|
Config config = getConfig();
|
|
572
|
+
String contentText = buildNotificationContentText(config);
|
|
533
573
|
Notification notification = new NotificationHelper.NotificationFactory(this).getNotification(
|
|
534
574
|
config.getNotificationTitle(),
|
|
535
|
-
|
|
575
|
+
contentText,
|
|
536
576
|
config.getLargeNotificationIcon(),
|
|
537
577
|
config.getSmallNotificationIcon(),
|
|
538
578
|
config.getNotificationIconColor());
|
|
@@ -548,12 +588,14 @@ public class LocationServiceImpl extends Service implements ProviderDelegate, Lo
|
|
|
548
588
|
super.startForeground(NOTIFICATION_ID, notification);
|
|
549
589
|
}
|
|
550
590
|
mIsInForeground = true;
|
|
591
|
+
scheduleNotificationUpdater();
|
|
551
592
|
}
|
|
552
593
|
}
|
|
553
594
|
|
|
554
595
|
@Override
|
|
555
596
|
public synchronized void stopForeground() {
|
|
556
597
|
if (sIsRunning && mIsInForeground) {
|
|
598
|
+
mMainHandler.removeCallbacks(mNotificationUpdateRunnable);
|
|
557
599
|
stopForeground(true);
|
|
558
600
|
if (mProvider != null) {
|
|
559
601
|
mProvider.onCommand(LocationProvider.CMD_SWITCH_MODE,
|
|
@@ -563,6 +605,70 @@ public class LocationServiceImpl extends Service implements ProviderDelegate, Lo
|
|
|
563
605
|
}
|
|
564
606
|
}
|
|
565
607
|
|
|
608
|
+
/** Resource names for optional app-localized notification labels (showTime / showDistance). */
|
|
609
|
+
private static final String RES_NOTIFICATION_TIME_LABEL = "plugin_bgloc_notification_time_label";
|
|
610
|
+
private static final String RES_NOTIFICATION_DISTANCE_LABEL = "plugin_bgloc_notification_distance_label";
|
|
611
|
+
|
|
612
|
+
private String getNotificationLabel(String resourceName, String defaultValue) {
|
|
613
|
+
Context app = getApplicationContext();
|
|
614
|
+
int id = app.getResources().getIdentifier(resourceName, "string", app.getPackageName());
|
|
615
|
+
return (id != 0) ? app.getString(id) : defaultValue;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
private String buildNotificationContentText(Config config) {
|
|
619
|
+
String base = config.getNotificationText() != null ? config.getNotificationText() : "ENABLED";
|
|
620
|
+
if (Boolean.TRUE.equals(config.getShowTime())) {
|
|
621
|
+
String timeLabel = getNotificationLabel(RES_NOTIFICATION_TIME_LABEL, "Time");
|
|
622
|
+
base += "\n" + timeLabel + ": " + formatElapsed(mSessionStartTime);
|
|
623
|
+
}
|
|
624
|
+
if (Boolean.TRUE.equals(config.getShowDistance())) {
|
|
625
|
+
String distanceLabel = getNotificationLabel(RES_NOTIFICATION_DISTANCE_LABEL, "Distance");
|
|
626
|
+
base += "\n" + distanceLabel + ": " + formatDistance(mSessionDistanceMeters);
|
|
627
|
+
}
|
|
628
|
+
return base;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
private static String formatElapsed(long startTimeMs) {
|
|
632
|
+
long elapsed = Math.max(0L, System.currentTimeMillis() - startTimeMs);
|
|
633
|
+
long s = (elapsed / 1000L) % 60L;
|
|
634
|
+
long m = (elapsed / 60000L) % 60L;
|
|
635
|
+
long h = elapsed / 3600000L;
|
|
636
|
+
return String.format(Locale.US, "%02d:%02d:%02d", h, m, s);
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
private static String formatDistance(double meters) {
|
|
640
|
+
return String.format(Locale.US, "%.2f km", meters / 1000.0);
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
private void updateForegroundNotification() {
|
|
644
|
+
if (!sIsRunning || !mIsInForeground || mConfig == null) {
|
|
645
|
+
return;
|
|
646
|
+
}
|
|
647
|
+
String contentText = buildNotificationContentText(mConfig);
|
|
648
|
+
Notification notification = new NotificationHelper.NotificationFactory(this).getNotification(
|
|
649
|
+
mConfig.getNotificationTitle(),
|
|
650
|
+
contentText,
|
|
651
|
+
mConfig.getLargeNotificationIcon(),
|
|
652
|
+
mConfig.getSmallNotificationIcon(),
|
|
653
|
+
mConfig.getNotificationIconColor());
|
|
654
|
+
NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
|
655
|
+
if (nm != null) {
|
|
656
|
+
nm.notify(NOTIFICATION_ID, notification);
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
private void scheduleNotificationUpdater() {
|
|
661
|
+
mMainHandler.removeCallbacks(mNotificationUpdateRunnable);
|
|
662
|
+
if (mConfig == null) {
|
|
663
|
+
return;
|
|
664
|
+
}
|
|
665
|
+
boolean showTime = Boolean.TRUE.equals(mConfig.getShowTime());
|
|
666
|
+
boolean showDistance = Boolean.TRUE.equals(mConfig.getShowDistance());
|
|
667
|
+
if ((showTime || showDistance) && sIsRunning && mIsInForeground) {
|
|
668
|
+
mMainHandler.postDelayed(mNotificationUpdateRunnable, NOTIFICATION_UPDATE_INTERVAL_MS);
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
|
|
566
672
|
@Override
|
|
567
673
|
public synchronized void configure(Config config) {
|
|
568
674
|
if (mConfig == null) {
|
|
@@ -580,7 +686,7 @@ public class LocationServiceImpl extends Service implements ProviderDelegate, Lo
|
|
|
580
686
|
public void run() {
|
|
581
687
|
if (sIsRunning) {
|
|
582
688
|
if (currentConfig.getStartForeground() == true && mConfig.getStartForeground() == false) {
|
|
583
|
-
stopForeground(
|
|
689
|
+
stopForeground();
|
|
584
690
|
}
|
|
585
691
|
|
|
586
692
|
if (mConfig.getStartForeground() == true) {
|
|
@@ -589,15 +695,17 @@ public class LocationServiceImpl extends Service implements ProviderDelegate, Lo
|
|
|
589
695
|
startForeground();
|
|
590
696
|
} else {
|
|
591
697
|
// was running in foreground, so just update existing notification
|
|
698
|
+
String contentText = buildNotificationContentText(mConfig);
|
|
592
699
|
Notification notification = new NotificationHelper.NotificationFactory(LocationServiceImpl.this).getNotification(
|
|
593
700
|
mConfig.getNotificationTitle(),
|
|
594
|
-
|
|
701
|
+
contentText,
|
|
595
702
|
mConfig.getLargeNotificationIcon(),
|
|
596
703
|
mConfig.getSmallNotificationIcon(),
|
|
597
704
|
mConfig.getNotificationIconColor());
|
|
598
705
|
|
|
599
706
|
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
|
600
707
|
notificationManager.notify(NOTIFICATION_ID, notification);
|
|
708
|
+
scheduleNotificationUpdater();
|
|
601
709
|
}
|
|
602
710
|
}
|
|
603
711
|
}
|
|
@@ -661,6 +769,26 @@ public class LocationServiceImpl extends Service implements ProviderDelegate, Lo
|
|
|
661
769
|
@Override
|
|
662
770
|
public void onLocation(BackgroundLocation location) {
|
|
663
771
|
mLastLocationTime = System.currentTimeMillis();
|
|
772
|
+
if (Boolean.TRUE.equals(mConfig != null ? mConfig.getShowDistance() : null)) {
|
|
773
|
+
double lat = location.getLatitude();
|
|
774
|
+
double lon = location.getLongitude();
|
|
775
|
+
if (mHasLastLocation) {
|
|
776
|
+
float[] dist = new float[1];
|
|
777
|
+
Location.distanceBetween(mLastLat, mLastLon, lat, lon, dist);
|
|
778
|
+
mSessionDistanceMeters += (double) dist[0];
|
|
779
|
+
}
|
|
780
|
+
mLastLat = lat;
|
|
781
|
+
mLastLon = lon;
|
|
782
|
+
mHasLastLocation = true;
|
|
783
|
+
if (mIsInForeground && mConfig != null && (Boolean.TRUE.equals(mConfig.getShowTime()) || Boolean.TRUE.equals(mConfig.getShowDistance()))) {
|
|
784
|
+
mMainHandler.post(new Runnable() {
|
|
785
|
+
@Override
|
|
786
|
+
public void run() {
|
|
787
|
+
updateForegroundNotification();
|
|
788
|
+
}
|
|
789
|
+
});
|
|
790
|
+
}
|
|
791
|
+
}
|
|
664
792
|
logger.debug("New location {}", location.toString());
|
|
665
793
|
|
|
666
794
|
location = transformLocation(location);
|
|
@@ -168,6 +168,34 @@ export class BackgroundGeolocationService {
|
|
|
168
168
|
return this.ensurePlugin().getPendingSyncCount(success, fail);
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
+
startSession(
|
|
172
|
+
success?: () => void,
|
|
173
|
+
fail?: (error: any) => void
|
|
174
|
+
): Promise<void> {
|
|
175
|
+
return this.ensurePlugin().startSession(success, fail);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
getSessionLocations(
|
|
179
|
+
success?: (locations: any[]) => void,
|
|
180
|
+
fail?: (error: any) => void
|
|
181
|
+
): Promise<any[]> {
|
|
182
|
+
return this.ensurePlugin().getSessionLocations(success, fail);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
clearSession(
|
|
186
|
+
success?: () => void,
|
|
187
|
+
fail?: (error: any) => void
|
|
188
|
+
): Promise<void> {
|
|
189
|
+
return this.ensurePlugin().clearSession(success, fail);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
getSessionLocationsCount(
|
|
193
|
+
success?: (count: number) => void,
|
|
194
|
+
fail?: (error: any) => void
|
|
195
|
+
): Promise<number> {
|
|
196
|
+
return this.ensurePlugin().getSessionLocationsCount(success, fail);
|
|
197
|
+
}
|
|
198
|
+
|
|
171
199
|
getConfig(
|
|
172
200
|
success?: (config: any) => void,
|
|
173
201
|
fail?: (error: any) => void
|
|
@@ -45,6 +45,10 @@ export declare class BackgroundGeolocationService {
|
|
|
45
45
|
forceSync(success?: () => void, fail?: (error: any) => void): Promise<void>;
|
|
46
46
|
clearSync(success?: () => void, fail?: (error: any) => void): Promise<void>;
|
|
47
47
|
getPendingSyncCount(success?: (count: number) => void, fail?: (error: any) => void): Promise<number>;
|
|
48
|
+
startSession(success?: () => void, fail?: (error: any) => void): Promise<void>;
|
|
49
|
+
getSessionLocations(success?: (locations: any[]) => void, fail?: (error: any) => void): Promise<any[]>;
|
|
50
|
+
clearSession(success?: () => void, fail?: (error: any) => void): Promise<void>;
|
|
51
|
+
getSessionLocationsCount(success?: (count: number) => void, fail?: (error: any) => void): Promise<number>;
|
|
48
52
|
getConfig(success?: (config: any) => void, fail?: (error: any) => void): Promise<any>;
|
|
49
53
|
getLogEntries(limit: number, fromId: number, minLevel: string, success?: (entries: any[]) => void, fail?: (error: any) => void): Promise<any[]>;
|
|
50
54
|
removeAllListeners(event?: string): void;
|
|
@@ -97,6 +97,18 @@ export class BackgroundGeolocationService {
|
|
|
97
97
|
getPendingSyncCount(success, fail) {
|
|
98
98
|
return this.ensurePlugin().getPendingSyncCount(success, fail);
|
|
99
99
|
}
|
|
100
|
+
startSession(success, fail) {
|
|
101
|
+
return this.ensurePlugin().startSession(success, fail);
|
|
102
|
+
}
|
|
103
|
+
getSessionLocations(success, fail) {
|
|
104
|
+
return this.ensurePlugin().getSessionLocations(success, fail);
|
|
105
|
+
}
|
|
106
|
+
clearSession(success, fail) {
|
|
107
|
+
return this.ensurePlugin().clearSession(success, fail);
|
|
108
|
+
}
|
|
109
|
+
getSessionLocationsCount(success, fail) {
|
|
110
|
+
return this.ensurePlugin().getSessionLocationsCount(success, fail);
|
|
111
|
+
}
|
|
100
112
|
getConfig(success, fail) {
|
|
101
113
|
return this.ensurePlugin().getConfig(success, fail);
|
|
102
114
|
}
|
|
@@ -151,4 +163,4 @@ export class BackgroundGeolocationService {
|
|
|
151
163
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: BackgroundGeolocationService, decorators: [{
|
|
152
164
|
type: Injectable
|
|
153
165
|
}] });
|
|
154
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFja2dyb3VuZC1nZW9sb2NhdGlvbi5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vYmFja2dyb3VuZC1nZW9sb2NhdGlvbi5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsY0FBYyxFQUFFLE1BQU0sZUFBZSxDQUFDOztBQUUzRDs7OztHQUlHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sOEJBQThCLEdBQUcsSUFBSSxjQUFjLENBQzlELDhCQUE4QixDQUMvQixDQUFDO0FBRUY7Ozs7Ozs7Ozs7R0FVRztBQUVILE1BQU0sT0FBTyw0QkFBNEI7SUFFdkMsOERBQThEO0lBQzlELElBQVksTUFBTTtRQUNoQixJQUFJLE9BQU8sTUFBTSxLQUFLLFdBQVc7WUFBRSxPQUFPLElBQUksQ0FBQztRQUMvQyxPQUFRLE1BQWMsQ0FBQyxxQkFBcUIsSUFBSSxJQUFJLENBQUM7SUFDdkQsQ0FBQztJQUVPLFlBQVk7UUFDbEIsTUFBTSxDQUFDLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQztRQUN0QixJQUFJLENBQUMsQ0FBQyxFQUFFLENBQUM7WUFDUCxNQUFNLElBQUksS0FBSyxDQUNiLHdJQUF3SSxDQUN6SSxDQUFDO1FBQ0osQ0FBQztRQUNELE9BQU8sQ0FBQyxDQUFDO0lBQ1gsQ0FBQztJQUVELFNBQVMsQ0FBQyxPQUFZLEVBQUUsT0FBb0IsRUFBRSxJQUF5QjtRQUNyRSxPQUFPLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQyxTQUFTLENBQUMsT0FBTyxFQUFFLE9BQU8sRUFBRSxJQUFJLENBQUMsQ0FBQztJQUMvRCxDQUFDO0lBRUQsS0FBSztRQUNILE9BQU8sSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQ3JDLENBQUM7SUFFRCxJQUFJO1FBQ0YsT0FBTyxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDcEMsQ0FBQztJQUVE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QkFBNEI7a0JBRHhDLFVBQVUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlLCBJbmplY3Rpb25Ub2tlbiB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuXG4vKipcbiAqIFRva2VuIHVzZWQgdG8gcHJvdmlkZSBCYWNrZ3JvdW5kR2VvbG9jYXRpb25TZXJ2aWNlIHdpdGhvdXQgdHJpZ2dlcmluZyBKSVQuXG4gKiBUaGUgbW9kdWxlIHByb3ZpZGVzIHRoaXMgdG9rZW4gd2l0aCB1c2VGYWN0b3J5OyB0aGUgY2xhc3MgaXMgYWxpYXNlZCB2aWEgdXNlRXhpc3RpbmdcbiAqIHNvIHlvdSBzdGlsbCBpbmplY3QgY29uc3RydWN0b3IocHJpdmF0ZSBiZzogQmFja2dyb3VuZEdlb2xvY2F0aW9uU2VydmljZSkge30uXG4gKi9cbmV4cG9ydCBjb25zdCBCQUNLR1JPVU5EX0dFT0xPQ0FUSU9OX1NFUlZJQ0UgPSBuZXcgSW5qZWN0aW9uVG9rZW48QmFja2dyb3VuZEdlb2xvY2F0aW9uU2VydmljZT4oXG4gICdCYWNrZ3JvdW5kR2VvbG9jYXRpb25TZXJ2aWNlJ1xuKTtcblxuLyoqXG4gKiBBbmd1bGFyIHNlcnZpY2UgdGhhdCB3cmFwcyB0aGUgQ29yZG92YS9DYXBhY2l0b3IgQmFja2dyb3VuZEdlb2xvY2F0aW9uIHBsdWdpbi5cbiAqIFVzZSBkZXBlbmRlbmN5IGluamVjdGlvbiBpbnN0ZWFkIG9mIHRoZSBnbG9iYWwgQmFja2dyb3VuZEdlb2xvY2F0aW9uIG9iamVjdC5cbiAqXG4gKiBUaGUgbmF0aXZlIHBsdWdpbiBtdXN0IGJlIGluc3RhbGxlZCBhbmQgYXZhaWxhYmxlIChlLmcuIGFmdGVyIGRldmljZXJlYWR5KS5cbiAqIFR5cGVzIChDb25maWd1cmVPcHRpb25zLCBMb2NhdGlvbiwgZXRjLikgY2FuIGJlIGltcG9ydGVkIGZyb21cbiAqICdAam9zdWVsbW0vY29yZG92YS1iYWNrZ3JvdW5kLWdlb2xvY2F0aW9uJy5cbiAqXG4gKiBQcm92aWRlZCB2aWEgQmFja2dyb3VuZEdlb2xvY2F0aW9uTW9kdWxlIHVzaW5nIGFuIEluamVjdGlvblRva2VuICsgdXNlRmFjdG9yeVxuICogc28gQU9UIGJ1aWxkcyBuZXZlciBuZWVkIHRoZSBKSVQgY29tcGlsZXIgZm9yIHRoaXMgY2xhc3MuXG4gKi9cbkBJbmplY3RhYmxlKClcbmV4cG9ydCBjbGFzcyBCYWNrZ3JvdW5kR2VvbG9jYXRpb25TZXJ2aWNlIHtcblxuICAvKiogUmV0dXJucyB0aGUgZ2xvYmFsIHBsdWdpbiBpbnN0YW5jZSAoQ29yZG92YS9DYXBhY2l0b3IpLiAqL1xuICBwcml2YXRlIGdldCBwbHVnaW4oKTogYW55IHtcbiAgICBpZiAodHlwZW9mIHdpbmRvdyA9PT0gJ3VuZGVmaW5lZCcpIHJldHVybiBudWxsO1xuICAgIHJldHVybiAod2luZG93IGFzIGFueSkuQmFja2dyb3VuZEdlb2xvY2F0aW9uIHx8IG51bGw7XG4gIH1cblxuICBwcml2YXRlIGVuc3VyZVBsdWdpbigpOiBhbnkge1xuICAgIGNvbnN0IHAgPSB0aGlzLnBsdWdpbjtcbiAgICBpZiAoIXApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgJ0JhY2tncm91bmRHZW9sb2NhdGlvbiBpcyBub3QgYXZhaWxhYmxlLiBFbnN1cmUgdGhlIHBsdWdpbiBpcyBpbnN0YWxsZWQgYW5kIHRoZSBhcHAgaXMgcnVubmluZyBpbiBhIG5hdGl2ZSBjb250ZXh0IChDb3Jkb3ZhL0NhcGFjaXRvcikuJ1xuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIHA7XG4gIH1cblxuICBjb25maWd1cmUob3B0aW9uczogYW55LCBzdWNjZXNzPzogKCkgPT4gdm9pZCwgZmFpbD86IChlcnI6IGFueSkgPT4gdm9pZCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHJldHVybiB0aGlzLmVuc3VyZVBsdWdpbigpLmNvbmZpZ3VyZShvcHRpb25zLCBzdWNjZXNzLCBmYWlsKTtcbiAgfVxuXG4gIHN0YXJ0KCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHJldHVybiB0aGlzLmVuc3VyZVBsdWdpbigpLnN0YXJ0KCk7XG4gIH1cblxuICBzdG9wKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHJldHVybiB0aGlzLmVuc3VyZVBsdWdpbigpLnN0b3AoKTtcbiAgfVxuXG4gIC8qKiBJbmZvcm0gdGhlIG5hdGl2ZSBwbHVnaW4gdGhhdCB0aGUgYmFja2dyb3VuZCB0YXNrIG1heSBjb21wbGV0ZSAoaU9TKS4gQ2FsbCBhZnRlciBoYW5kbGluZyBsb2NhdGlvbi9zdGF0aW9uYXJ5IGluIHRoZSBjYWxsYmFjay4gKi9cbiAgZmluaXNoKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHJldHVybiB0aGlzLmVuc3VyZVBsdWdpbigpLmZpbmlzaCgpO1xuICB9XG5cbiAgLyoqIEZvcmNlIHRoZSBwbHVnaW4gdG8gZW50ZXIgXCJtb3ZpbmdcIiBvciBcInN0YXRpb25hcnlcIiBzdGF0ZSAoaU9TKS4gKi9cbiAgY2hhbmdlUGFjZShpc01vdmluZzogYm9vbGVhbik6IFByb21pc2U8dm9pZD4ge1xuICAgIHJldHVybiB0aGlzLmVuc3VyZVBsdWdpbigpLmNoYW5nZVBhY2UoaXNNb3ZpbmcpO1xuICB9XG5cbiAgZ2V0Q3VycmVudExvY2F0aW9uKFxuICAgIHN1Y2Nlc3M/OiAobG9jYXRpb246IGFueSkgPT4gdm9pZCxcbiAgICBmYWlsPzogKGVycm9yOiBhbnkpID0+IHZvaWQsXG4gICAgb3B0aW9ucz86IGFueVxuICApOiBQcm9taXNlPGFueT4ge1xuICAgIHJldHVybiB0aGlzLmVuc3VyZVBsdWdpbigpLmdldEN1cnJlbnRMb2NhdGlvbihzdWNjZXNzLCBmYWlsLCBvcHRpb25zKTtcbiAgfVxuXG4gIGdldFN0YXRpb25hcnlMb2NhdGlvbihcbiAgICBzdWNjZXNzPzogKGxvY2F0aW9uOiBhbnkpID0+IHZvaWQsXG4gICAgZmFpbD86IChlcnJvcjogYW55KSA9PiB2b2lkXG4gICk6IFByb21pc2U8YW55PiB7XG4gICAgcmV0dXJuIHRoaXMuZW5zdXJlUGx1Z2luKCkuZ2V0U3RhdGlvbmFyeUxvY2F0aW9uKHN1Y2Nlc3MsIGZhaWwpO1xuICB9XG5cbiAgY2hlY2tTdGF0dXMoXG4gICAgc3VjY2Vzcz86IChzdGF0dXM6IGFueSkgPT4gdm9pZCxcbiAgICBmYWlsPzogKGVycm9yOiBhbnkpID0+IHZvaWRcbiAgKTogUHJvbWlzZTxhbnk+IHtcbiAgICByZXR1cm4gdGhpcy5lbnN1cmVQbHVnaW4oKS5jaGVja1N0YXR1cyhzdWNjZXNzLCBmYWlsKTtcbiAgfVxuXG4gIHNob3dBcHBTZXR0aW5ncygpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICByZXR1cm4gdGhpcy5lbnN1cmVQbHVnaW4oKS5zaG93QXBwU2V0dGluZ3MoKTtcbiAgfVxuXG4gIC8qKiBPcGVuIGFwcCBzZXR0aW5ncyAoYWxpYXMgZm9yIHNob3dBcHBTZXR0aW5ncykuICovXG4gIG9wZW5TZXR0aW5ncygpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICByZXR1cm4gdGhpcy5lbnN1cmVQbHVnaW4oKS5vcGVuU2V0dGluZ3MoKTtcbiAgfVxuXG4gIHNob3dMb2NhdGlvblNldHRpbmdzKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHJldHVybiB0aGlzLmVuc3VyZVBsdWdpbigpLnNob3dMb2NhdGlvblNldHRpbmdzKCk7XG4gIH1cblxuICBnZXRQbHVnaW5WZXJzaW9uKFxuICAgIHN1Y2Nlc3M/OiAodmVyc2lvbjogc3RyaW5nKSA9PiB2b2lkLFxuICAgIGZhaWw/OiAoZXJyb3I6IGFueSkgPT4gdm9pZFxuICApOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIHJldHVybiB0aGlzLmVuc3VyZVBsdWdpbigpLmdldFBsdWdpblZlcnNpb24oc3VjY2VzcywgZmFpbCk7XG4gIH1cblxuICBnZXRMb2NhdGlvbnMoXG4gICAgc3VjY2Vzcz86IChsb2NhdGlvbnM6IGFueVtdKSA9PiB2b2lkLFxuICAgIGZhaWw/OiAoZXJyb3I6IGFueSkgPT4gdm9pZFxuICApOiBQcm9taXNlPGFueVtdPiB7XG4gICAgcmV0dXJuIHRoaXMuZW5zdXJlUGx1Z2luKCkuZ2V0TG9jYXRpb25zKHN1Y2Nlc3MsIGZhaWwpO1xuICB9XG5cbiAgZ2V0VmFsaWRMb2NhdGlvbnMoXG4gICAgc3VjY2Vzcz86IChsb2NhdGlvbnM6IGFueVtdKSA9PiB2b2lkLFxuICAgIGZhaWw/OiAoZXJyb3I6IGFueSkgPT4gdm9pZFxuICApOiBQcm9taXNlPGFueVtdPiB7XG4gICAgcmV0dXJuIHRoaXMuZW5zdXJlUGx1Z2luKCkuZ2V0VmFsaWRMb2NhdGlvbnMoc3VjY2VzcywgZmFpbCk7XG4gIH1cblxuICBnZXRWYWxpZExvY2F0aW9uc0FuZERlbGV0ZShcbiAgICBzdWNjZXNzPzogKGxvY2F0aW9uczogYW55W10pID0+IHZvaWQsXG4gICAgZmFpbD86IChlcnJvcjogYW55KSA9PiB2b2lkXG4gICk6IFByb21pc2U8YW55W10+IHtcbiAgICByZXR1cm4gdGhpcy5lbnN1cmVQbHVnaW4oKS5nZXRWYWxpZExvY2F0aW9uc0FuZERlbGV0ZShzdWNjZXNzLCBmYWlsKTtcbiAgfVxuXG4gIGRlbGV0ZUxvY2F0aW9uKFxuICAgIGxvY2F0aW9uSWQ6IG51bWJlcixcbiAgICBzdWNjZXNzPzogKCkgPT4gdm9pZCxcbiAgICBmYWlsPzogKGVycm9yOiBhbnkpID0+IHZvaWRcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgcmV0dXJuIHRoaXMuZW5zdXJlUGx1Z2luKCkuZGVsZXRlTG9jYXRpb24obG9jYXRpb25JZCwgc3VjY2VzcywgZmFpbCk7XG4gIH1cblxuICBkZWxldGVBbGxMb2NhdGlvbnMoXG4gICAgc3VjY2Vzcz86ICgpID0+IHZvaWQsXG4gICAgZmFpbD86IChlcnJvcjogYW55KSA9PiB2b2lkXG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIHJldHVybiB0aGlzLmVuc3VyZVBsdWdpbigpLmRlbGV0ZUFsbExvY2F0aW9ucyhzdWNjZXNzLCBmYWlsKTtcbiAgfVxuXG4gIHN3aXRjaE1vZGUoXG4gICAgbW9kZUlkOiBudW1iZXIsXG4gICAgc3VjY2Vzcz86ICgpID0+IHZvaWQsXG4gICAgZmFpbD86IChlcnJvcjogYW55KSA9PiB2b2lkXG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIHJldHVybiB0aGlzLmVuc3VyZVBsdWdpbigpLnN3aXRjaE1vZGUobW9kZUlkLCBzdWNjZXNzLCBmYWlsKTtcbiAgfVxuXG4gIGZvcmNlU3luYyhcbiAgICBzdWNjZXNzPzogKCkgPT4gdm9pZCxcbiAgICBmYWlsPzogKGVycm9yOiBhbnkpID0+IHZvaWRcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgcmV0dXJuIHRoaXMuZW5zdXJlUGx1Z2luKCkuZm9yY2VTeW5jKHN1Y2Nlc3MsIGZhaWwpO1xuICB9XG5cbiAgY2xlYXJTeW5jKFxuICAgIHN1Y2Nlc3M/OiAoKSA9PiB2b2lkLFxuICAgIGZhaWw/OiAoZXJyb3I6IGFueSkgPT4gdm9pZFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICByZXR1cm4gdGhpcy5lbnN1cmVQbHVnaW4oKS5jbGVhclN5bmMoc3VjY2VzcywgZmFpbCk7XG4gIH1cblxuICBnZXRQZW5kaW5nU3luY0NvdW50KFxuICAgIHN1Y2Nlc3M/OiAoY291bnQ6IG51bWJlcikgPT4gdm9pZCxcbiAgICBmYWlsPzogKGVycm9yOiBhbnkpID0+IHZvaWRcbiAgKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICByZXR1cm4gdGhpcy5lbnN1cmVQbHVnaW4oKS5nZXRQZW5kaW5nU3luY0NvdW50KHN1Y2Nlc3MsIGZhaWwpO1xuICB9XG5cbiAgZ2V0Q29uZmlnKFxuICAgIHN1Y2Nlc3M/OiAoY29uZmlnOiBhbnkpID0+IHZvaWQsXG4gICAgZmFpbD86IChlcnJvcjogYW55KSA9PiB2b2lkXG4gICk6IFByb21pc2U8YW55PiB7XG4gICAgcmV0dXJuIHRoaXMuZW5zdXJlUGx1Z2luKCkuZ2V0Q29uZmlnKHN1Y2Nlc3MsIGZhaWwpO1xuICB9XG5cbiAgZ2V0TG9nRW50cmllcyhcbiAgICBsaW1pdDogbnVtYmVyLFxuICAgIGZyb21JZDogbnVtYmVyLFxuICAgIG1pbkxldmVsOiBzdHJpbmcsXG4gICAgc3VjY2Vzcz86IChlbnRyaWVzOiBhbnlbXSkgPT4gdm9pZCxcbiAgICBmYWlsPzogKGVycm9yOiBhbnkpID0+IHZvaWRcbiAgKTogUHJvbWlzZTxhbnlbXT4ge1xuICAgIHJldHVybiB0aGlzLmVuc3VyZVBsdWdpbigpLmdldExvZ0VudHJpZXMobGltaXQsIGZyb21JZCwgbWluTGV2ZWwsIHN1Y2Nlc3MsIGZhaWwpO1xuICB9XG5cbiAgcmVtb3ZlQWxsTGlzdGVuZXJzKGV2ZW50Pzogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhpcy5lbnN1cmVQbHVnaW4oKS5yZW1vdmVBbGxMaXN0ZW5lcnMoZXZlbnQpO1xuICB9XG5cbiAgc3RhcnRUYXNrKFxuICAgIHN1Y2Nlc3M/OiAodGFza0tleTogbnVtYmVyKSA9PiB2b2lkLFxuICAgIGZhaWw/OiAoZXJyb3I6IGFueSkgPT4gdm9pZFxuICApOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIHJldHVybiB0aGlzLmVuc3VyZVBsdWdpbigpLnN0YXJ0VGFzayhzdWNjZXNzLCBmYWlsKTtcbiAgfVxuXG4gIGVuZFRhc2soXG4gICAgdGFza0tleTogbnVtYmVyLFxuICAgIHN1Y2Nlc3M/OiAoKSA9PiB2b2lkLFxuICAgIGZhaWw/OiAoZXJyb3I6IGFueSkgPT4gdm9pZFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICByZXR1cm4gdGhpcy5lbnN1cmVQbHVnaW4oKS5lbmRUYXNrKHRhc2tLZXksIHN1Y2Nlc3MsIGZhaWwpO1xuICB9XG5cbiAgaGVhZGxlc3NUYXNrKHRhc2s6IChldmVudDogYW55KSA9PiB2b2lkKTogdm9pZCB7XG4gICAgdGhpcy5lbnN1cmVQbHVnaW4oKS5oZWFkbGVzc1Rhc2sodGFzayk7XG4gIH1cblxuICAvKipcbiAgICogUmVnaXN0ZXIgYW4gZXZlbnQgbGlzdGVuZXIuIENvbXBhdGlibGUgd2l0aCBBd2Vzb21lLXN0eWxlIHVzYWdlOlxuICAgKiAub24oQmFja2dyb3VuZEdlb2xvY2F0aW9uRXZlbnRzLmVycm9yKS5zdWJzY3JpYmUoKGVycikgPT4gLi4uKSDigJQgcmV0dXJucyBzdWJzY3JpcHRpb24gd2l0aCAudW5zdWJzY3JpYmUoKS5cbiAgICogLm9uKCdsb2NhdGlvbicsIChsb2MpID0+IC4uLikg4oCUIGFsc28gc3VwcG9ydGVkOyByZXR1cm5lZCBvYmplY3QgaGFzIC51bnN1YnNjcmliZSgpLlxuICAgKi9cbiAgb24oZXZlbnROYW1lOiBzdHJpbmcsIGNhbGxiYWNrPzogKHZhbHVlOiBhbnkpID0+IHZvaWQpOiB7IHN1YnNjcmliZShjYjogKHZhbHVlOiBhbnkpID0+IHZvaWQpOiB7IHVuc3Vic2NyaWJlKCk6IHZvaWQgfTsgdW5zdWJzY3JpYmUoKTogdm9pZCB9IHtcbiAgICBjb25zdCBwbHVnaW4gPSB0aGlzLmVuc3VyZVBsdWdpbigpO1xuICAgIGlmIChjYWxsYmFjayAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBjb25zdCBzdWIgPSBwbHVnaW4ub24oZXZlbnROYW1lLCBjYWxsYmFjaykgYXMgeyByZW1vdmU/OiAoKSA9PiB2b2lkIH07XG4gICAgICByZXR1cm4ge1xuICAgICAgICBzdWJzY3JpYmUoY2I6ICh2YWx1ZTogYW55KSA9PiB2b2lkKSB7XG4gICAgICAgICAgY29uc3QgcyA9IGNiID8gKHBsdWdpbi5vbihldmVudE5hbWUsIGNiKSBhcyB7IHJlbW92ZT86ICgpID0+IHZvaWQgfSkgOiBudWxsO1xuICAgICAgICAgIHJldHVybiB7IHVuc3Vic2NyaWJlKCkgeyBzPy5yZW1vdmU/LigpOyB9IH07XG4gICAgICAgIH0sXG4gICAgICAgIHVuc3Vic2NyaWJlKCkgeyBzdWIucmVtb3ZlPy4oKTsgfVxuICAgICAgfTtcbiAgICB9XG4gICAgY29uc3QgY2hhbm5lbCA9IHBsdWdpbi5vbihldmVudE5hbWUpIGFzIHsgc3Vic2NyaWJlOiAoY2I6ICh2OiBhbnkpID0+IHZvaWQpID0+IHZvaWQ7IHVuc3Vic2NyaWJlOiAoY2I6ICh2OiBhbnkpID0+IHZvaWQpID0+IHZvaWQgfTtcbiAgICByZXR1cm4ge1xuICAgICAgc3Vic2NyaWJlKGNiOiAodmFsdWU6IGFueSkgPT4gdm9pZCkge1xuICAgICAgICBjaGFubmVsLnN1YnNjcmliZShjYik7XG4gICAgICAgIHJldHVybiB7IHVuc3Vic2NyaWJlKCkgeyBjaGFubmVsLnVuc3Vic2NyaWJlKGNiKTsgfSB9O1xuICAgICAgfSxcbiAgICAgIHVuc3Vic2NyaWJlKCkgeyAvKiBuby1vcCB3aGVuIG5vIGNhbGxiYWNrICovIH1cbiAgICB9O1xuICB9XG5cbiAgLyoqIENvbnZlbmllbmNlOiBhY2Nlc3MgcGx1Z2luIGNvbnN0YW50cyAoZS5nLiBBQ1RJVklUWV9QUk9WSURFUiwgSElHSF9BQ0NVUkFDWSkuICovXG4gIGdldCBuYXRpdmUoKTogYW55IHtcbiAgICByZXR1cm4gdGhpcy5wbHVnaW47XG4gIH1cbn1cbiJdfQ==
|
|
166
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFja2dyb3VuZC1nZW9sb2NhdGlvbi5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vYmFja2dyb3VuZC1nZW9sb2NhdGlvbi5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsY0FBYyxFQUFFLE1BQU0sZUFBZSxDQUFDOztBQUUzRDs7OztHQUlHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sOEJBQThCLEdBQUcsSUFBSSxjQUFjLENBQzlELDhCQUE4QixDQUMvQixDQUFDO0FBRUY7Ozs7Ozs7Ozs7R0FVRztBQUVILE1BQU0sT0FBTyw0QkFBNEI7SUFFdkMsOERBQThEO0lBQzlELElBQVksTUFBTTtRQUNoQixJQUFJLE9BQU8sTUFBTSxLQUFLLFdBQVc7WUFBRSxPQUFPLElBQUksQ0FBQztRQUMvQyxPQUFRLE1BQWMsQ0FBQyxxQkFBcUIsSUFBSSxJQUFJLENBQUM7SUFDdkQsQ0FBQztJQUVPLFlBQVk7UUFDbEIsTUFBTSxDQUFDLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQztRQUN0QixJQUFJLENBQUMsQ0FBQyxFQUFFLENBQUM7WUFDUCxNQUFNLElBQUksS0FBSyxDQUNiLHdJQUF3SSxDQUN6SSxDQUFDO1FBQ0osQ0FBQztRQUNELE9BQU8sQ0FBQyxDQUFDO0lBQ1gsQ0FBQztJQUVELFNBQVMsQ0FBQyxPQUFZLEVBQUUsT0FBb0IsRUFBRSxJQUF5QjtRQUNyRSxPQUFPLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQyxTQUFTLENBQUMsT0FBTyxFQUFFLE9BQU8sRUFBRSxJQUFJLENBQUMsQ0FBQztJQUMvRCxDQUFDO0lBRUQsS0FBSztRQUNILE9BQU8sSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQ3JDLENBQUM7SUFFRCxJQUFJO1FBQ0YsT0FBTyxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDcEMsQ0FBQztJQUVELHFJQUFxSTtJQUNySSxNQUFNO1FBQ0osT0FBTyxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUMsTUFBTSxFQUFFLENBQUM7SUFDdEMsQ0FBQztJQUVELHNFQUFzRTtJQUN0RSxVQUFVLENBQUMsUUFBaUI7UUFDMUIsT0FBTyxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQ2xELENBQUM7SUFFRCxrQkFBa0IsQ0FDaEIsT0FBaUMsRUFDakMsSUFBMkIsRUFDM0IsT0FBYTtRQUViLE9BQU8sSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDLGtCQUFrQixDQUFDLE9BQU8sRUFBRSxJQUFJLEVBQUUsT0FBTyxDQUFDLENBQUM7SUFDeEUsQ0FBQztJQUVELHFCQUFxQixDQUNuQixPQUFpQyxFQUNqQyxJQUEyQjtRQUUzQixPQUFPLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQyxxQkFBcUIsQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDbEUsQ0FBQztJQUVELFdBQVcsQ0FDVCxPQUErQixFQUMvQixJQUEyQjtRQUUzQixPQUFPLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQyxXQUFXLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxDQUFDO0lBQ3hELENBQUM7SUFFRCxlQUFlO1FBQ2IsT0FBTyxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUMsZUFBZSxFQUFFLENBQUM7SUFDL0MsQ0FBQztJQUVELHFEQUFxRDtJQUNyRCxZQUFZO1FBQ1YsT0FBTyxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUMsWUFBWSxFQUFFLENBQUM7SUFDNUMsQ0FBQztJQUVELG9CQUFvQjtRQUNsQixPQUFPLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQyxvQkFBb0IsRUFBRSxDQUFDO0lBQ3BELENBQUM7SUFFRCxnQkFBZ0IsQ0FDZCxPQUFtQyxFQUNuQyxJQUEyQjtRQUUzQixPQUFPLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQyxnQkFBZ0IsQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDN0QsQ0FBQztJQUVELFlBQVksQ0FDVixPQUFvQyxFQUNwQyxJQUEyQjtRQUUzQixPQUFPLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQyxZQUFZLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxDQUFDO0lBQ3pELENBQUM7SUFFRCxpQkFBaUIsQ0FDZixPQUFvQyxFQUNwQyxJQUEyQjtRQUUzQixPQUFPLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQyxpQkFBaUIsQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDOUQsQ0FBQztJQUVELDBCQUEwQixDQUN4QixPQUFvQyxFQUNwQyxJQUEyQjtRQUUzQixPQUFPLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQywwQkFBMEIsQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDdkUsQ0FBQztJQUVELGNBQWMsQ0FDWixVQUFrQixFQUNsQixPQUFvQixFQUNwQixJQUEyQjtRQUUzQixPQUFPLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQyxjQUFjLENBQUMsVUFBVSxFQUFFLE9BQU8sRUFBRSxJQUFJLENBQUMsQ0FBQztJQUN2RSxDQUFDO0lBRUQsa0JBQWtCLENBQ2hCLE9BQW9CLEVBQ3BCLElBQTJCO1FBRTNCLE9BQU8sSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDLGtCQUFrQixDQUFDLE9BQU8sRUFBRSxJQUFJLENBQUMsQ0FBQztJQUMvRCxDQUFDO0lBRUQsVUFBVSxDQUNSLE1BQWMsRUFDZCxPQUFvQixFQUNwQixJQUEyQjtRQUUzQixPQUFPLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQyxVQUFVLENBQUMsTUFBTSxFQUFFLE9BQU8sRUFBRSxJQUFJLENBQUMsQ0FBQztJQUMvRCxDQUFDO0lBRUQsU0FBUyxDQUNQLE9BQW9CLEVBQ3BCLElBQTJCO1FBRTNCLE9BQU8sSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDLFNBQVMsQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDdEQsQ0FBQztJQUVELFNBQVMsQ0FDUCxPQUFvQixFQUNwQixJQUEyQjtRQUUzQixPQUFPLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQyxTQUFTLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxDQUFDO0lBQ3RELENBQUM7SUFFRCxtQkFBbUIsQ0FDakIsT0FBaUMsRUFDakMsSUFBMkI7UUFFM0IsT0FBTyxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUMsbUJBQW1CLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxDQUFDO0lBQ2hFLENBQUM7SUFFRCxZQUFZLENBQ1YsT0FBb0IsRUFDcEIsSUFBMkI7UUFFM0IsT0FBTyxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUMsWUFBWSxDQUFDLE9BQU8sRUFBRSxJQUFJLENBQUMsQ0FBQztJQUN6RCxDQUFDO0lBRUQsbUJBQW1CLENBQ2pCLE9BQW9DLEVBQ3BDLElBQTJCO1FBRTNCLE9BQU8sSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDLG1CQUFtQixDQUFDLE9BQU8sRUFBRSxJQUFJLENBQUMsQ0FBQztJQUNoRSxDQUFDO0lBRUQsWUFBWSxDQUNWLE9BQW9CLEVBQ3BCLElBQTJCO1FBRTNCLE9BQU8sSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDLFlBQVksQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDekQsQ0FBQztJQUVELHdCQUF3QixDQUN0QixPQUFpQyxFQUNqQyxJQUEyQjtRQUUzQixPQUFPLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQyx3QkFBd0IsQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDckUsQ0FBQztJQUVELFNBQVMsQ0FDUCxPQUErQixFQUMvQixJQUEyQjtRQUUzQixPQUFPLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQyxTQUFTLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxDQUFDO0lBQ3RELENBQUM7SUFFRCxhQUFhLENBQ1gsS0FBYSxFQUNiLE1BQWMsRUFDZCxRQUFnQixFQUNoQixPQUFrQyxFQUNsQyxJQUEyQjtRQUUzQixPQUFPLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQyxhQUFhLENBQUMsS0FBSyxFQUFFLE1BQU0sRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFLElBQUksQ0FBQyxDQUFDO0lBQ25GLENBQUM7SUFFRCxrQkFBa0IsQ0FBQyxLQUFjO1FBQy9CLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQyxrQkFBa0IsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUNoRCxDQUFDO0lBRUQsU0FBUyxDQUNQLE9BQW1DLEVBQ25DLElBQTJCO1FBRTNCLE9BQU8sSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDLFNBQVMsQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDdEQsQ0FBQztJQUVELE9BQU8sQ0FDTCxPQUFlLEVBQ2YsT0FBb0IsRUFDcEIsSUFBMkI7UUFFM0IsT0FBTyxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUMsT0FBTyxDQUFDLE9BQU8sRUFBRSxPQUFPLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDN0QsQ0FBQztJQUVELFlBQVksQ0FBQyxJQUEwQjtRQUNyQyxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ3pDLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsRUFBRSxDQUFDLFNBQWlCLEVBQUUsUUFBK0I7UUFDbkQsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO1FBQ25DLElBQUksUUFBUSxLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQzNCLE1BQU0sR0FBRyxHQUFHLE1BQU0sQ0FBQyxFQUFFLENBQUMsU0FBUyxFQUFFLFFBQVEsQ0FBNEIsQ0FBQztZQUN0RSxPQUFPO2dCQUNMLFNBQVMsQ0FBQyxFQUF3QjtvQkFDaEMsTUFBTSxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUMsQ0FBRSxNQUFNLENBQUMsRUFBRSxDQUFDLFNBQVMsRUFBRSxFQUFFLENBQTZCLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQztvQkFDNUUsT0FBTyxFQUFFLFdBQVcsS0FBSyxDQUFDLEVBQUUsTUFBTSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO2dCQUM5QyxDQUFDO2dCQUNELFdBQVcsS0FBSyxHQUFHLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUM7YUFDbEMsQ0FBQztRQUNKLENBQUM7UUFDRCxNQUFNLE9BQU8sR0FBRyxNQUFNLENBQUMsRUFBRSxDQUFDLFNBQVMsQ0FBK0YsQ0FBQztRQUNuSSxPQUFPO1lBQ0wsU0FBUyxDQUFDLEVBQXdCO2dCQUNoQyxPQUFPLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQyxDQUFDO2dCQUN0QixPQUFPLEVBQUUsV0FBVyxLQUFLLE9BQU8sQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztZQUN4RCxDQUFDO1lBQ0QsV0FBVyxLQUFrQyxDQUFDO1NBQy9DLENBQUM7SUFDSixDQUFDO0lBRUQsb0ZBQW9GO0lBQ3BGLElBQUksTUFBTTtRQUNSLE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQztJQUNyQixDQUFDO3dHQXJQVSw0QkFBNEI7NEdBQTVCLDRCQUE0Qjs7NEZBQTVCLDRCQUE0QjtrQkFEeEMsVUFBVSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGFibGUsIEluamVjdGlvblRva2VuIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5cbi8qKlxuICogVG9rZW4gdXNlZCB0byBwcm92aWRlIEJhY2tncm91bmRHZW9sb2NhdGlvblNlcnZpY2Ugd2l0aG91dCB0cmlnZ2VyaW5nIEpJVC5cbiAqIFRoZSBtb2R1bGUgcHJvdmlkZXMgdGhpcyB0b2tlbiB3aXRoIHVzZUZhY3Rvcnk7IHRoZSBjbGFzcyBpcyBhbGlhc2VkIHZpYSB1c2VFeGlzdGluZ1xuICogc28geW91IHN0aWxsIGluamVjdCBjb25zdHJ1Y3Rvcihwcml2YXRlIGJnOiBCYWNrZ3JvdW5kR2VvbG9jYXRpb25TZXJ2aWNlKSB7fS5cbiAqL1xuZXhwb3J0IGNvbnN0IEJBQ0tHUk9VTkRfR0VPTE9DQVRJT05fU0VSVklDRSA9IG5ldyBJbmplY3Rpb25Ub2tlbjxCYWNrZ3JvdW5kR2VvbG9jYXRpb25TZXJ2aWNlPihcbiAgJ0JhY2tncm91bmRHZW9sb2NhdGlvblNlcnZpY2UnXG4pO1xuXG4vKipcbiAqIEFuZ3VsYXIgc2VydmljZSB0aGF0IHdyYXBzIHRoZSBDb3Jkb3ZhL0NhcGFjaXRvciBCYWNrZ3JvdW5kR2VvbG9jYXRpb24gcGx1Z2luLlxuICogVXNlIGRlcGVuZGVuY3kgaW5qZWN0aW9uIGluc3RlYWQgb2YgdGhlIGdsb2JhbCBCYWNrZ3JvdW5kR2VvbG9jYXRpb24gb2JqZWN0LlxuICpcbiAqIFRoZSBuYXRpdmUgcGx1Z2luIG11c3QgYmUgaW5zdGFsbGVkIGFuZCBhdmFpbGFibGUgKGUuZy4gYWZ0ZXIgZGV2aWNlcmVhZHkpLlxuICogVHlwZXMgKENvbmZpZ3VyZU9wdGlvbnMsIExvY2F0aW9uLCBldGMuKSBjYW4gYmUgaW1wb3J0ZWQgZnJvbVxuICogJ0Bqb3N1ZWxtbS9jb3Jkb3ZhLWJhY2tncm91bmQtZ2VvbG9jYXRpb24nLlxuICpcbiAqIFByb3ZpZGVkIHZpYSBCYWNrZ3JvdW5kR2VvbG9jYXRpb25Nb2R1bGUgdXNpbmcgYW4gSW5qZWN0aW9uVG9rZW4gKyB1c2VGYWN0b3J5XG4gKiBzbyBBT1QgYnVpbGRzIG5ldmVyIG5lZWQgdGhlIEpJVCBjb21waWxlciBmb3IgdGhpcyBjbGFzcy5cbiAqL1xuQEluamVjdGFibGUoKVxuZXhwb3J0IGNsYXNzIEJhY2tncm91bmRHZW9sb2NhdGlvblNlcnZpY2Uge1xuXG4gIC8qKiBSZXR1cm5zIHRoZSBnbG9iYWwgcGx1Z2luIGluc3RhbmNlIChDb3Jkb3ZhL0NhcGFjaXRvcikuICovXG4gIHByaXZhdGUgZ2V0IHBsdWdpbigpOiBhbnkge1xuICAgIGlmICh0eXBlb2Ygd2luZG93ID09PSAndW5kZWZpbmVkJykgcmV0dXJuIG51bGw7XG4gICAgcmV0dXJuICh3aW5kb3cgYXMgYW55KS5CYWNrZ3JvdW5kR2VvbG9jYXRpb24gfHwgbnVsbDtcbiAgfVxuXG4gIHByaXZhdGUgZW5zdXJlUGx1Z2luKCk6IGFueSB7XG4gICAgY29uc3QgcCA9IHRoaXMucGx1Z2luO1xuICAgIGlmICghcCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAnQmFja2dyb3VuZEdlb2xvY2F0aW9uIGlzIG5vdCBhdmFpbGFibGUuIEVuc3VyZSB0aGUgcGx1Z2luIGlzIGluc3RhbGxlZCBhbmQgdGhlIGFwcCBpcyBydW5uaW5nIGluIGEgbmF0aXZlIGNvbnRleHQgKENvcmRvdmEvQ2FwYWNpdG9yKS4nXG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gcDtcbiAgfVxuXG4gIGNvbmZpZ3VyZShvcHRpb25zOiBhbnksIHN1Y2Nlc3M/OiAoKSA9PiB2b2lkLCBmYWlsPzogKGVycjogYW55KSA9PiB2b2lkKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgcmV0dXJuIHRoaXMuZW5zdXJlUGx1Z2luKCkuY29uZmlndXJlKG9wdGlvbnMsIHN1Y2Nlc3MsIGZhaWwpO1xuICB9XG5cbiAgc3RhcnQoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgcmV0dXJuIHRoaXMuZW5zdXJlUGx1Z2luKCkuc3RhcnQoKTtcbiAgfVxuXG4gIHN0b3AoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgcmV0dXJuIHRoaXMuZW5zdXJlUGx1Z2luKCkuc3RvcCgpO1xuICB9XG5cbiAgLyoqIEluZm9ybSB0aGUgbmF0aXZlIHBsdWdpbiB0aGF0IHRoZSBiYWNrZ3JvdW5kIHRhc2sgbWF5IGNvbXBsZXRlIChpT1MpLiBDYWxsIGFmdGVyIGhhbmRsaW5nIGxvY2F0aW9uL3N0YXRpb25hcnkgaW4gdGhlIGNhbGxiYWNrLiAqL1xuICBmaW5pc2goKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgcmV0dXJuIHRoaXMuZW5zdXJlUGx1Z2luKCkuZmluaXNoKCk7XG4gIH1cblxuICAvKiogRm9yY2UgdGhlIHBsdWdpbiB0byBlbnRlciBcIm1vdmluZ1wiIG9yIFwic3RhdGlvbmFyeVwiIHN0YXRlIChpT1MpLiAqL1xuICBjaGFuZ2VQYWNlKGlzTW92aW5nOiBib29sZWFuKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgcmV0dXJuIHRoaXMuZW5zdXJlUGx1Z2luKCkuY2hhbmdlUGFjZShpc01vdmluZyk7XG4gIH1cblxuICBnZXRDdXJyZW50TG9jYXRpb24oXG4gICAgc3VjY2Vzcz86IChsb2NhdGlvbjogYW55KSA9PiB2b2lkLFxuICAgIGZhaWw/OiAoZXJyb3I6IGFueSkgPT4gdm9pZCxcbiAgICBvcHRpb25zPzogYW55XG4gICk6IFByb21pc2U8YW55PiB7XG4gICAgcmV0dXJuIHRoaXMuZW5zdXJlUGx1Z2luKCkuZ2V0Q3VycmVudExvY2F0aW9uKHN1Y2Nlc3MsIGZhaWwsIG9wdGlvbnMpO1xuICB9XG5cbiAgZ2V0U3RhdGlvbmFyeUxvY2F0aW9uKFxuICAgIHN1Y2Nlc3M/OiAobG9jYXRpb246IGFueSkgPT4gdm9pZCxcbiAgICBmYWlsPzogKGVycm9yOiBhbnkpID0+IHZvaWRcbiAgKTogUHJvbWlzZTxhbnk+IHtcbiAgICByZXR1cm4gdGhpcy5lbnN1cmVQbHVnaW4oKS5nZXRTdGF0aW9uYXJ5TG9jYXRpb24oc3VjY2VzcywgZmFpbCk7XG4gIH1cblxuICBjaGVja1N0YXR1cyhcbiAgICBzdWNjZXNzPzogKHN0YXR1czogYW55KSA9PiB2b2lkLFxuICAgIGZhaWw/OiAoZXJyb3I6IGFueSkgPT4gdm9pZFxuICApOiBQcm9taXNlPGFueT4ge1xuICAgIHJldHVybiB0aGlzLmVuc3VyZVBsdWdpbigpLmNoZWNrU3RhdHVzKHN1Y2Nlc3MsIGZhaWwpO1xuICB9XG5cbiAgc2hvd0FwcFNldHRpbmdzKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHJldHVybiB0aGlzLmVuc3VyZVBsdWdpbigpLnNob3dBcHBTZXR0aW5ncygpO1xuICB9XG5cbiAgLyoqIE9wZW4gYXBwIHNldHRpbmdzIChhbGlhcyBmb3Igc2hvd0FwcFNldHRpbmdzKS4gKi9cbiAgb3BlblNldHRpbmdzKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHJldHVybiB0aGlzLmVuc3VyZVBsdWdpbigpLm9wZW5TZXR0aW5ncygpO1xuICB9XG5cbiAgc2hvd0xvY2F0aW9uU2V0dGluZ3MoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgcmV0dXJuIHRoaXMuZW5zdXJlUGx1Z2luKCkuc2hvd0xvY2F0aW9uU2V0dGluZ3MoKTtcbiAgfVxuXG4gIGdldFBsdWdpblZlcnNpb24oXG4gICAgc3VjY2Vzcz86ICh2ZXJzaW9uOiBzdHJpbmcpID0+IHZvaWQsXG4gICAgZmFpbD86IChlcnJvcjogYW55KSA9PiB2b2lkXG4gICk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgcmV0dXJuIHRoaXMuZW5zdXJlUGx1Z2luKCkuZ2V0UGx1Z2luVmVyc2lvbihzdWNjZXNzLCBmYWlsKTtcbiAgfVxuXG4gIGdldExvY2F0aW9ucyhcbiAgICBzdWNjZXNzPzogKGxvY2F0aW9uczogYW55W10pID0+IHZvaWQsXG4gICAgZmFpbD86IChlcnJvcjogYW55KSA9PiB2b2lkXG4gICk6IFByb21pc2U8YW55W10+IHtcbiAgICByZXR1cm4gdGhpcy5lbnN1cmVQbHVnaW4oKS5nZXRMb2NhdGlvbnMoc3VjY2VzcywgZmFpbCk7XG4gIH1cblxuICBnZXRWYWxpZExvY2F0aW9ucyhcbiAgICBzdWNjZXNzPzogKGxvY2F0aW9uczogYW55W10pID0+IHZvaWQsXG4gICAgZmFpbD86IChlcnJvcjogYW55KSA9PiB2b2lkXG4gICk6IFByb21pc2U8YW55W10+IHtcbiAgICByZXR1cm4gdGhpcy5lbnN1cmVQbHVnaW4oKS5nZXRWYWxpZExvY2F0aW9ucyhzdWNjZXNzLCBmYWlsKTtcbiAgfVxuXG4gIGdldFZhbGlkTG9jYXRpb25zQW5kRGVsZXRlKFxuICAgIHN1Y2Nlc3M/OiAobG9jYXRpb25zOiBhbnlbXSkgPT4gdm9pZCxcbiAgICBmYWlsPzogKGVycm9yOiBhbnkpID0+IHZvaWRcbiAgKTogUHJvbWlzZTxhbnlbXT4ge1xuICAgIHJldHVybiB0aGlzLmVuc3VyZVBsdWdpbigpLmdldFZhbGlkTG9jYXRpb25zQW5kRGVsZXRlKHN1Y2Nlc3MsIGZhaWwpO1xuICB9XG5cbiAgZGVsZXRlTG9jYXRpb24oXG4gICAgbG9jYXRpb25JZDogbnVtYmVyLFxuICAgIHN1Y2Nlc3M/OiAoKSA9PiB2b2lkLFxuICAgIGZhaWw/OiAoZXJyb3I6IGFueSkgPT4gdm9pZFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICByZXR1cm4gdGhpcy5lbnN1cmVQbHVnaW4oKS5kZWxldGVMb2NhdGlvbihsb2NhdGlvbklkLCBzdWNjZXNzLCBmYWlsKTtcbiAgfVxuXG4gIGRlbGV0ZUFsbExvY2F0aW9ucyhcbiAgICBzdWNjZXNzPzogKCkgPT4gdm9pZCxcbiAgICBmYWlsPzogKGVycm9yOiBhbnkpID0+IHZvaWRcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgcmV0dXJuIHRoaXMuZW5zdXJlUGx1Z2luKCkuZGVsZXRlQWxsTG9jYXRpb25zKHN1Y2Nlc3MsIGZhaWwpO1xuICB9XG5cbiAgc3dpdGNoTW9kZShcbiAgICBtb2RlSWQ6IG51bWJlcixcbiAgICBzdWNjZXNzPzogKCkgPT4gdm9pZCxcbiAgICBmYWlsPzogKGVycm9yOiBhbnkpID0+IHZvaWRcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgcmV0dXJuIHRoaXMuZW5zdXJlUGx1Z2luKCkuc3dpdGNoTW9kZShtb2RlSWQsIHN1Y2Nlc3MsIGZhaWwpO1xuICB9XG5cbiAgZm9yY2VTeW5jKFxuICAgIHN1Y2Nlc3M/OiAoKSA9PiB2b2lkLFxuICAgIGZhaWw/OiAoZXJyb3I6IGFueSkgPT4gdm9pZFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICByZXR1cm4gdGhpcy5lbnN1cmVQbHVnaW4oKS5mb3JjZVN5bmMoc3VjY2VzcywgZmFpbCk7XG4gIH1cblxuICBjbGVhclN5bmMoXG4gICAgc3VjY2Vzcz86ICgpID0+IHZvaWQsXG4gICAgZmFpbD86IChlcnJvcjogYW55KSA9PiB2b2lkXG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIHJldHVybiB0aGlzLmVuc3VyZVBsdWdpbigpLmNsZWFyU3luYyhzdWNjZXNzLCBmYWlsKTtcbiAgfVxuXG4gIGdldFBlbmRpbmdTeW5jQ291bnQoXG4gICAgc3VjY2Vzcz86IChjb3VudDogbnVtYmVyKSA9PiB2b2lkLFxuICAgIGZhaWw/OiAoZXJyb3I6IGFueSkgPT4gdm9pZFxuICApOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIHJldHVybiB0aGlzLmVuc3VyZVBsdWdpbigpLmdldFBlbmRpbmdTeW5jQ291bnQoc3VjY2VzcywgZmFpbCk7XG4gIH1cblxuICBzdGFydFNlc3Npb24oXG4gICAgc3VjY2Vzcz86ICgpID0+IHZvaWQsXG4gICAgZmFpbD86IChlcnJvcjogYW55KSA9PiB2b2lkXG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIHJldHVybiB0aGlzLmVuc3VyZVBsdWdpbigpLnN0YXJ0U2Vzc2lvbihzdWNjZXNzLCBmYWlsKTtcbiAgfVxuXG4gIGdldFNlc3Npb25Mb2NhdGlvbnMoXG4gICAgc3VjY2Vzcz86IChsb2NhdGlvbnM6IGFueVtdKSA9PiB2b2lkLFxuICAgIGZhaWw/OiAoZXJyb3I6IGFueSkgPT4gdm9pZFxuICApOiBQcm9taXNlPGFueVtdPiB7XG4gICAgcmV0dXJuIHRoaXMuZW5zdXJlUGx1Z2luKCkuZ2V0U2Vzc2lvbkxvY2F0aW9ucyhzdWNjZXNzLCBmYWlsKTtcbiAgfVxuXG4gIGNsZWFyU2Vzc2lvbihcbiAgICBzdWNjZXNzPzogKCkgPT4gdm9pZCxcbiAgICBmYWlsPzogKGVycm9yOiBhbnkpID0+IHZvaWRcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgcmV0dXJuIHRoaXMuZW5zdXJlUGx1Z2luKCkuY2xlYXJTZXNzaW9uKHN1Y2Nlc3MsIGZhaWwpO1xuICB9XG5cbiAgZ2V0U2Vzc2lvbkxvY2F0aW9uc0NvdW50KFxuICAgIHN1Y2Nlc3M/OiAoY291bnQ6IG51bWJlcikgPT4gdm9pZCxcbiAgICBmYWlsPzogKGVycm9yOiBhbnkpID0+IHZvaWRcbiAgKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICByZXR1cm4gdGhpcy5lbnN1cmVQbHVnaW4oKS5nZXRTZXNzaW9uTG9jYXRpb25zQ291bnQoc3VjY2VzcywgZmFpbCk7XG4gIH1cblxuICBnZXRDb25maWcoXG4gICAgc3VjY2Vzcz86IChjb25maWc6IGFueSkgPT4gdm9pZCxcbiAgICBmYWlsPzogKGVycm9yOiBhbnkpID0+IHZvaWRcbiAgKTogUHJvbWlzZTxhbnk+IHtcbiAgICByZXR1cm4gdGhpcy5lbnN1cmVQbHVnaW4oKS5nZXRDb25maWcoc3VjY2VzcywgZmFpbCk7XG4gIH1cblxuICBnZXRMb2dFbnRyaWVzKFxuICAgIGxpbWl0OiBudW1iZXIsXG4gICAgZnJvbUlkOiBudW1iZXIsXG4gICAgbWluTGV2ZWw6IHN0cmluZyxcbiAgICBzdWNjZXNzPzogKGVudHJpZXM6IGFueVtdKSA9PiB2b2lkLFxuICAgIGZhaWw/OiAoZXJyb3I6IGFueSkgPT4gdm9pZFxuICApOiBQcm9taXNlPGFueVtdPiB7XG4gICAgcmV0dXJuIHRoaXMuZW5zdXJlUGx1Z2luKCkuZ2V0TG9nRW50cmllcyhsaW1pdCwgZnJvbUlkLCBtaW5MZXZlbCwgc3VjY2VzcywgZmFpbCk7XG4gIH1cblxuICByZW1vdmVBbGxMaXN0ZW5lcnMoZXZlbnQ/OiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aGlzLmVuc3VyZVBsdWdpbigpLnJlbW92ZUFsbExpc3RlbmVycyhldmVudCk7XG4gIH1cblxuICBzdGFydFRhc2soXG4gICAgc3VjY2Vzcz86ICh0YXNrS2V5OiBudW1iZXIpID0+IHZvaWQsXG4gICAgZmFpbD86IChlcnJvcjogYW55KSA9PiB2b2lkXG4gICk6IFByb21pc2U8bnVtYmVyPiB7XG4gICAgcmV0dXJuIHRoaXMuZW5zdXJlUGx1Z2luKCkuc3RhcnRUYXNrKHN1Y2Nlc3MsIGZhaWwpO1xuICB9XG5cbiAgZW5kVGFzayhcbiAgICB0YXNrS2V5OiBudW1iZXIsXG4gICAgc3VjY2Vzcz86ICgpID0+IHZvaWQsXG4gICAgZmFpbD86IChlcnJvcjogYW55KSA9PiB2b2lkXG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIHJldHVybiB0aGlzLmVuc3VyZVBsdWdpbigpLmVuZFRhc2sodGFza0tleSwgc3VjY2VzcywgZmFpbCk7XG4gIH1cblxuICBoZWFkbGVzc1Rhc2sodGFzazogKGV2ZW50OiBhbnkpID0+IHZvaWQpOiB2b2lkIHtcbiAgICB0aGlzLmVuc3VyZVBsdWdpbigpLmhlYWRsZXNzVGFzayh0YXNrKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWdpc3RlciBhbiBldmVudCBsaXN0ZW5lci4gQ29tcGF0aWJsZSB3aXRoIEF3ZXNvbWUtc3R5bGUgdXNhZ2U6XG4gICAqIC5vbihCYWNrZ3JvdW5kR2VvbG9jYXRpb25FdmVudHMuZXJyb3IpLnN1YnNjcmliZSgoZXJyKSA9PiAuLi4pIOKAlCByZXR1cm5zIHN1YnNjcmlwdGlvbiB3aXRoIC51bnN1YnNjcmliZSgpLlxuICAgKiAub24oJ2xvY2F0aW9uJywgKGxvYykgPT4gLi4uKSDigJQgYWxzbyBzdXBwb3J0ZWQ7IHJldHVybmVkIG9iamVjdCBoYXMgLnVuc3Vic2NyaWJlKCkuXG4gICAqL1xuICBvbihldmVudE5hbWU6IHN0cmluZywgY2FsbGJhY2s/OiAodmFsdWU6IGFueSkgPT4gdm9pZCk6IHsgc3Vic2NyaWJlKGNiOiAodmFsdWU6IGFueSkgPT4gdm9pZCk6IHsgdW5zdWJzY3JpYmUoKTogdm9pZCB9OyB1bnN1YnNjcmliZSgpOiB2b2lkIH0ge1xuICAgIGNvbnN0IHBsdWdpbiA9IHRoaXMuZW5zdXJlUGx1Z2luKCk7XG4gICAgaWYgKGNhbGxiYWNrICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGNvbnN0IHN1YiA9IHBsdWdpbi5vbihldmVudE5hbWUsIGNhbGxiYWNrKSBhcyB7IHJlbW92ZT86ICgpID0+IHZvaWQgfTtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHN1YnNjcmliZShjYjogKHZhbHVlOiBhbnkpID0+IHZvaWQpIHtcbiAgICAgICAgICBjb25zdCBzID0gY2IgPyAocGx1Z2luLm9uKGV2ZW50TmFtZSwgY2IpIGFzIHsgcmVtb3ZlPzogKCkgPT4gdm9pZCB9KSA6IG51bGw7XG4gICAgICAgICAgcmV0dXJuIHsgdW5zdWJzY3JpYmUoKSB7IHM/LnJlbW92ZT8uKCk7IH0gfTtcbiAgICAgICAgfSxcbiAgICAgICAgdW5zdWJzY3JpYmUoKSB7IHN1Yi5yZW1vdmU/LigpOyB9XG4gICAgICB9O1xuICAgIH1cbiAgICBjb25zdCBjaGFubmVsID0gcGx1Z2luLm9uKGV2ZW50TmFtZSkgYXMgeyBzdWJzY3JpYmU6IChjYjogKHY6IGFueSkgPT4gdm9pZCkgPT4gdm9pZDsgdW5zdWJzY3JpYmU6IChjYjogKHY6IGFueSkgPT4gdm9pZCkgPT4gdm9pZCB9O1xuICAgIHJldHVybiB7XG4gICAgICBzdWJzY3JpYmUoY2I6ICh2YWx1ZTogYW55KSA9PiB2b2lkKSB7XG4gICAgICAgIGNoYW5uZWwuc3Vic2NyaWJlKGNiKTtcbiAgICAgICAgcmV0dXJuIHsgdW5zdWJzY3JpYmUoKSB7IGNoYW5uZWwudW5zdWJzY3JpYmUoY2IpOyB9IH07XG4gICAgICB9LFxuICAgICAgdW5zdWJzY3JpYmUoKSB7IC8qIG5vLW9wIHdoZW4gbm8gY2FsbGJhY2sgKi8gfVxuICAgIH07XG4gIH1cblxuICAvKiogQ29udmVuaWVuY2U6IGFjY2VzcyBwbHVnaW4gY29uc3RhbnRzIChlLmcuIEFDVElWSVRZX1BST1ZJREVSLCBISUdIX0FDQ1VSQUNZKS4gKi9cbiAgZ2V0IG5hdGl2ZSgpOiBhbnkge1xuICAgIHJldHVybiB0aGlzLnBsdWdpbjtcbiAgfVxufVxuIl19
|