mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-12-29 20:15:50 +01:00
Merge branch 'bip-wip'
This commit is contained in:
commit
c493df2423
@ -15,6 +15,8 @@
|
||||
*/
|
||||
package nodomain.freeyourgadget.gadgetbridge.daogen;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import de.greenrobot.daogenerator.DaoGenerator;
|
||||
import de.greenrobot.daogenerator.Entity;
|
||||
import de.greenrobot.daogenerator.Index;
|
||||
@ -32,6 +34,7 @@ public class GBDaoGenerator {
|
||||
private static final String MAIN_PACKAGE = "nodomain.freeyourgadget.gadgetbridge";
|
||||
private static final String MODEL_PACKAGE = MAIN_PACKAGE + ".model";
|
||||
private static final String VALID_BY_DATE = MODEL_PACKAGE + ".ValidByDate";
|
||||
private static final String ACTIVITY_SUMMARY = MODEL_PACKAGE + ".ActivitySummary";
|
||||
private static final String OVERRIDE = "@Override";
|
||||
private static final String SAMPLE_RAW_INTENSITY = "rawIntensity";
|
||||
private static final String SAMPLE_STEPS = "steps";
|
||||
@ -42,7 +45,7 @@ public class GBDaoGenerator {
|
||||
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
Schema schema = new Schema(17, MAIN_PACKAGE + ".entities");
|
||||
Schema schema = new Schema(18, MAIN_PACKAGE + ".entities");
|
||||
|
||||
Entity userAttributes = addUserAttributes(schema);
|
||||
Entity user = addUserInfo(schema, userAttributes);
|
||||
@ -69,6 +72,8 @@ public class GBDaoGenerator {
|
||||
|
||||
addCalendarSyncState(schema, device);
|
||||
|
||||
addBipActivitySummary(schema, user, device);
|
||||
|
||||
new DaoGenerator().generateAll(schema, "app/src/main/java");
|
||||
}
|
||||
|
||||
@ -309,6 +314,31 @@ public class GBDaoGenerator {
|
||||
calendarSyncState.addIntProperty("hash").notNull();
|
||||
}
|
||||
|
||||
private static void addBipActivitySummary(Schema schema, Entity user, Entity device) {
|
||||
Entity summary = addEntity(schema, "BaseActivitySummary");
|
||||
summary.implementsInterface(ACTIVITY_SUMMARY);
|
||||
summary.addIdProperty();
|
||||
|
||||
summary.setJavaDoc(
|
||||
"This class represents the summary of a user's activity event. I.e. a walk, hike, a bicycle tour, etc.");
|
||||
|
||||
summary.addStringProperty("name").codeBeforeGetter(OVERRIDE);
|
||||
summary.addDateProperty("startTime").notNull().codeBeforeGetter(OVERRIDE);
|
||||
summary.addDateProperty("endTime").notNull().codeBeforeGetter(OVERRIDE);
|
||||
summary.addIntProperty("activityKind").notNull().codeBeforeGetter(OVERRIDE);
|
||||
|
||||
summary.addIntProperty("baseLongitude").javaDocGetterAndSetter("Temporary, bip-specific");
|
||||
summary.addIntProperty("baseLatitude").javaDocGetterAndSetter("Temporary, bip-specific");
|
||||
summary.addIntProperty("baseAltitude").javaDocGetterAndSetter("Temporary, bip-specific");
|
||||
|
||||
summary.addStringProperty("gpxTrack").codeBeforeGetter(OVERRIDE);
|
||||
|
||||
Property deviceId = summary.addLongProperty("deviceId").notNull().codeBeforeGetter(OVERRIDE).getProperty();
|
||||
summary.addToOne(device, deviceId);
|
||||
Property userId = summary.addLongProperty("userId").notNull().codeBeforeGetter(OVERRIDE).getProperty();
|
||||
summary.addToOne(user, userId);
|
||||
}
|
||||
|
||||
private static Property findProperty(Entity entity, String propertyName) {
|
||||
for (Property prop : entity.getProperties()) {
|
||||
if (propertyName.equals(prop.getPropertyName())) {
|
||||
|
@ -59,6 +59,10 @@
|
||||
android:name=".devices.miband.MiBandPreferencesActivity"
|
||||
android:label="@string/preferences_miband_settings"
|
||||
android:parentActivityName=".activities.SettingsActivity" />
|
||||
<activity
|
||||
android:name=".activities.ActivitySummariesActivity"
|
||||
android:label="@string/activity_summaries"
|
||||
android:parentActivityName=".activities.ControlCenterv2" />
|
||||
<activity
|
||||
android:launchMode="singleTop"
|
||||
android:name=".activities.appmanager.AppManagerActivity"
|
||||
@ -415,7 +419,7 @@
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/screenshot_provider_paths"/>
|
||||
android:resource="@xml/shared_paths" />
|
||||
</provider>
|
||||
|
||||
<receiver android:name=".SleepAlarmWidget">
|
||||
|
@ -25,6 +25,9 @@ import android.app.NotificationManager.Policy;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.database.Cursor;
|
||||
@ -607,4 +610,24 @@ public class GBApplication extends Application {
|
||||
public static Locale getLanguage() {
|
||||
return language;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
try {
|
||||
return getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_META_DATA).versionName;
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
GB.log("Unable to determine Gadgetbridge's version", GB.WARN, e);
|
||||
return "0.0.0";
|
||||
}
|
||||
}
|
||||
|
||||
public String getNameAndVersion() {
|
||||
try {
|
||||
ApplicationInfo appInfo = getPackageManager().getApplicationInfo(getContext().getPackageName(), PackageManager.GET_META_DATA);
|
||||
PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_META_DATA);
|
||||
return String.format("%s %s", appInfo.name, packageInfo.versionName);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
GB.log("Unable to determine Gadgetbridge's name/version", GB.WARN, e);
|
||||
return "Gadgetbridge";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -148,7 +148,7 @@ public abstract class Logging {
|
||||
}
|
||||
StringBuilder builder = new StringBuilder(bytes.length * 5);
|
||||
for (byte b : bytes) {
|
||||
builder.append(String.format("0x%2x", b));
|
||||
builder.append(String.format("0x%02x", b));
|
||||
builder.append(" ");
|
||||
}
|
||||
return builder.toString().trim();
|
||||
|
@ -0,0 +1,51 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.activities;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.widget.ListView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.adapter.AbstractItemAdapter;
|
||||
import nodomain.freeyourgadget.gadgetbridge.adapter.ItemWithDetailsAdapter;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.BaseActivitySummary;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.BaseActivitySummaryDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.GenericItem;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ItemWithDetails;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
|
||||
public abstract class AbstractListActivity<T> extends AbstractGBActivity {
|
||||
private AbstractItemAdapter<T> itemAdapter;
|
||||
private ListView itemListView;
|
||||
|
||||
public void setItemAdapter(AbstractItemAdapter<T> itemAdapter) {
|
||||
this.itemAdapter = itemAdapter;
|
||||
itemListView.setAdapter(itemAdapter);
|
||||
}
|
||||
|
||||
protected void refresh() {
|
||||
this.itemAdapter.loadItems();
|
||||
}
|
||||
|
||||
public AbstractItemAdapter<T> getItemAdapter() {
|
||||
return itemAdapter;
|
||||
}
|
||||
|
||||
public ListView getItemListView() {
|
||||
return itemListView;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.activity_list);
|
||||
itemListView = (ListView) findViewById(R.id.itemListView);
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.activities;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.adapter.ActivitySummariesAdapter;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.BaseActivitySummary;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySummary;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.AndroidUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
|
||||
public class ActivitySummariesActivity extends AbstractListActivity<BaseActivitySummary> {
|
||||
|
||||
private int selectedIndex;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setItemAdapter(new ActivitySummariesAdapter(this));
|
||||
|
||||
getItemListView().setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
Object item = parent.getItemAtPosition(position);
|
||||
if (item != null) {
|
||||
ActivitySummary summary = (ActivitySummary) item;
|
||||
String gpxTrack = summary.getGpxTrack();
|
||||
if (gpxTrack != null) {
|
||||
showTrack(gpxTrack);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
getItemListView().setOnCreateContextMenuListener(new View.OnCreateContextMenuListener() {
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View v, final ContextMenu.ContextMenuInfo menuInfo) {
|
||||
MenuItem delete = menu.add("Delete");
|
||||
delete.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
deleteItemAt(selectedIndex);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
getItemListView().setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
|
||||
@Override
|
||||
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
selectedIndex = position;
|
||||
return getItemListView().showContextMenu();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void deleteItemAt(int position) {
|
||||
BaseActivitySummary item = getItemAdapter().getItem(position);
|
||||
if (item != null) {
|
||||
item.delete();
|
||||
getItemAdapter().remove(item);
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
|
||||
private void showTrack(String gpxTrack) {
|
||||
try {
|
||||
AndroidUtils.viewFile(gpxTrack, Intent.ACTION_VIEW, this);
|
||||
} catch (IOException e) {
|
||||
GB.toast(this, "Unable to display GPX track: " + e.getMessage(), Toast.LENGTH_LONG, GB.ERROR, e);
|
||||
}
|
||||
}
|
||||
}
|
@ -27,4 +27,8 @@ public class HeartRateUtils {
|
||||
* Value is in minutes
|
||||
*/
|
||||
public static final int MAX_HR_MEASUREMENTS_GAP_MINUTES = 10;
|
||||
|
||||
public static boolean isValidHeartRateValue(int value) {
|
||||
return value > HeartRateUtils.MIN_HEART_RATE_VALUE && value < HeartRateUtils.MAX_HEART_RATE_VALUE;
|
||||
}
|
||||
}
|
||||
|
@ -70,6 +70,8 @@ import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
|
||||
|
||||
import static nodomain.freeyourgadget.gadgetbridge.activities.HeartRateUtils.isValidHeartRateValue;
|
||||
|
||||
/**
|
||||
* A base class fragment to be used with ChartsActivity. The fragment can supply
|
||||
* a title to be displayed in the activity by returning non-null in #getTitle()
|
||||
@ -439,6 +441,7 @@ public abstract class AbstractChartFragment extends AbstractGBFragment {
|
||||
List<Entry> notWornEntries = new ArrayList<>(numEntries);
|
||||
boolean hr = supportsHeartrate(gbDevice);
|
||||
List<Entry> heartrateEntries = hr ? new ArrayList<Entry>(numEntries) : null;
|
||||
List<Integer> colors = new ArrayList<>(numEntries); // this is kinda inefficient...
|
||||
int lastHrSampleIndex = -1;
|
||||
|
||||
for (int i = 0; i < numEntries; i++) {
|
||||
@ -509,7 +512,7 @@ public abstract class AbstractChartFragment extends AbstractGBFragment {
|
||||
}
|
||||
activityEntries.add(createLineEntry(value, ts));
|
||||
}
|
||||
if (hr && sample.getKind() != ActivityKind.TYPE_NOT_WORN && isValidHeartRateValue(sample.getHeartRate())) {
|
||||
if (hr && sample.getKind() != ActivityKind.TYPE_NOT_WORN && HeartRateUtils.isValidHeartRateValue(sample.getHeartRate())) {
|
||||
if (lastHrSampleIndex > -1 && ts - lastHrSampleIndex > 1800*HeartRateUtils.MAX_HR_MEASUREMENTS_GAP_MINUTES) {
|
||||
heartrateEntries.add(createLineEntry(0, lastHrSampleIndex + 1));
|
||||
heartrateEntries.add(createLineEntry(0, ts - 1));
|
||||
@ -574,10 +577,6 @@ public abstract class AbstractChartFragment extends AbstractGBFragment {
|
||||
return new DefaultChartsData(lineData, xValueFormatter);
|
||||
}
|
||||
|
||||
protected boolean isValidHeartRateValue(int value) {
|
||||
return value > HeartRateUtils.MIN_HEART_RATE_VALUE && value < HeartRateUtils.MAX_HEART_RATE_VALUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement this to supply the samples to be displayed.
|
||||
*
|
||||
|
@ -168,7 +168,7 @@ public class LiveActivityFragment extends AbstractChartFragment {
|
||||
private void addSample(ActivitySample sample) {
|
||||
int heartRate = sample.getHeartRate();
|
||||
int timestamp = tsTranslation.shorten(sample.getTimestamp());
|
||||
if (isValidHeartRateValue(heartRate)) {
|
||||
if (HeartRateUtils.isValidHeartRateValue(heartRate)) {
|
||||
setCurrentHeartRate(heartRate, timestamp);
|
||||
}
|
||||
int steps = sample.getSteps();
|
||||
|
@ -0,0 +1,122 @@
|
||||
/* Copyright (C) 2015-2017 Andreas Shimokawa, Carsten Pfeiffer
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.DrawableRes;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
|
||||
/**
|
||||
* Adapter for displaying generic ItemWithDetails instances.
|
||||
*/
|
||||
public abstract class AbstractItemAdapter<T> extends ArrayAdapter<T> {
|
||||
|
||||
public static final int SIZE_SMALL = 1;
|
||||
public static final int SIZE_MEDIUM = 2;
|
||||
public static final int SIZE_LARGE = 3;
|
||||
private final Context context;
|
||||
private final List<T> items;
|
||||
private boolean horizontalAlignment;
|
||||
private int size = SIZE_MEDIUM;
|
||||
|
||||
public AbstractItemAdapter(Context context) {
|
||||
this (context, new ArrayList<T>());
|
||||
}
|
||||
|
||||
public AbstractItemAdapter(Context context, List<T> items) {
|
||||
super(context, 0, items);
|
||||
|
||||
this.context = context;
|
||||
this.items = items;
|
||||
}
|
||||
|
||||
public void setHorizontalAlignment(boolean horizontalAlignment) {
|
||||
this.horizontalAlignment = horizontalAlignment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View view, ViewGroup parent) {
|
||||
T item = getItem(position);
|
||||
|
||||
if (view == null) {
|
||||
LayoutInflater inflater = (LayoutInflater) context
|
||||
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
|
||||
if (horizontalAlignment) {
|
||||
view = inflater.inflate(R.layout.item_with_details_horizontal, parent, false);
|
||||
} else {
|
||||
switch (size) {
|
||||
case SIZE_SMALL:
|
||||
view = inflater.inflate(R.layout.item_with_details_small, parent, false);
|
||||
break;
|
||||
default:
|
||||
view = inflater.inflate(R.layout.item_with_details, parent, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ImageView iconView = (ImageView) view.findViewById(R.id.item_image);
|
||||
TextView nameView = (TextView) view.findViewById(R.id.item_name);
|
||||
TextView detailsView = (TextView) view.findViewById(R.id.item_details);
|
||||
|
||||
nameView.setText(getName(item));
|
||||
detailsView.setText(getDetails(item));
|
||||
iconView.setImageResource(getIcon(item));
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
protected abstract String getName(T item);
|
||||
|
||||
protected abstract String getDetails(T item);
|
||||
|
||||
@DrawableRes
|
||||
protected abstract int getIcon(T item);
|
||||
|
||||
public void setSize(int size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public List<T> getItems() {
|
||||
return items;
|
||||
}
|
||||
|
||||
public void loadItems() {
|
||||
}
|
||||
|
||||
public void setItems(List<T> items, boolean notify) {
|
||||
this.items.clear();
|
||||
this.items.addAll(items);
|
||||
if (notify) {
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.BaseActivitySummary;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.BaseActivitySummaryDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
|
||||
public class ActivitySummariesAdapter extends AbstractItemAdapter<BaseActivitySummary> {
|
||||
public ActivitySummariesAdapter(Context context) {
|
||||
super(context);
|
||||
loadItems();
|
||||
}
|
||||
|
||||
public void loadItems() {
|
||||
try (DBHandler handler = GBApplication.acquireDB()) {
|
||||
BaseActivitySummaryDao summaryDao = handler.getDaoSession().getBaseActivitySummaryDao();
|
||||
List<BaseActivitySummary> allSummaries = summaryDao.loadAll();
|
||||
setItems(allSummaries, true);
|
||||
} catch (Exception e) {
|
||||
GB.toast("Error loading activity summaries.", Toast.LENGTH_SHORT, GB.ERROR, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getName(BaseActivitySummary item) {
|
||||
String name = item.getName();
|
||||
if (name != null && name.length() > 0) {
|
||||
return name;
|
||||
}
|
||||
|
||||
Date startTime = item.getStartTime();
|
||||
if (startTime != null) {
|
||||
return DateTimeUtils.formatDateTime(startTime);
|
||||
}
|
||||
return "Unknown activity";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDetails(BaseActivitySummary item) {
|
||||
return ActivityKind.asString(item.getActivityKind(), getContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getIcon(BaseActivitySummary item) {
|
||||
return ActivityKind.getIconId(item.getActivityKind());
|
||||
}
|
||||
}
|
@ -43,6 +43,7 @@ import java.util.List;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.ActivitySummariesActivity;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.ConfigureAlarms;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.VibrationActivity;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.charts.ChartsActivity;
|
||||
@ -210,6 +211,20 @@ public class GBDeviceAdapterv2 extends RecyclerView.Adapter<GBDeviceAdapterv2.Vi
|
||||
}
|
||||
);
|
||||
|
||||
//show activity tracks
|
||||
holder.showActivityTracks.setVisibility(coordinator.supportsActivityTracks() ? View.VISIBLE : View.GONE);
|
||||
holder.showActivityTracks.setOnClickListener(new View.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Intent startIntent;
|
||||
startIntent = new Intent(context, ActivitySummariesActivity.class);
|
||||
startIntent.putExtra(GBDevice.EXTRA_DEVICE, device);
|
||||
context.startActivity(startIntent);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
ItemWithDetailsAdapter infoAdapter = new ItemWithDetailsAdapter(context, device.getDeviceInfos());
|
||||
infoAdapter.setHorizontalAlignment(true);
|
||||
holder.deviceInfoList.setAdapter(infoAdapter);
|
||||
@ -338,6 +353,7 @@ public class GBDeviceAdapterv2 extends RecyclerView.Adapter<GBDeviceAdapterv2.Vi
|
||||
ImageView manageAppsView;
|
||||
ImageView setAlarmsView;
|
||||
ImageView showActivityGraphs;
|
||||
ImageView showActivityTracks;
|
||||
|
||||
ImageView deviceInfoView;
|
||||
//overflow
|
||||
@ -365,6 +381,7 @@ public class GBDeviceAdapterv2 extends RecyclerView.Adapter<GBDeviceAdapterv2.Vi
|
||||
manageAppsView = (ImageView) view.findViewById(R.id.device_action_manage_apps);
|
||||
setAlarmsView = (ImageView) view.findViewById(R.id.device_action_set_alarms);
|
||||
showActivityGraphs = (ImageView) view.findViewById(R.id.device_action_show_activity_graphs);
|
||||
showActivityTracks = (ImageView) view.findViewById(R.id.device_action_show_activity_tracks);
|
||||
deviceInfoView = (ImageView) view.findViewById(R.id.device_info_image);
|
||||
|
||||
deviceInfoBox = (RelativeLayout) view.findViewById(R.id.device_item_infos_box);
|
||||
|
@ -17,77 +17,33 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ItemWithDetails;
|
||||
|
||||
/**
|
||||
* Adapter for displaying generic ItemWithDetails instances.
|
||||
*/
|
||||
public class ItemWithDetailsAdapter extends ArrayAdapter<ItemWithDetails> {
|
||||
|
||||
public static final int SIZE_SMALL = 1;
|
||||
public static final int SIZE_MEDIUM = 2;
|
||||
public static final int SIZE_LARGE = 3;
|
||||
private final Context context;
|
||||
private boolean horizontalAlignment;
|
||||
private int size = SIZE_MEDIUM;
|
||||
public class ItemWithDetailsAdapter extends AbstractItemAdapter<ItemWithDetails> {
|
||||
|
||||
public ItemWithDetailsAdapter(Context context, List<ItemWithDetails> items) {
|
||||
super(context, 0, items);
|
||||
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public void setHorizontalAlignment(boolean horizontalAlignment) {
|
||||
this.horizontalAlignment = horizontalAlignment;
|
||||
super(context, items);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View view, ViewGroup parent) {
|
||||
ItemWithDetails item = getItem(position);
|
||||
|
||||
if (view == null) {
|
||||
LayoutInflater inflater = (LayoutInflater) context
|
||||
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
|
||||
if (horizontalAlignment) {
|
||||
view = inflater.inflate(R.layout.item_with_details_horizontal, parent, false);
|
||||
} else {
|
||||
switch (size) {
|
||||
case SIZE_SMALL:
|
||||
view = inflater.inflate(R.layout.item_with_details_small, parent, false);
|
||||
break;
|
||||
default:
|
||||
view = inflater.inflate(R.layout.item_with_details, parent, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ImageView iconView = (ImageView) view.findViewById(R.id.item_image);
|
||||
TextView nameView = (TextView) view.findViewById(R.id.item_name);
|
||||
TextView detailsView = (TextView) view.findViewById(R.id.item_details);
|
||||
|
||||
nameView.setText(item.getName());
|
||||
detailsView.setText(item.getDetails());
|
||||
iconView.setImageResource(item.getIcon());
|
||||
|
||||
return view;
|
||||
protected String getName(ItemWithDetails item) {
|
||||
return item.getName();
|
||||
}
|
||||
|
||||
public void setSize(int size) {
|
||||
this.size = size;
|
||||
@Override
|
||||
protected String getDetails(ItemWithDetails item) {
|
||||
return item.getDetails();
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return size;
|
||||
@Override
|
||||
protected int getIcon(ItemWithDetails item) {
|
||||
return item.getIcon();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,32 +0,0 @@
|
||||
/* Copyright (C) 2015-2018 Carsten Pfeiffer
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.database;
|
||||
|
||||
/**
|
||||
* Contains the configuration used for particular activity samples.
|
||||
*/
|
||||
public class UsedConfiguration {
|
||||
String fwVersion;
|
||||
String userName;
|
||||
short userWeight;
|
||||
short userSize;
|
||||
// ...
|
||||
int usedFrom; // timestamp
|
||||
int usedUntil; // timestamp
|
||||
short sleepGoal; // minutes
|
||||
short stepsGoal;
|
||||
}
|
@ -124,4 +124,9 @@ public abstract class AbstractDeviceCoordinator implements DeviceCoordinator {
|
||||
public int getBondingStyle(GBDevice device) {
|
||||
return BONDING_STYLE_ASK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsActivityTracks() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -139,6 +139,14 @@ public interface DeviceCoordinator {
|
||||
*/
|
||||
boolean supportsActivityTracking();
|
||||
|
||||
/**
|
||||
* Indicates whether the device supports recording dedicated activity tracks, like
|
||||
* walking, hiking, running, swimming, etc. and retrieving the recorded
|
||||
* data. This is different from the constant activity tracking since the tracks are
|
||||
* usually recorded with additional features, like e.g. GPS.
|
||||
*/
|
||||
boolean supportsActivityTracks();
|
||||
|
||||
/**
|
||||
* Returns true if activity data fetching is supported AND possible at this
|
||||
* very moment. This will consider the device state (being connected/disconnected/busy...)
|
||||
|
@ -0,0 +1,206 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.amazfitbip;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.BaseActivitySummary;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
|
||||
|
||||
public class BipActivitySummary extends BaseActivitySummary {
|
||||
private int version;
|
||||
private float distanceMeters;
|
||||
private float ascentMeters;
|
||||
private float descentMeters;
|
||||
private float minAltitude;
|
||||
private float maxAltitude;
|
||||
private int minLatitude;
|
||||
private int maxLatitude;
|
||||
private int minLongitude;
|
||||
private int maxLongitude;
|
||||
private long steps;
|
||||
private long activeTimeSeconds;
|
||||
private float caloriesBurnt;
|
||||
private float maxSpeed;
|
||||
private float minPace;
|
||||
private float maxPace;
|
||||
private float totalStride;
|
||||
private long timeAscent;
|
||||
private long timeDescent;
|
||||
private long timeFlat;
|
||||
private int averageHR;
|
||||
private int averagePace;
|
||||
private int averageStride;
|
||||
|
||||
// @Override
|
||||
// public long getSteps() {
|
||||
// return steps;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public float getDistanceMeters() {
|
||||
// return distanceMeters;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public float getAscentMeters() {
|
||||
// return ascentMeters;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public float getDescentMeters() {
|
||||
// return descentMeters;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public float getMinAltitude() {
|
||||
// return minAltitude;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public float getMaxAltitude() {
|
||||
// return maxAltitude;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public float getCalories() {
|
||||
// return caloriesBurnt;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public float getMaxSpeed() {
|
||||
// return maxSpeed;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public float getMinSpeed() {
|
||||
// return minPace;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public float getAverageSpeed() {
|
||||
// return averagePace;
|
||||
// }
|
||||
|
||||
public void setVersion(int version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public int getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setDistanceMeters(float distanceMeters) {
|
||||
this.distanceMeters = distanceMeters;
|
||||
}
|
||||
|
||||
public void setAscentMeters(float ascentMeters) {
|
||||
this.ascentMeters = ascentMeters;
|
||||
}
|
||||
|
||||
public void setDescentMeters(float descentMeters) {
|
||||
this.descentMeters = descentMeters;
|
||||
}
|
||||
|
||||
public void setMinAltitude(float minAltitude) {
|
||||
this.minAltitude = minAltitude;
|
||||
}
|
||||
|
||||
public void setMaxAltitude(float maxAltitude) {
|
||||
this.maxAltitude = maxAltitude;
|
||||
}
|
||||
|
||||
public void setMinLatitude(int minLatitude) {
|
||||
this.minLatitude = minLatitude;
|
||||
}
|
||||
|
||||
public void setMaxLatitude(int maxLatitude) {
|
||||
this.maxLatitude = maxLatitude;
|
||||
}
|
||||
|
||||
public void setMinLongitude(int minLongitude) {
|
||||
this.minLongitude = minLongitude;
|
||||
}
|
||||
|
||||
public void setMaxLongitude(int maxLongitude) {
|
||||
this.maxLongitude = maxLongitude;
|
||||
}
|
||||
|
||||
public void setSteps(long steps) {
|
||||
this.steps = steps;
|
||||
}
|
||||
|
||||
public void setActiveTimeSeconds(long activeTimeSeconds) {
|
||||
this.activeTimeSeconds = activeTimeSeconds;
|
||||
}
|
||||
|
||||
public void setCaloriesBurnt(float caloriesBurnt) {
|
||||
this.caloriesBurnt = caloriesBurnt;
|
||||
}
|
||||
|
||||
public void setMaxSpeed(float maxSpeed) {
|
||||
this.maxSpeed = maxSpeed;
|
||||
}
|
||||
|
||||
public void setMinPace(float minPace) {
|
||||
this.minPace = minPace;
|
||||
}
|
||||
|
||||
public void setMaxPace(float maxPace) {
|
||||
this.maxPace = maxPace;
|
||||
}
|
||||
|
||||
public void setTotalStride(float totalStride) {
|
||||
this.totalStride = totalStride;
|
||||
}
|
||||
|
||||
public float getTotalStride() {
|
||||
return totalStride;
|
||||
}
|
||||
|
||||
public void setTimeAscent(long timeAscent) {
|
||||
this.timeAscent = timeAscent;
|
||||
}
|
||||
|
||||
public long getTimeAscent() {
|
||||
return timeAscent;
|
||||
}
|
||||
|
||||
public void setTimeDescent(long timeDescent) {
|
||||
this.timeDescent = timeDescent;
|
||||
}
|
||||
|
||||
public long getTimeDescent() {
|
||||
return timeDescent;
|
||||
}
|
||||
|
||||
public void setTimeFlat(long timeFlat) {
|
||||
this.timeFlat = timeFlat;
|
||||
}
|
||||
|
||||
public long getTimeFlat() {
|
||||
return timeFlat;
|
||||
}
|
||||
|
||||
public void setAverageHR(int averageHR) {
|
||||
this.averageHR = averageHR;
|
||||
}
|
||||
|
||||
public int getAverageHR() {
|
||||
return averageHR;
|
||||
}
|
||||
|
||||
public void setAveragePace(int averagePace) {
|
||||
this.averagePace = averagePace;
|
||||
}
|
||||
|
||||
public int getAveragePace() {
|
||||
return averagePace;
|
||||
}
|
||||
|
||||
public void setAverageStride(int averageStride) {
|
||||
this.averageStride = averageStride;
|
||||
}
|
||||
|
||||
public int getAverageStride() {
|
||||
return averageStride;
|
||||
}
|
||||
}
|
@ -64,6 +64,11 @@ public class AmazfitBipCoordinator extends HuamiCoordinator {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsActivityTracks() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsWeather() {
|
||||
return true;
|
||||
|
@ -36,5 +36,8 @@ public class AmazfitBipService {
|
||||
public static final byte[] COMMAND_SET_LANGUAGE_NEW_TEMPLATE = new byte[]{ENDPOINT_DISPLAY, 0x17, 0x00, 0, 0, 0, 0, 0};
|
||||
|
||||
|
||||
public static final byte COMMAND_ACTIVITY_DATA_TYPE_SPORTS_SUMMARIES = 0x05;
|
||||
public static final byte COMMAND_ACTIVITY_DATA_TYPE_SPORTS_DETAILS = 0x06;
|
||||
|
||||
public static final byte[] COMMAND_ACK_FIND_PHONE_IN_PROGRESS = new byte[]{ENDPOINT_DISPLAY, 0x14, 0x00, 0x00};
|
||||
}
|
||||
|
@ -20,38 +20,15 @@ package nodomain.freeyourgadget.gadgetbridge.devices.miband;
|
||||
import java.util.List;
|
||||
|
||||
import de.greenrobot.dao.query.QueryBuilder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.miband2.MiBand2Const;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.MiBandActivitySample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.MiBandActivitySampleDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.miband2.MiBand2Const.*;
|
||||
|
||||
public class MiBand2SampleProvider extends AbstractMiBandSampleProvider {
|
||||
|
||||
|
||||
// observed the following values so far:
|
||||
// 00 01 02 09 0a 0b 0c 10 11
|
||||
|
||||
// 0 = same activity kind as before
|
||||
// 1 = light activity walking?
|
||||
// 3 = definitely non-wear
|
||||
// 9 = probably light sleep, definitely some kind of sleep
|
||||
// 10 = ignore, except for hr (if valid)
|
||||
// 11 = probably deep sleep
|
||||
// 12 = definitely wake up
|
||||
// 17 = definitely not sleep related
|
||||
|
||||
public static final int TYPE_UNSET = -1;
|
||||
public static final int TYPE_NO_CHANGE = 0;
|
||||
public static final int TYPE_ACTIVITY = 1;
|
||||
public static final int TYPE_RUNNING = 2;
|
||||
public static final int TYPE_NONWEAR = 3;
|
||||
public static final int TYPE_CHARGING = 6;
|
||||
public static final int TYPE_LIGHT_SLEEP = 9;
|
||||
public static final int TYPE_IGNORE = 10;
|
||||
public static final int TYPE_DEEP_SLEEP = 11;
|
||||
public static final int TYPE_WAKE_UP = 12;
|
||||
|
||||
public MiBand2SampleProvider(GBDevice device, DaoSession session) {
|
||||
super(device, session);
|
||||
}
|
||||
@ -111,39 +88,11 @@ public class MiBand2SampleProvider extends AbstractMiBandSampleProvider {
|
||||
|
||||
@Override
|
||||
public int normalizeType(int rawType) {
|
||||
switch (rawType) {
|
||||
case TYPE_DEEP_SLEEP:
|
||||
return ActivityKind.TYPE_DEEP_SLEEP;
|
||||
case TYPE_LIGHT_SLEEP:
|
||||
return ActivityKind.TYPE_LIGHT_SLEEP;
|
||||
case TYPE_ACTIVITY:
|
||||
case TYPE_RUNNING:
|
||||
case TYPE_WAKE_UP:
|
||||
return ActivityKind.TYPE_ACTIVITY;
|
||||
case TYPE_NONWEAR:
|
||||
return ActivityKind.TYPE_NOT_WORN;
|
||||
case TYPE_CHARGING:
|
||||
return ActivityKind.TYPE_NOT_WORN; //I believe it's a safe assumption
|
||||
default:
|
||||
case TYPE_UNSET: // fall through
|
||||
return ActivityKind.TYPE_UNKNOWN;
|
||||
}
|
||||
return MiBand2Const.toActivityKind(rawType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int toRawActivityKind(int activityKind) {
|
||||
switch (activityKind) {
|
||||
case ActivityKind.TYPE_ACTIVITY:
|
||||
return TYPE_ACTIVITY;
|
||||
case ActivityKind.TYPE_DEEP_SLEEP:
|
||||
return TYPE_DEEP_SLEEP;
|
||||
case ActivityKind.TYPE_LIGHT_SLEEP:
|
||||
return TYPE_LIGHT_SLEEP;
|
||||
case ActivityKind.TYPE_NOT_WORN:
|
||||
return TYPE_NONWEAR;
|
||||
case ActivityKind.TYPE_UNKNOWN: // fall through
|
||||
default:
|
||||
return TYPE_UNSET;
|
||||
}
|
||||
return MiBand2Const.toRawActivityType(activityKind);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,68 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.miband2;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
|
||||
|
||||
public class MiBand2Const {
|
||||
// observed the following values so far:
|
||||
// 00 01 02 09 0a 0b 0c 10 11
|
||||
|
||||
// 0 = same activity kind as before
|
||||
// 1 = light activity walking?
|
||||
// 3 = definitely non-wear
|
||||
// 9 = probably light sleep, definitely some kind of sleep
|
||||
// 10 = ignore, except for hr (if valid)
|
||||
// 11 = probably deep sleep
|
||||
// 12 = definitely wake up
|
||||
// 17 = definitely not sleep related
|
||||
|
||||
public static final int TYPE_UNSET = -1;
|
||||
public static final int TYPE_NO_CHANGE = 0;
|
||||
public static final int TYPE_ACTIVITY = 1;
|
||||
public static final int TYPE_RUNNING = 2;
|
||||
public static final int TYPE_NONWEAR = 3;
|
||||
public static final int TYPE_RIDE_BIKE = 4;
|
||||
public static final int TYPE_CHARGING = 6;
|
||||
public static final int TYPE_LIGHT_SLEEP = 9;
|
||||
public static final int TYPE_IGNORE = 10;
|
||||
public static final int TYPE_DEEP_SLEEP = 11;
|
||||
public static final int TYPE_WAKE_UP = 12;
|
||||
|
||||
public static int toActivityKind(int rawType) {
|
||||
switch (rawType) {
|
||||
case TYPE_DEEP_SLEEP:
|
||||
return ActivityKind.TYPE_DEEP_SLEEP;
|
||||
case TYPE_LIGHT_SLEEP:
|
||||
return ActivityKind.TYPE_LIGHT_SLEEP;
|
||||
case TYPE_ACTIVITY:
|
||||
case TYPE_RUNNING:
|
||||
case TYPE_WAKE_UP:
|
||||
return ActivityKind.TYPE_ACTIVITY;
|
||||
case TYPE_NONWEAR:
|
||||
return ActivityKind.TYPE_NOT_WORN;
|
||||
case TYPE_CHARGING:
|
||||
return ActivityKind.TYPE_NOT_WORN; //I believe it's a safe assumption
|
||||
case TYPE_RIDE_BIKE:
|
||||
return ActivityKind.TYPE_CYCLING;
|
||||
default:
|
||||
case TYPE_UNSET: // fall through
|
||||
return ActivityKind.TYPE_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
public static int toRawActivityType(int activityKind) {
|
||||
switch (activityKind) {
|
||||
case ActivityKind.TYPE_ACTIVITY:
|
||||
return TYPE_ACTIVITY;
|
||||
case ActivityKind.TYPE_DEEP_SLEEP:
|
||||
return TYPE_DEEP_SLEEP;
|
||||
case ActivityKind.TYPE_LIGHT_SLEEP:
|
||||
return TYPE_LIGHT_SLEEP;
|
||||
case ActivityKind.TYPE_NOT_WORN:
|
||||
return TYPE_NONWEAR;
|
||||
case ActivityKind.TYPE_UNKNOWN: // fall through
|
||||
default:
|
||||
return TYPE_UNSET;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.export;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityTrack;
|
||||
|
||||
public interface ActivityTrackExporter {
|
||||
@NonNull
|
||||
String getDefaultFileName(@NonNull ActivityTrack track);
|
||||
|
||||
void performExport(ActivityTrack track, File targetFile) throws IOException;
|
||||
}
|
@ -0,0 +1,158 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.export;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Xml;
|
||||
|
||||
import org.xmlpull.v1.XmlSerializer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.HeartRateUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityPoint;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityTrack;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.GPSCoordinate;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
|
||||
|
||||
public class GPXExporter implements ActivityTrackExporter {
|
||||
private static final String NS_DEFAULT = "";
|
||||
private static final String NS_DEFAULT_URI = "http://www.topografix.com/GPX/1/1";
|
||||
private static final String NS_DEFAULT_PREFIX = "";
|
||||
private static final String NS_TRACKPOINT_EXTENSION = "gpxtpx";
|
||||
private static final String NS_TRACKPOINT_EXTENSION_URI = "http://www.garmin.com/xmlschemas/TrackPointExtension/v1";
|
||||
private static final String NS_XSI_URI = "http://www.w3.org/2001/XMLSchema-instance";
|
||||
|
||||
private String creator;
|
||||
private boolean includeHeartRate = true;
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getDefaultFileName(@NonNull ActivityTrack track) {
|
||||
return FileUtils.makeValidFileName(track.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void performExport(ActivityTrack track, File targetFile) throws IOException {
|
||||
String encoding = StandardCharsets.UTF_8.name();
|
||||
XmlSerializer ser = Xml.newSerializer();
|
||||
try {
|
||||
ser.setOutput(new FileOutputStream(targetFile), encoding);
|
||||
ser.startDocument(encoding, Boolean.TRUE);
|
||||
ser.setPrefix("xsi", NS_XSI_URI);
|
||||
ser.setPrefix(NS_DEFAULT_PREFIX, NS_DEFAULT);
|
||||
|
||||
ser.startTag(NS_DEFAULT, "gpx");
|
||||
ser.attribute(NS_DEFAULT, "version", "1.1");
|
||||
ser.attribute(NS_DEFAULT, "creator", getCreator());
|
||||
ser.attribute(NS_XSI_URI, "schemaLocation", NS_DEFAULT_URI + " " + "http://www.topografix.com/GPX/1/1/gpx.xsd");
|
||||
|
||||
exportMetadata(ser, track);
|
||||
exportTrack(ser, track);
|
||||
|
||||
ser.endTag(NS_DEFAULT, "gpx");
|
||||
ser.endDocument();
|
||||
} finally {
|
||||
ser.flush();
|
||||
}
|
||||
}
|
||||
|
||||
private void exportMetadata(XmlSerializer ser, ActivityTrack track) throws IOException {
|
||||
ser.startTag(NS_DEFAULT, "metadata");
|
||||
ser.startTag(NS_DEFAULT, "name").text(track.getName()).endTag(NS_DEFAULT, "name");
|
||||
|
||||
ser.startTag(NS_DEFAULT, "author");
|
||||
ser.startTag(NS_DEFAULT, "name").text(track.getUser().getName()).endTag(NS_DEFAULT, "name");
|
||||
ser.endTag(NS_DEFAULT, "author");
|
||||
|
||||
ser.startTag(NS_DEFAULT, "time").text(formatTime(new Date())).endTag(NS_DEFAULT, "time");
|
||||
|
||||
ser.endTag(NS_DEFAULT, "metadata");
|
||||
}
|
||||
|
||||
private String formatTime(Date date) {
|
||||
return DateTimeUtils.formatIso8601(date);
|
||||
}
|
||||
|
||||
private void exportTrack(XmlSerializer ser, ActivityTrack track) throws IOException {
|
||||
ser.startTag(NS_DEFAULT, "trk");
|
||||
ser.startTag(NS_DEFAULT, "trkseg");
|
||||
|
||||
List<ActivityPoint> trackPoints = track.getTrackPoints();
|
||||
String source = getSource(track);
|
||||
for (ActivityPoint point : trackPoints) {
|
||||
exportTrackPoint(ser, point, source);
|
||||
}
|
||||
|
||||
ser.endTag(NS_DEFAULT, "trkseg");
|
||||
ser.endTag(NS_DEFAULT, "trk");
|
||||
}
|
||||
|
||||
private String getSource(ActivityTrack track) {
|
||||
return track.getDevice().getName();
|
||||
}
|
||||
|
||||
private void exportTrackPoint(XmlSerializer ser, ActivityPoint point, String source) throws IOException {
|
||||
GPSCoordinate location = point.getLocation();
|
||||
if (location == null) {
|
||||
return; // skip invalid points, that just contain hr data, for example
|
||||
}
|
||||
ser.startTag(NS_DEFAULT, "trkpt");
|
||||
ser.attribute(NS_DEFAULT, "lon", formatLocation(location.getLongitude()));
|
||||
ser.attribute(NS_DEFAULT, "lat", formatLocation(location.getLatitude()));
|
||||
ser.startTag(NS_DEFAULT, "ele").text(formatLocation(location.getAltitude())).endTag(NS_DEFAULT, "ele");
|
||||
ser.startTag(NS_DEFAULT, "time").text(formatTime(point.getTime())).endTag(NS_DEFAULT, "time");
|
||||
String description = point.getDescription();
|
||||
if (description != null) {
|
||||
ser.startTag(NS_DEFAULT, "desc").text(description).endTag(NS_DEFAULT, "desc");
|
||||
}
|
||||
ser.startTag(NS_DEFAULT, "src").text(source).endTag(NS_DEFAULT, "src");
|
||||
|
||||
exportTrackpointExtensions(ser, point);
|
||||
|
||||
ser.endTag(NS_DEFAULT, "trkpt");
|
||||
}
|
||||
|
||||
private void exportTrackpointExtensions(XmlSerializer ser, ActivityPoint point) throws IOException {
|
||||
if (!includeHeartRate) {
|
||||
return;
|
||||
}
|
||||
|
||||
int hr = point.getHeartRate();
|
||||
if (!HeartRateUtils.isValidHeartRateValue(hr)) {
|
||||
return;
|
||||
}
|
||||
ser.startTag(NS_DEFAULT, "extensions");
|
||||
|
||||
ser.setPrefix(NS_TRACKPOINT_EXTENSION, NS_TRACKPOINT_EXTENSION_URI);
|
||||
ser.startTag(NS_TRACKPOINT_EXTENSION_URI, "hr").text(String.valueOf(hr)).endTag(NS_TRACKPOINT_EXTENSION_URI, "hr");
|
||||
|
||||
ser.endTag(NS_DEFAULT, "extensions");
|
||||
}
|
||||
|
||||
private String formatLocation(double value) {
|
||||
return new BigDecimal(value).setScale(GPSCoordinate.GPS_DECIMAL_DEGREES_SCALE, RoundingMode.HALF_UP).toPlainString();
|
||||
}
|
||||
|
||||
public String getCreator() {
|
||||
return creator; // TODO: move to some kind of BrandingInfo class
|
||||
}
|
||||
|
||||
public void setCreator(String creator) {
|
||||
this.creator = creator;
|
||||
}
|
||||
|
||||
public void setIncludeHeartRate(boolean includeHeartRate) {
|
||||
this.includeHeartRate = includeHeartRate;
|
||||
}
|
||||
|
||||
public boolean isIncludeHeartRate() {
|
||||
return includeHeartRate;
|
||||
}
|
||||
}
|
@ -17,8 +17,12 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.model;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.DrawableRes;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
|
||||
|
||||
public class ActivityKind {
|
||||
@ -28,6 +32,11 @@ public class ActivityKind {
|
||||
public static final int TYPE_LIGHT_SLEEP = 2;
|
||||
public static final int TYPE_DEEP_SLEEP = 4;
|
||||
public static final int TYPE_NOT_WORN = 8;
|
||||
public static final int TYPE_RUNNING = 16;
|
||||
public static final int TYPE_WALKING = 32;
|
||||
public static final int TYPE_SWIMMING = 64;
|
||||
public static final int TYPE_CYCLING = 128;
|
||||
public static final int TYPE_TREADMILL = 256;
|
||||
|
||||
public static final int TYPE_SLEEP = TYPE_LIGHT_SLEEP | TYPE_DEEP_SLEEP;
|
||||
public static final int TYPE_ALL = TYPE_ACTIVITY | TYPE_SLEEP | TYPE_NOT_WORN;
|
||||
@ -47,7 +56,75 @@ public class ActivityKind {
|
||||
if ((types & ActivityKind.TYPE_NOT_WORN) != 0) {
|
||||
result[i++] = provider.toRawActivityKind(TYPE_NOT_WORN);
|
||||
}
|
||||
if ((types & ActivityKind.TYPE_RUNNING) != 0) {
|
||||
result[i++] = provider.toRawActivityKind(TYPE_RUNNING);
|
||||
}
|
||||
if ((types & ActivityKind.TYPE_WALKING) != 0) {
|
||||
result[i++] = provider.toRawActivityKind(TYPE_WALKING);
|
||||
}
|
||||
if ((types & ActivityKind.TYPE_SWIMMING) != 0) {
|
||||
result[i++] = provider.toRawActivityKind(TYPE_SWIMMING);
|
||||
}
|
||||
if ((types & ActivityKind.TYPE_CYCLING) != 0) {
|
||||
result[i++] = provider.toRawActivityKind(TYPE_CYCLING);
|
||||
}
|
||||
if ((types & ActivityKind.TYPE_TREADMILL) != 0) {
|
||||
result[i++] = provider.toRawActivityKind(TYPE_TREADMILL);
|
||||
}
|
||||
return Arrays.copyOf(result, i);
|
||||
}
|
||||
|
||||
public static String asString(int kind, Context context) {
|
||||
switch (kind) {
|
||||
case TYPE_NOT_MEASURED:
|
||||
return context.getString(R.string.activity_type_not_measured);
|
||||
case TYPE_ACTIVITY:
|
||||
return context.getString(R.string.activity_type_activity);
|
||||
case TYPE_LIGHT_SLEEP:
|
||||
return context.getString(R.string.activity_type_light_sleep);
|
||||
case TYPE_DEEP_SLEEP:
|
||||
return context.getString(R.string.activity_type_deep_sleep);
|
||||
case TYPE_NOT_WORN:
|
||||
return context.getString(R.string.activity_type_not_worn);
|
||||
case TYPE_RUNNING:
|
||||
return context.getString(R.string.activity_type_running);
|
||||
case TYPE_WALKING:
|
||||
return context.getString(R.string.activity_type_walking);
|
||||
case TYPE_SWIMMING:
|
||||
return context.getString(R.string.activity_type_swimming);
|
||||
case TYPE_CYCLING:
|
||||
return context.getString(R.string.activity_type_biking);
|
||||
case TYPE_TREADMILL:
|
||||
return context.getString(R.string.activity_type_treadmill);
|
||||
case TYPE_UNKNOWN:
|
||||
default:
|
||||
return context.getString(R.string.activity_type_unknown);
|
||||
}
|
||||
}
|
||||
|
||||
@DrawableRes
|
||||
public static int getIconId(int kind) {
|
||||
switch (kind) {
|
||||
case TYPE_NOT_MEASURED:
|
||||
return R.drawable.ic_activity_not_measured;
|
||||
case TYPE_LIGHT_SLEEP:
|
||||
return R.drawable.ic_activity_light_sleep;
|
||||
case TYPE_DEEP_SLEEP:
|
||||
return R.drawable.ic_activity_deep_sleep;
|
||||
case TYPE_RUNNING:
|
||||
return R.drawable.ic_activity_running;
|
||||
case TYPE_WALKING:
|
||||
return R.drawable.ic_activity_walking;
|
||||
case TYPE_CYCLING:
|
||||
return R.drawable.ic_activity_biking;
|
||||
case TYPE_TREADMILL:
|
||||
return R.drawable.ic_activity_walking;
|
||||
case TYPE_SWIMMING: // fall through
|
||||
case TYPE_NOT_WORN: // fall through
|
||||
case TYPE_ACTIVITY: // fall through
|
||||
case TYPE_UNKNOWN: // fall through
|
||||
default:
|
||||
return R.drawable.ic_activity_unknown;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,95 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.model;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
// https://www8.garmin.com/xmlschemas/TrackPointExtensionv1.xsd
|
||||
/*
|
||||
<trkpt lat="54.8591470" lon="-1.5754310">
|
||||
<ele>29.2</ele>
|
||||
<time>2015-07-26T07:43:42Z</time>
|
||||
<extensions>
|
||||
<gpxtpx:TrackPointExtension>
|
||||
<gpxtpx:atemp>11</gpxtpx:atemp>
|
||||
<gpxtpx:hr>92</gpxtpx:hr>
|
||||
<gpxtpx:cad>0</gpxtpx:cad>
|
||||
</gpxtpx:TrackPointExtension>
|
||||
</extensions>
|
||||
</trkpt>
|
||||
*/
|
||||
public class ActivityPoint {
|
||||
private Date time;
|
||||
private GPSCoordinate location;
|
||||
private int heartRate;
|
||||
private long speed4;
|
||||
private long speed5;
|
||||
private long speed6;
|
||||
|
||||
// e.g. to describe a pause during the activity
|
||||
private @Nullable String description;
|
||||
|
||||
public ActivityPoint() {
|
||||
}
|
||||
|
||||
public ActivityPoint(Date time) {
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
public Date getTime() {
|
||||
return time;
|
||||
}
|
||||
|
||||
public void setTime(Date time) {
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(@Nullable String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public GPSCoordinate getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
public void setLocation(GPSCoordinate location) {
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public int getHeartRate() {
|
||||
return heartRate;
|
||||
}
|
||||
|
||||
public void setHeartRate(int heartRate) {
|
||||
this.heartRate = heartRate;
|
||||
}
|
||||
|
||||
public long getSpeed4() {
|
||||
return speed4;
|
||||
}
|
||||
|
||||
public void setSpeed4(long speed4) {
|
||||
this.speed4 = speed4;
|
||||
}
|
||||
|
||||
public long getSpeed5() {
|
||||
return speed5;
|
||||
}
|
||||
|
||||
public void setSpeed5(long speed5) {
|
||||
this.speed5 = speed5;
|
||||
}
|
||||
|
||||
public long getSpeed6() {
|
||||
return speed6;
|
||||
}
|
||||
|
||||
public void setSpeed6(long speed6) {
|
||||
this.speed6 = speed6;
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Summarized information about a temporal activity.
|
||||
*
|
||||
* // TODO: split into separate entities?
|
||||
*/
|
||||
public interface ActivitySummary extends Serializable {
|
||||
String getName();
|
||||
Date getStartTime();
|
||||
Date getEndTime();
|
||||
|
||||
int getActivityKind();
|
||||
String getGpxTrack();
|
||||
|
||||
long getDeviceId();
|
||||
|
||||
long getUserId();
|
||||
// long getSteps();
|
||||
// float getDistanceMeters();
|
||||
// float getAscentMeters();
|
||||
// float getDescentMeters();
|
||||
// float getMinAltitude();
|
||||
// float getMaxAltitude();
|
||||
// float getCalories();
|
||||
//
|
||||
// float getMaxSpeed();
|
||||
// float getMinSpeed();
|
||||
// float getAverageSpeed();
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.User;
|
||||
|
||||
public class ActivityTrack {
|
||||
private Date baseTime;
|
||||
private Device device;
|
||||
private User user;
|
||||
private String name;
|
||||
|
||||
|
||||
public void setBaseTime(Date baseTime) {
|
||||
this.baseTime = baseTime;
|
||||
}
|
||||
|
||||
public Device getDevice() {
|
||||
return device;
|
||||
}
|
||||
|
||||
public void setDevice(Device device) {
|
||||
this.device = device;
|
||||
}
|
||||
|
||||
public User getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public void setUser(User user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public void setTrackPoints(List<ActivityPoint> trackPoints) {
|
||||
this.trackPoints = trackPoints;
|
||||
}
|
||||
|
||||
private List<ActivityPoint> trackPoints = new ArrayList<>();
|
||||
|
||||
public void addTrackPoint(ActivityPoint point) {
|
||||
trackPoints.add(point);
|
||||
}
|
||||
|
||||
public List<ActivityPoint> getTrackPoints() {
|
||||
return trackPoints;
|
||||
}
|
||||
|
||||
public Date getBaseTime() {
|
||||
return baseTime;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.model;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
public final class GPSCoordinate {
|
||||
private final double latitude;
|
||||
private final double longitude;
|
||||
private final double altitude;
|
||||
|
||||
public static final int GPS_DECIMAL_DEGREES_SCALE = 6; // precise to 111.132mm at equator: https://en.wikipedia.org/wiki/Decimal_degrees
|
||||
|
||||
public GPSCoordinate(double longitude, double latitude, double altitude) {
|
||||
this.longitude = longitude;
|
||||
this.latitude = latitude;
|
||||
this.altitude = altitude;
|
||||
}
|
||||
|
||||
public double getLatitude() {
|
||||
return latitude;
|
||||
}
|
||||
|
||||
public double getLongitude() {
|
||||
return longitude;
|
||||
}
|
||||
|
||||
public double getAltitude() {
|
||||
return altitude;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
GPSCoordinate that = (GPSCoordinate) o;
|
||||
|
||||
if (Double.compare(that.getLatitude(), getLatitude()) != 0) return false;
|
||||
if (Double.compare(that.getLongitude(), getLongitude()) != 0) return false;
|
||||
return Double.compare(that.getAltitude(), getAltitude()) == 0;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result;
|
||||
long temp;
|
||||
temp = Double.doubleToLongBits(getLatitude());
|
||||
result = (int) (temp ^ (temp >>> 32));
|
||||
temp = Double.doubleToLongBits(getLongitude());
|
||||
result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||
temp = Double.doubleToLongBits(getAltitude());
|
||||
result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||
return result;
|
||||
}
|
||||
|
||||
private String formatLocation(double value) {
|
||||
return new BigDecimal(value).setScale(8, RoundingMode.HALF_UP).toPlainString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "lon: " + formatLocation(longitude) + ", lat: " + formatLocation(latitude) + ", alt: " + formatLocation(altitude) + "m";
|
||||
}
|
||||
}
|
@ -43,6 +43,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.operations.Op
|
||||
public abstract class AbstractBTLEOperation<T extends AbstractBTLEDeviceSupport> implements GattCallback, BTLEOperation {
|
||||
private final T mSupport;
|
||||
protected OperationStatus operationStatus = OperationStatus.INITIAL;
|
||||
private String name;
|
||||
|
||||
protected AbstractBTLEOperation(T support) {
|
||||
mSupport = support;
|
||||
@ -115,6 +116,22 @@ public abstract class AbstractBTLEOperation<T extends AbstractBTLEDeviceSupport>
|
||||
return mSupport.getDevice();
|
||||
}
|
||||
|
||||
protected void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
if (name != null) {
|
||||
return name;
|
||||
}
|
||||
String busyTask = getDevice().getBusyTask();
|
||||
if (busyTask != null) {
|
||||
return busyTask;
|
||||
}
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
|
||||
protected BluetoothGattCharacteristic getCharacteristic(UUID uuid) {
|
||||
return mSupport.getCharacteristic(uuid);
|
||||
}
|
||||
|
@ -30,6 +30,9 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotificat
|
||||
* Provides methods to convert standard BLE units to byte sequences and vice versa.
|
||||
*/
|
||||
public class BLETypeConversions {
|
||||
public static final int TZ_FLAG_NONE = 0;
|
||||
public static final int TZ_FLAG_INCLUDE_DST_IN_TZ = 1;
|
||||
|
||||
/**
|
||||
* Converts a timestamp to the byte sequence to be sent to the current time characteristic
|
||||
*
|
||||
@ -164,10 +167,33 @@ public class BLETypeConversions {
|
||||
return createCalendar();
|
||||
}
|
||||
|
||||
public static long toUnsigned(int unsignedInt) {
|
||||
return ((long) unsignedInt) & 0xffffffffL;
|
||||
}
|
||||
public static int toUnsigned(short value) {
|
||||
return value & 0xffff;
|
||||
}
|
||||
|
||||
public static int toUnsigned(byte value) {
|
||||
return value & 0xff;
|
||||
}
|
||||
|
||||
public static int toUint16(byte value) {
|
||||
return toUnsigned(value);
|
||||
}
|
||||
|
||||
public static int toUint16(byte... bytes) {
|
||||
return (bytes[0] & 0xff) | ((bytes[1] & 0xff) << 8);
|
||||
}
|
||||
|
||||
public static int toInt16(byte... bytes) {
|
||||
return (short) (bytes[0] & 0xff | ((bytes[1] & 0xff) << 8));
|
||||
}
|
||||
|
||||
public static int toUint32(byte... bytes) {
|
||||
return (bytes[0] & 0xff) | ((bytes[1] & 0xff) << 8) | ((bytes[2] & 0xff) << 16) | ((bytes[3] & 0xff) << 24);
|
||||
}
|
||||
|
||||
public static byte[] fromUint16(int value) {
|
||||
return new byte[] {
|
||||
(byte) (value & 0xff),
|
||||
@ -230,7 +256,20 @@ public class BLETypeConversions {
|
||||
* @return sint8 value from -48..+56
|
||||
*/
|
||||
public static byte mapTimeZone(TimeZone timeZone) {
|
||||
int utcOffsetInHours = (timeZone.getRawOffset() / (1000 * 60 * 60));
|
||||
return mapTimeZone(timeZone, TZ_FLAG_NONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.time_zone.xml
|
||||
* @param timeZone
|
||||
* @return sint8 value from -48..+56
|
||||
*/
|
||||
public static byte mapTimeZone(TimeZone timeZone, int timezoneFlags) {
|
||||
int offsetMillis = timeZone.getRawOffset();
|
||||
if (false && timezoneFlags == TZ_FLAG_INCLUDE_DST_IN_TZ) {
|
||||
offsetMillis += timeZone.getDSTSavings();
|
||||
}
|
||||
int utcOffsetInHours = (offsetMillis / (1000 * 60 * 60));
|
||||
return (byte) (utcOffsetInHours * 4);
|
||||
}
|
||||
|
||||
|
@ -20,4 +20,9 @@ import java.io.IOException;
|
||||
|
||||
public interface BTLEOperation {
|
||||
void perform() throws IOException;
|
||||
|
||||
/**
|
||||
* Returns a human readable name of this operation, to be used e.g. in log output.
|
||||
*/
|
||||
String getName();
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.Logging;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice.State;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.DeviceSupport;
|
||||
@ -467,10 +468,7 @@ public final class BtLEQueue {
|
||||
public void onCharacteristicChanged(BluetoothGatt gatt,
|
||||
BluetoothGattCharacteristic characteristic) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
String content = "";
|
||||
for (byte b : characteristic.getValue()) {
|
||||
content += String.format(" 0x%1x", b);
|
||||
}
|
||||
String content = Logging.formatBytes(characteristic.getValue());
|
||||
LOG.debug("characteristic changed: " + characteristic.getUuid() + " value: " + content);
|
||||
}
|
||||
if (!checkCorrectGattInstance(gatt, "characteristic changed")) {
|
||||
|
@ -0,0 +1,216 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.amazfitbip;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Date;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBException;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.BaseActivitySummary;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityPoint;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityTrack;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.GPSCoordinate;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions;
|
||||
|
||||
public class ActivityDetailsParser {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ActivityDetailsParser.class);
|
||||
|
||||
private static final byte TYPE_GPS = 0;
|
||||
private static final byte TYPE_HR = 1;
|
||||
private static final byte TYPE_UNKNOWN2 = 2;
|
||||
private static final byte TYPE_PAUSE = 3;
|
||||
private static final byte TYPE_SPEED4 = 4;
|
||||
private static final byte TYPE_SPEED5 = 5;
|
||||
private static final byte TYPE_GPS_SPEED6 = 6;
|
||||
|
||||
public static final BigDecimal HUAMI_TO_DECIMAL_DEGREES_DIVISOR = new BigDecimal(3000000.0);
|
||||
private final BaseActivitySummary summary;
|
||||
private final ActivityTrack activityTrack;
|
||||
// private final int version;
|
||||
private final Date baseDate;
|
||||
private long baseLongitude;
|
||||
private long baseLatitude;
|
||||
private int baseAltitude;
|
||||
private ActivityPoint lastActivityPoint;
|
||||
|
||||
public boolean getSkipCounterByte() {
|
||||
return skipCounterByte;
|
||||
}
|
||||
|
||||
public void setSkipCounterByte(boolean skipCounterByte) {
|
||||
this.skipCounterByte = skipCounterByte;
|
||||
}
|
||||
|
||||
private boolean skipCounterByte;
|
||||
|
||||
public ActivityDetailsParser(BaseActivitySummary summary) {
|
||||
this.summary = summary;
|
||||
// this.version = version;
|
||||
// this.baseDate = baseDate;
|
||||
//
|
||||
this.baseLongitude = summary.getBaseLongitude();
|
||||
this.baseLatitude = summary.getBaseLatitude();
|
||||
this.baseAltitude = summary.getBaseAltitude();
|
||||
this.baseDate = summary.getStartTime();
|
||||
|
||||
this.activityTrack = new ActivityTrack();
|
||||
activityTrack.setUser(summary.getUser());
|
||||
activityTrack.setDevice(summary.getDevice());
|
||||
activityTrack.setName(summary.getName() + "-" + summary.getId());
|
||||
}
|
||||
|
||||
public ActivityTrack parse(byte[] bytes) throws GBException {
|
||||
int i = 0;
|
||||
try {
|
||||
long totalTimeOffset = 0;
|
||||
int lastTimeOffset = 0;
|
||||
while (i < bytes.length) {
|
||||
if (skipCounterByte && (i % 17) == 0) {
|
||||
i++;
|
||||
}
|
||||
|
||||
byte type = bytes[i++];
|
||||
int timeOffset = BLETypeConversions.toUnsigned(bytes[i++]);
|
||||
// handle timeOffset overflows (1 byte, always increasing, relative to base)
|
||||
if (lastTimeOffset <= timeOffset) {
|
||||
timeOffset = timeOffset - lastTimeOffset;
|
||||
lastTimeOffset += timeOffset;
|
||||
} else {
|
||||
lastTimeOffset = timeOffset;
|
||||
}
|
||||
totalTimeOffset += timeOffset;
|
||||
|
||||
switch (type) {
|
||||
case TYPE_GPS:
|
||||
i += consumeGPSAndUpdateBaseLocation(bytes, i, totalTimeOffset);
|
||||
break;
|
||||
case TYPE_HR:
|
||||
i += consumeHeartRate(bytes, i, totalTimeOffset);
|
||||
break;
|
||||
case TYPE_UNKNOWN2:
|
||||
i += consumeUnknown2(bytes, i);
|
||||
break;
|
||||
case TYPE_PAUSE:
|
||||
i += consumePause(bytes, i);
|
||||
break;
|
||||
case TYPE_SPEED4:
|
||||
i += consumeSpeed4(bytes, i);
|
||||
break;
|
||||
case TYPE_SPEED5:
|
||||
i += consumeSpeed5(bytes, i);
|
||||
break;
|
||||
case TYPE_GPS_SPEED6:
|
||||
i += consumeSpeed6(bytes, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (IndexOutOfBoundsException ex) {
|
||||
throw new GBException("Error parsing activity details: " + ex.getMessage(), ex);
|
||||
}
|
||||
|
||||
return activityTrack;
|
||||
}
|
||||
|
||||
private int consumeGPSAndUpdateBaseLocation(byte[] bytes, int offset, long timeOffset) {
|
||||
int i = 0;
|
||||
int longitudeDelta = BLETypeConversions.toInt16(bytes[offset + i++], bytes[offset + i++]);
|
||||
int latitudeDelta = BLETypeConversions.toInt16(bytes[offset + i++], bytes[offset + i++]);
|
||||
int altitudeDelta = BLETypeConversions.toInt16(bytes[offset + i++], bytes[offset + i++]);
|
||||
|
||||
baseLongitude += longitudeDelta;
|
||||
baseLatitude += latitudeDelta;
|
||||
baseAltitude += altitudeDelta;
|
||||
|
||||
GPSCoordinate coordinate = new GPSCoordinate(
|
||||
convertHuamiValueToDecimalDegrees(baseLongitude),
|
||||
convertHuamiValueToDecimalDegrees(baseLatitude),
|
||||
baseAltitude);
|
||||
|
||||
ActivityPoint ap = getActivityPointFor(timeOffset);
|
||||
ap.setLocation(coordinate);
|
||||
add(ap);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
private double convertHuamiValueToDecimalDegrees(long huamiValue) {
|
||||
BigDecimal result = new BigDecimal(huamiValue).divide(HUAMI_TO_DECIMAL_DEGREES_DIVISOR, GPSCoordinate.GPS_DECIMAL_DEGREES_SCALE, RoundingMode.HALF_UP);
|
||||
return result.doubleValue();
|
||||
}
|
||||
|
||||
private int consumeHeartRate(byte[] bytes, int offset, long timeOffsetSeconds) {
|
||||
int v1 = BLETypeConversions.toUint16(bytes[offset]);
|
||||
int v2 = BLETypeConversions.toUint16(bytes[offset + 1]);
|
||||
int v3 = BLETypeConversions.toUint16(bytes[offset + 2]);
|
||||
int v4 = BLETypeConversions.toUint16(bytes[offset + 3]);
|
||||
int v5 = BLETypeConversions.toUint16(bytes[offset + 4]);
|
||||
int v6 = BLETypeConversions.toUint16(bytes[offset + 5]);
|
||||
|
||||
if (v2 == 0 && v3 == 0 && v4 == 0 && v5 == 0 && v6 == 0) {
|
||||
// new version
|
||||
// LOG.info("detected heart rate in 'new' version, where version is: " + summary.getVersion());
|
||||
LOG.info("detected heart rate in 'new' version format");
|
||||
ActivityPoint ap = getActivityPointFor(timeOffsetSeconds);
|
||||
ap.setHeartRate(v1);
|
||||
add(ap);
|
||||
} else {
|
||||
ActivityPoint ap = getActivityPointFor(v1);
|
||||
ap.setHeartRate(v2);
|
||||
add(ap);
|
||||
|
||||
ap = getActivityPointFor(v3);
|
||||
ap.setHeartRate(v4);
|
||||
add(ap);
|
||||
|
||||
ap = getActivityPointFor(v5);
|
||||
ap.setHeartRate(v6);
|
||||
add(ap);
|
||||
}
|
||||
return 6;
|
||||
}
|
||||
|
||||
private ActivityPoint getActivityPointFor(long timeOffsetSeconds) {
|
||||
Date time = makeAbsolute(timeOffsetSeconds);
|
||||
// if (lastActivityPoint != null) {
|
||||
// if (lastActivityPoint.getTime().equals(time)) {
|
||||
// return lastActivityPoint;
|
||||
// }
|
||||
// }
|
||||
return new ActivityPoint(time);
|
||||
}
|
||||
|
||||
private Date makeAbsolute(long timeOffsetSeconds) {
|
||||
return new Date(baseDate.getTime() + timeOffsetSeconds * 1000);
|
||||
}
|
||||
|
||||
private void add(ActivityPoint ap) {
|
||||
if (ap != lastActivityPoint) {
|
||||
lastActivityPoint = ap;
|
||||
activityTrack.addTrackPoint(ap);
|
||||
} else {
|
||||
LOG.info("skipping point!");
|
||||
}
|
||||
}
|
||||
|
||||
private int consumeUnknown2(byte[] bytes, int offset) {
|
||||
return 6; // just guessing...
|
||||
}
|
||||
|
||||
private int consumePause(byte[] bytes, int i) {
|
||||
return 6; // just guessing...
|
||||
}
|
||||
|
||||
private int consumeSpeed4(byte[] bytes, int offset) {
|
||||
return 6;
|
||||
}
|
||||
|
||||
private int consumeSpeed5(byte[] bytes, int offset) {
|
||||
return 6;
|
||||
}
|
||||
|
||||
private int consumeSpeed6(byte[] bytes, int offset) {
|
||||
return 6;
|
||||
}
|
||||
}
|
@ -49,10 +49,10 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.ConditionalWrit
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification.AlertCategory;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification.AlertNotificationProfile;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification.NewAlert;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.amazfitbip.operations.AmazfitBipFetchLogsOperation;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiIcon;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.NotificationStrategy;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.MiBand2Support;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.operations.FetchSportsSummaryOperation;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.Version;
|
||||
|
||||
@ -285,7 +285,8 @@ public class AmazfitBipSupport extends MiBand2Support {
|
||||
@Override
|
||||
public void onTestNewFunction() {
|
||||
try {
|
||||
new AmazfitBipFetchLogsOperation(this).perform();
|
||||
// new AmazfitBipFetchLogsOperation(this).perform();
|
||||
new FetchSportsSummaryOperation(this).perform();
|
||||
} catch (IOException ex) {
|
||||
LOG.error("Unable to fetch logs", ex);
|
||||
}
|
||||
|
@ -0,0 +1,53 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.amazfitbip;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
|
||||
|
||||
public enum BipActivityType {
|
||||
Outdoor(1),
|
||||
Treadmill(2),
|
||||
Walking(3),
|
||||
Cycling(4);
|
||||
|
||||
private final int code;
|
||||
|
||||
BipActivityType(final int code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public int toActivityKind() {
|
||||
switch (this) {
|
||||
case Outdoor:
|
||||
return ActivityKind.TYPE_RUNNING;
|
||||
case Treadmill:
|
||||
return ActivityKind.TYPE_TREADMILL;
|
||||
case Cycling:
|
||||
return ActivityKind.TYPE_CYCLING;
|
||||
case Walking:
|
||||
return ActivityKind.TYPE_WALKING;
|
||||
}
|
||||
throw new RuntimeException("Not mapped activity kind for: " + this);
|
||||
}
|
||||
|
||||
public static BipActivityType fromCode(int bipCode) {
|
||||
for (BipActivityType type : values()) {
|
||||
if (type.code == bipCode) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("No matching BipActivityType for code: " + bipCode);
|
||||
}
|
||||
|
||||
public static BipActivityType fromActivityKind(int activityKind) {
|
||||
switch (activityKind) {
|
||||
case ActivityKind.TYPE_RUNNING:
|
||||
return Outdoor;
|
||||
case ActivityKind.TYPE_TREADMILL:
|
||||
return Treadmill;
|
||||
case ActivityKind.TYPE_CYCLING:
|
||||
return Cycling;
|
||||
case ActivityKind.TYPE_WALKING:
|
||||
return Walking;
|
||||
}
|
||||
throw new RuntimeException("No matching activity activityKind: " + activityKind);
|
||||
}
|
||||
}
|
@ -26,7 +26,6 @@ import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
@ -50,6 +49,7 @@ public class AmazfitBipFetchLogsOperation extends AbstractFetchOperation {
|
||||
|
||||
public AmazfitBipFetchLogsOperation(AmazfitBipSupport support) {
|
||||
super(support);
|
||||
setName("fetch logs");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -89,8 +89,8 @@ public class AmazfitBipFetchLogsOperation extends AbstractFetchOperation {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleActivityFetchFinish() {
|
||||
LOG.info("Fetching log data has finished");
|
||||
protected void handleActivityFetchFinish(boolean success) {
|
||||
LOG.info(getName() +" data has finished");
|
||||
try {
|
||||
logOutputStream.close();
|
||||
logOutputStream = null;
|
||||
@ -98,7 +98,7 @@ public class AmazfitBipFetchLogsOperation extends AbstractFetchOperation {
|
||||
LOG.warn("could not close output stream", e);
|
||||
return;
|
||||
}
|
||||
super.handleActivityFetchFinish();
|
||||
super.handleActivityFetchFinish(success);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -113,18 +113,18 @@ public class AmazfitBipFetchLogsOperation extends AbstractFetchOperation {
|
||||
lastPacketCounter++;
|
||||
bufferActivityData(value);
|
||||
} else {
|
||||
GB.toast("Error fetching activity data, invalid package counter: " + value[0], Toast.LENGTH_LONG, GB.ERROR);
|
||||
handleActivityFetchFinish();
|
||||
GB.toast("Error " + getName() + " invalid package counter: " + value[0], Toast.LENGTH_LONG, GB.ERROR);
|
||||
handleActivityFetchFinish(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void bufferActivityData(@NonNull byte[] value) {
|
||||
try {
|
||||
logOutputStream.write(Arrays.copyOfRange(value, 1, value.length));
|
||||
logOutputStream.write(value, 1, value.length);
|
||||
} catch (IOException e) {
|
||||
LOG.warn("could not write to output stream", e);
|
||||
handleActivityFetchFinish();
|
||||
handleActivityFetchFinish(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -40,6 +40,7 @@ import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.UUID;
|
||||
@ -69,6 +70,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandService;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.miband.VibrationProfile;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.miband2.MiBand2Const;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.MiBandActivitySample;
|
||||
@ -105,6 +107,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.NotificationS
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.RealtimeSamplesSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.actions.StopNotificationAction;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.operations.FetchActivityOperation;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.operations.FetchSportsSummaryOperation;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.operations.InitOperation;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.operations.UpdateFirmwareOperation;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
@ -214,6 +217,14 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
|
||||
return builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the given date/time (calendar) as a byte sequence, suitable for sending to the
|
||||
* Mi Band 2 (or derivative). The band appears to not handle DST offsets, so we simply add this
|
||||
* to the timezone.
|
||||
* @param calendar
|
||||
* @param precision
|
||||
* @return
|
||||
*/
|
||||
public byte[] getTimeBytes(Calendar calendar, TimeUnit precision) {
|
||||
byte[] bytes;
|
||||
if (precision == TimeUnit.MINUTES) {
|
||||
@ -223,7 +234,8 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported precision, only MINUTES and SECONDS are supported till now");
|
||||
}
|
||||
byte[] tail = new byte[] { 0, BLETypeConversions.mapTimeZone(calendar.getTimeZone()) }; // 0 = adjust reason bitflags? or DST offset?? , timezone
|
||||
byte[] tail = new byte[] { 0, BLETypeConversions.mapTimeZone(calendar.getTimeZone(), BLETypeConversions.TZ_FLAG_INCLUDE_DST_IN_TZ) };
|
||||
// 0 = adjust reason bitflags? or DST offset?? , timezone
|
||||
// byte[] tail = new byte[] { 0x2 }; // reason
|
||||
byte[] all = BLETypeConversions.join(bytes, tail);
|
||||
return all;
|
||||
@ -1189,7 +1201,7 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
|
||||
sample.setHeartRate(getHeartrateBpm());
|
||||
sample.setSteps(getSteps());
|
||||
sample.setRawIntensity(ActivitySample.NOT_MEASURED);
|
||||
sample.setRawKind(MiBand2SampleProvider.TYPE_ACTIVITY); // to make it visible in the charts TODO: add a MANUAL kind for that?
|
||||
sample.setRawKind(MiBand2Const.TYPE_ACTIVITY); // to make it visible in the charts TODO: add a MANUAL kind for that?
|
||||
|
||||
provider.addGBActivitySample(sample);
|
||||
|
||||
@ -1372,10 +1384,9 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
|
||||
@Override
|
||||
public void onTestNewFunction() {
|
||||
try {
|
||||
TransactionBuilder builder = performInitialized("test realtime steps");
|
||||
builder.read(getCharacteristic(MiBand2Service.UUID_CHARACTERISTIC_7_REALTIME_STEPS));
|
||||
builder.queue(getQueue());
|
||||
} catch (IOException e) {
|
||||
new FetchSportsSummaryOperation(this).perform();
|
||||
} catch (IOException ex) {
|
||||
LOG.error("Unable to fetch MI activity data", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -57,6 +57,7 @@ public abstract class AbstractFetchOperation extends AbstractMiBand2Operation {
|
||||
protected BluetoothGattCharacteristic characteristicActivityData;
|
||||
protected BluetoothGattCharacteristic characteristicFetch;
|
||||
protected Calendar startTimestamp;
|
||||
protected int expectedDataLength;
|
||||
|
||||
public AbstractFetchOperation(MiBand2Support support) {
|
||||
super(support);
|
||||
@ -66,7 +67,8 @@ public abstract class AbstractFetchOperation extends AbstractMiBand2Operation {
|
||||
protected void enableNeededNotifications(TransactionBuilder builder, boolean enable) {
|
||||
if (!enable) {
|
||||
// dynamically enabled, but always disabled on finish
|
||||
builder.notify(getCharacteristic(MiBand2Service.UUID_CHARACTERISTIC_5_ACTIVITY_DATA), enable);
|
||||
builder.notify(characteristicFetch, enable);
|
||||
builder.notify(characteristicActivityData, enable);
|
||||
}
|
||||
}
|
||||
|
||||
@ -78,7 +80,7 @@ public abstract class AbstractFetchOperation extends AbstractMiBand2Operation {
|
||||
protected void startFetching() throws IOException {
|
||||
lastPacketCounter = -1;
|
||||
|
||||
TransactionBuilder builder = performInitialized("fetching activity data");
|
||||
TransactionBuilder builder = performInitialized(getName());
|
||||
getSupport().setLowLatency(builder);
|
||||
if (fetchCount == 0) {
|
||||
builder.add(new SetDeviceBusyAction(getDevice(), getContext().getString(R.string.busy_task_fetch_activity_data), getContext()));
|
||||
@ -115,7 +117,7 @@ public abstract class AbstractFetchOperation extends AbstractMiBand2Operation {
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
protected void handleActivityFetchFinish() {
|
||||
protected void handleActivityFetchFinish(boolean success) {
|
||||
operationFinished();
|
||||
unsetBusy();
|
||||
}
|
||||
@ -139,7 +141,8 @@ public abstract class AbstractFetchOperation extends AbstractMiBand2Operation {
|
||||
// first two bytes are whether our request was accepted
|
||||
if (ArrayUtils.equals(value, MiBand2Service.RESPONSE_ACTIVITY_DATA_START_DATE_SUCCESS, 0)) {
|
||||
// the third byte (0x01 on success) = ?
|
||||
// the 4th - 7th bytes probably somehow represent the number of bytes/packets to expect
|
||||
// the 4th - 7th bytes epresent the number of bytes/packets to expect, excluding the counter bytes
|
||||
expectedDataLength = BLETypeConversions.toUint32(Arrays.copyOfRange(value, 3, 7));
|
||||
|
||||
// last 8 bytes are the start date
|
||||
Calendar startTimestamp = getSupport().fromTimeBytes(Arrays.copyOfRange(value, 7, value.length));
|
||||
@ -149,18 +152,18 @@ public abstract class AbstractFetchOperation extends AbstractMiBand2Operation {
|
||||
DateFormat.getDateTimeInstance().format(startTimestamp.getTime())), Toast.LENGTH_LONG, GB.INFO);
|
||||
} else {
|
||||
LOG.warn("Unexpected activity metadata: " + Logging.formatBytes(value));
|
||||
handleActivityFetchFinish();
|
||||
handleActivityFetchFinish(false);
|
||||
}
|
||||
} else if (value.length == 3) {
|
||||
if (Arrays.equals(MiBand2Service.RESPONSE_FINISH_SUCCESS, value)) {
|
||||
handleActivityFetchFinish();
|
||||
handleActivityFetchFinish(true);
|
||||
} else {
|
||||
LOG.warn("Unexpected activity metadata: " + Logging.formatBytes(value));
|
||||
handleActivityFetchFinish();
|
||||
handleActivityFetchFinish(false);
|
||||
}
|
||||
} else {
|
||||
LOG.warn("Unexpected activity metadata: " + Logging.formatBytes(value));
|
||||
handleActivityFetchFinish();
|
||||
handleActivityFetchFinish(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -183,7 +186,7 @@ public abstract class AbstractFetchOperation extends AbstractMiBand2Operation {
|
||||
return calendar;
|
||||
}
|
||||
GregorianCalendar calendar = BLETypeConversions.createCalendar();
|
||||
calendar.add(Calendar.DAY_OF_MONTH, -10);
|
||||
calendar.add(Calendar.DAY_OF_MONTH, - 100);
|
||||
return calendar;
|
||||
}
|
||||
}
|
||||
|
@ -57,6 +57,7 @@ public class FetchActivityOperation extends AbstractFetchOperation {
|
||||
|
||||
public FetchActivityOperation(MiBand2Support support) {
|
||||
super(support);
|
||||
setName("fetching activity data");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -74,24 +75,24 @@ public class FetchActivityOperation extends AbstractFetchOperation {
|
||||
builder.write(characteristicFetch, new byte[] { MiBand2Service.COMMAND_FETCH_DATA});
|
||||
}
|
||||
|
||||
protected void handleActivityFetchFinish() {
|
||||
LOG.info("Fetching activity data has finished round " + fetchCount);
|
||||
protected void handleActivityFetchFinish(boolean success) {
|
||||
LOG.info(getName() + " has finished round " + fetchCount);
|
||||
GregorianCalendar lastSyncTimestamp = saveSamples();
|
||||
if (lastSyncTimestamp != null && needsAnotherFetch(lastSyncTimestamp)) {
|
||||
try {
|
||||
startFetching();
|
||||
return;
|
||||
} catch (IOException ex) {
|
||||
LOG.error("Error starting another round of fetching activity data", ex);
|
||||
LOG.error("Error starting another round of " + getName(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
super.handleActivityFetchFinish();
|
||||
super.handleActivityFetchFinish(success);
|
||||
}
|
||||
|
||||
private boolean needsAnotherFetch(GregorianCalendar lastSyncTimestamp) {
|
||||
if (fetchCount > 5) {
|
||||
LOG.warn("Already jave 5 fetch rounds, not doing another one.");
|
||||
LOG.warn("Already have 5 fetch rounds, not doing another one.");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -166,12 +167,13 @@ public class FetchActivityOperation extends AbstractFetchOperation {
|
||||
lastPacketCounter++;
|
||||
bufferActivityData(value);
|
||||
} else {
|
||||
GB.toast("Error fetching activity data, invalid package counter: " + value[0], Toast.LENGTH_LONG, GB.ERROR);
|
||||
handleActivityFetchFinish();
|
||||
GB.toast("Error " + getName() + ", invalid package counter: " + value[0], Toast.LENGTH_LONG, GB.ERROR);
|
||||
handleActivityFetchFinish(false);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
GB.toast("Error fetching activity data, unexpected package length: " + value.length, Toast.LENGTH_LONG, GB.ERROR);
|
||||
GB.toast("Error " + getName() + ", unexpected package length: " + value.length, Toast.LENGTH_LONG, GB.ERROR);
|
||||
handleActivityFetchFinish(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,181 @@
|
||||
/* Copyright (C) 2017 Andreas Shimokawa, Carsten Pfeiffer
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.operations;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.Logging;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huami.amazfitbip.AmazfitBipService;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBand2Service;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.BaseActivitySummary;
|
||||
import nodomain.freeyourgadget.gadgetbridge.export.ActivityTrackExporter;
|
||||
import nodomain.freeyourgadget.gadgetbridge.export.GPXExporter;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityTrack;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.WaitAction;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.amazfitbip.ActivityDetailsParser;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.MiBand2Support;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
|
||||
/**
|
||||
* An operation that fetches activity data. For every fetch, a new operation must
|
||||
* be created, i.e. an operation may not be reused for multiple fetches.
|
||||
*/
|
||||
public class FetchSportsDetailsOperation extends AbstractFetchOperation {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(FetchSportsDetailsOperation.class);
|
||||
private final BaseActivitySummary summary;
|
||||
private final String lastSyncTimeKey;
|
||||
|
||||
private ByteArrayOutputStream buffer;
|
||||
|
||||
public FetchSportsDetailsOperation(@NonNull BaseActivitySummary summary, @NonNull MiBand2Support support, @NonNull String lastSyncTimeKey) {
|
||||
super(support);
|
||||
setName("fetching sport details");
|
||||
this.summary = summary;
|
||||
this.lastSyncTimeKey = lastSyncTimeKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startFetching(TransactionBuilder builder) {
|
||||
LOG.info("start " + getName());
|
||||
buffer = new ByteArrayOutputStream(1024);
|
||||
GregorianCalendar sinceWhen = getLastSuccessfulSyncTime();
|
||||
builder.write(characteristicFetch, BLETypeConversions.join(new byte[] {
|
||||
MiBand2Service.COMMAND_ACTIVITY_DATA_START_DATE,
|
||||
AmazfitBipService.COMMAND_ACTIVITY_DATA_TYPE_SPORTS_DETAILS},
|
||||
getSupport().getTimeBytes(sinceWhen, TimeUnit.MINUTES)));
|
||||
builder.add(new WaitAction(1000)); // TODO: actually wait for the success-reply
|
||||
builder.notify(characteristicActivityData, true);
|
||||
builder.write(characteristicFetch, new byte[] { MiBand2Service.COMMAND_FETCH_DATA });
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleActivityFetchFinish(boolean success) {
|
||||
LOG.info(getName() + " has finished round " + fetchCount);
|
||||
// GregorianCalendar lastSyncTimestamp = saveSamples();
|
||||
// if (lastSyncTimestamp != null && needsAnotherFetch(lastSyncTimestamp)) {
|
||||
// try {
|
||||
// startFetching();
|
||||
// return;
|
||||
// } catch (IOException ex) {
|
||||
// LOG.error("Error starting another round of fetching activity data", ex);
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
if (success) {
|
||||
ActivityDetailsParser parser = new ActivityDetailsParser(summary);
|
||||
parser.setSkipCounterByte(false); // is already stripped
|
||||
try {
|
||||
ActivityTrack track = parser.parse(buffer.toByteArray());
|
||||
ActivityTrackExporter exporter = createExporter();
|
||||
String fileName = FileUtils.makeValidFileName("gadgetbridge-track-" + DateTimeUtils.formatIso8601(summary.getStartTime()));
|
||||
File targetFile = new File(FileUtils.getExternalFilesDir(), fileName);
|
||||
exporter.performExport(track, targetFile);
|
||||
|
||||
try (DBHandler dbHandler = GBApplication.acquireDB()) {
|
||||
summary.setGpxTrack(targetFile.getAbsolutePath());
|
||||
dbHandler.getDaoSession().getBaseActivitySummaryDao().update(summary);
|
||||
}
|
||||
GregorianCalendar endTime = BLETypeConversions.createCalendar();
|
||||
endTime.setTime(summary.getEndTime());
|
||||
saveLastSyncTimestamp(endTime);
|
||||
} catch (Exception ex) {
|
||||
GB.toast(getContext(), "Error getting activity details: " + ex.getMessage(), Toast.LENGTH_LONG, GB.ERROR, ex);
|
||||
}
|
||||
}
|
||||
|
||||
super.handleActivityFetchFinish(success);
|
||||
}
|
||||
|
||||
protected ActivityTrackExporter createExporter() {
|
||||
GPXExporter exporter = new GPXExporter();
|
||||
exporter.setCreator(GBApplication.app().getNameAndVersion());
|
||||
return exporter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to handle the incoming activity data.
|
||||
* There are two kind of messages we currently know:
|
||||
* - the first one is 11 bytes long and contains metadata (how many bytes to expect, when the data starts, etc.)
|
||||
* - the second one is 20 bytes long and contains the actual activity data
|
||||
* <p/>
|
||||
* The first message type is parsed by this method, for every other length of the value param, bufferActivityData is called.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
@Override
|
||||
protected void handleActivityNotif(byte[] value) {
|
||||
LOG.warn("sports details: " + Logging.formatBytes(value));
|
||||
|
||||
if (!isOperationRunning()) {
|
||||
LOG.error("ignoring sports details notification because operation is not running. Data length: " + value.length);
|
||||
getSupport().logMessageContent(value);
|
||||
return;
|
||||
}
|
||||
|
||||
if (value.length < 2) {
|
||||
LOG.error("unexpected sports details data length: " + value.length);
|
||||
getSupport().logMessageContent(value);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((byte) (lastPacketCounter + 1) == value[0] ) {
|
||||
lastPacketCounter++;
|
||||
bufferActivityData(value);
|
||||
} else {
|
||||
GB.toast("Error " + getName() + ", invalid package counter: " + value[0] + ", last was: " + lastPacketCounter, Toast.LENGTH_LONG, GB.ERROR);
|
||||
handleActivityFetchFinish(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Buffers the given activity summary data. If the total size is reached,
|
||||
* it is converted to an object and saved in the database.
|
||||
* @param value
|
||||
*/
|
||||
@Override
|
||||
protected void bufferActivityData(byte[] value) {
|
||||
buffer.write(value, 1, value.length - 1); // skip the counter
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getLastSyncTimeKey() {
|
||||
return lastSyncTimeKey;
|
||||
}
|
||||
|
||||
protected GregorianCalendar getLastSuccessfulSyncTime() {
|
||||
GregorianCalendar calendar = BLETypeConversions.createCalendar();
|
||||
calendar.setTime(summary.getStartTime());
|
||||
return calendar;
|
||||
}
|
||||
}
|
@ -23,12 +23,30 @@ import android.widget.Toast;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.Logging;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huami.amazfitbip.AmazfitBipService;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBand2Service;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.BaseActivitySummary;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.User;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.WaitAction;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.amazfitbip.BipActivityType;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband2.MiBand2Support;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
|
||||
@ -39,29 +57,30 @@ import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
public class FetchSportsSummaryOperation extends AbstractFetchOperation {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(FetchSportsSummaryOperation.class);
|
||||
|
||||
// private List<MiBandActivitySample> samples = new ArrayList<>(60*24); // 1day per default
|
||||
|
||||
private byte lastPacketCounter;
|
||||
private ByteArrayOutputStream buffer = new ByteArrayOutputStream(140);
|
||||
|
||||
public FetchSportsSummaryOperation(MiBand2Support support) {
|
||||
super(support);
|
||||
setName("fetching sport summaries");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startFetching(TransactionBuilder builder) {
|
||||
LOG.info("start" + getName());
|
||||
GregorianCalendar sinceWhen = getLastSuccessfulSyncTime();
|
||||
// builder.write(characteristicFetch, BLETypeConversions.join(new byte[] {
|
||||
// MiBand2Service.COMMAND_ACTIVITY_DATA_START_DATE,
|
||||
// AmazfitBipService.COMMAND_ACTIVITY_DATA_TYPE_SPORTS_SUMMARIES},
|
||||
// getSupport().getTimeBytes(sinceWhen, TimeUnit.MINUTES)));
|
||||
// builder.add(new WaitAction(1000)); // TODO: actually wait for the success-reply
|
||||
// builder.notify(characteristicActivityData, true);
|
||||
// builder.write(characteristicFetch, new byte[] { MiBand2Service.COMMAND_FETCH_DATA });
|
||||
builder.write(characteristicFetch, BLETypeConversions.join(new byte[] {
|
||||
MiBand2Service.COMMAND_ACTIVITY_DATA_START_DATE,
|
||||
AmazfitBipService.COMMAND_ACTIVITY_DATA_TYPE_SPORTS_SUMMARIES},
|
||||
getSupport().getTimeBytes(sinceWhen, TimeUnit.MINUTES)));
|
||||
builder.add(new WaitAction(1000)); // TODO: actually wait for the success-reply
|
||||
builder.notify(characteristicActivityData, true);
|
||||
builder.write(characteristicFetch, new byte[] { MiBand2Service.COMMAND_FETCH_DATA });
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleActivityFetchFinish() {
|
||||
LOG.info("Fetching activity data has finished round " + fetchCount);
|
||||
protected void handleActivityFetchFinish(boolean success) {
|
||||
LOG.info(getName() + " has finished round " + fetchCount);
|
||||
|
||||
// GregorianCalendar lastSyncTimestamp = saveSamples();
|
||||
// if (lastSyncTimestamp != null && needsAnotherFetch(lastSyncTimestamp)) {
|
||||
// try {
|
||||
@ -72,7 +91,31 @@ public class FetchSportsSummaryOperation extends AbstractFetchOperation {
|
||||
// }
|
||||
// }
|
||||
|
||||
super.handleActivityFetchFinish();
|
||||
BaseActivitySummary summary = null;
|
||||
if (success) {
|
||||
summary = parseSummary(buffer);
|
||||
try (DBHandler dbHandler = GBApplication.acquireDB()) {
|
||||
DaoSession session = dbHandler.getDaoSession();
|
||||
Device device = DBHelper.getDevice(getDevice(), session);
|
||||
User user = DBHelper.getUser(session);
|
||||
summary.setDevice(device);
|
||||
summary.setUser(user);
|
||||
session.getBaseActivitySummaryDao().insertOrReplace(summary);
|
||||
} catch (Exception ex) {
|
||||
GB.toast(getContext(), "Error saving activity summary", Toast.LENGTH_LONG, GB.ERROR, ex);
|
||||
}
|
||||
}
|
||||
|
||||
super.handleActivityFetchFinish(success);
|
||||
|
||||
if (summary != null) {
|
||||
FetchSportsDetailsOperation nextOperation = new FetchSportsDetailsOperation(summary, getSupport(), getLastSyncTimeKey());
|
||||
try {
|
||||
nextOperation.perform();
|
||||
} catch (IOException ex) {
|
||||
GB.toast(getContext(), "Unable to fetch activity details: " + ex.getMessage(), Toast.LENGTH_LONG, GB.ERROR, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -93,7 +136,7 @@ public class FetchSportsSummaryOperation extends AbstractFetchOperation {
|
||||
*/
|
||||
@Override
|
||||
protected void handleActivityNotif(byte[] value) {
|
||||
LOG.warn("sports data: " + Logging.formatBytes(value));
|
||||
LOG.warn("sports summary data: " + Logging.formatBytes(value));
|
||||
|
||||
if (!isOperationRunning()) {
|
||||
LOG.error("ignoring activity data notification because operation is not running. Data length: " + value.length);
|
||||
@ -101,48 +144,99 @@ public class FetchSportsSummaryOperation extends AbstractFetchOperation {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((value.length % 4) == 1) {
|
||||
if ((byte) (lastPacketCounter + 1) == value[0] ) {
|
||||
lastPacketCounter++;
|
||||
bufferActivityData(value);
|
||||
} else {
|
||||
GB.toast("Error fetching activity data, invalid package counter: " + value[0], Toast.LENGTH_LONG, GB.ERROR);
|
||||
handleActivityFetchFinish();
|
||||
return;
|
||||
}
|
||||
if (value.length < 2) {
|
||||
LOG.error("unexpected sports summary data length: " + value.length);
|
||||
getSupport().logMessageContent(value);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((byte) (lastPacketCounter + 1) == value[0] ) {
|
||||
lastPacketCounter++;
|
||||
bufferActivityData(value);
|
||||
} else {
|
||||
GB.toast("Error fetching activity data, unexpected package length: " + value.length, Toast.LENGTH_LONG, GB.ERROR);
|
||||
LOG.warn("Unexpected activity data: " + Logging.formatBytes(value));
|
||||
GB.toast("Error " + getName() + ", invalid package counter: " + value[0] + ", last was: " + lastPacketCounter, Toast.LENGTH_LONG, GB.ERROR);
|
||||
handleActivityFetchFinish(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates samples from the given 17-length array
|
||||
* Buffers the given activity summary data. If the total size is reached,
|
||||
* it is converted to an object and saved in the database.
|
||||
* @param value
|
||||
*/
|
||||
@Override
|
||||
protected void bufferActivityData(byte[] value) {
|
||||
// TODO: implement
|
||||
// int len = value.length;
|
||||
buffer.write(value, 1, value.length - 1); // skip the counter
|
||||
}
|
||||
|
||||
private BaseActivitySummary parseSummary(ByteArrayOutputStream stream) {
|
||||
BaseActivitySummary summary = new BaseActivitySummary();
|
||||
ByteBuffer buffer = ByteBuffer.wrap(stream.toByteArray()).order(ByteOrder.LITTLE_ENDIAN);
|
||||
// summary.setVersion(BLETypeConversions.toUnsigned(buffer.getShort()));
|
||||
buffer.getShort(); // version
|
||||
int activityKind = ActivityKind.TYPE_UNKNOWN;
|
||||
try {
|
||||
int rawKind = BLETypeConversions.toUnsigned(buffer.getShort());
|
||||
BipActivityType activityType = BipActivityType.fromCode(rawKind);
|
||||
activityKind = activityType.toActivityKind();
|
||||
} catch (Exception ex) {
|
||||
LOG.error("Error mapping acivity kind: " + ex.getMessage(), ex);
|
||||
}
|
||||
summary.setActivityKind(activityKind);
|
||||
// FIXME: should save timezone etc.
|
||||
summary.setStartTime(new Date(BLETypeConversions.toUnsigned(buffer.getInt()) * 1000));
|
||||
summary.setEndTime(new Date(BLETypeConversions.toUnsigned(buffer.getInt()) * 1000));
|
||||
int baseLongitude = buffer.getInt();
|
||||
int baseLatitude = buffer.getInt();
|
||||
int baseAltitude = buffer.getInt();
|
||||
summary.setBaseLongitude(baseLongitude);
|
||||
summary.setBaseLatitude(baseLatitude);
|
||||
summary.setBaseAltitude(baseAltitude);
|
||||
// summary.setBaseCoordinate(new GPSCoordinate(baseLatitude, baseLongitude, baseAltitude));
|
||||
|
||||
// summary.setDistanceMeters(Float.intBitsToFloat(buffer.getInt()));
|
||||
// summary.setAscentMeters(Float.intBitsToFloat(buffer.getInt()));
|
||||
// summary.setDescentMeters(Float.intBitsToFloat(buffer.getInt()));
|
||||
//
|
||||
// if (len % 4 != 1) {
|
||||
// throw new AssertionError("Unexpected activity array size: " + len);
|
||||
// }
|
||||
// summary.setMinAltitude(Float.intBitsToFloat(buffer.getInt()));
|
||||
// summary.setMaxAltitude(Float.intBitsToFloat(buffer.getInt()));
|
||||
// summary.setMinLatitude(buffer.getInt());
|
||||
// summary.setMaxLatitude(buffer.getInt());
|
||||
// summary.setMinLongitude(buffer.getInt());
|
||||
// summary.setMaxLongitude(buffer.getInt());
|
||||
//
|
||||
// for (int i = 1; i < len; i+=4) {
|
||||
// }
|
||||
// summary.setSteps(BLETypeConversions.toUnsigned(buffer.getInt()));
|
||||
// summary.setActiveTimeSeconds(BLETypeConversions.toUnsigned(buffer.getInt()));
|
||||
//
|
||||
// summary.setCaloriesBurnt(Float.intBitsToFloat(buffer.get()));
|
||||
// summary.setMaxSpeed(Float.intBitsToFloat(buffer.get()));
|
||||
// summary.setMinPace(Float.intBitsToFloat(buffer.get()));
|
||||
// summary.setMaxPace(Float.intBitsToFloat(buffer.get()));
|
||||
// summary.setTotalStride(Float.intBitsToFloat(buffer.get()));
|
||||
|
||||
buffer.getInt(); //
|
||||
buffer.getInt(); //
|
||||
buffer.getInt(); //
|
||||
|
||||
// summary.setTimeAscent(BLETypeConversions.toUnsigned(buffer.getInt()));
|
||||
// buffer.getInt(); //
|
||||
// summary.setTimeDescent(BLETypeConversions.toUnsigned(buffer.getInt()));
|
||||
// buffer.getInt(); //
|
||||
// summary.setTimeFlat(BLETypeConversions.toUnsigned(buffer.getInt()));
|
||||
//
|
||||
// summary.setAverageHR(BLETypeConversions.toUnsigned(buffer.getShort()));
|
||||
//
|
||||
// summary.setAveragePace(BLETypeConversions.toUnsigned(buffer.getShort()));
|
||||
// summary.setAverageStride(BLETypeConversions.toUnsigned(buffer.getShort()));
|
||||
|
||||
buffer.getShort(); //
|
||||
|
||||
return summary;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getLastSyncTimeKey() {
|
||||
return getDevice().getAddress() + "_" + "lastSportsSyncTimeMillis";
|
||||
}
|
||||
|
||||
|
||||
protected GregorianCalendar getLastSuccessfulSyncTime() {
|
||||
// FIXME: remove this!
|
||||
GregorianCalendar calendar = BLETypeConversions.createCalendar();
|
||||
calendar.add(Calendar.DAY_OF_MONTH, -1);
|
||||
return calendar;
|
||||
return getDevice().getAddress() + "_" + "lastSportsActivityTimeMillis";
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ import android.app.Activity;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ContentUris;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Color;
|
||||
@ -33,9 +34,12 @@ import android.provider.DocumentsContract;
|
||||
import android.provider.MediaStore;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.content.FileProvider;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Locale;
|
||||
|
||||
@ -43,6 +47,12 @@ import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
|
||||
public class AndroidUtils {
|
||||
/**
|
||||
* Creates a new {@link ParcelUuid} array with the contents of the given uuids.
|
||||
* The given array is expected to contain only {@link ParcelUuid} elements.
|
||||
* @param uuids an array of {@link ParcelUuid} elements
|
||||
* @return a {@link ParcelUuid} array instance with the same contents
|
||||
*/
|
||||
public static ParcelUuid[] toParcelUUids(Parcelable[] uuids) {
|
||||
if (uuids == null) {
|
||||
return null;
|
||||
@ -207,4 +217,15 @@ public class AndroidUtils {
|
||||
}
|
||||
throw new IllegalArgumentException("Unable to decode the given uri to a file path: " + uri);
|
||||
}
|
||||
|
||||
public static void viewFile(String path, String action, Context context) throws IOException {
|
||||
Intent intent = new Intent(action);
|
||||
File file = new File(path);
|
||||
|
||||
Uri contentUri = FileProvider.getUriForFile(context,
|
||||
context.getApplicationContext().getPackageName() + ".screenshot_provider", file);
|
||||
intent.setFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
intent.setData(contentUri);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
}
|
||||
|
@ -33,9 +33,14 @@ import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
|
||||
public class DateTimeUtils {
|
||||
private static SimpleDateFormat DAY_STORAGE_FORMAT = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
|
||||
public static SimpleDateFormat ISO_8601_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ssXXX", Locale.US);
|
||||
|
||||
public static String formatDateTime(Date date) {
|
||||
return DateUtils.formatDateTime(GBApplication.getContext(), date.getTime(), DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_TIME);
|
||||
return DateUtils.formatDateTime(GBApplication.getContext(), date.getTime(), DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_NO_YEAR);
|
||||
}
|
||||
|
||||
public static String formatIso8601(Date date) {
|
||||
return ISO_8601_FORMAT.format(date);
|
||||
}
|
||||
|
||||
public static String formatDate(Date date) {
|
||||
|
@ -310,4 +310,14 @@ public class FileUtils {
|
||||
}
|
||||
throw new IOException("Cannot create temporary directory in " + parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces some wellknown invalid characters in the given filename
|
||||
* to underscrores.
|
||||
* @param name the file name to make valid
|
||||
* @return the valid file name
|
||||
*/
|
||||
public static String makeValidFileName(String name) {
|
||||
return name.replaceAll("\0/:\\r\\n\\\\", "_");
|
||||
}
|
||||
}
|
7
app/src/main/res/drawable/ic_activity_biking.xml
Normal file
7
app/src/main/res/drawable/ic_activity_biking.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path android:fillColor="#000" android:pathData="M5,20.5A3.5,3.5 0 0,1 1.5,17A3.5,3.5 0 0,1 5,13.5A3.5,3.5 0 0,1 8.5,17A3.5,3.5 0 0,1 5,20.5M5,12A5,5 0 0,0 0,17A5,5 0 0,0 5,22A5,5 0 0,0 10,17A5,5 0 0,0 5,12M14.8,10H19V8.2H15.8L13.86,4.93C13.57,4.43 13,4.1 12.4,4.1C11.93,4.1 11.5,4.29 11.2,4.6L7.5,8.29C7.19,8.6 7,9 7,9.5C7,10.13 7.33,10.66 7.85,10.97L11.2,13V18H13V11.5L10.75,9.85L13.07,7.5M19,20.5A3.5,3.5 0 0,1 15.5,17A3.5,3.5 0 0,1 19,13.5A3.5,3.5 0 0,1 22.5,17A3.5,3.5 0 0,1 19,20.5M19,12A5,5 0 0,0 14,17A5,5 0 0,0 19,22A5,5 0 0,0 24,17A5,5 0 0,0 19,12M16,4.8C17,4.8 17.8,4 17.8,3C17.8,2 17,1.2 16,1.2C15,1.2 14.2,2 14.2,3C14.2,4 15,4.8 16,4.8Z" />
|
||||
</vector>
|
7
app/src/main/res/drawable/ic_activity_deep_sleep.xml
Normal file
7
app/src/main/res/drawable/ic_activity_deep_sleep.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path android:fillColor="#000" android:pathData="M23,12H17V10L20.39,6H17V4H23V6L19.62,10H23V12M15,16H9V14L12.39,10H9V8H15V10L11.62,14H15V16M7,20H1V18L4.39,14H1V12H7V14L3.62,18H7V20Z" />
|
||||
</vector>
|
7
app/src/main/res/drawable/ic_activity_light_sleep.xml
Normal file
7
app/src/main/res/drawable/ic_activity_light_sleep.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path android:fillColor="#000" android:pathData="M23,12H17V10L20.39,6H17V4H23V6L19.62,10H23V12M15,16H9V14L12.39,10H9V8H15V10L11.62,14H15V16M7,20H1V18L4.39,14H1V12H7V14L3.62,18H7V20Z" />
|
||||
</vector>
|
7
app/src/main/res/drawable/ic_activity_not_measured.xml
Normal file
7
app/src/main/res/drawable/ic_activity_not_measured.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path android:fillColor="#000" android:pathData="M12,20A7,7 0 0,1 5,13C5,11.72 5.35,10.5 5.95,9.5L15.5,19.04C14.5,19.65 13.28,20 12,20M3,4L1.75,5.27L4.5,8.03C3.55,9.45 3,11.16 3,13A9,9 0 0,0 12,22C13.84,22 15.55,21.45 17,20.5L19.5,23L20.75,21.73L13.04,14L3,4M11,9.44L13,11.44V8H11M15,1H9V3H15M19.04,4.55L17.62,5.97C16.07,4.74 14.12,4 12,4C10.17,4 8.47,4.55 7.05,5.5L8.5,6.94C9.53,6.35 10.73,6 12,6A7,7 0 0,1 19,13C19,14.27 18.65,15.47 18.06,16.5L19.5,17.94C20.45,16.53 21,14.83 21,13C21,10.88 20.26,8.93 19.03,7.39L20.45,5.97L19.04,4.55Z" />
|
||||
</vector>
|
7
app/src/main/res/drawable/ic_activity_running.xml
Normal file
7
app/src/main/res/drawable/ic_activity_running.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path android:fillColor="#000" android:pathData="M13.5,5.5C14.59,5.5 15.5,4.58 15.5,3.5C15.5,2.38 14.59,1.5 13.5,1.5C12.39,1.5 11.5,2.38 11.5,3.5C11.5,4.58 12.39,5.5 13.5,5.5M9.89,19.38L10.89,15L13,17V23H15V15.5L12.89,13.5L13.5,10.5C14.79,12 16.79,13 19,13V11C17.09,11 15.5,10 14.69,8.58L13.69,7C13.29,6.38 12.69,6 12,6C11.69,6 11.5,6.08 11.19,6.08L6,8.28V13H8V9.58L9.79,8.88L8.19,17L3.29,16L2.89,18L9.89,19.38Z" />
|
||||
</vector>
|
7
app/src/main/res/drawable/ic_activity_tracks.xml
Normal file
7
app/src/main/res/drawable/ic_activity_tracks.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path android:fillColor="#000" android:pathData="M13.5,5.5C14.59,5.5 15.5,4.58 15.5,3.5C15.5,2.38 14.59,1.5 13.5,1.5C12.39,1.5 11.5,2.38 11.5,3.5C11.5,4.58 12.39,5.5 13.5,5.5M9.89,19.38L10.89,15L13,17V23H15V15.5L12.89,13.5L13.5,10.5C14.79,12 16.79,13 19,13V11C17.09,11 15.5,10 14.69,8.58L13.69,7C13.29,6.38 12.69,6 12,6C11.69,6 11.5,6.08 11.19,6.08L6,8.28V13H8V9.58L9.79,8.88L8.19,17L3.29,16L2.89,18L9.89,19.38Z" />
|
||||
</vector>
|
7
app/src/main/res/drawable/ic_activity_unknown.xml
Normal file
7
app/src/main/res/drawable/ic_activity_unknown.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path android:fillColor="#000" android:pathData="M12,18A6,6 0 0,1 6,12A6,6 0 0,1 12,6A6,6 0 0,1 18,12A6,6 0 0,1 12,18M20,15.31L23.31,12L20,8.69V4H15.31L12,0.69L8.69,4H4V8.69L0.69,12L4,15.31V20H8.69L12,23.31L15.31,20H20V15.31Z" />
|
||||
</vector>
|
7
app/src/main/res/drawable/ic_activity_walking.xml
Normal file
7
app/src/main/res/drawable/ic_activity_walking.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path android:fillColor="#000" android:pathData="M14.12,10H19V8.2H15.38L13.38,4.87C13.08,4.37 12.54,4.03 11.92,4.03C11.74,4.03 11.58,4.06 11.42,4.11L6,5.8V11H7.8V7.33L9.91,6.67L6,22H7.8L10.67,13.89L13,17V22H14.8V15.59L12.31,11.05L13.04,8.18M14,3.8C15,3.8 15.8,3 15.8,2C15.8,1 15,0.2 14,0.2C13,0.2 12.2,1 12.2,2C12.2,3 13,3.8 14,3.8Z" />
|
||||
</vector>
|
12
app/src/main/res/layout/activity_list.xml
Normal file
12
app/src/main/res/layout/activity_list.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical" android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ListView
|
||||
android:id="@+id/itemListView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="false"></ListView>
|
||||
|
||||
</LinearLayout>
|
@ -231,12 +231,27 @@
|
||||
card_view:srcCompat="@drawable/ic_activity_graphs" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/device_action_find"
|
||||
android:id="@+id/device_action_show_activity_tracks"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_below="@id/device_image"
|
||||
android:layout_margin="4dp"
|
||||
android:layout_toEndOf="@id/device_action_show_activity_graphs"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:contentDescription="@string/controlcenter_start_activity_tracks"
|
||||
android:padding="4dp"
|
||||
android:scaleType="fitXY"
|
||||
android:tint="@color/secondarytext"
|
||||
card_view:srcCompat="@drawable/ic_activity_tracks" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/device_action_find"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_below="@id/device_image"
|
||||
android:layout_margin="4dp"
|
||||
android:layout_toEndOf="@id/device_action_show_activity_tracks"
|
||||
android:clickable="true"
|
||||
android:contentDescription="@string/controlcenter_find_device"
|
||||
android:padding="4dp"
|
||||
|
@ -508,6 +508,20 @@
|
||||
<string name="_pebble_watch_mute">Mute</string>
|
||||
<string name="_pebble_watch_reply">Reply</string>
|
||||
|
||||
<string name="controlcenter_start_activity_tracks">Your activity tracks</string>
|
||||
<string name="activity_type_not_measured">Not measured</string>
|
||||
<string name="activity_type_activity">Activity</string>
|
||||
<string name="activity_type_light_sleep">Light sleep</string>
|
||||
<string name="activity_type_deep_sleep">Deep sleep</string>
|
||||
<string name="activity_type_not_worn">Device not worn</string>
|
||||
<string name="activity_type_running">Running</string>
|
||||
<string name="activity_type_walking">Walking</string>
|
||||
<string name="activity_type_swimming">Swimming</string>
|
||||
<string name="activity_type_unknown">Unknown activity</string>
|
||||
<string name="activity_summaries">Activities</string>
|
||||
<string name="activity_type_biking">Biking</string>
|
||||
<string name="activity_type_treadmill">Treadmill</string>
|
||||
|
||||
<string name="kind_firmware">Firmware</string>
|
||||
<string name="kind_invalid">Invalid data</string>
|
||||
<string name="kind_font">Font</string>
|
||||
|
@ -1,4 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- defines directories shared to other applications -->
|
||||
<paths xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<external-path name="external_files" path="."/>
|
||||
<files-path name="gpx" path="./"/>
|
||||
</paths>
|
@ -0,0 +1,110 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.test;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBException;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.amazfitbip.BipActivitySummary;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.User;
|
||||
import nodomain.freeyourgadget.gadgetbridge.export.GPXExporter;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityPoint;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityTrack;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.amazfitbip.ActivityDetailsParser;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class ActivityDetailsParserTest extends TestBase {
|
||||
private static final URL DETAILS_1 = ActivityDetailsParserTest.class.getClassLoader().getResource("ActivityDetailsDump1.txt");
|
||||
private static final long MAX_DETAILS = 1024 * 1024;
|
||||
private static Date baseTime;
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpSuite() throws Exception {
|
||||
baseTime = DateTimeUtils.ISO_8601_FORMAT.parse("2017-01-20T14:00:00-00:00"); // yyyy-mm-dd'T'hh:mm:ssZ
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActivityDetails() throws Exception {
|
||||
BipActivitySummary summary = createSummary();
|
||||
|
||||
ActivityDetailsParser parser = new ActivityDetailsParser(summary);
|
||||
parser.setSkipCounterByte(true);
|
||||
try (InputStream in = getContents(DETAILS_1)) {
|
||||
ActivityTrack track = parser.parse(FileUtils.readAll(in, MAX_DETAILS));
|
||||
assertEquals("SuperBand 2000", track.getDevice().getName());
|
||||
assertEquals("Elvis", track.getUser().getName());
|
||||
|
||||
List<ActivityPoint> trackPoints = track.getTrackPoints();
|
||||
assertEquals(1208, trackPoints.size());
|
||||
}
|
||||
}
|
||||
|
||||
private BipActivitySummary createSummary() {
|
||||
BipActivitySummary summary = new BipActivitySummary();
|
||||
summary.setBaseLongitude(1);
|
||||
summary.setBaseLatitude(1);
|
||||
summary.setBaseAltitude(1);
|
||||
summary.setStartTime(baseTime);
|
||||
User dummyUser = new User(0L);
|
||||
dummyUser.setName("Elvis");
|
||||
summary.setName("testtrack");
|
||||
summary.setUser(dummyUser);
|
||||
Device device = new Device(0l);
|
||||
device.setName("SuperBand 2000");
|
||||
summary.setDevice(device);
|
||||
|
||||
return summary;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGPXExport() throws Exception {
|
||||
BipActivitySummary summary = createSummary();
|
||||
|
||||
int baseLongi = BLETypeConversions.toUint32((byte) 0xd6, (byte) 0xc4,(byte) 0x62,(byte) 0x02);
|
||||
int baseLati = BLETypeConversions.toUint32((byte) 0xff, (byte) 0xa9, (byte) 0x61, (byte) 0x9);
|
||||
int baseAlti = BLETypeConversions.toUint32((byte) 0x30, (byte) 0x0, (byte) 0x0, (byte) 0x0);
|
||||
|
||||
summary.setBaseLongitude(baseLongi);
|
||||
summary.setBaseLatitude(baseLati);
|
||||
summary.setBaseAltitude(baseAlti);
|
||||
|
||||
ActivityDetailsParser parser = new ActivityDetailsParser(summary);
|
||||
parser.setSkipCounterByte(true);
|
||||
try (InputStream in = getContents(DETAILS_1)) {
|
||||
ActivityTrack track = parser.parse(FileUtils.readAll(in, MAX_DETAILS));
|
||||
|
||||
List<ActivityPoint> trackPoints = track.getTrackPoints();
|
||||
assertEquals(1208, trackPoints.size());
|
||||
|
||||
|
||||
GPXExporter exporter = new GPXExporter();
|
||||
exporter.setIncludeHeartRate(false);
|
||||
exporter.setCreator(getClass().getName());
|
||||
File targetFile = File.createTempFile("gadgetbridge-track", ".gpx");
|
||||
System.out.println("Writing GPX file: " + targetFile);
|
||||
exporter.performExport(track, targetFile);
|
||||
|
||||
assertTrue(targetFile.length() > 1024);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private InputStream getContents(URL hexFile) throws IOException {
|
||||
return new HexToBinaryInputStream(hexFile.openStream());
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.test;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.GregorianCalendar;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class BLETypeConversionsTest extends TestBase {
|
||||
@Test
|
||||
public void testTimeParsing1() {
|
||||
byte[] requested = new byte[] {
|
||||
(byte) 0xe1, 0x07, 0x0a, 0x1d, 0x00, 0x1c, 0x00,0x08
|
||||
};
|
||||
byte[] received = new byte[] {
|
||||
(byte) 0xe1, 0x07, 0x0a, 0x1c, 0x17, 0x1c, 0x00, 0x04
|
||||
};
|
||||
GregorianCalendar calRequested = BLETypeConversions.rawBytesToCalendar(requested, false);
|
||||
GregorianCalendar calReceived = BLETypeConversions.rawBytesToCalendar(received, false);
|
||||
|
||||
assertTrue(calRequested.getTime().equals(calReceived.getTime()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTimeParsingWithDST() {
|
||||
byte[] requested = new byte[] {
|
||||
(byte) 0xe1,0x07,0x0a,0x09,0x11,0x23,0x00,0x08
|
||||
};
|
||||
byte[] received = new byte[] {
|
||||
(byte) 0xe1,0x07,0x0a,0x09,0x10,0x23,0x00,0x04
|
||||
};
|
||||
GregorianCalendar calRequested = BLETypeConversions.rawBytesToCalendar(requested, false);
|
||||
GregorianCalendar calReceived = BLETypeConversions.rawBytesToCalendar(received, false);
|
||||
|
||||
assertTrue(calRequested.getTime().equals(calReceived.getTime()));
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.test;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
class HexToBinaryInputStream extends FilterInputStream {
|
||||
HexToBinaryInputStream(InputStream in) {
|
||||
super(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
int value;
|
||||
StringBuilder buffer = new StringBuilder(4);
|
||||
|
||||
loop:
|
||||
while (true) {
|
||||
value = super.read();
|
||||
switch (value) {
|
||||
case -1:
|
||||
case ' ':
|
||||
case '\r':
|
||||
case '\n':
|
||||
break loop;
|
||||
default:
|
||||
buffer.append((char) value);
|
||||
}
|
||||
}
|
||||
if (buffer.length() > 0) {
|
||||
return Integer.decode(buffer.toString());
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(@NonNull byte[] b, int off, int len) throws IOException {
|
||||
if (off < 0 || len < 0 || len > b.length - off) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
for (int i = 0; i < len; i++) {
|
||||
int value = read();
|
||||
if (value == -1) {
|
||||
return i;
|
||||
}
|
||||
b[off + i] = (byte) value;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.test;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class HexToBinaryInputStreamTest extends TestBase {
|
||||
|
||||
@Test
|
||||
public void testConversion() throws IOException {
|
||||
byte[] hexString;
|
||||
byte[] binString;
|
||||
|
||||
try (InputStream in = ActivityDetailsParserTest.class.getClassLoader().getResourceAsStream("ActivityDetailsDump1.txt")) {
|
||||
hexString = FileUtils.readAll(in, 1024 * 1024);
|
||||
assertTrue(hexString.length > 1);
|
||||
try (InputStream in2 = getContents(ActivityDetailsParserTest.class.getClassLoader().getResource("ActivityDetailsDump1.txt"))) {
|
||||
binString = FileUtils.readAll(in2, 1024 * 1024);
|
||||
assertTrue(binString.length > 1);
|
||||
}
|
||||
}
|
||||
Assert.assertTrue(hexString.length > binString.length);
|
||||
ByteArrayOutputStream binToHexOut = new ByteArrayOutputStream(hexString.length);
|
||||
for (int i = 0; i < binString.length; i++) {
|
||||
String hexed = String.format("0x%x", binString[i]);
|
||||
binToHexOut.write(hexed.getBytes("US-ASCII"));
|
||||
if ((i + 1) % 17 == 0) {
|
||||
binToHexOut.write('\n');
|
||||
} else {
|
||||
binToHexOut.write(' ');
|
||||
}
|
||||
}
|
||||
|
||||
byte[] hexedBytes = binToHexOut.toByteArray();
|
||||
Assert.assertArrayEquals(hexString, hexedBytes);
|
||||
}
|
||||
|
||||
private InputStream getContents(URL hexFile) throws IOException {
|
||||
return new HexToBinaryInputStream(hexFile.openStream());
|
||||
}
|
||||
|
||||
}
|
@ -23,6 +23,11 @@ public class Tryout extends TestBase {
|
||||
byte b = (byte) v;
|
||||
LOG.info("v: " + v);
|
||||
Logging.logBytes(LOG, new byte[] { b });
|
||||
|
||||
byte[] bs = new byte[] {(byte) 0xf0,0x28,0x00,0x00 };
|
||||
LOG.warn("uint32: " + BLETypeConversions.toUint32(bs));
|
||||
LOG.warn("uint16: " + BLETypeConversions.toUint16(bs));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
861
app/src/test/resources/ActivityDetailsDump1.txt
Normal file
861
app/src/test/resources/ActivityDetailsDump1.txt
Normal file
@ -0,0 +1,861 @@
|
||||
0x0 0x1 0x7 0x47 0x0 0x0 0x0 0x0 0x0 0x1 0x8 0x46 0x0 0x0 0x0 0x0 0x0
|
||||
0x1 0x1 0xa 0x43 0x0 0x0 0x0 0x0 0x0 0x1 0xc 0x46 0x0 0x0 0x0 0x0 0x0
|
||||
0x2 0x1 0xd 0x44 0x0 0x0 0x0 0x0 0x0 0x1 0xf 0x3e 0x0 0x0 0x0 0x0 0x0
|
||||
0x3 0x1 0x11 0x3b 0x0 0x0 0x0 0x0 0x0 0x1 0x12 0x3e 0x0 0x0 0x0 0x0 0x0
|
||||
0x4 0x1 0x17 0x3d 0x0 0x0 0x0 0x0 0x0 0x1 0x18 0x3f 0x0 0x0 0x0 0x0 0x0
|
||||
0x5 0x1 0x1b 0x41 0x0 0x0 0x0 0x0 0x0 0x1 0x1d 0x42 0x0 0x0 0x0 0x0 0x0
|
||||
0x6 0x1 0x20 0x43 0x0 0x0 0x0 0x0 0x0 0x1 0x21 0x44 0x0 0x0 0x0 0x0 0x0
|
||||
0x7 0x1 0x22 0x45 0x0 0x0 0x0 0x0 0x0 0x0 0x23 0x0 0x0 0x0 0x0 0x0 0x0
|
||||
0x8 0x0 0x23 0x79 0xff 0xcd 0x0 0x0 0x0 0x0 0x23 0x88 0xff 0xc3 0x0 0x0 0x0
|
||||
0x9 0x0 0x23 0xbf 0xff 0xeb 0x0 0x0 0x0 0x0 0x23 0xec 0xff 0x4 0x1 0x0 0x0
|
||||
0xa 0x0 0x23 0x5 0x0 0x4 0x1 0x0 0x0 0x0 0x23 0xf6 0xff 0x4f 0x1 0x0 0x0
|
||||
0xb 0x0 0x23 0xec 0xff 0x18 0x1 0x0 0x0 0x0 0x23 0xf1 0xff 0xff 0x0 0x0 0x0
|
||||
0xc 0x0 0x23 0xf1 0xff 0xf5 0x0 0x0 0x0 0x0 0x23 0xe2 0xff 0xa0 0x0 0x0 0x0
|
||||
0xd 0x0 0x23 0x9c 0xff 0xeb 0x0 0x0 0x0 0x0 0x23 0xf1 0xff 0xeb 0x0 0x0 0x0
|
||||
0xe 0x0 0x23 0xfb 0xff 0xe 0x1 0x0 0x0 0x0 0x23 0xf6 0xff 0x13 0x1 0x0 0x0
|
||||
0xf 0x0 0x23 0xfb 0xff 0x68 0x1 0x0 0x0 0x0 0x23 0xe2 0xff 0x18 0x1 0x0 0x0
|
||||
0x10 0x0 0x23 0xb5 0xff 0xd2 0x0 0x0 0x0 0x0 0x23 0x97 0xff 0x87 0x0 0x0 0x0
|
||||
0x11 0x0 0x23 0xba 0xff 0xa5 0x0 0x0 0x0 0x0 0x23 0xe2 0xff 0xfa 0x0 0x0 0x0
|
||||
0x12 0x0 0x23 0xe2 0xff 0xb9 0x0 0x0 0x0 0x0 0x23 0xfb 0xff 0x4 0x1 0x0 0x0
|
||||
0x13 0x0 0x23 0xec 0xff 0xa5 0x0 0x0 0x0 0x0 0x23 0xf1 0xff 0x2c 0x1 0x0 0x0
|
||||
0x14 0x0 0x23 0x5 0x0 0xe 0x1 0x0 0x0 0x0 0x23 0xec 0xff 0x9b 0x0 0x0 0x0
|
||||
0x15 0x0 0x23 0xf1 0xff 0xa5 0x0 0x0 0x0 0x0 0x23 0xf6 0xff 0xb4 0x0 0x0 0x0
|
||||
0x16 0x0 0x23 0xec 0xff 0xc3 0x0 0x0 0x0 0x0 0x23 0x7e 0xff 0xd2 0x0 0x0 0x0
|
||||
0x17 0x6 0x23 0x81 0x0 0xd2 0x0 0x0 0x0 0x0 0x24 0xd3 0xff 0x7d 0x0 0x0 0x0
|
||||
0x18 0x6 0x24 0x81 0x0 0x7d 0x0 0x0 0x0 0x0 0x25 0xc1 0xff 0xb1 0x0 0x0 0x0
|
||||
0x19 0x6 0x25 0x81 0x0 0xb1 0x0 0x0 0x0 0x0 0x26 0xca 0xff 0xc9 0x0 0x0 0x0
|
||||
0x1a 0x6 0x26 0x81 0x0 0xc9 0x0 0x0 0x0 0x0 0x27 0xd7 0xff 0xdd 0x0 0x0 0x0
|
||||
0x1b 0x6 0x27 0x81 0x0 0xdd 0x0 0x0 0x0 0x1 0x27 0x46 0x0 0x0 0x0 0x0 0x0
|
||||
0x1c 0x0 0x28 0xe4 0xff 0xf8 0x0 0x0 0x0 0x6 0x28 0x81 0x0 0xf8 0x0 0x0 0x0
|
||||
0x1d 0x0 0x29 0xef 0xff 0xf 0x1 0x0 0x0 0x6 0x29 0x81 0x0 0xf 0x1 0x0 0x0
|
||||
0x1e 0x1 0x29 0x43 0x0 0x0 0x0 0x0 0x0 0x0 0x2a 0xf1 0xff 0x2 0x1 0x0 0x0
|
||||
0x1f 0x6 0x2a 0x81 0x0 0x2 0x1 0x0 0x0 0x1 0x2a 0x45 0x0 0x0 0x0 0x0 0x0
|
||||
0x20 0x0 0x2b 0xeb 0xff 0xf4 0x0 0xfe 0xff 0x6 0x2b 0x81 0x0 0xf4 0x0 0xfe 0xff
|
||||
0x21 0x0 0x2c 0xe8 0xff 0xdc 0x0 0x0 0x0 0x6 0x2c 0x81 0x0 0xdc 0x0 0x0 0x0
|
||||
0x22 0x0 0x2d 0xe9 0xff 0xca 0x0 0x0 0x0 0x6 0x2d 0x81 0x0 0xca 0x0 0x0 0x0
|
||||
0x23 0x0 0x2e 0xeb 0xff 0xc9 0x0 0x0 0x0 0x6 0x2e 0x81 0x0 0xc9 0x0 0x0 0x0
|
||||
0x24 0x1 0x2e 0x46 0x0 0x0 0x0 0x0 0x0 0x0 0x2f 0xed 0xff 0xcb 0x0 0x0 0x0
|
||||
0x25 0x6 0x2f 0x81 0x0 0xcb 0x0 0x0 0x0 0x1 0x2f 0x47 0x0 0x0 0x0 0x0 0x0
|
||||
0x26 0x0 0x30 0xf0 0xff 0xc5 0x0 0x0 0x0 0x6 0x30 0x81 0x0 0xc5 0x0 0x0 0x0
|
||||
0x27 0x0 0x31 0xf2 0xff 0xb7 0x0 0x0 0x0 0x6 0x31 0x81 0x0 0xb7 0x0 0x0 0x0
|
||||
0x28 0x0 0x32 0xf1 0xff 0xb1 0x0 0x0 0x0 0x6 0x32 0x81 0x0 0xb1 0x0 0x0 0x0
|
||||
0x29 0x0 0x33 0xf7 0xff 0xb5 0x0 0x0 0x0 0x6 0x33 0x81 0x0 0xb5 0x0 0x0 0x0
|
||||
0x2a 0x1 0x33 0x49 0x0 0x0 0x0 0x0 0x0 0x0 0x34 0xfa 0xff 0xc8 0x0 0x0 0x0
|
||||
0x2b 0x6 0x34 0x81 0x0 0xc8 0x0 0x0 0x0 0x1 0x34 0x4a 0x0 0x0 0x0 0x0 0x0
|
||||
0x2c 0x0 0x35 0xf7 0xff 0xda 0x0 0x0 0x0 0x6 0x35 0x81 0x0 0xda 0x0 0x0 0x0
|
||||
0x2d 0x1 0x35 0x4b 0x0 0x0 0x0 0x0 0x0 0x0 0x36 0xf3 0xff 0xdb 0x0 0x0 0x0
|
||||
0x2e 0x6 0x36 0x81 0x0 0xdb 0x0 0x0 0x0 0x0 0x37 0xe9 0xff 0xed 0x0 0x0 0x0
|
||||
0x2f 0x6 0x37 0x81 0x0 0xed 0x0 0x0 0x0 0x1 0x38 0x4c 0x0 0x0 0x0 0x0 0x0
|
||||
0x30 0x0 0x38 0xe9 0xff 0xf6 0x0 0x0 0x0 0x6 0x38 0x81 0x0 0xf6 0x0 0x0 0x0
|
||||
0x31 0x0 0x39 0xeb 0xff 0xe4 0x0 0xfe 0xff 0x6 0x39 0x81 0x0 0xe4 0x0 0xfe 0xff
|
||||
0x32 0x1 0x39 0x4d 0x0 0x0 0x0 0x0 0x0 0x0 0x3a 0xef 0xff 0xbd 0x0 0x0 0x0
|
||||
0x33 0x6 0x3a 0x81 0x0 0xbd 0x0 0x0 0x0 0x1 0x3a 0x4e 0x0 0x0 0x0 0x0 0x0
|
||||
0x34 0x0 0x3c 0xed 0xff 0xcc 0x0 0x0 0x0 0x6 0x3c 0x81 0x0 0xcc 0x0 0x0 0x0
|
||||
0x35 0x1 0x3d 0x4f 0x0 0x0 0x0 0x0 0x0 0x1 0x3e 0x50 0x0 0x0 0x0 0x0 0x0
|
||||
0x36 0x0 0x3e 0x1 0x0 0xcd 0x0 0x0 0x0 0x6 0x3e 0x81 0x0 0xcd 0x0 0x0 0x0
|
||||
0x37 0x0 0x3f 0x14 0x0 0x91 0x0 0x0 0x0 0x6 0x3f 0x81 0x0 0x91 0x0 0x0 0x0
|
||||
0x38 0x1 0x3f 0x51 0x0 0x0 0x0 0x0 0x0 0x0 0x41 0x86 0x1 0x6e 0x0 0x0 0x0
|
||||
0x39 0x6 0x41 0x81 0x0 0x6e 0x0 0x0 0x0 0x1 0x41 0x52 0x0 0x0 0x0 0x0 0x0
|
||||
0x3a 0x0 0x42 0x5e 0x1 0x55 0x0 0x0 0x0 0x6 0x42 0x81 0x0 0x55 0x0 0x0 0x0
|
||||
0x3b 0x0 0x43 0x36 0x1 0x48 0x0 0x0 0x0 0x6 0x43 0x81 0x0 0x48 0x0 0x0 0x0
|
||||
0x3c 0x0 0x44 0x31 0x1 0x36 0x0 0x0 0x0 0x6 0x44 0x81 0x0 0x36 0x0 0x0 0x0
|
||||
0x3d 0x1 0x44 0x53 0x0 0x0 0x0 0x0 0x0 0x0 0x45 0x3d 0x1 0x2f 0x0 0x0 0x0
|
||||
0x3e 0x6 0x45 0x81 0x0 0x2f 0x0 0x0 0x0 0x0 0x46 0x35 0x1 0x38 0x0 0x0 0x0
|
||||
0x3f 0x6 0x46 0x81 0x0 0x38 0x0 0x0 0x0 0x1 0x46 0x54 0x0 0x0 0x0 0x0 0x0
|
||||
0x40 0x0 0x47 0x76 0x1 0x37 0x0 0x0 0x0 0x6 0x47 0x81 0x0 0x37 0x0 0x0 0x0
|
||||
0x41 0x0 0x48 0xbd 0x1 0x32 0x0 0x0 0x0 0x6 0x48 0x81 0x0 0x32 0x0 0x0 0x0
|
||||
0x42 0x1 0x49 0x55 0x0 0x0 0x0 0x0 0x0 0x0 0x49 0xb0 0x1 0xd 0x0 0x0 0x0
|
||||
0x43 0x6 0x49 0x81 0x0 0xd 0x0 0x0 0x0 0x0 0x4a 0x9b 0x1 0x1a 0x0 0x0 0x0
|
||||
0x44 0x6 0x4a 0x81 0x0 0x1a 0x0 0x0 0x0 0x0 0x4b 0x7a 0x1 0x1c 0x0 0xfe 0xff
|
||||
0x45 0x6 0x4b 0x81 0x0 0x1c 0x0 0xfe 0xff 0x0 0x4c 0x53 0x1 0x34 0x0 0x0 0x0
|
||||
0x46 0x6 0x4c 0x81 0x0 0x34 0x0 0x0 0x0 0x1 0x4c 0x56 0x0 0x0 0x0 0x0 0x0
|
||||
0x47 0x0 0x4d 0x24 0x1 0xfe 0xff 0x0 0x0 0x6 0x4d 0x81 0x0 0xfe 0xff 0x0 0x0
|
||||
0x48 0x1 0x4e 0x55 0x0 0x0 0x0 0x0 0x0 0x0 0x4f 0x3c 0x1 0xff 0xff 0x0 0x0
|
||||
0x49 0x6 0x4f 0x81 0x0 0xff 0xff 0x0 0x0 0x0 0x51 0x5 0x1 0x2a 0x0 0x0 0x0
|
||||
0x4a 0x6 0x51 0x81 0x0 0x2a 0x0 0x0 0x0 0x1 0x52 0x54 0x0 0x0 0x0 0x0 0x0
|
||||
0x4b 0x0 0x53 0xd5 0x0 0x77 0x0 0x0 0x0 0x6 0x53 0x81 0x0 0x77 0x0 0x0 0x0
|
||||
0x4c 0x0 0x54 0x86 0x0 0x89 0x0 0x0 0x0 0x6 0x54 0x81 0x0 0x89 0x0 0x0 0x0
|
||||
0x4d 0x1 0x55 0x53 0x0 0x0 0x0 0x0 0x0 0x0 0x55 0x59 0x0 0xa3 0x0 0x0 0x0
|
||||
0x4e 0x6 0x55 0x95 0x0 0xa3 0x0 0x0 0x0 0x0 0x56 0x3c 0x0 0xc2 0x0 0x0 0x0
|
||||
0x4f 0x6 0x56 0x95 0x0 0xc2 0x0 0x0 0x0 0x1 0x56 0x4f 0x0 0x0 0x0 0x0 0x0
|
||||
0x50 0x0 0x57 0x23 0x0 0xe8 0x0 0x0 0x0 0x6 0x57 0x95 0x0 0xe8 0x0 0x0 0x0
|
||||
0x51 0x1 0x57 0x50 0x0 0x0 0x0 0x0 0x0 0x0 0x58 0x11 0x0 0x5 0x1 0x0 0x0
|
||||
0x52 0x6 0x58 0x95 0x0 0x5 0x1 0x0 0x0 0x0 0x59 0xfc 0xff 0xf 0x1 0x0 0x0
|
||||
0x53 0x6 0x59 0x95 0x0 0xf 0x1 0x0 0x0 0x1 0x5a 0x51 0x0 0x0 0x0 0x0 0x0
|
||||
0x54 0x0 0x5a 0xed 0xff 0x25 0x1 0x0 0x0 0x6 0x5a 0x95 0x0 0x25 0x1 0x0 0x0
|
||||
0x55 0x0 0x5b 0xe7 0xff 0x32 0x1 0x0 0x0 0x6 0x5b 0x95 0x0 0x32 0x1 0x0 0x0
|
||||
0x56 0x0 0x5c 0xb8 0xff 0xa5 0x1 0x0 0x0 0x6 0x5c 0x95 0x0 0xa5 0x1 0x0 0x0
|
||||
0x57 0x0 0x5d 0xc0 0xff 0x7c 0x1 0x0 0x0 0x6 0x5d 0x95 0x0 0x7c 0x1 0x0 0x0
|
||||
0x58 0x0 0x5e 0xde 0xff 0x3e 0x1 0x0 0x0 0x6 0x5e 0x82 0x0 0x3e 0x1 0x0 0x0
|
||||
0x59 0x1 0x5f 0x52 0x0 0x0 0x0 0x0 0x0 0x0 0x5f 0xd8 0xff 0x46 0x1 0x0 0x0
|
||||
0x5a 0x6 0x5f 0x82 0x0 0x46 0x1 0x0 0x0 0x1 0x60 0x53 0x0 0x0 0x0 0x0 0x0
|
||||
0x5b 0x0 0x60 0xd3 0xff 0x39 0x1 0x0 0x0 0x6 0x60 0x82 0x0 0x39 0x1 0x0 0x0
|
||||
0x5c 0x0 0x61 0xc9 0xff 0x1f 0x1 0x0 0x0 0x6 0x61 0x82 0x0 0x1f 0x1 0x0 0x0
|
||||
0x5d 0x1 0x61 0x55 0x0 0x0 0x0 0x0 0x0 0x0 0x63 0xbf 0xff 0xdd 0x0 0x0 0x0
|
||||
0x5e 0x6 0x63 0x82 0x0 0xdd 0x0 0x0 0x0 0x1 0x63 0x56 0x0 0x0 0x0 0x0 0x0
|
||||
0x5f 0x1 0x66 0x57 0x0 0x0 0x0 0x0 0x0 0x0 0x6a 0xea 0xff 0xc6 0x0 0x0 0x0
|
||||
0x60 0x6 0x6a 0x82 0x0 0xc6 0x0 0x0 0x0 0x1 0x6b 0x56 0x0 0x0 0x0 0x0 0x0
|
||||
0x61 0x0 0x6c 0x59 0x0 0x9f 0x0 0x0 0x0 0x6 0x6c 0x96 0x0 0x9f 0x0 0x0 0x0
|
||||
0x62 0x1 0x6d 0x55 0x0 0x0 0x0 0x0 0x0 0x0 0x6e 0x24 0x1 0x61 0x0 0x0 0x0
|
||||
0x63 0x6 0x6e 0x96 0x0 0x61 0x0 0x0 0x0 0x1 0x6e 0x54 0x0 0x0 0x0 0x0 0x0
|
||||
0x64 0x0 0x6f 0x39 0x1 0x24 0x0 0x0 0x0 0x6 0x6f 0x96 0x0 0x24 0x0 0x0 0x0
|
||||
0x65 0x1 0x70 0x53 0x0 0x0 0x0 0x0 0x0 0x0 0x70 0x5b 0x1 0xfb 0xff 0x0 0x0
|
||||
0x66 0x6 0x70 0x96 0x0 0xfb 0xff 0x0 0x0 0x0 0x71 0x7f 0x1 0xe0 0xff 0x0 0x0
|
||||
0x67 0x6 0x71 0x96 0x0 0xe0 0xff 0x0 0x0 0x0 0x72 0xa3 0x1 0xd4 0xff 0x0 0x0
|
||||
0x68 0x6 0x72 0x96 0x0 0xd4 0xff 0x0 0x0 0x1 0x72 0x54 0x0 0x0 0x0 0x0 0x0
|
||||
0x69 0x0 0x73 0xc2 0x1 0xcf 0xff 0x0 0x0 0x6 0x73 0x96 0x0 0xcf 0xff 0x0 0x0
|
||||
0x6a 0x0 0x74 0xd8 0x1 0xc7 0xff 0x0 0x0 0x6 0x74 0x96 0x0 0xc7 0xff 0x0 0x0
|
||||
0x6b 0x1 0x74 0x55 0x0 0x0 0x0 0x0 0x0 0x0 0x75 0xe6 0x1 0xbe 0xff 0x0 0x0
|
||||
0x6c 0x6 0x75 0x96 0x0 0xbe 0xff 0x0 0x0 0x0 0x76 0xeb 0x1 0xb2 0xff 0x0 0x0
|
||||
0x6d 0x6 0x76 0x96 0x0 0xb2 0xff 0x0 0x0 0x1 0x77 0x56 0x0 0x0 0x0 0x0 0x0
|
||||
0x6e 0x0 0x77 0x8a 0x2 0x70 0xff 0x0 0x0 0x6 0x77 0x96 0x0 0x70 0xff 0x0 0x0
|
||||
0x6f 0x0 0x78 0x92 0x2 0x9a 0xff 0x0 0x0 0x6 0x78 0x96 0x0 0x9a 0xff 0x0 0x0
|
||||
0x70 0x1 0x78 0x57 0x0 0x0 0x0 0x0 0x0 0x0 0x79 0x7c 0x2 0xb9 0xff 0x0 0x0
|
||||
0x71 0x6 0x79 0x96 0x0 0xb9 0xff 0x0 0x0 0x0 0x7a 0x59 0x2 0xb9 0xff 0x0 0x0
|
||||
0x72 0x6 0x7a 0x83 0x0 0xb9 0xff 0x0 0x0 0x0 0x7b 0x33 0x2 0xa3 0xff 0x0 0x0
|
||||
0x73 0x6 0x7b 0x83 0x0 0xa3 0xff 0x0 0x0 0x0 0x7c 0x27 0x2 0xac 0xff 0x0 0x0
|
||||
0x74 0x6 0x7c 0x83 0x0 0xac 0xff 0x0 0x0 0x1 0x7d 0x56 0x0 0x0 0x0 0x0 0x0
|
||||
0x75 0x0 0x7d 0x29 0x2 0xb1 0xff 0x0 0x0 0x6 0x7d 0x83 0x0 0xb1 0xff 0x0 0x0
|
||||
0x76 0x0 0x7e 0x16 0x2 0xa9 0xff 0x2 0x0 0x6 0x7e 0x83 0x0 0xa9 0xff 0x2 0x0
|
||||
0x77 0x1 0x7e 0x55 0x0 0x0 0x0 0x0 0x0 0x0 0x7f 0xd 0x2 0xaf 0xff 0x0 0x0
|
||||
0x78 0x6 0x7f 0x83 0x0 0xaf 0xff 0x0 0x0 0x0 0x80 0x0 0x2 0xb5 0xff 0x0 0x0
|
||||
0x79 0x6 0x80 0x70 0x0 0xb5 0xff 0x0 0x0 0x1 0x80 0x54 0x0 0x0 0x0 0x0 0x0
|
||||
0x7a 0x0 0x81 0x7 0x2 0xb7 0xff 0x0 0x0 0x6 0x81 0x70 0x0 0xb7 0xff 0x0 0x0
|
||||
0x7b 0x0 0x82 0xa 0x2 0xc2 0xff 0x0 0x0 0x6 0x82 0x70 0x0 0xc2 0xff 0x0 0x0
|
||||
0x7c 0x4 0x83 0x83 0x0 0x15 0x0 0x0 0x0 0x0 0x83 0x6 0x2 0xc6 0xff 0x0 0x0
|
||||
0x7d 0x6 0x83 0x70 0x0 0xc6 0xff 0x0 0x0 0x0 0x84 0x0 0x2 0xc2 0xff 0x0 0x0
|
||||
0x7e 0x6 0x84 0x70 0x0 0xc2 0xff 0x0 0x0 0x0 0x85 0x9 0x2 0xba 0xff 0x0 0x0
|
||||
0x7f 0x6 0x85 0x70 0x0 0xba 0xff 0x0 0x0 0x1 0x85 0x54 0x0 0x0 0x0 0x0 0x0
|
||||
0x80 0x0 0x86 0x8 0x2 0xb6 0xff 0x0 0x0 0x6 0x86 0x70 0x0 0xb6 0xff 0x0 0x0
|
||||
0x81 0x0 0x87 0xfe 0x1 0xaf 0xff 0x0 0x0 0x6 0x87 0x70 0x0 0xaf 0xff 0x0 0x0
|
||||
0x82 0x1 0x88 0x55 0x0 0x0 0x0 0x0 0x0 0x0 0x88 0xfc 0x1 0xae 0xff 0x0 0x0
|
||||
0x83 0x6 0x88 0x70 0x0 0xae 0xff 0x0 0x0 0x0 0x89 0xf3 0x1 0xad 0xff 0x0 0x0
|
||||
0x84 0x6 0x89 0x70 0x0 0xad 0xff 0x0 0x0 0x0 0x8a 0xe4 0x1 0xae 0xff 0x0 0x0
|
||||
0x85 0x6 0x8a 0x70 0x0 0xae 0xff 0x0 0x0 0x1 0x8a 0x56 0x0 0x0 0x0 0x0 0x0
|
||||
0x86 0x0 0x8b 0xd3 0x1 0xad 0xff 0x0 0x0 0x6 0x8b 0x70 0x0 0xad 0xff 0x0 0x0
|
||||
0x87 0x0 0x8c 0xcd 0x1 0xb3 0xff 0x0 0x0 0x6 0x8c 0x70 0x0 0xb3 0xff 0x0 0x0
|
||||
0x88 0x1 0x8d 0x57 0x0 0x0 0x0 0x0 0x0 0x0 0x8d 0xcf 0x1 0xae 0xff 0x0 0x0
|
||||
0x89 0x6 0x8d 0x70 0x0 0xae 0xff 0x0 0x0 0x0 0x8e 0xdf 0x1 0xb0 0xff 0x0 0x0
|
||||
0x8a 0x6 0x8e 0x70 0x0 0xb0 0xff 0x0 0x0 0x0 0x8f 0xec 0x1 0xb9 0xff 0x2 0x0
|
||||
0x8b 0x6 0x8f 0x70 0x0 0xb9 0xff 0x2 0x0 0x0 0x90 0xfa 0x1 0xb5 0xff 0x0 0x0
|
||||
0x8c 0x6 0x90 0x70 0x0 0xb5 0xff 0x0 0x0 0x1 0x90 0x59 0x0 0x0 0x0 0x0 0x0
|
||||
0x8d 0x0 0x91 0x1 0x2 0xcd 0xff 0x0 0x0 0x6 0x91 0x70 0x0 0xcd 0xff 0x0 0x0
|
||||
0x8e 0x0 0x92 0xa 0x2 0xda 0xff 0x0 0x0 0x6 0x92 0x70 0x0 0xda 0xff 0x0 0x0
|
||||
0x8f 0x0 0x93 0xe 0x2 0xd7 0xff 0x0 0x0 0x6 0x93 0x70 0x0 0xd7 0xff 0x0 0x0
|
||||
0x90 0x1 0x94 0x5a 0x0 0x0 0x0 0x0 0x0 0x0 0x94 0x15 0x2 0xda 0xff 0x0 0x0
|
||||
0x91 0x6 0x94 0x70 0x0 0xda 0xff 0x0 0x0 0x0 0x95 0x13 0x2 0xed 0xff 0x0 0x0
|
||||
0x92 0x6 0x95 0x70 0x0 0xed 0xff 0x0 0x0 0x1 0x95 0x5b 0x0 0x0 0x0 0x0 0x0
|
||||
0x93 0x0 0x96 0xe1 0x1 0xf4 0xff 0x0 0x0 0x6 0x96 0x70 0x0 0xf4 0xff 0x0 0x0
|
||||
0x94 0x1 0x96 0x5c 0x0 0x0 0x0 0x0 0x0 0x0 0x97 0x38 0x2 0x4 0x0 0x0 0x0
|
||||
0x95 0x6 0x97 0x70 0x0 0x4 0x0 0x0 0x0 0x0 0x98 0x2f 0x2 0x13 0x0 0x0 0x0
|
||||
0x96 0x6 0x98 0x5d 0x0 0x13 0x0 0x0 0x0 0x1 0x99 0x5d 0x0 0x0 0x0 0x0 0x0
|
||||
0x97 0x0 0x99 0x2a 0x2 0x23 0x0 0x0 0x0 0x6 0x99 0x5d 0x0 0x23 0x0 0x0 0x0
|
||||
0x98 0x0 0x9a 0x28 0x2 0x25 0x0 0x0 0x0 0x6 0x9a 0x5d 0x0 0x25 0x0 0x0 0x0
|
||||
0x99 0x1 0x9a 0x5e 0x0 0x0 0x0 0x0 0x0 0x0 0x9b 0x22 0x2 0x2c 0x0 0x0 0x0
|
||||
0x9a 0x6 0x9b 0x5d 0x0 0x2c 0x0 0x0 0x0 0x1 0x9b 0x5f 0x0 0x0 0x0 0x0 0x0
|
||||
0x9b 0x0 0x9c 0x18 0x2 0x34 0x0 0x0 0x0 0x6 0x9c 0x5d 0x0 0x34 0x0 0x0 0x0
|
||||
0x9c 0x0 0x9d 0xe3 0x1 0x38 0x0 0x0 0x0 0x6 0x9d 0x5d 0x0 0x38 0x0 0x0 0x0
|
||||
0x9d 0x1 0x9e 0x60 0x0 0x0 0x0 0x0 0x0 0x0 0x9e 0x2f 0x2 0x50 0x0 0x0 0x0
|
||||
0x9e 0x6 0x9e 0x5d 0x0 0x50 0x0 0x0 0x0 0x1 0x9f 0x61 0x0 0x0 0x0 0x0 0x0
|
||||
0x9f 0x0 0x9f 0x23 0x2 0x5a 0x0 0x0 0x0 0x6 0x9f 0x5d 0x0 0x5a 0x0 0x0 0x0
|
||||
0xa0 0x0 0xa0 0x1d 0x2 0x6c 0x0 0x0 0x0 0x6 0xa0 0x5d 0x0 0x6c 0x0 0x0 0x0
|
||||
0xa1 0x1 0xa0 0x60 0x0 0x0 0x0 0x0 0x0 0x0 0xa1 0x15 0x2 0x72 0x0 0x0 0x0
|
||||
0xa2 0x6 0xa1 0x5d 0x0 0x72 0x0 0x0 0x0 0x0 0xa2 0xe 0x2 0x7f 0x0 0x0 0x0
|
||||
0xa3 0x6 0xa2 0x5d 0x0 0x7f 0x0 0x0 0x0 0x0 0xa3 0x6 0x2 0x88 0x0 0x0 0x0
|
||||
0xa4 0x6 0xa3 0x5d 0x0 0x88 0x0 0x0 0x0 0x1 0xa4 0x61 0x0 0x0 0x0 0x0 0x0
|
||||
0xa5 0x0 0xa4 0xfd 0x1 0x96 0x0 0x0 0x0 0x6 0xa4 0x5d 0x0 0x96 0x0 0x0 0x0
|
||||
0xa6 0x0 0xa5 0xc2 0x1 0x91 0x0 0x0 0x0 0x6 0xa5 0x5d 0x0 0x91 0x0 0x0 0x0
|
||||
0xa7 0x0 0xa6 0x0 0x2 0xaf 0x0 0x0 0x0 0x6 0xa6 0x5d 0x0 0xaf 0x0 0x0 0x0
|
||||
0xa8 0x0 0xa7 0xe4 0x1 0xb2 0x0 0x0 0x0 0x6 0xa7 0x5d 0x0 0xb2 0x0 0x0 0x0
|
||||
0xa9 0x1 0xa7 0x62 0x0 0x0 0x0 0x0 0x0 0x0 0xa8 0xc9 0x1 0xb3 0x0 0x0 0x0
|
||||
0xaa 0x6 0xa8 0x5d 0x0 0xb3 0x0 0x0 0x0 0x1 0xa9 0x61 0x0 0x0 0x0 0x0 0x0
|
||||
0xab 0x0 0xa9 0xaf 0x1 0xb6 0x0 0x2 0x0 0x6 0xa9 0x5d 0x0 0xb6 0x0 0x2 0x0
|
||||
0xac 0x0 0xaa 0xa2 0x1 0xbc 0x0 0x0 0x0 0x6 0xaa 0x5d 0x0 0xbc 0x0 0x0 0x0
|
||||
0xad 0x0 0xab 0x69 0x1 0xae 0x0 0x0 0x0 0x6 0xab 0x5d 0x0 0xae 0x0 0x0 0x0
|
||||
0xae 0x0 0xac 0x93 0x1 0xcf 0x0 0x0 0x0 0x6 0xac 0x5d 0x0 0xcf 0x0 0x0 0x0
|
||||
0xaf 0x1 0xac 0x62 0x0 0x0 0x0 0x0 0x0 0x0 0xad 0x4c 0x1 0xb8 0x0 0x0 0x0
|
||||
0xb0 0x6 0xad 0x5d 0x0 0xb8 0x0 0x0 0x0 0x1 0xad 0x61 0x0 0x0 0x0 0x0 0x0
|
||||
0xb1 0x0 0xae 0x43 0x1 0xc0 0x0 0x0 0x0 0x6 0xae 0x5d 0x0 0xc0 0x0 0x0 0x0
|
||||
0xb2 0x0 0xaf 0x60 0x1 0xdd 0x0 0x0 0x0 0x6 0xaf 0x5d 0x0 0xdd 0x0 0x0 0x0
|
||||
0xb3 0x0 0xb0 0x48 0x1 0xd5 0x0 0x0 0x0 0x6 0xb0 0x5d 0x0 0xd5 0x0 0x0 0x0
|
||||
0xb4 0x0 0xb1 0x3f 0x1 0xe0 0x0 0x0 0x0 0x6 0xb1 0x5d 0x0 0xe0 0x0 0x0 0x0
|
||||
0xb5 0x0 0xb2 0x1a 0x1 0xd4 0x0 0x0 0x0 0x6 0xb2 0x5d 0x0 0xd4 0x0 0x0 0x0
|
||||
0xb6 0x1 0xb2 0x61 0x0 0x0 0x0 0x0 0x0 0x0 0xb3 0x26 0x1 0xe7 0x0 0x0 0x0
|
||||
0xb7 0x6 0xb3 0x5d 0x0 0xe7 0x0 0x0 0x0 0x0 0xb4 0x47 0x1 0x4 0x1 0x0 0x0
|
||||
0xb8 0x6 0xb4 0x5d 0x0 0x4 0x1 0x0 0x0 0x0 0xb5 0x3c 0x1 0xff 0x0 0x0 0x0
|
||||
0xb9 0x6 0xb5 0x5d 0x0 0xff 0x0 0x0 0x0 0x1 0xb6 0x60 0x0 0x0 0x0 0x0 0x0
|
||||
0xba 0x0 0xb6 0x2f 0x1 0xf8 0x0 0x0 0x0 0x6 0xb6 0x5d 0x0 0xf8 0x0 0x0 0x0
|
||||
0xbb 0x0 0xb7 0x32 0x1 0xf9 0x0 0x0 0x0 0x6 0xb7 0x5d 0x0 0xf9 0x0 0x0 0x0
|
||||
0xbc 0x5 0xb7 0xb7 0x0 0xf9 0x0 0x0 0x0 0x1 0xb7 0x61 0x0 0x0 0x0 0x0 0x0
|
||||
0xbd 0x0 0xb8 0x32 0x1 0xf2 0x0 0x0 0x0 0x6 0xb8 0x5d 0x0 0xf2 0x0 0x0 0x0
|
||||
0xbe 0x0 0xb9 0x25 0x1 0xee 0x0 0x0 0x0 0x6 0xb9 0x5d 0x0 0xee 0x0 0x0 0x0
|
||||
0xbf 0x0 0xba 0x14 0x1 0xe3 0x0 0x0 0x0 0x6 0xba 0x5d 0x0 0xe3 0x0 0x0 0x0
|
||||
0xc0 0x1 0xbb 0x60 0x0 0x0 0x0 0x0 0x0 0x0 0xbb 0x0 0x1 0xd3 0x0 0x0 0x0
|
||||
0xc1 0x6 0xbb 0x5d 0x0 0xd3 0x0 0x0 0x0 0x0 0xbc 0xe4 0x0 0xbe 0x0 0x0 0x0
|
||||
0xc2 0x6 0xbc 0x5d 0x0 0xbe 0x0 0x0 0x0 0x1 0xbc 0x61 0x0 0x0 0x0 0x0 0x0
|
||||
0xc3 0x0 0xbd 0xc7 0x0 0xaa 0x0 0x0 0x0 0x6 0xbd 0x5d 0x0 0xaa 0x0 0x0 0x0
|
||||
0xc4 0x1 0xbd 0x62 0x0 0x0 0x0 0x0 0x0 0x0 0xbe 0xa0 0x0 0x8c 0x0 0x0 0x0
|
||||
0xc5 0x6 0xbe 0x5d 0x0 0x8c 0x0 0x0 0x0 0x0 0xbf 0xbc 0x0 0xa3 0x0 0x0 0x0
|
||||
0xc6 0x6 0xbf 0x5d 0x0 0xa3 0x0 0x0 0x0 0x1 0xc0 0x63 0x0 0x0 0x0 0x0 0x0
|
||||
0xc7 0x0 0xc0 0xbf 0x0 0xa4 0x0 0x0 0x0 0x6 0xc0 0x5d 0x0 0xa4 0x0 0x0 0x0
|
||||
0xc8 0x0 0xc1 0xbe 0x0 0x9f 0x0 0x0 0x0 0x6 0xc1 0x5d 0x0 0x9f 0x0 0x0 0x0
|
||||
0xc9 0x0 0xc2 0xb4 0x0 0x93 0x0 0x0 0x0 0x6 0xc2 0x5d 0x0 0x93 0x0 0x0 0x0
|
||||
0xca 0x1 0xc2 0x5c 0x0 0x0 0x0 0x0 0x0 0x0 0xc3 0xc6 0x0 0xa1 0x0 0x0 0x0
|
||||
0xcb 0x6 0xc3 0x5d 0x0 0xa1 0x0 0x0 0x0 0x0 0xc4 0xd0 0x0 0xa6 0x0 0x0 0x0
|
||||
0xcc 0x6 0xc4 0x5d 0x0 0xa6 0x0 0x0 0x0 0x1 0xc4 0x5b 0x0 0x0 0x0 0x0 0x0
|
||||
0xcd 0x0 0xc5 0xe8 0x0 0xb9 0x0 0x0 0x0 0x6 0xc5 0x5d 0x0 0xb9 0x0 0x0 0x0
|
||||
0xce 0x1 0xc6 0x5a 0x0 0x0 0x0 0x0 0x0 0x0 0xc6 0xe7 0x0 0xb7 0x0 0x0 0x0
|
||||
0xcf 0x6 0xc6 0x5d 0x0 0xb7 0x0 0x0 0x0 0x1 0xc7 0x5f 0x0 0x0 0x0 0x0 0x0
|
||||
0xd0 0x0 0xc7 0xe9 0x0 0xba 0x0 0x0 0x0 0x6 0xc7 0x5d 0x0 0xba 0x0 0x0 0x0
|
||||
0xd1 0x0 0xc8 0xf5 0x0 0xc6 0x0 0x0 0x0 0x6 0xc8 0x5d 0x0 0xc6 0x0 0x0 0x0
|
||||
0xd2 0x0 0xc9 0x2 0x1 0xcf 0x0 0x0 0x0 0x6 0xc9 0x5d 0x0 0xcf 0x0 0x0 0x0
|
||||
0xd3 0x1 0xc9 0x5e 0x0 0x0 0x0 0x0 0x0 0x0 0xca 0x13 0x1 0xdd 0x0 0x0 0x0
|
||||
0xd4 0x6 0xca 0x5d 0x0 0xdd 0x0 0x0 0x0 0x1 0xcb 0x5d 0x0 0x0 0x0 0x0 0x0
|
||||
0xd5 0x0 0xcb 0x18 0x1 0xdf 0x0 0x0 0x0 0x6 0xcb 0x5d 0x0 0xdf 0x0 0x0 0x0
|
||||
0xd6 0x1 0xcc 0x56 0x0 0x0 0x0 0x0 0x0 0x0 0xcc 0x27 0x1 0xea 0x0 0x0 0x0
|
||||
0xd7 0x6 0xcc 0x5d 0x0 0xea 0x0 0x0 0x0 0x0 0xcd 0x2a 0x1 0xed 0x0 0x0 0x0
|
||||
0xd8 0x6 0xcd 0x5d 0x0 0xed 0x0 0x0 0x0 0x0 0xce 0x35 0x1 0xf3 0x0 0x0 0x0
|
||||
0xd9 0x6 0xce 0x5d 0x0 0xf3 0x0 0x0 0x0 0x1 0xce 0x55 0x0 0x0 0x0 0x0 0x0
|
||||
0xda 0x0 0xcf 0x44 0x1 0xfe 0x0 0x0 0x0 0x6 0xcf 0x5d 0x0 0xfe 0x0 0x0 0x0
|
||||
0xdb 0x1 0xcf 0x44 0x0 0x0 0x0 0x0 0x0 0x0 0xd0 0x4f 0x1 0x9 0x1 0x0 0x0
|
||||
0xdc 0x6 0xd0 0x5d 0x0 0x9 0x1 0x0 0x0 0x1 0xd1 0x4a 0x0 0x0 0x0 0x0 0x0
|
||||
0xdd 0x0 0xd1 0x37 0x1 0xf2 0x0 0x0 0x0 0x6 0xd1 0x5d 0x0 0xf2 0x0 0x0 0x0
|
||||
0xde 0x0 0xd2 0x71 0x1 0x1e 0x1 0x0 0x0 0x6 0xd2 0x5d 0x0 0x1e 0x1 0x0 0x0
|
||||
0xdf 0x0 0xd3 0x42 0x1 0xf8 0x0 0xfe 0xff 0x6 0xd3 0x5d 0x0 0xf8 0x0 0xfe 0xff
|
||||
0xe0 0x1 0xd3 0x49 0x0 0x0 0x0 0x0 0x0 0x0 0xd4 0x59 0x1 0x8 0x1 0x0 0x0
|
||||
0xe1 0x6 0xd4 0x5d 0x0 0x8 0x1 0x0 0x0 0x1 0xd4 0x48 0x0 0x0 0x0 0x0 0x0
|
||||
0xe2 0x0 0xd5 0x75 0x1 0x22 0x1 0x0 0x0 0x6 0xd5 0x5d 0x0 0x22 0x1 0x0 0x0
|
||||
0xe3 0x1 0xd5 0x47 0x0 0x0 0x0 0x0 0x0 0x0 0xd6 0x64 0x1 0x10 0x1 0x0 0x0
|
||||
0xe4 0x6 0xd6 0x5d 0x0 0x10 0x1 0x0 0x0 0x0 0xd7 0x38 0x1 0xec 0x0 0xff 0xff
|
||||
0xe5 0x6 0xd7 0x5d 0x0 0xec 0x0 0xff 0xff 0x1 0xd8 0x48 0x0 0x0 0x0 0x0 0x0
|
||||
0xe6 0x0 0xd8 0x66 0x1 0x14 0x1 0xff 0xff 0x6 0xd8 0x5d 0x0 0x14 0x1 0xff 0xff
|
||||
0xe7 0x0 0xd9 0x58 0x1 0xc 0x1 0x0 0x0 0x6 0xd9 0x5d 0x0 0xc 0x1 0x0 0x0
|
||||
0xe8 0x1 0xd9 0x49 0x0 0x0 0x0 0x0 0x0 0x0 0xda 0x3b 0x1 0xf6 0x0 0x0 0x0
|
||||
0xe9 0x6 0xda 0x5d 0x0 0xf6 0x0 0x0 0x0 0x0 0xdb 0x53 0x1 0xa 0x1 0x0 0x0
|
||||
0xea 0x6 0xdb 0x5d 0x0 0xa 0x1 0x0 0x0 0x0 0xdc 0x38 0x1 0xf5 0x0 0x0 0x0
|
||||
0xeb 0x6 0xdc 0x5d 0x0 0xf5 0x0 0x0 0x0 0x4 0xdd 0x5a 0x0 0x15 0x0 0x0 0x0
|
||||
0xec 0x1 0xdd 0x4a 0x0 0x0 0x0 0x0 0x0 0x0 0xdd 0x7 0x1 0xd5 0x0 0x0 0x0
|
||||
0xed 0x6 0xdd 0x5d 0x0 0xd5 0x0 0x0 0x0 0x0 0xde 0x11 0x1 0xdb 0x0 0xfe 0xff
|
||||
0xee 0x6 0xde 0x5d 0x0 0xdb 0x0 0xfe 0xff 0x1 0xde 0x4b 0x0 0x0 0x0 0x0 0x0
|
||||
0xef 0x0 0xdf 0x7 0x1 0xd1 0x0 0x0 0x0 0x6 0xdf 0x5d 0x0 0xd1 0x0 0x0 0x0
|
||||
0xf0 0x1 0xdf 0x4c 0x0 0x0 0x0 0x0 0x0 0x0 0xe0 0xc 0x1 0xd4 0x0 0x0 0x0
|
||||
0xf1 0x6 0xe0 0x5d 0x0 0xd4 0x0 0x0 0x0 0x0 0xe1 0xd6 0x0 0xa9 0x0 0x0 0x0
|
||||
0xf2 0x6 0xe1 0x5d 0x0 0xa9 0x0 0x0 0x0 0x1 0xe2 0x4d 0x0 0x0 0x0 0x0 0x0
|
||||
0xf3 0x0 0xe2 0xdb 0x0 0xac 0x0 0x0 0x0 0x6 0xe2 0x5d 0x0 0xac 0x0 0x0 0x0
|
||||
0xf4 0x0 0xe4 0x2d 0x1 0xad 0x0 0x0 0x0 0x6 0xe4 0x5d 0x0 0xad 0x0 0x0 0x0
|
||||
0xf5 0x1 0xe4 0x4e 0x0 0x0 0x0 0x0 0x0 0x0 0xe6 0xf3 0x0 0x8b 0x0 0x0 0x0
|
||||
0xf6 0x6 0xe6 0x5d 0x0 0x8b 0x0 0x0 0x0 0x1 0xe6 0x4f 0x0 0x0 0x0 0x0 0x0
|
||||
0xf7 0x1 0xe8 0x51 0x0 0x0 0x0 0x0 0x0 0x1 0xeb 0x52 0x0 0x0 0x0 0x0 0x0
|
||||
0xf8 0x1 0xee 0x53 0x0 0x0 0x0 0x0 0x0 0x0 0xf0 0xf7 0x0 0x87 0x0 0x0 0x0
|
||||
0xf9 0x6 0xf0 0x74 0x0 0x87 0x0 0x0 0x0 0x1 0xf0 0x54 0x0 0x0 0x0 0x0 0x0
|
||||
0xfa 0x0 0xf2 0xd8 0x0 0x7f 0x0 0x0 0x0 0x6 0xf2 0x8c 0x0 0x7f 0x0 0x0 0x0
|
||||
0xfb 0x1 0xf2 0x55 0x0 0x0 0x0 0x0 0x0 0x0 0xf4 0xcb 0x0 0x7c 0x0 0x0 0x0
|
||||
0xfc 0x6 0xf4 0x8c 0x0 0x7c 0x0 0x0 0x0 0x1 0xf5 0x56 0x0 0x0 0x0 0x0 0x0
|
||||
0xfd 0x0 0xf6 0x1c 0x1 0x75 0x0 0x0 0x0 0x6 0xf6 0xa1 0x0 0x75 0x0 0x0 0x0
|
||||
0xfe 0x1 0xf6 0x58 0x0 0x0 0x0 0x0 0x0 0x1 0xf7 0x57 0x0 0x0 0x0 0x0 0x0
|
||||
0xff 0x0 0xf8 0x67 0x1 0x3a 0x0 0x2 0x0 0x6 0xf8 0xa1 0x0 0x3a 0x0 0x2 0x0
|
||||
0x0 0x0 0xf9 0x24 0x1 0x2 0x0 0x0 0x0 0x6 0xf9 0xa1 0x0 0x2 0x0 0x0 0x0
|
||||
0x1 0x1 0xfa 0x58 0x0 0x0 0x0 0x0 0x0 0x0 0xfa 0x19 0x1 0xd6 0xff 0x0 0x0
|
||||
0x2 0x6 0xfa 0xa1 0x0 0xd6 0xff 0x0 0x0 0x0 0xfb 0x1e 0x1 0xb9 0xff 0x0 0x0
|
||||
0x3 0x6 0xfb 0xa1 0x0 0xb9 0xff 0x0 0x0 0x0 0xfc 0x22 0x1 0xa6 0xff 0x0 0x0
|
||||
0x4 0x6 0xfc 0xa1 0x0 0xa6 0xff 0x0 0x0 0x1 0xfc 0x59 0x0 0x0 0x0 0x0 0x0
|
||||
0x5 0x0 0xfd 0x68 0x1 0x47 0xff 0x0 0x0 0x6 0xfd 0xa1 0x0 0x47 0xff 0x0 0x0
|
||||
0x6 0x0 0xfe 0x3e 0x1 0x58 0xff 0x0 0x0 0x6 0xfe 0xa1 0x0 0x58 0xff 0x0 0x0
|
||||
0x7 0x0 0xff 0x32 0x1 0x5f 0xff 0x0 0x0 0x6 0xff 0xa1 0x0 0x5f 0xff 0x0 0x0
|
||||
0x8 0x0 0x0 0x19 0x1 0x67 0xff 0x0 0x0 0x6 0x0 0xa1 0x0 0x67 0xff 0x0 0x0
|
||||
0x9 0x0 0x1 0xff 0x0 0x7f 0xff 0x0 0x0 0x6 0x1 0xa1 0x0 0x7f 0xff 0x0 0x0
|
||||
0xa 0x1 0x1 0x5a 0x0 0x0 0x0 0x0 0x0 0x0 0x2 0xf5 0x0 0x92 0xff 0x0 0x0
|
||||
0xb 0x6 0x2 0xa1 0x0 0x92 0xff 0x0 0x0 0x1 0x3 0x57 0x0 0x0 0x0 0x0 0x0
|
||||
0xc 0x0 0x4 0xe1 0x0 0x9f 0xff 0xfe 0xff 0x6 0x4 0xa1 0x0 0x9f 0xff 0xfe 0xff
|
||||
0xd 0x1 0x5 0x58 0x0 0x0 0x0 0x0 0x0 0x1 0xb 0x59 0x0 0x0 0x0 0x0 0x0
|
||||
0xe 0x0 0xc 0xa3 0x0 0x91 0xff 0x0 0x0 0x6 0xc 0xb8 0x0 0x91 0xff 0x0 0x0
|
||||
0xf 0x1 0xd 0x5a 0x0 0x0 0x0 0x0 0x0 0x1 0xe 0x60 0x0 0x0 0x0 0x0 0x0
|
||||
0x10 0x1 0x10 0x61 0x0 0x0 0x0 0x0 0x0 0x1 0x13 0x68 0x0 0x0 0x0 0x0 0x0
|
||||
0x11 0x1 0x14 0x6d 0x0 0x0 0x0 0x0 0x0 0x1 0x17 0x6c 0x0 0x0 0x0 0x0 0x0
|
||||
0x12 0x1 0x18 0x65 0x0 0x0 0x0 0x0 0x0 0x1 0x19 0x6a 0x0 0x0 0x0 0x0 0x0
|
||||
0x13 0x0 0x1b 0xe5 0x0 0xa0 0xff 0x0 0x0 0x6 0x1b 0x54 0x1 0xa0 0xff 0x0 0x0
|
||||
0x14 0x1 0x1c 0x6c 0x0 0x0 0x0 0x0 0x0 0x0 0x1d 0x12 0x1 0xa6 0xff 0x0 0x0
|
||||
0x15 0x6 0x1d 0x54 0x1 0xa6 0xff 0x0 0x0 0x1 0x1d 0x6d 0x0 0x0 0x0 0x0 0x0
|
||||
0x16 0x0 0x1e 0x10 0x1 0xaa 0xff 0x0 0x0 0x6 0x1e 0x6b 0x1 0xaa 0xff 0x0 0x0
|
||||
0x17 0x1 0x1e 0x69 0x0 0x0 0x0 0x0 0x0 0x0 0x1f 0x23 0x1 0xb2 0xff 0x0 0x0
|
||||
0x18 0x6 0x1f 0x6b 0x1 0xb2 0xff 0x0 0x0 0x0 0x20 0x46 0x1 0xac 0xff 0x0 0x0
|
||||
0x19 0x6 0x20 0x6b 0x1 0xac 0xff 0x0 0x0 0x1 0x21 0x6b 0x0 0x0 0x0 0x0 0x0
|
||||
0x1a 0x0 0x21 0x66 0x1 0xa7 0xff 0x0 0x0 0x6 0x21 0x4c 0x1 0xa7 0xff 0x0 0x0
|
||||
0x1b 0x1 0x22 0x6e 0x0 0x0 0x0 0x0 0x0 0x0 0x22 0x8f 0x1 0x9f 0xff 0x0 0x0
|
||||
0x1c 0x6 0x22 0x36 0x1 0x9f 0xff 0x0 0x0 0x0 0x23 0xdf 0x1 0x8b 0xff 0x0 0x0
|
||||
0x1d 0x6 0x23 0x36 0x1 0x8b 0xff 0x0 0x0 0x1 0x23 0x70 0x0 0x0 0x0 0x0 0x0
|
||||
0x1e 0x0 0x24 0x92 0x1 0x9d 0xff 0xff 0xff 0x6 0x24 0x19 0x1 0x9d 0xff 0xff 0xff
|
||||
0x1f 0x0 0x25 0x82 0x1 0xa1 0xff 0x0 0x0 0x6 0x25 0x2 0x1 0xa1 0xff 0x0 0x0
|
||||
0x20 0x1 0x25 0x6a 0x0 0x0 0x0 0x0 0x0 0x0 0x26 0x2a 0x1 0xb7 0xff 0x0 0x0
|
||||
0x21 0x6 0x26 0xef 0x0 0xb7 0xff 0x0 0x0 0x1 0x27 0x67 0x0 0x0 0x0 0x0 0x0
|
||||
0x22 0x0 0x27 0x6 0x1 0xbf 0xff 0x0 0x0 0x6 0x27 0xef 0x0 0xbf 0xff 0x0 0x0
|
||||
0x23 0x1 0x28 0x6e 0x0 0x0 0x0 0x0 0x0 0x0 0x29 0x1b 0x1 0xb9 0xff 0x0 0x0
|
||||
0x24 0x6 0x29 0xd8 0x0 0xb9 0xff 0x0 0x0 0x1 0x2a 0x74 0x0 0x0 0x0 0x0 0x0
|
||||
0x25 0x1 0x2b 0x70 0x0 0x0 0x0 0x0 0x0 0x0 0x2c 0xf9 0x0 0xbc 0xff 0x0 0x0
|
||||
0x26 0x6 0x2c 0xd8 0x0 0xbc 0xff 0x0 0x0 0x1 0x2d 0x72 0x0 0x0 0x0 0x0 0x0
|
||||
0x27 0x1 0x2f 0x6b 0x0 0x0 0x0 0x0 0x0 0x0 0x30 0xa5 0x0 0x86 0xff 0x0 0x0
|
||||
0x28 0x6 0x30 0xeb 0x0 0x86 0xff 0x0 0x0 0x1 0x30 0x64 0x0 0x0 0x0 0x0 0x0
|
||||
0x29 0x1 0x32 0x63 0x0 0x0 0x0 0x0 0x0 0x1 0x34 0x5c 0x0 0x0 0x0 0x0 0x0
|
||||
0x2a 0x1 0x35 0x57 0x0 0x0 0x0 0x0 0x0 0x1 0x36 0x54 0x0 0x0 0x0 0x0 0x0
|
||||
0x2b 0x0 0x38 0x78 0x0 0x7b 0xff 0x0 0x0 0x6 0x38 0x30 0x1 0x7b 0xff 0x0 0x0
|
||||
0x2c 0x1 0x39 0x4d 0x0 0x0 0x0 0x0 0x0 0x1 0x3a 0x4c 0x0 0x0 0x0 0x0 0x0
|
||||
0x2d 0x1 0x3b 0x45 0x0 0x0 0x0 0x0 0x0 0x1 0x3e 0x47 0x0 0x0 0x0 0x0 0x0
|
||||
0x2e 0x0 0x3f 0xbe 0x0 0xbb 0xff 0x0 0x0 0x6 0x3f 0x64 0x1 0xbb 0xff 0x0 0x0
|
||||
0x2f 0x1 0x3f 0x46 0x0 0x0 0x0 0x0 0x0 0x1 0x40 0x45 0x0 0x0 0x0 0x0 0x0
|
||||
0x30 0x0 0x41 0xd4 0x0 0xc4 0xff 0x0 0x0 0x6 0x41 0x81 0x1 0xc4 0xff 0x0 0x0
|
||||
0x31 0x1 0x43 0x44 0x0 0x0 0x0 0x0 0x0 0x0 0x43 0x37 0x1 0xb0 0xff 0x0 0x0
|
||||
0x32 0x6 0x43 0x97 0x1 0xb0 0xff 0x0 0x0 0x1 0x44 0x46 0x0 0x0 0x0 0x0 0x0
|
||||
0x33 0x0 0x44 0x39 0x1 0xab 0xff 0x0 0x0 0x6 0x44 0x97 0x1 0xab 0xff 0x0 0x0
|
||||
0x34 0x0 0x45 0x53 0x1 0x9f 0xff 0x0 0x0 0x6 0x45 0x97 0x1 0x9f 0xff 0x0 0x0
|
||||
0x35 0x1 0x45 0x48 0x0 0x0 0x0 0x0 0x0 0x0 0x46 0x74 0x1 0x89 0xff 0x0 0x0
|
||||
0x36 0x6 0x46 0x7b 0x1 0x89 0xff 0x0 0x0 0x0 0x47 0x6c 0x1 0x90 0xff 0x0 0x0
|
||||
0x37 0x6 0x47 0x5c 0x1 0x90 0xff 0x0 0x0 0x1 0x48 0x47 0x0 0x0 0x0 0x0 0x0
|
||||
0x38 0x0 0x48 0x4e 0x1 0x99 0xff 0x0 0x0 0x6 0x48 0x3f 0x1 0x99 0xff 0x0 0x0
|
||||
0x39 0x0 0x49 0x6d 0x1 0x95 0xff 0x0 0x0 0x6 0x49 0x25 0x1 0x95 0xff 0x0 0x0
|
||||
0x3a 0x1 0x4a 0x48 0x0 0x0 0x0 0x0 0x0 0x1 0x4c 0x49 0x0 0x0 0x0 0x0 0x0
|
||||
0x3b 0x1 0x4e 0x4a 0x0 0x0 0x0 0x0 0x0 0x0 0x4e 0x4a 0x6 0xc3 0xfd 0x0 0x0
|
||||
0x3c 0x6 0x4e 0xdf 0x0 0xc3 0xfd 0x0 0x0 0x1 0x4f 0x4b 0x0 0x0 0x0 0x0 0x0
|
||||
0x3d 0x0 0x4f 0x62 0x4 0x58 0xfe 0x0 0x0 0x6 0x4f 0xdf 0x0 0x58 0xfe 0x0 0x0
|
||||
0x3e 0x0 0x50 0x44 0x3 0xaa 0xfe 0x0 0x0 0x6 0x50 0xdf 0x0 0xaa 0xfe 0x0 0x0
|
||||
0x3f 0x0 0x51 0x95 0x2 0xe2 0xfe 0x0 0x0 0x6 0x51 0xc1 0x0 0xe2 0xfe 0x0 0x0
|
||||
0x40 0x1 0x51 0x4c 0x0 0x0 0x0 0x0 0x0 0x0 0x52 0x24 0x2 0x8 0xff 0x0 0x0
|
||||
0x41 0x6 0x52 0xc1 0x0 0x8 0xff 0x0 0x0 0x1 0x52 0x4d 0x0 0x0 0x0 0x0 0x0
|
||||
0x42 0x0 0x53 0xcd 0x1 0x2c 0xff 0x0 0x0 0x6 0x53 0xa4 0x0 0x2c 0xff 0x0 0x0
|
||||
0x43 0x0 0x54 0x96 0x1 0x4b 0xff 0x0 0x0 0x6 0x54 0xa4 0x0 0x4b 0xff 0x0 0x0
|
||||
0x44 0x0 0x55 0x66 0x1 0x5d 0xff 0x0 0x0 0x6 0x55 0xa4 0x0 0x5d 0xff 0x0 0x0
|
||||
0x45 0x0 0x56 0x44 0x1 0x6e 0xff 0x0 0x0 0x6 0x56 0xa4 0x0 0x6e 0xff 0x0 0x0
|
||||
0x46 0x0 0x57 0x1c 0x1 0x7b 0xff 0x1 0x0 0x6 0x57 0x90 0x0 0x7b 0xff 0x1 0x0
|
||||
0x47 0x1 0x57 0x4e 0x0 0x0 0x0 0x0 0x0 0x0 0x58 0xfc 0x0 0x8a 0xff 0x0 0x0
|
||||
0x48 0x6 0x58 0x90 0x0 0x8a 0xff 0x0 0x0 0x1 0x59 0x4f 0x0 0x0 0x0 0x0 0x0
|
||||
0x49 0x0 0x59 0xe2 0x0 0x97 0xff 0x0 0x0 0x6 0x59 0x90 0x0 0x97 0xff 0x0 0x0
|
||||
0x4a 0x0 0x5a 0xd8 0x0 0x9d 0xff 0x0 0x0 0x6 0x5a 0x90 0x0 0x9d 0xff 0x0 0x0
|
||||
0x4b 0x0 0x5b 0xc6 0x0 0xa5 0xff 0x0 0x0 0x6 0x5b 0x90 0x0 0xa5 0xff 0x0 0x0
|
||||
0x4c 0x1 0x5b 0x50 0x0 0x0 0x0 0x0 0x0 0x1 0x5c 0x57 0x0 0x0 0x0 0x0 0x0
|
||||
0x4d 0x0 0x5d 0xef 0x0 0x92 0xff 0x0 0x0 0x6 0x5d 0x90 0x0 0x92 0xff 0x0 0x0
|
||||
0x4e 0x1 0x5d 0x50 0x0 0x0 0x0 0x0 0x0 0x1 0x60 0x4f 0x0 0x0 0x0 0x0 0x0
|
||||
0x4f 0x0 0x61 0xdb 0x0 0x9d 0xff 0x0 0x0 0x6 0x61 0x90 0x0 0x9d 0xff 0x0 0x0
|
||||
0x50 0x1 0x61 0x4e 0x0 0x0 0x0 0x0 0x0 0x1 0x62 0x48 0x0 0x0 0x0 0x0 0x0
|
||||
0x51 0x1 0x65 0x41 0x0 0x0 0x0 0x0 0x0 0x1 0x66 0x43 0x0 0x0 0x0 0x0 0x0
|
||||
0x52 0x1 0x67 0x44 0x0 0x0 0x0 0x0 0x0 0x1 0x6a 0x4b 0x0 0x0 0x0 0x0 0x0
|
||||
0x53 0x1 0x6b 0x4c 0x0 0x0 0x0 0x0 0x0 0x1 0x6c 0x47 0x0 0x0 0x0 0x0 0x0
|
||||
0x54 0x1 0x6e 0x4e 0x0 0x0 0x0 0x0 0x0 0x1 0x70 0x51 0x0 0x0 0x0 0x0 0x0
|
||||
0x55 0x1 0x71 0x52 0x0 0x0 0x0 0x0 0x0 0x0 0x72 0xc5 0x0 0x99 0xff 0x1 0x0
|
||||
0x56 0x6 0x72 0x13 0x1 0x99 0xff 0x1 0x0 0x0 0x74 0xec 0x0 0xc2 0xff 0x1 0x0
|
||||
0x57 0x6 0x74 0x2f 0x1 0xc2 0xff 0x1 0x0 0x1 0x74 0x50 0x0 0x0 0x0 0x0 0x0
|
||||
0x58 0x1 0x76 0x52 0x0 0x0 0x0 0x0 0x0 0x0 0x76 0x2d 0x1 0x2f 0x0 0x0 0x0
|
||||
0x59 0x6 0x76 0x44 0x1 0x2f 0x0 0x0 0x0 0x0 0x77 0xeb 0x0 0x65 0x0 0x0 0x0
|
||||
0x5a 0x6 0x77 0x44 0x1 0x65 0x0 0x0 0x0 0x0 0x78 0xe9 0x0 0x67 0x0 0x0 0x0
|
||||
0x5b 0x6 0x78 0x44 0x1 0x67 0x0 0x0 0x0 0x1 0x78 0x51 0x0 0x0 0x0 0x0 0x0
|
||||
0x5c 0x0 0x79 0xdb 0x0 0xae 0x0 0x0 0x0 0x6 0x79 0x44 0x1 0xae 0x0 0x0 0x0
|
||||
0x5d 0x1 0x79 0x50 0x0 0x0 0x0 0x0 0x0 0x0 0x7a 0xe5 0x0 0xf4 0x0 0x2 0x0
|
||||
0x5e 0x6 0x7a 0x26 0x1 0xf4 0x0 0x2 0x0 0x0 0x7b 0xe3 0x0 0xfc 0x0 0x0 0x0
|
||||
0x5f 0x6 0x7b 0x13 0x1 0xfc 0x0 0x0 0x0 0x0 0x7c 0xc2 0x0 0xd 0x1 0x0 0x0
|
||||
0x60 0x6 0x7c 0xff 0x0 0xd 0x1 0x0 0x0 0x0 0x7d 0xc2 0x0 0x4c 0x1 0x0 0x0
|
||||
0x61 0x6 0x7d 0xff 0x0 0x4c 0x1 0x0 0x0 0x1 0x7d 0x4f 0x0 0x0 0x0 0x0 0x0
|
||||
0x62 0x0 0x7e 0x96 0x0 0x43 0x1 0x0 0x0 0x6 0x7e 0xe7 0x0 0x43 0x1 0x0 0x0
|
||||
0x63 0x1 0x7e 0x52 0x0 0x0 0x0 0x0 0x0 0x0 0x7f 0x48 0x0 0x5d 0x1 0x0 0x0
|
||||
0x64 0x6 0x7f 0xd4 0x0 0x5d 0x1 0x0 0x0 0x1 0x7f 0x55 0x0 0x0 0x0 0x0 0x0
|
||||
0x65 0x0 0x80 0xe8 0xff 0x63 0x1 0x0 0x0 0x6 0x80 0xd4 0x0 0x63 0x1 0x0 0x0
|
||||
0x66 0x0 0x81 0x9a 0xff 0x7c 0x1 0x0 0x0 0x6 0x81 0xb5 0x0 0x7c 0x1 0x0 0x0
|
||||
0x67 0x1 0x82 0x56 0x0 0x0 0x0 0x0 0x0 0x0 0x82 0x69 0xff 0x60 0x1 0x0 0x0
|
||||
0x68 0x6 0x82 0xb5 0x0 0x60 0x1 0x0 0x0 0x0 0x83 0x67 0xff 0x2b 0x1 0x0 0x0
|
||||
0x69 0x6 0x83 0xb5 0x0 0x2b 0x1 0x0 0x0 0x1 0x83 0x57 0x0 0x0 0x0 0x0 0x0
|
||||
0x6a 0x0 0x84 0x5f 0xff 0x1f 0x1 0x0 0x0 0x6 0x84 0x9f 0x0 0x1f 0x1 0x0 0x0
|
||||
0x6b 0x1 0x84 0x53 0x0 0x0 0x0 0x0 0x0 0x0 0x85 0x62 0xff 0xf 0x1 0x0 0x0
|
||||
0x6c 0x6 0x85 0x9f 0x0 0xf 0x1 0x0 0x0 0x0 0x86 0x6a 0xff 0xf8 0x0 0x0 0x0
|
||||
0x6d 0x6 0x86 0x9f 0x0 0xf8 0x0 0x0 0x0 0x1 0x87 0x51 0x0 0x0 0x0 0x0 0x0
|
||||
0x6e 0x0 0x87 0xd6 0xfe 0xca 0x1 0x0 0x0 0x6 0x87 0x9f 0x0 0xca 0x1 0x0 0x0
|
||||
0x6f 0x1 0x88 0x4b 0x0 0x0 0x0 0x0 0x0 0x0 0x88 0xba 0xff 0x7d 0x0 0x0 0x0
|
||||
0x70 0x6 0x88 0x8c 0x0 0x7d 0x0 0x0 0x0 0x0 0x89 0xc1 0xff 0x96 0x0 0x0 0x0
|
||||
0x71 0x6 0x89 0x8c 0x0 0x96 0x0 0x0 0x0 0x1 0x89 0x4c 0x0 0x0 0x0 0x0 0x0
|
||||
0x72 0x0 0x8a 0xc5 0xff 0xb1 0x0 0x0 0x0 0x6 0x8a 0x8c 0x0 0xb1 0x0 0x0 0x0
|
||||
0x73 0x0 0x8b 0xcf 0xff 0xbf 0x0 0x0 0x0 0x6 0x8b 0x8c 0x0 0xbf 0x0 0x0 0x0
|
||||
0x74 0x0 0x8c 0xda 0xff 0xce 0x0 0x0 0x0 0x6 0x8c 0x8c 0x0 0xce 0x0 0x0 0x0
|
||||
0x75 0x1 0x8d 0x47 0x0 0x0 0x0 0x0 0x0 0x0 0x8d 0xd6 0xff 0xd0 0x0 0x0 0x0
|
||||
0x76 0x6 0x8d 0x8c 0x0 0xd0 0x0 0x0 0x0 0x0 0x8e 0xd8 0xff 0xd6 0x0 0x0 0x0
|
||||
0x77 0x6 0x8e 0x8c 0x0 0xd6 0x0 0x0 0x0 0x1 0x8e 0x43 0x0 0x0 0x0 0x0 0x0
|
||||
0x78 0x0 0x8f 0xe7 0xff 0xe3 0x0 0x0 0x0 0x6 0x8f 0x8c 0x0 0xe3 0x0 0x0 0x0
|
||||
0x79 0x0 0x90 0xfe 0xff 0xee 0x0 0x1 0x0 0x6 0x90 0x8c 0x0 0xee 0x0 0x1 0x0
|
||||
0x7a 0x1 0x90 0x41 0x0 0x0 0x0 0x0 0x0 0x0 0x91 0x10 0x0 0xf9 0x0 0x0 0x0
|
||||
0x7b 0x6 0x91 0x8c 0x0 0xf9 0x0 0x0 0x0 0x1 0x92 0x3f 0x0 0x0 0x0 0x0 0x0
|
||||
0x7c 0x0 0x92 0x17 0x0 0xe 0x1 0x0 0x0 0x6 0x92 0x8c 0x0 0xe 0x1 0x0 0x0
|
||||
0x7d 0x1 0x93 0x45 0x0 0x0 0x0 0x0 0x0 0x0 0x93 0x1b 0x0 0x22 0x1 0x1 0x0
|
||||
0x7e 0x6 0x93 0x8c 0x0 0x22 0x1 0x1 0x0 0x0 0x94 0x24 0x0 0x54 0x1 0x0 0x0
|
||||
0x7f 0x6 0x94 0x8c 0x0 0x54 0x1 0x0 0x0 0x0 0x95 0x1c 0x0 0x33 0x1 0x0 0x0
|
||||
0x80 0x6 0x95 0x8c 0x0 0x33 0x1 0x0 0x0 0x1 0x95 0x48 0x0 0x0 0x0 0x0 0x0
|
||||
0x81 0x0 0x96 0x29 0x0 0x49 0x1 0x0 0x0 0x6 0x96 0x8c 0x0 0x49 0x1 0x0 0x0
|
||||
0x82 0x1 0x96 0x47 0x0 0x0 0x0 0x0 0x0 0x0 0x97 0x2e 0x0 0x56 0x1 0x0 0x0
|
||||
0x83 0x6 0x97 0x8c 0x0 0x56 0x1 0x0 0x0 0x1 0x98 0x4e 0x0 0x0 0x0 0x0 0x0
|
||||
0x84 0x0 0x98 0x2e 0x0 0x5f 0x1 0x0 0x0 0x6 0x98 0x77 0x0 0x5f 0x1 0x0 0x0
|
||||
0x85 0x0 0x99 0x2a 0x0 0x86 0x1 0x0 0x0 0x6 0x99 0x77 0x0 0x86 0x1 0x0 0x0
|
||||
0x86 0x4 0x99 0xbc 0x0 0x86 0x1 0x0 0x0 0x0 0x9a 0x21 0x0 0x5c 0x1 0x0 0x0
|
||||
0x87 0x6 0x9a 0x77 0x0 0x5c 0x1 0x0 0x0 0x1 0x9a 0x4f 0x0 0x0 0x0 0x0 0x0
|
||||
0x88 0x0 0x9b 0x26 0x0 0x6e 0x1 0x0 0x0 0x6 0x9b 0x77 0x0 0x6e 0x1 0x0 0x0
|
||||
0x89 0x1 0x9b 0x50 0x0 0x0 0x0 0x0 0x0 0x0 0x9c 0x2f 0x0 0x7d 0x1 0x0 0x0
|
||||
0x8a 0x6 0x9c 0x77 0x0 0x7d 0x1 0x0 0x0 0x1 0x9d 0x52 0x0 0x0 0x0 0x0 0x0
|
||||
0x8b 0x0 0x9d 0x43 0x0 0x7f 0x1 0x0 0x0 0x6 0x9d 0x77 0x0 0x7f 0x1 0x0 0x0
|
||||
0x8c 0x0 0x9e 0x92 0x0 0x82 0x1 0x0 0x0 0x6 0x9e 0x77 0x0 0x82 0x1 0x0 0x0
|
||||
0x8d 0x1 0x9f 0x53 0x0 0x0 0x0 0x0 0x0 0x0 0x9f 0xba 0x0 0x87 0x1 0x0 0x0
|
||||
0x8e 0x6 0x9f 0x77 0x0 0x87 0x1 0x0 0x0 0x0 0xa0 0xe4 0x0 0xae 0x1 0x0 0x0
|
||||
0x8f 0x6 0xa0 0x77 0x0 0xae 0x1 0x0 0x0 0x1 0xa0 0x54 0x0 0x0 0x0 0x0 0x0
|
||||
0x90 0x0 0xa1 0xd6 0x0 0x77 0x1 0x0 0x0 0x6 0xa1 0x63 0x0 0x77 0x1 0x0 0x0
|
||||
0x91 0x1 0xa1 0x55 0x0 0x0 0x0 0x0 0x0 0x0 0xa2 0xe5 0x0 0x81 0x1 0x0 0x0
|
||||
0x92 0x6 0xa2 0x63 0x0 0x81 0x1 0x0 0x0 0x0 0xa3 0xeb 0x0 0x89 0x1 0x0 0x0
|
||||
0x93 0x6 0xa3 0x63 0x0 0x89 0x1 0x0 0x0 0x1 0xa4 0x54 0x0 0x0 0x0 0x0 0x0
|
||||
0x94 0x0 0xa4 0xf2 0x0 0x91 0x1 0x0 0x0 0x6 0xa4 0x63 0x0 0x91 0x1 0x0 0x0
|
||||
0x95 0x0 0xa5 0xef 0x0 0x98 0x1 0x1 0x0 0x6 0xa5 0x63 0x0 0x98 0x1 0x1 0x0
|
||||
0x96 0x1 0xa5 0x55 0x0 0x0 0x0 0x0 0x0 0x0 0xa6 0xef 0x0 0x99 0x1 0x0 0x0
|
||||
0x97 0x6 0xa6 0x63 0x0 0x99 0x1 0x0 0x0 0x1 0xa6 0x54 0x0 0x0 0x0 0x0 0x0
|
||||
0x98 0x0 0xa7 0xed 0x0 0x9a 0x1 0x0 0x0 0x6 0xa7 0x63 0x0 0x9a 0x1 0x0 0x0
|
||||
0x99 0x5 0xa7 0xf0 0x0 0x9a 0x1 0x0 0x0 0x0 0xa8 0xec 0x0 0x9a 0x1 0x0 0x0
|
||||
0x9a 0x6 0xa8 0x63 0x0 0x9a 0x1 0x0 0x0 0x1 0xa9 0x4d 0x0 0x0 0x0 0x0 0x0
|
||||
0x9b 0x0 0xa9 0xa 0x1 0xc2 0x1 0x0 0x0 0x6 0xa9 0x63 0x0 0xc2 0x1 0x0 0x0
|
||||
0x9c 0x1 0xaa 0x49 0x0 0x0 0x0 0x0 0x0 0x0 0xaa 0xeb 0x0 0x86 0x1 0x0 0x0
|
||||
0x9d 0x6 0xaa 0x63 0x0 0x86 0x1 0x0 0x0 0x0 0xab 0x9 0x1 0xb5 0x1 0x0 0x0
|
||||
0x9e 0x6 0xab 0x63 0x0 0xb5 0x1 0x0 0x0 0x1 0xab 0x4a 0x0 0x0 0x0 0x0 0x0
|
||||
0x9f 0x0 0xac 0xe9 0x0 0x7d 0x1 0x0 0x0 0x6 0xac 0x63 0x0 0x7d 0x1 0x0 0x0
|
||||
0xa0 0x0 0xad 0xf1 0x0 0x89 0x1 0x0 0x0 0x6 0xad 0x50 0x0 0x89 0x1 0x0 0x0
|
||||
0xa1 0x1 0xad 0x51 0x0 0x0 0x0 0x0 0x0 0x0 0xae 0xf1 0x0 0x8f 0x1 0x0 0x0
|
||||
0xa2 0x6 0xae 0x50 0x0 0x8f 0x1 0x0 0x0 0x1 0xaf 0x52 0x0 0x0 0x0 0x0 0x0
|
||||
0xa3 0x0 0xaf 0x7 0x1 0xb8 0x1 0x0 0x0 0x6 0xaf 0x50 0x0 0xb8 0x1 0x0 0x0
|
||||
0xa4 0x0 0xb0 0xf7 0x0 0xa1 0x1 0x0 0x0 0x6 0xb0 0x50 0x0 0xa1 0x1 0x0 0x0
|
||||
0xa5 0x1 0xb0 0x51 0x0 0x0 0x0 0x0 0x0 0x0 0xb1 0xd5 0x0 0x6c 0x1 0x0 0x0
|
||||
0xa6 0x6 0xb1 0x50 0x0 0x6c 0x1 0x0 0x0 0x0 0xb2 0xf4 0x0 0x9e 0x1 0x0 0x0
|
||||
0xa7 0x6 0xb2 0x50 0x0 0x9e 0x1 0x0 0x0 0x1 0xb2 0x54 0x0 0x0 0x0 0x0 0x0
|
||||
0xa8 0x0 0xb3 0xed 0x0 0x92 0x1 0x0 0x0 0x6 0xb3 0x50 0x0 0x92 0x1 0x0 0x0
|
||||
0xa9 0x1 0xb3 0x57 0x0 0x0 0x0 0x0 0x0 0x0 0xb4 0xd5 0x0 0x69 0x1 0x0 0x0
|
||||
0xaa 0x6 0xb4 0x50 0x0 0x69 0x1 0x0 0x0 0x1 0xb5 0x56 0x0 0x0 0x0 0x0 0x0
|
||||
0xab 0x0 0xb5 0xe2 0x0 0x7f 0x1 0x0 0x0 0x6 0xb5 0x50 0x0 0x7f 0x1 0x0 0x0
|
||||
0xac 0x0 0xb6 0xde 0x0 0x80 0x1 0x0 0x0 0x6 0xb6 0x50 0x0 0x80 0x1 0x0 0x0
|
||||
0xad 0x0 0xb7 0xe1 0x0 0x83 0x1 0x0 0x0 0x6 0xb7 0x50 0x0 0x83 0x1 0x0 0x0
|
||||
0xae 0x0 0xb8 0xdd 0x0 0x7b 0x1 0x0 0x0 0x6 0xb8 0x50 0x0 0x7b 0x1 0x0 0x0
|
||||
0xaf 0x1 0xb8 0x54 0x0 0x0 0x0 0x0 0x0 0x0 0xb9 0xf2 0x0 0x9c 0x1 0x0 0x0
|
||||
0xb0 0x6 0xb9 0x50 0x0 0x9c 0x1 0x0 0x0 0x1 0xba 0x56 0x0 0x0 0x0 0x0 0x0
|
||||
0xb1 0x0 0xba 0xd6 0x0 0x61 0x1 0x0 0x0 0x6 0xba 0x50 0x0 0x61 0x1 0x0 0x0
|
||||
0xb2 0x0 0xbb 0xf8 0x0 0x94 0x1 0x0 0x0 0x6 0xbb 0x50 0x0 0x94 0x1 0x0 0x0
|
||||
0xb3 0x0 0xbc 0xd7 0x0 0x60 0x1 0x0 0x0 0x6 0xbc 0x50 0x0 0x60 0x1 0x0 0x0
|
||||
0xb4 0x0 0xbd 0xfb 0x0 0x96 0x1 0x0 0x0 0x6 0xbd 0x50 0x0 0x96 0x1 0x0 0x0
|
||||
0xb5 0x0 0xbe 0xf2 0x0 0x8c 0x1 0x0 0x0 0x6 0xbe 0x50 0x0 0x8c 0x1 0x0 0x0
|
||||
0xb6 0x1 0xbe 0x58 0x0 0x0 0x0 0x0 0x0 0x0 0xbf 0xd6 0x0 0x61 0x1 0x0 0x0
|
||||
0xb7 0x6 0xbf 0x50 0x0 0x61 0x1 0x0 0x0 0x0 0xc0 0xe0 0x0 0x73 0x1 0x0 0x0
|
||||
0xb8 0x6 0xc0 0x50 0x0 0x73 0x1 0x0 0x0 0x0 0xc1 0xe1 0x0 0x78 0x1 0x0 0x0
|
||||
0xb9 0x6 0xc1 0x50 0x0 0x78 0x1 0x0 0x0 0x0 0xc2 0xe1 0x0 0x77 0x1 0x0 0x0
|
||||
0xba 0x6 0xc2 0x50 0x0 0x77 0x1 0x0 0x0 0x1 0xc2 0x5a 0x0 0x0 0x0 0x0 0x0
|
||||
0xbb 0x0 0xc3 0xe0 0x0 0x75 0x1 0x0 0x0 0x6 0xc3 0x50 0x0 0x75 0x1 0x0 0x0
|
||||
0xbc 0x1 0xc3 0x5b 0x0 0x0 0x0 0x0 0x0 0x0 0xc4 0xe3 0x0 0x7d 0x1 0x0 0x0
|
||||
0xbd 0x6 0xc4 0x50 0x0 0x7d 0x1 0x0 0x0 0x0 0xc5 0xe5 0x0 0x7f 0x1 0x0 0x0
|
||||
0xbe 0x6 0xc5 0x50 0x0 0x7f 0x1 0x0 0x0 0x1 0xc6 0x5c 0x0 0x0 0x0 0x0 0x0
|
||||
0xbf 0x0 0xc6 0xe4 0x0 0x7e 0x1 0x0 0x0 0x6 0xc6 0x50 0x0 0x7e 0x1 0x0 0x0
|
||||
0xc0 0x0 0xc7 0xe5 0x0 0x7f 0x1 0x0 0x0 0x6 0xc7 0x50 0x0 0x7f 0x1 0x0 0x0
|
||||
0xc1 0x1 0xc7 0x5d 0x0 0x0 0x0 0x0 0x0 0x0 0xc8 0xfb 0x0 0xa6 0x1 0x0 0x0
|
||||
0xc2 0x6 0xc8 0x50 0x0 0xa6 0x1 0x0 0x0 0x1 0xc8 0x5e 0x0 0x0 0x0 0x0 0x0
|
||||
0xc3 0x0 0xc9 0xd0 0x0 0x6e 0x1 0x0 0x0 0x6 0xc9 0x50 0x0 0x6e 0x1 0x0 0x0
|
||||
0xc4 0x0 0xca 0xdc 0x0 0x7a 0x1 0x0 0x0 0x6 0xca 0x50 0x0 0x7a 0x1 0x0 0x0
|
||||
0xc5 0x1 0xcb 0x5f 0x0 0x0 0x0 0x0 0x0 0x0 0xcb 0xe0 0x0 0x7d 0x1 0x0 0x0
|
||||
0xc6 0x6 0xcb 0x50 0x0 0x7d 0x1 0x0 0x0 0x1 0xcc 0x60 0x0 0x0 0x0 0x0 0x0
|
||||
0xc7 0x0 0xcc 0xe2 0x0 0x7f 0x1 0x0 0x0 0x6 0xcc 0x50 0x0 0x7f 0x1 0x0 0x0
|
||||
0xc8 0x0 0xcd 0xe4 0x0 0x80 0x1 0x0 0x0 0x6 0xcd 0x50 0x0 0x80 0x1 0x0 0x0
|
||||
0xc9 0x1 0xcd 0x61 0x0 0x0 0x0 0x0 0x0 0x0 0xce 0xe4 0x0 0x81 0x1 0x0 0x0
|
||||
0xca 0x6 0xce 0x50 0x0 0x81 0x1 0x0 0x0 0x0 0xcf 0xe2 0x0 0x7e 0x1 0x0 0x0
|
||||
0xcb 0x6 0xcf 0x50 0x0 0x7e 0x1 0x0 0x0 0x1 0xd0 0x60 0x0 0x0 0x0 0x0 0x0
|
||||
0xcc 0x0 0xd0 0xf6 0x0 0x9e 0x1 0x0 0x0 0x6 0xd0 0x50 0x0 0x9e 0x1 0x0 0x0
|
||||
0xcd 0x0 0xd1 0xd1 0x0 0x60 0x1 0x0 0x0 0x6 0xd1 0x50 0x0 0x60 0x1 0x0 0x0
|
||||
0xce 0x0 0xd2 0xd2 0x0 0x61 0x1 0x0 0x0 0x6 0xd2 0x50 0x0 0x61 0x1 0x0 0x0
|
||||
0xcf 0x1 0xd2 0x5f 0x0 0x0 0x0 0x0 0x0 0x0 0xd3 0xd5 0x0 0x67 0x1 0x0 0x0
|
||||
0xd0 0x6 0xd3 0x50 0x0 0x67 0x1 0x0 0x0 0x0 0xd4 0xec 0x0 0x8d 0x1 0x0 0x0
|
||||
0xd1 0x6 0xd4 0x50 0x0 0x8d 0x1 0x0 0x0 0x1 0xd4 0x5e 0x0 0x0 0x0 0x0 0x0
|
||||
0xd2 0x0 0xd5 0xc9 0x0 0x53 0x1 0x0 0x0 0x6 0xd5 0x50 0x0 0x53 0x1 0x0 0x0
|
||||
0xd3 0x1 0xd6 0x5c 0x0 0x0 0x0 0x0 0x0 0x0 0xd6 0xcd 0x0 0x58 0x1 0x0 0x0
|
||||
0xd4 0x6 0xd6 0x50 0x0 0x58 0x1 0x0 0x0 0x1 0xd7 0x5b 0x0 0x0 0x0 0x0 0x0
|
||||
0xd5 0x0 0xd7 0xca 0x0 0x54 0x1 0x0 0x0 0x6 0xd7 0x50 0x0 0x54 0x1 0x0 0x0
|
||||
0xd6 0x0 0xd8 0xd2 0x0 0x5e 0x1 0x0 0x0 0x6 0xd8 0x50 0x0 0x5e 0x1 0x0 0x0
|
||||
0xd7 0x0 0xd9 0x2c 0x1 0x15 0x1 0x0 0x0 0x6 0xd9 0x50 0x0 0x15 0x1 0x0 0x0
|
||||
0xd8 0x0 0xda 0x60 0x1 0x1c 0x1 0x0 0x0 0x6 0xda 0x50 0x0 0x1c 0x1 0x0 0x0
|
||||
0xd9 0x1 0xda 0x55 0x0 0x0 0x0 0x0 0x0 0x0 0xdb 0x5d 0x1 0xd6 0x0 0x0 0x0
|
||||
0xda 0x6 0xdb 0x50 0x0 0xd6 0x0 0x0 0x0 0x4 0xdc 0x43 0x0 0xd6 0x0 0x0 0x0
|
||||
0xdb 0x1 0xdc 0x58 0x0 0x0 0x0 0x0 0x0 0x0 0xdc 0x9c 0x1 0xc8 0x0 0x0 0x0
|
||||
0xdc 0x6 0xdc 0x50 0x0 0xc8 0x0 0x0 0x0 0x0 0xdd 0x70 0x1 0x8e 0x0 0x0 0x0
|
||||
0xdd 0x6 0xdd 0x50 0x0 0x8e 0x0 0x0 0x0 0x0 0xde 0x83 0x1 0x86 0x0 0x0 0x0
|
||||
0xde 0x6 0xde 0x50 0x0 0x86 0x0 0x0 0x0 0x0 0xdf 0x93 0x1 0x86 0x0 0x0 0x0
|
||||
0xdf 0x6 0xdf 0x50 0x0 0x86 0x0 0x0 0x0 0x1 0xdf 0x57 0x0 0x0 0x0 0x0 0x0
|
||||
0xe0 0x0 0xe0 0x74 0x1 0x7d 0x0 0x0 0x0 0x6 0xe0 0x50 0x0 0x7d 0x0 0x0 0x0
|
||||
0xe1 0x0 0xe1 0x2d 0x1 0x7c 0x0 0x0 0x0 0x6 0xe1 0x50 0x0 0x7c 0x0 0x0 0x0
|
||||
0xe2 0x0 0xe3 0xf0 0x0 0xa5 0x0 0xff 0xff 0x6 0xe3 0x50 0x0 0xa5 0x0 0xff 0xff
|
||||
0xe3 0x1 0xe4 0x58 0x0 0x0 0x0 0x0 0x0 0x0 0xe4 0x73 0x0 0x99 0x0 0x0 0x0
|
||||
0xe4 0x6 0xe4 0x50 0x0 0x99 0x0 0x0 0x0 0x0 0xe6 0x14 0x0 0xb5 0x0 0x0 0x0
|
||||
0xe5 0x6 0xe6 0x50 0x0 0xb5 0x0 0x0 0x0 0x0 0xe8 0xfb 0xff 0xbf 0x0 0x0 0x0
|
||||
0xe6 0x6 0xe8 0x50 0x0 0xbf 0x0 0x0 0x0 0x1 0xe9 0x59 0x0 0x0 0x0 0x0 0x0
|
||||
0xe7 0x0 0xea 0x8 0x0 0xd5 0x0 0x0 0x0 0x6 0xea 0x50 0x0 0xd5 0x0 0x0 0x0
|
||||
0xe8 0x1 0xec 0x58 0x0 0x0 0x0 0x0 0x0 0x0 0xee 0x68 0x0 0xae 0x0 0x0 0x0
|
||||
0xe9 0x6 0xee 0x64 0x0 0xae 0x0 0x0 0x0 0x0 0xf0 0xc5 0x0 0x5e 0x0 0x0 0x0
|
||||
0xea 0x6 0xf0 0x64 0x0 0x5e 0x0 0x0 0x0 0x1 0xf1 0x59 0x0 0x0 0x0 0x0 0x0
|
||||
0xeb 0x0 0xf2 0x1b 0x1 0x2f 0x0 0x1 0x0 0x6 0xf2 0x64 0x0 0x2f 0x0 0x1 0x0
|
||||
0xec 0x1 0xf2 0x58 0x0 0x0 0x0 0x0 0x0 0x0 0xf3 0x15 0x1 0x15 0x0 0x0 0x0
|
||||
0xed 0x6 0xf3 0x64 0x0 0x15 0x0 0x0 0x0 0x0 0xf4 0x2a 0x1 0x8 0x0 0x0 0x0
|
||||
0xee 0x6 0xf4 0x76 0x0 0x8 0x0 0x0 0x0 0x1 0xf5 0x59 0x0 0x0 0x0 0x0 0x0
|
||||
0xef 0x0 0xf5 0x6c 0x1 0x13 0x0 0x0 0x0 0x6 0xf5 0x76 0x0 0x13 0x0 0x0 0x0
|
||||
0xf0 0x0 0xf6 0x63 0x1 0xa 0x0 0x0 0x0 0x6 0xf6 0x76 0x0 0xa 0x0 0x0 0x0
|
||||
0xf1 0x0 0xf7 0x8d 0x1 0x2 0x0 0x0 0x0 0x6 0xf7 0x76 0x0 0x2 0x0 0x0 0x0
|
||||
0xf2 0x1 0xf7 0x5a 0x0 0x0 0x0 0x0 0x0 0x0 0xf8 0xa5 0x1 0xf7 0xff 0x0 0x0
|
||||
0xf3 0x6 0xf8 0x76 0x0 0xf7 0xff 0x0 0x0 0x0 0xf9 0x22 0x2 0xd6 0xff 0x0 0x0
|
||||
0xf4 0x6 0xf9 0x76 0x0 0xd6 0xff 0x0 0x0 0x1 0xfa 0x57 0x0 0x0 0x0 0x0 0x0
|
||||
0xf5 0x0 0xfa 0x1 0x2 0xdf 0xff 0x0 0x0 0x6 0xfa 0x76 0x0 0xdf 0xff 0x0 0x0
|
||||
0xf6 0x1 0xfb 0x54 0x0 0x0 0x0 0x0 0x0 0x0 0xfb 0xd2 0x1 0xe8 0xff 0x0 0x0
|
||||
0xf7 0x6 0xfb 0x76 0x0 0xe8 0xff 0x0 0x0 0x0 0xfc 0xaf 0x1 0xf4 0xff 0x0 0x0
|
||||
0xf8 0x6 0xfc 0x76 0x0 0xf4 0xff 0x0 0x0 0x1 0xfc 0x57 0x0 0x0 0x0 0x0 0x0
|
||||
0xf9 0x0 0xfd 0x93 0x1 0x4 0x0 0x0 0x0 0x6 0xfd 0x76 0x0 0x4 0x0 0x0 0x0
|
||||
0xfa 0x0 0xfe 0x8a 0x1 0x7 0x0 0x0 0x0 0x6 0xfe 0x76 0x0 0x7 0x0 0x0 0x0
|
||||
0xfb 0x0 0xff 0x6f 0x1 0x7 0x0 0x0 0x0 0x6 0xff 0x76 0x0 0x7 0x0 0x0 0x0
|
||||
0xfc 0x1 0x0 0x58 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x5a 0x1 0x5 0x0 0x0 0x0
|
||||
0xfd 0x6 0x0 0x76 0x0 0x5 0x0 0x0 0x0 0x1 0x1 0x57 0x0 0x0 0x0 0x0 0x0
|
||||
0xfe 0x0 0x1 0x22 0x1 0x1 0x0 0x0 0x0 0x6 0x1 0x76 0x0 0x1 0x0 0x0 0x0
|
||||
0xff 0x0 0x3 0x20 0x1 0x5 0x0 0x0 0x0 0x6 0x3 0x76 0x0 0x5 0x0 0x0 0x0
|
||||
0x0 0x1 0x3 0x58 0x0 0x0 0x0 0x0 0x0 0x1 0x4 0x59 0x0 0x0 0x0 0x0 0x0
|
||||
0x1 0x0 0x8 0xfe 0x0 0x1b 0x0 0x0 0x0 0x6 0x8 0x76 0x0 0x1b 0x0 0x0 0x0
|
||||
0x2 0x1 0x9 0x59 0x0 0x0 0x0 0x0 0x0 0x1 0xe 0x58 0x0 0x0 0x0 0x0 0x0
|
||||
0x3 0x0 0xf 0xc0 0x0 0x53 0x0 0x0 0x0 0x6 0xf 0xa5 0x0 0x53 0x0 0x0 0x0
|
||||
0x4 0x0 0x11 0x5d 0x0 0x7f 0x0 0x0 0x0 0x6 0x11 0xa5 0x0 0x7f 0x0 0x0 0x0
|
||||
0x5 0x1 0x15 0x58 0x0 0x0 0x0 0x0 0x0 0x0 0x16 0x16 0x0 0xb7 0x0 0x0 0x0
|
||||
0x6 0x6 0x16 0xb9 0x0 0xb7 0x0 0x0 0x0 0x1 0x16 0x59 0x0 0x0 0x0 0x0 0x0
|
||||
0x7 0x0 0x16 0x1 0x0 0xa4 0x0 0x0 0x0 0x6 0x16 0xb9 0x0 0xa4 0x0 0x0 0x0
|
||||
0x8 0x0 0x17 0x14 0x0 0xe6 0x0 0x0 0x0 0x6 0x17 0xb9 0x0 0xe6 0x0 0x0 0x0
|
||||
0x9 0x1 0x17 0x58 0x0 0x0 0x0 0x0 0x0 0x0 0x18 0x14 0x0 0xff 0x0 0x0 0x0
|
||||
0xa 0x6 0x18 0xb9 0x0 0xff 0x0 0x0 0x0 0x1 0x19 0x57 0x0 0x0 0x0 0x0 0x0
|
||||
0xb 0x0 0x19 0xd 0x0 0xe3 0x0 0x0 0x0 0x6 0x19 0xb9 0x0 0xe3 0x0 0x0 0x0
|
||||
0xc 0x0 0x1a 0xe 0x0 0xef 0x0 0xff 0xff 0x6 0x1a 0xb9 0x0 0xef 0x0 0xff 0xff
|
||||
0xd 0x0 0x1b 0x13 0x0 0xe5 0x0 0x0 0x0 0x6 0x1b 0xb9 0x0 0xe5 0x0 0x0 0x0
|
||||
0xe 0x0 0x1c 0xc 0x0 0xca 0x0 0x0 0x0 0x6 0x1c 0xb9 0x0 0xca 0x0 0x0 0x0
|
||||
0xf 0x0 0x1d 0xff 0xff 0xc4 0x0 0x0 0x0 0x6 0x1d 0xb9 0x0 0xc4 0x0 0x0 0x0
|
||||
0x10 0x1 0x1d 0x56 0x0 0x0 0x0 0x0 0x0 0x0 0x1e 0x9 0x0 0xe2 0x0 0x0 0x0
|
||||
0x11 0x6 0x1e 0xb9 0x0 0xe2 0x0 0x0 0x0 0x1 0x1f 0x54 0x0 0x0 0x0 0x0 0x0
|
||||
0x12 0x0 0x1f 0xc 0x0 0xd7 0x0 0x0 0x0 0x6 0x1f 0xa6 0x0 0xd7 0x0 0x0 0x0
|
||||
0x13 0x0 0x20 0x11 0x0 0xd2 0x0 0x0 0x0 0x6 0x20 0xa6 0x0 0xd2 0x0 0x0 0x0
|
||||
0x14 0x0 0x21 0x12 0x0 0xb7 0x0 0x0 0x0 0x6 0x21 0xa6 0x0 0xb7 0x0 0x0 0x0
|
||||
0x15 0x0 0x22 0xc 0x0 0xc2 0x0 0x0 0x0 0x6 0x22 0xa6 0x0 0xc2 0x0 0x0 0x0
|
||||
0x16 0x1 0x22 0x53 0x0 0x0 0x0 0x0 0x0 0x0 0x23 0x6 0x0 0xc5 0x0 0x0 0x0
|
||||
0x17 0x6 0x23 0xa6 0x0 0xc5 0x0 0x0 0x0 0x1 0x23 0x54 0x0 0x0 0x0 0x0 0x0
|
||||
0x18 0x0 0x24 0xff 0xff 0xc9 0x0 0x0 0x0 0x6 0x24 0xa6 0x0 0xc9 0x0 0x0 0x0
|
||||
0x19 0x1 0x25 0x53 0x0 0x0 0x0 0x0 0x0 0x0 0x25 0xfe 0xff 0xdf 0x0 0x0 0x0
|
||||
0x1a 0x6 0x25 0xa6 0x0 0xdf 0x0 0x0 0x0 0x0 0x26 0x4 0x0 0xc2 0x0 0x0 0x0
|
||||
0x1b 0x6 0x26 0xa6 0x0 0xc2 0x0 0x0 0x0 0x0 0x27 0x8 0x0 0xc2 0x0 0x0 0x0
|
||||
0x1c 0x6 0x27 0xa6 0x0 0xc2 0x0 0x0 0x0 0x1 0x27 0x52 0x0 0x0 0x0 0x0 0x0
|
||||
0x1d 0x0 0x28 0xe 0x0 0xd7 0x0 0x0 0x0 0x6 0x28 0xa6 0x0 0xd7 0x0 0x0 0x0
|
||||
0x1e 0x0 0x29 0x10 0x0 0xbb 0x0 0x0 0x0 0x6 0x29 0xa6 0x0 0xbb 0x0 0x0 0x0
|
||||
0x1f 0x1 0x29 0x53 0x0 0x0 0x0 0x0 0x0 0x0 0x2a 0x11 0x0 0xc4 0x0 0x0 0x0
|
||||
0x20 0x6 0x2a 0xa6 0x0 0xc4 0x0 0x0 0x0 0x0 0x2b 0x13 0x0 0xd5 0x0 0x0 0x0
|
||||
0x21 0x6 0x2b 0xa6 0x0 0xd5 0x0 0x0 0x0 0x1 0x2c 0x54 0x0 0x0 0x0 0x0 0x0
|
||||
0x22 0x0 0x2c 0xe 0x0 0xb6 0x0 0x0 0x0 0x6 0x2c 0xa6 0x0 0xb6 0x0 0x0 0x0
|
||||
0x23 0x0 0x2d 0x9 0x0 0xbc 0x0 0x0 0x0 0x6 0x2d 0xa6 0x0 0xbc 0x0 0x0 0x0
|
||||
0x24 0x0 0x2e 0x5 0x0 0xbb 0x0 0x0 0x0 0x6 0x2e 0xa6 0x0 0xbb 0x0 0x0 0x0
|
||||
0x25 0x0 0x2f 0x3 0x0 0xd5 0x0 0x0 0x0 0x6 0x2f 0xa6 0x0 0xd5 0x0 0x0 0x0
|
||||
0x26 0x0 0x30 0xfd 0xff 0xd6 0x0 0x0 0x0 0x6 0x30 0xa6 0x0 0xd6 0x0 0x0 0x0
|
||||
0x27 0x1 0x31 0x55 0x0 0x0 0x0 0x0 0x0 0x0 0x31 0xfc 0xff 0xbe 0x0 0x0 0x0
|
||||
0x28 0x6 0x31 0x94 0x0 0xbe 0x0 0x0 0x0 0x0 0x32 0xfd 0xff 0xcd 0x0 0x0 0x0
|
||||
0x29 0x6 0x32 0x94 0x0 0xcd 0x0 0x0 0x0 0x1 0x32 0x56 0x0 0x0 0x0 0x0 0x0
|
||||
0x2a 0x0 0x33 0xfc 0xff 0xd7 0x0 0x0 0x0 0x6 0x33 0x94 0x0 0xd7 0x0 0x0 0x0
|
||||
0x2b 0x0 0x34 0xfb 0xff 0xc8 0x0 0xff 0xff 0x6 0x34 0x94 0x0 0xc8 0x0 0xff 0xff
|
||||
0x2c 0x0 0x35 0xff 0xff 0xb4 0x0 0x0 0x0 0x6 0x35 0x94 0x0 0xb4 0x0 0x0 0x0
|
||||
0x2d 0x1 0x36 0x57 0x0 0x0 0x0 0x0 0x0 0x1 0x37 0x58 0x0 0x0 0x0 0x0 0x0
|
||||
0x2e 0x0 0x37 0xf8 0xff 0xb6 0x0 0x0 0x0 0x6 0x37 0x94 0x0 0xb6 0x0 0x0 0x0
|
||||
0x2f 0x1 0x38 0x59 0x0 0x0 0x0 0x0 0x0 0x0 0x39 0xf9 0xff 0xa1 0x0 0x0 0x0
|
||||
0x30 0x6 0x39 0x94 0x0 0xa1 0x0 0x0 0x0 0x1 0x3a 0x5a 0x0 0x0 0x0 0x0 0x0
|
||||
0x31 0x1 0x3c 0x5c 0x0 0x0 0x0 0x0 0x0 0x1 0x3d 0x5b 0x0 0x0 0x0 0x0 0x0
|
||||
0x32 0x0 0x3d 0xd 0x0 0x94 0x0 0x0 0x0 0x6 0x3d 0x94 0x0 0x94 0x0 0x0 0x0
|
||||
0x33 0x1 0x40 0x62 0x0 0x0 0x0 0x0 0x0 0x1 0x42 0x61 0x0 0x0 0x0 0x0 0x0
|
||||
0x34 0x1 0x44 0x68 0x0 0x0 0x0 0x0 0x0 0x0 0x45 0xbf 0xff 0x84 0x0 0x0 0x0
|
||||
0x35 0x6 0x45 0xc0 0x0 0x84 0x0 0x0 0x0 0x1 0x45 0x6e 0x0 0x0 0x0 0x0 0x0
|
||||
0x36 0x1 0x47 0x66 0x0 0x0 0x0 0x0 0x0 0x0 0x47 0x74 0xff 0x56 0x0 0x0 0x0
|
||||
0x37 0x6 0x47 0xdb 0x0 0x56 0x0 0x0 0x0 0x0 0x49 0xd7 0xfe 0x3a 0x0 0x0 0x0
|
||||
0x38 0x6 0x49 0xdb 0x0 0x3a 0x0 0x0 0x0 0x1 0x49 0x68 0x0 0x0 0x0 0x0 0x0
|
||||
0x39 0x0 0x4a 0xa 0xff 0x60 0x0 0x0 0x0 0x6 0x4a 0xf1 0x0 0x60 0x0 0x0 0x0
|
||||
0x3a 0x1 0x4b 0x61 0x0 0x0 0x0 0x0 0x0 0x0 0x4c 0xdd 0xfe 0x3f 0x0 0x0 0x0
|
||||
0x3b 0x6 0x4c 0xf1 0x0 0x3f 0x0 0x0 0x0 0x1 0x4e 0x60 0x0 0x0 0x0 0x0 0x0
|
||||
0x3c 0x0 0x4e 0xd6 0xfe 0x3d 0x0 0x0 0x0 0x6 0x4e 0xf1 0x0 0x3d 0x0 0x0 0x0
|
||||
0x3d 0x1 0x4f 0x59 0x0 0x0 0x0 0x0 0x0 0x0 0x50 0xf6 0xfe 0x24 0x0 0x0 0x0
|
||||
0x3e 0x6 0x50 0xf1 0x0 0x24 0x0 0x0 0x0 0x1 0x50 0x54 0x0 0x0 0x0 0x0 0x0
|
||||
0x3f 0x0 0x52 0x8 0xff 0x26 0x0 0x0 0x0 0x6 0x52 0xf1 0x0 0x26 0x0 0x0 0x0
|
||||
0x40 0x1 0x53 0x51 0x0 0x0 0x0 0x0 0x0 0x1 0x54 0x4e 0x0 0x0 0x0 0x0 0x0
|
||||
0x41 0x0 0x55 0x7 0xff 0x40 0x0 0x0 0x0 0x6 0x55 0xf1 0x0 0x40 0x0 0x0 0x0
|
||||
0x42 0x1 0x55 0x4f 0x0 0x0 0x0 0x0 0x0 0x0 0x57 0xe 0xff 0x20 0x0 0x0 0x0
|
||||
0x43 0x6 0x57 0x6 0x1 0x20 0x0 0x0 0x0 0x1 0x58 0x52 0x0 0x0 0x0 0x0 0x0
|
||||
0x44 0x0 0x59 0xb5 0xfe 0x12 0x0 0x0 0x0 0x6 0x59 0x6 0x1 0x12 0x0 0x0 0x0
|
||||
0x45 0x0 0x5a 0xc4 0xfe 0xb 0x0 0x0 0x0 0x6 0x5a 0x6 0x1 0xb 0x0 0x0 0x0
|
||||
0x46 0x1 0x5a 0x53 0x0 0x0 0x0 0x0 0x0 0x0 0x5b 0xbb 0xfe 0xb 0x0 0x2 0x0
|
||||
0x47 0x6 0x5b 0x6 0x1 0xb 0x0 0x2 0x0 0x0 0x5c 0xac 0xfe 0xd 0x0 0x0 0x0
|
||||
0x48 0x6 0x5c 0x6 0x1 0xd 0x0 0x0 0x0 0x1 0x5c 0x54 0x0 0x0 0x0 0x0 0x0
|
||||
0x49 0x0 0x5d 0x2c 0xfe 0x1a 0x0 0x0 0x0 0x6 0x5d 0x6 0x1 0x1a 0x0 0x0 0x0
|
||||
0x4a 0x1 0x5e 0x56 0x0 0x0 0x0 0x0 0x0 0x0 0x5e 0x44 0xfe 0x22 0x0 0x0 0x0
|
||||
0x4b 0x6 0x5e 0xf2 0x0 0x22 0x0 0x0 0x0 0x1 0x5f 0x55 0x0 0x0 0x0 0x0 0x0
|
||||
0x4c 0x0 0x5f 0x76 0xfe 0x27 0x0 0x0 0x0 0x6 0x5f 0xf2 0x0 0x27 0x0 0x0 0x0
|
||||
0x4d 0x0 0x60 0xa2 0xfe 0x26 0x0 0x0 0x0 0x6 0x60 0xf2 0x0 0x26 0x0 0x0 0x0
|
||||
0x4e 0x0 0x61 0xd2 0xfe 0x1d 0x0 0x0 0x0 0x6 0x61 0xd9 0x0 0x1d 0x0 0x0 0x0
|
||||
0x4f 0x1 0x62 0x54 0x0 0x0 0x0 0x0 0x0 0x0 0x63 0xc6 0xfe 0x19 0x0 0x0 0x0
|
||||
0x50 0x6 0x63 0xd9 0x0 0x19 0x0 0x0 0x0 0x1 0x64 0x55 0x0 0x0 0x0 0x0 0x0
|
||||
0x51 0x1 0x66 0x56 0x0 0x0 0x0 0x0 0x0 0x1 0x67 0x57 0x0 0x0 0x0 0x0 0x0
|
||||
0x52 0x1 0x68 0x58 0x0 0x0 0x0 0x0 0x0 0x1 0x6b 0x59 0x0 0x0 0x0 0x0 0x0
|
||||
0x53 0x0 0x6b 0x2c 0xff 0x4a 0x0 0x0 0x0 0x6 0x6b 0xf3 0x0 0x4a 0x0 0x0 0x0
|
||||
0x54 0x1 0x6d 0x5b 0x0 0x0 0x0 0x0 0x0 0x1 0x6e 0x5a 0x0 0x0 0x0 0x0 0x0
|
||||
0x55 0x1 0x73 0x58 0x0 0x0 0x0 0x0 0x0 0x0 0x74 0xe5 0xfe 0x37 0x0 0x0 0x0
|
||||
0x56 0x6 0x74 0x3a 0x1 0x37 0x0 0x0 0x0 0x1 0x75 0x59 0x0 0x0 0x0 0x0 0x0
|
||||
0x57 0x1 0x76 0x58 0x0 0x0 0x0 0x0 0x0 0x0 0x77 0xee 0xfe 0x5 0x0 0x0 0x0
|
||||
0x58 0x6 0x77 0x56 0x1 0x5 0x0 0x0 0x0 0x1 0x78 0x59 0x0 0x0 0x0 0x0 0x0
|
||||
0x59 0x1 0x7a 0x58 0x0 0x0 0x0 0x0 0x0 0x1 0x7c 0x59 0x0 0x0 0x0 0x0 0x0
|
||||
0x5a 0x1 0x80 0x5a 0x0 0x0 0x0 0x0 0x0 0x1 0x81 0x59 0x0 0x0 0x0 0x0 0x0
|
||||
0x5b 0x1 0x84 0x5a 0x0 0x0 0x0 0x0 0x0 0x0 0x84 0xf 0x0 0xf8 0xff 0x0 0x0
|
||||
0x5c 0x6 0x84 0xfc 0x1 0xf8 0xff 0x0 0x0 0x1 0x85 0x5b 0x0 0x0 0x0 0x0 0x0
|
||||
0x5d 0x1 0x86 0x5a 0x0 0x0 0x0 0x0 0x0 0x0 0x86 0x9e 0x0 0xeb 0xff 0x0 0x0
|
||||
0x5e 0x6 0x86 0x13 0x2 0xeb 0xff 0x0 0x0 0x1 0x88 0x5b 0x0 0x0 0x0 0x0 0x0
|
||||
0x5f 0x0 0x89 0xbf 0x0 0xf0 0xff 0x0 0x0 0x6 0x89 0x13 0x2 0xf0 0xff 0x0 0x0
|
||||
0x60 0x1 0x8a 0x5a 0x0 0x0 0x0 0x0 0x0 0x1 0x8b 0x5b 0x0 0x0 0x0 0x0 0x0
|
||||
0x61 0x1 0x8d 0x5c 0x0 0x0 0x0 0x0 0x0 0x1 0x8e 0x5b 0x0 0x0 0x0 0x0 0x0
|
||||
0x62 0x0 0x91 0xea 0xff 0xf6 0xff 0x0 0x0 0x6 0x91 0x57 0x2 0xf6 0xff 0x0 0x0
|
||||
0x63 0x1 0x92 0x5c 0x0 0x0 0x0 0x0 0x0 0x1 0x93 0x5d 0x0 0x0 0x0 0x0 0x0
|
||||
0x64 0x1 0x98 0x5e 0x0 0x0 0x0 0x0 0x0 0x1 0x99 0x5f 0x0 0x0 0x0 0x0 0x0
|
||||
0x65 0x1 0x9c 0x5e 0x0 0x0 0x0 0x0 0x0 0x1 0x9d 0x5f 0x0 0x0 0x0 0x0 0x0
|
||||
0x66 0x1 0xa1 0x60 0x0 0x0 0x0 0x0 0x0 0x1 0xa2 0x61 0x0 0x0 0x0 0x0 0x0
|
||||
0x67 0x1 0xa3 0x63 0x0 0x0 0x0 0x0 0x0 0x1 0xa5 0x64 0x0 0x0 0x0 0x0 0x0
|
||||
0x68 0x1 0xaa 0x63 0x0 0x0 0x0 0x0 0x0 0x1 0xad 0x61 0x0 0x0 0x0 0x0 0x0
|
||||
0x69 0x1 0xaf 0x5f 0x0 0x0 0x0 0x0 0x0 0x1 0xb0 0x5d 0x0 0x0 0x0 0x0 0x0
|
||||
0x6a 0x1 0xb1 0x5c 0x0 0x0 0x0 0x0 0x0 0x0 0xb3 0x85 0xff 0xfb 0xff 0x0 0x0
|
||||
0x6b 0x6 0xb3 0xa8 0x6 0xfb 0xff 0x0 0x0 0x1 0xb4 0x5b 0x0 0x0 0x0 0x0 0x0
|
||||
0x6c 0x1 0xb6 0x59 0x0 0x0 0x0 0x0 0x0 0x1 0xb9 0x58 0x0 0x0 0x0 0x0 0x0
|
||||
0x6d 0x1 0xba 0x57 0x0 0x0 0x0 0x0 0x0 0x1 0xbe 0x58 0x0 0x0 0x0 0x0 0x0
|
||||
0x6e 0x1 0xbf 0x59 0x0 0x0 0x0 0x0 0x0 0x1 0xc0 0x5a 0x0 0x0 0x0 0x0 0x0
|
||||
0x6f 0x1 0xc3 0x5b 0x0 0x0 0x0 0x0 0x0 0x0 0xc3 0x30 0x0 0xec 0xff 0x0 0x0
|
||||
0x70 0x6 0xc3 0x0 0x0 0xec 0xff 0x0 0x0 0x1 0xc4 0x5d 0x0 0x0 0x0 0x0 0x0
|
||||
0x71 0x1 0xc7 0x5e 0x0 0x0 0x0 0x0 0x0 0x0 0xc8 0x8b 0x0 0xda 0xff 0x0 0x0
|
||||
0x72 0x6 0xc8 0x0 0x0 0xda 0xff 0x0 0x0 0x1 0xc9 0x5d 0x0 0x0 0x0 0x0 0x0
|
||||
0x73 0x1 0xcc 0x5e 0x0 0x0 0x0 0x0 0x0 0x0 0xcc 0xc0 0x0 0xeb 0xff 0x0 0x0
|
||||
0x74 0x6 0xcc 0xf0 0x6 0xeb 0xff 0x0 0x0 0x1 0xcf 0x5d 0x0 0x0 0x0 0x0 0x0
|
||||
0x75 0x0 0xd0 0xd8 0x0 0xeb 0xff 0x0 0x0 0x6 0xd0 0xc4 0x5 0xeb 0xff 0x0 0x0
|
||||
0x76 0x1 0xd1 0x5c 0x0 0x0 0x0 0x0 0x0 0x1 0xd4 0x5d 0x0 0x0 0x0 0x0 0x0
|
||||
0x77 0x0 0xd4 0xe4 0x0 0xfd 0xff 0x0 0x0 0x6 0xd4 0xc 0x5 0xfd 0xff 0x0 0x0
|
||||
0x78 0x1 0xd6 0x5e 0x0 0x0 0x0 0x0 0x0 0x1 0xd7 0x5f 0x0 0x0 0x0 0x0 0x0
|
||||
0x79 0x0 0xd7 0xed 0x0 0xf7 0xff 0x0 0x0 0x6 0xd7 0x82 0x4 0xf7 0xff 0x0 0x0
|
||||
0x7a 0x1 0xd8 0x60 0x0 0x0 0x0 0x0 0x0 0x0 0xda 0xec 0x0 0xef 0xff 0x0 0x0
|
||||
0x7b 0x6 0xda 0x1b 0x4 0xef 0xff 0x0 0x0 0x1 0xdb 0x62 0x0 0x0 0x0 0x0 0x0
|
||||
0x7c 0x1 0xdc 0x63 0x0 0x0 0x0 0x0 0x0 0x1 0xdd 0x64 0x0 0x0 0x0 0x0 0x0
|
||||
0x7d 0x0 0xdd 0xeb 0x0 0xef 0xff 0x0 0x0 0x6 0xdd 0xa5 0x3 0xef 0xff 0x0 0x0
|
||||
0x7e 0x1 0xe1 0x65 0x0 0x0 0x0 0x0 0x0 0x0 0xe1 0xff 0x0 0xef 0xff 0x0 0x0
|
||||
0x7f 0x6 0xe1 0x52 0x3 0xef 0xff 0x0 0x0 0x1 0xe2 0x64 0x0 0x0 0x0 0x0 0x0
|
||||
0x80 0x0 0xe5 0xe6 0x0 0xe3 0xff 0x0 0x0 0x6 0xe5 0x27 0x3 0xe3 0xff 0x0 0x0
|
||||
0x81 0x1 0xe6 0x63 0x0 0x0 0x0 0x0 0x0 0x0 0xe9 0xfa 0x0 0xcc 0xff 0x0 0x0
|
||||
0x82 0x6 0xe9 0x27 0x3 0xcc 0xff 0x0 0x0 0x1 0xeb 0x62 0x0 0x0 0x0 0x0 0x0
|
||||
0x83 0x0 0xed 0xee 0x0 0xfa 0xff 0x0 0x0 0x6 0xed 0x14 0x3 0xfa 0xff 0x0 0x0
|
||||
0x84 0x1 0xee 0x64 0x0 0x0 0x0 0x0 0x0 0x1 0xf0 0x65 0x0 0x0 0x0 0x0 0x0
|
||||
0x85 0x0 0xf2 0xfe 0x0 0xf 0x0 0x0 0x0 0x6 0xf2 0x14 0x3 0xf 0x0 0x0 0x0
|
||||
0x86 0x1 0xf3 0x66 0x0 0x0 0x0 0x0 0x0 0x1 0xf4 0x67 0x0 0x0 0x0 0x0 0x0
|
||||
0x87 0x1 0xf6 0x69 0x0 0x0 0x0 0x0 0x0 0x0 0xf7 0xef 0x0 0xf3 0xff 0xfe 0xff
|
||||
0x88 0x6 0xf7 0x14 0x3 0xf3 0xff 0xfe 0xff 0x1 0xf8 0x6a 0x0 0x0 0x0 0x0 0x0
|
||||
0x89 0x1 0xf9 0x6b 0x0 0x0 0x0 0x0 0x0 0x1 0xfa 0x6d 0x0 0x0 0x0 0x0 0x0
|
||||
0x8a 0x0 0xfb 0xe6 0x0 0xd7 0xff 0x0 0x0 0x6 0xfb 0x14 0x3 0xd7 0xff 0x0 0x0
|
||||
0x8b 0x1 0xfc 0x6f 0x0 0x0 0x0 0x0 0x0 0x1 0xfd 0x70 0x0 0x0 0x0 0x0 0x0
|
||||
0x8c 0x0 0xfe 0xe3 0x0 0xe6 0xff 0x0 0x0 0x6 0xfe 0x14 0x3 0xe6 0xff 0x0 0x0
|
||||
0x8d 0x1 0xff 0x71 0x0 0x0 0x0 0x0 0x0 0x1 0x2 0x72 0x0 0x0 0x0 0x0 0x0
|
||||
0x8e 0x0 0x3 0xe7 0x0 0xda 0xff 0x0 0x0 0x6 0x3 0x14 0x3 0xda 0xff 0x0 0x0
|
||||
0x8f 0x1 0x4 0x73 0x0 0x0 0x0 0x0 0x0 0x1 0x6 0x72 0x0 0x0 0x0 0x0 0x0
|
||||
0x90 0x0 0x7 0xfb 0x0 0xfc 0xff 0x0 0x0 0x6 0x7 0x14 0x3 0xfc 0xff 0x0 0x0
|
||||
0x91 0x1 0x7 0x71 0x0 0x0 0x0 0x0 0x0 0x1 0x8 0x70 0x0 0x0 0x0 0x0 0x0
|
||||
0x92 0x0 0xb 0xee 0x0 0xd 0x0 0x0 0x0 0x6 0xb 0x14 0x3 0xd 0x0 0x0 0x0
|
||||
0x93 0x1 0xb 0x71 0x0 0x0 0x0 0x0 0x0 0x1 0xc 0x70 0x0 0x0 0x0 0x0 0x0
|
||||
0x94 0x1 0xd 0x6f 0x0 0x0 0x0 0x0 0x0 0x0 0xe 0xef 0x0 0x13 0x0 0x0 0x0
|
||||
0x95 0x6 0xe 0x14 0x3 0x13 0x0 0x0 0x0 0x1 0x10 0x71 0x0 0x0 0x0 0x0 0x0
|
||||
0x96 0x1 0x11 0x70 0x0 0x0 0x0 0x0 0x0 0x1 0x12 0x71 0x0 0x0 0x0 0x0 0x0
|
||||
0x97 0x0 0x14 0x6 0x1 0xf1 0xff 0x0 0x0 0x6 0x14 0x1 0x3 0xf1 0xff 0x0 0x0
|
||||
0x98 0x1 0x15 0x72 0x0 0x0 0x0 0x0 0x0 0x1 0x17 0x73 0x0 0x0 0x0 0x0 0x0
|
||||
0x99 0x0 0x18 0x7 0x1 0xa 0x0 0xff 0xff 0x6 0x18 0x1 0x3 0xa 0x0 0xff 0xff
|
||||
0x9a 0x5 0x18 0x71 0x1 0xa 0x0 0xff 0xff 0x1 0x1b 0x75 0x0 0x0 0x0 0x0 0x0
|
||||
0x9b 0x0 0x1b 0x1 0x1 0x7 0x0 0x0 0x0 0x6 0x1b 0xd2 0x2 0x7 0x0 0x0 0x0
|
||||
0x9c 0x1 0x1c 0x74 0x0 0x0 0x0 0x0 0x0 0x0 0x1f 0xc 0x1 0x4 0x0 0x0 0x0
|
||||
0x9d 0x6 0x1f 0xba 0x2 0x4 0x0 0x0 0x0 0x1 0x1f 0x76 0x0 0x0 0x0 0x0 0x0
|
||||
0x9e 0x1 0x21 0x75 0x0 0x0 0x0 0x0 0x0 0x1 0x23 0x76 0x0 0x0 0x0 0x0 0x0
|
||||
0x9f 0x0 0x24 0xc7 0x0 0xb4 0xff 0x0 0x0 0x6 0x24 0xba 0x2 0xb4 0xff 0x0 0x0
|
||||
0xa0 0x1 0x24 0x75 0x0 0x0 0x0 0x0 0x0 0x0 0x27 0x78 0x0 0x8a 0xff 0x0 0x0
|
||||
0xa1 0x6 0x27 0xba 0x2 0x8a 0xff 0x0 0x0 0x1 0x28 0x74 0x0 0x0 0x0 0x0 0x0
|
||||
0xa2 0x1 0x29 0x73 0x0 0x0 0x0 0x0 0x0 0x0 0x2a 0x4b 0x0 0x7a 0xff 0x0 0x0
|
||||
0xa3 0x6 0x2a 0xba 0x2 0x7a 0xff 0x0 0x0 0x1 0x2a 0x72 0x0 0x0 0x0 0x0 0x0
|
||||
0xa4 0x0 0x2d 0x37 0x0 0x6d 0xff 0x0 0x0 0x6 0x2d 0xa1 0x2 0x6d 0xff 0x0 0x0
|
||||
0xa5 0x1 0x2d 0x71 0x0 0x0 0x0 0x0 0x0 0x1 0x2e 0x70 0x0 0x0 0x0 0x0 0x0
|
||||
0xa6 0x0 0x30 0x34 0x0 0x67 0xff 0x0 0x0 0x6 0x30 0x85 0x2 0x67 0xff 0x0 0x0
|
||||
0xa7 0x1 0x32 0x6f 0x0 0x0 0x0 0x0 0x0 0x0 0x33 0x35 0x0 0x61 0xff 0x0 0x0
|
||||
0xa8 0x6 0x33 0x70 0x2 0x61 0xff 0x0 0x0 0x1 0x33 0x70 0x0 0x0 0x0 0x0 0x0
|
||||
0xa9 0x0 0x36 0x26 0x0 0x6a 0xff 0x0 0x0 0x6 0x36 0x5e 0x2 0x6a 0xff 0x0 0x0
|
||||
0xaa 0x1 0x37 0x6f 0x0 0x0 0x0 0x0 0x0 0x0 0x39 0x28 0x0 0x68 0xff 0x0 0x0
|
||||
0xab 0x6 0x39 0x4b 0x2 0x68 0xff 0x0 0x0 0x1 0x39 0x6e 0x0 0x0 0x0 0x0 0x0
|
||||
0xac 0x1 0x3b 0x6d 0x0 0x0 0x0 0x0 0x0 0x0 0x3c 0x24 0x0 0x66 0xff 0x0 0x0
|
||||
0xad 0x6 0x3c 0x4b 0x2 0x66 0xff 0x0 0x0 0x1 0x3d 0x6b 0x0 0x0 0x0 0x0 0x0
|
||||
0xae 0x0 0x3f 0x26 0x0 0x66 0xff 0x0 0x0 0x6 0x3f 0x4b 0x2 0x66 0xff 0x0 0x0
|
||||
0xaf 0x1 0x40 0x6a 0x0 0x0 0x0 0x0 0x0 0x1 0x41 0x68 0x0 0x0 0x0 0x0 0x0
|
||||
0xb0 0x0 0x42 0x1f 0x0 0x54 0xff 0x0 0x0 0x6 0x42 0x36 0x2 0x54 0xff 0x0 0x0
|
||||
0xb1 0x1 0x43 0x67 0x0 0x0 0x0 0x0 0x0 0x0 0x45 0xf 0x0 0x4d 0xff 0x0 0x0
|
||||
0xb2 0x6 0x45 0x36 0x2 0x4d 0xff 0x0 0x0 0x1 0x45 0x68 0x0 0x0 0x0 0x0 0x0
|
||||
0xb3 0x1 0x46 0x69 0x0 0x0 0x0 0x0 0x0 0x0 0x48 0xd 0x0 0x68 0xff 0x0 0x0
|
||||
0xb4 0x6 0x48 0x23 0x2 0x68 0xff 0x0 0x0 0x0 0x4b 0x13 0x0 0x62 0xff 0x0 0x0
|
||||
0xb5 0x6 0x4b 0x23 0x2 0x62 0xff 0x0 0x0 0x1 0x4b 0x6a 0x0 0x0 0x0 0x0 0x0
|
||||
0xb6 0x1 0x4c 0x6c 0x0 0x0 0x0 0x0 0x0 0x0 0x4e 0x0 0x0 0x4d 0xff 0x0 0x0
|
||||
0xb7 0x6 0x4e 0x23 0x2 0x4d 0xff 0x0 0x0 0x1 0x50 0x6e 0x0 0x0 0x0 0x0 0x0
|
||||
0xb8 0x0 0x51 0xf4 0xff 0x5b 0xff 0x0 0x0 0x6 0x51 0x23 0x2 0x5b 0xff 0x0 0x0
|
||||
0xb9 0x1 0x51 0x6d 0x0 0x0 0x0 0x0 0x0 0x0 0x54 0x1 0x0 0x63 0xff 0x0 0x0
|
||||
0xba 0x6 0x54 0x23 0x2 0x63 0xff 0x0 0x0 0x1 0x54 0x6e 0x0 0x0 0x0 0x0 0x0
|
||||
0xbb 0x1 0x55 0x6f 0x0 0x0 0x0 0x0 0x0 0x0 0x57 0xf6 0xff 0x6e 0xff 0x0 0x0
|
||||
0xbc 0x6 0x57 0x23 0x2 0x6e 0xff 0x0 0x0 0x1 0x5a 0x6e 0x0 0x0 0x0 0x0 0x0
|
||||
0xbd 0x0 0x5c 0xe5 0xff 0x64 0xff 0x0 0x0 0x6 0x5c 0x36 0x2 0x64 0xff 0x0 0x0
|
||||
0xbe 0x1 0x5d 0x71 0x0 0x0 0x0 0x0 0x0 0x0 0x5f 0x1a 0x0 0x71 0xff 0x0 0x0
|
||||
0xbf 0x6 0x5f 0x4e 0x2 0x71 0xff 0x0 0x0 0x0 0x62 0xb 0x0 0x5c 0xff 0x0 0x0
|
||||
0xc0 0x6 0x62 0x4e 0x2 0x5c 0xff 0x0 0x0 0x1 0x62 0x70 0x0 0x0 0x0 0x0 0x0
|
||||
0xc1 0x1 0x64 0x71 0x0 0x0 0x0 0x0 0x0 0x0 0x65 0xf1 0xff 0x5e 0xff 0x0 0x0
|
||||
0xc2 0x6 0x65 0x4e 0x2 0x5e 0xff 0x0 0x0 0x1 0x65 0x72 0x0 0x0 0x0 0x0 0x0
|
||||
0xc3 0x1 0x67 0x70 0x0 0x0 0x0 0x0 0x0 0x0 0x68 0x2 0x0 0x67 0xff 0x0 0x0
|
||||
0xc4 0x6 0x68 0x3b 0x2 0x67 0xff 0x0 0x0 0x1 0x68 0x6e 0x0 0x0 0x0 0x0 0x0
|
||||
0xc5 0x0 0x6b 0x16 0x0 0x59 0xff 0x0 0x0 0x6 0x6b 0x3b 0x2 0x59 0xff 0x0 0x0
|
||||
0xc6 0x1 0x6c 0x6f 0x0 0x0 0x0 0x0 0x0 0x0 0x6e 0x23 0x0 0x6c 0xff 0x0 0x0
|
||||
0xc7 0x6 0x6e 0x3b 0x2 0x6c 0xff 0x0 0x0 0x1 0x71 0x6e 0x0 0x0 0x0 0x0 0x0
|
||||
0xc8 0x0 0x72 0x3a 0x0 0x57 0xff 0x0 0x0 0x6 0x72 0x27 0x2 0x57 0xff 0x0 0x0
|
||||
0xc9 0x1 0x72 0x70 0x0 0x0 0x0 0x0 0x0 0x0 0x75 0x16 0x0 0x5b 0xff 0x0 0x0
|
||||
0xca 0x6 0x75 0x27 0x2 0x5b 0xff 0x0 0x0 0x1 0x76 0x6f 0x0 0x0 0x0 0x0 0x0
|
||||
0xcb 0x1 0x77 0x6e 0x0 0x0 0x0 0x0 0x0 0x0 0x78 0xf7 0xff 0x5b 0xff 0x0 0x0
|
||||
0xcc 0x6 0x78 0x27 0x2 0x5b 0xff 0x0 0x0 0x4 0x78 0x9c 0x1 0x5b 0xff 0x0 0x0
|
||||
0xcd 0x1 0x78 0x6d 0x0 0x0 0x0 0x0 0x0 0x0 0x7b 0xf2 0xff 0x6d 0xff 0x0 0x0
|
||||
0xce 0x6 0x7b 0x27 0x2 0x6d 0xff 0x0 0x0 0x1 0x7c 0x6c 0x0 0x0 0x0 0x0 0x0
|
||||
0xcf 0x1 0x7d 0x6b 0x0 0x0 0x0 0x0 0x0 0x0 0x7e 0xef 0xff 0x64 0xff 0x0 0x0
|
||||
0xd0 0x6 0x7e 0x27 0x2 0x64 0xff 0x0 0x0 0x1 0x7f 0x6a 0x0 0x0 0x0 0x0 0x0
|
||||
0xd1 0x0 0x82 0xca 0xff 0x58 0xff 0x0 0x0 0x6 0x82 0x27 0x2 0x58 0xff 0x0 0x0
|
||||
0xd2 0x1 0x82 0x69 0x0 0x0 0x0 0x0 0x0 0x1 0x84 0x6a 0x0 0x0 0x0 0x0 0x0
|
||||
0xd3 0x0 0x86 0xce 0xff 0x57 0xff 0x0 0x0 0x6 0x86 0x27 0x2 0x57 0xff 0x0 0x0
|
||||
0xd4 0x0 0x89 0xfe 0xff 0x65 0xff 0x0 0x0 0x6 0x89 0x27 0x2 0x65 0xff 0x0 0x0
|
||||
0xd5 0x1 0x89 0x6b 0x0 0x0 0x0 0x0 0x0 0x1 0x8a 0x6c 0x0 0x0 0x0 0x0 0x0
|
||||
0xd6 0x1 0x8c 0x6d 0x0 0x0 0x0 0x0 0x0 0x0 0x8d 0x13 0x0 0x68 0xff 0x0 0x0
|
||||
0xd7 0x6 0x8d 0x27 0x2 0x68 0xff 0x0 0x0 0x1 0x8e 0x6c 0x0 0x0 0x0 0x0 0x0
|
||||
0xd8 0x1 0x8f 0x6b 0x0 0x0 0x0 0x0 0x0 0x0 0x91 0xf0 0xff 0x6b 0xff 0x0 0x0
|
||||
0xd9 0x6 0x91 0x54 0x2 0x6b 0xff 0x0 0x0 0x0 0x94 0xee 0xff 0x6b 0xff 0x0 0x0
|
||||
0xda 0x6 0x94 0x54 0x2 0x6b 0xff 0x0 0x0 0x1 0x94 0x6c 0x0 0x0 0x0 0x0 0x0
|
||||
0xdb 0x0 0x97 0xfc 0xff 0x6f 0xff 0x0 0x0 0x6 0x97 0x54 0x2 0x6f 0xff 0x0 0x0
|
||||
0xdc 0x1 0x98 0x6d 0x0 0x0 0x0 0x0 0x0 0x1 0x99 0x6e 0x0 0x0 0x0 0x0 0x0
|
||||
0xdd 0x0 0x9a 0x11 0x0 0x6f 0xff 0x0 0x0 0x6 0x9a 0x54 0x2 0x6f 0xff 0x0 0x0
|
||||
0xde 0x1 0x9a 0x70 0x0 0x0 0x0 0x0 0x0 0x1 0x9d 0x71 0x0 0x0 0x0 0x0 0x0
|
||||
0xdf 0x0 0x9d 0x25 0x0 0x72 0xff 0x0 0x0 0x6 0x9d 0x54 0x2 0x72 0xff 0x0 0x0
|
||||
0xe0 0x1 0x9e 0x72 0x0 0x0 0x0 0x0 0x0 0x0 0xa1 0xed 0xff 0x70 0xff 0x0 0x0
|
||||
0xe1 0x6 0xa1 0x54 0x2 0x70 0xff 0x0 0x0 0x1 0xa2 0x73 0x0 0x0 0x0 0x0 0x0
|
||||
0xe2 0x1 0xa3 0x74 0x0 0x0 0x0 0x0 0x0 0x1 0xa4 0x73 0x0 0x0 0x0 0x0 0x0
|
||||
0xe3 0x1 0xa6 0x72 0x0 0x0 0x0 0x0 0x0 0x1 0xa7 0x70 0x0 0x0 0x0 0x0 0x0
|
||||
0xe4 0x1 0xab 0x6e 0x0 0x0 0x0 0x0 0x0 0x1 0xac 0x6d 0x0 0x0 0x0 0x0 0x0
|
||||
0xe5 0x0 0xad 0x60 0x0 0xcc 0xff 0x0 0x0 0x6 0xad 0xfb 0x2 0xcc 0xff 0x0 0x0
|
||||
0xe6 0x1 0xaf 0x6e 0x0 0x0 0x0 0x0 0x0 0x1 0xb5 0x6f 0x0 0x0 0x0 0x0 0x0
|
||||
0xe7 0x1 0xb6 0x70 0x0 0x0 0x0 0x0 0x0 0x1 0xb8 0x6f 0x0 0x0 0x0 0x0 0x0
|
||||
0xe8 0x1 0xbd 0x70 0x0 0x0 0x0 0x0 0x0 0x1 0xc0 0x6f 0x0 0x0 0x0 0x0 0x0
|
||||
0xe9 0x1 0xc2 0x68 0x0 0x0 0x0 0x0 0x0 0x1 0xc3 0x67 0x0 0x0 0x0 0x0 0x0
|
||||
0xea 0x1 0xc4 0x66 0x0 0x0 0x0 0x0 0x0 0x1 0xc7 0x5f 0x0 0x0 0x0 0x0 0x0
|
||||
0xeb 0x1 0xc8 0x5e 0x0 0x0 0x0 0x0 0x0 0x1 0xc9 0x59 0x0 0x0 0x0 0x0 0x0
|
||||
0xec 0x1 0xcc 0x58 0x0 0x0 0x0 0x0 0x0 0x1 0xcd 0x57 0x0 0x0 0x0 0x0 0x0
|
||||
0xed 0x1 0xce 0x54 0x0 0x0 0x0 0x0 0x0 0x1 0xd1 0x4d 0x0 0x0 0x0 0x0 0x0
|
||||
0xee 0x1 0xd2 0x4c 0x0 0x0 0x0 0x0 0x0 0x1 0xd3 0x4a 0x0 0x0 0x0 0x0 0x0
|
||||
0xef 0x1 0xd8 0x49 0x0 0x0 0x0 0x0 0x0 0x1 0xda 0x4a 0x0 0x0 0x0 0x0 0x0
|
||||
0xf0 0x1 0xdc 0x51 0x0 0x0 0x0 0x0 0x0 0x1 0xdd 0x4a 0x0 0x0 0x0 0x0 0x0
|
||||
0xf1 0x1 0xdf 0x51 0x0 0x0 0x0 0x0 0x0 0x1 0xe0 0x52 0x0 0x0 0x0 0x0 0x0
|
||||
0xf2 0x1 0xe2 0x53 0x0 0x0 0x0 0x0 0x0 0x1 0xe4 0x5a 0x0 0x0 0x0 0x0 0x0
|
||||
0xf3 0x1 0xe5 0x56 0x0 0x0 0x0 0x0 0x0 0x1 0xe7 0x54 0x0 0x0 0x0 0x0 0x0
|
||||
0xf4 0x1 0xe9 0x5a 0x0 0x0 0x0 0x0 0x0 0x1 0xea 0x58 0x0 0x0 0x0 0x0 0x0
|
||||
0xf5 0x1 0xeb 0x56 0x0 0x0 0x0 0x0 0x0 0x1 0xee 0x54 0x0 0x0 0x0 0x0 0x0
|
||||
0xf6 0x1 0xef 0x55 0x0 0x0 0x0 0x0 0x0 0x1 0xf4 0x56 0x0 0x0 0x0 0x0 0x0
|
||||
0xf7 0x1 0xf5 0x57 0x0 0x0 0x0 0x0 0x0 0x1 0xf8 0x58 0x0 0x0 0x0 0x0 0x0
|
||||
0xf8 0x1 0xfa 0x5a 0x0 0x0 0x0 0x0 0x0 0x1 0xff 0x59 0x0 0x0 0x0 0x0 0x0
|
||||
0xf9 0x1 0x1 0x55 0x0 0x0 0x0 0x0 0x0 0x1 0x3 0x58 0x0 0x0 0x0 0x0 0x0
|
||||
0xfa 0x1 0x4 0x59 0x0 0x0 0x0 0x0 0x0 0x1 0x6 0x60 0x0 0x0 0x0 0x0 0x0
|
||||
0xfb 0x1 0x7 0x61 0x0 0x0 0x0 0x0 0x0 0x1 0x9 0x68 0x0 0x0 0x0 0x0 0x0
|
||||
0xfc 0x1 0xc 0x6e 0x0 0x0 0x0 0x0 0x0 0x1 0x10 0x6f 0x0 0x0 0x0 0x0 0x0
|
||||
0xfd 0x1 0x11 0x6e 0x0 0x0 0x0 0x0 0x0 0x1 0x12 0x6f 0x0 0x0 0x0 0x0 0x0
|
||||
0xfe 0x1 0x15 0x70 0x0 0x0 0x0 0x0 0x0 0x1 0x16 0x6f 0x0 0x0 0x0 0x0 0x0
|
||||
0xff 0x1 0x17 0x6e 0x0 0x0 0x0 0x0 0x0 0x1 0x1c 0x6d 0x0 0x0 0x0 0x0 0x0
|
||||
0x0 0x1 0x1f 0x6b 0x0 0x0 0x0 0x0 0x0 0x1 0x21 0x6a 0x0 0x0 0x0 0x0 0x0
|
||||
0x1 0x1 0x25 0x6b 0x0 0x0 0x0 0x0 0x0 0x1 0x26 0x6c 0x0 0x0 0x0 0x0 0x0
|
||||
0x2 0x1 0x28 0x6e 0x0 0x0 0x0 0x0 0x0 0x1 0x2a 0x6f 0x0 0x0 0x0 0x0 0x0
|
||||
0x3 0x1 0x2e 0x6e 0x0 0x0 0x0 0x0 0x0 0x1 0x30 0x6d 0x0 0x0 0x0 0x0 0x0
|
||||
0x4 0x1 0x32 0x6b 0x0 0x0 0x0 0x0 0x0 0x1 0x33 0x6a 0x0 0x0 0x0 0x0 0x0
|
||||
0x5 0x1 0x34 0x69 0x0 0x0 0x0 0x0 0x0 0x1 0x38 0x68 0x0 0x0 0x0 0x0 0x0
|
||||
0x6 0x1 0x39 0x67 0x0 0x0 0x0 0x0 0x0 0x1 0x3d 0x66 0x0 0x0 0x0 0x0 0x0
|
||||
0x7 0x1 0x3e 0x67 0x0 0x0 0x0 0x0 0x0 0x1 0x41 0x6e 0x0 0x0 0x0 0x0 0x0
|
||||
0x8 0x1 0x42 0x6f 0x0 0x0 0x0 0x0 0x0 0x1 0x43 0x68 0x0 0x0 0x0 0x0 0x0
|
||||
0x9 0x0 0x44 0x9f 0x2 0x56 0xfe 0x0 0x0 0x6 0x44 0x4 0x4 0x56 0xfe 0x0 0x0
|
||||
0xa 0x0 0x45 0xfd 0xff 0x2 0x0 0x1 0x0 0x6 0x45 0x4 0x4 0x2 0x0 0x1 0x0
|
||||
0xb 0x1 0x46 0x67 0x0 0x0 0x0 0x0 0x0 0x1 0x47 0x6c 0x0 0x0 0x0 0x0 0x0
|
||||
0xc 0x1 0x48 0x6b 0x0 0x0 0x0 0x0 0x0 0x1 0x4a 0x6a 0x0 0x0 0x0 0x0 0x0
|
||||
0xd 0x1 0x4c 0x67 0x0 0x0 0x0 0x0 0x0 0x1 0x4d 0x68 0x0 0x0 0x0 0x0 0x0
|
||||
0xe 0x1 0x4f 0x6b 0x0 0x0 0x0 0x0 0x0 0x1 0x50 0x6a 0x0 0x0 0x0 0x0 0x0
|
||||
0xf 0x1 0x52 0x69 0x0 0x0 0x0 0x0 0x0 0x1 0x54 0x68 0x0 0x0 0x0 0x0 0x0
|
||||
0x10 0x1 0x59 0x68 0x0 0x0 0x0 0x0 0x0 0x1 0x5a 0x67 0x0 0x0 0x0 0x0 0x0
|
||||
0x11 0x1 0x5b 0x66 0x0 0x0 0x0 0x0 0x0 0x1 0x5e 0x65 0x0 0x0 0x0 0x0 0x0
|
||||
0x12 0x1 0x5f 0x64 0x0 0x0 0x0 0x0 0x0 0x1 0x64 0x63 0x0 0x0 0x0 0x0 0x0
|
||||
0x13 0x1 0x68 0x64 0x0 0x0 0x0 0x0 0x0 0x1 0x69 0x65 0x0 0x0 0x0 0x0 0x0
|
||||
0x14 0x1 0x6e 0x66 0x0 0x0 0x0 0x0 0x0 0x1 0x6f 0x68 0x0 0x0 0x0 0x0 0x0
|
||||
0x15 0x1 0x74 0x68 0x0 0x0 0x0 0x0 0x0 0x1 0x76 0x67 0x0 0x0 0x0 0x0 0x0
|
||||
0x16 0x1 0x77 0x66 0x0 0x0 0x0 0x0 0x0 0x1 0x7c 0x65 0x0 0x0 0x0 0x0 0x0
|
||||
0x17 0x1 0x7e 0x66 0x0 0x0 0x0 0x0 0x0 0x1 0x85 0x64 0x0 0x0 0x0 0x0 0x0
|
||||
0x18 0x1 0x86 0x65 0x0 0x0 0x0 0x0 0x0 0x1 0x87 0x64 0x0 0x0 0x0 0x0 0x0
|
||||
0x19 0x1 0x8a 0x63 0x0 0x0 0x0 0x0 0x0 0x1 0x8c 0x61 0x0 0x0 0x0 0x0 0x0
|
||||
0x1a 0x1 0x90 0x60 0x0 0x0 0x0 0x0 0x0 0x1 0x91 0x5f 0x0 0x0 0x0 0x0 0x0
|
||||
0x1b 0x1 0x93 0x5e 0x0 0x0 0x0 0x0 0x0 0x1 0x95 0x5d 0x0 0x0 0x0 0x0 0x0
|
||||
0x1c 0x1 0x96 0x5e 0x0 0x0 0x0 0x0 0x0 0x1 0x9b 0x5d 0x0 0x0 0x0 0x0 0x0
|
||||
0x1d 0x1 0x9d 0x5f 0x0 0x0 0x0 0x0 0x0 0x1 0x9e 0x5e 0x0 0x0 0x0 0x0 0x0
|
||||
0x1e 0x1 0xa0 0x65 0x0 0x0 0x0 0x0 0x0 0x1 0xa2 0x5e 0x0 0x0 0x0 0x0 0x0
|
||||
0x1f 0x1 0xa3 0x5d 0x0 0x0 0x0 0x0 0x0 0x1 0xa5 0x56 0x0 0x0 0x0 0x0 0x0
|
||||
0x20 0x1 0xa7 0x52 0x0 0x0 0x0 0x0 0x0 0x1 0xa8 0x51 0x0 0x0 0x0 0x0 0x0
|
||||
0x21 0x1 0xa9 0x4e 0x0 0x0 0x0 0x0 0x0 0x1 0xac 0x4d 0x0 0x0 0x0 0x0 0x0
|
||||
0x22 0x1 0xad 0x4c 0x0 0x0 0x0 0x0 0x0 0x1 0xae 0x4b 0x0 0x0 0x0 0x0 0x0
|
||||
0x23 0x1 0xb1 0x4a 0x0 0x0 0x0 0x0 0x0 0x1 0xb2 0x4c 0x0 0x0 0x0 0x0 0x0
|
||||
0x24 0x1 0xb3 0x4b 0x0 0x0 0x0 0x0 0x0 0x1 0xb6 0x4a 0x0 0x0 0x0 0x0 0x0
|
||||
0x25 0x1 0xb8 0x4b 0x0 0x0 0x0 0x0 0x0 0x1 0xba 0x4c 0x0 0x0 0x0 0x0 0x0
|
||||
0x26 0x1 0xbc 0x4d 0x0 0x0 0x0 0x0 0x0 0x1 0xbd 0x4e 0x0 0x0 0x0 0x0 0x0
|
||||
0x27 0x1 0xc1 0x50 0x0 0x0 0x0 0x0 0x0 0x1 0xc2 0x51 0x0 0x0 0x0 0x0 0x0
|
||||
0x28 0x1 0xc4 0x52 0x0 0x0 0x0 0x0 0x0 0x1 0xc7 0x53 0x0 0x0 0x0 0x0 0x0
|
||||
0x29 0x1 0xc9 0x54 0x0 0x0 0x0 0x0 0x0 0x1 0xce 0x55 0x0 0x0 0x0 0x0 0x0
|
||||
0x2a 0x1 0xcf 0x56 0x0 0x0 0x0 0x0 0x0 0x1 0xd0 0x55 0x0 0x0 0x0 0x0 0x0
|
||||
0x2b 0x1 0xd3 0x56 0x0 0x0 0x0 0x0 0x0 0x1 0xd4 0x57 0x0 0x0 0x0 0x0 0x0
|
||||
0x2c 0x1 0xd5 0x54 0x0 0x0 0x0 0x0 0x0 0x1 0xd8 0x53 0x0 0x0 0x0 0x0 0x0
|
||||
0x2d 0x1 0xd9 0x55 0x0 0x0 0x0 0x0 0x0 0x1 0xdd 0x54 0x0 0x0 0x0 0x0 0x0
|
||||
0x2e 0x1 0xdf 0x55 0x0 0x0 0x0 0x0 0x0 0x1 0xe1 0x56 0x0 0x0 0x0 0x0 0x0
|
||||
0x2f 0x1 0xe3 0x57 0x0 0x0 0x0 0x0 0x0 0x1 0xe6 0x59 0x0 0x0 0x0 0x0 0x0
|
||||
0x30 0x1 0xe8 0x5a 0x0 0x0 0x0 0x0 0x0 0x1 0xe9 0x5b 0x0 0x0 0x0 0x0 0x0
|
||||
0x31 0x1 0xeb 0x5a 0x0 0x0 0x0 0x0 0x0 0x1 0xec 0x53 0x0 0x0 0x0 0x0 0x0
|
||||
0x32 0x1 0xee 0x52 0x0 0x0 0x0 0x0 0x0 0x1 0xf0 0x51 0x0 0x0 0x0 0x0 0x0
|
||||
0x33 0x1 0xf1 0x4a 0x0 0x0 0x0 0x0 0x0 0x1 0xf3 0x49 0x0 0x0 0x0 0x0 0x0
|
||||
0x34 0x1 0xf5 0x42 0x0 0x0 0x0 0x0 0x0 0x1 0xf6 0x43 0x0 0x0 0x0 0x0 0x0
|
||||
0x35 0x1 0xf7 0x44 0x0 0x0 0x0 0x0 0x0 0x1 0xfa 0x4b 0x0 0x0 0x0 0x0 0x0
|
||||
0x36 0x1 0xfb 0x51 0x0 0x0 0x0 0x0 0x0 0x1 0xfc 0x50 0x0 0x0 0x0 0x0 0x0
|
||||
0x37 0x1 0xff 0x4f 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x50 0x0 0x0 0x0 0x0 0x0
|
||||
0x38 0x1 0x1 0x51 0x0 0x0 0x0 0x0 0x0 0x1 0x5 0x50 0x0 0x0 0x0 0x0 0x0
|
||||
0x39 0x1 0x8 0x53 0x0 0x0 0x0 0x0 0x0 0x1 0xa 0x51 0x0 0x0 0x0 0x0 0x0
|
||||
0x3a 0x1 0xf 0x51 0x0 0x0 0x0 0x0 0x0 0x1 0x12 0x53 0x0 0x0 0x0 0x0 0x0
|
||||
0x3b 0x1 0x13 0x5a 0x0 0x0 0x0 0x0 0x0 0x1 0x15 0x5f 0x0 0x0 0x0 0x0 0x0
|
||||
0x3c 0x1 0x17 0x64 0x0 0x0 0x0 0x0 0x0 0x1 0x18 0x5e 0x0 0x0 0x0 0x0 0x0
|
||||
0x3d 0x1 0x19 0x5f 0x0 0x0 0x0 0x0 0x0 0x1 0x1c 0x60 0x0 0x0 0x0 0x0 0x0
|
||||
0x3e 0x1 0x1e 0x5f 0x0 0x0 0x0 0x0 0x0 0x1 0x21 0x5d 0x0 0x0 0x0 0x0 0x0
|
||||
0x3f 0x1 0x22 0x5c 0x0 0x0 0x0 0x0 0x0 0x1 0x23 0x5d 0x0 0x0 0x0 0x0 0x0
|
||||
0x40 0x1 0x26 0x5e 0x0 0x0 0x0 0x0 0x0 0x1 0x27 0x5f 0x0 0x0 0x0 0x0 0x0
|
||||
0x41 0x1 0x2b 0x5e 0x0 0x0 0x0 0x0 0x0 0x1 0x2f 0x5d 0x0 0x0 0x0 0x0 0x0
|
||||
0x42 0x1 0x31 0x5c 0x0 0x0 0x0 0x0 0x0 0x1 0x32 0x5a 0x0 0x0 0x0 0x0 0x0
|
||||
0x43 0x1 0x34 0x5b 0x0 0x0 0x0 0x0 0x0 0x1 0x35 0x5c 0x0 0x0 0x0 0x0 0x0
|
||||
0x44 0x1 0x37 0x5d 0x0 0x0 0x0 0x0 0x0 0x1 0x39 0x5e 0x0 0x0 0x0 0x0 0x0
|
||||
0x45 0x1 0x3a 0x5f 0x0 0x0 0x0 0x0 0x0 0x1 0x3b 0x61 0x0 0x0 0x0 0x0 0x0
|
||||
0x46 0x1 0x3e 0x63 0x0 0x0 0x0 0x0 0x0 0x1 0x3f 0x64 0x0 0x0 0x0 0x0 0x0
|
||||
0x47 0x1 0x43 0x63 0x0 0x0 0x0 0x0 0x0 0x1 0x44 0x64 0x0 0x0 0x0 0x0 0x0
|
||||
0x48 0x1 0x45 0x63 0x0 0x0 0x0 0x0 0x0 0x1 0x47 0x62 0x0 0x0 0x0 0x0 0x0
|
||||
0x49 0x1 0x49 0x61 0x0 0x0 0x0 0x0 0x0 0x1 0x4e 0x60 0x0 0x0 0x0 0x0 0x0
|
||||
0x4a 0x1 0x4f 0x61 0x0 0x0 0x0 0x0 0x0 0x1 0x51 0x60 0x0 0x0 0x0 0x0 0x0
|
||||
0x4b 0x1 0x52 0x61 0x0 0x0 0x0 0x0 0x0 0x1 0x56 0x62 0x0 0x0 0x0 0x0 0x0
|
||||
0x4c 0x1 0x57 0x63 0x0 0x0 0x0 0x0 0x0 0x1 0x58 0x62 0x0 0x0 0x0 0x0 0x0
|
||||
0x4d 0x1 0x5b 0x64 0x0 0x0 0x0 0x0 0x0 0x1 0x5d 0x65 0x0 0x0 0x0 0x0 0x0
|
||||
0x4e 0x1 0x60 0x66 0x0 0x0 0x0 0x0 0x0 0x1 0x62 0x67 0x0 0x0 0x0 0x0 0x0
|
||||
0x4f 0x1 0x65 0x66 0x0 0x0 0x0 0x0 0x0 0x1 0x66 0x60 0x0 0x0 0x0 0x0 0x0
|
||||
0x50 0x1 0x67 0x5a 0x0 0x0 0x0 0x0 0x0 0x1 0x69 0x57 0x0 0x0 0x0 0x0 0x0
|
||||
0x51 0x1 0x6b 0x50 0x0 0x0 0x0 0x0 0x0 0x1 0x6c 0x57 0x0 0x0 0x0 0x0 0x0
|
||||
0x52 0x1 0x6e 0x56 0x0 0x0 0x0 0x0 0x0 0x1 0x71 0x57 0x0 0x0 0x0 0x0 0x0
|
||||
0x53 0x1 0x73 0x58 0x0 0x0 0x0 0x0 0x0 0x1 0x74 0x5b 0x0 0x0 0x0 0x0 0x0
|
||||
0x54 0x1 0x78 0x5a 0x0 0x0 0x0 0x0 0x0 0x1 0x7d 0x5a 0x0 0x0 0x0 0x0 0x0
|
||||
0x55 0x1 0x82 0x5a 0x0 0x0 0x0 0x0 0x0 0x1 0x83 0x5b 0x0 0x0 0x0 0x0 0x0
|
||||
0x56 0x1 0x87 0x5a 0x0 0x0 0x0 0x0 0x0 0x1 0x88 0x59 0x0 0x0 0x0 0x0 0x0
|
||||
0x57 0x1 0x8b 0x58 0x0 0x0 0x0 0x0 0x0 0x1 0x8d 0x57 0x0 0x0 0x0 0x0 0x0
|
||||
0x58 0x1 0x8e 0x56 0x0 0x0 0x0 0x0 0x0 0x1 0x90 0x57 0x0 0x0 0x0 0x0 0x0
|
||||
0x59 0x1 0x93 0x55 0x0 0x0 0x0 0x0 0x0 0x1 0x96 0x54 0x0 0x0 0x0 0x0 0x0
|
||||
0x5a 0x1 0x98 0x55 0x0 0x0 0x0 0x0 0x0 0x1 0x9c 0x56 0x0 0x0 0x0 0x0 0x0
|
||||
0x5b 0x1 0x9f 0x57 0x0 0x0 0x0 0x0 0x0 0x1 0xa0 0x58 0x0 0x0 0x0 0x0 0x0
|
||||
0x5c 0x1 0xa4 0x59 0x0 0x0 0x0 0x0 0x0 0x2 0xa8 0x0 0x0 0x0 0x0 0x0 0x0
|
Loading…
Reference in New Issue
Block a user