diff --git a/Blocks/build.gradle b/Blocks/build.gradle
index 2b203709..aa6d1cd5 100644
--- a/Blocks/build.gradle
+++ b/Blocks/build.gradle
@@ -1,27 +1,13 @@
apply plugin: 'com.android.library'
-
-android.buildFeatures.buildConfig true
+apply from: '../build.androidVersionCommon.gradle'
android {
-
namespace 'com.google.blocks'
- compileSdkVersion 29
-
defaultConfig {
- minSdkVersion 23
- targetSdkVersion 28
- versionCode 110
- versionName "22.1"
+ versionCode 115
+ versionName "23.1"
}
-
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
- }
- }
-
}
dependencies {
diff --git a/Blocks/proguard-rules.pro b/Blocks/proguard-rules.pro
deleted file mode 100644
index f1b42451..00000000
--- a/Blocks/proguard-rules.pro
+++ /dev/null
@@ -1,21 +0,0 @@
-# Add project specific ProGuard rules here.
-# You can control the set of applied configuration files using the
-# proguardFiles setting in build.gradle.
-#
-# For more details, see
-# http://developer.android.com/guide/developing/tools/proguard.html
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-# public *;
-#}
-
-# Uncomment this to preserve the line number information for
-# debugging stack traces.
-#-keepattributes SourceFile,LineNumberTable
-
-# If you keep the line number information, uncomment this to
-# hide the original source file name.
-#-renamesourcefileattribute SourceFile
diff --git a/Blocks/src/main/AndroidManifest.xml b/Blocks/src/main/AndroidManifest.xml
index 9976aca4..b19aa584 100644
--- a/Blocks/src/main/AndroidManifest.xml
+++ b/Blocks/src/main/AndroidManifest.xml
@@ -1,6 +1,5 @@
-
+
-
\ No newline at end of file
+
diff --git a/Blocks/src/main/assets/blocks/gamepad.js b/Blocks/src/main/assets/blocks/gamepad.js
index d989aeca..7ff2d36b 100644
--- a/Blocks/src/main/assets/blocks/gamepad.js
+++ b/Blocks/src/main/assets/blocks/gamepad.js
@@ -22,6 +22,7 @@
// The following are defined in vars.js:
// getPropertyColor
+// setPropertyColor
// functionColor
function createGamepadDropdown() {
@@ -75,6 +76,9 @@ Blockly.Blocks['gamepad_getProperty'] = {
['LeftStickX', 'LeftStickX'],
['LeftStickY', 'LeftStickY'],
['LeftTrigger', 'LeftTrigger'],
+ ['LeftTriggerPressed', 'LeftTriggerPressed'],
+ ['LeftTriggerWasPressed', 'LeftTriggerWasPressed'],
+ ['LeftTriggerWasReleased', 'LeftTriggerWasReleased'],
['Options', 'Options'],
['OptionsWasPressed', 'OptionsWasPressed'],
['OptionsWasReleased', 'OptionsWasReleased'],
@@ -90,6 +94,9 @@ Blockly.Blocks['gamepad_getProperty'] = {
['RightStickX', 'RightStickX'],
['RightStickY', 'RightStickY'],
['RightTrigger', 'RightTrigger'],
+ ['RightTriggerPressed', 'RightTriggerPressed'],
+ ['RightTriggerWasPressed', 'RightTriggerWasPressed'],
+ ['RightTriggerWasReleased', 'RightTriggerWasReleased'],
['Share', 'Share'],
['ShareWasPressed', 'ShareWasPressed'],
['ShareWasReleased', 'ShareWasReleased'],
@@ -111,6 +118,7 @@ Blockly.Blocks['gamepad_getProperty'] = {
['Triangle', 'Triangle'],
['TriangleWasPressed', 'TriangleWasPressed'],
['TriangleWasReleased', 'TriangleWasReleased'],
+ ['TriggerThreshold', 'TriggerThreshold'],
['X', 'X'],
['XWasPressed', 'XWasPressed'],
['XWasReleased', 'XWasReleased'],
@@ -170,6 +178,9 @@ Blockly.Blocks['gamepad_getProperty'] = {
['LeftStickX', 'Returns a numeric value between -1.0 and +1.0 representing the left analog stick horizontal axis value.'],
['LeftStickY', 'Returns a numeric value between -1.0 and +1.0 representing the left analog stick vertical axis value.'],
['LeftTrigger', 'Returns a numeric value between 0.0 and +1.0 representing the left trigger value.'],
+ ['LeftTriggerPressed', 'Returns true if the left trigger is past the trigger threshold.'],
+ ['LeftTriggerWasPressed', 'Returns true if the left trigger was pressed since the last call of this block.'],
+ ['LeftTriggerWasReleased', 'Returns true if the left trigger was released since the last call of this block.'],
['Options', 'Returns true if the Options button is pressed.'],
['OptionsWasPressed', 'Returns true if the Options button was pressed since the last call of this block.'],
['OptionsWasReleased', 'Returns true if the Options button was released since the last call of this block.'],
@@ -185,6 +196,9 @@ Blockly.Blocks['gamepad_getProperty'] = {
['RightStickX', 'Returns a numeric value between -1.0 and +1.0 representing the right analog stick horizontal axis value.'],
['RightStickY', 'Returns a numeric value between -1.0 and +1.0 representing the right analog stick vertical axis value .'],
['RightTrigger', 'Returns a numeric value between 0.0 and +1.0 representing the right trigger value.'],
+ ['RightTriggerPressed', 'Returns true if the right trigger is past the trigger threshold.'],
+ ['RightTriggerWasPressed', 'Returns true if the right trigger was pressed since the last call of this block.'],
+ ['RightTriggerWasReleased', 'Returns true if the right trigger was released since the last call of this block.'],
['Share', 'Returns true if the Share button is pressed.'],
['ShareWasPressed', 'Returns true if the Share button was pressed since the last call of this block.'],
['ShareWasReleased', 'Returns true if the Share button was released since the last call of this block.'],
@@ -199,13 +213,14 @@ Blockly.Blocks['gamepad_getProperty'] = {
['TouchpadWasReleased', 'Returns true if the Touchpad button was released since the last call of this block.'],
['TouchpadFinger1', 'Returns true if the Touchpad is tracking finger ID # 1.'],
['TouchpadFinger2', 'Returns true if the Touchpad is tracking finger ID # 2.'],
- ['TouchpadFinger1X', 'Returns a numeric value between -1.0 and +1.0 representing the horizontal axis value.'],
- ['TouchpadFinger1Y', 'Returns a numeric value between -1.0 and +1.0 representing the vertical axis value.'],
- ['TouchpadFinger2X', 'Returns a numeric value between -1.0 and +1.0 representing the horizontal axis value.'],
- ['TouchpadFinger2Y', 'Returns a numeric value between -1.0 and +1.0 representing the vertical axis value.'],
+ ['TouchpadFinger1X', 'Returns a numeric value between -1.0 and +1.0 representing the horizontal axis value.'],
+ ['TouchpadFinger1Y', 'Returns a numeric value between -1.0 and +1.0 representing the vertical axis value.'],
+ ['TouchpadFinger2X', 'Returns a numeric value between -1.0 and +1.0 representing the horizontal axis value.'],
+ ['TouchpadFinger2Y', 'Returns a numeric value between -1.0 and +1.0 representing the vertical axis value.'],
['Triangle', 'Returns true if the Triangle button is pressed.'],
['TriangleWasPressed', 'Returns true if the Triangle button was pressed since the last call of this block.'],
['TriangleWasReleased', 'Returns true if the Triangle button was released since the last call of this block.'],
+ ['TriggerThreshold', 'Returns the threshold for determining if a trigger is pressed.'],
['X', 'Returns true if the X button is pressed.'],
['XWasPressed', 'Returns true if the X button was pressed since the last call of this block.'],
['XWasReleased', 'Returns true if the X button was released since the last call of this block.'],
@@ -241,10 +256,10 @@ Blockly.FtcJava['gamepad_getProperty'] = function(block) {
code = 'a';
break;
case 'AWasPressed':
- code = 'a_was_pressed()';
+ code = 'aWasPressed()';
break;
case 'AWasReleased':
- code = 'a_was_released()';
+ code = 'aWasReleased()';
break;
case 'AtRest':
code = 'atRest()';
@@ -253,226 +268,208 @@ Blockly.FtcJava['gamepad_getProperty'] = function(block) {
code = 'b';
break;
case 'BWasPressed':
- code = 'b_was_pressed()';
+ code = 'bWasPressed()';
break;
case 'BWasReleased':
- code = 'b_was_released()';
+ code = 'bWasReleased()';
break;
case 'Back':
code = 'back';
break;
case 'BackWasPressed':
- code = 'back_was_pressed()';
+ code = 'backWasPressed()';
break;
case 'BackWasReleased':
- code = 'back_was_released()';
+ code = 'backWasReleased()';
break;
case 'Circle':
code = 'circle';
break;
case 'CircleWasPressed':
- code = 'circle_was_pressed()';
+ code = 'circleWasPressed()';
break;
case 'CircleWasReleased':
- code = 'circle_was_released()';
+ code = 'circleWasReleased()';
break;
case 'Cross':
code = 'cross';
break;
case 'CrossWasPressed':
- code = 'cross_was_pressed()';
+ code = 'crossWasPressed()';
break;
case 'CrossWasReleased':
- code = 'cross_was_released()';
+ code = 'crossWasReleased()';
break;
case 'DpadDown':
code = 'dpad_down';
break;
case 'DpadDownWasPressed':
- code = 'dpad_down_was_pressed()';
+ code = 'dpadDownWasPressed()';
break;
case 'DpadDownWasReleased':
- code = 'dpad_down_was_released()';
+ code = 'dpadDownWasReleased()';
break;
case 'DpadLeft':
code = 'dpad_left';
break;
case 'DpadLeftWasPressed':
- code = 'dpad_left_was_pressed()';
+ code = 'dpadLeftWasPressed()';
break;
case 'DpadLeftWasReleased':
- code = 'dpad_left_was_released()';
+ code = 'dpadLeftWasReleased()';
break;
case 'DpadRight':
code = 'dpad_right';
break;
case 'DpadRightWasPressed':
- code = 'dpad_right_was_pressed()';
+ code = 'dpadRightWasPressed()';
break;
case 'DpadRightWasReleased':
- code = 'dpad_right_was_released()';
+ code = 'dpadRightWasReleased()';
break;
case 'DpadUp':
code = 'dpad_up';
break;
case 'DpadUpWasPressed':
- code = 'dpad_up_was_pressed()';
+ code = 'dpadUpWasPressed()';
break;
case 'DpadUpWasReleased':
- code = 'dpad_up_was_released()';
+ code = 'dpadUpWasReleased()';
break;
case 'Guide':
code = 'guide';
break;
case 'GuideWasPressed':
- code = 'guide_was_pressed()';
+ code = 'guideWasPressed()';
break;
case 'GuideWasReleased':
- code = 'guide_was_released()';
+ code = 'guideWasReleased()';
break;
case 'LeftBumper':
code = 'left_bumper';
break;
case 'LeftBumperWasPressed':
- code = 'left_bumper_was_pressed()';
+ code = 'leftBumperWasPressed()';
break;
case 'LeftBumperWasReleased':
- code = 'left_bumper_was_released()';
+ code = 'leftBumperWasReleased()';
break;
case 'LeftStickButton':
code = 'left_stick_button';
break;
case 'LeftStickButtonWasPressed':
- code = 'left_stick_button_was_pressed()';
+ code = 'leftStickButtonWasPressed()';
break;
case 'LeftStickButtonWasReleased':
- code = 'left_stick_button_was_released()';
+ code = 'leftStickButtonWasReleased()';
break;
case 'LeftStickX':
code = 'left_stick_x';
break;
- case 'LeftStickXWasPressed':
- code = 'left_stick_x_was_pressed()';
- break;
- case 'LeftStickXWasReleased':
- code = 'left_stick_x_was_released()';
- break;
case 'LeftStickY':
code = 'left_stick_y';
break;
- case 'LeftStickYWasPressed':
- code = 'left_stick_y_was_pressed()';
- break;
- case 'LeftStickYWasReleased':
- code = 'left_stick_y_was_released()';
- break;
case 'LeftTrigger':
code = 'left_trigger';
break;
+ case 'LeftTriggerPressed':
+ code = 'left_trigger_pressed';
+ break;
case 'LeftTriggerWasPressed':
- code = 'left_trigger_was_pressed()';
+ code = 'leftTriggerWasPressed()';
break;
case 'LeftTriggerWasReleased':
- code = 'left_trigger_was_released()';
+ code = 'leftTriggerWasReleased()';
break;
case 'Options':
code = 'options';
break;
case 'OptionsWasPressed':
- code = 'options_was_pressed()';
+ code = 'optionsWasPressed()';
break;
case 'OptionsWasReleased':
- code = 'options_was_released()';
+ code = 'optionsWasReleased()';
break;
case 'PS':
code = 'ps';
break;
case 'PSWasPressed':
- code = 'ps_was_pressed()';
+ code = 'psWasPressed()';
break;
case 'PSWasReleased':
- code = 'ps_was_released()';
+ code = 'psWasReleased()';
break;
case 'RightBumper':
code = 'right_bumper';
break;
case 'RightBumperWasPressed':
- code = 'right_bumper_was_pressed()';
+ code = 'rightBumperWasPressed()';
break;
case 'RightBumperWasReleased':
- code = 'right_bumper_was_released()';
+ code = 'rightBumperWasReleased()';
break;
case 'RightStickButton':
code = 'right_stick_button';
break;
case 'RightStickButtonWasPressed':
- code = 'right_stick_button_was_pressed()';
+ code = 'rightStickButtonWasPressed()';
break;
case 'RightStickButtonWasReleased':
- code = 'right_stick_button_was_released()';
+ code = 'rightStickButtonWasReleased()';
break;
case 'RightStickX':
code = 'right_stick_x';
break;
- case 'RightStickXWasPressed':
- code = 'right_stick_x_was_pressed()';
- break;
- case 'RightStickXWasReleased':
- code = 'right_stick_x_was_released()';
- break;
case 'RightStickY':
code = 'right_stick_y';
break;
- case 'RightStickYWasPressed':
- code = 'right_stick_y_was_pressed()';
- break;
- case 'RightStickYWasReleased':
- code = 'right_stick_y_was_released()';
- break;
case 'RightTrigger':
code = 'right_trigger';
break;
+ case 'RightTriggerPressed':
+ code = 'right_trigger_pressed';
+ break;
case 'RightTriggerWasPressed':
- code = 'right_trigger_was_pressed()';
+ code = 'rightTriggerWasPressed()';
break;
case 'RightTriggerWasReleased':
- code = 'right_trigger_was_released()';
+ code = 'rightTriggerWasReleased()';
break;
case 'Share':
code = 'share';
break;
case 'ShareWasPressed':
- code = 'share_was_pressed()';
+ code = 'shareWasPressed()';
break;
case 'ShareWasReleased':
- code = 'share_was_released()';
+ code = 'shareWasReleased()';
break;
case 'Square':
code = 'square';
break;
case 'SquareWasPressed':
- code = 'square_was_pressed()';
+ code = 'squareWasPressed()';
break;
case 'SquareWasReleased':
- code = 'square_was_released()';
+ code = 'squareWasReleased()';
break;
case 'Start':
code = 'start';
break;
case 'StartWasPressed':
- code = 'start_was_pressed()';
+ code = 'startWasPressed()';
break;
case 'StartWasReleased':
- code = 'start_was_released()';
+ code = 'startWasReleased()';
break;
case 'Touchpad':
code = 'touchpad';
break;
case 'TouchpadWasPressed':
- code = 'touchpad_was_pressed()';
+ code = 'touchpadWasPressed()';
break;
case 'TouchpadWasReleased':
- code = 'touchpad_was_released()';
+ code = 'touchpadWasReleased()';
break;
case 'TouchpadFinger1':
code = 'touchpad_finger_1';
@@ -496,28 +493,31 @@ Blockly.FtcJava['gamepad_getProperty'] = function(block) {
code = 'triangle';
break;
case 'TriangleWasPressed':
- code = 'triangle_was_pressed()';
+ code = 'triangleWasPressed()';
break;
case 'TriangleWasReleased':
- code = 'triangle_was_released()';
+ code = 'triangleWasReleased()';
+ break;
+ case 'TriggerThreshold':
+ code = 'getTriggerThreshold()';
break;
case 'X':
code = 'x';
break;
case 'XWasPressed':
- code = 'x_was_pressed()';
+ code = 'xWasPressed()';
break;
case 'XWasReleased':
- code = 'x_was_released()';
+ code = 'xWasReleased()';
break;
case 'Y':
code = 'y';
break;
case 'YWasPressed':
- code = 'y_was_pressed()';
+ code = 'yWasPressed()';
break;
case 'YWasReleased':
- code = 'y_was_released()';
+ code = 'yWasReleased()';
break;
default:
throw 'Unexpected property ' + property + ' (gamepad_getProperty).';
@@ -569,6 +569,9 @@ Blockly.Blocks['gamepad_getProperty_Boolean'] = {
['LeftStickButton', 'LeftStickButton'],
['LeftStickButtonWasPressed', 'LeftStickButtonWasPressed'],
['LeftStickButtonWasReleased', 'LeftStickButtonWasReleased'],
+ ['LeftTriggerPressed', 'LeftTriggerPressed'],
+ ['LeftTriggerWasPressed', 'LeftTriggerWasPressed'],
+ ['LeftTriggerWasReleased', 'LeftTriggerWasReleased'],
['Options', 'Options'],
['OptionsWasPressed', 'OptionsWasPressed'],
['OptionsWasReleased', 'OptionsWasReleased'],
@@ -581,6 +584,9 @@ Blockly.Blocks['gamepad_getProperty_Boolean'] = {
['RightStickButton', 'RightStickButton'],
['RightStickButtonWasPressed', 'RightStickButtonWasPressed'],
['RightStickButtonWasReleased', 'RightStickButtonWasReleased'],
+ ['RightTriggerPressed', 'RightTriggerPressed'],
+ ['RightTriggerWasPressed', 'RightTriggerWasPressed'],
+ ['RightTriggerWasReleased', 'RightTriggerWasReleased'],
['Share', 'Share'],
['ShareWasPressed', 'ShareWasPressed'],
['ShareWasReleased', 'ShareWasReleased'],
@@ -654,6 +660,9 @@ Blockly.Blocks['gamepad_getProperty_Boolean'] = {
['LeftStickButton', 'Returns true if the left stick button is pressed.'],
['LeftStickButtonWasPressed', 'Returns true if the left stick button was pressed since the last call of this block.'],
['LeftStickButtonWasReleased', 'Returns true if the left stick button was released since the last call of this block.'],
+ ['LeftTriggerPressed', 'Returns true if the left trigger is past the trigger threshold.'],
+ ['LeftTriggerWasPressed', 'Returns true if the left trigger was pressed since the last call of this block.'],
+ ['LeftTriggerWasReleased', 'Returns true if the left trigger was released since the last call of this block.'],
['Options', 'Returns true if the Options button is pressed.'],
['OptionsWasPressed', 'Returns true if the Options button was pressed since the last call of this block.'],
['OptionsWasReleased', 'Returns true if the Options button was released since the last call of this block.'],
@@ -666,6 +675,9 @@ Blockly.Blocks['gamepad_getProperty_Boolean'] = {
['RightStickButton', 'Returns true if the right stick button is pressed.'],
['RightStickButtonWasPressed', 'Returns true if the right stick button was pressed since the last call of this block.'],
['RightStickButtonWasReleased', 'Returns true if the right stick button was released since the last call of this block.'],
+ ['RightTriggerPressed', 'Returns true if the right trigger is past the trigger threshold.'],
+ ['RightTriggerWasPressed', 'Returns true if the right trigger was pressed since the last call of this block.'],
+ ['RightTriggerWasReleased', 'Returns true if the right trigger was released since the last call of this block.'],
['Share', 'Returns true if the Share button is pressed.'],
['ShareWasPressed', 'Returns true if the Share button was pressed since the last call of this block.'],
['ShareWasReleased', 'Returns true if the Share button was released since the last call of this block.'],
@@ -722,6 +734,7 @@ Blockly.Blocks['gamepad_getProperty_Number'] = {
['TouchpadFinger1Y', 'TouchpadFinger1Y'],
['TouchpadFinger2X', 'TouchpadFinger2X'],
['TouchpadFinger2Y', 'TouchpadFinger2Y'],
+ ['TriggerThreshold', 'TriggerThreshold'],
];
this.setOutput(true, 'Number');
this.appendDummyInput()
@@ -738,10 +751,11 @@ Blockly.Blocks['gamepad_getProperty_Number'] = {
['RightStickX', 'Returns a numeric value between -1.0 and +1.0 representing the right analog stick horizontal axis value.'],
['RightStickY', 'Returns a numeric value between -1.0 and +1.0 representing the right analog stick vertical axis value .'],
['RightTrigger', 'Returns a numeric value between 0.0 and +1.0 representing the right trigger value.'],
- ['TouchpadFinger1X', 'Returns a numeric value between -1.0 and +1.0 representing the horizontal axis value.'],
- ['TouchpadFinger1Y', 'Returns a numeric value between -1.0 and +1.0 representing the vertical axis value.'],
- ['TouchpadFinger2X', 'Returns a numeric value between -1.0 and +1.0 representing the horizontal axis value.'],
- ['TouchpadFinger2Y', 'Returns a numeric value between -1.0 and +1.0 representing the vertical axis value.'],
+ ['TouchpadFinger1X', 'Returns a numeric value between -1.0 and +1.0 representing the horizontal axis value.'],
+ ['TouchpadFinger1Y', 'Returns a numeric value between -1.0 and +1.0 representing the vertical axis value.'],
+ ['TouchpadFinger2X', 'Returns a numeric value between -1.0 and +1.0 representing the horizontal axis value.'],
+ ['TouchpadFinger2Y', 'Returns a numeric value between -1.0 and +1.0 representing the vertical axis value.'],
+ ['TriggerThreshold', 'Returns the threshold for determining if a trigger is pressed.'],
];
this.setTooltip(function() {
var key = thisBlock.getFieldValue('PROP');
@@ -765,6 +779,7 @@ Blockly.Blocks['gamepad_getProperty_Number'] = {
case 'TouchpadFinger1Y':
case 'TouchpadFinger2X':
case 'TouchpadFinger2Y':
+ case 'TriggerThreshold':
return 'float';
default:
throw 'Unexpected property ' + property + ' (gamepad_getProperty_Number getOutputType).';
@@ -779,6 +794,64 @@ Blockly.JavaScript['gamepad_getProperty_Number'] =
Blockly.FtcJava['gamepad_getProperty_Number'] =
Blockly.FtcJava['gamepad_getProperty'];
+Blockly.Blocks['gamepad_setProperty_Number'] = {
+ init: function() {
+ var PROPERTY_CHOICES = [
+ ['TriggerThreshold', 'TriggerThreshold'],
+ ];
+ this.appendValueInput('VALUE').setCheck('Number')
+ .appendField('set')
+ .appendField(createGamepadDropdown(), 'IDENTIFIER')
+ .appendField('.')
+ .appendField(new Blockly.FieldDropdown(PROPERTY_CHOICES), 'PROP')
+ .appendField('to');
+ this.setPreviousStatement(true);
+ this.setNextStatement(true);
+ this.setColour(setPropertyColor);
+ // Assign 'this' to a variable for use in the closures below.
+ var thisBlock = this;
+ var TOOLTIPS = [
+ ['TriggerThreshold', 'Sets the threshold for determining if a trigger is pressed.'],
+ ];
+ this.setTooltip(function() {
+ var key = thisBlock.getFieldValue('PROP');
+ for (var i = 0; i < TOOLTIPS.length; i++) {
+ if (TOOLTIPS[i][0] == key) {
+ return TOOLTIPS[i][1];
+ }
+ }
+ return '';
+ });
+ this.getFtcJavaInputType = function(inputName) {
+ if (inputName == 'VALUE') {
+ var property = thisBlock.getFieldValue('PROP');
+ switch (property) {
+ case 'TriggerThreshold':
+ return 'float';
+ default:
+ throw 'Unexpected property ' + property + ' (gamepad_setProperty_Number getArgumentType).';
+ }
+ }
+ return '';
+ };
+ }
+};
+
+Blockly.JavaScript['gamepad_setProperty_Number'] = function(block) {
+ var identifier = block.getFieldValue('IDENTIFIER');
+ var property = block.getFieldValue('PROP');
+ var value = Blockly.JavaScript.valueToCode(
+ block, 'VALUE', Blockly.JavaScript.ORDER_NONE);
+ return identifier + '.set' + property + '(' + value + ');\n';
+};
+
+Blockly.FtcJava['gamepad_setProperty_Number'] = function(block) {
+ var property = block.getFieldValue('PROP');
+ var identifier = Blockly.FtcJava.importDeclareAssign_(block, 'IDENTIFIER', 'DcMotor');
+ var value = Blockly.FtcJava.valueToCode(block, 'VALUE', Blockly.FtcJava.ORDER_NONE);
+ return identifier + '.set' + property + '(' + value + ');\n';
+};
+
Blockly.Blocks['gamepad_rumble_with1'] = {
init: function() {
this.appendDummyInput()
diff --git a/Blocks/src/main/assets/blocks/gobilda_pinpoint.js b/Blocks/src/main/assets/blocks/gobilda_pinpoint.js
index 14e9cb8f..970566f7 100644
--- a/Blocks/src/main/assets/blocks/gobilda_pinpoint.js
+++ b/Blocks/src/main/assets/blocks/gobilda_pinpoint.js
@@ -205,6 +205,145 @@ Blockly.FtcJava['goBildaPinpoint_typedEnum_readData'] = function(block) {
return [code, Blockly.FtcJava.ORDER_MEMBER];
};
+Blockly.Blocks['goBildaPinpoint_typedEnum_errorDetectionType'] = {
+ init: function() {
+ var ERROR_DETECTION_TYPE_CHOICES = [
+ ['NONE', 'NONE'],
+ ['CRC', 'CRC'],
+ ['LOCAL_TEST', 'LOCAL_TEST'],
+ ];
+ this.setOutput(true, 'GoBildaPinpointDriver.ErrorDetectionType');
+ this.appendDummyInput()
+ .appendField(createNonEditableField('ErrorDetectionType'))
+ .appendField('.')
+ .appendField(new Blockly.FieldDropdown(ERROR_DETECTION_TYPE_CHOICES), 'ERROR_DETECTION_TYPE');
+ this.setColour(getPropertyColor);
+ // Assign 'this' to a variable for use in the tooltip closure below.
+ var thisBlock = this;
+ var TOOLTIPS = [
+ ['NONE',
+ 'The GoBildaPinpointDriver.ErrorDetectionType value NONE. ' +
+ 'Does not check the data and passes it directly to the user.'],
+ ['CRC',
+ 'The GoBildaPinpointDriver.ErrorDetectionType value CRC. ' +
+ 'Uses CRC8 error detection to catch incorrect reads. Only supported by devices with ' +
+ 'V3 firmware or newer.'],
+ ['LOCAL_TEST',
+ 'The GoBildaPinpointDriver.ErrorDetectionType value LOCAL_TEST. ' +
+ 'Uses "Controller only" validation to ensure that the data is !NAN, is not all zeros, ' +
+ 'and is a reasonable number. This is faster than CRC but may not catch every ' +
+ 'erroneous read.'],
+ ];
+ this.setTooltip(function() {
+ var key = thisBlock.getFieldValue('ERROR_DETECTION_TYPE');
+ for (var i = 0; i < TOOLTIPS.length; i++) {
+ if (TOOLTIPS[i][0] == key) {
+ return TOOLTIPS[i][1];
+ }
+ }
+ return '';
+ });
+ }
+};
+
+Blockly.JavaScript['goBildaPinpoint_typedEnum_errorDetectionType'] = function(block) {
+ var code = '"' + block.getFieldValue('ERROR_DETECTION_TYPE') + '"';
+ return [code, Blockly.JavaScript.ORDER_ATOMIC];
+};
+
+Blockly.FtcJava['goBildaPinpoint_typedEnum_errorDetectionType'] = function(block) {
+ var code = 'GoBildaPinpointDriver.ErrorDetectionType.' + block.getFieldValue('ERROR_DETECTION_TYPE');
+ Blockly.FtcJava.generateImport_('GoBildaPinpointDriver');
+ return [code, Blockly.FtcJava.ORDER_MEMBER];
+};
+
+Blockly.Blocks['goBildaPinpoint_typedEnum_register'] = {
+ init: function() {
+ var REGISTER_CHOICES = [
+ ['DEVICE_ID', 'DEVICE_ID'],
+ ['DEVICE_VERSION', 'DEVICE_VERSION'],
+ ['DEVICE_STATUS', 'DEVICE_STATUS'],
+ ['DEVICE_CONTROL', 'DEVICE_CONTROL'],
+ ['LOOP_TIME', 'LOOP_TIME'],
+ ['X_ENCODER_VALUE', 'X_ENCODER_VALUE'],
+ ['Y_ENCODER_VALUE', 'Y_ENCODER_VALUE'],
+ ['X_POSITION', 'X_POSITION'],
+ ['Y_POSITION', 'Y_POSITION'],
+ ['H_ORIENTATION', 'H_ORIENTATION'],
+ ['X_VELOCITY', 'X_VELOCITY'],
+ ['Y_VELOCITY', 'Y_VELOCITY'],
+ ['H_VELOCITY', 'H_VELOCITY'],
+ ['MM_PER_TICK', 'MM_PER_TICK'],
+ ['X_POD_OFFSET', 'X_POD_OFFSET'],
+ ['Y_POD_OFFSET', 'Y_POD_OFFSET'],
+ ['YAW_SCALAR', 'YAW_SCALAR'],
+ ['BULK_READ', 'BULK_READ'],
+ ['QUATERNION_W', 'QUATERNION_W'],
+ ['QUATERNION_X', 'QUATERNION_X'],
+ ['QUATERNION_Y', 'QUATERNION_Y'],
+ ['QUATERNION_Z', 'QUATERNION_Z'],
+ ['PITCH', 'PITCH'],
+ ['ROLL', 'ROLL'],
+ ['SET_BULK_READ', 'SET_BULK_READ'],
+ ];
+ this.setOutput(true, 'GoBildaPinpointDriver.Register');
+ this.appendDummyInput()
+ .appendField(createNonEditableField('Register'))
+ .appendField('.')
+ .appendField(new Blockly.FieldDropdown(REGISTER_CHOICES), 'REGISTER');
+ this.setColour(getPropertyColor);
+ // Assign 'this' to a variable for use in the tooltip closure below.
+ var thisBlock = this;
+ var TOOLTIPS = [
+ ['DEVICE_ID', 'The GoBildaPinpointDriver.Register value DEVICE_ID'],
+ ['DEVICE_VERSION', 'The GoBildaPinpointDriver.Register value DEVICE_VERSION'],
+ ['DEVICE_STATUS', 'The GoBildaPinpointDriver.Register value DEVICE_STATUS'],
+ ['DEVICE_CONTROL', 'The GoBildaPinpointDriver.Register value DEVICE_CONTROL'],
+ ['LOOP_TIME', 'The GoBildaPinpointDriver.Register value LOOP_TIME'],
+ ['X_ENCODER_VALUE', 'The GoBildaPinpointDriver.Register value X_ENCODER_VALUE'],
+ ['Y_ENCODER_VALUE', 'The GoBildaPinpointDriver.Register value Y_ENCODER_VALUE'],
+ ['X_POSITION', 'The GoBildaPinpointDriver.Register value X_POSITION'],
+ ['Y_POSITION', 'The GoBildaPinpointDriver.Register value Y_POSITION'],
+ ['H_ORIENTATION', 'The GoBildaPinpointDriver.Register value H_ORIENTATION'],
+ ['X_VELOCITY', 'The GoBildaPinpointDriver.Register value X_VELOCITY'],
+ ['Y_VELOCITY', 'The GoBildaPinpointDriver.Register value Y_VELOCITY'],
+ ['H_VELOCITY', 'The GoBildaPinpointDriver.Register value H_VELOCITY'],
+ ['MM_PER_TICK', 'The GoBildaPinpointDriver.Register value MM_PER_TICK'],
+ ['X_POD_OFFSET', 'The GoBildaPinpointDriver.Register value X_POD_OFFSET'],
+ ['Y_POD_OFFSET', 'The GoBildaPinpointDriver.Register value Y_POD_OFFSET'],
+ ['YAW_SCALAR', 'The GoBildaPinpointDriver.Register value YAW_SCALAR'],
+ ['BULK_READ', 'The GoBildaPinpointDriver.Register value BULK_READ'],
+ ['QUATERNION_W', 'The GoBildaPinpointDriver.Register value QUATERNION_W'],
+ ['QUATERNION_X', 'The GoBildaPinpointDriver.Register value QUATERNION_X'],
+ ['QUATERNION_Y', 'The GoBildaPinpointDriver.Register value QUATERNION_Y'],
+ ['QUATERNION_Z', 'The GoBildaPinpointDriver.Register value QUATERNION_Z'],
+ ['PITCH', 'The GoBildaPinpointDriver.Register value PITCH'],
+ ['ROLL', 'The GoBildaPinpointDriver.Register value ROLL'],
+ ['SET_BULK_READ', 'The GoBildaPinpointDriver.Register value SET_BULK_READ'],
+ ];
+ this.setTooltip(function() {
+ var key = thisBlock.getFieldValue('REGISTER');
+ for (var i = 0; i < TOOLTIPS.length; i++) {
+ if (TOOLTIPS[i][0] == key) {
+ return TOOLTIPS[i][1];
+ }
+ }
+ return '';
+ });
+ }
+};
+
+Blockly.JavaScript['goBildaPinpoint_typedEnum_register'] = function(block) {
+ var code = '"' + block.getFieldValue('REGISTER') + '"';
+ return [code, Blockly.JavaScript.ORDER_ATOMIC];
+};
+
+Blockly.FtcJava['goBildaPinpoint_typedEnum_register'] = function(block) {
+ var code = 'GoBildaPinpointDriver.Register.' + block.getFieldValue('REGISTER');
+ Blockly.FtcJava.generateImport_('GoBildaPinpointDriver');
+ return [code, Blockly.FtcJava.ORDER_MEMBER];
+};
+
// Properties
Blockly.Blocks['goBildaPinpoint_setProperty_Number'] = {
@@ -422,6 +561,38 @@ Blockly.JavaScript['goBildaPinpoint_getProperty_Pose2D'] = Blockly.JavaScript['g
Blockly.FtcJava['goBildaPinpoint_getProperty_Pose2D'] = Blockly.FtcJava['goBildaPinpoint_getProperty_Number'];
+Blockly.Blocks['goBildaPinpoint_getProperty_Quaternion'] = {
+ init: function() {
+ var PROPERTY_CHOICES = [
+ ['Quaternion', 'Quaternion'],
+ ];
+ this.setOutput(true, 'Quaternion');
+ this.appendDummyInput()
+ .appendField(createGoBildaPinpointDropdown(), 'IDENTIFIER')
+ .appendField('.')
+ .appendField(new Blockly.FieldDropdown(PROPERTY_CHOICES), 'PROP');
+ this.setColour(getPropertyColor);
+ // Assign 'this' to a variable for use in the tooltip closure below.
+ var thisBlock = this;
+ var TOOLTIPS = [
+ ['Quaternion', 'Returns a Quaternion which describes the 3d orientation of the device.'],
+ ];
+ this.setTooltip(function() {
+ var key = thisBlock.getFieldValue('PROP');
+ for (var i = 0; i < TOOLTIPS.length; i++) {
+ if (TOOLTIPS[i][0] == key) {
+ return TOOLTIPS[i][1];
+ }
+ }
+ return '';
+ });
+ }
+};
+
+Blockly.JavaScript['goBildaPinpoint_getProperty_Quaternion'] = Blockly.JavaScript['goBildaPinpoint_getProperty_Number'];
+
+Blockly.FtcJava['goBildaPinpoint_getProperty_Quaternion'] = Blockly.FtcJava['goBildaPinpoint_getProperty_Number'];
+
// Functions
Blockly.Blocks['goBildaPinpoint_update'] = {
@@ -1219,3 +1390,249 @@ Blockly.FtcJava['goBildaPinpoint_getYOffset'] = function(block) {
var code = identifier + '.getYOffset(' + distanceUnit + ')';
return [code, Blockly.FtcJava.ORDER_FUNCTION_CALL];
};
+
+Blockly.Blocks['goBildaPinpoint_setBulkReadScope'] = {
+ init: function() {
+ this.appendDummyInput()
+ .appendField('call')
+ .appendField(createGoBildaPinpointDropdown(), 'IDENTIFIER')
+ .appendField('.')
+ .appendField(createNonEditableField('setBulkReadScope'));
+ this.setInputsInline(true);
+ this.setPreviousStatement(true);
+ this.setNextStatement(true);
+ this.setColour(functionColor);
+ this.setTooltip(
+ 'Configures the registers that are read in bulk when update is called. Use this to ' +
+ 'minimize read times based on your unique application. Note that this is only supported ' +
+ 'on V3 firmware and above.');
+ this.itemCount_ = 3;
+ this.updateShape_();
+ this.setMutator(new Blockly.Mutator(['goBildaPinpoint_setBulkReadScope_item']));
+ },
+ mutationToDom: function() {
+ var container = Blockly.utils.xml.createElement('mutation');
+ container.setAttribute('items', this.itemCount_);
+ return container;
+ },
+ domToMutation: function(xmlElement) {
+ this.itemCount_ = parseInt(xmlElement.getAttribute('items'), 10);
+ this.updateShape_();
+ },
+ decompose: function(workspace) {
+ var containerBlock = workspace.newBlock('goBildaPinpoint_setBulkReadScope_container');
+ containerBlock.initSvg();
+ var connection = containerBlock.getInput('STACK').connection;
+ for (var i = 0; i < this.itemCount_; i++) {
+ var itemBlock = workspace.newBlock('goBildaPinpoint_setBulkReadScope_item');
+ itemBlock.initSvg();
+ connection.connect(itemBlock.previousConnection);
+ connection = itemBlock.nextConnection;
+ }
+ return containerBlock;
+ },
+ compose: function(containerBlock) {
+ var itemBlock = containerBlock.getInputTargetBlock('STACK');
+ // Count number of inputs.
+ var connections = [];
+ while (itemBlock) {
+ connections.push(itemBlock.valueConnection_);
+ itemBlock = itemBlock.nextConnection &&
+ itemBlock.nextConnection.targetBlock();
+ }
+ // Disconnect any children that don't belong.
+ for (var i = 0; i < this.itemCount_; i++) {
+ var connection = this.getInput('REGISTER' + i).connection.targetConnection;
+ if (connection && connections.indexOf(connection) == -1) {
+ connection.disconnect();
+ }
+ }
+ this.itemCount_ = connections.length;
+ this.updateShape_();
+ // Reconnect any child blocks.
+ for (var i = 0; i < this.itemCount_; i++) {
+ Blockly.Mutator.reconnect(connections[i], this, 'REGISTER' + i);
+ }
+ },
+ saveConnections: function(containerBlock) {
+ var itemBlock = containerBlock.getInputTargetBlock('STACK');
+ var i = 0;
+ while (itemBlock) {
+ var input = this.getInput('REGISTER' + i);
+ itemBlock.valueConnection_ = input && input.connection.targetConnection;
+ i++;
+ itemBlock = itemBlock.nextConnection &&
+ itemBlock.nextConnection.targetBlock();
+ }
+ },
+ updateShape_: function() {
+ // Add new inputs.
+ for (var i = 0; i < this.itemCount_; i++) {
+ if (!this.getInput('REGISTER' + i)) {
+ var input = this.appendValueInput('REGISTER' + i);
+ }
+ }
+ // Remove deleted inputs.
+ while (this.getInput('REGISTER' + i)) {
+ this.removeInput('REGISTER' + i);
+ i++;
+ }
+ }
+};
+
+Blockly.Blocks['goBildaPinpoint_setBulkReadScope_container'] = {
+ /**
+ * Mutator block for list container.
+ * @this Blockly.Block
+ */
+ init: function() {
+ this.setStyle('list_blocks');
+ this.appendDummyInput()
+ .appendField('');
+ this.appendStatementInput('STACK');
+ this.setTooltip('Add, remove, or reorder registers.');
+ this.contextMenu = false;
+ }
+};
+
+Blockly.Blocks['goBildaPinpoint_setBulkReadScope_item'] = {
+ /**
+ * Mutator block for adding items.
+ * @this Blockly.Block
+ */
+ init: function() {
+ this.setStyle('list_blocks');
+ this.appendDummyInput()
+ .appendField('register');
+ this.setPreviousStatement(true);
+ this.setNextStatement(true);
+ this.setTooltip('Add a register.');
+ this.contextMenu = false;
+ }
+};
+
+Blockly.JavaScript['goBildaPinpoint_setBulkReadScope'] = function(block) {
+ var identifier = block.getFieldValue('IDENTIFIER');
+ var elements = new Array(block.itemCount_);
+ for (var i = 0; i < block.itemCount_; i++) {
+ elements[i] = Blockly.JavaScript.valueToCode(block, 'REGISTER' + i,
+ Blockly.JavaScript.ORDER_COMMA) || 'null';
+ }
+ var registers = '[' + elements.join(', ') + ']';
+ return identifier + '.setBulkReadScope(JSON.stringify(' + registers + '));\n';
+};
+
+Blockly.FtcJava['goBildaPinpoint_setBulkReadScope'] = function(block) {
+ var identifier = Blockly.FtcJava.importDeclareAssign_(block, 'IDENTIFIER', 'GoBildaPinpointDriver');
+ var elements = new Array(block.itemCount_);
+ for (var i = 0; i < block.itemCount_; i++) {
+ elements[i] = Blockly.FtcJava.valueToCode(block, 'REGISTER' + i,
+ Blockly.FtcJava.ORDER_COMMA) || 'null';
+ }
+ var registers = elements.join(',\n' + Blockly.FtcJava.INDENT_CONTINUE);
+ return identifier + '.setBulkReadScope(\n' +
+ Blockly.FtcJava.INDENT_CONTINUE + registers + ');\n';
+};
+
+Blockly.Blocks['goBildaPinpoint_setErrorDetectionType'] = {
+ init: function() {
+ this.appendDummyInput()
+ .appendField('call')
+ .appendField(createGoBildaPinpointDropdown(), 'IDENTIFIER')
+ .appendField('.')
+ .appendField(createNonEditableField('setErrorDetectionType'));
+ this.appendValueInput('ERROR_DETECTION_TYPE').setCheck('GoBildaPinpointDriver.ErrorDetectionType')
+ .appendField('errorDetectionType')
+ .setAlign(Blockly.ALIGN_RIGHT);
+ this.setPreviousStatement(true);
+ this.setNextStatement(true);
+ this.setColour(functionColor);
+ this.setTooltip('Sets the kind of error correction used on the I²C communication from the device.');
+ }
+};
+
+Blockly.JavaScript['goBildaPinpoint_setErrorDetectionType'] = function(block) {
+ var identifier = block.getFieldValue('IDENTIFIER');
+ var errorDetectionType = Blockly.JavaScript.valueToCode(
+ block, 'ERROR_DETECTION_TYPE', Blockly.JavaScript.ORDER_NONE);
+ return identifier + '.setErrorDetectionType(' + errorDetectionType + ');\n';
+};
+
+Blockly.FtcJava['goBildaPinpoint_setErrorDetectionType'] = function(block) {
+ var identifier = Blockly.FtcJava.importDeclareAssign_(block, 'IDENTIFIER', 'GoBildaPinpointDriver');
+ var errorDetectionType = Blockly.FtcJava.valueToCode(
+ block, 'ERROR_DETECTION_TYPE', Blockly.FtcJava.ORDER_NONE);
+ return identifier + '.setErrorDetectionType(' + errorDetectionType + ');\n';
+};
+
+Blockly.Blocks['goBildaPinpoint_getPitch'] = {
+ init: function() {
+ this.setOutput(true, 'Number');
+ this.appendDummyInput()
+ .appendField('call')
+ .appendField(createGoBildaPinpointDropdown(), 'IDENTIFIER')
+ .appendField('.')
+ .appendField(createNonEditableField('getPitch'));
+ this.appendValueInput('ANGLE_UNIT').setCheck('AngleUnit')
+ .appendField('angleUnit')
+ .setAlign(Blockly.ALIGN_RIGHT);
+ this.setColour(functionColor);
+ this.setTooltip(
+ 'Returns the current pitch of the device in the specified AngleUnit.');
+ this.getFtcJavaOutputType = function() {
+ return 'double';
+ };
+ }
+};
+
+Blockly.JavaScript['goBildaPinpoint_getPitch'] = function(block) {
+ var identifier = block.getFieldValue('IDENTIFIER');
+ var angleUnit = Blockly.JavaScript.valueToCode(
+ block, 'ANGLE_UNIT', Blockly.JavaScript.ORDER_NONE);
+ var code = identifier + '.getPitch(' + angleUnit + ')';
+ return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL];
+};
+
+Blockly.FtcJava['goBildaPinpoint_getPitch'] = function(block) {
+ var identifier = Blockly.FtcJava.importDeclareAssign_(block, 'IDENTIFIER', 'GoBildaPinpointDriver');
+ var angleUnit = Blockly.FtcJava.valueToCode(
+ block, 'ANGLE_UNIT', Blockly.FtcJava.ORDER_NONE);
+ var code = identifier + '.getPitch(' + angleUnit + ')';
+ return [code, Blockly.FtcJava.ORDER_FUNCTION_CALL];
+};
+
+Blockly.Blocks['goBildaPinpoint_getRoll'] = {
+ init: function() {
+ this.setOutput(true, 'Number');
+ this.appendDummyInput()
+ .appendField('call')
+ .appendField(createGoBildaPinpointDropdown(), 'IDENTIFIER')
+ .appendField('.')
+ .appendField(createNonEditableField('getRoll'));
+ this.appendValueInput('ANGLE_UNIT').setCheck('AngleUnit')
+ .appendField('angleUnit')
+ .setAlign(Blockly.ALIGN_RIGHT);
+ this.setColour(functionColor);
+ this.setTooltip(
+ 'Returns the current roll of the device in the specified AngleUnit.');
+ this.getFtcJavaOutputType = function() {
+ return 'double';
+ };
+ }
+};
+
+Blockly.JavaScript['goBildaPinpoint_getRoll'] = function(block) {
+ var identifier = block.getFieldValue('IDENTIFIER');
+ var angleUnit = Blockly.JavaScript.valueToCode(
+ block, 'ANGLE_UNIT', Blockly.JavaScript.ORDER_NONE);
+ var code = identifier + '.getRoll(' + angleUnit + ')';
+ return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL];
+};
+
+Blockly.FtcJava['goBildaPinpoint_getRoll'] = function(block) {
+ var identifier = Blockly.FtcJava.importDeclareAssign_(block, 'IDENTIFIER', 'GoBildaPinpointDriver');
+ var angleUnit = Blockly.FtcJava.valueToCode(
+ block, 'ANGLE_UNIT', Blockly.FtcJava.ORDER_NONE);
+ var code = identifier + '.getRoll(' + angleUnit + ')';
+ return [code, Blockly.FtcJava.ORDER_FUNCTION_CALL];
+};
diff --git a/Blocks/src/main/assets/blocks/samples/ConceptGamepadEdgeDetection.blk b/Blocks/src/main/assets/blocks/samples/ConceptGamepadEdgeDetection.blk
index 8972d1b5..1d386c28 100644
--- a/Blocks/src/main/assets/blocks/samples/ConceptGamepadEdgeDetection.blk
+++ b/Blocks/src/main/assets/blocks/samples/ConceptGamepadEdgeDetection.blk
@@ -171,6 +171,134 @@ There are two main types of edge detection. Rising edge detection will trigger w
+
+Add an empty line to separate the buttons in telemetry
+
+
+
+
+
+
+
+
+
+Add the status of the Gamepad 1 Left trigger
+
+
+
+
+Gamepad 1 Left Trigger Pressed
+
+
+
+
+text
+
+
+gamepad1
+LeftTriggerWasPressed
+{"IDENTIFIER":"gamepad1"}
+
+
+
+
+
+
+Gamepad 1 Left Trigger Released
+
+
+
+
+text
+
+
+gamepad1
+LeftTriggerWasReleased
+{"IDENTIFIER":"gamepad1"}
+
+
+
+
+
+
+Gamepad 1 Left Trigger Status
+
+
+
+
+text
+
+
+gamepad1
+LeftTriggerPressed
+{"IDENTIFIER":"gamepad1"}
+
+
+
+
+Add an empty line to separate the buttons in telemetry
+
+
+
+
+
+
+
+
+
+Add the status of the Gamepad 1 Right trigger
+
+
+
+
+Gamepad 1 Right Trigger Pressed
+
+
+
+
+text
+
+
+gamepad1
+RightTriggerWasPressed
+{"IDENTIFIER":"gamepad1"}
+
+
+
+
+
+
+Gamepad 1 Right Trigger Released
+
+
+
+
+text
+
+
+gamepad1
+RightTriggerWasReleased
+{"IDENTIFIER":"gamepad1"}
+
+
+
+
+
+
+Gamepad 1 Right Trigger Status
+
+
+
+
+text
+
+
+gamepad1
+RightTriggerPressed
+{"IDENTIFIER":"gamepad1"}
+
+
+Add a note that the telemetry is only updated every 2 seconds
@@ -220,6 +348,30 @@ There are two main types of edge detection. Rising edge detection will trigger w
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Blocks/src/main/assets/toolbox/gamepad.xml b/Blocks/src/main/assets/toolbox/gamepad.xml
index e08ce403..7363bfa8 100644
--- a/Blocks/src/main/assets/toolbox/gamepad.xml
+++ b/Blocks/src/main/assets/toolbox/gamepad.xml
@@ -63,6 +63,10 @@
gamepad1LeftTrigger
+
+ gamepad1
+ LeftTriggerPressed
+ gamepad1Options
@@ -91,6 +95,10 @@
gamepad1RightTrigger
+
+ gamepad1
+ RightTriggerPressed
+ gamepad1Share
@@ -135,6 +143,15 @@
gamepad1Triangle
+
+ gamepad1
+ TriggerThreshold
+
+
+ gamepad1
+ TriggerThreshold
+ 0.5
+ gamepad1X
@@ -192,6 +209,10 @@
gamepad1LeftStickButtonWasPressed
+
+ gamepad1
+ LeftTriggerWasPressed
+ gamepad1OptionsWasPressed
@@ -208,6 +229,10 @@
gamepad1RightStickButtonWasPressed
+
+ gamepad1
+ RightTriggerWasPressed
+ gamepad1ShareWasPressed
@@ -289,6 +314,10 @@
gamepad1LeftStickButtonWasReleased
+
+ gamepad1
+ LeftTriggerWasReleased
+ gamepad1OptionsWasReleased
@@ -305,6 +334,10 @@
gamepad1RightStickButtonWasReleased
+
+ gamepad1
+ RightTriggerWasReleased
+ gamepad1ShareWasReleased
diff --git a/Blocks/src/main/java/com/google/blocks/ftcrobotcontroller/hardware/HardwareUtil.java b/Blocks/src/main/java/com/google/blocks/ftcrobotcontroller/hardware/HardwareUtil.java
index 69f9aa2b..bb709ac6 100644
--- a/Blocks/src/main/java/com/google/blocks/ftcrobotcontroller/hardware/HardwareUtil.java
+++ b/Blocks/src/main/java/com/google/blocks/ftcrobotcontroller/hardware/HardwareUtil.java
@@ -1451,6 +1451,16 @@ private static void processMethodArguments(StringBuilder xmlToolbox, Class[] par
shadow = (defaultValue == null)
? ToolboxUtil.makeTypedEnumShadow("goBildaPinpoint", "readData")
: ToolboxUtil.makeTypedEnumShadow("goBildaPinpoint", "readData", "READ_DATA", defaultValue);
+ } else if (argType.equals(GoBildaPinpointDriver.ErrorDetectionType.class.getName())) {
+ String defaultValue = parseEnumDefaultValue(parameterDefaultValues[i], GoBildaPinpointDriver.ErrorDetectionType.class);
+ shadow = (defaultValue == null)
+ ? ToolboxUtil.makeTypedEnumShadow("goBildaPinpoint", "errorDetectionType")
+ : ToolboxUtil.makeTypedEnumShadow("goBildaPinpoint", "errorDetectionType", "ERROR_DETECTION_TYPE", defaultValue);
+ } else if (argType.equals(GoBildaPinpointDriver.Register.class.getName())) {
+ String defaultValue = parseEnumDefaultValue(parameterDefaultValues[i], GoBildaPinpointDriver.Register.class);
+ shadow = (defaultValue == null)
+ ? ToolboxUtil.makeTypedEnumShadow("goBildaPinpoint", "register")
+ : ToolboxUtil.makeTypedEnumShadow("goBildaPinpoint", "register", "REGISTER", defaultValue);
} else if (argType.equals(HuskyLens.Algorithm.class.getName())) {
String defaultValue = parseEnumDefaultValue(parameterDefaultValues[i], HuskyLens.Algorithm.class);
shadow = (defaultValue == null)
@@ -2540,6 +2550,7 @@ private static void addGoBildaPinpointCategoryToToolbox(
String identifier = hardwareItems.get(0).identifier;
String zero = ToolboxUtil.makeNumberShadow(0);
String encoderDirection = ToolboxUtil.makeTypedEnumShadow(hardwareType, "encoderDirection");
+ String errorDetectionType = ToolboxUtil.makeTypedEnumShadow(hardwareType, "errorDetectionType");
String readData = ToolboxUtil.makeTypedEnumShadow(hardwareType, "readData");
String goBildaOdometryPods = ToolboxUtil.makeTypedEnumShadow(hardwareType, "goBildaOdometryPods");
String distanceUnit = ToolboxUtil.makeTypedEnumShadow("navigation", "distanceUnit");
@@ -2558,6 +2569,7 @@ private static void addGoBildaPinpointCategoryToToolbox(
properties.put("Frequency", "Number");
properties.put("DeviceStatus", "DeviceStatus");
properties.put("Position", "Pose2D");
+ properties.put("Quaternion", "Quaternion");
Map setterValues = new HashMap();
setterValues.put("YawScalar", new String[] { zero });
Map enumBlocks = new HashMap();
@@ -2634,7 +2646,42 @@ private static void addGoBildaPinpointCategoryToToolbox(
Map getYOffsetArgs = new LinkedHashMap();
getYOffsetArgs.put("DISTANCE_UNIT", distanceUnit);
functions.put("getYOffset", getYOffsetArgs);
+ Map setErrorDetectionTypeArgs = new LinkedHashMap();
+ setErrorDetectionTypeArgs.put("ERROR_DETECTION_TYPE", errorDetectionType);
+ functions.put("setErrorDetectionType", setErrorDetectionTypeArgs);
+ Map getPitchArgs = new LinkedHashMap();
+ getPitchArgs.put("ANGLE_UNIT", angleUnit);
+ functions.put("getPitch", getPitchArgs);
+ Map getRollArgs = new LinkedHashMap();
+ getRollArgs.put("ANGLE_UNIT", angleUnit);
+ functions.put("getRoll", getRollArgs);
ToolboxUtil.addFunctions(xmlToolbox, hardwareType, identifier, functions);
+
+ GoBildaPinpointDriver.Register[] bulkReadScopeExample = new GoBildaPinpointDriver.Register[] {
+ GoBildaPinpointDriver.Register.X_POSITION,
+ GoBildaPinpointDriver.Register.Y_POSITION,
+ GoBildaPinpointDriver.Register.H_ORIENTATION,
+ };
+ xmlToolbox
+ .append("\n")
+ .append(" \n")
+ .append(" ").append(identifier).append("\n");
+ for (int i = 0; i < bulkReadScopeExample.length; i++) {
+ xmlToolbox
+ .append(" \n")
+ .append(" \n")
+ .append(" ").append(bulkReadScopeExample[i]).append("\n")
+ .append(" \n")
+ .append(" \n");
+ }
+ xmlToolbox
+ .append("\n");
+ for (GoBildaPinpointDriver.Register register : GoBildaPinpointDriver.Register.values()) {
+ xmlToolbox
+ .append("\n")
+ .append(" ").append(register).append("\n")
+ .append("\n");
+ }
}
/**
diff --git a/Blocks/src/main/java/com/google/blocks/ftcrobotcontroller/runtime/GamepadAccess.java b/Blocks/src/main/java/com/google/blocks/ftcrobotcontroller/runtime/GamepadAccess.java
index 4ec56ddc..3e2e8111 100644
--- a/Blocks/src/main/java/com/google/blocks/ftcrobotcontroller/runtime/GamepadAccess.java
+++ b/Blocks/src/main/java/com/google/blocks/ftcrobotcontroller/runtime/GamepadAccess.java
@@ -935,6 +935,60 @@ public float getLeftTrigger() {
}
}
+ @SuppressWarnings("unused")
+ @JavascriptInterface
+ @Block(classes = {Gamepad.class}, fieldName = "left_trigger_pressed")
+ public boolean getLeftTriggerPressed() {
+ try {
+ startBlockExecution(BlockType.GETTER, ".LeftTriggerPressed");
+ if (gamepad != null) {
+ return gamepad.left_trigger_pressed;
+ }
+ return false;
+ } catch (Throwable e) {
+ blocksOpMode.handleFatalException(e);
+ throw new AssertionError("impossible", e);
+ } finally {
+ endBlockExecution();
+ }
+ }
+
+ @SuppressWarnings("unused")
+ @JavascriptInterface
+ @Block(classes = {Gamepad.class}, methodName = "leftTriggerWasPressed")
+ public boolean getLeftTriggerWasPressed() {
+ try {
+ startBlockExecution(BlockType.GETTER, ".LeftTriggerWasPressed");
+ if (gamepad != null) {
+ return gamepad.leftTriggerWasPressed();
+ }
+ return false;
+ } catch (Throwable e) {
+ blocksOpMode.handleFatalException(e);
+ throw new AssertionError("impossible", e);
+ } finally {
+ endBlockExecution();
+ }
+ }
+
+ @SuppressWarnings("unused")
+ @JavascriptInterface
+ @Block(classes = {Gamepad.class}, methodName = "leftTriggerWasReleased")
+ public boolean getLeftTriggerWasReleased() {
+ try {
+ startBlockExecution(BlockType.GETTER, ".LeftTriggerWasReleased");
+ if (gamepad != null) {
+ return gamepad.leftTriggerWasReleased();
+ }
+ return false;
+ } catch (Throwable e) {
+ blocksOpMode.handleFatalException(e);
+ throw new AssertionError("impossible", e);
+ } finally {
+ endBlockExecution();
+ }
+ }
+
@SuppressWarnings("unused")
@JavascriptInterface
@Block(classes = {Gamepad.class}, fieldName = "right_trigger")
@@ -953,6 +1007,95 @@ public float getRightTrigger() {
}
}
+ @SuppressWarnings("unused")
+ @JavascriptInterface
+ @Block(classes = {Gamepad.class}, fieldName = "right_trigger_pressed")
+ public boolean getRightTriggerPressed() {
+ try {
+ startBlockExecution(BlockType.GETTER, ".RightTriggerPressed");
+ if (gamepad != null) {
+ return gamepad.right_trigger_pressed;
+ }
+ return false;
+ } catch (Throwable e) {
+ blocksOpMode.handleFatalException(e);
+ throw new AssertionError("impossible", e);
+ } finally {
+ endBlockExecution();
+ }
+ }
+
+ @SuppressWarnings("unused")
+ @JavascriptInterface
+ @Block(classes = {Gamepad.class}, methodName = "rightTriggerWasPressed")
+ public boolean getRightTriggerWasPressed() {
+ try {
+ startBlockExecution(BlockType.GETTER, ".RightTriggerWasPressed");
+ if (gamepad != null) {
+ return gamepad.rightTriggerWasPressed();
+ }
+ return false;
+ } catch (Throwable e) {
+ blocksOpMode.handleFatalException(e);
+ throw new AssertionError("impossible", e);
+ } finally {
+ endBlockExecution();
+ }
+ }
+
+ @SuppressWarnings("unused")
+ @JavascriptInterface
+ @Block(classes = {Gamepad.class}, methodName = "rightTriggerWasReleased")
+ public boolean getRightTriggerWasReleased() {
+ try {
+ startBlockExecution(BlockType.GETTER, ".RightTriggerWasReleased");
+ if (gamepad != null) {
+ return gamepad.rightTriggerWasReleased();
+ }
+ return false;
+ } catch (Throwable e) {
+ blocksOpMode.handleFatalException(e);
+ throw new AssertionError("impossible", e);
+ } finally {
+ endBlockExecution();
+ }
+ }
+
+ @SuppressWarnings("unused")
+ @JavascriptInterface
+ @Block(classes = {Gamepad.class}, methodName = "getTriggerThreshold")
+ public float getTriggerThreshold() {
+ try {
+ startBlockExecution(BlockType.GETTER, ".TriggerThreshold");
+ if (gamepad != null) {
+ return gamepad.getTriggerThreshold();
+ }
+ return 0f;
+ } catch (Throwable e) {
+ blocksOpMode.handleFatalException(e);
+ throw new AssertionError("impossible", e);
+ } finally {
+ endBlockExecution();
+ }
+ }
+
+ @SuppressWarnings("unused")
+ @JavascriptInterface
+ @Block(classes = {Gamepad.class}, methodName = "setTriggerThreshold")
+ public void setTriggerThreshold(float threshold) {
+ try {
+ startBlockExecution(BlockType.SETTER, ".TriggerThreshold");
+ if (gamepad != null) {
+ gamepad.setTriggerThreshold(threshold);
+ }
+ } catch (Throwable e) {
+ blocksOpMode.handleFatalException(e);
+ throw new AssertionError("impossible", e);
+ } finally {
+ endBlockExecution();
+ }
+ }
+
@SuppressWarnings("unused")
@JavascriptInterface
@Block(classes = {Gamepad.class}, methodName = "atRest")
diff --git a/Blocks/src/main/java/com/google/blocks/ftcrobotcontroller/runtime/GoBildaPinpointAccess.java b/Blocks/src/main/java/com/google/blocks/ftcrobotcontroller/runtime/GoBildaPinpointAccess.java
index c6e1ec52..b19b5b21 100644
--- a/Blocks/src/main/java/com/google/blocks/ftcrobotcontroller/runtime/GoBildaPinpointAccess.java
+++ b/Blocks/src/main/java/com/google/blocks/ftcrobotcontroller/runtime/GoBildaPinpointAccess.java
@@ -21,12 +21,15 @@
import com.qualcomm.hardware.gobilda.GoBildaPinpointDriver;
import com.qualcomm.hardware.gobilda.GoBildaPinpointDriver.DeviceStatus;
import com.qualcomm.hardware.gobilda.GoBildaPinpointDriver.EncoderDirection;
+import com.qualcomm.hardware.gobilda.GoBildaPinpointDriver.ErrorDetectionType;
import com.qualcomm.hardware.gobilda.GoBildaPinpointDriver.GoBildaOdometryPods;
import com.qualcomm.hardware.gobilda.GoBildaPinpointDriver.ReadData;
+import com.qualcomm.hardware.gobilda.GoBildaPinpointDriver.Register;
import com.qualcomm.robotcore.hardware.HardwareMap;
import org.firstinspires.ftc.robotcore.external.navigation.AngleUnit;
import org.firstinspires.ftc.robotcore.external.navigation.DistanceUnit;
import org.firstinspires.ftc.robotcore.external.navigation.Pose2D;
+import org.firstinspires.ftc.robotcore.external.navigation.Quaternion;
import org.firstinspires.ftc.robotcore.external.navigation.UnnormalizedAngleUnit;
/**
@@ -54,6 +57,14 @@ private ReadData checkReadData(String readDataString) {
return checkArg(readDataString, ReadData.class, "readData");
}
+ private ErrorDetectionType checkErrorDetectionType(String errorDetectionTypeString) {
+ return checkArg(errorDetectionTypeString, ErrorDetectionType.class, "errorDetectionType");
+ }
+
+ private Register checkRegister(String registerString) {
+ return checkArg(registerString, Register.class, "register");
+ }
+
@SuppressWarnings("unused")
@JavascriptInterface
@Block(classes = {GoBildaPinpointDriver.class}, methodName = "setYawScalar")
@@ -588,4 +599,95 @@ public float getYOffset(String distanceUnitString) {
endBlockExecution();
}
}
+
+ @SuppressWarnings("unused")
+ @JavascriptInterface
+ @Block(classes = {GoBildaPinpointDriver.class}, methodName = "setBulkReadScope")
+ public void setBulkReadScope(String json) {
+ try {
+ startBlockExecution(BlockType.GETTER, ".setBulkReadScope");
+ String[] registerStrings = fromJson(json, String[].class);
+ Register[] registers = new Register[registerStrings.length];
+ for (int i = 0; i < registers.length; i++) {
+ registers[i] = checkRegister(registerStrings[i]);
+ }
+ goBildaPinpoint.setBulkReadScope(registers);
+ } catch (Throwable e) {
+ blocksOpMode.handleFatalException(e);
+ throw new AssertionError("impossible", e);
+ } finally {
+ endBlockExecution();
+ }
+ }
+
+ @SuppressWarnings("unused")
+ @JavascriptInterface
+ @Block(classes = {GoBildaPinpointDriver.class}, methodName = "setErrorDetectionType")
+ public void setErrorDetectionType(String errorDetectionTypeString) {
+ try {
+ startBlockExecution(BlockType.FUNCTION, ".setErrorDetectionType");
+ ErrorDetectionType errorDetectionType = checkErrorDetectionType(errorDetectionTypeString);
+ if (errorDetectionType != null) {
+ goBildaPinpoint.setErrorDetectionType(errorDetectionType);
+ }
+ } catch (Throwable e) {
+ blocksOpMode.handleFatalException(e);
+ throw new AssertionError("impossible", e);
+ } finally {
+ endBlockExecution();
+ }
+ }
+
+ @SuppressWarnings("unused")
+ @JavascriptInterface
+ @Block(classes = {GoBildaPinpointDriver.class}, methodName = "getQuaternion")
+ public Quaternion getQuaternion() {
+ try {
+ startBlockExecution(BlockType.GETTER, ".Quaternion");
+ return goBildaPinpoint.getQuaternion();
+ } catch (Throwable e) {
+ blocksOpMode.handleFatalException(e);
+ throw new AssertionError("impossible", e);
+ } finally {
+ endBlockExecution();
+ }
+ }
+
+ @SuppressWarnings("unused")
+ @JavascriptInterface
+ @Block(classes = {GoBildaPinpointDriver.class}, methodName = "getPitch")
+ public double getPitch(String angleUnitString) {
+ try {
+ startBlockExecution(BlockType.FUNCTION, ".getPitch");
+ AngleUnit angleUnit = checkAngleUnit(angleUnitString);
+ if (angleUnit != null) {
+ return goBildaPinpoint.getPitch(angleUnit);
+ }
+ return 0;
+ } catch (Throwable e) {
+ blocksOpMode.handleFatalException(e);
+ throw new AssertionError("impossible", e);
+ } finally {
+ endBlockExecution();
+ }
+ }
+
+ @SuppressWarnings("unused")
+ @JavascriptInterface
+ @Block(classes = {GoBildaPinpointDriver.class}, methodName = "getRoll")
+ public double getRoll(String angleUnitString) {
+ try {
+ startBlockExecution(BlockType.FUNCTION, ".getRoll");
+ AngleUnit angleUnit = checkAngleUnit(angleUnitString);
+ if (angleUnit != null) {
+ return goBildaPinpoint.getRoll(angleUnit);
+ }
+ return 0;
+ } catch (Throwable e) {
+ blocksOpMode.handleFatalException(e);
+ throw new AssertionError("impossible", e);
+ } finally {
+ endBlockExecution();
+ }
+ }
}
diff --git a/FtcCommon/build.gradle b/FtcCommon/build.gradle
index c3d0128e..af448da9 100644
--- a/FtcCommon/build.gradle
+++ b/FtcCommon/build.gradle
@@ -1,31 +1,13 @@
apply plugin: 'com.android.library'
-
-android.buildFeatures.buildConfig true
+apply from: '../build.androidVersionCommon.gradle'
android {
-
namespace 'com.qualcomm.ftccommon'
- compileSdkVersion 29
-
defaultConfig {
- minSdkVersion 23
- targetSdkVersion 28
- versionCode 110
- versionName "22.1"
- }
-
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
- }
- }
- compileOptions {
- sourceCompatibility JavaVersion.VERSION_1_8
- targetCompatibility JavaVersion.VERSION_1_8
+ versionCode 115
+ versionName "23.1"
}
-
}
dependencies {
@@ -41,4 +23,4 @@ dependencies {
* External
*/
implementation fileTree(include: ['*.jar'], dir: 'libs')
-}
\ No newline at end of file
+}
diff --git a/FtcCommon/proguard-rules.pro b/FtcCommon/proguard-rules.pro
deleted file mode 100644
index f1b42451..00000000
--- a/FtcCommon/proguard-rules.pro
+++ /dev/null
@@ -1,21 +0,0 @@
-# Add project specific ProGuard rules here.
-# You can control the set of applied configuration files using the
-# proguardFiles setting in build.gradle.
-#
-# For more details, see
-# http://developer.android.com/guide/developing/tools/proguard.html
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-# public *;
-#}
-
-# Uncomment this to preserve the line number information for
-# debugging stack traces.
-#-keepattributes SourceFile,LineNumberTable
-
-# If you keep the line number information, uncomment this to
-# hide the original source file name.
-#-renamesourcefileattribute SourceFile
diff --git a/FtcCommon/src/main/AndroidManifest.xml b/FtcCommon/src/main/AndroidManifest.xml
index 98389723..a1a36cb1 100644
--- a/FtcCommon/src/main/AndroidManifest.xml
+++ b/FtcCommon/src/main/AndroidManifest.xml
@@ -1,7 +1,6 @@
-
+
-
\ No newline at end of file
+
diff --git a/FtcRobotController/build.gradle b/FtcRobotController/build.gradle
index fc521b5a..b271b761 100644
--- a/FtcRobotController/build.gradle
+++ b/FtcRobotController/build.gradle
@@ -1,33 +1,17 @@
import java.text.SimpleDateFormat
+//
+// build.gradle in FtcRobotController
+//
apply plugin: 'com.android.library'
-
-android.buildFeatures.buildConfig true
+apply from: '../build.androidVersionCommon.gradle'
android {
-
- namespace 'com.qualcomm.ftcrobotcontroller'
-
- compileSdkVersion 29
-
defaultConfig {
- minSdkVersion 23
- targetSdkVersion 28
- versionCode 56
- versionName "11.0"
-
buildConfigField "String", "APP_BUILD_TIME", '"' + (new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.ROOT).format(new Date())) + '"'
}
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
- }
- }
-
- ndkVersion '21.3.6528147'
-
+ namespace 'com.qualcomm.ftcrobotcontroller'
}
dependencies {
diff --git a/FtcRobotController/proguard-rules.pro b/FtcRobotController/proguard-rules.pro
deleted file mode 100644
index f1b42451..00000000
--- a/FtcRobotController/proguard-rules.pro
+++ /dev/null
@@ -1,21 +0,0 @@
-# Add project specific ProGuard rules here.
-# You can control the set of applied configuration files using the
-# proguardFiles setting in build.gradle.
-#
-# For more details, see
-# http://developer.android.com/guide/developing/tools/proguard.html
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-# public *;
-#}
-
-# Uncomment this to preserve the line number information for
-# debugging stack traces.
-#-keepattributes SourceFile,LineNumberTable
-
-# If you keep the line number information, uncomment this to
-# hide the original source file name.
-#-renamesourcefileattribute SourceFile
diff --git a/FtcRobotController/src/main/AndroidManifest.xml b/FtcRobotController/src/main/AndroidManifest.xml
index 99420297..4c585768 100644
--- a/FtcRobotController/src/main/AndroidManifest.xml
+++ b/FtcRobotController/src/main/AndroidManifest.xml
@@ -1,9 +1,8 @@
+ android:versionCode="61"
+ android:versionName="11.1">
diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptAprilTag.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptAprilTag.java
index 8ec77dd8..4ee7ffef 100644
--- a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptAprilTag.java
+++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptAprilTag.java
@@ -92,24 +92,22 @@ public void runOpMode() {
telemetry.update();
waitForStart();
- if (opModeIsActive()) {
- while (opModeIsActive()) {
+ while (opModeIsActive()) {
- telemetryAprilTag();
+ telemetryAprilTag();
- // Push telemetry to the Driver Station.
- telemetry.update();
+ // Push telemetry to the Driver Station.
+ telemetry.update();
- // Save CPU resources; can resume streaming when needed.
- if (gamepad1.dpad_down) {
- visionPortal.stopStreaming();
- } else if (gamepad1.dpad_up) {
- visionPortal.resumeStreaming();
- }
-
- // Share the CPU.
- sleep(20);
+ // Save CPU resources; can resume streaming when needed.
+ if (gamepad1.dpad_down) {
+ visionPortal.stopStreaming();
+ } else if (gamepad1.dpad_up) {
+ visionPortal.resumeStreaming();
}
+
+ // Share the CPU.
+ sleep(20);
}
// Save more CPU resources when camera is no longer needed.
diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptAprilTagEasy.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptAprilTagEasy.java
index 12dcf6e9..7bda71b4 100644
--- a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptAprilTagEasy.java
+++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptAprilTagEasy.java
@@ -88,24 +88,22 @@ public void runOpMode() {
telemetry.update();
waitForStart();
- if (opModeIsActive()) {
- while (opModeIsActive()) {
+ while (opModeIsActive()) {
- telemetryAprilTag();
+ telemetryAprilTag();
- // Push telemetry to the Driver Station.
- telemetry.update();
+ // Push telemetry to the Driver Station.
+ telemetry.update();
- // Save CPU resources; can resume streaming when needed.
- if (gamepad1.dpad_down) {
- visionPortal.stopStreaming();
- } else if (gamepad1.dpad_up) {
- visionPortal.resumeStreaming();
- }
-
- // Share the CPU.
- sleep(20);
+ // Save CPU resources; can resume streaming when needed.
+ if (gamepad1.dpad_down) {
+ visionPortal.stopStreaming();
+ } else if (gamepad1.dpad_up) {
+ visionPortal.resumeStreaming();
}
+
+ // Share the CPU.
+ sleep(20);
}
// Save more CPU resources when camera is no longer needed.
diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptAprilTagSwitchableCameras.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptAprilTagSwitchableCameras.java
index 7ee1064b..02e83d37 100644
--- a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptAprilTagSwitchableCameras.java
+++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptAprilTagSwitchableCameras.java
@@ -81,27 +81,25 @@ public void runOpMode() {
telemetry.update();
waitForStart();
- if (opModeIsActive()) {
- while (opModeIsActive()) {
+ while (opModeIsActive()) {
- telemetryCameraSwitching();
- telemetryAprilTag();
+ telemetryCameraSwitching();
+ telemetryAprilTag();
- // Push telemetry to the Driver Station.
- telemetry.update();
+ // Push telemetry to the Driver Station.
+ telemetry.update();
- // Save CPU resources; can resume streaming when needed.
- if (gamepad1.dpad_down) {
- visionPortal.stopStreaming();
- } else if (gamepad1.dpad_up) {
- visionPortal.resumeStreaming();
- }
+ // Save CPU resources; can resume streaming when needed.
+ if (gamepad1.dpad_down) {
+ visionPortal.stopStreaming();
+ } else if (gamepad1.dpad_up) {
+ visionPortal.resumeStreaming();
+ }
- doCameraSwitching();
+ doCameraSwitching();
- // Share the CPU.
- sleep(20);
- }
+ // Share the CPU.
+ sleep(20);
}
// Save more CPU resources when camera is no longer needed.
diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptGamepadEdgeDetection.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptGamepadEdgeDetection.java
index 90243ac5..d3c4417a 100644
--- a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptGamepadEdgeDetection.java
+++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptGamepadEdgeDetection.java
@@ -83,6 +83,22 @@ public void telemetryButtonData() {
telemetry.addData("Gamepad 1 Right Bumper Released", gamepad1.rightBumperWasReleased());
telemetry.addData("Gamepad 1 Right Bumper Status", gamepad1.right_bumper);
+ // Add an empty line to separate the buttons in telemetry
+ telemetry.addLine();
+
+ // Add the status of the Gamepad 1 Left trigger
+ telemetry.addData("Gamepad 1 Left Trigger Pressed", gamepad1.leftTriggerWasPressed());
+ telemetry.addData("Gamepad 1 Left Trigger Released", gamepad1.leftTriggerWasReleased());
+ telemetry.addData("Gamepad 1 Left Trigger Status", gamepad1.left_trigger_pressed);
+
+ // Add an empty line to separate the buttons in telemetry
+ telemetry.addLine();
+
+ // Add the status of the Gamepad 1 Right trigger
+ telemetry.addData("Gamepad 1 Right Trigger Pressed", gamepad1.rightTriggerWasPressed());
+ telemetry.addData("Gamepad 1 Right Trigger Released", gamepad1.rightTriggerWasReleased());
+ telemetry.addData("Gamepad 1 Right Trigger Status", gamepad1.right_trigger_pressed);
+
// Add a note that the telemetry is only updated every 2 seconds
telemetry.addLine("\nTelemetry is updated every 2 seconds.");
diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/externalhardware/ConceptExternalHardwareClass.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/externalhardware/ConceptExternalHardwareClass.java
index 7a721fef..cee35f64 100644
--- a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/externalhardware/ConceptExternalHardwareClass.java
+++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/externalhardware/ConceptExternalHardwareClass.java
@@ -27,7 +27,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-package org.firstinspires.ftc.robotcontroller.external.samples;
+package org.firstinspires.ftc.robotcontroller.external.samples.externalhardware;
import com.qualcomm.robotcore.eventloop.opmode.Disabled;
import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;
diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/externalhardware/RobotHardware.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/externalhardware/RobotHardware.java
index b1c8de62..64f2206f 100644
--- a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/externalhardware/RobotHardware.java
+++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/externalhardware/RobotHardware.java
@@ -27,7 +27,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-package org.firstinspires.ftc.robotcontroller.external.samples;
+package org.firstinspires.ftc.robotcontroller.external.samples.externalhardware;
import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;
import com.qualcomm.robotcore.hardware.DcMotor;
diff --git a/Hardware/build.gradle b/Hardware/build.gradle
index 56feae08..3992e2fa 100644
--- a/Hardware/build.gradle
+++ b/Hardware/build.gradle
@@ -1,31 +1,13 @@
apply plugin: 'com.android.library'
-
-android.buildFeatures.buildConfig true
+apply from: '../build.androidVersionCommon.gradle'
android {
-
namespace 'com.qualcomm.hardware'
- compileSdkVersion 29
-
- defaultConfig {
- minSdkVersion 23
- targetSdkVersion 28
- versionCode 110
- versionName "22.1"
+ defaultConfig {
+ versionCode 115
+ versionName "23.1"
}
-
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
- }
- }
- compileOptions {
- sourceCompatibility JavaVersion.VERSION_1_8
- targetCompatibility JavaVersion.VERSION_1_8
- }
-
}
dependencies {
diff --git a/Hardware/proguard-rules.pro b/Hardware/proguard-rules.pro
deleted file mode 100644
index f1b42451..00000000
--- a/Hardware/proguard-rules.pro
+++ /dev/null
@@ -1,21 +0,0 @@
-# Add project specific ProGuard rules here.
-# You can control the set of applied configuration files using the
-# proguardFiles setting in build.gradle.
-#
-# For more details, see
-# http://developer.android.com/guide/developing/tools/proguard.html
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-# public *;
-#}
-
-# Uncomment this to preserve the line number information for
-# debugging stack traces.
-#-keepattributes SourceFile,LineNumberTable
-
-# If you keep the line number information, uncomment this to
-# hide the original source file name.
-#-renamesourcefileattribute SourceFile
diff --git a/Hardware/src/main/AndroidManifest.xml b/Hardware/src/main/AndroidManifest.xml
index b50472e5..9a40236b 100644
--- a/Hardware/src/main/AndroidManifest.xml
+++ b/Hardware/src/main/AndroidManifest.xml
@@ -1,5 +1,3 @@
-
-
-
\ No newline at end of file
+
+
diff --git a/Hardware/src/main/java/com/qualcomm/hardware/gobilda/GoBildaPinpointDriver.java b/Hardware/src/main/java/com/qualcomm/hardware/gobilda/GoBildaPinpointDriver.java
index 0a5a592e..3d6637fd 100644
--- a/Hardware/src/main/java/com/qualcomm/hardware/gobilda/GoBildaPinpointDriver.java
+++ b/Hardware/src/main/java/com/qualcomm/hardware/gobilda/GoBildaPinpointDriver.java
@@ -23,6 +23,7 @@
package com.qualcomm.hardware.gobilda;
import static com.qualcomm.robotcore.util.TypeConversion.byteArrayToInt;
+import static com.qualcomm.robotcore.util.TypeConversion.intToByteArray;
import com.qualcomm.hardware.lynx.LynxI2cDeviceSynch;
import com.qualcomm.robotcore.hardware.I2cAddr;
@@ -30,16 +31,19 @@
import com.qualcomm.robotcore.hardware.I2cDeviceSynchSimple;
import com.qualcomm.robotcore.hardware.configuration.annotations.DeviceProperties;
import com.qualcomm.robotcore.hardware.configuration.annotations.I2cDeviceType;
-import com.qualcomm.robotcore.util.TypeConversion;
import org.firstinspires.ftc.robotcore.external.navigation.AngleUnit;
import org.firstinspires.ftc.robotcore.external.navigation.DistanceUnit;
import org.firstinspires.ftc.robotcore.external.navigation.Pose2D;
+import org.firstinspires.ftc.robotcore.external.navigation.Quaternion;
import org.firstinspires.ftc.robotcore.external.navigation.UnnormalizedAngleUnit;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Iterator;
+import java.util.stream.Stream;
@I2cDeviceType
@@ -51,6 +55,8 @@
public class GoBildaPinpointDriver extends I2cDeviceSynchDevice {
+ private int deviceID = 0;
+ private int deviceVersion = 0;
private int deviceStatus = 0;
private int loopTime = 0;
private int xEncoderValue = 0;
@@ -61,10 +67,48 @@ public class GoBildaPinpointDriver extends I2cDeviceSynchDevice RegisterType.GENERIC.length) {
+ if (computeCRC8(Arrays.copyOfRange(byteArray, 0, RegisterType.GENERIC.length)) == byteArray[(RegisterType.GENERIC.length + CRC_SIZE) - 1]) {
+ return true;
+ } else {
+ deviceStatus = DeviceStatus.FAULT_BAD_READ.status;
+ return false;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Computes the correct CRC8 for a byteArray.
+ *
+ * @param byteArray data to check
+ * @return byte to compare against received CRC.
+ */
+ private byte computeCRC8(byte[] byteArray) {
+ byte crc = CRC_INITIAL_VALUE;
+
+ for (byte b : byteArray) {
+ crc ^= b;
+ for (int i = 0; i < 8; i++) {
+ if ((crc & 0x80) != 0) {
+ crc = (byte) ((crc << 1) ^ CRC_POLYNOMIAL_VALUE);
+ } else {
+ crc <<= 1;
+ }
+ }
+ }
+ return (byte) (crc ^ CRC_FINAL_XOR_VALUE);
+ }
+
/**
* Confirm that the number received is a number, and does not include a change above the threshold
*
@@ -310,9 +541,9 @@ private Float isPositionCorrupt(float oldValue, float newValue, int threshold, b
* @param threshold the velocity allowed to be reported
* @return newValue if the velocity is good, oldValue otherwise
*/
- private Float isVelocityCorrupt(float oldValue, float newValue, int threshold) {
- boolean isCorrupt = Float.isNaN(newValue) || Math.abs(newValue) > threshold;
- boolean noData = (loopTime <= 1);
+ private Float isVelocityCorrupt(float oldValue, float newValue, int threshold, boolean bulkUpdate) {
+ boolean noData = bulkUpdate && (loopTime <= 1);
+ boolean isCorrupt = noData || Float.isNaN(newValue) || Math.abs(newValue) > threshold;
if (!isCorrupt) {
return newValue;
@@ -323,9 +554,42 @@ private Float isVelocityCorrupt(float oldValue, float newValue, int threshold) {
}
/**
- * Call this once per loop to read new data from the Odometry Computer. Data will only update once this is called.
+ * Reads the BULK_READ register depending on how the bulkReadScope is configured and saves data to local variables.
+ * if CRC is enabled, and a bad CRC is detected on the BulkRead, then no data will be saved.
*/
- public void update() {
+ private void flexBulkRead() {
+ byte[] bArr;
+
+ if (errorDetectionType == ErrorDetectionType.CRC) {
+ bArr = deviceClient.read(Register.BULK_READ.bVal, (bulkReadScope.length * RegisterType.GENERIC.length) + CRC_SIZE);
+ if (!checkCRC(bArr, RegisterType.BULK)) {
+ return;
+ }
+ } else {
+ bArr = deviceClient.read(Register.BULK_READ.bVal, (bulkReadScope.length * RegisterType.GENERIC.length));
+ }
+
+ for (int i = 0; i < bulkReadScope.length; i++) {
+ int index = i * RegisterType.GENERIC.length;
+ switch (bulkReadScope[i].registerType) {
+ case INT32:
+ int dataI = byteArrayToInt(Arrays.copyOfRange(bArr, index, index + bulkReadScope[i].registerType.length), ByteOrder.LITTLE_ENDIAN);
+ saveData(bulkReadScope[i], dataI, 0);
+ break;
+ case FLOAT:
+ float dataF = byteArrayToFloat(Arrays.copyOfRange(bArr, index, index + bulkReadScope[i].registerType.length), ByteOrder.LITTLE_ENDIAN);
+ saveData(bulkReadScope[i], 0, dataF);
+ break;
+ }
+ }
+ }
+
+ /**
+ * For devices with version 1 or version 2 firmware, this reads a fixed length BULK_READ register.
+ * A warning is thrown if CRC is requested as CRC was not enabled on V1 or V2 devices.
+ */
+ private void fixedBulkRead() {
+
final int positionThreshold = 5000; //more than one FTC field in mm
final int headingThreshold = 120; //About 20 full rotations in Radians
final int velocityThreshold = 10000; //10k mm/sec is faster than an FTC robot should be going...
@@ -350,17 +614,69 @@ public void update() {
yVelocity = byteArrayToFloat(Arrays.copyOfRange(bArr, 32, 36), ByteOrder.LITTLE_ENDIAN);
hVelocity = byteArrayToFloat(Arrays.copyOfRange(bArr, 36, 40), ByteOrder.LITTLE_ENDIAN);
- /*
- * Check to see if any of the floats we have received from the device are NaN or are too large
- * if they are, we return the previously read value and alert the user via the DeviceStatus Enum.
- */
- xPosition = isPositionCorrupt(oldPosX, xPosition, positionThreshold, true);
- yPosition = isPositionCorrupt(oldPosY, yPosition, positionThreshold, true);
- hOrientation = isPositionCorrupt(oldPosH, hOrientation, headingThreshold, true);
- xVelocity = isVelocityCorrupt(oldVelX, xVelocity, velocityThreshold);
- yVelocity = isVelocityCorrupt(oldVelY, yVelocity, velocityThreshold);
- hVelocity = isVelocityCorrupt(oldVelH, hVelocity, headingVelocityThreshold);
+ switch (errorDetectionType) {
+ case CRC:
+ throw new RuntimeException("CRC Error Handling Not Supported by this Firmware");
+ case LOCAL_TEST:
+ /*
+ * Check to see if any of the floats we have received from the device are NaN or are too large
+ * if they are, we return the previously read value and alert the user via the DeviceStatus Enum.
+ */
+ xPosition = isPositionCorrupt(oldPosX, xPosition, positionThreshold, true);
+ yPosition = isPositionCorrupt(oldPosY, yPosition, positionThreshold, true);
+ hOrientation = isPositionCorrupt(oldPosH, hOrientation, headingThreshold, true);
+ xVelocity = isVelocityCorrupt(oldVelX, xVelocity, velocityThreshold, true);
+ yVelocity = isVelocityCorrupt(oldVelY, yVelocity, velocityThreshold, true);
+ hVelocity = isVelocityCorrupt(oldVelH, hVelocity, headingVelocityThreshold, true);
+ break;
+ }
+ }
+ /**
+ * Reads a register and saves the data found there to the local variable. Uses either CRC or Local error detection.
+ *
+ * @param register register to read
+ */
+ private void readRegister(Register register) {
+ boolean checkCRC = (errorDetectionType == ErrorDetectionType.CRC);
+
+ byte[] temp = deviceClient.read(register.bVal, RegisterType.GENERIC.length + CRC_SIZE);
+
+ switch (register.registerType) {
+ case INT32:
+ if (checkCRC(temp, RegisterType.INT32) || !checkCRC) {
+ saveData(register, byteArrayToInt(Arrays.copyOfRange(temp, 0, RegisterType.INT32.length), ByteOrder.LITTLE_ENDIAN), 0);
+ } else {
+ deviceStatus = DeviceStatus.FAULT_BAD_READ.status;
+ }
+ break;
+ case FLOAT:
+ if (checkCRC(temp, RegisterType.FLOAT) || !checkCRC) {
+ saveData(register, 0, byteArrayToFloat(Arrays.copyOfRange(temp, 0, RegisterType.FLOAT.length), ByteOrder.LITTLE_ENDIAN));
+ } else {
+ deviceStatus = DeviceStatus.FAULT_BAD_READ.status;
+ }
+ break;
+ case BULK:
+ update();
+ break;
+ }
+ }
+
+ /**
+ * Call this once per loop to read new data from the Odometry Computer. Data will only update once this is called.
+ */
+ public void update() {
+ if (deviceVersion == 0) {
+ getDeviceVersion(); // Makes sure device version has been read
+ }
+
+ if (deviceVersion == 1 || deviceVersion == 2) {
+ fixedBulkRead();
+ }
+ if (deviceVersion >= 3) {
+ flexBulkRead();
+ }
}
/**
@@ -386,6 +702,50 @@ public void update(ReadData data) {
}
}
+ /**
+ * Only supported on V3 firmware and above. This configures the registers that are read in bulk
+ * when .update() is called. Use this to minimize read times based on your unique application.
+ *
+ * @param registers An array of registers, add registers that you need data from frequently.
+ */
+ public void setBulkReadScope(Register... registers) {
+
+ if (deviceVersion == 0) {
+ deviceVersion = readInt(Register.DEVICE_VERSION);
+ }
+ if (deviceVersion == 1 || deviceVersion == 2) {
+ throw new RuntimeException(".setBulkReadScope is not supported by this device firmware.");
+ }
+ if (deviceVersion >= 3) {
+ bulkReadScope = registers.clone();
+
+ Stream reg = Arrays.stream(registers).distinct();
+ ArrayList arrayList = new ArrayList<>(registers.length);
+
+ Iterator iter = reg.iterator();
+ while (iter.hasNext()) {
+ arrayList.add((byte) iter.next().bVal);
+ }
+
+ byte[] arr = new byte[arrayList.size()];
+ for (int i = 0; i < arrayList.size(); i++) {
+ arr[i] = arrayList.get(i);
+ }
+ writeByteArray(Register.SET_BULK_READ, arr); //write all registers sequentially
+ }
+ }
+
+ /**
+ * The kind of error correction used on the I²C communication from the device.
+ * NONE: This does not check the data, and passes it directly to the user.
+ * CRC: This uses CRC8 error detection to catch incorrect reads. - Only supported by devices with V3 firmware or newer.
+ * LOCAL_TEST: "Controller only" validation that ensures that the data is !NAN, is not all zeros, and is a reasonable number.
+ * This is faster than CRC but may not catch every erroneous read.
+ */
+ public void setErrorDetectionType(ErrorDetectionType e) {
+ errorDetectionType = e;
+ }
+
/**
* Sets the odometry pod positions relative to the point that the odometry computer tracks around.
* The most common tracking position is the center of the robot.
@@ -461,11 +821,11 @@ public void setEncoderResolution(GoBildaOdometryPods pods) {
* You can find this number by dividing the counts-per-revolution of your encoder by the circumference of the wheel.
*
* @param ticksPerUnit should be somewhere between 10 ticks/mm and 100 ticks/mm a goBILDA Swingarm pod is ~13.26291192
- * @param distanceUnit unit used for distance
+ * @param distanceUnit unit used for distance
*/
public void setEncoderResolution(double ticksPerUnit, DistanceUnit distanceUnit) {
- double resolution = distanceUnit.toMm(ticksPerUnit);
- writeByteArray(Register.TICKS_PER_MM, (floatToByteArray((float) resolution, ByteOrder.LITTLE_ENDIAN)));
+ double resolution = 1.0 / distanceUnit.toMm(1.0 / ticksPerUnit);
+ writeByteArray(Register.MM_PER_TICK, (floatToByteArray((float) resolution, ByteOrder.LITTLE_ENDIAN)));
}
/**
@@ -553,21 +913,30 @@ public void setHeading(double heading, AngleUnit angleUnit) {
* @return 1 if device is functional.
*/
public int getDeviceID() {
- return readInt(Register.DEVICE_ID);
+ if (registerNotInBulkRead(Register.DEVICE_ID)) {
+ readRegister(Register.DEVICE_ID);
+ }
+ return deviceID;
}
/**
* @return the firmware version of the Odometry Computer
*/
public int getDeviceVersion() {
- return readInt(Register.DEVICE_VERSION);
+ if (registerNotInBulkRead(Register.DEVICE_VERSION)) {
+ readRegister(Register.DEVICE_VERSION);
+ }
+ return deviceVersion;
}
/**
* @return a scalar that the IMU measured heading is multiplied by.
*/
public float getYawScalar() {
- return readFloat(Register.YAW_SCALAR);
+ if (registerNotInBulkRead(Register.YAW_SCALAR)) {
+ readRegister(Register.YAW_SCALAR);
+ }
+ return yawScalar;
}
/**
@@ -615,6 +984,9 @@ public double getFrequency() {
* @return the raw value of the X (forward) encoder in ticks
*/
public int getEncoderX() {
+ if (registerNotInBulkRead(Register.X_ENCODER_VALUE)) {
+ readRegister(Register.X_ENCODER_VALUE);
+ }
return xEncoderValue;
}
@@ -622,6 +994,9 @@ public int getEncoderX() {
* @return the raw value of the Y (strafe) encoder in ticks
*/
public int getEncoderY() {
+ if (registerNotInBulkRead(Register.Y_ENCODER_VALUE)) {
+ readRegister(Register.Y_ENCODER_VALUE);
+ }
return yEncoderValue;
}
@@ -630,6 +1005,9 @@ public int getEncoderY() {
* @return the estimated X (forward) position of the robot in specified unit
*/
public double getPosX(DistanceUnit distanceUnit) {
+ if (registerNotInBulkRead(Register.X_POSITION)) {
+ readRegister(Register.X_POSITION);
+ }
return distanceUnit.fromMm(xPosition);
}
@@ -638,6 +1016,9 @@ public double getPosX(DistanceUnit distanceUnit) {
* @return the estimated Y (Strafe) position of the robot in specified unit
*/
public double getPosY(DistanceUnit distanceUnit) {
+ if (registerNotInBulkRead(Register.Y_POSITION)) {
+ readRegister(Register.Y_POSITION);
+ }
return distanceUnit.fromMm(yPosition);
}
@@ -646,6 +1027,9 @@ public double getPosY(DistanceUnit distanceUnit) {
* normalized heading is wrapped from -180°, to 180°.
*/
public double getHeading(AngleUnit angleUnit) {
+ if (registerNotInBulkRead(Register.H_ORIENTATION)) {
+ readRegister(Register.H_ORIENTATION);
+ }
return angleUnit.fromRadians(hOrientation);
}
@@ -655,6 +1039,9 @@ public double getHeading(AngleUnit angleUnit) {
* multiple rotations.
*/
public double getHeading(UnnormalizedAngleUnit unnormalizedAngleUnit) {
+ if (registerNotInBulkRead(Register.H_ORIENTATION)) {
+ readRegister(Register.H_ORIENTATION);
+ }
return unnormalizedAngleUnit.fromRadians(hOrientation);
}
@@ -662,6 +1049,9 @@ public double getHeading(UnnormalizedAngleUnit unnormalizedAngleUnit) {
* @return the estimated X (forward) velocity of the robot in specified unit/sec
*/
public double getVelX(DistanceUnit distanceUnit) {
+ if (registerNotInBulkRead(Register.X_VELOCITY)) {
+ readRegister(Register.X_VELOCITY);
+ }
return distanceUnit.fromMm(xVelocity);
}
@@ -669,6 +1059,9 @@ public double getVelX(DistanceUnit distanceUnit) {
* @return the estimated Y (strafe) velocity of the robot in specified unit/sec
*/
public double getVelY(DistanceUnit distanceUnit) {
+ if (registerNotInBulkRead(Register.Y_VELOCITY)) {
+ readRegister(Register.Y_VELOCITY);
+ }
return distanceUnit.fromMm(yVelocity);
}
@@ -676,6 +1069,9 @@ public double getVelY(DistanceUnit distanceUnit) {
* @return the estimated H (heading) velocity of the robot in specified unit/sec
*/
public double getHeadingVelocity(UnnormalizedAngleUnit unnormalizedAngleUnit) {
+ if (registerNotInBulkRead(Register.H_VELOCITY)) {
+ readRegister(Register.H_VELOCITY);
+ }
return unnormalizedAngleUnit.fromRadians(hVelocity);
}
@@ -685,7 +1081,10 @@ public double getHeadingVelocity(UnnormalizedAngleUnit unnormalizedAngleUnit) {
* @return the user-set offset for the X (forward) pod in specified unit
*/
public float getXOffset(DistanceUnit distanceUnit) {
- return (float) distanceUnit.fromMm(readFloat(Register.X_POD_OFFSET));
+ if (registerNotInBulkRead(Register.X_POD_OFFSET)) {
+ readRegister(Register.X_POD_OFFSET);
+ }
+ return (float) distanceUnit.fromMm(xPodOffset);
}
/**
@@ -694,22 +1093,90 @@ public float getXOffset(DistanceUnit distanceUnit) {
* @return the user-set offset for the Y (strafe) pod
*/
public float getYOffset(DistanceUnit distanceUnit) {
- return (float) distanceUnit.fromMm(readFloat(Register.Y_POD_OFFSET));
+ if (registerNotInBulkRead(Register.Y_POD_OFFSET)) {
+ readRegister(Register.Y_POD_OFFSET);
+ }
+ return (float) distanceUnit.fromMm(yPodOffset);
}
/**
* @return a Pose2D containing the estimated position of the robot
*/
public Pose2D getPosition() {
+ if (registerNotInBulkRead(Register.X_POSITION)) {
+ readRegister(Register.X_POSITION);
+ }
+ if (registerNotInBulkRead(Register.Y_POSITION)) {
+ readRegister(Register.Y_POSITION);
+ }
+ if (registerNotInBulkRead(Register.H_ORIENTATION)) {
+ readRegister(Register.H_ORIENTATION);
+ }
return new Pose2D(DistanceUnit.MM,
xPosition,
yPosition,
AngleUnit.RADIANS,
AngleUnit.normalizeRadians(hOrientation));
}
-}
-
+ /**
+ * @return a Quaternion which describes the 3d orientation of the device.
+ */
+ public Quaternion getQuaternion() {
+ if (deviceVersion == 0) {
+ readInt(Register.DEVICE_VERSION);
+ }
+ if (deviceVersion == 1 || deviceVersion == 2) {
+ throw new RuntimeException("Quaternion output is not supported on this device firmware");
+ } else {
+ if (registerNotInBulkRead(Register.QUATERNION_W)) {
+ readRegister(Register.QUATERNION_W);
+ }
+ if (registerNotInBulkRead(Register.QUATERNION_X)) {
+ readRegister(Register.QUATERNION_X);
+ }
+ if (registerNotInBulkRead(Register.QUATERNION_Y)) {
+ readRegister(Register.QUATERNION_Y);
+ }
+ if (registerNotInBulkRead(Register.QUATERNION_Z)) {
+ readRegister(Register.QUATERNION_Z);
+ }
+ return new Quaternion(quaternionW, quaternionX, quaternionY, quaternionZ, 0);
+ }
+ }
+ /**
+ * @return the current pitch of the device in the specified AngleUnit.
+ */
+ public double getPitch(AngleUnit angleUnit) {
+ if (deviceVersion == 0) {
+ readInt(Register.DEVICE_VERSION);
+ }
+ if (deviceVersion == 1 || deviceVersion == 2) {
+ throw new RuntimeException("IMU Pitch output is not supported on this device firmware");
+ } else {
+ if (registerNotInBulkRead(Register.PITCH)) {
+ pitch = readFloat(Register.PITCH);
+ }
+ return angleUnit.fromRadians(pitch);
+ }
+ }
+ /**
+ * @return the current roll of the device in the specified AngleUnit.
+ */
+ public double getRoll(AngleUnit angleUnit) {
+ if (deviceVersion == 0) {
+ readInt(Register.DEVICE_VERSION);
+ }
+ if (deviceVersion == 1 || deviceVersion == 2) {
+ throw new RuntimeException("IMU Roll output is not supported on this device firmware");
+ } else {
+ if (registerNotInBulkRead(Register.ROLL)) {
+ roll = readFloat(Register.ROLL);
+ }
+ return angleUnit.fromRadians(roll);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Inspection/build.gradle b/Inspection/build.gradle
index ac05f601..11aa5ec3 100644
--- a/Inspection/build.gradle
+++ b/Inspection/build.gradle
@@ -1,27 +1,13 @@
apply plugin: 'com.android.library'
-
-android.buildFeatures.buildConfig true
+apply from: '../build.androidVersionCommon.gradle'
android {
-
namespace 'org.firstinspires.inspection'
- compileSdkVersion 29
-
defaultConfig {
- minSdkVersion 23
- targetSdkVersion 28
- versionCode 110
- versionName "22.1"
+ versionCode 115
+ versionName "23.1"
}
-
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
- }
- }
-
}
dependencies {
diff --git a/Inspection/proguard-rules.pro b/Inspection/proguard-rules.pro
deleted file mode 100644
index f1b42451..00000000
--- a/Inspection/proguard-rules.pro
+++ /dev/null
@@ -1,21 +0,0 @@
-# Add project specific ProGuard rules here.
-# You can control the set of applied configuration files using the
-# proguardFiles setting in build.gradle.
-#
-# For more details, see
-# http://developer.android.com/guide/developing/tools/proguard.html
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-# public *;
-#}
-
-# Uncomment this to preserve the line number information for
-# debugging stack traces.
-#-keepattributes SourceFile,LineNumberTable
-
-# If you keep the line number information, uncomment this to
-# hide the original source file name.
-#-renamesourcefileattribute SourceFile
diff --git a/Inspection/src/main/AndroidManifest.xml b/Inspection/src/main/AndroidManifest.xml
index 3b2f3b1e..db0ba2be 100644
--- a/Inspection/src/main/AndroidManifest.xml
+++ b/Inspection/src/main/AndroidManifest.xml
@@ -1,6 +1,5 @@
-
+
@@ -23,4 +22,4 @@
-
\ No newline at end of file
+
diff --git a/OnBotJava/build.gradle b/OnBotJava/build.gradle
index b234a06e..20d8a5be 100644
--- a/OnBotJava/build.gradle
+++ b/OnBotJava/build.gradle
@@ -1,31 +1,13 @@
apply plugin: 'com.android.library'
-
-android.buildFeatures.buildConfig true
+apply from: '../build.androidVersionCommon.gradle'
android {
-
namespace 'com.google.blocks.ftcrobotcontroller.onbotjava'
- compileSdkVersion 29
-
defaultConfig {
- minSdkVersion 23
- targetSdkVersion 28
- versionCode 70
- versionName "14.1"
+ versionCode 75
+ versionName "15.1"
}
-
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
- }
- }
- compileOptions {
- sourceCompatibility JavaVersion.VERSION_1_8
- targetCompatibility JavaVersion.VERSION_1_8
- }
-
}
dependencies {
diff --git a/OnBotJava/libs/javac.jar b/OnBotJava/libs/javac.jar
index 94669ab5..54a9749e 100644
Binary files a/OnBotJava/libs/javac.jar and b/OnBotJava/libs/javac.jar differ
diff --git a/OnBotJava/proguard-rules.pro b/OnBotJava/proguard-rules.pro
deleted file mode 100644
index f1b42451..00000000
--- a/OnBotJava/proguard-rules.pro
+++ /dev/null
@@ -1,21 +0,0 @@
-# Add project specific ProGuard rules here.
-# You can control the set of applied configuration files using the
-# proguardFiles setting in build.gradle.
-#
-# For more details, see
-# http://developer.android.com/guide/developing/tools/proguard.html
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-# public *;
-#}
-
-# Uncomment this to preserve the line number information for
-# debugging stack traces.
-#-keepattributes SourceFile,LineNumberTable
-
-# If you keep the line number information, uncomment this to
-# hide the original source file name.
-#-renamesourcefileattribute SourceFile
diff --git a/OnBotJava/src/main/AndroidManifest.xml b/OnBotJava/src/main/AndroidManifest.xml
index c3045cd3..86fee1e7 100644
--- a/OnBotJava/src/main/AndroidManifest.xml
+++ b/OnBotJava/src/main/AndroidManifest.xml
@@ -31,7 +31,6 @@
~ TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
~ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-->
-
+
-
\ No newline at end of file
+
diff --git a/OnBotJava/src/main/assets/java/js/worker/index.js b/OnBotJava/src/main/assets/java/js/worker/index.js
index b8102f63..27d0a6d0 100644
--- a/OnBotJava/src/main/assets/java/js/worker/index.js
+++ b/OnBotJava/src/main/assets/java/js/worker/index.js
@@ -1,7 +1,7 @@
-(()=>{var X1=Object.create;var fs=Object.defineProperty,J1=Object.defineProperties,Q1=Object.getOwnPropertyDescriptor,Z1=Object.getOwnPropertyDescriptors,e4=Object.getOwnPropertyNames,jl=Object.getOwnPropertySymbols,t4=Object.getPrototypeOf,Ul=Object.prototype.hasOwnProperty,n4=Object.prototype.propertyIsEnumerable;var Vl=(h,k,G)=>k in h?fs(h,k,{enumerable:!0,configurable:!0,writable:!0,value:G}):h[k]=G,Zo=(h,k)=>{for(var G in k||(k={}))Ul.call(k,G)&&Vl(h,G,k[G]);if(jl)for(var G of jl(k))n4.call(k,G)&&Vl(h,G,k[G]);return h},es=(h,k)=>J1(h,Z1(k)),zl=h=>fs(h,"__esModule",{value:!0}),c=(h,k)=>fs(h,"name",{value:k,configurable:!0}),ts=(h=>typeof require!="undefined"?require:typeof Proxy!="undefined"?new Proxy(h,{get:(k,G)=>(typeof require!="undefined"?require:k)[G]}):h)(function(h){if(typeof require!="undefined")return require.apply(this,arguments);throw new Error('Dynamic require of "'+h+'" is not supported')});var fr=(h,k)=>()=>(k||h((k={exports:{}}).exports,k),k.exports),Ba=(h,k)=>{zl(h);for(var G in k)fs(h,G,{get:k[G],enumerable:!0})},r4=(h,k,G)=>{if(k&&typeof k=="object"||typeof k=="function")for(let T of e4(k))!Ul.call(h,T)&&T!=="default"&&fs(h,T,{get:()=>k[T],enumerable:!(G=Q1(k,T))||G.enumerable});return h},zn=h=>r4(zl(fs(h!=null?X1(t4(h)):{},"default",h&&h.__esModule&&"default"in h?{get:()=>h.default,enumerable:!0}:{value:h,enumerable:!0})),h);var Ji=fr((Kl,Ks)=>{(function(h,k){"use strict";typeof Ks=="object"&&typeof Ks.exports=="object"?Ks.exports=h.document?k(h,!0):function(G){if(!G.document)throw new Error("jQuery requires a window with a document");return k(G)}:k(h)})(typeof window!="undefined"?window:Kl,function(h,k){"use strict";var G=[],T=Object.getPrototypeOf,m=G.slice,a=G.flat?function(A){return G.flat.call(A)}:function(A){return G.concat.apply([],A)},o=G.push,s=G.indexOf,r={},i=r.toString,n=r.hasOwnProperty,t=n.toString,e=t.call(Object),d={},f=c(function(B){return typeof B=="function"&&typeof B.nodeType!="number"&&typeof B.item!="function"},"isFunction"),p=c(function(B){return B!=null&&B===B.window},"isWindow"),l=h.document,v={type:!0,src:!0,nonce:!0,noModule:!0};function y(A,B,j){j=j||l;var K,se,ae=j.createElement("script");if(ae.text=A,B)for(K in v)se=B[K]||B.getAttribute&&B.getAttribute(K),se&&ae.setAttribute(K,se);j.head.appendChild(ae).parentNode.removeChild(ae)}c(y,"DOMEval");function b(A){return A==null?A+"":typeof A=="object"||typeof A=="function"?r[i.call(A)]||"object":typeof A}c(b,"toType");var x="3.6.4",g=c(function(A,B){return new g.fn.init(A,B)},"jQuery");g.fn=g.prototype={jquery:x,constructor:g,length:0,toArray:function(){return m.call(this)},get:function(A){return A==null?m.call(this):A<0?this[A+this.length]:this[A]},pushStack:function(A){var B=g.merge(this.constructor(),A);return B.prevObject=this,B},each:function(A){return g.each(this,A)},map:function(A){return this.pushStack(g.map(this,function(B,j){return A.call(B,j,B)}))},slice:function(){return this.pushStack(m.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},even:function(){return this.pushStack(g.grep(this,function(A,B){return(B+1)%2}))},odd:function(){return this.pushStack(g.grep(this,function(A,B){return B%2}))},eq:function(A){var B=this.length,j=+A+(A<0?B:0);return this.pushStack(j>=0&&j0&&B-1 in A}c(_,"isArrayLike");var S=function(A){var B,j,K,se,ae,he,He,Fe,st,vt,Ht,gt,bt,vn,w,F,O,W,z,q="sizzle"+1*new Date,oe=A.document,ge=0,de=0,Ee=rs(),Le=rs(),it=rs(),yt=rs(),Ct=c(function(ve,Pe){return ve===Pe&&(Ht=!0),0},"sortOrder"),ot={}.hasOwnProperty,qt=[],zt=qt.pop,sn=qt.push,xn=qt.push,An=qt.slice,qn=c(function(ve,Pe){for(var Je=0,Ot=ve.length;Je+~]|"+kn+")"+kn+"*"),uo=new RegExp(kn+"|>"),ne=new RegExp(Kn),ue=new RegExp("^"+xr+"$"),Re={ID:new RegExp("^#("+xr+")"),CLASS:new RegExp("^\\.("+xr+")"),TAG:new RegExp("^("+xr+"|[*])"),ATTR:new RegExp("^"+rr),PSEUDO:new RegExp("^"+Kn),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+kn+"*(even|odd|(([+-]|)(\\d*)n|)"+kn+"*(?:([+-]|)"+kn+"*(\\d+)|))"+kn+"*\\)|)","i"),bool:new RegExp("^(?:"+Mr+")$","i"),needsContext:new RegExp("^"+kn+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+kn+"*((?:-\\d)?\\d*)"+kn+"*\\)|)(?=[^-]|$)","i")},Oe=/HTML$/i,rt=/^(?:input|select|textarea|button)$/i,Qe=/^h\d$/i,Rt=/^[^{]+\{\s*\[native \w/,Yt=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,Nn=/[+~]/,rn=new RegExp("\\\\[\\da-fA-F]{1,6}"+kn+"?|\\\\([^\\r\\n\\f])","g"),vr=c(function(ve,Pe){var Je="0x"+ve.slice(1)-65536;return Pe||(Je<0?String.fromCharCode(Je+65536):String.fromCharCode(Je>>10|55296,Je&1023|56320))},"funescape"),Er=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,$n=c(function(ve,Pe){return Pe?ve==="\0"?"\uFFFD":ve.slice(0,-1)+"\\"+ve.charCodeAt(ve.length-1).toString(16)+" ":"\\"+ve},"fcssescape"),co=c(function(){gt()},"unloadHandler"),yo=bo(function(ve){return ve.disabled===!0&&ve.nodeName.toLowerCase()==="fieldset"},{dir:"parentNode",next:"legend"});try{xn.apply(qt=An.call(oe.childNodes),oe.childNodes),qt[oe.childNodes.length].nodeType}catch{xn={apply:qt.length?function(Pe,Je){sn.apply(Pe,An.call(Je))}:function(Pe,Je){for(var Ot=Pe.length,at=0;Pe[Ot++]=Je[at++];);Pe.length=Ot-1}}}function Ar(ve,Pe,Je,Ot){var at,Wt,Vt,nn,cn,Fn,In,Bn=Pe&&Pe.ownerDocument,Hn=Pe?Pe.nodeType:9;if(Je=Je||[],typeof ve!="string"||!ve||Hn!==1&&Hn!==9&&Hn!==11)return Je;if(!Ot&&(gt(Pe),Pe=Pe||bt,w)){if(Hn!==11&&(cn=Yt.exec(ve)))if(at=cn[1]){if(Hn===9)if(Vt=Pe.getElementById(at)){if(Vt.id===at)return Je.push(Vt),Je}else return Je;else if(Bn&&(Vt=Bn.getElementById(at))&&z(Pe,Vt)&&Vt.id===at)return Je.push(Vt),Je}else{if(cn[2])return xn.apply(Je,Pe.getElementsByTagName(ve)),Je;if((at=cn[3])&&j.getElementsByClassName&&Pe.getElementsByClassName)return xn.apply(Je,Pe.getElementsByClassName(at)),Je}if(j.qsa&&!yt[ve+" "]&&(!F||!F.test(ve))&&(Hn!==1||Pe.nodeName.toLowerCase()!=="object")){if(In=ve,Bn=Pe,Hn===1&&(uo.test(ve)||Ei.test(ve))){for(Bn=Nn.test(ve)&&ys(Pe.parentNode)||Pe,(Bn!==Pe||!j.scope)&&((nn=Pe.getAttribute("id"))?nn=nn.replace(Er,$n):Pe.setAttribute("id",nn=q)),Fn=he(ve),Wt=Fn.length;Wt--;)Fn[Wt]=(nn?"#"+nn:":scope")+" "+Ko(Fn[Wt]);In=Fn.join(",")}try{return xn.apply(Je,Bn.querySelectorAll(In)),Je}catch{yt(ve,!0)}finally{nn===q&&Pe.removeAttribute("id")}}}return Fe(ve.replace(Sr,"$1"),Pe,Je,Ot)}c(Ar,"Sizzle");function rs(){var ve=[];function Pe(Je,Ot){return ve.push(Je+" ")>K.cacheLength&&delete Pe[ve.shift()],Pe[Je+" "]=Ot}return c(Pe,"cache"),Pe}c(rs,"createCache");function qr(ve){return ve[q]=!0,ve}c(qr,"markFunction");function to(ve){var Pe=bt.createElement("fieldset");try{return!!ve(Pe)}catch{return!1}finally{Pe.parentNode&&Pe.parentNode.removeChild(Pe),Pe=null}}c(to,"assert");function So(ve,Pe){for(var Je=ve.split("|"),Ot=Je.length;Ot--;)K.attrHandle[Je[Ot]]=Pe}c(So,"addHandle");function Gi(ve,Pe){var Je=Pe&&ve,Ot=Je&&ve.nodeType===1&&Pe.nodeType===1&&ve.sourceIndex-Pe.sourceIndex;if(Ot)return Ot;if(Je){for(;Je=Je.nextSibling;)if(Je===Pe)return-1}return ve?1:-1}c(Gi,"siblingCheck");function vs(ve){return function(Pe){var Je=Pe.nodeName.toLowerCase();return Je==="input"&&Pe.type===ve}}c(vs,"createInputPseudo");function is(ve){return function(Pe){var Je=Pe.nodeName.toLowerCase();return(Je==="input"||Je==="button")&&Pe.type===ve}}c(is,"createButtonPseudo");function Pi(ve){return function(Pe){return"form"in Pe?Pe.parentNode&&Pe.disabled===!1?"label"in Pe?"label"in Pe.parentNode?Pe.parentNode.disabled===ve:Pe.disabled===ve:Pe.isDisabled===ve||Pe.isDisabled!==!ve&&yo(Pe)===ve:Pe.disabled===ve:"label"in Pe?Pe.disabled===ve:!1}}c(Pi,"createDisabledPseudo");function Wn(ve){return qr(function(Pe){return Pe=+Pe,qr(function(Je,Ot){for(var at,Wt=ve([],Je.length,Pe),Vt=Wt.length;Vt--;)Je[at=Wt[Vt]]&&(Je[at]=!(Ot[at]=Je[at]))})})}c(Wn,"createPositionalPseudo");function ys(ve){return ve&&typeof ve.getElementsByTagName!="undefined"&&ve}c(ys,"testContext"),j=Ar.support={},ae=Ar.isXML=function(ve){var Pe=ve&&ve.namespaceURI,Je=ve&&(ve.ownerDocument||ve).documentElement;return!Oe.test(Pe||Je&&Je.nodeName||"HTML")},gt=Ar.setDocument=function(ve){var Pe,Je,Ot=ve?ve.ownerDocument||ve:oe;return Ot==bt||Ot.nodeType!==9||!Ot.documentElement||(bt=Ot,vn=bt.documentElement,w=!ae(bt),oe!=bt&&(Je=bt.defaultView)&&Je.top!==Je&&(Je.addEventListener?Je.addEventListener("unload",co,!1):Je.attachEvent&&Je.attachEvent("onunload",co)),j.scope=to(function(at){return vn.appendChild(at).appendChild(bt.createElement("div")),typeof at.querySelectorAll!="undefined"&&!at.querySelectorAll(":scope fieldset div").length}),j.cssHas=to(function(){try{return bt.querySelector(":has(*,:jqfake)"),!1}catch{return!0}}),j.attributes=to(function(at){return at.className="i",!at.getAttribute("className")}),j.getElementsByTagName=to(function(at){return at.appendChild(bt.createComment("")),!at.getElementsByTagName("*").length}),j.getElementsByClassName=Rt.test(bt.getElementsByClassName),j.getById=to(function(at){return vn.appendChild(at).id=q,!bt.getElementsByName||!bt.getElementsByName(q).length}),j.getById?(K.filter.ID=function(at){var Wt=at.replace(rn,vr);return function(Vt){return Vt.getAttribute("id")===Wt}},K.find.ID=function(at,Wt){if(typeof Wt.getElementById!="undefined"&&w){var Vt=Wt.getElementById(at);return Vt?[Vt]:[]}}):(K.filter.ID=function(at){var Wt=at.replace(rn,vr);return function(Vt){var nn=typeof Vt.getAttributeNode!="undefined"&&Vt.getAttributeNode("id");return nn&&nn.value===Wt}},K.find.ID=function(at,Wt){if(typeof Wt.getElementById!="undefined"&&w){var Vt,nn,cn,Fn=Wt.getElementById(at);if(Fn){if(Vt=Fn.getAttributeNode("id"),Vt&&Vt.value===at)return[Fn];for(cn=Wt.getElementsByName(at),nn=0;Fn=cn[nn++];)if(Vt=Fn.getAttributeNode("id"),Vt&&Vt.value===at)return[Fn]}return[]}}),K.find.TAG=j.getElementsByTagName?function(at,Wt){if(typeof Wt.getElementsByTagName!="undefined")return Wt.getElementsByTagName(at);if(j.qsa)return Wt.querySelectorAll(at)}:function(at,Wt){var Vt,nn=[],cn=0,Fn=Wt.getElementsByTagName(at);if(at==="*"){for(;Vt=Fn[cn++];)Vt.nodeType===1&&nn.push(Vt);return nn}return Fn},K.find.CLASS=j.getElementsByClassName&&function(at,Wt){if(typeof Wt.getElementsByClassName!="undefined"&&w)return Wt.getElementsByClassName(at)},O=[],F=[],(j.qsa=Rt.test(bt.querySelectorAll))&&(to(function(at){var Wt;vn.appendChild(at).innerHTML="",at.querySelectorAll("[msallowcapture^='']").length&&F.push("[*^$]="+kn+`*(?:''|"")`),at.querySelectorAll("[selected]").length||F.push("\\["+kn+"*(?:value|"+Mr+")"),at.querySelectorAll("[id~="+q+"-]").length||F.push("~="),Wt=bt.createElement("input"),Wt.setAttribute("name",""),at.appendChild(Wt),at.querySelectorAll("[name='']").length||F.push("\\["+kn+"*name"+kn+"*="+kn+`*(?:''|"")`),at.querySelectorAll(":checked").length||F.push(":checked"),at.querySelectorAll("a#"+q+"+*").length||F.push(".#.+[+~]"),at.querySelectorAll("\\\f"),F.push("[\\r\\n\\f]")}),to(function(at){at.innerHTML="";var Wt=bt.createElement("input");Wt.setAttribute("type","hidden"),at.appendChild(Wt).setAttribute("name","D"),at.querySelectorAll("[name=d]").length&&F.push("name"+kn+"*[*^$|!~]?="),at.querySelectorAll(":enabled").length!==2&&F.push(":enabled",":disabled"),vn.appendChild(at).disabled=!0,at.querySelectorAll(":disabled").length!==2&&F.push(":enabled",":disabled"),at.querySelectorAll("*,:x"),F.push(",.*:")})),(j.matchesSelector=Rt.test(W=vn.matches||vn.webkitMatchesSelector||vn.mozMatchesSelector||vn.oMatchesSelector||vn.msMatchesSelector))&&to(function(at){j.disconnectedMatch=W.call(at,"*"),W.call(at,"[s!='']:x"),O.push("!=",Kn)}),j.cssHas||F.push(":has"),F=F.length&&new RegExp(F.join("|")),O=O.length&&new RegExp(O.join("|")),Pe=Rt.test(vn.compareDocumentPosition),z=Pe||Rt.test(vn.contains)?function(at,Wt){var Vt=at.nodeType===9&&at.documentElement||at,nn=Wt&&Wt.parentNode;return at===nn||!!(nn&&nn.nodeType===1&&(Vt.contains?Vt.contains(nn):at.compareDocumentPosition&&at.compareDocumentPosition(nn)&16))}:function(at,Wt){if(Wt){for(;Wt=Wt.parentNode;)if(Wt===at)return!0}return!1},Ct=Pe?function(at,Wt){if(at===Wt)return Ht=!0,0;var Vt=!at.compareDocumentPosition-!Wt.compareDocumentPosition;return Vt||(Vt=(at.ownerDocument||at)==(Wt.ownerDocument||Wt)?at.compareDocumentPosition(Wt):1,Vt&1||!j.sortDetached&&Wt.compareDocumentPosition(at)===Vt?at==bt||at.ownerDocument==oe&&z(oe,at)?-1:Wt==bt||Wt.ownerDocument==oe&&z(oe,Wt)?1:vt?qn(vt,at)-qn(vt,Wt):0:Vt&4?-1:1)}:function(at,Wt){if(at===Wt)return Ht=!0,0;var Vt,nn=0,cn=at.parentNode,Fn=Wt.parentNode,In=[at],Bn=[Wt];if(!cn||!Fn)return at==bt?-1:Wt==bt?1:cn?-1:Fn?1:vt?qn(vt,at)-qn(vt,Wt):0;if(cn===Fn)return Gi(at,Wt);for(Vt=at;Vt=Vt.parentNode;)In.unshift(Vt);for(Vt=Wt;Vt=Vt.parentNode;)Bn.unshift(Vt);for(;In[nn]===Bn[nn];)nn++;return nn?Gi(In[nn],Bn[nn]):In[nn]==oe?-1:Bn[nn]==oe?1:0}),bt},Ar.matches=function(ve,Pe){return Ar(ve,null,null,Pe)},Ar.matchesSelector=function(ve,Pe){if(gt(ve),j.matchesSelector&&w&&!yt[Pe+" "]&&(!O||!O.test(Pe))&&(!F||!F.test(Pe)))try{var Je=W.call(ve,Pe);if(Je||j.disconnectedMatch||ve.document&&ve.document.nodeType!==11)return Je}catch{yt(Pe,!0)}return Ar(Pe,bt,null,[ve]).length>0},Ar.contains=function(ve,Pe){return(ve.ownerDocument||ve)!=bt&>(ve),z(ve,Pe)},Ar.attr=function(ve,Pe){(ve.ownerDocument||ve)!=bt&>(ve);var Je=K.attrHandle[Pe.toLowerCase()],Ot=Je&&ot.call(K.attrHandle,Pe.toLowerCase())?Je(ve,Pe,!w):void 0;return Ot!==void 0?Ot:j.attributes||!w?ve.getAttribute(Pe):(Ot=ve.getAttributeNode(Pe))&&Ot.specified?Ot.value:null},Ar.escape=function(ve){return(ve+"").replace(Er,$n)},Ar.error=function(ve){throw new Error("Syntax error, unrecognized expression: "+ve)},Ar.uniqueSort=function(ve){var Pe,Je=[],Ot=0,at=0;if(Ht=!j.detectDuplicates,vt=!j.sortStable&&ve.slice(0),ve.sort(Ct),Ht){for(;Pe=ve[at++];)Pe===ve[at]&&(Ot=Je.push(at));for(;Ot--;)ve.splice(Je[Ot],1)}return vt=null,ve},se=Ar.getText=function(ve){var Pe,Je="",Ot=0,at=ve.nodeType;if(at){if(at===1||at===9||at===11){if(typeof ve.textContent=="string")return ve.textContent;for(ve=ve.firstChild;ve;ve=ve.nextSibling)Je+=se(ve)}else if(at===3||at===4)return ve.nodeValue}else for(;Pe=ve[Ot++];)Je+=se(Pe);return Je},K=Ar.selectors={cacheLength:50,createPseudo:qr,match:Re,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(ve){return ve[1]=ve[1].replace(rn,vr),ve[3]=(ve[3]||ve[4]||ve[5]||"").replace(rn,vr),ve[2]==="~="&&(ve[3]=" "+ve[3]+" "),ve.slice(0,4)},CHILD:function(ve){return ve[1]=ve[1].toLowerCase(),ve[1].slice(0,3)==="nth"?(ve[3]||Ar.error(ve[0]),ve[4]=+(ve[4]?ve[5]+(ve[6]||1):2*(ve[3]==="even"||ve[3]==="odd")),ve[5]=+(ve[7]+ve[8]||ve[3]==="odd")):ve[3]&&Ar.error(ve[0]),ve},PSEUDO:function(ve){var Pe,Je=!ve[6]&&ve[2];return Re.CHILD.test(ve[0])?null:(ve[3]?ve[2]=ve[4]||ve[5]||"":Je&&ne.test(Je)&&(Pe=he(Je,!0))&&(Pe=Je.indexOf(")",Je.length-Pe)-Je.length)&&(ve[0]=ve[0].slice(0,Pe),ve[2]=Je.slice(0,Pe)),ve.slice(0,3))}},filter:{TAG:function(ve){var Pe=ve.replace(rn,vr).toLowerCase();return ve==="*"?function(){return!0}:function(Je){return Je.nodeName&&Je.nodeName.toLowerCase()===Pe}},CLASS:function(ve){var Pe=Ee[ve+" "];return Pe||(Pe=new RegExp("(^|"+kn+")"+ve+"("+kn+"|$)"))&&Ee(ve,function(Je){return Pe.test(typeof Je.className=="string"&&Je.className||typeof Je.getAttribute!="undefined"&&Je.getAttribute("class")||"")})},ATTR:function(ve,Pe,Je){return function(Ot){var at=Ar.attr(Ot,ve);return at==null?Pe==="!=":Pe?(at+="",Pe==="="?at===Je:Pe==="!="?at!==Je:Pe==="^="?Je&&at.indexOf(Je)===0:Pe==="*="?Je&&at.indexOf(Je)>-1:Pe==="$="?Je&&at.slice(-Je.length)===Je:Pe==="~="?(" "+at.replace(ei," ")+" ").indexOf(Je)>-1:Pe==="|="?at===Je||at.slice(0,Je.length+1)===Je+"-":!1):!0}},CHILD:function(ve,Pe,Je,Ot,at){var Wt=ve.slice(0,3)!=="nth",Vt=ve.slice(-4)!=="last",nn=Pe==="of-type";return Ot===1&&at===0?function(cn){return!!cn.parentNode}:function(cn,Fn,In){var Bn,Hn,_r,Tn,ti,wi,qi=Wt!==Vt?"nextSibling":"previousSibling",zr=cn.parentNode,Fo=nn&&cn.nodeName.toLowerCase(),Go=!In&&!nn,no=!1;if(zr){if(Wt){for(;qi;){for(Tn=cn;Tn=Tn[qi];)if(nn?Tn.nodeName.toLowerCase()===Fo:Tn.nodeType===1)return!1;wi=qi=ve==="only"&&!wi&&"nextSibling"}return!0}if(wi=[Vt?zr.firstChild:zr.lastChild],Vt&&Go){for(Tn=zr,_r=Tn[q]||(Tn[q]={}),Hn=_r[Tn.uniqueID]||(_r[Tn.uniqueID]={}),Bn=Hn[ve]||[],ti=Bn[0]===ge&&Bn[1],no=ti&&Bn[2],Tn=ti&&zr.childNodes[ti];Tn=++ti&&Tn&&Tn[qi]||(no=ti=0)||wi.pop();)if(Tn.nodeType===1&&++no&&Tn===cn){Hn[ve]=[ge,ti,no];break}}else if(Go&&(Tn=cn,_r=Tn[q]||(Tn[q]={}),Hn=_r[Tn.uniqueID]||(_r[Tn.uniqueID]={}),Bn=Hn[ve]||[],ti=Bn[0]===ge&&Bn[1],no=ti),no===!1)for(;(Tn=++ti&&Tn&&Tn[qi]||(no=ti=0)||wi.pop())&&!((nn?Tn.nodeName.toLowerCase()===Fo:Tn.nodeType===1)&&++no&&(Go&&(_r=Tn[q]||(Tn[q]={}),Hn=_r[Tn.uniqueID]||(_r[Tn.uniqueID]={}),Hn[ve]=[ge,no]),Tn===cn)););return no-=at,no===Ot||no%Ot==0&&no/Ot>=0}}},PSEUDO:function(ve,Pe){var Je,Ot=K.pseudos[ve]||K.setFilters[ve.toLowerCase()]||Ar.error("unsupported pseudo: "+ve);return Ot[q]?Ot(Pe):Ot.length>1?(Je=[ve,ve,"",Pe],K.setFilters.hasOwnProperty(ve.toLowerCase())?qr(function(at,Wt){for(var Vt,nn=Ot(at,Pe),cn=nn.length;cn--;)Vt=qn(at,nn[cn]),at[Vt]=!(Wt[Vt]=nn[cn])}):function(at){return Ot(at,0,Je)}):Ot}},pseudos:{not:qr(function(ve){var Pe=[],Je=[],Ot=He(ve.replace(Sr,"$1"));return Ot[q]?qr(function(at,Wt,Vt,nn){for(var cn,Fn=Ot(at,null,nn,[]),In=at.length;In--;)(cn=Fn[In])&&(at[In]=!(Wt[In]=cn))}):function(at,Wt,Vt){return Pe[0]=at,Ot(Pe,null,Vt,Je),Pe[0]=null,!Je.pop()}}),has:qr(function(ve){return function(Pe){return Ar(ve,Pe).length>0}}),contains:qr(function(ve){return ve=ve.replace(rn,vr),function(Pe){return(Pe.textContent||se(Pe)).indexOf(ve)>-1}}),lang:qr(function(ve){return ue.test(ve||"")||Ar.error("unsupported lang: "+ve),ve=ve.replace(rn,vr).toLowerCase(),function(Pe){var Je;do if(Je=w?Pe.lang:Pe.getAttribute("xml:lang")||Pe.getAttribute("lang"))return Je=Je.toLowerCase(),Je===ve||Je.indexOf(ve+"-")===0;while((Pe=Pe.parentNode)&&Pe.nodeType===1);return!1}}),target:function(ve){var Pe=A.location&&A.location.hash;return Pe&&Pe.slice(1)===ve.id},root:function(ve){return ve===vn},focus:function(ve){return ve===bt.activeElement&&(!bt.hasFocus||bt.hasFocus())&&!!(ve.type||ve.href||~ve.tabIndex)},enabled:Pi(!1),disabled:Pi(!0),checked:function(ve){var Pe=ve.nodeName.toLowerCase();return Pe==="input"&&!!ve.checked||Pe==="option"&&!!ve.selected},selected:function(ve){return ve.parentNode&&ve.parentNode.selectedIndex,ve.selected===!0},empty:function(ve){for(ve=ve.firstChild;ve;ve=ve.nextSibling)if(ve.nodeType<6)return!1;return!0},parent:function(ve){return!K.pseudos.empty(ve)},header:function(ve){return Qe.test(ve.nodeName)},input:function(ve){return rt.test(ve.nodeName)},button:function(ve){var Pe=ve.nodeName.toLowerCase();return Pe==="input"&&ve.type==="button"||Pe==="button"},text:function(ve){var Pe;return ve.nodeName.toLowerCase()==="input"&&ve.type==="text"&&((Pe=ve.getAttribute("type"))==null||Pe.toLowerCase()==="text")},first:Wn(function(){return[0]}),last:Wn(function(ve,Pe){return[Pe-1]}),eq:Wn(function(ve,Pe,Je){return[Je<0?Je+Pe:Je]}),even:Wn(function(ve,Pe){for(var Je=0;JePe?Pe:Je;--Ot>=0;)ve.push(Ot);return ve}),gt:Wn(function(ve,Pe,Je){for(var Ot=Je<0?Je+Pe:Je;++Ot1?function(Pe,Je,Ot){for(var at=ve.length;at--;)if(!ve[at](Pe,Je,Ot))return!1;return!0}:ve[0]}c(jo,"elementMatcher");function xa(ve,Pe,Je){for(var Ot=0,at=Pe.length;Ot-1&&(Vt[In]=!(nn[In]=Hn))}}else zr=Eo(zr===nn?zr.splice(ti,zr.length):zr),at?at(null,nn,zr,Fn):xn.apply(nn,zr)})}c(bs,"setMatcher");function ws(ve){for(var Pe,Je,Ot,at=ve.length,Wt=K.relative[ve[0].type],Vt=Wt||K.relative[" "],nn=Wt?1:0,cn=bo(function(Bn){return Bn===Pe},Vt,!0),Fn=bo(function(Bn){return qn(Pe,Bn)>-1},Vt,!0),In=[function(Bn,Hn,_r){var Tn=!Wt&&(_r||Hn!==st)||((Pe=Hn).nodeType?cn(Bn,Hn,_r):Fn(Bn,Hn,_r));return Pe=null,Tn}];nn1&&jo(In),nn>1&&Ko(ve.slice(0,nn-1).concat({value:ve[nn-2].type===" "?"*":""})).replace(Sr,"$1"),Je,nn0,Ot=ve.length>0,at=c(function(Wt,Vt,nn,cn,Fn){var In,Bn,Hn,_r=0,Tn="0",ti=Wt&&[],wi=[],qi=st,zr=Wt||Ot&&K.find.TAG("*",Fn),Fo=ge+=qi==null?1:Math.random()||.1,Go=zr.length;for(Fn&&(st=Vt==bt||Vt||Fn);Tn!==Go&&(In=zr[Tn])!=null;Tn++){if(Ot&&In){for(Bn=0,!Vt&&In.ownerDocument!=bt&&(gt(In),nn=!w);Hn=ve[Bn++];)if(Hn(In,Vt||bt,nn)){cn.push(In);break}Fn&&(ge=Fo)}Je&&((In=!Hn&&In)&&_r--,Wt&&ti.push(In))}if(_r+=Tn,Je&&Tn!==_r){for(Bn=0;Hn=Pe[Bn++];)Hn(ti,wi,Vt,nn);if(Wt){if(_r>0)for(;Tn--;)ti[Tn]||wi[Tn]||(wi[Tn]=zt.call(cn));wi=Eo(wi)}xn.apply(cn,wi),Fn&&!Wt&&wi.length>0&&_r+Pe.length>1&&Ar.uniqueSort(cn)}return Fn&&(ge=Fo,st=qi),ti},"superMatcher");return Je?qr(at):at}return c(Ls,"matcherFromGroupMatchers"),He=Ar.compile=function(ve,Pe){var Je,Ot=[],at=[],Wt=it[ve+" "];if(!Wt){for(Pe||(Pe=he(ve)),Je=Pe.length;Je--;)Wt=ws(Pe[Je]),Wt[q]?Ot.push(Wt):at.push(Wt);Wt=it(ve,Ls(at,Ot)),Wt.selector=ve}return Wt},Fe=Ar.select=function(ve,Pe,Je,Ot){var at,Wt,Vt,nn,cn,Fn=typeof ve=="function"&&ve,In=!Ot&&he(ve=Fn.selector||ve);if(Je=Je||[],In.length===1){if(Wt=In[0]=In[0].slice(0),Wt.length>2&&(Vt=Wt[0]).type==="ID"&&Pe.nodeType===9&&w&&K.relative[Wt[1].type]){if(Pe=(K.find.ID(Vt.matches[0].replace(rn,vr),Pe)||[])[0],Pe)Fn&&(Pe=Pe.parentNode);else return Je;ve=ve.slice(Wt.shift().value.length)}for(at=Re.needsContext.test(ve)?0:Wt.length;at--&&(Vt=Wt[at],!K.relative[nn=Vt.type]);)if((cn=K.find[nn])&&(Ot=cn(Vt.matches[0].replace(rn,vr),Nn.test(Wt[0].type)&&ys(Pe.parentNode)||Pe))){if(Wt.splice(at,1),ve=Ot.length&&Ko(Wt),!ve)return xn.apply(Je,Ot),Je;break}}return(Fn||He(ve,In))(Ot,Pe,!w,Je,!Pe||Nn.test(ve)&&ys(Pe.parentNode)||Pe),Je},j.sortStable=q.split("").sort(Ct).join("")===q,j.detectDuplicates=!!Ht,gt(),j.sortDetached=to(function(ve){return ve.compareDocumentPosition(bt.createElement("fieldset"))&1}),to(function(ve){return ve.innerHTML="",ve.firstChild.getAttribute("href")==="#"})||So("type|href|height|width",function(ve,Pe,Je){if(!Je)return ve.getAttribute(Pe,Pe.toLowerCase()==="type"?1:2)}),(!j.attributes||!to(function(ve){return ve.innerHTML="",ve.firstChild.setAttribute("value",""),ve.firstChild.getAttribute("value")===""}))&&So("value",function(ve,Pe,Je){if(!Je&&ve.nodeName.toLowerCase()==="input")return ve.defaultValue}),to(function(ve){return ve.getAttribute("disabled")==null})||So(Mr,function(ve,Pe,Je){var Ot;if(!Je)return ve[Pe]===!0?Pe.toLowerCase():(Ot=ve.getAttributeNode(Pe))&&Ot.specified?Ot.value:null}),Ar}(h);g.find=S,g.expr=S.selectors,g.expr[":"]=g.expr.pseudos,g.uniqueSort=g.unique=S.uniqueSort,g.text=S.getText,g.isXMLDoc=S.isXML,g.contains=S.contains,g.escapeSelector=S.escape;var L=c(function(A,B,j){for(var K=[],se=j!==void 0;(A=A[B])&&A.nodeType!==9;)if(A.nodeType===1){if(se&&g(A).is(j))break;K.push(A)}return K},"dir"),C=c(function(A,B){for(var j=[];A;A=A.nextSibling)A.nodeType===1&&A!==B&&j.push(A);return j},"siblings"),M=g.expr.match.needsContext;function D(A,B){return A.nodeName&&A.nodeName.toLowerCase()===B.toLowerCase()}c(D,"nodeName");var P=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function U(A,B,j){return f(B)?g.grep(A,function(K,se){return!!B.call(K,se,K)!==j}):B.nodeType?g.grep(A,function(K){return K===B!==j}):typeof B!="string"?g.grep(A,function(K){return s.call(B,K)>-1!==j}):g.filter(B,A,j)}c(U,"winnow"),g.filter=function(A,B,j){var K=B[0];return j&&(A=":not("+A+")"),B.length===1&&K.nodeType===1?g.find.matchesSelector(K,A)?[K]:[]:g.find.matches(A,g.grep(B,function(se){return se.nodeType===1}))},g.fn.extend({find:function(A){var B,j,K=this.length,se=this;if(typeof A!="string")return this.pushStack(g(A).filter(function(){for(B=0;B1?g.uniqueSort(j):j},filter:function(A){return this.pushStack(U(this,A||[],!1))},not:function(A){return this.pushStack(U(this,A||[],!0))},is:function(A){return!!U(this,typeof A=="string"&&M.test(A)?g(A):A||[],!1).length}});var ee,le=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,fe=g.fn.init=function(A,B,j){var K,se;if(!A)return this;if(j=j||ee,typeof A=="string")if(A[0]==="<"&&A[A.length-1]===">"&&A.length>=3?K=[null,A,null]:K=le.exec(A),K&&(K[1]||!B))if(K[1]){if(B=B instanceof g?B[0]:B,g.merge(this,g.parseHTML(K[1],B&&B.nodeType?B.ownerDocument||B:l,!0)),P.test(K[1])&&g.isPlainObject(B))for(K in B)f(this[K])?this[K](B[K]):this.attr(K,B[K]);return this}else return se=l.getElementById(K[2]),se&&(this[0]=se,this.length=1),this;else return!B||B.jquery?(B||j).find(A):this.constructor(B).find(A);else{if(A.nodeType)return this[0]=A,this.length=1,this;if(f(A))return j.ready!==void 0?j.ready(A):A(g)}return g.makeArray(A,this)};fe.prototype=g.fn,ee=g(l);var be=/^(?:parents|prev(?:Until|All))/,ce={children:!0,contents:!0,next:!0,prev:!0};g.fn.extend({has:function(A){var B=g(A,this),j=B.length;return this.filter(function(){for(var K=0;K-1:j.nodeType===1&&g.find.matchesSelector(j,A))){ae.push(j);break}}return this.pushStack(ae.length>1?g.uniqueSort(ae):ae)},index:function(A){return A?typeof A=="string"?s.call(g(A),this[0]):s.call(this,A.jquery?A[0]:A):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(A,B){return this.pushStack(g.uniqueSort(g.merge(this.get(),g(A,B))))},addBack:function(A){return this.add(A==null?this.prevObject:this.prevObject.filter(A))}});function re(A,B){for(;(A=A[B])&&A.nodeType!==1;);return A}c(re,"sibling"),g.each({parent:function(A){var B=A.parentNode;return B&&B.nodeType!==11?B:null},parents:function(A){return L(A,"parentNode")},parentsUntil:function(A,B,j){return L(A,"parentNode",j)},next:function(A){return re(A,"nextSibling")},prev:function(A){return re(A,"previousSibling")},nextAll:function(A){return L(A,"nextSibling")},prevAll:function(A){return L(A,"previousSibling")},nextUntil:function(A,B,j){return L(A,"nextSibling",j)},prevUntil:function(A,B,j){return L(A,"previousSibling",j)},siblings:function(A){return C((A.parentNode||{}).firstChild,A)},children:function(A){return C(A.firstChild)},contents:function(A){return A.contentDocument!=null&&T(A.contentDocument)?A.contentDocument:(D(A,"template")&&(A=A.content||A),g.merge([],A.childNodes))}},function(A,B){g.fn[A]=function(j,K){var se=g.map(this,B,j);return A.slice(-5)!=="Until"&&(K=j),K&&typeof K=="string"&&(se=g.filter(K,se)),this.length>1&&(ce[A]||g.uniqueSort(se),be.test(A)&&se.reverse()),this.pushStack(se)}});var me=/[^\x20\t\r\n\f]+/g;function ye(A){var B={};return g.each(A.match(me)||[],function(j,K){B[K]=!0}),B}c(ye,"createOptions"),g.Callbacks=function(A){A=typeof A=="string"?ye(A):g.extend({},A);var B,j,K,se,ae=[],he=[],He=-1,Fe=c(function(){for(se=se||A.once,K=B=!0;he.length;He=-1)for(j=he.shift();++He-1;)ae.splice(gt,1),gt<=He&&He--}),this},has:function(vt){return vt?g.inArray(vt,ae)>-1:ae.length>0},empty:function(){return ae&&(ae=[]),this},disable:function(){return se=he=[],ae=j="",this},disabled:function(){return!ae},lock:function(){return se=he=[],!j&&!B&&(ae=j=""),this},locked:function(){return!!se},fireWith:function(vt,Ht){return se||(Ht=Ht||[],Ht=[vt,Ht.slice?Ht.slice():Ht],he.push(Ht),B||Fe()),this},fire:function(){return st.fireWith(this,arguments),this},fired:function(){return!!K}};return st};function We(A){return A}c(We,"Identity");function Ve(A){throw A}c(Ve,"Thrower");function _e(A,B,j,K){var se;try{A&&f(se=A.promise)?se.call(A).done(B).fail(j):A&&f(se=A.then)?se.call(A,B,j):B.apply(void 0,[A].slice(K))}catch(ae){j.apply(void 0,[ae])}}c(_e,"adoptValue"),g.extend({Deferred:function(A){var B=[["notify","progress",g.Callbacks("memory"),g.Callbacks("memory"),2],["resolve","done",g.Callbacks("once memory"),g.Callbacks("once memory"),0,"resolved"],["reject","fail",g.Callbacks("once memory"),g.Callbacks("once memory"),1,"rejected"]],j="pending",K={state:function(){return j},always:function(){return se.done(arguments).fail(arguments),this},catch:function(ae){return K.then(null,ae)},pipe:function(){var ae=arguments;return g.Deferred(function(he){g.each(B,function(He,Fe){var st=f(ae[Fe[4]])&&ae[Fe[4]];se[Fe[1]](function(){var vt=st&&st.apply(this,arguments);vt&&f(vt.promise)?vt.promise().progress(he.notify).done(he.resolve).fail(he.reject):he[Fe[0]+"With"](this,st?[vt]:arguments)})}),ae=null}).promise()},then:function(ae,he,He){var Fe=0;function st(vt,Ht,gt,bt){return function(){var vn=this,w=arguments,F=c(function(){var W,z;if(!(vt=Fe&&(gt!==Ve&&(vn=void 0,w=[W]),Ht.rejectWith(vn,w))}};vt?O():(g.Deferred.getStackHook&&(O.stackTrace=g.Deferred.getStackHook()),h.setTimeout(O))}}return c(st,"resolve"),g.Deferred(function(vt){B[0][3].add(st(0,vt,f(He)?He:We,vt.notifyWith)),B[1][3].add(st(0,vt,f(ae)?ae:We)),B[2][3].add(st(0,vt,f(he)?he:Ve))}).promise()},promise:function(ae){return ae!=null?g.extend(ae,K):K}},se={};return g.each(B,function(ae,he){var He=he[2],Fe=he[5];K[he[1]]=He.add,Fe&&He.add(function(){j=Fe},B[3-ae][2].disable,B[3-ae][3].disable,B[0][2].lock,B[0][3].lock),He.add(he[3].fire),se[he[0]]=function(){return se[he[0]+"With"](this===se?void 0:this,arguments),this},se[he[0]+"With"]=He.fireWith}),K.promise(se),A&&A.call(se,se),se},when:function(A){var B=arguments.length,j=B,K=Array(j),se=m.call(arguments),ae=g.Deferred(),he=c(function(He){return function(Fe){K[He]=this,se[He]=arguments.length>1?m.call(arguments):Fe,--B||ae.resolveWith(K,se)}},"updateFunc");if(B<=1&&(_e(A,ae.done(he(j)).resolve,ae.reject,!B),ae.state()==="pending"||f(se[j]&&se[j].then)))return ae.then();for(;j--;)_e(se[j],he(j),ae.reject);return ae.promise()}});var Ue=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;g.Deferred.exceptionHook=function(A,B){h.console&&h.console.warn&&A&&Ue.test(A.name)&&h.console.warn("jQuery.Deferred exception: "+A.message,A.stack,B)},g.readyException=function(A){h.setTimeout(function(){throw A})};var pe=g.Deferred();g.fn.ready=function(A){return pe.then(A).catch(function(B){g.readyException(B)}),this},g.extend({isReady:!1,readyWait:1,ready:function(A){(A===!0?--g.readyWait:g.isReady)||(g.isReady=!0,!(A!==!0&&--g.readyWait>0)&&pe.resolveWith(l,[g]))}}),g.ready.then=pe.then;function ct(){l.removeEventListener("DOMContentLoaded",ct),h.removeEventListener("load",ct),g.ready()}c(ct,"completed"),l.readyState==="complete"||l.readyState!=="loading"&&!l.documentElement.doScroll?h.setTimeout(g.ready):(l.addEventListener("DOMContentLoaded",ct),h.addEventListener("load",ct));var je=c(function(A,B,j,K,se,ae,he){var He=0,Fe=A.length,st=j==null;if(b(j)==="object"){se=!0;for(He in j)je(A,B,He,j[He],!0,ae,he)}else if(K!==void 0&&(se=!0,f(K)||(he=!0),st&&(he?(B.call(A,K),B=null):(st=B,B=c(function(vt,Ht,gt){return st.call(g(vt),gt)},"fn"))),B))for(;He1,null,!0)},removeData:function(A){return this.each(function(){$e.remove(this,A)})}}),g.extend({queue:function(A,B,j){var K;if(A)return B=(B||"fx")+"queue",K=ke.get(A,B),j&&(!K||Array.isArray(j)?K=ke.access(A,B,g.makeArray(j)):K.push(j)),K||[]},dequeue:function(A,B){B=B||"fx";var j=g.queue(A,B),K=j.length,se=j.shift(),ae=g._queueHooks(A,B),he=c(function(){g.dequeue(A,B)},"next");se==="inprogress"&&(se=j.shift(),K--),se&&(B==="fx"&&j.unshift("inprogress"),delete ae.stop,se.call(A,he,ae)),!K&&ae&&ae.empty.fire()},_queueHooks:function(A,B){var j=B+"queueHooks";return ke.get(A,j)||ke.access(A,j,{empty:g.Callbacks("once memory").add(function(){ke.remove(A,[B+"queue",j])})})}}),g.fn.extend({queue:function(A,B){var j=2;return typeof A!="string"&&(B=A,A="fx",j--),arguments.length\x20\t\r\n\f]*)/i,mn=/^$|^module$|\/(?:java|ecma)script/i;(function(){var A=l.createDocumentFragment(),B=A.appendChild(l.createElement("div")),j=l.createElement("input");j.setAttribute("type","radio"),j.setAttribute("checked","checked"),j.setAttribute("name","t"),B.appendChild(j),d.checkClone=B.cloneNode(!0).cloneNode(!0).lastChild.checked,B.innerHTML="",d.noCloneChecked=!!B.cloneNode(!0).lastChild.defaultValue,B.innerHTML="",d.option=!!B.lastChild})();var Un={thead:[1,"