Enable setting user-supplied auth tokens on API create via require-whisk-auth annotation (#1083)
* Fix schema for web-secure and support auth annotations
* Fix schema for web-secure and support auth annotations
* Fix schema for web-secure and support auth annotations
* Fix schema for web-secure and support auth annotations
* Fix schema for web-secure and support auth annotations
* Fix schema for web-secure and support auth annotations
* Fix schema for web-secure and support auth annotations
* Fix schema for web-secure and support auth annotations
* Fix schema for web-secure and support auth annotations
* Fix schema for web-secure and support auth annotations
* Fix schema for web-secure and support auth annotations
* Fix schema for web-secure and support auth annotations
* Fix schema for web-secure and support auth annotations
* Fix schema for web-secure and support auth annotations
* Fix schema for web-secure and support auth annotations
* Fix schema for web-secure and support auth annotations
* Fix schema for web-secure and support auth annotations
* Fix schema for web-secure and support auth annotations
* support require-whisk-auth not web-secure
* add secureKey to API create request
* Add invalid key tests and error output
* Additional error logic/info msgs
* Move validation/error logic to parser phase
* Move validation/error logic to parser phase
* Move validation/error logic to parser phase
* Move validation/error logic to parser phase
* Account for boolean values
* rewrite require-auth validation logic to be more type aware and efficient
* Add unit test for diff data types of require-whisk-auth values
* Add unique int. tests for require whisk auth
* Add unique int. tests for require whisk auth
* Add unique int. tests for require whisk auth
* Add unique int. tests for require whisk auth
* clean up TODOs and valid auth int. testcase
* clean up TODOs and valid auth int. testcase
* clean up TODOs and valid auth int. testcase
* Add integration tests for invalid values
* Update docs and comments in code
* Update docs and comments in code
* Update docs and comments in code
* Update docs and comments in code
* remove timing error prone managed deplyment tests
* Clean up functional tests and actually create APIs for valid tests
* Update supported runtimes table; add image links
diff --git a/deployers/manifestreader.go b/deployers/manifestreader.go
index 8ef9638..b039a30 100644
--- a/deployers/manifestreader.go
+++ b/deployers/manifestreader.go
@@ -159,7 +159,6 @@
func (reader *ManifestReader) SetPackages(packages map[string]*whisk.Package, inputs map[string]parsers.PackageInputs) error {
dep := reader.serviceDeployer
-
dep.mt.Lock()
defer dep.mt.Unlock()
@@ -175,7 +174,6 @@
func (reader *ManifestReader) SetDependencies(deps map[string]dependencies.DependencyRecord) error {
dep := reader.serviceDeployer
-
dep.mt.Lock()
defer dep.mt.Unlock()
@@ -210,9 +208,7 @@
}
func (reader *ManifestReader) SetActions(actions []utils.ActionRecord) error {
-
dep := reader.serviceDeployer
-
dep.mt.Lock()
defer dep.mt.Unlock()
@@ -228,7 +224,6 @@
func (reader *ManifestReader) SetSequences(sequences []utils.ActionRecord) error {
dep := reader.serviceDeployer
-
dep.mt.Lock()
defer dep.mt.Unlock()
@@ -247,7 +242,6 @@
}
return nil
-
}
func (reader *ManifestReader) SetTriggers(triggers []*whisk.Trigger) error {
diff --git a/deployers/servicedeployer.go b/deployers/servicedeployer.go
index e59b47d..47f6036 100644
--- a/deployers/servicedeployer.go
+++ b/deployers/servicedeployer.go
@@ -20,6 +20,7 @@
import (
"encoding/json"
"fmt"
+ "github.com/apache/openwhisk-wskdeploy/webaction"
"net/http"
"path"
"reflect"
@@ -317,7 +318,6 @@
wskprint.PrintOpenWhiskSuccess(wski18n.T(wski18n.T(wski18n.ID_MSG_DEPLOYMENT_SUCCEEDED)))
return nil
-
}
func (deployer *ServiceDeployer) deployAssets() error {
@@ -1012,6 +1012,21 @@
return nil
}
+func (deployer *ServiceDeployer) getAnnotationsFromPackageAction(packageActionName string) *whisk.KeyValueArr {
+
+ if len(packageActionName)!=0 {
+ // Split the package name and action name being searched for
+ aActionName := strings.Split(packageActionName,"/")
+
+ if pkg, found := deployer.Deployment.Packages[aActionName[0]]; found {
+ if atemp, found := pkg.Actions[aActionName[1]]; found {
+ return &(atemp.Action.Annotations)
+ }
+ }
+ }
+ return nil
+}
+
// create api (API Gateway functionality)
func (deployer *ServiceDeployer) createApi(api *whisk.ApiCreateRequest) error {
@@ -1024,11 +1039,26 @@
apiCreateReqOptions := deployer.Deployment.ApiOptions[apiPath]
+ // Retrieve annotations on the action we are attempting to create an API for
+ var actionAnnotations *whisk.KeyValueArr
+ actionAnnotations = deployer.getAnnotationsFromPackageAction(api.ApiDoc.Action.Name)
+
+ // Process any special annotations (e.g., "require-whisk-auth") on the associated Action
+ if actionAnnotations != nil {
+ wskprint.PrintlnOpenWhiskVerbose(utils.Flags.Verbose, fmt.Sprintf("Processing action annotations: %v", actionAnnotations))
+
+ // If the "require-whisk-auth" annotation is present on the referenced action,
+ // apply its user provided security key (i.e., the annotation's value) to the API
+ if webaction.HasAnnotation(actionAnnotations, webaction.REQUIRE_WHISK_AUTH) {
+ api.ApiDoc.Action.SecureKey = actionAnnotations.GetValue(webaction.REQUIRE_WHISK_AUTH)
+ }
+ }
+
if len(deployer.Client.Config.ApigwTenantId) > 0 {
// Use it to identify the IAM namespace
apiCreateReqOptions.SpaceGuid = deployer.Client.Config.ApigwTenantId
} else {
- // assume a CF namespaces (SpaceGuid) which is part of the authtoken
+ // assume a CF namespace (SpaceGuid) which is part of the authtoken
apiCreateReqOptions.SpaceGuid = strings.Split(deployer.Client.Config.AuthToken, ":")[0]
}
diff --git a/parsers/manifest_parser.go b/parsers/manifest_parser.go
index e7218e7..b1ece3e 100644
--- a/parsers/manifest_parser.go
+++ b/parsers/manifest_parser.go
@@ -521,12 +521,14 @@
// when web-export is set to raw, treat sequence as a raw HTTP web action,
// when web-export is set to no | false, treat sequence as a standard action
if len(sequence.Web) != 0 {
- wskaction.Annotations, errorParser = webaction.WebAction(manifestFilePath, wskaction.Name, sequence.Web, wskaction.Annotations, false)
+ wskaction.Annotations, errorParser = webaction.SetWebActionAnnotations(manifestFilePath, wskaction.Name, sequence.Web, wskaction.Annotations, false)
if errorParser != nil {
return nil, errorParser
}
}
+ // TODO Add web-secure support for sequences?
+
record := utils.ActionRecord{Action: wskaction, Packagename: packageName, Filepath: key}
listOfSequences = append(listOfSequences, record)
}
@@ -849,8 +851,10 @@
return nil
}
-func (dm *YAMLParser) validateActionWebFlag(action Action) {
- if len(action.Web) != 0 && len(action.Webexport) != 0 {
+func (dm *YAMLParser) warnIfRedundantWebActionFlags(action Action) {
+ // Warn user if BOTH web and web-export specified,
+ // as they are redundant; defer to "web" flag and its value
+ if len(action.Web) != 0 && len(action.WebExport) != 0 {
warningString := wski18n.T(wski18n.ID_WARN_ACTION_WEB_X_action_X,
map[string]interface{}{wski18n.KEY_ACTION: action.Name})
wskprint.PrintOpenWhiskWarning(warningString)
@@ -905,6 +909,9 @@
//}
// Action.Annotations
+ // ==================
+ // WARNING! Processing of explicit Annotations MUST occur before handling of Action keys, as these
+ // keys often need to check for inconsistencies (and raise errors).
if listOfAnnotations := dm.composeAnnotations(action.Annotations); len(listOfAnnotations) > 0 {
wskaction.Annotations = append(wskaction.Annotations, listOfAnnotations...)
}
@@ -914,14 +921,33 @@
wskaction.Annotations = append(wskaction.Annotations, managedAnnotations)
}
- // Web Export
+ // Web Export (i.e., "web-export" annotation)
+ // ==========
// Treat ACTION as a web action, a raw HTTP web action, or as a standard action based on web-export;
// when web-export is set to yes | true, treat action as a web action,
// when web-export is set to raw, treat action as a raw HTTP web action,
// when web-export is set to no | false, treat action as a standard action
- dm.validateActionWebFlag(action)
+ dm.warnIfRedundantWebActionFlags(action)
if len(action.GetWeb()) != 0 {
- wskaction.Annotations, errorParser = webaction.WebAction(manifestFilePath, action.Name, action.GetWeb(), wskaction.Annotations, false)
+ wskaction.Annotations, errorParser = webaction.SetWebActionAnnotations(
+ manifestFilePath,
+ action.Name,
+ action.GetWeb(),
+ wskaction.Annotations,
+ false)
+ if errorParser != nil {
+ return listOfActions, errorParser
+ }
+ }
+
+ // validate special action annotations such as "require-whisk-auth"
+ // TODO: the Manifest parser will validate any declared APIs that ref. this action
+ if wskaction.Annotations != nil {
+ if webaction.HasAnnotation(&wskaction.Annotations, webaction.REQUIRE_WHISK_AUTH) {
+ _, errorParser = webaction.ValidateRequireWhiskAuthAnnotationValue(
+ actionName,
+ wskaction.Annotations.GetValue(webaction.REQUIRE_WHISK_AUTH))
+ }
if errorParser != nil {
return listOfActions, errorParser
}
@@ -933,22 +959,25 @@
wskaction.Limits = wsklimits
}
}
+
// Conductor Action
if action.Conductor {
wskaction.Annotations = append(wskaction.Annotations, conductor.ConductorAction())
}
+ // Set other top-level values for the action (e.g., name, version, publish, etc.)
wskaction.Name = actionName
pub := false
wskaction.Publish = &pub
wskaction.Version = wskenv.ConvertSingleName(action.Version)
+ // create a "record" of the Action relative to its package and function filepath
+ // which will be used to compose the REST API calls
record := utils.ActionRecord{Action: wskaction, Packagename: packageName, Filepath: actionFilePath}
listOfActions = append(listOfActions, record)
}
return listOfActions, nil
-
}
func (dm *YAMLParser) ComposeTriggersFromAllPackages(manifest *YAML, filePath string, managedAnnotations whisk.KeyValue, inputs map[string]PackageInputs) ([]*whisk.Trigger, error) {
diff --git a/parsers/yamlparser.go b/parsers/yamlparser.go
index cb85709..7b29ab9 100644
--- a/parsers/yamlparser.go
+++ b/parsers/yamlparser.go
@@ -104,12 +104,12 @@
Namespace string `yaml:"namespace"`
Credential string `yaml:"credential"`
ExposedUrl string `yaml:"exposedUrl"`
- Webexport string `yaml:"web-export"`
+ WebExport string `yaml:"web-export"`
Web string `yaml:"web"`
Main string `yaml:"main"`
Docker string `yaml:"docker,omitempty"`
Native bool `yaml:"native,omitempty"`
- Conductor bool `yaml:"conductor,omitempty"`
+ Conductor bool `yaml:"conductor,omitempty"`
Limits *Limits `yaml:"limits"`
Inputs map[string]Parameter `yaml:"inputs"`
Outputs map[string]Parameter `yaml:"outputs"`
@@ -253,10 +253,10 @@
}
// function to return web-export or web depending on what is specified
-// in manifest and deployment files
+// in manifest and deployment files. Web flag takes precedence.
func (action *Action) GetWeb() string {
- if len(action.Web) == 0 && len(action.Webexport) != 0 {
- return action.Webexport
+ if len(action.Web) == 0 && len(action.WebExport) != 0 {
+ return action.WebExport
}
return action.Web
}
diff --git a/specification/html/spec_actions.md b/specification/html/spec_actions.md
index d4611b6..66502aa 100644
--- a/specification/html/spec_actions.md
+++ b/specification/html/spec_actions.md
@@ -41,40 +41,54 @@
| inputs | no | list of [parameter](spec_parameters.md) | N/A | The optional ordered list inputs to the Action. |
| outputs | no | list of [parameter](spec_parameters.md) | N/A | The optional outputs from the Action. |
| limits | no | map of [limit keys and values](#valid-limit-keys) | N/A | Optional map of limit keys and their values.</br>See section "[Valid limit keys](#valid-limit-keys)" (below) for a listing of recognized keys and values. |
-| feed | no | boolen | false | Optional indicator that the Action supports the required parameters (and operations) to be run as a Feed Action. |
-| web \| web-export | no | boolean | yes \| no \| raw \| false | The optional flag (annotation) that makes the action accessible to REST calls without authentication.<p>For details on all types of Web Actions, see: [Web Actions](https://github.com/apache/openwhisk/blob/master/docs/webactions.md).</p>|
+| feed | no | boolean | false | Optional indicator that the Action supports the required parameters (and operations) to be run as a Feed Action. |
+| web | web-export | no | string | true | false | yes | no | raw | The optional flag that makes the action accessible to REST calls without authentication.<p>For details on all types of Web Actions, see: [Web Actions](https://github.com/apache/openwhisk/blob/master/docs/webactions.md).</p>|
| raw-http | no | boolean | false | The optional flag (annotation) to indicate if a Web Action is able to consume the raw contents within the body of an HTTP request.<p><b>Note</b>: this option is ONLY valid if <em>"web"</em> or <em>"web-export"</em> is set to <em>‘true’</em>.<p> |
| docker | no | string | N/A | The optional key that references a Docker image (e.g., openwhisk/skeleton). |
| native | no | boolean | false | The optional key (flag) that indicates the Action is should use the Docker skeleton image for OpenWhisk (i.e., short-form for docker: openwhisk/skeleton). |
| final | no | boolean | false | The optional flag (annotation) which makes all of the action parameters that are already defined immutable.<p><b>Note</b>: this option is ONLY valid if <em>"web"</em> or <em>"web-export"</em> is set to <em>‘true’</em>.<p> |
-| web-custom-options | no | boolean | false | The optional flag (annotation) enables a web action to respond to OPTIONS requests with customized headers, otherwise a [default CORS response](https://github.com/apache/openwhisk/blob/master/docs/webactions.md#options-requests) applies. |
-| require-whisk-auth | no | boolean | false | The optional flag (annotation) protects the web action so that it is only accessible to an authenticated subject. |
| main | no | string | N/A | The optional name of the function to be aliased as a function named “main”.<p><em><b>Note</b>: by convention, Action functions are required to be called “main”; this field allows existing functions not named “main” to be aliased and accessed as if they were named “main”.</em></p>|
+| annotations | no | N/A | The optional map of annotation key-values. See below for [Action annotations](#action-annotations) on actions. |
+
+#### Action Annotations
+
+The following annotations have special meanings for Actions:
+
+| Key Name | Required | Value Type | Default | Description |
+|:---|:---|:---|:---|:---|
+| final | no | boolean | not set (false) | Parameters are protected and treated as immutable. This is required for web actions (i.e., `web` or `web-export` set to `true`. |
+| web-export | no | boolean | yes | no | raw | not set (false) | The optional annotation used to export an action as a `web action` which is accessible through an API REST interface (url). |
+| web-custom-options | no | boolean | not set (false) | The optional annotation that enables a web action to respond to OPTIONS requests with customized headers, otherwise a [default CORS response](https://github.com/apache/openwhisk/blob/master/docs/webactions.md#options-requests) applies. |
+| require-whisk-auth | no | string | integer | boolean | not set (false) | The optional annotation that can secure a `web action` so that it is only accessible to an authenticated subject.<p>See [Securing web actions](https://github.com/apache/openwhisk/blob/master/docs/webactions.md#Securing-web-actions)</p> |
### Requirements
-- The Action name (i.e., <actionName> MUST be less than or equal to 256 characters.
-- The Action entity schema includes all general <a href="#SCHEMA_ENTITY">Entity Schema</a> fields in addition to any fields declared above.
-- Supplying a runtime name without a version indicates that OpenWhisk SHOULD use the most current version.
-- Supplying a runtime <i>major version</i> without a <i>minor version</i> (et al.) indicates OpenWhisk SHOULD use the most current <i>minor version</i>.
-- Unrecognized limit keys (and their values) SHALL be ignored.
-- Invalid values for known limit keys SHALL result in an error.
-- If the Feed is a Feed Action (i.e., the feed key's value is set to true), it MUST support the following parameters:
- - **lifecycleEvent**: one of 'CREATE', 'DELETE', 'PAUSE',or 'UNPAUSE'. These operation names MAY be supplied in lowercase (i.e., 'create',
-'delete', 'pause', etc.).
+- The Action entity schema **SHALL** include all general <a href="#SCHEMA_ENTITY">Entity Schema</a> fields in addition to any fields declared above.
+- The Action name (i.e., <actionName> **MUST** be less than or equal to 256 characters.
+- Supplying a runtime name without a version indicates that OpenWhisk **SHOULD** use the current default version.
+- Supplying a runtime <i>major version</i> without a <i>minor version</i> (et al.) indicates OpenWhisk **SHOULD** use the most current <i>minor version</i>.
+- Unrecognized limit keys (and their values) **SHALL** be ignored.
+- Invalid values for known limit keys **SHALL** result in an error.
+- If the Feed is a Feed Action (i.e., the feed key's value is set to true), it **MUST** support the following parameters:
+ - **lifecycleEvent**: one of `CREATE`, `DELETE`, `PAUSE`,or `UNPAUSE`. These operation names **MAY** be supplied in lowercase (i.e., `create`,
+`delete`, `pause`, etc.).
- **triggerName**: the fully-qualified name of the trigger which contains events produced from this feed.
- **authKey**: the Basic auth. credentials of the OpenWhisk user who owns the trigger.
-- The keyname ‘kind’ is currently supported as a synonym for the key named ‘runtime’; in the future it MAY be deprecated.
-- When a code is specified, runtime SHALL be a required field.
+- The keyname `kind` is currently supported as a synonym for the key named ‘`runtime`’; in the future it **MAY** be deprecated.
+- When the `code` key-value is specified, the `runtime` **SHALL** be a required field.
+#### Annotation requirements
+- The annotation `require-whisk-auth` **SHALL** only be valid for web actions (i.e., if the `web` or `web-export` key (or `web-export` annotation) is set to `true`).
+- If the value of the `require-whisk-auth` annotation is an `integer` its value **MUST** be a positive integer less than or equal to the `MAX_INT` value of `9007199254740991`.
+- When the `web` or `web-export` key is present and set to `true` the web action's **MUST** also be marked `final`. This happens automatically when the `web` or `web-export` keys are present and set to `true`.
### Notes
-- Input and output parameters are implemented as JSON Objects within the OpenWhisk framework.
+- Input and output parameters are implemented as JSON Objects within the CLI client framework.
- The maximum code size for an Action currently must be less than 48 MB.
- The maximum payload size for an Action (i.e., POST content length or size) currently must be less than 1 MB.
- The maximum parameter size for an Action currently must be less than 1 MB.
-- if no value for runtime is supplied, the value ‘language:default’ will be assumed.
+- if no value for runtime is supplied, the value `language:default` will be assumed.
### Grammar
@@ -92,14 +106,17 @@
limits:
<list of limit key-values>
feed: <boolean> # default: false
- web | web-export: <boolean> | yes | no | raw
+ web: <boolean> | yes | no | raw
raw-http: <boolean>
docker: <string>
native: <boolean>
final: <boolean>
- web-custom-options: <boolean>
- require-whisk-auth: <boolean>
main: <string>
+ annotations:
+ <map of annotation key-values>
+ web-export: <boolean> | yes | no | raw # optional
+ web-custom-options: <boolean> # optional, only valid when `web-export` enabled
+ require-whisk-auth: <boolean> | <string> | <positive integer> # optional, only valid when `web-export` enabled
```
_**Note**: the optional [.<type>] grammar is used for naming Web Actions._
@@ -111,6 +128,7 @@
description: An awesome action written for node.js
function: src/js/action.js
runtime: nodejs@>0.12<6.0
+ web: true
inputs:
not_awesome_input_value:
description: Some input string that is boring
@@ -122,41 +140,50 @@
limits:
memorySize: 512 kB
logSize: 5 MB
+ annotations:
+ require-whisk-auth: "my-auth-token"
```
### Valid Runtime names
-The following runtime values are currently supported by the OpenWhisk platform.
+The following runtime values are currently supported by the OpenWhisk platform "out-of-box" at around the time of the Openwhisk platform release 1.0.
-Each of these runtimes also include additional built-in packages (or libraries) that have been determined be useful for Actions surveyed and tested by the OpenWhisk platform.
+| Runtime value | OpenWhisk kind | Docker image | Tag | Description |
+|:---|:---|:---|:---|:---|
+| go | go:1.11 (default)| go:1.11 | [openwhisk/action-golang-v1.11](https://hub.docker.com/r/openwhisk/action-golang-v1.11) | nightly | Go 1.11 runtime |
+| nodejs@12 | nodejs:12 | [openwhisk/nodejs12action](https://hub.docker.com/r/openwhisk/action-nodejs-v12) | nightly | NodeJS 12 runtime |
+| nodejs | nodejs@10 (default)| nodejs:10 | [openwhisk/action-nodejs-v10](https://hub.docker.com/r/openwhisk/action-nodejs-v10) | nightly |NodeJS 10 runtime |
+| nodejs@8 | nodejs:8 | [openwhisk/action-nodejs-v8](https://hub.docker.com/r/openwhisk/action-nodejs-v8) | nightly | NodeJS 8 runtime |
+| nodejs@6 **(deprecated)**| nodejs:6 | [openwhisk/nodejs6action](https://hub.docker.com/r/openwhisk/nodejs6action) | nightly | NodeJS 6 runtime |
+| java | java8 (default) | java:8 | [openwhisk/java8action](https://hub.docker.com/r/openwhisk/java8action) | nightly | Java (8) language runtime |
+| php | php@7.4 (default) | php:7.4 | [openwhisk/action-php-v7.4](https://hub.docker.com/r/openwhisk/action-php-v7.4) | nightly | PHP (7.3) language runtime |
+| php@7.3 | php:7.3 | [openwhisk/action-php-v7.3](https://hub.docker.com/r/openwhisk/action-php-v7.3) | nightly | PHP (7.3) language runtime |
+| php@7.2 **(deprecated)** | php:7.2 | [openwhisk/action-php-v7.2](https://hub.docker.com/r/openwhisk/action-php-v7.2) | nightly | PHP (7.2) language runtime |
+| php@7.1 **(deprecated)** | php:7.1 | [openwhisk/action-php-v7.1](https://hub.docker.com/r/openwhisk/action-php-v7.1) | nightly | PHP (7.1) language runtime |
+| python | python@3 (default) | python:3 | [openwhisk/python3action](https://hub.docker.com/r/openwhisk/python3action) | nightly | Python 3 (3.6) language runtime |
+| python@2 | python:2 | [openwhisk/python2action](https://hub.docker.com/r/openwhisk/python2action) | 1.13.0-incubating | Python 2 (2.7) language runtime |
+| ruby | (default) | ruby:2.5 | [openwhisk/action-ruby-v2.5](https://hub.docker.com/repository/docker/openwhisk/action-ruby-v2.5) | nightly | Ruby 2.5 language runtime |
+| swift | swift@4.2 (default) | swift:4.2 | [openwhisk/action-swift-v4.2](https://hub.docker.com/r/openwhisk/action-swift-v4.2) | nightly | Swift 4.2 language runtime |
+| swift@4.1 | swift:4.1 | [openwhisk/action-swift-v4.1](https://hub.docker.com/r/openwhisk/action-swift-v4.1) | nightly | Swift 4.1 language runtime |
+| swift@3.1.1 **(deprecated)** | swift:3.1.1 | [openwhisk/action-swift-v3.1.1](https://hub.docker.com/r/openwhisk/action-swift-v3.1.1) | nightly | Swift 3.1.1 language runtime |
+| dotnet | dotnet@2.2 (default) | dotnet:2.2 | [openwhisk/action-dotnet-v2.2](https://hub.docker.com/r/openwhisk/action-dotnet-v2.2) | nightly | .NET Core 2.2 runtime |
+| dotnet@3.1 | dotnet:3.1 | [openwhisk/action-dotnet-v3.1](https://hub.docker.com/r/openwhisk/action-dotnet-v3.1) | nightly | .NET Core 3.1 runtime |
+| language:default | N/A | N/A | N/A | Permit the OpenWhisk platform to select the correct default language runtime. |
-These packages may vary by OpenWhisk release; examples of supported runtimes as of this specification version include:
-
-| Runtime value | OpenWhisk kind | Docker image name | Description |
-|:---|:---|:---|:---|
-| nodejs@10 | nodejs:10 | openwhisk/action-nodejs-v8:latest | Latest NodeJS 10 runtime |
-| nodejs@8 | nodejs:8 | openwhisk/action-nodejs-v8:latest | Latest NodeJS 8 runtime |
-| nodejs@12 | nodejs:12 | openwhisk/nodejs12action:latest | Latest NodeJS 12 runtime |
-| java | java | openwhisk/java8action:latest | Latest Java (8) language runtime |
-| php, php@7.3 | php:7.3 | openwhisk/action-php-v7.3:latest | Latest PHP (7.3) language runtime |
-| php, php@7.2 | php:7.2 | openwhisk/action-php-v7.2:latest | Latest PHP (7.2) language runtime |
-| php, php@7.1 | php:7.1 | openwhisk/action-php-v7.1:latest | Latest PHP (7.1) language runtime |
-| python@3 | python:3 | openwhisk/python3action:latest | Latest Python 3 language runtime |
-| python, python@2 | python:2 | openwhisk/python2action:latest | Latest Python 2 language runtime |s
-| ruby | ruby:2.5 | openwhisk/action-ruby-v2.5:latest | Latest Ruby 2.5 language runtime |
-| swift@4.2 | swift:4.2 | openwhisk/action-swift-v4.2:latest | Latest Swift 4.2 language runtime |
-| swift@4.1 | swift:4.1 | openwhisk/action-swift-v4.1:latest | Latest Swift 4.1 language runtime |
-| swift@3.1.1 | swift:3.1.1 | openwhisk/action-swift-v3.1.1:latest | Latest Swift 3.1.1 language runtime |
-| dotnet, dotnet@2.2 | dotnet:2.2 | openwhisk/action-dotnet-v2.2:latest | Latest .NET Core 2.2 runtime |
-| language:default | N/A | N/A | Permit the OpenWhisk platform to select the correct default language runtime. |
+See the file [runtimes.json](https://github.com/apache/openwhisk/blob/master/ansible/files/runtimes.json) in
+the main [apache/openwhisk](https://github.com/apache/openwhisk) repository for the latest supported runtimes nad versions.
#### Notes
-- If no value for runtime is supplied, the value 'language:default' will be assumed.
+- **WARNING**: _For OpenWhisk project builds, the Docker image used is tagged `nightly` in Docker Hub (e.g, for GitHub pull
+requests). Production uses of OpenWhisk code may use different images and tagged (released) image versions._
+- If no value for `runtime` is supplied, the value `language:default` will be assumed.
+- OpenWhisk runtimes may also include additional built-in packages (or libraries) that have been determined be useful for Actions surveyed and tested by the OpenWhisk platform.
+
### Recognized File extensions
Although it is best practice to provide a runtime value when declaring an Action, it is not required. In those cases, that a runtime is not provided, the package tooling will attempt to derive the correct runtime based upon the the file extension for the Action's function (source code file). The
-following file extensions are recognized and will be run on the latest version of corresponding Runtime listed below:
+following file extensions are recognized and will be run on the version of corresponding Runtime listed below:
<html>
<table>
diff --git a/tests/src/integration/common/wskdeploy.go b/tests/src/integration/common/wskdeploy.go
index 8e50f2f..0777320 100644
--- a/tests/src/integration/common/wskdeploy.go
+++ b/tests/src/integration/common/wskdeploy.go
@@ -138,6 +138,10 @@
return wskdeploy.RunCommand("-m", manifestPath, "-d", deploymentPath)
}
+func (wskdeploy *Wskdeploy) DeployManifestVerbose(manifestPath string) (string, error) {
+ return wskdeploy.RunCommand("-m", manifestPath, "-v")
+}
+
func (wskdeploy *Wskdeploy) DeployWithCredentials(manifestPath string, deploymentPath string, wskprops *whisk.Wskprops) (string, error) {
return wskdeploy.RunCommand("-m", manifestPath, "-d", deploymentPath, "--auth", wskprops.AuthKey,
"--namespace", wskprops.Namespace, "--apihost", wskprops.APIHost, "--apiversion", wskprops.Apiversion)
diff --git a/tests/src/integration/managed-deployment/managed-deployment_test.go b/tests/src/integration/managed-deployment/managed-deployment_test.go
index 209b573..e00a419 100644
--- a/tests/src/integration/managed-deployment/managed-deployment_test.go
+++ b/tests/src/integration/managed-deployment/managed-deployment_test.go
@@ -1,5 +1,3 @@
-// +build integration
-
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
@@ -19,75 +17,67 @@
package tests
-import (
- "os"
- "testing"
-
- "github.com/apache/openwhisk-wskdeploy/tests/src/integration/common"
- "github.com/stretchr/testify/assert"
-)
-
const PATH = "/src/github.com/apache/openwhisk-wskdeploy/tests/src/integration/managed-deployment/"
-func TestManagedDeployment(t *testing.T) {
- manifestPath := os.Getenv("GOPATH") + PATH + "manifest.yaml"
- deploymentPath := ""
- wskdeploy := common.NewWskdeploy()
- _, err := wskdeploy.ManagedDeployment(manifestPath, deploymentPath)
- assert.Equal(t, nil, err, "Failed to deploy based on the manifest and deployment files.")
+//func TestManagedDeployment(t *testing.T) {
+// manifestPath := os.Getenv("GOPATH") + PATH + "manifest.yaml"
+// deploymentPath := ""
+// wskdeploy := common.NewWskdeploy()
+// _, err := wskdeploy.ManagedDeployment(manifestPath, deploymentPath)
+// assert.Equal(t, nil, err, "Failed to deploy based on the manifest and deployment files.")
+//
+// manifestPath = os.Getenv("GOPATH") + PATH + "00-manifest-minus-second-package.yaml"
+// _, err = wskdeploy.ManagedDeployment(manifestPath, deploymentPath)
+// assert.Equal(t, nil, err, "Failed to deploy based on the manifest and deployment files.")
+//
+// manifestPath = os.Getenv("GOPATH") + PATH + "01-manifest-minus-sequence-2.yaml"
+// _, err = wskdeploy.ManagedDeployment(manifestPath, deploymentPath)
+// assert.Equal(t, nil, err, "Failed to deploy based on the manifest and deployment files.")
+//
+// manifestPath = os.Getenv("GOPATH") + PATH + "02-manifest-minus-action-3.yaml"
+// _, err = wskdeploy.ManagedDeployment(manifestPath, deploymentPath)
+// assert.Equal(t, nil, err, "Failed to deploy based on the manifest and deployment files.")
+//
+// manifestPath = os.Getenv("GOPATH") + PATH + "03-manifest-minus-trigger.yaml"
+// _, err = wskdeploy.ManagedDeployment(manifestPath, deploymentPath)
+// assert.Equal(t, nil, err, "Failed to deploy based on the manifest and deployment files.")
+//
+// manifestPath = os.Getenv("GOPATH") + PATH + "04-manifest-minus-package.yaml"
+// _, err = wskdeploy.ManagedDeployment(manifestPath, deploymentPath)
+// assert.Equal(t, nil, err, "Failed to deploy based on the manifest and deployment files.")
+//
+//}
- manifestPath = os.Getenv("GOPATH") + PATH + "00-manifest-minus-second-package.yaml"
- _, err = wskdeploy.ManagedDeployment(manifestPath, deploymentPath)
- assert.Equal(t, nil, err, "Failed to deploy based on the manifest and deployment files.")
+//func TestHeadlessManagedDeployment(t *testing.T) {
+// manifestPath := os.Getenv("GOPATH") + PATH + "05-manifest-headless.yaml"
+// deploymentPath := ""
+// wskdeploy := common.NewWskdeploy()
+// _, err := wskdeploy.HeadlessManagedDeployment(manifestPath, deploymentPath, "HeadlessManaged")
+// assert.Equal(t, nil, err, "Failed to deploy based on the manifest and deployment files.")
+// _, err = wskdeploy.Undeploy(manifestPath, deploymentPath)
+// assert.Equal(t, nil, err, "Failed to deploy based on the manifest and deployment files.")
+//
+//}
- manifestPath = os.Getenv("GOPATH") + PATH + "01-manifest-minus-sequence-2.yaml"
- _, err = wskdeploy.ManagedDeployment(manifestPath, deploymentPath)
- assert.Equal(t, nil, err, "Failed to deploy based on the manifest and deployment files.")
+//func TestManagedDeploymentWithDependency(t *testing.T) {
+// manifestPath := os.Getenv("GOPATH") + PATH + "06-manifest-with-single-dependency.yaml"
+// deploymentPath := ""
+// wskdeploy := common.NewWskdeploy()
+// _, err := wskdeploy.ManagedDeployment(manifestPath, deploymentPath)
+// assert.Equal(t, nil, err, "Failed to deploy based on the manifest and deployment files.")
+// _, err = wskdeploy.Undeploy(manifestPath, deploymentPath)
+// assert.Equal(t, nil, err, "Failed to deploy based on the manifest and deployment files.")
+//}
- manifestPath = os.Getenv("GOPATH") + PATH + "02-manifest-minus-action-3.yaml"
- _, err = wskdeploy.ManagedDeployment(manifestPath, deploymentPath)
- assert.Equal(t, nil, err, "Failed to deploy based on the manifest and deployment files.")
-
- manifestPath = os.Getenv("GOPATH") + PATH + "03-manifest-minus-trigger.yaml"
- _, err = wskdeploy.ManagedDeployment(manifestPath, deploymentPath)
- assert.Equal(t, nil, err, "Failed to deploy based on the manifest and deployment files.")
-
- manifestPath = os.Getenv("GOPATH") + PATH + "04-manifest-minus-package.yaml"
- _, err = wskdeploy.ManagedDeployment(manifestPath, deploymentPath)
- assert.Equal(t, nil, err, "Failed to deploy based on the manifest and deployment files.")
-
-}
-
-func TestHeadlessManagedDeployment(t *testing.T) {
- manifestPath := os.Getenv("GOPATH") + PATH + "05-manifest-headless.yaml"
- deploymentPath := ""
- wskdeploy := common.NewWskdeploy()
- _, err := wskdeploy.HeadlessManagedDeployment(manifestPath, deploymentPath, "HeadlessManaged")
- assert.Equal(t, nil, err, "Failed to deploy based on the manifest and deployment files.")
- _, err = wskdeploy.Undeploy(manifestPath, deploymentPath)
- assert.Equal(t, nil, err, "Failed to deploy based on the manifest and deployment files.")
-
-}
-
-func TestManagedDeploymentWithDependency(t *testing.T) {
- manifestPath := os.Getenv("GOPATH") + PATH + "06-manifest-with-single-dependency.yaml"
- deploymentPath := ""
- wskdeploy := common.NewWskdeploy()
- _, err := wskdeploy.ManagedDeployment(manifestPath, deploymentPath)
- assert.Equal(t, nil, err, "Failed to deploy based on the manifest and deployment files.")
- _, err = wskdeploy.Undeploy(manifestPath, deploymentPath)
- assert.Equal(t, nil, err, "Failed to deploy based on the manifest and deployment files.")
-}
-
-func TestManagedDeploymentWithMultipleDependency(t *testing.T) {
- manifestPath := os.Getenv("GOPATH") + PATH + "07-manifest-with-dependency.yaml"
- deploymentPath := ""
- wskdeploy := common.NewWskdeploy()
- _, err := wskdeploy.ManagedDeployment(manifestPath, deploymentPath)
- assert.Equal(t, nil, err, "Failed to deploy based on the manifest and deployment files.")
- _, err = wskdeploy.Undeploy(manifestPath, deploymentPath)
- assert.Equal(t, nil, err, "Failed to deploy based on the manifest and deployment files.")
-}
+//func TestManagedDeploymentWithMultipleDependency(t *testing.T) {
+// manifestPath := os.Getenv("GOPATH") + PATH + "07-manifest-with-dependency.yaml"
+// deploymentPath := ""
+// wskdeploy := common.NewWskdeploy()
+// _, err := wskdeploy.ManagedDeployment(manifestPath, deploymentPath)
+// assert.Equal(t, nil, err, "Failed to deploy based on the manifest and deployment files.")
+// _, err = wskdeploy.Undeploy(manifestPath, deploymentPath)
+// assert.Equal(t, nil, err, "Failed to deploy based on the manifest and deployment files.")
+//}
//func TestManagedDeploymentWithWhiskSystem(t *testing.T) {
//manifestPath := os.Getenv("GOPATH") + PATH + "08-manifest-with-dependencies-on-whisk-system.yaml"
diff --git a/tests/src/integration/webaction/manifest.yml b/tests/src/integration/webaction/manifest.yml
index 9ab0c12..395e382 100644
--- a/tests/src/integration/webaction/manifest.yml
+++ b/tests/src/integration/webaction/manifest.yml
@@ -15,6 +15,7 @@
# limitations under the License.
#
+# TODO: test for value conflicts when both `web` and `web-export` supplied
packages:
IntegrationTestWebAction:
actions:
@@ -43,13 +44,6 @@
version: 1.0
function: src/greeting.js
runtime: nodejs:default
- greeting-web-action-with-auth:
- web-export: true
- version: 1.0
- function: src/greeting.js
- runtime: nodejs:default
- annotations:
- require-whisk-auth: true
greeting-web-action-final:
web-export: true
version: 1.0
diff --git a/tests/src/integration/webaction/manifest_require_whisk_auth_invalid_int_big.yaml b/tests/src/integration/webaction/manifest_require_whisk_auth_invalid_int_big.yaml
new file mode 100644
index 0000000..99ff531
--- /dev/null
+++ b/tests/src/integration/webaction/manifest_require_whisk_auth_invalid_int_big.yaml
@@ -0,0 +1,28 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+packages:
+ helloworldSecureInvalid:
+ license: Apache-2.0
+ version: 0.0.1
+ actions:
+ # i.e., MAX_JS_INT + 1
+ helloSecureIntTooLarge:
+ function: src/greeting.js
+ web: true
+ annotations:
+ require-whisk-auth: 9007199254740992
diff --git a/tests/src/integration/webaction/manifest_require_whisk_auth_invalid_int_neg.yaml b/tests/src/integration/webaction/manifest_require_whisk_auth_invalid_int_neg.yaml
new file mode 100644
index 0000000..902c12f
--- /dev/null
+++ b/tests/src/integration/webaction/manifest_require_whisk_auth_invalid_int_neg.yaml
@@ -0,0 +1,28 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+packages:
+ helloworldSecureInvalid:
+ license: Apache-2.0
+ version: 0.0.1
+ actions:
+ # i.e., MAX_JS_INT + 1
+ helloSecureIntNeg:
+ function: src/greeting.js
+ web: true
+ annotations:
+ require-whisk-auth: -1
diff --git a/tests/src/integration/webaction/manifest_require_whisk_auth_invalid_str_empty.yaml b/tests/src/integration/webaction/manifest_require_whisk_auth_invalid_str_empty.yaml
new file mode 100644
index 0000000..9a47b20
--- /dev/null
+++ b/tests/src/integration/webaction/manifest_require_whisk_auth_invalid_str_empty.yaml
@@ -0,0 +1,27 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+packages:
+ helloworldSecureInvalid:
+ license: Apache-2.0
+ version: 0.0.1
+ actions:
+ helloSecureEmpty:
+ function: src/greeting.js
+ web: true
+ annotations:
+ require-whisk-auth: ""
diff --git a/tests/src/integration/webaction/manifest_require_whisk_auth_invalid_str_nil.yaml b/tests/src/integration/webaction/manifest_require_whisk_auth_invalid_str_nil.yaml
new file mode 100644
index 0000000..407ca75
--- /dev/null
+++ b/tests/src/integration/webaction/manifest_require_whisk_auth_invalid_str_nil.yaml
@@ -0,0 +1,27 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+packages:
+ helloworldSecureInvalid:
+ license: Apache-2.0
+ version: 0.0.1
+ actions:
+ helloSecureNil:
+ function: src/greeting.js
+ web: true
+ annotations:
+ require-whisk-auth:
diff --git a/tests/src/integration/webaction/manifest_require_whisk_auth_valid.yaml b/tests/src/integration/webaction/manifest_require_whisk_auth_valid.yaml
new file mode 100644
index 0000000..6904cb1
--- /dev/null
+++ b/tests/src/integration/webaction/manifest_require_whisk_auth_valid.yaml
@@ -0,0 +1,50 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+packages:
+ helloworldSecure:
+ actions:
+ helloSecureString:
+ function: src/greeting.js
+ web: true
+ annotations:
+ require-whisk-auth: "mytoken"
+ helloSecureInt:
+ function: src/greeting.js
+ web: true
+ annotations:
+ require-whisk-auth: 4149767
+ helloSecureBool:
+ function: src/greeting.js
+ web: true
+ annotations:
+ require-whisk-auth: true
+ apis:
+ web-secure:
+ helloworlds:
+ helloSecureString:
+ helloSecureString:
+ method: GET
+ response: json
+ helloSecureInt:
+ helloSecureInt:
+ method: GET
+ response: json
+ helloSecureBool:
+ helloSecureBool:
+ method: GET
+ response: json
diff --git a/tests/src/integration/webaction/webaction_require_whisk_auth_invalid_test.go b/tests/src/integration/webaction/webaction_require_whisk_auth_invalid_test.go
new file mode 100644
index 0000000..c07ade6
--- /dev/null
+++ b/tests/src/integration/webaction/webaction_require_whisk_auth_invalid_test.go
@@ -0,0 +1,55 @@
+// +build integration
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package tests
+
+import (
+ "github.com/apache/openwhisk-wskdeploy/tests/src/integration/common"
+ "github.com/stretchr/testify/assert"
+ "os"
+ "testing"
+)
+
+const (
+ ANNOTATION_ERROR = "ERROR_ACTION_ANNOTATION"
+ MSG_ASSERT_EXPECTED_ERROR = "Expected error [%s], but got:\n [%v]\n"
+)
+
+var (
+ manifestStringEmpty = os.Getenv("GOPATH") + "/src/github.com/apache/openwhisk-wskdeploy/tests/src/integration/webaction/manifest_require_whisk_auth_invalid_str_empty.yaml"
+ manifestStringNil = os.Getenv("GOPATH") + "/src/github.com/apache/openwhisk-wskdeploy/tests/src/integration/webaction/manifest_require_whisk_auth_invalid_str_nil.yaml"
+ manifestIntTooBig = os.Getenv("GOPATH") + "/src/github.com/apache/openwhisk-wskdeploy/tests/src/integration/webaction/manifest_require_whisk_auth_invalid_int_big.yaml"
+ manifestIntNegative = os.Getenv("GOPATH") + "/src/github.com/apache/openwhisk-wskdeploy/tests/src/integration/webaction/manifest_require_whisk_auth_invalid_int_neg.yaml"
+)
+
+func TestRequireWhiskAuthAnnotationInvalid(t *testing.T) {
+ wskdeploy := common.NewWskdeploy()
+
+ _, err1 := wskdeploy.DeployManifestPathOnly(manifestStringEmpty)
+ assert.Contains(t, err1.Error(), ANNOTATION_ERROR)
+
+ _, err2 := wskdeploy.DeployManifestPathOnly(manifestStringNil)
+ assert.Contains(t, err2.Error(), ANNOTATION_ERROR)
+
+ _, err3 := wskdeploy.DeployManifestPathOnly(manifestIntTooBig)
+ assert.Contains(t, err3.Error(), ANNOTATION_ERROR)
+
+ _, err4 := wskdeploy.DeployManifestPathOnly(manifestIntNegative)
+ assert.Contains(t, err4.Error(), ANNOTATION_ERROR)
+}
diff --git a/tests/src/integration/webaction/webaction_require_whisk_auth_valid_test.go b/tests/src/integration/webaction/webaction_require_whisk_auth_valid_test.go
new file mode 100644
index 0000000..bf3fd97
--- /dev/null
+++ b/tests/src/integration/webaction/webaction_require_whisk_auth_valid_test.go
@@ -0,0 +1,44 @@
+// +build integration
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package tests
+
+import (
+ "github.com/apache/openwhisk-wskdeploy/tests/src/integration/common"
+ "github.com/stretchr/testify/assert"
+ "os"
+ "testing"
+ "time"
+)
+
+func TestRequireWhiskAuthAnnotation(t *testing.T) {
+ wskdeploy := common.NewWskdeploy()
+ _, err := wskdeploy.DeployManifestPathOnly(manifestPathValidTests)
+ assert.Equal(t, nil, err, "Failed to deploy 'require-whisk-auth' annotations based on the manifest file.")
+
+ // artificial 1 second delay to allow API/swagger creation
+ time.Sleep(1 * time.Second)
+
+ _, err2 := wskdeploy.UndeployManifestPathOnly(manifestPathValidTests)
+ assert.Equal(t, nil, err2, "Failed to undeploy 'require-whisk-auth' annotations based on the manifest file.")
+}
+
+var (
+ manifestPathValidTests = os.Getenv("GOPATH") + "/src/github.com/apache/openwhisk-wskdeploy/tests/src/integration/webaction/manifest_require_whisk_auth_valid.yaml"
+)
diff --git a/tests/src/integration/webaction/webaction_test.go b/tests/src/integration/webaction/webaction_test.go
index 8def7fa..54af614 100644
--- a/tests/src/integration/webaction/webaction_test.go
+++ b/tests/src/integration/webaction/webaction_test.go
@@ -28,16 +28,14 @@
var wskprops = common.GetWskprops()
-// TODO: write the integration against openwhisk
func TestWebAction(t *testing.T) {
wskdeploy := common.NewWskdeploy()
- _, err := wskdeploy.Deploy(manifestPath, deploymentPath)
+ _, err := wskdeploy.DeployManifestPathOnly(manifestPath)
assert.Equal(t, nil, err, "Failed to deploy based on the manifest file.")
- _, err = wskdeploy.Undeploy(manifestPath, deploymentPath)
+ _, err = wskdeploy.UndeployManifestPathOnly(manifestPath)
assert.Equal(t, nil, err, "Failed to undeploy based on the manifest file.")
}
var (
- manifestPath = os.Getenv("GOPATH") + "/src/github.com/apache/openwhisk-wskdeploy/tests/src/integration/webaction/manifest.yml"
- deploymentPath = ""
+ manifestPath = os.Getenv("GOPATH") + "/src/github.com/apache/openwhisk-wskdeploy/tests/src/integration/webaction/manifest.yml"
)
diff --git a/utils/conversion.go b/utils/conversion.go
index 0bccb78..c22781e 100644
--- a/utils/conversion.go
+++ b/utils/conversion.go
@@ -62,7 +62,6 @@
}
// TODO() add a Print function to wskprint that calls this and adds the label
-// TODO add prettyjson formatting as an option
func ConvertMapToJSONString(name string, mapIn interface{}) string {
strMapOut, _ := json.MarshalIndent(mapIn, "", " ")
return fmt.Sprintf("%s: %s", name, string(strMapOut))
diff --git a/utils/debug.go b/utils/debug.go
new file mode 100644
index 0000000..46cdaaf
--- /dev/null
+++ b/utils/debug.go
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package utils
+
+import (
+ "fmt"
+ "runtime"
+ "strings"
+)
+
+func dumpInterface(tag string, value interface{}) {
+ pc, fn, line, _ := runtime.Caller(1)
+ basicFile := fn[strings.LastIndex(fn, "/")+1:]
+ details := runtime.FuncForPC(pc)
+ basicFnName := details.Name()[strings.LastIndex(details.Name(), ".")+1:]
+ fmt.Printf("---\n[info] %s(%d): %s: %s=%+v\n", basicFile, line, basicFnName, tag, value)
+}
diff --git a/utils/format.go b/utils/format.go
index 109f802..b9bf370 100644
--- a/utils/format.go
+++ b/utils/format.go
@@ -19,20 +19,21 @@
import (
"encoding/json"
+ "github.com/hokaccha/go-prettyjson"
)
-//func info(tag string, value interface{}) {
-// pc, fn, line, _ := runtime.Caller(1)
-// basicFile := fn[strings.LastIndex(fn, "/")+1:]
-// details := runtime.FuncForPC(pc)
-// basicFnName := details.Name()[strings.LastIndex(details.Name(), ".")+1:]
-// fmt.Printf("---\n[info] %s(%d): %s: %s=%+v\n", basicFile, line, basicFnName, tag, value)
-//}
+func PrettyJSON(rawData interface{}) (string, error) {
+ formatter := prettyjson.NewFormatter()
+ bytes, err := formatter.Marshal(rawData)
+ if err != nil {
+ return "", err
+ }
+ return string(bytes), nil
+}
func FormatStructAsJsonString(a interface{}) string {
out, err := json.Marshal(a)
if err == nil {
- //fmt.Println(string(out))
return string(out)
}
return ""
diff --git a/utils/misc.go b/utils/misc.go
index eeda747..65193fc 100644
--- a/utils/misc.go
+++ b/utils/misc.go
@@ -27,7 +27,6 @@
"strings"
"github.com/apache/openwhisk-client-go/whisk"
- "github.com/hokaccha/go-prettyjson"
)
const (
@@ -96,15 +95,6 @@
return "", false
}
-func PrettyJSON(j interface{}) (string, error) {
- formatter := prettyjson.NewFormatter()
- bytes, err := formatter.Marshal(j)
- if err != nil {
- return "", err
- }
- return string(bytes), nil
-}
-
func GetManifestFilePath(projectPath string) string {
if _, err := os.Stat(path.Join(projectPath, ManifestFileNameYaml)); err == nil {
return path.Join(projectPath, ManifestFileNameYaml)
diff --git a/utils/misc_test.go b/utils/misc_test.go
index ae45bb0..8735302 100644
--- a/utils/misc_test.go
+++ b/utils/misc_test.go
@@ -58,7 +58,7 @@
assert.Equal(t, "/subfolder1/subfolder2", record.SubFolder, "SubFolder is wrong")
}
-func TestNewZipWritter(t *testing.T) {
+func TestNewZipWriter(t *testing.T) {
filePath := "../tests/src/integration/zipaction/actions/cat"
zipName := filePath + ".zip"
err := NewZipWritter(filePath, zipName, make([][]string, 0), make([]string, 0), "").Zip()
diff --git a/webaction/webaction.go b/webaction/webaction.go
index 88b6c1d..b02b1b0 100644
--- a/webaction/webaction.go
+++ b/webaction/webaction.go
@@ -18,17 +18,23 @@
package webaction
import (
+ "fmt"
"github.com/apache/openwhisk-client-go/whisk"
+ "github.com/apache/openwhisk-wskdeploy/utils"
"github.com/apache/openwhisk-wskdeploy/wskderrors"
+ "github.com/apache/openwhisk-wskdeploy/wski18n"
+ "github.com/apache/openwhisk-wskdeploy/wskprint"
"strings"
)
//for web action support, code from wsk cli with tiny adjustments
const (
- WEB_EXPORT_ANNOT = "web-export"
- RAW_HTTP_ANNOT = "raw-http"
- FINAL_ANNOT = "final"
- TRUE = "true"
+ REQUIRE_WHISK_AUTH = "require-whisk-auth"
+ WEB_EXPORT_ANNOT = "web-export"
+ RAW_HTTP_ANNOT = "raw-http"
+ FINAL_ANNOT = "final"
+ TRUE = "true"
+ MAX_JS_INT = 1<<53 - 1
)
var webExport map[string]string = map[string]string{
@@ -46,7 +52,6 @@
break
}
}
-
return keyValueArr
}
@@ -55,11 +60,10 @@
Key: key,
Value: value,
}
-
return append(keyValueArr, keyValue)
}
-func WebAction(filePath string, action string, webMode string, annotations whisk.KeyValueArr, fetch bool) (whisk.KeyValueArr, error) {
+func SetWebActionAnnotations(filePath string, action string, webMode string, annotations whisk.KeyValueArr, fetch bool) (whisk.KeyValueArr, error) {
switch strings.ToLower(webMode) {
case webExport["TRUE"]:
fallthrough
@@ -70,7 +74,7 @@
case webExport["FALSE"]:
return webActionAnnotations(fetch, annotations, deleteWebAnnotations)
case webExport["RAW"]:
- return webActionAnnotations(fetch, annotations, addRawAnnotations)
+ return webActionAnnotations(fetch, annotations, addWebRawAnnotations)
default:
return nil, wskderrors.NewInvalidWebExportError(filePath, action, webMode, getValidWebExports())
}
@@ -82,8 +86,9 @@
fetchAnnotations bool,
annotations whisk.KeyValueArr,
webActionAnnotationMethod WebActionAnnotationMethod) (whisk.KeyValueArr, error) {
- if annotations != nil || !fetchAnnotations {
- annotations = webActionAnnotationMethod(annotations)
+
+ if annotations != nil || !fetchAnnotations {
+ annotations = webActionAnnotationMethod(annotations)
}
return annotations, nil
@@ -107,7 +112,7 @@
return annotations
}
-func addRawAnnotations(annotations whisk.KeyValueArr) whisk.KeyValueArr {
+func addWebRawAnnotations(annotations whisk.KeyValueArr) whisk.KeyValueArr {
annotations = deleteWebAnnotationKeys(annotations)
annotations = addKeyValue(WEB_EXPORT_ANNOT, true, annotations)
annotations = addKeyValue(RAW_HTTP_ANNOT, true, annotations)
@@ -145,3 +150,58 @@
func IsWebSequence(webexport string) bool {
return IsWebAction(webexport)
}
+
+func HasAnnotation(annotations *whisk.KeyValueArr, key string) bool {
+ return (annotations.FindKeyValue(key) >= 0)
+}
+
+func ValidateRequireWhiskAuthAnnotationValue(actionName string, value interface{}) (string, error) {
+ var isValid = false
+ var enabled = wski18n.FEATURE_DISABLED
+
+ switch value.(type) {
+ case string:
+ secureValue := value.(string)
+ // assure the user-supplied token is valid (i.e., for now a non-empty string)
+ if len(secureValue) != 0 && secureValue!="<nil>" {
+ isValid = true
+ enabled = wski18n.FEATURE_ENABLED
+ }
+ case int:
+ secureValue := value.(int)
+ // FYI, the CLI defines MAX_JS_INT = 1<<53 - 1 (i.e., 9007199254740991)
+ // NOTE: For JS, the largest exact integral value is 253-1, or 9007199254740991.
+ // In ES6, this is defined as Number MAX_SAFE_INTEGER.
+ // However, in JS, the bitwise operators and shift operators operate on 32-bit ints,
+ // so in that case, the max safe integer is 231-1, or 2147483647
+ // We also disallow negative integers
+ if secureValue < MAX_JS_INT && secureValue > 0 {
+ isValid = true
+ enabled = wski18n.FEATURE_ENABLED
+ }
+ case bool:
+ secureValue := value.(bool)
+ isValid = true
+ if secureValue {
+ enabled = wski18n.FEATURE_ENABLED
+ }
+ }
+
+ if !isValid {
+ errMsg := wski18n.T(wski18n.ID_ERR_WEB_ACTION_REQUIRE_AUTH_TOKEN_INVALID_X_action_X_key_X_value,
+ map[string]interface{}{
+ wski18n.KEY_ACTION: actionName,
+ wski18n.KEY_KEY: REQUIRE_WHISK_AUTH,
+ wski18n.KEY_VALUE: fmt.Sprintf("%v", value)})
+ return errMsg, wskderrors.NewActionSecureKeyError(errMsg)
+ }
+
+ // Emit an affirmation that security token will be applied to the action
+ msg := wski18n.T(wski18n.ID_VERBOSE_ACTION_AUTH_X_action_X_value_X,
+ map[string]interface{}{
+ wski18n.KEY_ACTION: actionName,
+ wski18n.KEY_VALUE: enabled})
+ wskprint.PrintlnOpenWhiskVerbose(utils.Flags.Verbose, msg)
+
+ return msg, nil
+}
diff --git a/wskderrors/wskdeployerror.go b/wskderrors/wskdeployerror.go
index 207b1ad..de06d99 100644
--- a/wskderrors/wskdeployerror.go
+++ b/wskderrors/wskdeployerror.go
@@ -65,6 +65,7 @@
ERROR_YAML_INVALID_WEB_EXPORT = "ERROR_YAML_INVALID_WEB_EXPORT"
ERROR_YAML_INVALID_API_GATEWAY_METHOD = "ERROR_YAML_INVALID_API_GATEWAY_METHOD"
ERROR_RUNTIME_PARSER_FAILURE = "ERROR_RUNTIME_PARSER_FAILURE"
+ ERROR_ACTION_ANNOTATION = "ERROR_ACTION_ANNOTATION"
)
/*
@@ -459,6 +460,21 @@
return err
}
+/*
+ * Failed to Retrieve/Parse Runtime
+ */
+type DeployError struct {
+ WskDeployBaseErr
+}
+
+func NewActionSecureKeyError(errorMsg string) *DeployError {
+ var err = &DeployError{}
+ err.SetErrorType(ERROR_ACTION_ANNOTATION)
+ err.SetCallerByStackFrameSkip(2)
+ err.SetMessage(errorMsg)
+ return err
+}
+
func IsCustomError(err error) bool {
switch err.(type) {
diff --git a/wski18n/i18n_ids.go b/wski18n/i18n_ids.go
index d670ec4..9fda5f7 100644
--- a/wski18n/i18n_ids.go
+++ b/wski18n/i18n_ids.go
@@ -36,6 +36,8 @@
COMMAND_LINE = "command line"
CONFIGURATION = "Configuration"
DEPLOYMENT_FILE = "deployment file"
+ FEATURE_DISABLED = "disabled"
+ FEATURE_ENABLED = "enabled"
MANIFEST_FILE = "manifest file"
NAME_PROJECT = "project name"
PACKAGE_BINDING = "package binding"
@@ -50,48 +52,48 @@
// Known keys used for text replacement in i18n translated strings
const (
KEY_ACTION = "action"
+ KEY_API = "api"
+ KEY_API_BASE_PATH = "apibasepath"
+ KEY_API_RELATIVE_PATH = "apirelativepath"
+ KEY_ARG = "arg"
+ KEY_BINDINGS = "bindings"
KEY_CMD = "cmd"
KEY_CODE = "code"
+ KEY_DEPENDENCY = "dependency"
KEY_DEPLOYMENT_NAME = "dname"
KEY_DEPLOYMENT_PATH = "dpath"
+ KEY_DESTINATION = "destination"
+ KEY_DUMMY_TOKEN = "dummytoken"
KEY_ERR = "err"
KEY_EXTENSION = "ext"
KEY_FILE_TYPE = "filetype"
KEY_HOST = "host"
+ KEY_INCLUDE = "include"
+ KEY_INPUTS = "inputs"
KEY_KEY = "key"
KEY_LIMIT = "limit"
+ KEY_LOCATION = "location"
KEY_MANIFEST_NAME = "mname"
KEY_MANIFEST_PATH = "mpath"
KEY_NAME = "name"
KEY_NAMESPACE = "namespace"
KEY_NEW = "newkey"
KEY_OLD = "oldkey"
+ KEY_PACKAGE = "package"
KEY_PATH = "path"
KEY_PROJECT = "project"
+ KEY_RESPONSE = "response"
+ KEY_RULE = "rule"
KEY_RUNTIME = "runtime"
- KEY_SOURCE = "source"
- KEY_VALUE = "value"
- KEY_VALUE_MIN = "min" // TODO() attempt to use this for Limit value range errors
- KEY_VALUE_MAX = "max" // TODO() attempt to use this for Limit value range errors
- KEY_API = "api"
- KEY_URL = "url"
- KEY_PACKAGE = "package"
- KEY_BINDINGS = "bindings"
- KEY_DEPENDENCY = "dependency"
- KEY_LOCATION = "location"
KEY_SEQUENCE = "sequence"
+ KEY_SOURCE = "source"
KEY_TRIGGER = "trigger"
KEY_TRIGGER_FEED = "feed"
- KEY_RULE = "rule"
- KEY_ARG = "arg"
- KEY_INPUTS = "inputs"
- KEY_API_BASE_PATH = "apibasepath"
- KEY_RESPONSE = "response"
- KEY_API_RELATIVE_PATH = "apirelativepath"
- KEY_DESTINATION = "destination"
- KEY_INCLUDE = "include"
- KEY_DUMMY_TOKEN = "dummytoken"
+ KEY_URL = "url"
KEY_UUID = "uuid"
+ KEY_VALUE = "value"
+ KEY_VALUE_MAX = "max" // TODO() attempt to use this for Limit value range errors
+ KEY_VALUE_MIN = "min" // TODO() attempt to use this for Limit value range errors
)
// DO NOT TRANSLATE
@@ -216,6 +218,7 @@
ID_ERR_REQUIRED_INPUTS_MISSING_VALUE_X_inputs_X = "msg_err_required_inputs_missing_value"
ID_ERR_API_GATEWAY_BASE_PATH_INVALID_X_api_X = "msg_err_api_gateway_base_path_invalid"
ID_ERR_RUNTIME_PARSER_ERROR = "msg_err_runtime_parser_error"
+ ID_ERR_WEB_ACTION_REQUIRE_AUTH_TOKEN_INVALID_X_action_X_key_X_value = "msg_err_web_action_require_auth_token_invalid"
// Server-side Errors (wskdeploy as an Action)
ID_ERR_JSON_MISSING_KEY_CMD = "msg_err_json_missing_cmd_key"
@@ -261,10 +264,11 @@
ID_VERBOSE_CREATING_ZIP_FILE_X_path_X = "msg_verbose_creating_zip_file"
ID_VERBOSE_DELETING_FILE_X_path_X = "msg_verbose_deleting_file"
ID_VERBOSE_LIST_OF_FILES_MATCHING_PATTERN = "msg_verbose_list_of_files_matching_pattern"
+ ID_VERBOSE_ACTION_AUTH_X_action_X_value_X = "msg_action_authentication"
)
// DO NOT TRANSLATE
-// Used to unit test that translations exist with these IDs
+// Used to unit test that translations exist with these IDs and their keys != their values (string)
var I18N_ID_SET = [](string){
ID_CMD_DESC_LONG_REPORT,
ID_CMD_DESC_LONG_ROOT,
@@ -278,11 +282,11 @@
ID_CMD_FLAG_CONFIG,
ID_CMD_FLAG_DEFAULTS,
ID_CMD_FLAG_DEPLOYMENT,
- ID_CMD_FLAG_PREVIEW,
ID_CMD_FLAG_KEY_FILE,
ID_CMD_FLAG_MANAGED,
ID_CMD_FLAG_MANIFEST,
ID_CMD_FLAG_NAMESPACE,
+ ID_CMD_FLAG_PREVIEW,
ID_CMD_FLAG_PROJECT,
ID_CMD_FLAG_PROJECTNAME,
ID_CMD_FLAG_STRICT,
@@ -292,9 +296,11 @@
ID_DEBUG_PACKAGES_FOUND_UNDER_PROJECT_X_path_X_name_X,
ID_DEBUG_PACKAGES_FOUND_UNDER_ROOT_X_path_X,
ID_DEBUG_PROJECT_SEARCH_X_path_X_key_X,
+ ID_ERR_CANT_SAVE_DOCKER_RUNTIME,
ID_ERR_DEPENDENCY_UNKNOWN_TYPE,
ID_ERR_ENTITY_CREATE_X_key_X_err_X_code_X,
ID_ERR_ENTITY_DELETE_X_key_X_err_X_code_X,
+ ID_ERR_FILE_ALREADY_EXISTS,
ID_ERR_JSON_MISSING_KEY_CMD,
ID_ERR_JSON_MISSING_KEY_CMD,
ID_ERR_KEY_MISSING_X_key_X,
@@ -305,15 +311,16 @@
ID_ERR_RUNTIMES_GET_X_err_X,
ID_ERR_URL_INVALID_X_urltype_X_url_X_filetype_X,
ID_ERR_URL_MALFORMED_X_urltype_X_url_X,
- ID_ERR_CANT_SAVE_DOCKER_RUNTIME,
- ID_ERR_FILE_ALREADY_EXISTS,
+ ID_ERR_WEB_ACTION_REQUIRE_AUTH_TOKEN_INVALID_X_action_X_key_X_value,
ID_MSG_COMMAND_USING_X_cmd_X_filetype_X_path_X,
ID_MSG_CONFIG_INFO_APIHOST_X_host_X_source_X,
ID_MSG_CONFIG_INFO_AUTHKEY_X_source_X,
ID_MSG_CONFIG_INFO_NAMESPACE_X_namespace_X_source_X,
+ ID_MSG_CONFIG_MISSING_APIGW_ACCESS_TOKEN,
ID_MSG_CONFIG_MISSING_APIHOST,
ID_MSG_CONFIG_MISSING_AUTHKEY,
ID_MSG_CONFIG_MISSING_NAMESPACE,
+ ID_MSG_CONFIG_PROVIDE_DEFAULT_APIGW_ACCESS_TOKEN,
ID_MSG_DEPENDENCY_DEPLOYING_X_name_X,
ID_MSG_DEPENDENCY_DEPLOYMENT_FAILURE_X_name_X,
ID_MSG_DEPENDENCY_DEPLOYMENT_SUCCESS_X_name_X,
@@ -355,6 +362,4 @@
ID_WARN_PACKAGES_NOT_FOUND_X_path_X,
ID_WARN_RUNTIME_CHANGED_X_runtime_X_action_X,
ID_WARN_WHISK_PROPS_DEPRECATED,
- ID_MSG_CONFIG_MISSING_APIGW_ACCESS_TOKEN,
- ID_MSG_CONFIG_PROVIDE_DEFAULT_APIGW_ACCESS_TOKEN,
}
diff --git a/wski18n/i18n_resources.go b/wski18n/i18n_resources.go
index 1430566..aae595c 100644
--- a/wski18n/i18n_resources.go
+++ b/wski18n/i18n_resources.go
@@ -97,7 +97,7 @@
return a, nil
}
-var _wski18nResourcesEn_usAllJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xcc\x3c\x6b\x6f\x1b\x39\x92\xdf\xe7\x57\x14\x06\x0b\x64\x16\x90\xe5\xec\xe2\x70\x58\x18\x97\x03\xbc\xb1\x33\xeb\x9d\x64\x1c\xd8\xce\x0c\xe6\x12\xa3\x43\x75\x97\x24\xae\xbb\xc9\x5e\x92\x2d\x45\x63\xe8\xbf\x1f\xaa\x48\x76\xb7\x64\xf5\x43\x4e\x06\x77\xf9\x12\x49\x24\xeb\xc5\x62\xb1\x5e\xf4\xc7\xef\x00\x1e\xbf\x03\x00\xf8\x5e\x66\xdf\x9f\xc1\xf7\x85\x5d\x24\xa5\xc1\xb9\xfc\x92\xa0\x31\xda\x7c\x3f\xf1\xa3\xce\x08\x65\x73\xe1\xa4\x56\x34\xed\x92\xc7\xbe\x03\xd8\x4e\x7a\x20\x48\x35\xd7\x1d\x00\xae\x68\x68\x68\xbd\xad\xd2\x14\xad\xed\x00\x71\x1b\x46\x87\xa0\xac\x85\x51\x52\x2d\x3a\xa0\xfc\x1a\x46\x3b\xa1\xa4\x45\x96\x64\x68\xd3\x24\xd7\x6a\x91\x18\x2c\xb5\x71\x1d\xb0\x6e\x78\xd0\x82\x56\x90\x61\x99\xeb\x0d\x66\x80\xca\x49\x27\xd1\xc2\x0f\x72\x8a\xd3\x09\xbc\x17\xe9\x83\x58\xa0\x9d\xc0\x79\x4a\xeb\xec\x04\xee\x8c\x5c\x2c\xd0\xd8\x09\xdc\x54\x39\x8d\xa0\x4b\xa7\x7f\x06\x61\x61\x8d\x79\x4e\xff\x1b\x4c\x51\x39\x5e\xb1\x62\x6c\x16\xa4\x02\xb7\x44\xb0\x25\xa6\x72\x2e\x31\x03\x25\x0a\xb4\xa5\x48\x71\x3a\x9a\x17\xad\xbb\x38\xb9\x5b\x22\x5c\x97\xa8\x7e\x5d\x4a\xfb\x00\x17\xcc\x4c\x41\x24\xdc\x69\x9d\x7f\x52\x9f\xd4\x9d\x86\x19\x2e\xa4\x82\xb5\x36\x0f\x52\x2d\x60\x2d\xdd\x12\xd6\xf6\xc1\x33\x3e\x01\x53\x79\x02\x5f\xd4\xbf\xbd\x80\x54\x17\x85\x50\xd9\x19\x01\xf8\xe4\xfe\xd4\x4c\x67\x88\x4b\x69\x61\x2d\xf3\x3c\xc8\xae\x85\x5f\x58\x8b\xce\xb6\x78\x95\x0a\x0a\xa1\xe4\x1c\xad\x9b\x6e\x44\x91\x83\x36\xad\x1f\x8a\xfc\x93\xba\x9a\x43\x5a\x19\x43\x24\x67\xd2\x60\xea\xb4\xd9\x40\xa6\xd1\x2a\x07\x4b\xb1\x42\x10\x6a\x53\x2f\x81\xb9\xcc\x71\xd2\x90\x03\xa5\x91\xca\x59\x70\x44\xd2\x12\xf3\x12\x0a\xb4\x56\x2c\x70\xea\x09\x45\x28\xb4\x75\xcc\x8e\x56\xb0\x16\x1b\x0b\x7a\x0e\x95\x65\x39\xd4\x40\x9c\x8e\x9c\x08\x95\x9d\x6a\x03\x95\xea\xe2\x4c\x18\x64\xa1\xec\x88\xa4\xf5\x05\x4e\x0a\x28\x85\x5b\x9e\x3a\x7d\xba\xc3\xf8\xb8\x59\x70\x92\xd5\x03\x59\xbd\x97\x07\x00\x44\x0a\x0f\xff\x3a\x92\x8a\xc1\xe9\xbd\xe4\x7c\x52\xe7\x95\x72\x4b\x3a\x36\x29\xab\xe3\xd9\x27\xd5\xc0\x36\x28\x32\x0b\xa9\xc1\x8c\x26\x88\xdc\xc2\xdc\xe8\x02\xfe\xf4\x8f\xeb\x77\x97\xa7\xd3\xb5\x7d\x28\x8d\x2e\x2d\xcc\x36\x90\xe1\x5c\x54\xb9\xfb\xa4\xae\x57\x68\xd6\x46\x3a\x8c\x3f\x41\xaa\xd5\x5c\x2e\x78\xd3\xe9\xa8\xbe\x7e\x7b\x75\xf6\x49\x01\xec\x48\xf2\x24\x4c\xfa\xaf\xd6\xe4\xff\xee\x11\xc0\xb5\x09\xea\xb9\x01\x91\xe7\xe0\x96\x06\x7b\x80\x8b\x52\x2e\x49\x83\xfe\x71\x7d\x7b\x47\x5f\x2b\xb7\x84\x9f\x2e\x7f\x83\x93\x93\xfa\x14\xc3\xcf\xe7\xef\x2e\x6f\xdf\x9f\xbf\xbe\xec\xc4\x3a\xe2\x9c\xdb\xa5\x36\xae\xdf\x68\xbd\x37\x7a\x25\x33\xb4\x20\xc0\x56\x45\x21\x0c\x49\x99\xe6\x93\x4e\x3f\xd1\xd4\x19\x92\x92\x47\xeb\x76\x1a\xf7\x1a\x33\x98\x09\x8b\x19\xb1\x1c\x69\x6c\xed\x2d\xfc\x76\xfe\xee\xed\x18\xbb\x14\xe8\xed\x36\x4c\xe7\xe0\xb4\xce\xc1\xa2\xa3\xf3\xc5\x67\x33\x48\x75\xa3\x2b\x03\xba\x44\xb5\x66\x7a\xcb\x60\x67\xc3\xb1\x14\xbb\x87\x7d\x3c\x2d\x2b\x34\x96\x70\x77\x09\x4f\x2a\xc7\x76\x2e\xcc\x03\x55\x15\x33\x34\x24\xbb\x7a\xc3\x47\xe3\xb2\x1b\x95\xf6\xf3\xed\x34\xd0\x24\xcf\x6c\xb3\x39\x35\xb3\x33\x74\x6b\x44\x05\x69\x2e\x49\xec\x42\x65\x60\xd1\xac\xd0\x8c\xbe\x14\xc6\xd3\xd0\xda\x5e\xc2\x13\x55\x81\x7f\xd8\x51\x9d\xee\xad\xa0\x75\xba\x24\xf8\x22\x6f\xc3\xa3\x2d\x8a\xd3\x59\x75\xc8\x2e\x5c\xc8\xf9\x1c\xd9\xa2\x47\x8b\x6b\x2a\x45\x77\x37\x93\x73\xb6\x6b\x84\xe8\xa7\xa7\xbf\x8c\xb4\x60\xbd\x53\xdb\xd6\xeb\xf9\x30\x4e\x4a\xa3\xff\x85\xa9\xa3\xf3\x0e\xef\x6f\xae\xff\x79\xf9\xfa\x6e\xb4\x9e\x44\x51\x77\xec\xd3\x87\xce\x7b\x86\x8d\xa5\x57\x88\xb1\xfa\x30\x16\x97\xc1\x42\xaf\xd0\x3e\xc5\xb9\x5e\xca\x74\x09\x6b\x34\xd8\x38\x45\x4c\x07\x9d\x9a\x1d\x4d\xd8\xb7\x17\x3b\x7e\x46\x86\x39\x3a\xda\xec\xc3\x4c\xed\x00\xf3\xd7\xb9\xa9\xd4\xd9\xff\xbb\xeb\xed\x30\xa4\x43\xda\x00\x3f\x68\x95\x6f\xd8\xbf\xb2\x30\xd7\xa6\x25\x1e\xf6\xfe\x58\xc1\x0a\x9d\xe1\x9f\x47\xeb\x0d\x7e\xe9\xb9\x07\x2e\x79\x10\x02\x25\x3b\xc2\xad\x45\x3e\x56\x69\x46\x20\xb2\xb4\x5d\x62\x81\x59\x3f\x46\xb2\x36\x3b\x4a\x32\xaf\x14\xfb\xcd\xde\x46\x74\xf8\x63\xb4\x8a\x1c\x50\x4f\xc7\x9e\x16\xf8\x1f\x3b\x84\xde\xda\x54\x3f\x0f\xb3\x93\x23\x2e\xdd\x79\x2e\x16\x89\x28\x65\x42\xd7\x7b\x07\xff\xfe\x7e\x3a\x7f\x7f\x05\x9f\xe9\xfe\xff\x3c\x12\x62\xff\x45\xd4\x02\xfa\xcb\xe5\xcd\xed\xd5\xf5\xcf\xa3\xe0\x56\x6e\x99\x3c\x60\xd7\xe1\xa6\x61\x6d\xe4\xef\xfc\x03\x7c\xfe\xe9\xf2\xb7\x31\x40\x53\x34\x2e\xa1\xdd\xe9\x80\x4a\xf2\x25\xeb\x4d\x47\x76\x4a\x93\x79\x2b\xc7\x00\x66\x57\xac\x03\x6a\xdb\xa9\xfb\x21\x7a\x7a\xd2\xee\xbb\x86\x03\x87\xc5\x4b\x25\xcf\xf5\x3a\x09\x30\xba\xa2\x4f\x9e\x04\xf5\xa4\x61\xa8\xcd\xf1\xed\x93\x4b\x1d\x34\xd4\xf7\xe0\x08\xd0\xa5\xc1\x95\xc4\x75\x07\x5c\xbb\x64\x42\x23\xd0\xd3\x9d\x8b\xba\xcc\x85\x1a\x81\xe1\x01\x37\xa3\xb7\xf4\x01\x37\x63\x09\xf7\x92\x0e\x86\xa0\x57\xd0\xd1\x48\xd4\xe1\xb4\xa3\x8b\x01\x0a\x61\x1e\x30\x8b\xa6\x64\x94\xa8\x18\x4e\x42\x87\xbe\x8b\x99\x80\x8a\xa7\x0c\x43\x8c\xd6\x61\x60\x57\x77\x2e\xa7\x11\x60\xeb\x40\xa0\x03\x6e\x33\x3e\x9a\xe9\x01\x0a\xbd\x5f\x90\xa3\xb5\x51\xda\x23\x40\x5b\x67\x64\x27\x64\xbf\x75\x95\x45\xba\xbc\xe6\x52\x61\x46\x56\xd9\xc9\xa2\x76\x97\x47\x60\x70\xa6\x5b\x08\x3c\x06\xba\x72\x65\x35\x86\x58\xaf\x6e\x2b\x34\x33\x6d\xbb\x40\x86\xd1\x63\x81\x96\xc2\x88\xa2\x53\xc0\x46\x14\xe8\xd0\xc0\x4a\xe4\x15\xf2\xed\x4d\xc6\x14\x7e\x39\x7f\xfb\xe1\xf2\x33\x5d\xee\x85\x38\x12\x55\xdf\x69\xfc\xfc\xe6\xea\xed\xe5\x67\x0a\x73\x9d\x90\xec\x20\x1f\xa2\xe0\x9f\xb7\xd7\x3f\x0f\xa3\x66\xab\x9a\x14\xd2\x92\x2f\xce\xf7\x45\xf7\x75\x41\x17\x31\xcd\x68\x62\x77\x20\x5b\x20\x2d\x28\x1d\xa3\xee\xca\x60\x36\xfd\xd4\xb7\xef\x7b\x18\x7d\xa4\xdc\x83\x91\xee\x3c\x0e\xa6\xbf\x0a\xcf\xd0\x71\x23\x4c\x4d\x6c\xfe\x2c\x54\x81\x95\xbe\xac\xe8\x3e\x3f\x1f\x1f\x1f\xa7\xf4\x79\xbb\xbd\x9f\x78\xc7\xe8\xf1\x71\x6a\x75\x65\x52\xdc\x6e\x47\xe1\xf4\x1b\x36\x84\x93\x13\x10\x61\xaf\x2c\xba\xe7\xe1\xaa\xc5\x33\x84\x6d\x47\x8e\xc4\x62\xfd\xc3\xf3\xf9\x2c\xe5\x62\x9d\x38\x54\x42\xb9\x44\x66\x63\x64\xfc\xa3\x70\x48\xae\xe2\x1d\x2f\x82\xab\x8b\x48\x4d\x55\xc9\xec\x2b\x09\x11\x9c\x99\x4e\x9c\x7e\x40\x75\x0c\x2d\x7e\x1d\xf0\xba\xe7\xed\x45\xa5\x0a\x61\xec\x52\xe4\x49\xae\x53\x91\x77\x46\x6d\x61\x56\xcb\xd1\x0e\x96\x39\x38\xe0\xbc\x3a\x58\x8b\x91\x08\x15\x3a\x0a\x56\x9e\x8d\x52\x2a\x87\x46\xa1\x03\xe1\x88\xdd\xca\xe4\x03\xbc\x36\x6e\x4c\x92\x0a\x95\x62\x9e\x77\x3a\x11\xd7\x3f\x4d\xe1\xb5\x9f\xd3\xe4\xaf\x38\x2c\x1b\x89\x60\x2e\x64\x37\xf4\x56\x7e\x3c\x93\x59\x30\x0d\x45\x99\xa3\x43\xb0\x15\x6d\xe9\xbc\xca\xf3\xcd\x14\x6e\x2a\x05\x9f\x9f\x06\x80\x9f\x39\x5e\xe1\x00\x9a\x4c\xb5\x93\x22\xcf\x37\x4d\xb4\xec\x03\xa3\xb1\x94\xfa\xe4\x5d\x62\x9d\x70\x55\x97\xf3\x7a\x72\x72\x72\xf2\xea\xd5\xab\x57\x87\x73\xfc\xb7\xbc\x14\x68\x02\x4d\x1c\x85\x95\x4b\x35\x98\x8d\x11\x51\x14\x4d\x06\xa1\xbe\xe3\x85\xd3\xaf\x64\xcf\xdf\xeb\xf6\xda\xf1\x48\x7a\xf7\xfb\x43\xdb\x83\xee\xdd\xf1\xd1\xf8\x86\xe4\xb7\x83\xf2\x19\x12\x0c\xa5\x97\x84\x73\x6a\xec\x3c\x90\xd1\x4d\x84\x4b\xc8\xfd\xeb\x40\xfa\xf8\x38\x4d\x8b\x6c\xbb\x0d\x99\xb8\xc7\xc7\x29\x2d\x74\x9b\x12\xb7\x5b\x36\x95\xb4\x76\xbb\xbd\x9f\x4e\x7b\x71\xb3\xcf\xbe\x49\xa2\x3e\x0f\x94\xf5\x1e\x1f\x29\x82\x08\x08\x88\xc8\xed\xf6\x1e\x96\xc2\xc2\x0c\x51\xed\x30\x5c\x9f\x90\xf1\xd8\xbb\xeb\x80\x17\x71\x1c\x0e\x12\x30\x9d\xf6\x64\x50\x03\x8a\x26\x19\xfe\xed\x58\x6c\x60\x8e\x61\x32\xce\xee\x66\xf3\x43\x33\xe3\x20\xa3\xbd\x7c\x66\x58\xa2\xca\x50\xa5\xc7\x88\xb3\x59\xf4\x7c\x3c\xcd\x11\xe9\x94\xe9\xc5\x41\x34\x5f\xa3\x38\x87\xa9\x20\xc3\x50\x99\x2e\x37\xf1\x62\x27\x05\x7e\x98\xf5\xff\xc3\x3b\x22\xf2\x73\x9c\x9e\x7c\xdd\x0e\x3e\x35\x73\xdf\x66\x0f\x47\x9e\x8c\x2e\x4a\xfa\xf7\xf1\xc3\x5e\x31\xe3\x39\x3b\xd9\x47\x55\x48\x58\x3c\xf7\xce\x61\x8a\xfc\x0d\x50\x27\x44\xfa\x68\x81\xac\x32\xb4\x93\x31\xe5\xda\xba\x11\xff\x38\x7d\x8b\x3c\xce\x75\xa5\xb2\x24\xd0\x1b\x2c\x55\xa7\x02\x84\x24\xff\x41\x0b\x19\x2a\x09\xdc\x0f\x41\x74\xb5\xea\x08\xb1\xd6\xbf\x9f\x53\xe6\x4b\xca\x7f\x26\x08\xc2\x32\x2f\x5c\xad\x1f\xeb\x16\x84\x14\x5f\x12\xaa\x58\x5d\x85\x40\x3f\xca\xb1\x0d\xb4\xd2\x8f\x06\x39\xad\x92\x4d\xb8\x2c\xdc\xb8\x5b\xf5\xb6\x11\x1d\xa6\x5e\x11\x90\x80\x68\x55\x4b\xda\x45\x56\xdf\xcb\x10\xb4\xdf\xf8\x32\xe0\x50\xe3\xc7\xe5\xcd\xcd\xf5\xcd\x6d\x07\xdd\xaf\xf6\xff\x81\x9f\x0e\x4f\x06\x5e\xbd\xea\xb9\x7e\x8c\xd9\x3d\x68\x0f\x4a\xaf\x55\x42\x9e\xc2\xf0\x51\xa7\x59\x24\xaa\xb0\x6a\x0a\xad\x5c\x3d\x97\x40\x6c\x55\xfa\x8a\xc1\x29\x67\xb9\xa7\x76\x63\x1d\x16\x30\x93\x2a\x93\x6a\x61\x41\x1b\x58\x48\xb7\xac\x66\xd3\x54\x17\x75\xb5\xb1\xff\xbe\x34\x26\xde\x99\xa9\x41\xe1\xba\xc8\xe4\x3e\x27\xe0\x29\x3b\x6a\xc9\xdd\x2e\xdc\x20\x15\x5b\x43\xce\x68\x10\x8d\xd9\x6e\xb9\x4c\xe1\xc7\x52\x9d\xf9\x01\xfa\x30\x10\xcd\xb4\x48\xf2\x67\xa5\x97\xa4\xec\xc9\x49\xf9\x83\x48\x9a\x23\x52\x38\xbd\xd2\x0f\x5d\x04\xbd\x61\xb3\x45\xe6\xc2\x4f\xe3\x03\x49\xcb\x60\xbd\xc4\x56\xe1\xce\xf9\x36\xa7\x30\xf4\xc7\x50\xfb\x80\x9b\x3a\xa5\x43\xfe\xae\x70\xda\xf4\xa5\xab\xea\x39\x9c\xfd\xf8\x18\x85\x79\x4f\xfa\x18\xe0\x0c\xe2\x8c\x99\xdd\x44\x69\xe7\x8d\x5d\x07\xc2\x77\xed\x14\x30\xdb\x6a\x9e\x4d\xf1\x2e\xe7\x60\xdb\x1e\xf5\x10\x52\xf6\xde\x0b\x69\x0b\xe1\xd2\x2e\xf7\x9d\x18\xac\xd5\x83\x16\x64\x8c\x22\x8b\xf6\x54\xaa\xfd\x5a\x83\x1f\x0f\x34\x70\xbb\x14\x93\xc9\x48\x78\x5b\xd9\xbc\xd1\xa4\xa2\x05\x64\x27\xb5\xed\x47\x23\x1b\xfd\x4c\x84\xf8\x9f\xd4\x4b\xe4\xb2\x4b\x6c\x57\x7e\x94\x7b\xbc\xfc\x96\xd4\x59\x64\xc2\x15\x3e\x13\x2d\x07\x1b\xc4\xb8\x76\x4a\xb4\x0b\x5f\x37\xa4\x35\xfe\xe3\x18\x39\x47\x12\x07\x44\x7d\x73\x0c\x41\x7b\x72\xe5\xa3\xe0\x29\x7a\x61\xc1\x67\x79\xbc\x28\xf1\x8b\x43\x65\x23\xd1\xf8\x85\xef\x30\x62\xe7\x6b\x58\xb1\xc9\x02\xbb\xf2\xa9\xcd\x51\x5e\xa0\x6f\x6b\x09\xb6\xb7\xc9\xdc\x3f\x29\xd0\xd2\xfd\x26\xd3\xd6\xf1\x1d\x2d\x53\x4f\x7a\xe2\x39\xe6\xd3\x53\x63\xeb\xa0\x6f\x87\x61\xf6\x0b\x49\x8c\x8d\x94\x85\xda\xd4\xba\x41\x46\xa4\xb5\xed\x83\x72\x0d\x39\xdd\x9a\x84\x41\x36\x2a\x93\x1f\xaf\xb9\x3e\xb1\x15\x42\xe8\x0f\x37\x6f\x7d\xc6\xd1\xe4\xe1\x28\x7d\xdc\x89\xb1\xef\x7d\xaf\xd2\x18\x42\x0a\x91\xcf\xb5\x29\x3a\x25\xf7\x2e\x8e\xf7\x51\x30\x85\x3b\xb3\x01\xb1\x10\x52\x0d\x85\xf4\xc6\x24\xff\xb2\x5a\xd5\xc6\x36\x2d\xb2\x9e\x42\x32\xd7\x1a\xa4\x2a\x2b\x07\x99\x70\x02\xde\x05\x69\xbc\x48\x8b\xec\x05\x99\xde\x7e\x4c\xa2\x94\x4d\x41\xc0\x2b\x8d\x36\x89\xc5\x7f\x57\xa8\x3a\x33\xf6\xbe\xbd\xf6\xf4\x36\xcc\xda\x3d\x2c\x2d\xfb\xee\xf5\x79\xaf\x77\xe4\xfc\xfd\x95\x5f\x50\x4a\x9a\x9d\x0a\xe5\x5d\x91\x19\x7a\x67\xa0\xdd\xef\xd6\x28\xd9\x69\x24\xe9\x00\xcc\x29\xbc\xcf\x51\x58\x84\xaa\xcc\x84\xdb\x6b\x56\xf1\x97\x67\x9a\x57\xd9\x3e\x9d\xc2\x82\x80\x35\xce\xf6\x31\x0c\xee\x4e\x90\x53\xbf\x82\x9e\x1f\xb0\x23\x24\x9a\xb0\x6a\x0a\x57\xce\x47\x5f\xda\x2d\xf9\x2e\xde\x6d\xc1\xa8\x0f\xde\xc4\x4b\x47\x2b\x0c\x55\xe0\x82\xa0\xe0\x97\x12\xd3\x31\x27\x29\xd0\x1a\xb7\x38\xda\x07\x32\x8c\x09\x61\xfd\x4a\xea\x99\xf0\xc6\x48\x10\x58\x5d\xb9\xb6\xb1\x98\xc2\xaf\x8d\x11\x8e\xa6\x82\x96\x4d\x6a\x73\x22\x6d\xe3\x2c\x0c\x5c\x6b\x81\x9d\x28\xa6\x84\xa2\x15\x87\x49\x26\xcd\x28\x23\x77\x90\x2d\xe2\xa3\x96\x7b\xa9\xa5\xf2\x2e\x95\x0f\xd1\x1c\xb6\x9a\x9c\x9b\xe3\x3c\xa1\x10\x30\x72\xc5\x4d\xc6\x7b\x16\xae\x9f\x8d\x54\x50\xc0\x2e\x56\x98\x64\x3a\x7d\xc0\xae\xa7\x00\xaf\x85\x62\xa8\x62\x85\x70\xc1\x13\x41\x16\xec\x80\x0f\x38\x96\x32\xc7\x44\xe4\x06\x45\xb6\x49\xf0\x8b\xb4\x9d\xad\x16\x6f\xe8\x84\x84\x99\xe0\x67\x0e\xc0\xce\x62\xab\x60\x13\x95\x48\xb4\x5e\xa1\x2c\x79\x4e\xb9\x98\x61\x57\x71\xe4\x5a\x21\x90\x1e\xe6\xb8\x1f\xf6\x37\x5f\xe3\x96\xb8\xb5\x86\x1a\x19\x17\x4d\xbc\xac\x69\x76\xfc\xe6\x0d\xeb\x52\x5a\x78\x90\x2a\xa3\x03\x12\x74\x31\xd4\x48\x9f\x5c\x3c\x7b\x96\x82\xec\x4b\x8b\x10\x26\xfd\x00\x39\xe1\x41\xc0\x13\xbb\xc2\xca\xc2\xf5\x7d\xf2\xdd\x22\x51\x10\xc3\x1a\x64\x1e\x2c\x96\xc2\xd0\x17\x86\xee\xfb\xcd\x3a\x78\x1b\xa7\xfc\xe1\x90\x25\xc4\xf2\xb1\x7a\xae\xb4\x97\x94\x45\x77\x1c\xb2\x63\x6d\x45\x40\xd6\x3a\xef\x03\xf8\xa2\xf5\x4d\x96\x62\x45\x96\x8a\x75\xc9\x27\xd2\x6d\x20\xa6\xeb\xb1\x4a\xfb\x1a\x8a\x60\x82\xbd\x8a\xaa\x1d\x7b\x24\xc8\xe6\xab\x68\x8c\x7c\xa0\xcf\xae\x18\xed\x5f\x88\x6e\xa7\xf1\xf5\x48\x68\xf1\xf5\xf0\x2c\x5f\x54\xa4\x4c\xfc\xc4\x81\x17\xb0\xc7\x2e\x15\x88\xa8\xd3\x11\xc2\xc0\xe1\xd7\x6a\x9e\xcb\x94\xac\x4c\x12\x02\x37\xe2\xd0\x68\x6b\x63\x26\xa4\xeb\xb8\xb6\xce\x4f\x0c\xf9\x88\xe9\xf0\x39\xf0\x1c\x79\x65\xe7\xb7\xa8\x72\x27\xcb\xdc\x47\x8d\xfe\xf0\xd0\xa7\xe0\x91\x78\xe4\x6c\xbe\xe2\xdd\xbb\x97\x06\x71\xed\xa2\xf2\x04\xa4\xf3\x27\xaa\xd4\xd6\xca\x99\x3f\x05\x2c\x90\xc8\x88\xc7\xda\x88\x67\x46\x7e\x49\xad\xe9\x4c\xc4\x93\x43\x18\x38\x61\x34\x4f\x82\x9e\x23\x84\x69\xaa\x1c\x9f\x21\x49\x5a\x16\xa2\x8b\x1c\x0f\xc9\xb0\xa1\x3f\xda\xfb\x3d\x47\xc2\xbf\x41\xa9\x45\xb0\xbb\x25\x53\xff\xf4\xe8\x5b\x08\x99\x19\x3c\x24\x61\x61\xad\x4e\x25\x83\x3e\x4c\xf1\x69\x24\x6e\x5f\xf8\xcc\xfc\xb3\x24\x2f\x4c\xd3\xe2\xc1\xc5\xec\xce\xd6\xf6\x50\x20\x83\x5c\x2a\x04\x61\x16\x15\x07\xc5\x24\x42\xb3\xd8\x6e\xdb\xfe\x22\xc3\x99\x40\xe9\x49\x8c\xaf\x3e\x48\x1e\x3c\x72\x04\x45\x0f\xb8\xf9\x66\x54\x3d\xe0\xe6\x94\x61\x41\x29\xa4\x79\x42\xde\xee\x30\xdb\x77\xfc\x22\x8a\x92\x9c\xdd\x1a\xdc\x03\x6e\x46\xf1\x10\x1c\xac\xe1\x4e\xa4\x2e\x06\x7e\x88\x28\xff\xcc\x36\x38\xc0\xf3\x6d\x4a\xfe\xe2\xaa\x53\x21\x13\x9f\x90\x6c\x85\x97\x51\x39\xea\xf7\x36\xe0\x57\x73\x90\xd1\x80\x18\xca\x3d\xe0\xbf\x2b\x69\x38\xb7\x55\x56\xce\x8e\xd2\x92\x9b\xb0\xc6\x87\x32\xfe\xb4\xec\x68\x85\x05\x5c\xa1\x02\x31\x77\x68\x40\x94\x65\xce\xf5\x13\x6e\x6c\x28\xb5\x87\x13\x6a\xa9\xa8\x56\x53\x58\x09\x23\xc5\x2c\xc7\x46\xe1\x2d\xba\x1a\xe2\xee\x94\x78\x80\x7d\x14\xd5\xb4\x71\x1d\x7a\x6d\xe3\x5f\x36\x99\xf0\xfe\x88\x37\x7b\xae\xf3\x5c\xaf\x3d\x35\x44\x3b\xcb\xd3\x7f\xdc\x6e\x87\xa3\xaf\x85\x6f\x50\x49\x28\xe8\xe1\x8a\xf1\x50\x60\xd1\x6a\x6a\xa1\x35\x4d\x82\x4b\x94\x92\x7e\x88\x39\xa6\x03\xee\x3a\x4f\xad\x3b\xd6\xe2\x03\x82\x7d\x2f\x29\x84\x1c\x06\x09\xe9\x2a\x20\xa8\x33\xc5\x7b\x30\x46\xe6\xa1\x4a\x61\x2c\x9a\xde\x87\xaf\x4d\x86\xc4\xa0\x33\x12\xd9\xe0\x85\xc4\x48\xad\xa1\x87\xb1\xfd\x7a\x7e\xf3\xf3\xd5\xcf\x3f\x8e\xcf\xc4\xc7\x05\xc7\xe5\xe2\xd7\xc2\xa8\xba\xdc\x4f\x44\x76\x05\xe5\x37\x34\x46\x1a\xf1\x31\xd6\xf9\xef\x83\xe6\xb2\x00\xce\x7c\x72\x84\x18\xba\xef\x0b\xe0\x02\x3e\xee\x7e\x3a\x3a\x1d\xd2\xee\xda\x6e\xa5\x3f\x21\x43\x37\x1c\x3a\x32\x66\xb2\xa1\x19\x96\x06\x53\xba\x59\x12\x83\x65\x2e\xd2\xce\xd8\xea\x6e\xe9\xf1\xe8\x3c\x0b\x89\x5e\xee\x7a\xf3\xae\xf3\x6e\x7f\x03\x3f\x45\xb5\x5a\x2b\x0a\xfa\x1b\x0c\xb5\x65\xad\xac\x77\xcd\xb9\x42\x85\xeb\x1d\x70\xd6\xa1\x18\x49\x7b\x90\xc4\x73\x72\xd4\x76\xa9\xab\x3c\x23\xf2\xc8\x53\x86\x0f\xd6\x17\x6b\x7d\x25\xc9\x1b\x7b\x9a\xcd\x9f\x86\xbb\x34\x6a\x8a\x78\xfe\xc0\x56\x12\x5d\x1e\x03\x19\x97\xa7\xb9\x73\x3a\xaa\xfe\x54\x1f\x81\x92\x83\x63\xb1\xea\xdd\xbc\x21\xa4\xbc\x3e\x6e\x68\xac\x0a\xc6\xb7\x79\xed\x47\x79\xc3\x84\xe5\xb2\x90\x2e\x91\x0b\xa5\x4d\x27\x49\x51\xa5\x83\xb3\xce\x4b\x7c\xf0\x47\x9f\xf6\xf3\xe3\x64\xec\x3c\xb8\xb1\xd8\xd3\xa5\x50\x0b\xa4\x0b\xa0\x3f\xae\x79\x5b\x23\xae\xf3\xf2\x36\xb2\x9f\x6f\x7c\x5d\xb8\x06\x35\x85\x2b\xa2\x42\xaa\xc5\x18\x95\x60\x42\x6c\x92\xeb\x45\x62\xe5\xef\x03\x74\xf0\xe4\x33\xc8\xf5\xe2\x56\xfe\x4e\xaa\xcb\x29\x33\x5d\x39\x2b\xb3\x18\xc9\x7a\xfd\x34\x44\x0d\xed\xc8\xc7\x97\x13\xf8\xcb\xcb\x7b\x78\xf7\xf7\xfa\x16\x5c\xa1\xa1\x8b\x9d\xab\x9b\xa5\x7f\x9e\x6a\x1a\xdb\xce\xaf\xb2\xbd\x9b\x32\x96\xf8\x02\x0b\x6d\x36\xe3\xe9\xf7\xf3\xc7\xb3\xf0\x97\xbf\xfe\x6d\x02\x7f\x7d\xf9\x1f\x7f\xfb\x63\xd9\xa0\x6b\x46\x57\x9d\x4f\x63\x77\x58\x08\x73\x47\xd2\xff\xf2\xe5\x04\xfe\xf3\x25\xfd\xbb\x87\x42\xe6\xb9\xb4\x98\x6a\xd5\x0a\x83\xbe\x1d\x2f\x5c\xc3\x4d\x4a\xa3\x4b\x34\x4e\x76\xc6\x3e\xd1\x52\xb7\xec\xaa\xaf\xfc\xfb\x5b\x37\xd4\xfe\x7d\x41\xb8\x01\x16\x7b\x04\x0e\xdb\xee\x68\xba\x33\xcd\x27\x82\x2c\xb8\x74\xb5\x68\xf4\x1c\xee\x8c\x58\x49\x0b\xb3\x4a\xe6\x59\x7f\x01\x99\x59\xf1\x66\x8b\xc5\x38\xca\x64\xd5\xc7\x73\xc7\x70\xa9\xbd\x8b\x27\x98\x75\x2e\x8b\x53\x90\xe6\x7f\x8d\x2f\x7b\x1f\x1f\xa7\x85\x54\xa1\x48\x4a\x5f\x44\x3a\x50\x72\x61\x52\xa3\x8b\xe3\xad\x40\x97\x39\x8b\x65\xac\x30\x8b\xdc\x9c\xbd\x8a\xd6\x81\xac\x77\x67\xd1\xea\x59\x95\x2a\xa6\x36\xd4\xc1\x39\xb3\xd2\x9b\x1a\x7c\x52\xe2\xdc\xb1\x81\x7b\x39\xc3\xc6\xc9\xce\xf9\xbd\xa1\xd2\x6e\x19\x42\xfa\x61\x92\x62\xa8\x3e\x58\xe5\xbd\x7b\x92\x84\x6b\x3b\x36\xe1\x51\x06\x66\xa0\xf4\xb8\x56\x05\xc6\xde\xea\x12\x62\xa1\x8c\x21\xe2\x60\x0f\x4d\xb8\x19\xf7\x83\x85\x75\x28\xa5\xf9\x82\xf4\xa1\x54\xe2\x08\x09\xb5\x9e\x56\x25\x7a\x85\xc6\xc8\x2c\xc3\xae\x84\x18\x51\xd8\x7e\x69\xd5\x74\x79\x35\x4b\xa3\x4f\xd3\x6e\xe2\x19\xbb\x51\x89\xb4\x49\x59\xcd\x72\xd9\xf5\x9a\xdd\xef\x0a\xcf\x8d\x05\x21\xff\x98\x8c\x42\x10\x5e\xf8\x24\xd9\x30\x21\x73\xc1\xb6\x65\x86\xb0\x92\x3e\xef\x41\xe7\x30\x15\x6c\x69\x7c\xfb\x3e\x66\x30\xdb\x80\x50\x1b\xad\x7a\x1e\x67\x31\xad\x31\x7f\x89\xb3\xf0\x64\x76\xc0\xdd\x78\x9a\xbe\xe4\xca\x0c\xd7\x87\x54\x46\xff\x9f\x84\xd7\xad\xfb\xa5\x19\x3a\x08\xfc\xe7\x49\x70\x36\xf1\x4e\x48\xf8\x16\x16\xf4\x44\x48\x9e\xd2\x56\x09\x8e\xc8\xed\x4d\x76\x76\x15\x66\x48\xc3\xda\xd5\xac\x51\x75\xb6\xf0\x67\x55\xea\x45\x53\x78\xad\xd5\x8a\xcc\x7d\x08\x5d\x1a\x14\x4e\xef\x80\x1f\x56\xd9\x7d\xae\x06\x4a\x8a\x7d\x49\xdc\x86\xb7\x38\x70\x24\x77\x75\x65\x6f\x9f\xbf\x36\xa2\x9a\xc3\x51\x75\xc0\x9a\xc7\x98\xb0\x31\x68\x4b\xad\x2c\xf6\x75\x66\xed\x11\xcd\xa9\xba\xfd\x90\x3c\x8c\xc7\xe0\xbb\x15\xcc\xc7\xb4\x4a\x9d\x0e\x5c\x3a\x57\xfa\x3f\x61\xe4\x51\xf3\xbd\x36\x85\xd7\x74\xc3\x70\x2b\x47\xfb\x77\x7f\xa9\xf3\x95\x13\x7e\x0e\x4c\x33\x14\xba\x4f\x1a\xca\x86\x34\x36\xee\x2b\xaa\x95\x34\x5a\xb1\xed\x8c\xd9\x94\xae\x22\x79\x88\x4a\x2f\x9b\x25\xf0\x4b\x58\xb2\x1b\x4a\x1d\xc6\x7d\x71\xf9\xf7\x0f\x3f\x8e\x0e\xef\x79\xf6\x71\xb1\x7d\x36\x5b\x24\x16\x85\x49\x97\xc4\x59\x34\xb8\x75\xed\xaf\x53\x6d\xc3\x8a\xda\xe0\xee\x56\x0b\xe3\xf6\x45\xf9\x7a\xc7\x64\x20\x36\x20\x52\xf6\x6f\xa5\x6f\x7d\x23\x3d\xf3\x36\x22\xd2\xea\xeb\xda\x77\x9f\xf6\xfc\x45\x99\x8b\x03\x2d\x50\x41\x22\x67\xf0\x86\x29\x68\xfe\x80\x09\x67\xc2\x09\xd8\xb1\x04\xf4\x3f\xc1\x3d\x9e\x86\x76\x83\x6b\x6c\xc8\x3e\xee\x59\xe5\xde\x33\xb5\xbe\xd7\x81\x34\xf9\xc9\xdb\xb4\xe3\x1f\x40\x86\xb8\xa1\xee\xa8\xfd\xe6\x44\x4c\xd8\xa5\x7f\xf1\xf8\x38\xcd\xaa\xa2\xd8\xf0\xac\xed\xf6\x05\x99\x9f\x76\xdc\xa3\x55\xbf\xfe\x84\x27\xc0\xc9\xef\xb2\x4c\xf0\x0b\x77\x65\xf8\x6a\x75\xcf\x53\x99\x4b\x9e\x47\x67\xec\xbd\x70\xcb\xb3\xf6\x0e\x8e\x45\x25\xb2\x2c\xbe\xcd\xe9\xc3\x74\xce\xd3\x76\x0e\xae\xd3\xf0\x3f\xb2\x84\x37\x43\x07\xa3\x8d\x2d\xb4\x9b\xc4\xee\xab\x1e\x84\x6f\x42\xff\xdc\xad\x77\xf2\x9f\xcd\xdf\x01\x8c\x49\x86\xd6\x49\xc5\xa8\xbe\x86\x04\xf6\x7e\x2e\x1a\x58\xad\x19\x2d\x0c\x23\x69\x8d\x97\x65\xa4\x17\x55\x77\x0e\x35\x26\x52\xe0\x2a\x74\xef\x5c\xd2\x64\x52\x38\xe9\x5a\xb9\x6d\xa6\x24\xc0\xe3\x6a\x5b\x9c\xce\xb0\xd9\x31\x40\xc9\xc1\x08\xdf\x99\x1f\x3d\x9f\xf7\x40\x06\xd9\x7f\x9e\xb4\xd9\xeb\x3f\xea\x91\x8f\xd8\xb5\xcc\xc2\xef\x29\xd2\xbc\x8e\xdd\xcd\x24\xe1\xa8\x47\x47\xef\x70\x2e\xad\x4b\xf4\x9c\x11\xd9\x84\x3b\x1b\xf9\x8e\x12\xce\xa1\xe9\x3a\xd8\xde\xb4\x71\xbf\x70\x5d\x9f\xf0\x7f\xfb\xc9\xd7\x85\x03\x94\xb8\xef\xdc\x08\xf2\xde\xfb\x22\x0c\x36\xca\xe1\xbb\xfb\xef\xfe\x37\x00\x00\xff\xff\xf8\xdf\xc5\xc7\xca\x52\x00\x00")
+var _wski18nResourcesEn_usAllJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xcc\x3c\x6b\x6f\x1b\x39\x92\xdf\xe7\x57\x14\x06\x0b\x64\x16\x90\xe5\xec\xe2\x70\x58\xf8\x2e\x07\x78\x13\x67\xc7\x3b\xc9\x38\xe7\xc7\x0e\xe6\x12\xa3\x43\x75\x97\x24\xae\xbb\xc9\x5e\x92\x2d\x45\x63\xe8\xbf\x1f\xaa\x48\x76\xb7\x64\xf5\x43\x4e\x06\x77\xf9\x12\x49\x24\xeb\xc5\x62\xb1\x5e\xf4\xc7\xef\x00\x1e\xbf\x03\x00\xf8\x5e\x66\xdf\x9f\xc1\xf7\x85\x5d\x24\xa5\xc1\xb9\xfc\x92\xa0\x31\xda\x7c\x3f\xf1\xa3\xce\x08\x65\x73\xe1\xa4\x56\x34\xed\x82\xc7\xbe\x03\xd8\x4e\x7a\x20\x48\x35\xd7\x1d\x00\x2e\x69\x68\x68\xbd\xad\xd2\x14\xad\xed\x00\x71\x13\x46\x87\xa0\xac\x85\x51\x52\x2d\x3a\xa0\xfc\x12\x46\x3b\xa1\xa4\x45\x96\x64\x68\xd3\x24\xd7\x6a\x91\x18\x2c\xb5\x71\x1d\xb0\xae\x79\xd0\x82\x56\x90\x61\x99\xeb\x0d\x66\x80\xca\x49\x27\xd1\xc2\x0f\x72\x8a\xd3\x09\x7c\x10\xe9\x83\x58\xa0\x9d\xc0\x79\x4a\xeb\xec\x04\x6e\x8d\x5c\x2c\xd0\xd8\x09\x5c\x57\x39\x8d\xa0\x4b\xa7\x7f\x04\x61\x61\x8d\x79\x4e\xff\x1b\x4c\x51\x39\x5e\xb1\x62\x6c\x16\xa4\x02\xb7\x44\xb0\x25\xa6\x72\x2e\x31\x03\x25\x0a\xb4\xa5\x48\x71\x3a\x9a\x17\xad\xbb\x38\xb9\x5d\x22\x5c\x95\xa8\x7e\x59\x4a\xfb\x00\x6f\x98\x99\x82\x48\xb8\xd5\x3a\xff\xa4\x3e\xa9\x5b\x0d\x33\x5c\x48\x05\x6b\x6d\x1e\xa4\x5a\xc0\x5a\xba\x25\xac\xed\x83\x67\x7c\x02\xa6\xf2\x04\xbe\xa8\x7f\x7b\x01\xa9\x2e\x0a\xa1\xb2\x33\x02\xf0\xc9\xfd\xa1\x99\xce\x10\x97\xd2\xc2\x5a\xe6\x79\x90\x5d\x0b\xbf\xb0\x16\x9d\x6d\xf1\x2a\x15\x14\x42\xc9\x39\x5a\x37\xdd\x88\x22\x07\x6d\x5a\x3f\x14\xf9\x27\x75\x39\x87\xb4\x32\x86\x48\xce\xa4\xc1\xd4\x69\xb3\x81\x4c\xa3\x55\x0e\x96\x62\x85\x20\xd4\xa6\x5e\x02\x73\x99\xe3\xa4\x21\x07\x4a\x23\x95\xb3\xe0\x88\xa4\x25\xe6\x25\x14\x68\xad\x58\xe0\xd4\x13\x8a\x50\x68\xeb\x98\x1d\xad\x60\x2d\x36\x16\xf4\x1c\x2a\xcb\x72\xa8\x81\x38\x1d\x39\x11\x2a\x3b\xd5\x06\x2a\xd5\xc5\x99\x30\xc8\x42\xd9\x11\x49\xeb\x0b\x9c\x14\x50\x0a\xb7\x3c\x75\xfa\x74\x87\xf1\x71\xb3\xe0\x24\xab\x07\xb2\x7a\x2f\x0f\x00\x88\x14\x1e\xfe\x75\x24\x15\x83\xd3\x7b\xc9\xf9\xa4\xce\x2b\xe5\x96\x74\x6c\x52\x56\xc7\xb3\x4f\xaa\x81\x6d\x50\x64\x16\x52\x83\x19\x4d\x10\xb9\x85\xb9\xd1\x05\xfc\xe1\xc7\xab\xf7\x17\xa7\xd3\xb5\x7d\x28\x8d\x2e\x2d\xcc\x36\x90\xe1\x5c\x54\xb9\xfb\xa4\xae\x56\x68\xd6\x46\x3a\x8c\x3f\x41\xaa\xd5\x5c\x2e\x78\xd3\xe9\xa8\xbe\x7e\x77\x79\xf6\x49\x01\xec\x48\xf2\x24\x4c\xfa\xcf\xd6\xe4\xff\xea\x11\xc0\x95\x09\xea\xb9\x01\x91\xe7\xe0\x96\x06\x7b\x80\x8b\x52\x2e\x49\x83\x7e\xbc\xba\xb9\xa5\xaf\x95\x5b\xc2\x4f\x17\xbf\xc2\xc9\x49\x7d\x8a\xe1\xe7\xf3\xf7\x17\x37\x1f\xce\x5f\x5f\x74\x62\x1d\x71\xce\xed\x52\x1b\xd7\x6f\xb4\x3e\x18\xbd\x92\x19\x5a\x10\x60\xab\xa2\x10\x86\xa4\x4c\xf3\x49\xa7\x9f\x68\xea\x0c\x49\xc9\xa3\x75\x3b\x8d\x7b\x8d\x19\xcc\x84\xc5\x8c\x58\x8e\x34\xb6\xf6\x16\x7e\x3d\x7f\xff\x6e\x8c\x5d\x0a\xf4\x76\x1b\xa6\x73\x70\x5a\xe7\x60\xd1\xd1\xf9\xe2\xb3\x19\xa4\xba\xd1\x95\x01\x5d\xa2\x5a\x33\xbd\x65\xb0\xb3\xe1\x58\x8a\xdd\xc3\x3e\x9e\x96\x15\x1a\x4b\xb8\xbb\x84\x27\x95\x63\x3b\x17\xe6\x81\xaa\x8a\x19\x1a\x92\x5d\xbd\xe1\xa3\x71\xd9\x8d\x4a\xfb\xf9\x76\x1a\x68\x92\x67\xb6\xd9\x9c\x9a\xd9\x19\xba\x35\xa2\x82\x34\x97\x24\x76\xa1\x32\xb0\x68\x56\x68\x46\x5f\x0a\xe3\x69\x68\x6d\x2f\xe1\x89\xaa\xc0\x3f\xec\xa8\x4e\xf7\x56\xd0\x3a\x5d\x12\x7c\x91\xb7\xe1\xd1\x16\xc5\xe9\xac\x3a\x64\x17\xde\xc8\xf9\x1c\xd9\xa2\x47\x8b\x6b\x2a\x45\x77\x37\x93\x73\xb6\x6b\x84\xe8\xa7\xa7\xbf\x8c\xb4\x60\xbd\x53\xdb\xd6\xeb\xf9\x30\x4e\x4a\xa3\xff\x89\xa9\xa3\xf3\x0e\x1f\xae\xaf\xfe\x7e\xf1\xfa\x76\xb4\x9e\x44\x51\x77\xec\xd3\x5d\xe7\x3d\xc3\xc6\xd2\x2b\xc4\x58\x7d\x18\x8b\xcb\x60\xa1\x57\x68\x9f\xe2\x5c\x2f\x65\xba\x84\x35\x1a\x6c\x9c\x22\xa6\x83\x4e\xcd\x8e\x26\xec\xdb\x8b\x1d\x3f\x23\xc3\x1c\x1d\x6d\xf6\x61\xa6\x76\x80\xf9\xeb\xdc\x54\xea\xec\xff\xdd\xf5\x76\x18\xd2\x21\x6d\x80\x1f\xb4\xca\x37\xec\x5f\x59\x98\x6b\xd3\x12\x0f\x7b\x7f\xac\x60\x85\xce\xf0\x8f\xa3\xf5\x06\xbf\xf4\xdc\x03\x17\x3c\x08\x81\x92\x1d\xe1\xd6\x22\x1f\xab\x34\x23\x10\x59\xda\x2e\xb1\xc0\xac\x1f\x23\x59\x9b\x1d\x25\x99\x57\x8a\xfd\x66\x6f\x23\x3a\xfc\x31\x5a\x45\x0e\xa8\xa7\x63\x4f\x0b\xfc\x8f\x1d\x42\x6f\x6d\xaa\x9f\x87\xd9\xc9\x11\x97\xee\x3c\x17\x8b\x44\x94\x32\xa1\xeb\xbd\x83\x7f\x7f\x3f\x9d\x7f\xb8\x84\xcf\x74\xff\x7f\x1e\x09\xb1\xff\x22\x6a\x01\xfd\xc7\xc5\xf5\xcd\xe5\xd5\xcf\xa3\xe0\x56\x6e\x99\x3c\x60\xd7\xe1\xa6\x61\x6d\xe4\x6f\xfc\x03\x7c\xfe\xe9\xe2\xd7\x31\x40\x53\x34\x2e\xa1\xdd\xe9\x80\x4a\xf2\x25\xeb\x4d\x47\x76\x4a\x93\x79\x2b\xc7\x00\x66\x57\xac\x03\x6a\xdb\xa9\xfb\x21\x7a\x7a\xd2\xee\xbb\x86\x03\x87\xc5\x4b\x25\xcf\xf5\x3a\x09\x30\xba\xa2\x4f\x9e\x04\xf5\xa4\x61\xa8\xcd\xf1\xed\x93\x4b\x1d\x34\xd4\xf7\xe0\x08\xd0\xa5\xc1\x95\xc4\x75\x07\x5c\xbb\x64\x42\x23\xd0\xd3\x9d\x8b\xba\xcc\x85\x1a\x81\xe1\x01\x37\xa3\xb7\xf4\x01\x37\x63\x09\xf7\x92\x0e\x86\xa0\x57\xd0\xd1\x48\xd4\xe1\xb4\xa3\x8b\x01\x0a\x61\x1e\x30\x8b\xa6\x64\x94\xa8\x18\x4e\x42\x87\xbe\x8b\x99\x80\x8a\xa7\x0c\x43\x8c\xd6\x61\x60\x57\x77\x2e\xa7\x11\x60\xeb\x40\xa0\x03\x6e\x33\x3e\x9a\xe9\x01\x0a\xbd\x5f\x90\xa3\xb5\x51\xda\x23\x40\x5b\x67\x64\x27\x64\xbf\x75\x95\x45\xba\xbc\xe6\x52\x61\x46\x56\xd9\xc9\xa2\x76\x97\x47\x60\x70\xa6\x5b\x08\x3c\x06\xba\x72\x65\x35\x86\x58\xaf\x6e\x2b\x34\x33\x6d\xbb\x40\x86\xd1\x63\x81\x96\xc2\x88\xa2\x53\xc0\x46\x14\xe8\xd0\xc0\x4a\xe4\x15\xf2\xed\x4d\xc6\x14\xfe\x71\xfe\xee\xee\xe2\x33\x5d\xee\x85\x38\x12\x55\xdf\x69\xfc\xfc\xf6\xf2\xdd\xc5\x67\x0a\x73\x9d\x90\xec\x20\x1f\xa2\xe0\xef\x37\x57\x3f\x0f\xa3\x66\xab\x9a\x14\xd2\x92\x2f\xce\xf7\x45\xf7\x75\x41\x17\x31\xcd\x68\x62\x77\x20\x5b\x20\x2d\x28\x1d\xa3\xee\xca\x60\x36\xfd\xd4\xb7\xef\x7b\x18\x7d\xa4\xdc\x83\x91\xee\x3c\x0e\xa6\xbf\x0a\xcf\xd0\x71\x23\x4c\x4d\x6c\xfe\x2c\x54\x81\x95\xbe\xac\xe8\x3e\x3f\x1f\x1f\x1f\xa7\xf4\x79\xbb\xbd\x9f\x78\xc7\xe8\xf1\x71\x6a\x75\x65\x52\xdc\x6e\x47\xe1\xf4\x1b\x36\x84\x93\x13\x10\x61\xaf\x2c\xba\xe7\xe1\xaa\xc5\x33\x84\x6d\x47\x8e\xc4\x62\xfd\xc3\xf3\xf9\x2c\xe5\x62\x9d\x38\x54\x42\xb9\x44\x66\x63\x64\xfc\x37\xe1\x90\x5c\xc5\x5b\x5e\x04\x97\x6f\x22\x35\x55\x25\xb3\xaf\x24\x44\x70\x66\x3a\x71\xfa\x01\xd5\x31\xb4\xf8\x75\xc0\xeb\x9e\xb7\x17\x95\x2a\x84\xb1\x4b\x91\x27\xb9\x4e\x45\xde\x19\xb5\x85\x59\x2d\x47\x3b\x58\xe6\xe0\x80\xf3\xea\x60\x2d\x46\x22\x54\xe8\x28\x58\x79\x36\x4a\xa9\x1c\x1a\x85\x0e\x84\x23\x76\x2b\x93\x0f\xf0\xda\xb8\x31\x49\x2a\x54\x8a\x79\xde\xe9\x44\x5c\xfd\x34\x85\xd7\x7e\x4e\x93\xbf\xe2\xb0\x6c\x24\x82\xb9\x90\xdd\xd0\x5b\xf9\xf1\x4c\x66\xc1\x34\x14\x65\x8e\x0e\xc1\x56\xb4\xa5\xf3\x2a\xcf\x37\x53\xb8\xae\x14\x7c\x7e\x1a\x00\x7e\xe6\x78\x85\x03\x68\x32\xd5\x4e\x8a\x3c\xdf\x34\xd1\xb2\x0f\x8c\xc6\x52\xea\x93\x77\x89\x75\xc2\x55\x5d\xce\xeb\xc9\xc9\xc9\xc9\xab\x57\xaf\x5e\x1d\xce\xf1\xdf\xf0\x52\xa0\x09\x34\x71\x14\x56\x2e\xd5\x60\x36\x46\x44\x51\x34\x19\x84\xfa\x8e\x17\x4e\xbf\x92\x3d\x7f\xaf\xdb\x6b\xc7\x23\xe9\xdd\xef\xbb\xb6\x07\xdd\xbb\xe3\xa3\xf1\x0d\xc9\x6f\x07\xe5\x33\x24\x18\x4a\x2f\x09\xe7\xd4\xd8\x79\x20\xa3\x9b\x08\x97\x90\xfb\xd7\x81\xf4\xf1\x71\x9a\x16\xd9\x76\x1b\x32\x71\x8f\x8f\x53\x5a\xe8\x36\x25\x6e\xb7\x6c\x2a\x69\xed\x76\x7b\x3f\x9d\xf6\xe2\x66\x9f\x7d\x93\x44\x7d\x1e\x28\xeb\x3d\x3e\x52\x04\x11\x10\x10\x91\xdb\xed\x3d\x2c\x85\x85\x19\xa2\xda\x61\xb8\x3e\x21\xe3\xb1\x77\xd7\x01\xdf\xc4\x71\x38\x48\xc0\x74\xda\x93\x41\x0d\x28\x9a\x64\xf8\xb7\x63\xb1\x81\x39\x86\xc9\x38\xbb\x9b\xcd\xbb\x66\xc6\x41\x46\x7b\xf9\xcc\xb0\x44\x95\xa1\x4a\x8f\x11\x67\xb3\xe8\xf9\x78\x9a\x23\xd2\x29\xd3\x37\x07\xd1\x7c\x8d\xe2\x1c\xa6\x82\x0c\x43\x65\xba\xdc\xc4\x37\x3b\x29\xf0\xc3\xac\xff\x1f\xde\x11\x91\x9f\xe3\xf4\xe4\xeb\x76\xf0\xa9\x99\xfb\x36\x7b\x38\xf2\x64\x74\x51\xd2\xbf\x8f\x77\x7b\xc5\x8c\xe7\xec\x64\x1f\x55\x21\x61\xf1\xdc\x3b\x87\x29\xf2\x37\x40\x9d\x10\xe9\xa3\x05\xb2\xca\xd0\x4e\xc6\x94\x6b\xeb\x46\xfc\xfd\xf4\x2d\xf2\x38\xd7\x95\xca\x92\x40\x6f\xb0\x54\x9d\x0a\x10\x92\xfc\x07\x2d\x64\xa8\x24\x70\x3f\x04\xd1\xd5\xaa\x23\xc4\x5a\xff\x7e\x4e\x99\x2f\x29\xff\x99\x20\x08\xcb\xbc\x70\xb5\x7e\xac\x5b\x10\x52\x7c\x49\xa8\x62\x75\x15\x02\xfd\x28\xc7\x36\xd0\x4a\x3f\x1a\xe4\xb4\x4a\x36\xe1\xb2\x70\xe3\x6e\xd5\xdb\x46\x74\x98\x7a\x45\x40\x02\xa2\x55\x2d\x69\x17\x59\x7d\x2f\x43\xd0\x7e\xe3\xcb\x80\x43\x8d\x1f\x17\xd7\xd7\x57\xd7\x37\x1d\x74\xbf\xda\xff\x07\x7e\x3a\x3c\x19\x78\xf5\xaa\xe7\xfa\x31\x66\xf7\xa0\x3d\x28\xbd\x56\x09\x79\x0a\xc3\x47\x9d\x66\x91\xa8\xc2\xaa\x29\xb4\x72\xf5\x5c\x02\xb1\x55\xe9\x2b\x06\xa7\x9c\xe5\x9e\xda\x8d\x75\x58\xc0\x4c\xaa\x4c\xaa\x85\x05\x6d\x60\x21\xdd\xb2\x9a\x4d\x53\x5d\xd4\xd5\xc6\xfe\xfb\xd2\x98\x78\x67\xa6\x06\x85\xeb\x22\x93\xfb\x9c\x80\xa7\xec\xa8\x25\x77\xbb\x70\x83\x54\x6c\x0d\x39\xa3\x41\x34\x66\xbb\xe5\x32\x85\x1f\x4b\x75\xe6\x07\xe8\xc3\x40\x34\xd3\x22\xc9\x9f\x95\x5e\x92\xb2\x27\x27\xe5\x77\x22\x69\x8e\x48\xe1\xf4\x4a\x3f\x74\x11\xf4\x96\xcd\x16\x99\x0b\x3f\x8d\x0f\x24\x2d\x83\xf5\x12\x5b\x85\x3b\xe7\xdb\x9c\xc2\xd0\xef\x43\xed\x03\x6e\xea\x94\x0e\xf9\xbb\xc2\x69\xd3\x97\xae\xaa\xe7\x70\xf6\xe3\x63\x14\xe6\x3d\xe9\x63\x80\x33\x88\x33\x66\x76\x13\xa5\x9d\x37\x76\x1d\x08\xdf\xb7\x53\xc0\x6c\xab\x79\x36\xc5\xbb\x9c\x83\x6d\x7b\xd4\x43\x48\xd9\x7b\x2f\xa4\x2d\x84\x4b\xbb\xdc\x77\x62\xb0\x56\x0f\x5a\x90\x31\x8a\x2c\xda\x53\xa9\xf6\x6b\x0d\x7e\x3c\xd0\xc0\xed\x52\x4c\x26\x23\xe1\x6d\x65\xf3\x46\x93\x8a\x16\x90\x9d\xd4\xb6\x1f\x8d\x6c\xf4\x33\x11\xe2\x7f\x52\x2f\x91\xcb\x2e\xb1\x5d\xfa\x51\xee\xf1\xf2\x5b\x52\x67\x91\x09\x57\xf8\x4c\xb4\x1c\x6c\x10\xe3\xda\x29\xd1\x2e\x7c\xdd\x90\xd6\xf8\x8f\x63\xe4\x1c\x49\x1c\x10\xf5\xf5\x31\x04\xed\xc9\x95\x8f\x82\xa7\xe8\x85\x05\x9f\xe5\xf1\xa2\xc4\x2f\x0e\x95\x8d\x44\xe3\x17\xbe\xc3\x88\x9d\xaf\x61\xc5\x26\x0b\xec\xca\xa7\x36\x47\x79\x81\xbe\xad\x25\xd8\xde\x26\x73\xff\xa4\x40\x4b\xf7\x9b\x4c\x5b\xc7\x77\xb4\x4c\x3d\xe9\x89\xe7\x98\x4f\x4f\x8d\xad\x83\xbe\x1d\x86\xd9\x2f\x24\x31\x36\x52\x16\x6a\x53\xeb\x06\x19\x91\xd6\xb6\x0f\xca\x35\xe4\x74\x6b\x12\x06\xd9\xa8\x4c\x7e\xbc\xe6\xfa\xc4\x56\x08\xa1\xef\xae\xdf\xf9\x8c\xa3\xc9\xc3\x51\xfa\xb8\x13\x63\xdf\xfb\x5e\xa5\x31\x84\x14\x22\x9f\x6b\x53\x74\x4a\xee\x7d\x1c\xef\xa3\x60\x0a\xb7\x66\x03\x62\x21\xa4\x1a\x0a\xe9\x8d\x49\xfe\x69\xb5\xaa\x8d\x6d\x5a\x64\x3d\x85\x64\xae\x35\x48\x55\x56\x0e\x32\xe1\x04\xbc\x0f\xd2\x78\x91\x16\xd9\x0b\x32\xbd\xfd\x98\x44\x29\x9b\x82\x80\x57\x1a\x6d\x12\x8b\xff\xaa\x50\x75\x66\xec\x7d\x7b\xed\xe9\x4d\x98\xb5\x7b\x58\x5a\xf6\xdd\xeb\xf3\x5e\xef\xc8\xf9\x87\x4b\xbf\xa0\x94\x34\x3b\x15\xca\xbb\x22\x33\xf4\xce\x40\xbb\xdf\xad\x51\xb2\xd3\x48\xd2\x01\x98\x53\xf8\x90\xa3\xb0\x08\x55\x99\x09\xb7\xd7\xac\xe2\x2f\xcf\x34\xaf\xb2\x7d\x3a\x85\x05\x01\x6b\x9c\xed\x63\x18\xdc\x9d\x20\xa7\x7e\x05\x3d\x3f\x60\x47\x48\x34\x61\xd5\x14\x2e\x9d\x8f\xbe\xb4\x5b\xf2\x5d\xbc\xdb\x82\x51\x1f\xbc\x89\x97\x8e\x56\x18\xaa\xc0\x05\x41\xc1\x2f\x25\xa6\x63\x4e\x52\xa0\x35\x6e\x71\xb4\x0f\x64\x18\x13\xc2\xfa\x95\xd4\x33\xe1\x8d\x91\x20\xb0\xba\x72\x6d\x63\x31\x85\x5f\x1a\x23\x1c\x4d\x05\x2d\x9b\xd4\xe6\x44\xda\xc6\x59\x18\xb8\xd6\x02\x3b\x51\x4c\x09\x45\x2b\x0e\x93\x4c\x9a\x51\x46\xee\x20\x5b\xc4\x47\x2d\xf7\x52\x4b\xe5\x5d\x2a\x1f\xa2\x39\x6c\x35\x39\x37\xc7\x79\x42\x21\x60\xe4\x8a\x9b\x8c\xf7\x2c\x5c\x3f\x1b\xa9\xa0\x80\x5d\xac\x30\xc9\x74\xfa\x80\x5d\x4f\x01\x5e\x0b\xc5\x50\xc5\x0a\xe1\x0d\x4f\x04\x59\xb0\x03\x3e\xe0\x58\xca\x1c\x13\x91\x1b\x14\xd9\x26\xc1\x2f\xd2\x76\xb6\x5a\xbc\xa5\x13\x12\x66\x82\x9f\x39\x00\x3b\x8b\xad\x82\x4d\x54\x22\xd1\x7a\x85\xb2\xe4\x39\xe5\x62\x86\x5d\xc5\x91\x2b\x85\x40\x7a\x98\xe3\x7e\xd8\xdf\x7c\x8d\x5b\xe2\xd6\x1a\x6a\x64\x5c\x34\xf1\xb2\xa6\xd9\xf1\x9b\x37\xac\x4b\x69\xe1\x41\xaa\x8c\x0e\x48\xd0\xc5\x50\x23\x7d\x72\xf1\xec\x59\x0a\xb2\x2f\x2d\x42\x98\xf4\x03\xe4\x84\x07\x01\x4f\xec\x0a\x2b\x0b\xd7\xf7\xc9\x77\x8b\x44\x41\x0c\x6b\x90\x79\xb0\x58\x0a\x43\x5f\x18\xba\xef\x37\xeb\xe0\x6d\x9c\xf2\x87\x43\x96\x10\xcb\xc7\xea\xb9\xd2\x5e\x52\x16\xdd\x71\xc8\x8e\xb5\x15\x01\x59\xeb\xbc\x0f\xe0\x8b\xd6\x37\x59\x8a\x15\x59\x2a\xd6\x25\x9f\x48\xb7\x81\x98\xae\xc7\x2a\xed\x6b\x28\x82\x09\xf6\x2a\xaa\x76\xec\x91\x20\x9b\xaf\xa2\x31\xf2\x81\x3e\xbb\x62\xb4\x7f\x21\xba\x9d\xc6\xd7\x23\xa1\xc5\xd7\xc3\xb3\x7c\x51\x91\x32\xf1\x13\x07\x5e\xc0\x1e\xbb\x54\x20\xa2\x4e\x47\x08\x03\x87\x5f\xab\x79\x2e\x53\xb2\x32\x49\x08\xdc\x88\x43\xa3\xad\x8d\x99\x90\xae\xe3\xda\x3a\x3f\x31\xe4\x23\xa6\xc3\xe7\xc0\x73\xe4\x95\x9d\xdf\xa2\xca\x9d\x2c\x73\x1f\x35\xfa\xc3\x43\x9f\x82\x47\xe2\x91\xb3\xf9\x8a\x77\xef\x5e\x1a\xc4\xb5\x8b\xca\x13\x90\xce\x9f\xa8\x52\x5b\x2b\x67\xfe\x14\xb0\x40\x22\x23\x1e\x6b\x23\x9e\x19\xf9\x25\xb5\xa6\x33\x11\x4f\x0e\x61\xe0\x84\xd1\x3c\x09\x7a\x8e\x10\xa6\xa9\x72\x7c\x86\x24\x69\x59\x88\x2e\x72\x3c\x24\xc3\x86\xfe\x68\xef\xf7\x1c\x09\xff\x06\xa5\x16\xc1\xee\x96\x4c\xfd\xd3\xa3\x6f\x21\x64\x66\xf0\x90\x84\x85\xb5\x3a\x95\x0c\xfa\x30\xc5\xa7\x91\xb8\x7d\xe1\x33\xf3\xcf\x92\xbc\x30\x4d\x8b\x07\x17\xb3\x3b\x5b\xdb\x43\x81\x0c\x72\xa9\x10\x84\x59\x54\x1c\x14\x93\x08\xcd\x62\xbb\x6d\xfb\x8b\x0c\x67\x02\xa5\x27\x31\xbe\xfa\x20\x79\xf0\xc8\x11\x14\x3d\xe0\xe6\x9b\x51\xf5\x80\x9b\x53\x86\x05\xa5\x90\xe6\x09\x79\xbb\xc3\x6c\xdf\xf1\x8b\x28\x4a\x72\x76\x6b\x70\x0f\xb8\x19\xc5\x43\x70\xb0\x86\x3b\x91\xba\x18\xf8\x21\xa2\xfc\x23\xdb\xe0\x00\xcf\xb7\x29\xf9\x8b\xab\x4e\x85\x4c\x7c\x42\xb2\x15\x5e\x46\xe5\xa8\xdf\xdb\x80\x5f\xcd\x41\x46\x03\x62\x28\xf7\x80\xff\xaa\xa4\xe1\xdc\x56\x59\x39\x3b\x4a\x4b\xae\xc3\x1a\x1f\xca\xf8\xd3\xb2\xa3\x15\x16\x70\x85\x0a\xc4\xdc\xa1\x01\x51\x96\x39\xd7\x4f\xb8\xb1\xa1\xd4\x1e\x4e\xa8\xa5\xa2\x5a\x4d\x61\x25\x8c\x14\xb3\x1c\x1b\x85\xb7\xe8\x6a\x88\xbb\x53\xe2\x01\xf6\x51\x54\xd3\xc6\x75\xe8\xb5\x8d\x7f\xd9\x64\xc2\xfb\x23\xde\xec\xb9\xce\x73\xbd\xf6\xd4\x10\xed\x2c\x4f\xff\x71\xbb\x1d\x8e\xbe\x16\xbe\x41\x25\xa1\xa0\x87\x2b\xc6\x43\x81\x45\xab\xa9\x85\xd6\x34\x09\x2e\x51\x4a\xfa\x21\xe6\x98\x0e\xb8\xeb\x3c\xb5\xee\x58\x8b\x0f\x08\xf6\xbd\xa4\x10\x72\x18\x24\xa4\xab\x80\xa0\xce\x14\xef\xc1\x18\x99\x87\x2a\x85\xb1\x68\x7a\x1f\xbe\x36\x19\x12\x83\xce\x48\x64\x83\x17\x12\x23\xb5\x86\xf6\x63\x5b\xe3\x2c\x3a\x2e\x41\x09\x7d\x1f\x76\xec\x16\xea\x93\xeb\x9d\x12\xc1\xd6\x5a\x4c\x2b\xe3\x9d\xc3\x26\x3c\xfc\x0f\x38\xe8\xe7\x9c\x93\x87\x2e\xea\x81\x90\xe2\x6c\x9f\x3c\x6f\x1a\x68\x90\x3f\x75\xa7\xee\x7e\x39\xbf\xfe\xf9\xf2\xe7\xbf\x8d\x2f\x27\xc4\x05\xc7\x15\x14\xd6\xc2\xa8\xba\x67\x81\x24\xdd\x95\x59\xb8\xa6\x31\x52\xeb\x8f\xb1\x59\xe1\x3e\x1c\x3f\xde\xc5\x33\x9f\xe1\xa1\x5d\xb9\xef\x8b\x42\x03\x3e\x6e\xe1\x3a\x3a\xa7\xd3\x6e\x3d\x6f\xe5\x70\x21\x43\x37\x1c\xff\x32\x66\xba\x08\x32\x2c\x0d\xa6\x74\x3d\x26\x06\xcb\x5c\xa4\x9d\x01\xe2\xed\xd2\xe3\xd1\x79\x16\xb6\x92\x5b\xf7\xbc\xff\xbf\xdb\xa4\xc1\xef\x69\xad\xd6\x0a\x66\x1c\x44\x04\x0c\xf5\xf5\x50\x59\xaf\x42\x5c\x66\xc3\xf5\x0e\x38\xeb\x50\x8c\xa4\x3d\x48\xe2\x39\x89\x76\xbb\xd4\x55\x9e\x11\x79\xe4\xee\xc3\x9d\xf5\x15\x67\x5f\x0e\x3b\xa0\x96\xfd\x79\xa9\x9a\x22\x9e\x3f\xb0\x95\x44\x97\xc7\x40\x16\xf2\x69\x01\x80\xec\x8d\x37\x4d\x47\xa0\xe4\x08\x5f\xac\x7a\x37\x6f\x08\x29\xaf\x8f\x1b\x1a\x4b\x9b\xf1\x81\x61\xfb\x65\xe1\x30\x61\xb9\x2c\xa4\x4b\xe4\x42\x69\xd3\x49\x52\x54\xe9\x10\x71\xf0\x12\x1f\xc1\xd2\xa7\xfd\x24\x3f\x59\x6c\x0f\x6e\x2c\xf6\x74\x29\xd4\x02\xc9\x70\xf5\x07\x67\xef\x6a\xc4\x75\x71\xc1\x46\xf6\xf3\x8d\x2f\x6e\xd7\xa0\xa6\x70\x49\x54\x48\xb5\x18\xa3\x12\x4c\x88\x4d\x72\xbd\x48\xac\xfc\x6d\x80\x0e\x9e\x7c\x06\xb9\x5e\xdc\xc8\xdf\x48\x75\x39\xef\xa7\x2b\x67\x65\x16\xc3\x71\xaf\x9f\x86\xa8\xa1\x1d\xf9\xf8\x72\x02\x7f\x7a\x79\x0f\xef\xff\x5a\x5f\xe5\x2b\x34\xe4\x9d\x70\x89\xb6\xf4\x6f\x6c\x4d\x73\x41\xf1\xd3\x72\xef\x6b\x8d\x25\xbe\xc0\x42\x9b\xcd\x78\xfa\xfd\xfc\xf1\x2c\xfc\xe9\xcf\x7f\x99\xc0\x9f\x5f\xfe\xdb\x5f\x7e\x5f\x36\xe8\xae\xd4\x55\xe7\xfb\xde\x1d\x16\xc2\xdc\x91\xf4\xbf\x7c\x39\x81\x7f\x7f\x49\xff\xee\xa1\x90\x79\x2e\x2d\xa6\x5a\xb5\x62\xb9\x6f\xc7\x0b\x17\xa2\x93\xd2\xe8\x12\x8d\x93\x9d\x01\x5c\xb4\xd4\x2d\xbb\xea\xdb\x17\xbc\xeb\x10\x1a\x18\x7c\x55\xbb\x01\x16\x1b\x1d\x0e\xdb\xee\x68\xba\x33\xcd\x27\x82\x2c\xb8\x74\xb5\x68\xf4\x1c\x6e\x8d\x58\x49\x0b\xb3\x4a\xe6\x59\x7f\x15\x9c\x59\xf1\x66\x8b\xc5\x38\xca\x64\xd5\xc7\x73\xc7\x70\xa9\xbd\x8b\x27\x98\x75\xae\xed\x53\xa4\xe9\x7f\x8d\xcf\x93\x1f\x1f\xa7\x85\x54\xa1\xd2\x4b\x5f\x44\x3a\x50\x37\x62\x52\xa3\x9f\xe6\xad\x40\x97\x39\x8b\xb5\xb8\x30\x8b\x9c\xa5\xbd\xb2\xdc\x81\xd4\x7d\x67\xe5\xed\x59\xe5\x36\xa6\x36\x14\xf3\x39\x3d\xd4\x9b\xdf\x7c\x52\xa7\xdd\xb1\x81\x7b\x89\xcf\x26\x52\xc8\xf9\xd1\xa4\xd2\x6e\x19\xf2\x12\xc3\x24\xc5\x7c\xc3\x60\xa9\xfa\xf6\x49\x26\xb1\xed\xd8\x84\x97\x25\x98\x81\xd2\xe3\xfa\x2d\x18\x7b\xab\xd5\x89\x85\x32\x86\x88\x83\x8d\x40\xe1\x66\xdc\x8f\x78\xd6\xa1\x1e\xe8\xab\xea\x87\xf2\xa1\x23\x24\xd4\x7a\x1f\x96\xe8\x15\x1a\x23\xb3\x0c\xbb\xb2\x7a\x44\x61\xfb\xb9\x58\xd3\xaa\xd6\x2c\x8d\x3e\x4d\xbb\x13\x69\xec\x46\x25\xd2\x26\x65\x35\xcb\x65\xd7\x93\x7c\xbf\x2b\x3c\x37\x56\xb5\xfc\x8b\x38\x8a\xa3\x78\xe1\x93\x8c\xc9\x84\xcc\x05\xdb\x96\x19\xc2\x4a\xfa\xe4\x0d\x9d\xc3\x54\xb0\xa5\xf1\x6f\x10\x30\x83\xd9\x06\x84\xda\x68\xd5\xf3\xc2\x8c\x69\x8d\x49\x58\x9c\x85\x77\xbf\x03\xee\xc6\xd3\x1c\x2c\x97\x97\x38\x8a\x51\x19\xfd\x7f\x12\x9e\xe8\xee\xd7\x97\xe8\x20\xf0\xdf\x58\xc1\xd9\xc4\x3b\x21\xe1\x5b\x58\xd0\x13\x78\x79\x4a\x5b\x75\xc4\x26\x0a\x3b\xb2\xba\x44\x1a\xd6\x2e\xc9\x8d\x2a\x16\x86\xbf\x0d\x53\x2f\x9a\xc2\x6b\xad\x56\x64\xee\x43\xe8\xd2\xa0\x70\x7a\x07\xfc\xb0\xca\xee\x73\x35\x50\x17\xed\xcb\x44\x37\xbc\xc5\x81\x23\xb9\xab\xcb\x93\xfb\xfc\xb5\x11\xd5\x1c\x8e\x2a\x66\xd6\x3c\xc6\xac\x93\x41\x5b\x6a\x65\xb1\xaf\xbd\x6c\x8f\x68\xce\x37\xee\xe7\x15\xc2\x78\xcc\x20\xb4\x32\x12\x31\x37\x54\xe7\x34\x97\xce\x95\xfe\xef\x30\x79\xd4\x7c\xaf\x4d\xe1\x35\xdd\x30\xdc\x8f\xd2\xfe\xdd\x5f\xea\x7c\xe5\x84\x9f\x03\xd3\x0c\x85\xee\x93\x86\xb2\x21\x8d\x8d\xfb\x8a\x6a\x25\x8d\x56\x6c\x3b\x63\x4a\xa8\xab\xd2\x1f\xa2\xd2\x8b\x66\x09\xfc\x23\x2c\x19\x13\xe1\xbf\xb9\xf8\xeb\xdd\xdf\x46\x87\xf7\x3c\xfb\xb8\xd8\x3e\x9b\x2d\x12\x8b\xc2\xa4\x4b\xe2\x2c\x1a\xdc\xba\x80\xd9\xa9\xb6\x61\x45\x6d\x70\x77\x4b\x9e\x71\xfb\xa2\x7c\xbd\x63\x32\x10\x1b\x10\x29\xfb\xb7\xd2\xb7\xbe\x91\x9e\x79\x1b\x11\x69\xf5\x75\xed\x5b\x68\x7b\xfe\x2c\xce\x9b\x03\x7d\x5c\x41\x22\x67\xf0\x96\x29\x68\xfe\x0a\x0b\xa7\xf3\x09\xd8\xb1\x04\xf4\xbf\x23\x3e\x9e\x86\x76\x97\x6e\xec\x2a\x3f\xee\x6d\xe8\xde\x5b\xbb\xbe\x27\x8e\x34\xf9\xc9\x03\xbb\xe3\x5f\x71\x86\xb8\xa1\x6e\x0b\xfe\xe6\x44\x4c\xd8\xa5\x7f\xf1\xf8\x38\xcd\xaa\xa2\xd8\xf0\xac\xed\xf6\x05\x99\x9f\x76\xdc\xa3\x55\xbf\xfe\x84\x77\xcc\xc9\x6f\xb2\x4c\xf0\x0b\xb7\x96\xf8\x92\x7b\xcf\x7b\x9f\x0b\x9e\x47\x67\xec\x83\x70\xcb\xb3\xf6\x0e\x8e\x45\x25\xb2\x2c\x3e\x30\xea\xc3\x74\xce\xd3\x76\x0e\xae\xd3\xf0\x3f\xb2\x84\xb7\x43\x07\xa3\x8d\x2d\xf4\xcc\xc4\x16\xb2\x1e\x84\x6f\x43\x13\xe0\x8d\x77\xf2\x9f\xcd\xdf\x01\x8c\x49\x86\xd6\x49\xc5\xa8\xbe\x86\x04\xf6\x7e\xde\x34\xb0\x5a\x33\x5a\x18\x46\xd2\x1a\x2f\xcb\x48\x2f\xaa\xee\x1c\x6a\x4c\xa4\xc0\x65\x68\x41\xba\xa0\xc9\xa4\x70\xd2\xb5\x12\xf4\x4c\x49\x80\xc7\x25\xc3\x38\x9d\x61\xb3\x63\x80\x92\x83\x11\xbe\x33\x3f\x7a\x3e\xef\x81\x0c\xb2\xff\x3c\x69\xb3\xd7\x7f\xd4\x23\x1f\xb1\xf5\x9a\x85\xdf\x53\x69\x7a\x1d\x5b\xb4\x49\xc2\x51\x8f\x8e\xde\xe1\x5c\x5a\x97\xe8\x39\x23\xb2\x09\xb7\x67\xf2\x1d\x25\x9c\x43\xd3\x75\xb0\xbd\x69\xe3\xa6\xe7\xba\xc8\xe2\xff\x80\x95\x2f\x6e\x07\x28\x71\xdf\xb9\x9b\xe5\x83\xf7\x45\x18\x6c\xaf\x1c\x82\x73\xbd\xfb\xac\xbe\xeb\x50\xed\xbe\xbd\xa7\x9b\xb0\xb3\xed\x81\x83\x94\xb6\x37\x10\x9c\x38\x62\xe3\xfa\xe2\xbf\xef\x2e\xaf\x2f\x92\x5f\x7e\xbc\xbc\xf9\x29\x39\xbf\xbb\xfd\xb1\x55\x41\x88\xd4\x7e\x77\xff\xdd\xff\x06\x00\x00\xff\xff\x58\x2a\x2d\x4f\x3d\x54\x00\x00")
func wski18nResourcesEn_usAllJsonBytes() ([]byte, error) {
return bindataRead(
@@ -112,7 +112,7 @@
return nil, err
}
- info := bindataFileInfo{name: "wski18n/resources/en_US.all.json", size: 21194, mode: os.FileMode(420), modTime: time.Unix(1571334180, 0)}
+ info := bindataFileInfo{name: "wski18n/resources/en_US.all.json", size: 21565, mode: os.FileMode(420), modTime: time.Unix(1579715078, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
diff --git a/wski18n/resources/en_US.all.json b/wski18n/resources/en_US.all.json
index 3350db5..bc0aba4 100644
--- a/wski18n/resources/en_US.all.json
+++ b/wski18n/resources/en_US.all.json
@@ -392,6 +392,10 @@
"translation": "Failed to retrieve runtimes {{.err}}."
},
{
+ "id": "msg_err_web_action_require_auth_token_invalid",
+ "translation": "Unable to secure the web action; Action [{{.action}}] Annotation [{{.key}}] has invalid value [{{.value}}]."
+ },
+ {
"id": "WARNINGS",
"translation": "================= WARNINGS ==================="
},
@@ -546,5 +550,9 @@
{
"id": "msg_verbose_list_of_files_matching_pattern",
"translation": "Found the following files with matching Source File Path pattern.\n"
+ },
+ {
+ "id": "msg_action_authentication",
+ "translation": "Authentication for Action [{{.action}}] has been [{{.value}}] using the REQUIRE_WHISK_AUTH Annotation.\n"
}
]
diff --git a/wskprint/console.go b/wskprint/console.go
index 4719c39..91ee593 100644
--- a/wskprint/console.go
+++ b/wskprint/console.go
@@ -118,12 +118,6 @@
}
}
-func PrintOpenWhiskBanner(verbose bool) {
- if verbose {
- PrintlnOpenWhiskOutput(" ____ ___ _ _ _ _ _\n /\\ \\ / _ \\ _ __ ___ _ __ | | | | |__ (_)___| | __\n /\\ /__\\ \\ | | | | '_ \\ / _ \\ '_ \\| | | | '_ \\| / __| |/ /\n / \\____ \\ / | |_| | |_) | __/ | | | |/\\| | | | | \\__ \\ <\n \\ \\ / \\/ \\___/| .__/ \\___|_| |_|__/\\__|_| |_|_|___/_|\\_\\ \n \\___\\/ |_|\n")
- }
-}
-
// Display "trace" output if either param is true OR we are running Go test verbose (i.e., "go test -v")
// Typical Args for "go test" looks as follows:
// arg[0] = [/var/folders/nj/<uuid>/T/<build-id>/github.com/apache/openwhisk-wskdeploy/deployers/_test/deployers.test
@@ -149,3 +143,9 @@
}
return false
}
+
+//func PrintOpenWhiskBanner(verbose bool) {
+// if verbose {
+// PrintlnOpenWhiskOutput(" ____ ___ _ _ _ _ _\n /\\ \\ / _ \\ _ __ ___ _ __ | | | | |__ (_)___| | __\n /\\ /__\\ \\ | | | | '_ \\ / _ \\ '_ \\| | | | '_ \\| / __| |/ /\n / \\____ \\ / | |_| | |_) | __/ | | | |/\\| | | | | \\__ \\ <\n \\ \\ / \\/ \\___/| .__/ \\___|_| |_|__/\\__|_| |_|_|___/_|\\_\\ \n \\___\\/ |_|\n")
+// }
+//}