json_schema: {
      "$schema": "http://json-schema.org/draft-04/schema#",
      "title": "descent-glovepie map",
      "description": "Describes the mappings for generating a GlovePIE script.",
      "type": "object",
      "properties": {
          "input": {
              "description": "Input prefix that is applied to all inputs.  For instance, if you set this to \"Sixaxis1\" and define a button mapping for \"Square\", then the generated script will use \"Sixaxis1.Square\".  This parameter is optional; if not specified, no prefix is applied to inputs.",
              "type": "string"
          },
          "alias": {
              "description": "Input aliases.  Allows arbitrary GlovePIE code to be used as an input.",
              "type": "object",
              "patternProperties": {
                  "^[A-Za-z][A-Za-z0-9]*$": {
                      "description": "Alias for an input.",
                      "type": "string"
                  }
              }
          },
          "shift": {
              "description": "List of inputs that can be used as shift buttons.",
              "type": "array",
              "items": {
                  "type": "string",
                  "pattern": "^:?[A-Za-z][A-Za-z0-9]*(\\.[A-Za-z][A-Za-z0-9]*)*$"
              },
              "_uniqueItems": true
          },
          "axis": {
              "description": "Mappings for analog inputs to virtual joystick axes.  Each property name is an input, and each value is the output.",
              "type": "object",
              "patternProperties": {
                  "^:?[A-Za-z][A-Za-z0-9]*(\\.[A-Za-z][A-Za-z0-9]*)*$": {
                      "description": "Mapping of an analog input to an output.  The output may be inverted by putting a dash (-) at the beginning of the value.",
                      "type": "string",
                      "pattern": "^-?[A-Za-z][A-Za-z0-9]*(\\.[A-Za-z][A-Za-z0-9]*)*$"
                  }
              },
              "additionalProperties": false
          },
          "button": {
              "description": "Mappings for digital inputs to virtual joystick buttons, keyboard keys, or keyboard macros.  Each property name is an input.",
              "type": "object",
              "patternProperties": {
                  "^:?[A-Za-z][A-Za-z0-9]*(\\.[A-Za-z][A-Za-z0-9]*)*$": {
                      "oneOf": [
                          {
                              "description": "Simple mapping for this digital input.",
                              "$ref": "#/definitions/output"
                          },
                          {
                              "description": "Mappings for this digital input.  The property names are the shift button inputs, except \"normal\" which is the unshifted mapping.",
                              "type": "object",
                              "properties": {
                                  "normal": {
                                      "description": "Normal, unshifted mapping for this digital input.",
                                      "$ref": "#/definitions/output"
                                  }
                              },
                              "patternProperties": {
                                  "^[A-Za-z][A-Za-z0-9]*(\\.[A-Za-z][A-Za-z0-9]*)*$": {
                                      "description": "Shifted mapping for this digital input.  The property name is the shift button input.",
                                      "$ref": "#/definitions/output"
                                  }
                              }
                          }
                      ]
                  }
              },
              "additionalProperties": false
          },
          "throttle": {
              "description": "Special mapping for using two buttons as a joystick axis and optional virtual button that indicates when both buttons are pressed.",
              "type": "object",
              "properties": {
                  "axis": {
                      "description": "Virtual joystick axis to use for the analog output.",
                      "type": "string",
                      "pattern": "^[A-Za-z][A-Za-z0-9]*(\\.[A-Za-z][A-Za-z0-9]*)*$"
                  },
                  "button": {
                      "description": "Virtual joystick button to use for the digital output indicating when both buttons are pressed.",
                      "type": "string",
                      "pattern": "^[A-Za-z][A-Za-z0-9]*(\\.[A-Za-z][A-Za-z0-9]*)*$"
                  },
                  "forwardButton": {
                      "description": "Virtual joystick button to use for the digital forward output.",
                      "type": "string",
                      "pattern": "^[A-Za-z][A-Za-z0-9]*(\\.[A-Za-z][A-Za-z0-9]*)*$"
                  },
                  "reverseButton": {
                      "description": "Virtual joystick button to use for the digital reverse output.",
                      "type": "string",
                      "pattern": "^[A-Za-z][A-Za-z0-9]*(\\.[A-Za-z][A-Za-z0-9]*)*$"
                  },
                  "forwardDigital": {
                      "description": "Digital input indicating when the button used for forward is pressed, if available.",
                      "type": "string",
                      "pattern": "^:?[A-Za-z][A-Za-z0-9]*(\\.[A-Za-z][A-Za-z0-9]*)*$"
                  },
                  "forwardAnalog": {
                      "description": "Analog input indicating how far the button used for forward is pressed, if available.",
                      "type": "string",
                      "pattern": "^:?[A-Za-z][A-Za-z0-9]*(\\.[A-Za-z][A-Za-z0-9]*)*$"
                  },
                  "reverseDigital": {
                      "description": "Digital input indicating when the button used for reverse is pressed, if available.",
                      "type": "string",
                      "pattern": "^:?[A-Za-z][A-Za-z0-9]*(\\.[A-Za-z][A-Za-z0-9]*)*$"
                  },
                  "reverseAnalog": {
                      "description": "Analog input indicating how far the button used for reverse is pressed, if available.",
                      "type": "string",
                      "pattern": "^:?[A-Za-z][A-Za-z0-9]*(\\.[A-Za-z][A-Za-z0-9]*)*$"
                  },
                  "analogThreshold": {
                      "description": "Threshold beyond which an analog button input is considered pressed for programming logic purposes.  This value is only used if a digital input is not specified for forward or reverse.",
                      "type": "number",
                      "minimum": 0,
                      "minimumExclusive": false,
                      "maximum": 1,
                      "maximumExclusive": true
                  }
              },
              "additionalProperties": false,
              "allOf": [
                  {
                      "anyOf": [
                          {
                              "required": [
                                  "axis"
                              ]
                          },
                          {
                              "required": [
                                  "button"
                              ]
                          },
                          {
                              "required": [
                                  "forwardButton"
                              ]
                          },
                          {
                              "required": [
                                  "reverseButton"
                              ]
                          }
                      ]
                  },
                  {
                      "anyOf": [
                          {
                              "required": [
                                  "forwardDigital"
                              ]
                          },
                          {
                              "required": [
                                  "forwardAnalog"
                              ]
                          }
                      ]
                  },
                  {
                      "anyOf": [
                          {
                              "required": [
                                  "reverseDigital"
                              ]
                          },
                          {
                              "required": [
                                  "reverseAnalog"
                              ]
                          }
                      ]
                  }
              ]
          }
      },
      "additionalProperties": false,
      "required": [
          "button"
      ],
      "definitions": {
          "simpleOutput": {
              "description": "Output assignment to a simple button or key.",
              "type": "string",
              "pattern": "^[A-Za-z][A-Za-z0-9]*(\\.[A-Za-z][A-Za-z0-9]*)*$"
          },
          "macroOutput": {
              "description": "Output assignment to a keyboard macro.",
              "type": "string",
              "pattern": "^~[A-Za-z][A-Za-z0-9]*([- ][A-Za-z][A-Za-z0-9]*)*$"
          },
          "output": {
              "oneOf": [
                  {
                      "$ref": "#/definitions/simpleOutput"
                  },
                  {
                      "$ref": "#/definitions/macroOutput"
                  }
              ]
          }
      }
  }