You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@openwhisk.apache.org by GitBox <gi...@apache.org> on 2017/12/15 14:24:58 UTC

[GitHub] mrutkows closed pull request #669: wskdeploy runtime overhaul

mrutkows closed pull request #669: wskdeploy runtime overhaul
URL: https://github.com/apache/incubator-openwhisk-wskdeploy/pull/669
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/cmd/root.go b/cmd/root.go
index fd0642d..eab75d2 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -146,9 +146,9 @@ func initConfig() {
 func setSupportedRuntimes(apiHost string) {
 	op, error := utils.ParseOpenWhisk(apiHost)
 	if error == nil {
-		utils.Rts = utils.ConvertToMap(op)
-	} else {
-		utils.Rts = utils.DefaultRts
+		utils.SupportedRunTimes = utils.ConvertToMap(op)
+		utils.DefaultRunTimes = utils.DefaultRuntimes(op)
+		utils.FileExtensionRuntimeKindMap = utils.FileExtensionRuntimes(op)
 	}
 }
 
diff --git a/parsers/manifest_parser.go b/parsers/manifest_parser.go
index 4a651c5..a7497b0 100644
--- a/parsers/manifest_parser.go
+++ b/parsers/manifest_parser.go
@@ -398,12 +398,13 @@ func (dm *YAMLParser) ComposeActionsFromAllPackages(manifest *YAML, filePath str
 
 func (dm *YAMLParser) ComposeActions(filePath string, actions map[string]Action, packageName string, ma whisk.KeyValue) ([]utils.ActionRecord, error) {
 
+	const RUNTIME_ERR_MESSAGE = "Please specify any of the supported runtime for zip actions in manifest YAML."
 	var errorParser error
+	var ext string
 	var s1 []utils.ActionRecord = make([]utils.ActionRecord, 0)
 
 	for key, action := range actions {
 		splitFilePath := strings.Split(filePath, string(os.PathSeparator))
-
 		// set the name of the action (which is the key)
 		action.Name = key
 
@@ -422,6 +423,7 @@ func (dm *YAMLParser) ComposeActions(filePath string, actions map[string]Action,
 
 		//bind action, and exposed URL
 		if action.Function != "" {
+
 			filePath := strings.TrimRight(filePath, splitFilePath[len(splitFilePath)-1]) + action.Function
 
 			if utils.IsDirectory(filePath) {
@@ -433,28 +435,27 @@ func (dm *YAMLParser) ComposeActions(filePath string, actions map[string]Action,
 				defer os.Remove(zipName)
 				// To do: support docker and main entry as did by go cli?
 				wskaction.Exec, err = utils.GetExec(zipName, action.Runtime, false, "")
+				if err != nil {
+					return nil, err
+				}
 			} else {
-				ext := path.Ext(filePath)
-				var kind string
+				ext = path.Ext(filePath)
+				// drop the "." from file extension
+				if len(ext) > 0 && ext[0] == '.' {
+					ext = ext[1:]
+				}
 
-				switch ext {
-				case ".swift":
-					kind = "swift:3.1.1"
-				case ".js":
-					kind = "nodejs:6"
-				case ".py":
-					kind = "python"
-				case ".java":
-					kind = "java"
-				case ".php":
-					kind = "php:7.1"
-				case ".jar":
-					kind = "java"
-				default:
-					kind = "nodejs:6"
-					errStr := wski18n.T("Unsupported runtime type, set to nodejs")
-					whisk.Debug(whisk.DbgWarn, errStr)
-				// TODO() add the user input kind here if interactive
+				// determine default runtime for the given file extension
+				var kind string
+				r := utils.FileExtensionRuntimeKindMap[ext]
+				kind = utils.DefaultRunTimes[r]
+
+				// produce an error when a runtime could not be derived from the action file extension
+				// and its not explicitly specified in the manifest YAML file
+				// and action source is not a zip file
+				if len(kind) == 0 && len(action.Runtime) == 0 && ext != utils.ZIP_FILE_EXTENSION {
+					errMessage := "ERROR: Failed to discover runtime from the action source files. " + RUNTIME_ERR_MESSAGE
+					return nil, wskderrors.NewInvalidRuntimeError(errMessage, splitFilePath[len(splitFilePath)-1], action.Name, "Not Specified in Manifest YAML", utils.ListOfSupportedRuntimes(utils.SupportedRunTimes))
 				}
 
 				wskaction.Exec.Kind = kind
@@ -465,11 +466,12 @@ func (dm *YAMLParser) ComposeActions(filePath string, actions map[string]Action,
 					return s1, err
 				}
 				code := string(dat)
-				if ext == ".zip" || ext == ".jar" {
+				if ext == utils.ZIP_FILE_EXTENSION || ext == utils.JAR_FILE_EXTENSION {
 					code = base64.StdEncoding.EncodeToString([]byte(dat))
 				}
-				if ext == ".zip" && action.Runtime == "" {
-					utils.PrintOpenWhiskOutputln("need explicit action Runtime value")
+				if ext == utils.ZIP_FILE_EXTENSION && len(action.Runtime) == 0 {
+					errMessage := "ERROR: Runtime is missing for zip action. " + RUNTIME_ERR_MESSAGE
+					return nil, wskderrors.NewInvalidRuntimeError(errMessage, splitFilePath[len(splitFilePath)-1], action.Name, "Not Specified in Manifest YAML", utils.ListOfSupportedRuntimes(utils.SupportedRunTimes))
 				}
 				wskaction.Exec.Code = &code
 			}
@@ -478,16 +480,56 @@ func (dm *YAMLParser) ComposeActions(filePath string, actions map[string]Action,
 
 		/*
  		 *  Action.Runtime
+		 *  Perform few checks if action runtime is specified in manifest YAML file
+		 *  (1) Check if specified runtime is one of the supported runtimes by OpenWhisk server
+		 *  (2) Check if specified runtime is consistent with action source file extensions
+		 *  Set the action runtime to match with the source file extension, if wskdeploy is not invoked in strict mode
  		 */
 		if action.Runtime != "" {
-			if utils.CheckExistRuntime(action.Runtime, utils.Rts) {
-				wskaction.Exec.Kind = action.Runtime
-
-			} else if utils.Flags.Strict {
-				wskaction.Exec.Kind = action.Runtime
+			if utils.CheckExistRuntime(action.Runtime, utils.SupportedRunTimes) {
+				// for zip actions, rely on the runtimes from the manifest file as it can not be derived from the action source file extension
+				// pick runtime from manifest file if its supported by OpenWhisk server
+				if ext == utils.ZIP_FILE_EXTENSION {
+					wskaction.Exec.Kind = action.Runtime
+				} else {
+					if utils.CheckRuntimeConsistencyWithFileExtension(ext, action.Runtime) {
+						wskaction.Exec.Kind = action.Runtime
+					} else {
+						errStr := wski18n.T("WARNING: Runtime specified in manifest " +
+							"YAML {{.runtime}} does not match with action source " +
+							"file extension {{.ext}} for action {{.action}}.\n",
+							map[string]interface{}{"runtime": action.Runtime, "ext": ext, "action": action.Name})
+						whisk.Debug(whisk.DbgWarn, errStr)
+						// even if runtime is not consistent with file extension, deploy action with specified runtime in strict mode
+						if utils.Flags.Strict {
+							wskaction.Exec.Kind = action.Runtime
+						} else {
+							errStr := wski18n.T("WARNING: Whisk Deploy has chosen appropriate " +
+								"runtime {{.runtime}} based on the action source file " +
+								"extension for that action {{.action}}.\n",
+								map[string]interface{}{"runtime": wskaction.Exec.Kind, "action": action.Name})
+							whisk.Debug(whisk.DbgWarn, errStr)
+						}
+					}
+				}
 			} else {
-				errStr := wski18n.T("wskdeploy has chosen a particular runtime for the action.\n")
+				errStr := wski18n.T("WARNING: Runtime specified in manifest " +
+					"YAML {{.runtime}} is not supported by OpenWhisk server " +
+					"for the action {{.action}}.\n",
+					map[string]interface{}{"runtime": action.Runtime, "action": action.Name})
 				whisk.Debug(whisk.DbgWarn, errStr)
+				if ext == utils.ZIP_FILE_EXTENSION {
+					// for zip action, error out if specified runtime is not supported by OpenWhisk server
+					errMessage := "ERROR: Given runtime for a zip action is not supported by OpenWhisk server. " + RUNTIME_ERR_MESSAGE
+					return nil, wskderrors.NewInvalidRuntimeError(errMessage, splitFilePath[len(splitFilePath)-1], action.Name, action.Runtime, utils.ListOfSupportedRuntimes(utils.SupportedRunTimes))
+				} else {
+					errStr = wski18n.T("WARNING: Whisk Deploy has chosen appropriate " +
+						"runtime {{.runtime}} based on the action source file " +
+						"extension for that action {{.action}}.\n",
+						map[string]interface{}{"runtime": wskaction.Exec.Kind, "action": action.Name})
+					whisk.Debug(whisk.DbgWarn, errStr)
+				}
+
 			}
 		}
 
diff --git a/parsers/manifest_parser_test.go b/parsers/manifest_parser_test.go
index 54d0a0d..9731630 100644
--- a/parsers/manifest_parser_test.go
+++ b/parsers/manifest_parser_test.go
@@ -31,6 +31,7 @@ import (
     "strings"
     "github.com/apache/incubator-openwhisk-client-go/whisk"
     "github.com/apache/incubator-openwhisk-wskdeploy/wskderrors"
+    "github.com/apache/incubator-openwhisk-wskdeploy/utils"
 )
 
 const (
@@ -46,6 +47,7 @@ const (
     TEST_MSG_ACTION_PARAMETER_VALUE_MISMATCH = "Action parameter [%s] had a value mismatch."
     TEST_MSG_PARAMETER_NUMBER_MISMATCH = "Number of Paramaters mismatched."
     TEST_MSG_MANIFEST_UNMARSHALL_ERROR_EXPECTED = "Manifest [%s]: Expected Unmarshal error."
+    TEST_MSG_ACTION_FUNCTION_RUNTIME_ERROR_EXPECTED = "Manifest [%s]: Expected runtime error."
 
     // local error messages
     TEST_ERROR_MANIFEST_PARSE_FAILURE = "Manifest [%s]: Failed to parse."
@@ -53,6 +55,14 @@ const (
     TEST_ERROR_MANIFEST_DATA_UNMARSHALL = "Manifest [%s]: Failed to Unmarshall manifest."
 )
 
+func init() {
+    op, error := utils.ParseOpenWhisk("")
+    if error == nil {
+        utils.SupportedRunTimes = utils.ConvertToMap(op)
+        utils.DefaultRunTimes = utils.DefaultRuntimes(op)
+        utils.FileExtensionRuntimeKindMap = utils.FileExtensionRuntimes(op)
+    }
+}
 
 func testReadAndUnmarshalManifest(t *testing.T, pathManifest string)(YAML, error){
     // Init YAML struct and attempt to Unmarshal YAML byte[] data
@@ -133,6 +143,22 @@ func testUnmarshalManifestAndActionBasic(t *testing.T,
     return m, nil
 }
 
+func testUnmarshalTemporaryFile (data []byte, filename string) (p *YAMLParser, m *YAML, t string) {
+    dir, _ := os.Getwd()
+    tmpfile, err := ioutil.TempFile(dir, filename)
+    if err == nil {
+        defer os.Remove(tmpfile.Name()) // clean up
+        if _, err := tmpfile.Write(data); err == nil {
+            // read and parse manifest.yaml file
+            p = NewYAMLParser()
+            m, _ = p.ParseManifest(tmpfile.Name())
+        }
+    }
+    t = tmpfile.Name()
+    tmpfile.Close()
+    return
+}
+
 // Test 1: validate manifest_parser:Unmarshal() method with a sample manifest in NodeJS
 // validate that manifest_parser is able to read and parse the manifest data
 func TestUnmarshalForHelloNodeJS(t *testing.T) {
@@ -478,66 +504,87 @@ func TestComposeActionsForImplicitRuntimes(t *testing.T) {
       function: ../tests/src/integration/helloworld/actions/hello.py
     helloSwift:
       function: ../tests/src/integration/helloworld/actions/hello.swift`
-
-    dir, _ := os.Getwd()
-    tmpfile, err := ioutil.TempFile(dir, "manifest_parser_validate_runtimes_")
+    p, m, tmpfile := testUnmarshalTemporaryFile([]byte(data), "manifest_parser_validate_runtime_")
+    actions, err := p.ComposeActionsFromAllPackages(m, tmpfile, whisk.KeyValue{})
+    var expectedResult string
     if err == nil {
-        defer os.Remove(tmpfile.Name()) // clean up
-        if _, err := tmpfile.Write([]byte(data)); err == nil {
-            // read and parse manifest.yaml file
-            p := NewYAMLParser()
-            m, _ := p.ParseManifest(tmpfile.Name())
-            actions, err := p.ComposeActionsFromAllPackages(m, tmpfile.Name(), whisk.KeyValue{})
-            var expectedResult string
-            if err == nil {
-                for i := 0; i < len(actions); i++ {
-                    if actions[i].Action.Name == "helloNodejs" {
-                        expectedResult = "nodejs:6"
-                    } else if actions[i].Action.Name == "helloJava" {
-                        expectedResult = "java"
-                    } else if actions[i].Action.Name == "helloPython" {
-                        expectedResult = "python"
-                    } else if actions[i].Action.Name == "helloSwift" {
-                        expectedResult = "swift:3.1.1"
-                    }
-                    actualResult := actions[i].Action.Exec.Kind
-                    assert.Equal(t, expectedResult, actualResult, TEST_MSG_ACTION_FUNCTION_RUNTIME_MISMATCH)
-                }
-            }
-
-        }
-        tmpfile.Close()
+	for i := 0; i < len(actions); i++ {
+	    if actions[i].Action.Name == "helloNodejs" {
+		expectedResult = utils.DefaultRunTimes[utils.FileExtensionRuntimeKindMap["js"]]
+	    } else if actions[i].Action.Name == "helloJava" {
+		expectedResult = utils.DefaultRunTimes[utils.FileExtensionRuntimeKindMap["jar"]]
+	    } else if actions[i].Action.Name == "helloPython" {
+		expectedResult = utils.DefaultRunTimes[utils.FileExtensionRuntimeKindMap["py"]]
+	    } else if actions[i].Action.Name == "helloSwift" {
+		expectedResult = utils.DefaultRunTimes[utils.FileExtensionRuntimeKindMap["swift"]]
+	    }
+	    actualResult := actions[i].Action.Exec.Kind
+	    assert.Equal(t, expectedResult, actualResult, TEST_MSG_ACTION_FUNCTION_RUNTIME_MISMATCH)
+	}
     }
+
 }
 
-// Test 10: validate manifest_parser.ComposeActions() method for invalid runtimes
-// when a runtime of an action is set to some garbage, manifest_parser should
+
+// Test 10(1): validate manifest_parser.ComposeActions() method for invalid runtimes
+// when the action has a source file written in unsupported runtimes, manifest_parser should
 // report an error for that action
-func TestComposeActionsForInvalidRuntime(t *testing.T) {
-    data :=
-        `package:
-   name: helloworld
-   actions:
-     helloInvalidRuntime:
-       function: ../tests/src/integration/helloworld/actions/hello.js
-       runtime: invalid`
-    dir, _ := os.Getwd()
-    tmpfile, err := ioutil.TempFile(dir, "manifest_parser_validate_runtime_")
-    if err == nil {
-        defer os.Remove(tmpfile.Name()) // clean up
-        if _, err := tmpfile.Write([]byte(data)); err == nil {
-            // read and parse manifest.yaml file
-            p := NewYAMLParser()
-            m, _ := p.ParseManifest(tmpfile.Name())
-            _, err := p.ComposeActionsFromAllPackages(m, tmpfile.Name(), whisk.KeyValue{})
-            // (TODO) uncomment the following test case after issue #307 is fixed
-            // (TODO) its failing right now as we are lacking check on invalid runtime
-            // TODO() https://github.com/apache/incubator-openwhisk-wskdeploy/issues/608
-            //assert.NotNil(t, err, "Invalid runtime, ComposeActions should report an error")
-            // (TODO) remove this print statement after uncommenting above test case
-            fmt.Println(fmt.Sprintf("!!! TODO(): Fix this testcase: error=[%v]", err))
+func TestComposeActionsForInvalidRuntime_1(t *testing.T) {
+    data := `packages:
+    helloworld:
+        actions:
+            helloInvalidRuntime:
+                function: ../tests/src/integration/common/wskdeploy.go`
+    p, m, tmpfile := testUnmarshalTemporaryFile([]byte(data), "manifest_parser_validate_runtime_")
+    _, err := p.ComposeActionsFromAllPackages(m, tmpfile, whisk.KeyValue{})
+    assert.NotNil(t, err, fmt.Sprintf(TEST_MSG_ACTION_FUNCTION_RUNTIME_ERROR_EXPECTED, tmpfile))
+}
+
+// Test 10(2): validate manifest_parser.ComposeActions() method for invalid runtimes
+// when a runtime of an action is missing for zip action, manifest_parser should
+// report an error for that action
+func TestComposeActionsForInvalidRuntime_2(t *testing.T) {
+    data := `packages:
+    helloworld:
+        actions:
+            helloInvalidRuntime:
+                function: ../tests/src/integration/runtimetests/src/helloworld/`
+    p, m, tmpfile := testUnmarshalTemporaryFile([]byte(data), "manifest_parser_validate_runtime_")
+    _, err := p.ComposeActionsFromAllPackages(m, tmpfile, whisk.KeyValue{})
+    assert.NotNil(t, err, fmt.Sprintf(TEST_MSG_ACTION_FUNCTION_RUNTIME_ERROR_EXPECTED, tmpfile))
+}
+
+// Test 10(3): validate manifest_parser.ComposeActions() method for invalid runtimes
+// when a runtime of an action is missing for zip action, manifest_parser should
+// report an error for that action
+func TestComposeActionsForInvalidRuntime_3(t *testing.T) {
+    data := `packages:
+    helloworld:
+        actions:
+            helloInvalidRuntime:
+                function: ../tests/src/integration/runtimetests/src/helloworld/helloworld.zip`
+    p, m, tmpfile := testUnmarshalTemporaryFile([]byte(data), "manifest_parser_validate_runtime_")
+    _, err := p.ComposeActionsFromAllPackages(m, tmpfile, whisk.KeyValue{})
+    assert.NotNil(t, err, fmt.Sprintf(TEST_MSG_ACTION_FUNCTION_RUNTIME_ERROR_EXPECTED, tmpfile))
+}
+
+// Test 10(3): validate manifest_parser.ComposeActions() method for valid runtimes with zip action
+// when a runtime of a zip action is set to one of the supported runtimes, manifest_parser should
+// return a valid actionRecord with specified runtime
+func TestComposeActionsForValidRuntime_ZipAction(t *testing.T) {
+    data := `packages:
+    helloworld:
+        actions:
+            hello:
+                function: ../tests/src/integration/runtimetests/src/helloworld/helloworld.zip
+                runtime: nodejs:6`
+    p, m, tmpfile := testUnmarshalTemporaryFile([]byte(data), "manifest_parser_validate_runtime_")
+    actions, _ := p.ComposeActionsFromAllPackages(m, tmpfile, whisk.KeyValue{})
+    for _, action := range actions {
+        if action.Action.Name == "hello" {
+            assert.Equal(t, action.Action.Exec.Kind, "nodejs:6", fmt.Sprintf(TEST_MSG_ACTION_FUNCTION_RUNTIME_MISMATCH, action))
         }
-        tmpfile.Close()
+
     }
 }
 
diff --git a/tests/src/integration/common/wskdeploy.go b/tests/src/integration/common/wskdeploy.go
index 7f9651b..7551c27 100644
--- a/tests/src/integration/common/wskdeploy.go
+++ b/tests/src/integration/common/wskdeploy.go
@@ -197,9 +197,9 @@ func (wskdeploy *Wskdeploy) GetDeploymentObjects(manifestPath string, deployment
 	//only for testing, mock values
 	op, err := utils.ParseOpenWhisk(clientConfig.Host)
 	if err == nil {
-		utils.Rts = utils.ConvertToMap(op)
-	} else {
-		utils.Rts = utils.DefaultRts
+		utils.SupportedRunTimes = utils.ConvertToMap(op)
+		utils.DefaultRunTimes = utils.DefaultRuntimes(op)
+		utils.FileExtensionRuntimeKindMap = utils.FileExtensionRuntimes(op)
 	}
 
 	//invoke ConstructDeploymentPlan to create the in memory objects for deployment
diff --git a/tests/src/integration/runtimetests/manifest.yaml b/tests/src/integration/runtimetests/manifest.yaml
index 922e7c4..3a8d12c 100644
--- a/tests/src/integration/runtimetests/manifest.yaml
+++ b/tests/src/integration/runtimetests/manifest.yaml
@@ -1,125 +1,218 @@
 packages:
-  TestExplicitRuntimes:
-      version: 1.0
-      license: Apache-2.0
-      actions:
-        greetingnodejs-with-explicit-runtime:
-          web-export: true
-          version: 1.0
-          function: src/greeting.js
-          runtime: nodejs:6
-          inputs:
-            name: string
-            place: string
-          outputs:
-            payload: string
-        greetingnodejs-without-explicit-runtime:
-          web-export: true
-          version: 1.0
-          function: src/greeting.js
-          inputs:
-            name: string
-            place: string
-          outputs:
-            payload: string
-        greetingphp-with-explicit-runtime:
-          web-export: true
-          version: 1.0
-          function: src/hello.php
-          runtime: php:7.1
-          inputs:
-            name: string
-            place: string
-          outputs:
-            payload: string
-        greetingphp-without-explicit-runtime:
-          web-export: true
-          version: 1.0
-          function: src/hello.php
-          inputs:
-            name: string
-            place: string
-          outputs:
-            payload: string
-        greetingpython-with-explicit-runtime:
-          web-export: true
-          version: 1.0
-          function: src/hello.py
-          runtime: python
-          inputs:
-            name: string
-            place: string
-          outputs:
-            payload: string
-        greetingpython-without-explicit-runtime:
-          web-export: true
-          version: 1.0
-          function: src/hello.py
-          inputs:
-            name: string
-            place: string
-          outputs:
-            payload: string
-        greetingpython2-with-explicit-runtime:
-          web-export: true
-          version: 1.0
-          function: src/hello.py
-          runtime: python:2
-          inputs:
-            name: string
-            place: string
-          outputs:
-            payload: string
-        greetingpython3-with-explicit-runtime:
-          web-export: true
-          version: 1.0
-          function: src/hello.py
-          runtime: python:3
-          inputs:
-            name: string
-            place: string
-          outputs:
-            payload: string
-        greetingswift311-with-explicit-runtime:
-          web-export: true
-          version: 1.0
-          function: src/hello.swift
-          runtime: swift:3.1.1
-          inputs:
-            name: string
-            place: string
-          outputs:
-            payload: string
-        greetingswift3-with-explicit-runtime:
-          web-export: true
-          version: 1.0
-          function: src/hello.swift
-          runtime: swift:3.1.1
-          inputs:
-            name: string
-            place: string
-          outputs:
-            payload: string
-        greetingswift-without-explicit-runtime:
-          web-export: true
-          version: 1.0
-          function: src/hello.swift
-          inputs:
-            name: string
-            place: string
-          outputs:
-            payload: string
-        helloworldjava-with-explicit-runtime:
-          function: src/hello.jar
-          runtime: java
-          main: Hello
-        helloworldjava-without-explicit-runtime:
-          function: src/hello.jar
-          main: Hello
-      triggers:
-        locationUpdateRuntime:
-      rules:
-        myRuleRuntime:
-          trigger: locationUpdateRuntime
-          action:  greetingnodejs-with-explicit-runtime
-
+    TestExplicitRuntimes:
+        version: 1.0
+        license: Apache-1.0
+        actions:
+            greetingnodejs6-with-explicit-runtime:
+                web-export: true
+                version: 1.0
+                function: src/greeting.js
+                runtime: nodejs:6
+                inputs:
+                    name: string
+                    place: string
+                outputs:
+                    payload: string
+            greetingnodejs8-with-explicit-runtime:
+                web-export: true
+                version: 1.0
+                function: src/greeting.js
+                runtime: nodejs:8
+                inputs:
+                    name: string
+                    place: string
+                outputs:
+                    payload: string
+            greetingphp-with-explicit-runtime:
+                web-export: true
+                version: 1.0
+                function: src/hello.php
+                runtime: php:7.1
+                inputs:
+                    name: string
+                    place: string
+                outputs:
+                    payload: string
+            greetingpython-with-explicit-runtime:
+                web-export: true
+                version: 1.0
+                function: src/hello.py
+                runtime: python
+                inputs:
+                    name: string
+                    place: string
+                outputs:
+                    payload: string
+            greetingpython2-with-explicit-runtime:
+                web-export: true
+                version: 1.0
+                function: src/hello.py
+                runtime: python:2
+                inputs:
+                    name: string
+                    place: string
+                outputs:
+                    payload: string
+            greetingpython3-with-explicit-runtime:
+                web-export: true
+                version: 1.0
+                function: src/hello.py
+                runtime: python:3
+                inputs:
+                    name: string
+                    place: string
+                outputs:
+                    payload: string
+            greetingswift311-with-explicit-runtime:
+                web-export: true
+                version: 1.0
+                function: src/hello.swift
+                runtime: swift:3.1.1
+                inputs:
+                    name: string
+                    place: string
+                outputs:
+                    payload: string
+            helloworldjava-with-explicit-runtime:
+                function: src/hello.jar
+                runtime: java
+                main: Hello
+            zipaction-with-explicit-runtime:
+                function: src/helloworld
+                runtime: nodejs:6
+                inputs:
+                    name: string
+                    place: string
+                outputs:
+                    payload: string
+    TestImplicitRuntimes:
+        actions:
+            greetingnodejs-without-explicit-runtime:
+                web-export: true
+                version: 1.0
+                function: src/greeting.js
+                inputs:
+                    name: string
+                    place: string
+                outputs:
+                    payload: string
+            greetingphp-without-explicit-runtime:
+                web-export: true
+                version: 1.0
+                function: src/hello.php
+                inputs:
+                    name: string
+                    place: string
+                outputs:
+                    payload: string
+            greetingpython-without-explicit-runtime:
+                web-export: true
+                version: 1.0
+                function: src/hello.py
+                inputs:
+                    name: string
+                    place: string
+                outputs:
+                    payload: string
+            greetingswift-without-explicit-runtime:
+                web-export: true
+                version: 1.0
+                function: src/hello.swift
+                inputs:
+                    name: string
+                    place: string
+                outputs:
+                    payload: string
+            helloworldjava-without-explicit-runtime:
+                function: src/hello.jar
+                main: Hello
+    TestInvalidExplicitRuntimes:
+        actions:
+            greetingnodejs-with-java-explicit-runtime:
+                web-export: true
+                version: 1.0
+                function: src/greeting.js
+                runtime: java
+                inputs:
+                    name: string
+                    place: string
+                outputs:
+                    payload: string
+            greetingnodejs-with-random-explicit-runtime:
+                web-export: true
+                version: 1.0
+                function: src/greeting.js
+                runtime: random
+                inputs:
+                    name: string
+                    place: string
+                outputs:
+                    payload: string
+            greetingphp-with-nodejs-explicit-runtime:
+                web-export: true
+                version: 1.0
+                function: src/hello.php
+                runtime: nodejs:6
+                inputs:
+                    name: string
+                    place: string
+                outputs:
+                    payload: string
+            greetingphp-with-random-explicit-runtime:
+                web-export: true
+                version: 1.0
+                function: src/hello.php
+                runtime: random
+                inputs:
+                    name: string
+                    place: string
+                outputs:
+                    payload: string
+            greetingpython-with-php-explicit-runtime:
+                web-export: true
+                version: 1.0
+                function: src/hello.py
+                runtime: php
+                inputs:
+                    name: string
+                    place: string
+                outputs:
+                    payload: string
+            greetingpython-with-random-explicit-runtime:
+                web-export: true
+                version: 1.0
+                function: src/hello.py
+                runtime: random
+                inputs:
+                    name: string
+                    place: string
+                outputs:
+                    payload: string
+            greetingswift-with-nodejs-explicit-runtime:
+                web-export: true
+                version: 1.0
+                function: src/hello.swift
+                runtime: nodejs:6
+                inputs:
+                    name: string
+                    place: string
+                outputs:
+                    payload: string
+            greetingswift-with-random-explicit-runtime:
+                web-export: true
+                version: 1.0
+                function: src/hello.swift
+                runtime: random
+                inputs:
+                    name: string
+                    place: string
+                outputs:
+                    payload: string
+            helloworldjava-with-swift-explicit-runtime:
+                function: src/hello.jar
+                main: Hello
+                runtime: swift:3.1.1
+            helloworldjava-with-random-explicit-runtime:
+                function: src/hello.jar
+                main: Hello
+                runtime: random
diff --git a/tests/src/integration/runtimetests/src/helloworld/helloworld.zip b/tests/src/integration/runtimetests/src/helloworld/helloworld.zip
new file mode 100644
index 0000000..190f0ef
Binary files /dev/null and b/tests/src/integration/runtimetests/src/helloworld/helloworld.zip differ
diff --git a/tests/src/integration/runtimetests/src/helloworld/index.js b/tests/src/integration/runtimetests/src/helloworld/index.js
new file mode 100644
index 0000000..7e2dffb
--- /dev/null
+++ b/tests/src/integration/runtimetests/src/helloworld/index.js
@@ -0,0 +1,8 @@
+function helloworld(params) {
+    var format = require('string-format');
+    var name = params.name || 'Stranger';
+    payload = format('Hello, {}!', name)
+    return { message: payload };
+}
+
+exports.main = helloworld;
diff --git a/tests/src/integration/runtimetests/src/helloworld/node_modules/string-format/README.md b/tests/src/integration/runtimetests/src/helloworld/node_modules/string-format/README.md
new file mode 100644
index 0000000..8f5aeb5
--- /dev/null
+++ b/tests/src/integration/runtimetests/src/helloworld/node_modules/string-format/README.md
@@ -0,0 +1,192 @@
+# String::format
+
+String::format is a small JavaScript library for formatting strings, based on
+Python's [`str.format()`][1]. For example:
+
+```javascript
+'"{firstName} {lastName}" <{email}>'.format(user)
+// => '"Jane Smith" <js...@example.com>'
+```
+
+The equivalent concatenation:
+
+```javascript
+'"' + user.firstName + ' ' + user.lastName + '" <' + user.email + '>'
+// => '"Jane Smith" <js...@example.com>'
+```
+
+### Installation
+
+#### Node
+
+1.  Install:
+
+        $ npm install string-format
+
+2.  Require:
+
+        var format = require('string-format')
+
+#### Browser
+
+1.  Define `window.format`:
+
+        <script src="path/to/string-format.js"></script>
+
+### Modes
+
+String::format can be used in two modes: [function mode](#function-mode) and
+[method mode](#method-mode).
+
+#### Function mode
+
+```javascript
+format('Hello, {}!', 'Alice')
+// => 'Hello, Alice!'
+```
+
+In this mode the first argument is a template string and the remaining
+arguments are values to be interpolated.
+
+#### Method mode
+
+```javascript
+'Hello, {}!'.format('Alice')
+// => 'Hello, Alice!'
+```
+
+In this mode values to be interpolated are supplied to the `format` method
+of a template string. This mode is not enabled by default. The method must
+first be defined via [`format.extend`](#formatextendprototype-transformers):
+
+```javascript
+format.extend(String.prototype)
+```
+
+`format(template, $0, $1, ?, $N)` and `template.format($0, $1, ?, $N)` can then
+be used interchangeably.
+
+### `format(template, $0, $1, ?, $N)`
+
+Returns the result of replacing each `{?}` placeholder in the template string
+with its corresponding replacement.
+
+Placeholders may contain numbers which refer to positional arguments:
+
+```javascript
+'{0}, you have {1} unread message{2}'.format('Holly', 2, 's')
+// => 'Holly, you have 2 unread messages'
+```
+
+Unmatched placeholders produce no output:
+
+```javascript
+'{0}, you have {1} unread message{2}'.format('Steve', 1)
+// => 'Steve, you have 1 unread message'
+```
+
+A format string may reference a positional argument multiple times:
+
+```javascript
+"The name's {1}. {0} {1}.".format('James', 'Bond')
+// => "The name's Bond. James Bond."
+```
+
+Positional arguments may be referenced implicitly:
+
+```javascript
+'{}, you have {} unread message{}'.format('Steve', 1)
+// => 'Steve, you have 1 unread message'
+```
+
+A format string must not contain both implicit and explicit references:
+
+```javascript
+'My name is {} {}. Do you like the name {0}?'.format('Lemony', 'Snicket')
+// => ValueError: cannot switch from implicit to explicit numbering
+```
+
+`{{` and `}}` in format strings produce `{` and `}`:
+
+```javascript
+'{{}} creates an empty {} in {}'.format('dictionary', 'Python')
+// => '{} creates an empty dictionary in Python'
+```
+
+Dot notation may be used to reference object properties:
+
+```javascript
+var bobby = {firstName: 'Bobby', lastName: 'Fischer'}
+var garry = {firstName: 'Garry', lastName: 'Kasparov'}
+
+'{0.firstName} {0.lastName} vs. {1.firstName} {1.lastName}'.format(bobby, garry)
+// => 'Bobby Fischer vs. Garry Kasparov'
+```
+
+`0.` may be omitted when referencing a property of `{0}`:
+
+```javascript
+var repo = {owner: 'davidchambers', slug: 'string-format'}
+
+'https://github.com/{owner}/{slug}'.format(repo)
+// => 'https://github.com/davidchambers/string-format'
+```
+
+If the referenced property is a method, it is invoked with no arguments to
+determine the replacement:
+
+```javascript
+var sheldon = {
+  firstName:  'Sheldon',
+  lastName:   'Cooper',
+  dob:        new Date('1970-01-01'),
+  fullName:   function() { return '{firstName} {lastName}'.format(this) },
+  quip:       function() { return 'Bazinga!' }
+}
+
+'{fullName} was born at precisely {dob.toISOString}'.format(sheldon)
+// => 'Sheldon Cooper was born at precisely 1970-01-01T00:00:00.000Z'
+
+"I've always wanted to go to a goth club. {quip.toUpperCase}".format(sheldon)
+// => "I've always wanted to go to a goth club. BAZINGA!"
+```
+
+### `format.extend(prototype[, transformers])`
+
+This function defines a `format` method on the provided prototype (presumably
+`String.prototype`). One may provide an object mapping names to transformers.
+A transformer is applied if its name appears, prefixed with `!`, after a field
+name in a template string.
+
+```javascript
+format.extend(String.prototype, {
+  escape: function(s) {
+    return s.replace(/[&<>"'`]/g, function(c) {
+      return '&#' + c.charCodeAt(0) + ';'
+    })
+  },
+  upper: function(s) { return s.toUpperCase() }
+})
+
+'Hello, {!upper}!'.format('Alice')
+// => 'Hello, ALICE!'
+
+var restaurant = {
+  name: 'Anchor & Hope',
+  url: 'http://anchorandhopesf.com/'
+}
+
+'<a href="{url!escape}">{name!escape}</a>'.format(restaurant)
+// => '<a href="http://anchorandhopesf.com/">Anchor &#38; Hope</a>'
+```
+
+### Running the test suite
+
+```console
+$ npm install
+$ npm test
+```
+
+
+[1]: http://docs.python.org/library/stdtypes.html#str.format
+[2]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
diff --git a/tests/src/integration/runtimetests/src/helloworld/node_modules/string-format/lib/string-format.js b/tests/src/integration/runtimetests/src/helloworld/node_modules/string-format/lib/string-format.js
new file mode 100644
index 0000000..e15b77b
--- /dev/null
+++ b/tests/src/integration/runtimetests/src/helloworld/node_modules/string-format/lib/string-format.js
@@ -0,0 +1,104 @@
+// Generated by CoffeeScript 1.8.0
+(function() {
+  var ValueError, create, explicitToImplicit, format, implicitToExplicit, lookup, resolve,
+    __hasProp = {}.hasOwnProperty,
+    __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
+    __slice = [].slice;
+
+  ValueError = (function(_super) {
+    __extends(ValueError, _super);
+
+    function ValueError(message) {
+      this.message = message;
+    }
+
+    ValueError.prototype.name = 'ValueError';
+
+    return ValueError;
+
+  })(Error);
+
+  implicitToExplicit = 'cannot switch from implicit to explicit numbering';
+
+  explicitToImplicit = 'cannot switch from explicit to implicit numbering';
+
+  create = function(transformers) {
+    if (transformers == null) {
+      transformers = {};
+    }
+    return function() {
+      var args, explicit, idx, implicit, message, template;
+      template = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
+      idx = 0;
+      explicit = implicit = false;
+      message = 'cannot switch from {} to {} numbering';
+      return template.replace(/([{}])\1|[{](.*?)(?:!(.+?))?[}]/g, function(match, literal, key, transformer) {
+        var value, _ref, _ref1;
+        if (literal) {
+          return literal;
+        }
+        if (key.length) {
+          if (implicit) {
+            throw new ValueError(implicitToExplicit);
+          }
+          explicit = true;
+          value = (_ref = lookup(args, key)) != null ? _ref : '';
+        } else {
+          if (explicit) {
+            throw new ValueError(explicitToImplicit);
+          }
+          implicit = true;
+          value = (_ref1 = args[idx++]) != null ? _ref1 : '';
+        }
+        if (Object.prototype.hasOwnProperty.call(transformers, transformer)) {
+          return transformers[transformer](value);
+        } else {
+          return value;
+        }
+      });
+    };
+  };
+
+  lookup = function(object, key) {
+    var match;
+    if (!/^(\d+)([.]|$)/.test(key)) {
+      key = '0.' + key;
+    }
+    while (match = /(.+?)[.](.+)/.exec(key)) {
+      object = resolve(object, match[1]);
+      key = match[2];
+    }
+    return resolve(object, key);
+  };
+
+  resolve = function(object, key) {
+    var value;
+    value = object[key];
+    if (typeof value === 'function') {
+      return value.call(object);
+    } else {
+      return value;
+    }
+  };
+
+  format = create({});
+
+  format.create = create;
+
+  format.extend = function(prototype, transformers) {
+    var $format;
+    $format = create(transformers);
+    prototype.format = function() {
+      return $format.apply(null, [this].concat(__slice.call(arguments)));
+    };
+  };
+
+  if (typeof module !== 'undefined') {
+    module.exports = format;
+  } else if (typeof define === 'function' && define.amd) {
+    define(format);
+  } else {
+    window.format = format;
+  }
+
+}).call(this);
diff --git a/tests/src/integration/runtimetests/src/helloworld/node_modules/string-format/package.json b/tests/src/integration/runtimetests/src/helloworld/node_modules/string-format/package.json
new file mode 100644
index 0000000..d6524b6
--- /dev/null
+++ b/tests/src/integration/runtimetests/src/helloworld/node_modules/string-format/package.json
@@ -0,0 +1,101 @@
+{
+  "_args": [
+    [
+      {
+        "raw": "string-format@0.5.0",
+        "scope": null,
+        "escapedName": "string-format",
+        "name": "string-format",
+        "rawSpec": "0.5.0",
+        "spec": "0.5.0",
+        "type": "version"
+      },
+      ""
+    ]
+  ],
+  "_from": "string-format@0.5.0",
+  "_id": "string-format@0.5.0",
+  "_inCache": true,
+  "_location": "/string-format",
+  "_npmUser": {
+    "name": "davidchambers",
+    "email": "dc@davidchambers.me"
+  },
+  "_npmVersion": "1.4.28",
+  "_phantomChildren": {},
+  "_requested": {
+    "raw": "string-format@0.5.0",
+    "scope": null,
+    "escapedName": "string-format",
+    "name": "string-format",
+    "rawSpec": "0.5.0",
+    "spec": "0.5.0",
+    "type": "version"
+  },
+  "_requiredBy": [
+    "/"
+  ],
+  "_resolved": "https://registry.npmjs.org/string-format/-/string-format-0.5.0.tgz",
+  "_shasum": "bfc4a69a250f17f273d97336797daf5dca6ecf30",
+  "_shrinkwrap": null,
+  "_spec": "string-format@0.5.0",
+  "_where": "",
+  "author": {
+    "name": "David Chambers",
+    "email": "dc@davidchambers.me"
+  },
+  "bugs": {
+    "url": "https://github.com/davidchambers/string-format/issues"
+  },
+  "dependencies": {},
+  "description": "Adds a `format` method to `String.prototype`. Inspired by Python's `str.format()`.",
+  "devDependencies": {
+    "coffee-script": "1.8.x",
+    "mocha": "2.x.x",
+    "ramda": "0.8.x",
+    "xyz": "0.5.x"
+  },
+  "directories": {},
+  "dist": {
+    "shasum": "bfc4a69a250f17f273d97336797daf5dca6ecf30",
+    "tarball": "https://registry.npmjs.org/string-format/-/string-format-0.5.0.tgz"
+  },
+  "files": [
+    "README.md",
+    "lib/string-format.js",
+    "package.json"
+  ],
+  "gitHead": "e98595d385a460edb8fe9bd384fe1af3da307a31",
+  "homepage": "https://github.com/davidchambers/string-format",
+  "keywords": [
+    "string",
+    "formatting",
+    "language",
+    "util"
+  ],
+  "licenses": [
+    {
+      "type": "WTFPL",
+      "url": "https://raw.github.com/davidchambers/string-format/master/LICENSE"
+    }
+  ],
+  "main": "./lib/string-format",
+  "maintainers": [
+    {
+      "name": "davidchambers",
+      "email": "dc@hashify.me"
+    }
+  ],
+  "name": "string-format",
+  "optionalDependencies": {},
+  "readme": "ERROR: No README data found!",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/davidchambers/string-format.git"
+  },
+  "scripts": {
+    "prepublish": "make clean && make",
+    "test": "make test"
+  },
+  "version": "0.5.0"
+}
diff --git a/tests/src/integration/runtimetests/src/helloworld/package.json b/tests/src/integration/runtimetests/src/helloworld/package.json
new file mode 100644
index 0000000..94de3f9
--- /dev/null
+++ b/tests/src/integration/runtimetests/src/helloworld/package.json
@@ -0,0 +1,14 @@
+{
+	"name": "hello-world-sample",
+	"description": "",
+	"license": "Apache-2.0",
+	"repository": {
+		"type": "git",
+		"url": "https://github.com/apache/incubator-openwhisk-wskdeploy"
+	},
+	"version": "1.0.0",
+	"main": "index.js",
+	"dependencies": {
+		"string-format": "0.5.0"
+	}
+}
diff --git a/utils/misc.go b/utils/misc.go
index 246656e..5026c1d 100644
--- a/utils/misc.go
+++ b/utils/misc.go
@@ -21,7 +21,6 @@ import (
 	"archive/zip"
 	"bufio"
 	"encoding/base64"
-	"encoding/json"
 	"errors"
 	"fmt"
 	"io"
@@ -31,25 +30,24 @@ import (
 	"reflect"
 	"strings"
 
-	"crypto/tls"
 	"github.com/apache/incubator-openwhisk-client-go/whisk"
 	"github.com/apache/incubator-openwhisk-wskdeploy/wski18n"
 	"github.com/hokaccha/go-prettyjson"
 	"io/ioutil"
 	"net/http"
 	"path"
-    "time"
 )
 
 const (
-    DEFAULT_HTTP_TIMEOUT = 30
-    DEFAULT_PROJECT_PATH = "."
-    // name of manifest and deployment files
-    ManifestFileNameYaml = "manifest.yaml"
-    ManifestFileNameYml = "manifest.yml"
-    DeploymentFileNameYaml = "deployment.yaml"
-    DeploymentFileNameYml = "deployment.yml"
+	DEFAULT_HTTP_TIMEOUT = 30
+	DEFAULT_PROJECT_PATH = "."
+	// name of manifest and deployment files
+	ManifestFileNameYaml   = "manifest.yaml"
+	ManifestFileNameYml    = "manifest.yml"
+	DeploymentFileNameYaml = "deployment.yaml"
+	DeploymentFileNameYml  = "deployment.yml"
 )
+
 // ActionRecord is a container to keep track of
 // a whisk action struct and a location filepath we use to
 // map files and manifest declared actions
@@ -72,8 +70,8 @@ type RuleRecord struct {
 func GetHomeDirectory() string {
 	usr, err := user.Current()
 	if err != nil {
-        return ""
-    }
+		return ""
+	}
 
 	return usr.HomeDir
 }
@@ -100,8 +98,8 @@ func PrettyJSON(j interface{}) (string, error) {
 	formatter := prettyjson.NewFormatter()
 	bytes, err := formatter.Marshal(j)
 	if err != nil {
-        	return "", err
-    	}
+		return "", err
+	}
 	return string(bytes), nil
 }
 
@@ -127,10 +125,10 @@ func isValidEnvironmentVar(value string) bool {
 	// and have at least 1 additional character after it, e.g. $ENV_VAR
 	// If the value is a concatenation of a string and a Env. variable, it should contain '$' (dollar)
 	// and have a string following which is surrounded with '{' and '}', e.g. xxx${ENV_VAR}xxx.
-	if value != "" && strings.HasPrefix(value, "$") && len(value) > 1  {
+	if value != "" && strings.HasPrefix(value, "$") && len(value) > 1 {
 		return true
 	}
-	if value != "" && strings.Contains(value,"${") && strings.Count(value,"{")==strings.Count(value,"}") {
+	if value != "" && strings.Contains(value, "${") && strings.Count(value, "{") == strings.Count(value, "}") {
 		return true
 	}
 	return false
@@ -153,23 +151,23 @@ func GetEnvVar(key interface{}) interface{} {
 			//test if the substr is a environment var
 			//if it is, replace it with the value
 			f := func(c rune) bool {
-				return c=='$' || c=='{' || c=='}'
+				return c == '$' || c == '{' || c == '}'
 			}
-			for _,substr := range strings.FieldsFunc(keystr, f) {
+			for _, substr := range strings.FieldsFunc(keystr, f) {
 				//if the substr is a $ENV_VAR
-				if strings.Contains(keystr,"$"+substr) {
+				if strings.Contains(keystr, "$"+substr) {
 					thisValue = os.Getenv(substr)
 					if thisValue == "" {
-                        PrintOpenWhiskOutputln("WARNING: Missing Environment Variable " + substr + ".")
+						PrintOpenWhiskOutputln("WARNING: Missing Environment Variable " + substr + ".")
 					}
-					keystr = strings.Replace(keystr,"$"+substr,thisValue,-1)
-				//if the substr is a ${ENV_VAR}
-				} else if strings.Contains(keystr,"${"+substr+"}") {
+					keystr = strings.Replace(keystr, "$"+substr, thisValue, -1)
+					//if the substr is a ${ENV_VAR}
+				} else if strings.Contains(keystr, "${"+substr+"}") {
 					thisValue = os.Getenv(substr)
 					if thisValue == "" {
-                        PrintOpenWhiskOutputln("WARNING: Missing Environment Variable " + substr + ".")
+						PrintOpenWhiskOutputln("WARNING: Missing Environment Variable " + substr + ".")
 					}
-					keystr = strings.Replace(keystr,"${"+substr+"}",thisValue,-1)
+					keystr = strings.Replace(keystr, "${"+substr+"}", thisValue, -1)
 				}
 			}
 			return keystr
@@ -254,13 +252,18 @@ func GetExec(artifact string, kind string, isDocker bool, mainEntry string) (*wh
 	var exec *whisk.Exec
 
 	ext := filepath.Ext(artifact)
+	// drop the "." from file extension
+	if len(ext) > 0 && ext[0] == '.' {
+		ext = ext[1:]
+	}
+
 	exec = new(whisk.Exec)
 
-	if !isDocker || ext == ".zip" {
+	if !isDocker || ext == ZIP_FILE_EXTENSION {
 		content, err = new(ContentReader).ReadLocal(artifact)
 		if err != nil {
-            return nil, err
-        }
+			return nil, err
+		}
 		code = string(content)
 		exec.Code = &code
 	}
@@ -269,22 +272,22 @@ func GetExec(artifact string, kind string, isDocker bool, mainEntry string) (*wh
 		exec.Kind = kind
 	} else if isDocker {
 		exec.Kind = "blackbox"
-		if ext != ".zip" {
+		if ext != ZIP_FILE_EXTENSION {
 			exec.Image = artifact
 		} else {
 			exec.Image = "openwhisk/dockerskeleton"
 		}
-	} else if ext == ".swift" {
-		exec.Kind = "swift:default"
-	} else if ext == ".js" {
-		exec.Kind = "nodejs:default"
-	} else if ext == ".py" {
-		exec.Kind = "python:default"
-	} else if ext == ".jar" {
-		exec.Kind = "java:default"
-		exec.Code = nil
 	} else {
-		if ext == ".zip" {
+		r := FileExtensionRuntimeKindMap[ext]
+		exec.Kind = DefaultRunTimes[r]
+	}
+
+	if ext == JAR_FILE_EXTENSION {
+		exec.Code = nil
+	}
+
+	if len(exec.Kind) == 0 {
+		if ext == ZIP_FILE_EXTENSION {
 			return nil, zipKindError()
 		} else {
 			return nil, extensionError(ext)
@@ -301,7 +304,7 @@ func GetExec(artifact string, kind string, isDocker bool, mainEntry string) (*wh
 	}
 
 	// Base64 encode the zip file content
-	if ext == ".zip" {
+	if ext == ZIP_FILE_EXTENSION {
 		code = base64.StdEncoding.EncodeToString([]byte(code))
 		exec.Code = &code
 	}
@@ -351,216 +354,6 @@ func addKeyValue(key string, value interface{}, keyValueArr whisk.KeyValueArr) w
 	return append(keyValueArr, keyValue)
 }
 
-// Structs used to denote the OpenWhisk Runtime information
-type Limit struct {
-	Apm       uint16 `json:"actions_per_minute"`
-	Tpm       uint16 `json:"triggers_per_minute"`
-	ConAction uint16 `json:"concurrent_actions"`
-}
-
-type Runtime struct {
-	Image      string `json:"image"`
-	Deprecated bool   `json:"deprecated"`
-	ReMain     bool   `json:"requireMain"`
-	Default    bool   `json:"default"`
-	Attach     bool   `json:"attached"`
-	Kind       string `json:"kind"`
-}
-
-type SupportInfo struct {
-	Github string `json:"github"`
-	Slack  string `json:"slack"`
-}
-
-type OpenWhiskInfo struct {
-	Support  SupportInfo          `json:"support"`
-	Desc     string               `json:"description"`
-	ApiPath  []string             `json:"api_paths"`
-	Runtimes map[string][]Runtime `json:"runtimes"`
-	Limits   Limit                `json:"limits"`
-}
-
-// We could get the openwhisk info from bluemix through running the command
-// `curl -k https://openwhisk.ng.bluemix.net`
-// hard coding it here in case of network unavailable or failure.
-func ParseOpenWhisk(apiHost string) (op OpenWhiskInfo, err error) {
-	ct := "application/json; charset=UTF-8"
-	req, _ := http.NewRequest("GET", "https://"+apiHost, nil)
-	req.Header.Set("Content-Type", ct)
-	tlsConfig := &tls.Config{
-		InsecureSkipVerify: true,
-	}
-
-    var netTransport = &http.Transport{
-        TLSClientConfig: tlsConfig,
-    }
-
-    var netClient = &http.Client{
-        Timeout: time.Second * DEFAULT_HTTP_TIMEOUT,
-        Transport: netTransport,
-    }
-
-	res, err := netClient.Do(req)
-    if err != nil {
-        errString := wski18n.T("Failed to get the supported runtimes from OpenWhisk service: {{.err}}.\n",
-            map[string]interface{}{"err": err.Error()})
-        whisk.Debug(whisk.DbgWarn, errString)
-    }
-
-    if res != nil {
-        defer res.Body.Close()
-    }
-
-	// Local openwhisk deployment sometimes only returns "application/json" as the content type
-	if err != nil || !strings.Contains(ct, res.Header.Get("Content-Type")) {
-        stdout := wski18n.T("Start to unmarshal Openwhisk info from local values.\n")
-        whisk.Debug(whisk.DbgInfo, stdout)
-		err = json.Unmarshal(runtimeInfo, &op)
-	} else {
-		b, _ := ioutil.ReadAll(res.Body)
-		if b != nil && len(b) > 0 {
-            stdout := wski18n.T("Unmarshal Openwhisk info from internet.\n")
-            whisk.Debug(whisk.DbgInfo, stdout)
-			err = json.Unmarshal(b, &op)
-		}
-	}
-	return
-}
-
-func ConvertToMap(op OpenWhiskInfo) (rt map[string][]string) {
-	rt = make(map[string][]string)
-	for k, v := range op.Runtimes {
-		rt[k] = make([]string, 0, len(v))
-		for i := range v {
-			if (!v[i].Deprecated) {
-				rt[k] = append(rt[k], v[i].Kind)
-			}
-		}
-	}
-	return
-}
-
-var runtimeInfo = []byte(`{
-	"support":{
-		"github":"https://github.com/apache/incubator-openwhisk/issues",
-		"slack":"http://slack.openwhisk.org"
-	},
-	"description":"OpenWhisk",
-	"api_paths":["/api/v1"],
-	"runtimes":{
-		"nodejs":[{
-			"image":"openwhisk/nodejsaction:latest",
-			"deprecated":true,
-			"requireMain":false,
-			"default":false,
-			"attached":false,
-			"kind":"nodejs"
-		},{
-			"image":"openwhisk/nodejs6action:latest",
-			"deprecated":false,
-			"requireMain":false,
-			"default":true,
-			"attached":false,
-			"kind":"nodejs:6"
-		},{
-			"image":"openwhisk/action-nodejs-v8:latest",
-			"deprecated":false,
-			"requireMain":false,
-			"default":false,
-			"attached":false,
-			"kind":"nodejs:8"
-		}],
-		"java":[{
-			"image":"openwhisk/java8action:latest",
-			"deprecated":false,
-			"requireMain":true,
-			"default":true,
-			"attached":true,
-			"kind":"java"
-		}],
-		"php":[{
-			"image":"openwhisk/action-php-v7.1:latest",
-			"deprecated":false,
-			"requireMain":false,
-			"default":true,
-			"attached":false,
-			"kind":"php:7.1"
-		}],
-		"python":[{
-			"image":"openwhisk/python2action:latest",
-			"deprecated":false,
-			"requireMain":false,
-			"default":false,
-			"attached":false,
-			"kind":"python"
-		},{
-			"image":"openwhisk/python2action:latest",
-			"deprecated":false,
-			"requireMain":false,
-			"default":true,
-			"attached":false,
-			"kind":"python:2"
-		},{
-			"image":"openwhisk/python3action:latest",
-			"deprecated":false,
-			"requireMain":false,
-			"default":false,
-			"attached":false,
-			"kind":"python:3"
-		}],
-		"swift":[{
-			"image":"openwhisk/swiftaction:latest",
-			"deprecated":true,
-			"requireMain":false,
-			"default":false,
-			"attached":false,
-			"kind":"swift"
-		},{
-			"image":"openwhisk/swift3action:latest",
-			"deprecated":true,
-			"requireMain":false,
-			"default":false,
-			"attached":false,
-			"kind":"swift:3"
-		},{
-			"image":"openwhisk/action-swift-v3.1.1:latest",
-			"deprecated":false,
-			"requireMain":false,
-			"default":true,
-			"attached":false,
-			"kind":"swift:3.1.1"
-		}]
-	},
-	"limits":{
-		"actions_per_minute":5000,
-		"triggers_per_minute":5000,
-		"concurrent_actions":1000
-	}
-	}
-`)
-
-
-var Rts map[string][]string
-
-var DefaultRts = map[string][]string{
-	"nodejs": {"nodejs:6"},
-	"java":   {"java"},
-	"php":    {"php:7.1"},
-	"python": {"python:2"},
-	"swift":  {"swift:3.1.1"},
-}
-
-func CheckExistRuntime(rtname string, rts map[string][]string) bool {
-	for _, v := range rts {
-		for i := range v {
-			if rtname == v[i] {
-				return true
-			}
-		}
-	}
-	return false
-}
-
 func GetManifestFilePath(projectPath string) string {
 	if _, err := os.Stat(path.Join(projectPath, ManifestFileNameYaml)); err == nil {
 		return path.Join(projectPath, ManifestFileNameYaml)
diff --git a/utils/runtimes.go b/utils/runtimes.go
new file mode 100644
index 0000000..e39d027
--- /dev/null
+++ b/utils/runtimes.go
@@ -0,0 +1,293 @@
+/*
+ * 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 (
+	"crypto/tls"
+	"encoding/json"
+	"github.com/apache/incubator-openwhisk-client-go/whisk"
+	"github.com/apache/incubator-openwhisk-wskdeploy/wski18n"
+	"io/ioutil"
+	"net/http"
+	"strings"
+	"time"
+)
+
+const NODEJS_FILE_EXTENSION = "js"
+const SWIFT_FILE_EXTENSION = "swift"
+const PYTHON_FILE_EXTENSION = "py"
+const JAVA_FILE_EXTENSION = "java"
+const JAR_FILE_EXTENSION = "jar"
+const PHP_FILE_EXTENSION = "php"
+const ZIP_FILE_EXTENSION = "zip"
+
+// Structs used to denote the OpenWhisk Runtime information
+type Limit struct {
+	Apm       uint16 `json:"actions_per_minute"`
+	Tpm       uint16 `json:"triggers_per_minute"`
+	ConAction uint16 `json:"concurrent_actions"`
+}
+
+type Runtime struct {
+	Image      string `json:"image"`
+	Deprecated bool   `json:"deprecated"`
+	ReMain     bool   `json:"requireMain"`
+	Default    bool   `json:"default"`
+	Attach     bool   `json:"attached"`
+	Kind       string `json:"kind"`
+}
+
+type SupportInfo struct {
+	Github string `json:"github"`
+	Slack  string `json:"slack"`
+}
+
+type OpenWhiskInfo struct {
+	Support  SupportInfo          `json:"support"`
+	Desc     string               `json:"description"`
+	ApiPath  []string             `json:"api_paths"`
+	Runtimes map[string][]Runtime `json:"runtimes"`
+	Limits   Limit                `json:"limits"`
+}
+
+var FileExtensionRuntimeKindMap map[string]string
+var SupportedRunTimes map[string][]string
+var DefaultRunTimes map[string]string
+
+
+// We could get the openwhisk info from bluemix through running the command
+// `curl -k https://openwhisk.ng.bluemix.net`
+// hard coding it here in case of network unavailable or failure.
+func ParseOpenWhisk(apiHost string) (op OpenWhiskInfo, err error) {
+	ct := "application/json; charset=UTF-8"
+	req, _ := http.NewRequest("GET", "https://"+apiHost, nil)
+	req.Header.Set("Content-Type", ct)
+	tlsConfig := &tls.Config{
+		InsecureSkipVerify: true,
+	}
+
+	var netTransport = &http.Transport{
+		TLSClientConfig: tlsConfig,
+	}
+
+	var netClient = &http.Client{
+		Timeout:   time.Second * DEFAULT_HTTP_TIMEOUT,
+		Transport: netTransport,
+	}
+
+	res, err := netClient.Do(req)
+	if err != nil {
+		errString := wski18n.T("Failed to get the supported runtimes from OpenWhisk service: {{.err}}.\n",
+			map[string]interface{}{"err": err.Error()})
+		whisk.Debug(whisk.DbgWarn, errString)
+	}
+
+	if res != nil {
+		defer res.Body.Close()
+	}
+
+	// Local openwhisk deployment sometimes only returns "application/json" as the content type
+	if err != nil || !strings.Contains(ct, res.Header.Get("Content-Type")) {
+		stdout := wski18n.T("Start to unmarshal Openwhisk info from local values.\n")
+		whisk.Debug(whisk.DbgInfo, stdout)
+		err = json.Unmarshal(RUNTIME_DETAILS, &op)
+	} else {
+		b, _ := ioutil.ReadAll(res.Body)
+		if b != nil && len(b) > 0 {
+			stdout := wski18n.T("Unmarshal Openwhisk info from internet.\n")
+			whisk.Debug(whisk.DbgInfo, stdout)
+			err = json.Unmarshal(b, &op)
+		}
+	}
+	return
+}
+
+func ConvertToMap(op OpenWhiskInfo) (rt map[string][]string) {
+	rt = make(map[string][]string)
+	for k, v := range op.Runtimes {
+		rt[k] = make([]string, 0, len(v))
+		for i := range v {
+			if !v[i].Deprecated {
+				rt[k] = append(rt[k], v[i].Kind)
+			}
+		}
+	}
+	return
+}
+
+func DefaultRuntimes(op OpenWhiskInfo) (rt map[string]string) {
+	rt = make(map[string]string)
+	for k, v := range op.Runtimes {
+		for i := range v {
+			if !v[i].Deprecated {
+				if v[i].Default {
+					rt[k] = v[i].Kind
+				}
+			}
+		}
+	}
+	return
+}
+
+func FileExtensionRuntimes(op OpenWhiskInfo) (ext map[string]string) {
+	ext = make(map[string]string)
+	for k := range op.Runtimes {
+		if strings.Contains(k, NODEJS_FILE_EXTENSION) {
+			ext[NODEJS_FILE_EXTENSION] = k
+		} else if strings.Contains(k, PYTHON_FILE_EXTENSION) {
+			ext[PYTHON_FILE_EXTENSION] = k
+		} else if strings.Contains(k, SWIFT_FILE_EXTENSION) {
+			ext[SWIFT_FILE_EXTENSION] = k
+		} else if strings.Contains(k, PHP_FILE_EXTENSION) {
+			ext[PHP_FILE_EXTENSION] = k
+		} else if strings.Contains(k, JAVA_FILE_EXTENSION) {
+			ext[JAVA_FILE_EXTENSION] = k
+			ext[JAR_FILE_EXTENSION] = k
+		}
+	}
+	return
+}
+
+func CheckRuntimeConsistencyWithFileExtension (ext string, runtime string) bool {
+	rt := FileExtensionRuntimeKindMap[ext]
+	for _, v := range SupportedRunTimes[rt] {
+		if (runtime == v) {
+			return true
+		}
+	}
+	return false
+}
+
+func CheckExistRuntime(rtname string, runtimes map[string][]string) bool {
+	for _, v := range runtimes {
+		for i := range v {
+			if rtname == v[i] {
+				return true
+			}
+		}
+	}
+	return false
+}
+
+func ListOfSupportedRuntimes(runtimes map[string][]string) (rt []string) {
+	for _, v := range runtimes {
+		for _, t := range v {
+			rt = append(rt, t)
+		}
+	}
+	return
+}
+
+var RUNTIME_DETAILS = []byte(`{
+	"support":{
+		"github":"https://github.com/apache/incubator-openwhisk/issues",
+		"slack":"http://slack.openwhisk.org"
+	},
+	"description":"OpenWhisk",
+	"api_paths":["/api/v1"],
+	"runtimes":{
+		"nodejs":[{
+			"image":"openwhisk/nodejsaction:latest",
+			"deprecated":true,
+			"requireMain":false,
+			"default":false,
+			"attached":false,
+			"kind":"nodejs"
+		},{
+			"image":"openwhisk/nodejs6action:latest",
+			"deprecated":false,
+			"requireMain":false,
+			"default":true,
+			"attached":false,
+			"kind":"nodejs:6"
+		},{
+			"image":"openwhisk/action-nodejs-v8:latest",
+			"deprecated":false,
+			"requireMain":false,
+			"default":false,
+			"attached":false,
+			"kind":"nodejs:8"
+		}],
+		"java":[{
+			"image":"openwhisk/java8action:latest",
+			"deprecated":false,
+			"requireMain":true,
+			"default":true,
+			"attached":true,
+			"kind":"java"
+		}],
+		"php":[{
+			"image":"openwhisk/action-php-v7.1:latest",
+			"deprecated":false,
+			"requireMain":false,
+			"default":true,
+			"attached":false,
+			"kind":"php:7.1"
+		}],
+		"python":[{
+			"image":"openwhisk/python2action:latest",
+			"deprecated":false,
+			"requireMain":false,
+			"default":false,
+			"attached":false,
+			"kind":"python"
+		},{
+			"image":"openwhisk/python2action:latest",
+			"deprecated":false,
+			"requireMain":false,
+			"default":true,
+			"attached":false,
+			"kind":"python:2"
+		},{
+			"image":"openwhisk/python3action:latest",
+			"deprecated":false,
+			"requireMain":false,
+			"default":false,
+			"attached":false,
+			"kind":"python:3"
+		}],
+		"swift":[{
+			"image":"openwhisk/swiftaction:latest",
+			"deprecated":true,
+			"requireMain":false,
+			"default":false,
+			"attached":false,
+			"kind":"swift"
+		},{
+			"image":"openwhisk/swift3action:latest",
+			"deprecated":true,
+			"requireMain":false,
+			"default":false,
+			"attached":false,
+			"kind":"swift:3"
+		},{
+			"image":"openwhisk/action-swift-v3.1.1:latest",
+			"deprecated":false,
+			"requireMain":false,
+			"default":true,
+			"attached":false,
+			"kind":"swift:3.1.1"
+		}]
+	},
+	"limits":{
+		"actions_per_minute":5000,
+		"triggers_per_minute":5000,
+		"concurrent_actions":1000
+	}
+	}
+`)
diff --git a/wskderrors/wskdeployerror.go b/wskderrors/wskdeployerror.go
index b1935f4..61881d1 100644
--- a/wskderrors/wskdeployerror.go
+++ b/wskderrors/wskdeployerror.go
@@ -35,6 +35,9 @@ const (
 	STR_EXPECTED = "Expected"
 	STR_ACTUAL = "Actual"
 	STR_NEWLINE = "\n"
+	STR_ACTION = "Action"
+	STR_RUNTIME = "Runtime"
+	STR_SUPPORTED_RUNTIMES = "Supported Runtimes"
 
 	// Formatting
 	STR_INDENT_1 = "==>"
@@ -49,6 +52,7 @@ const (
 	ERROR_YAML_PARSER_ERROR = "ERROR_YAML_PARSER_ERROR"
 	ERROR_YAML_PARAMETER_TYPE_MISMATCH = "ERROR_YAML_PARAMETER_TYPE_MISMATCH"
 	ERROR_YAML_INVALID_PARAMETER_TYPE = "ERROR_YAML_INVALID_PARAMETER_TYPE"
+	ERROR_YAML_INVALID_RUNTIME = "ERROR_YAML_INVALID_RUNTIME"
 )
 
 /*
@@ -346,6 +350,32 @@ func NewYAMLParserErr(fpath string, msg interface{}) *YAMLParserError {
 	return err
 }
 
+
+/*
+ * InvalidRuntime
+ */
+type InvalidRuntimeError struct {
+	FileError
+	Runtime    		string
+	SupportedRuntimes	[]string
+}
+
+func NewInvalidRuntimeError(errMessage string, fpath string, action string, runtime string, supportedRuntimes []string) *InvalidRuntimeError {
+	var err = &InvalidRuntimeError{
+		SupportedRuntimes: supportedRuntimes,
+	}
+	err.SetErrorFilePath(fpath)
+	err.SetErrorType(ERROR_YAML_INVALID_RUNTIME)
+	err.SetCallerByStackFrameSkip(2)
+	str := fmt.Sprintf("%s %s [%s]: %s [%s]: %s [%s]",
+		errMessage,
+		STR_ACTION, action,
+		STR_RUNTIME, runtime,
+		STR_SUPPORTED_RUNTIMES, strings.Join(supportedRuntimes, ", "))
+	err.SetMessage(str)
+	return err
+}
+
 func IsCustomError( err error ) bool {
 
 	switch err.(type) {
diff --git a/wski18n/i18n_resources.go b/wski18n/i18n_resources.go
index 53ecfca..15db0ca 100644
--- a/wski18n/i18n_resources.go
+++ b/wski18n/i18n_resources.go
@@ -15,6 +15,7 @@
  * limitations under the License.
  */
 
+
 // Code generated by go-bindata.
 // sources:
 // wski18n/resources/de_DE.all.json
@@ -114,7 +115,7 @@ func wski18nResourcesDe_deAllJson() (*asset, error) {
 	return a, nil
 }
 
-var _wski18nResourcesEn_usAllJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5b\x4d\x6f\xdb\x38\x13\xbe\xe7\x57\x0c\x72\xf1\x25\xd0\xdb\xf6\xc5\x02\x8b\xde\x82\xed\x57\xd0\x36\x09\x92\x6c\x8b\xa2\x5b\x20\xb4\x38\xb6\x58\x53\xa4\x40\x52\x0e\x5c\xc3\xff\x7d\x41\x51\xb2\x9d\x44\xa2\x28\x59\x76\x82\x62\x73\x72\x64\xce\xf3\x3c\x33\xfc\x1c\x6a\xfc\xfd\x08\x60\x79\x04\x00\x70\xcc\xe8\xf1\x6b\x38\xfe\x80\x9c\xcb\xe3\x13\xf7\xc8\x28\x22\x34\x27\x86\x49\x61\xbf\x3b\x15\x70\x7a\x79\x06\x89\xd4\x06\xd2\x5c\x1b\x18\x23\x64\x4a\xce\x19\x45\x1a\x1d\x1f\x01\xac\x4e\x1e\xc2\x7d\x66\x5a\x33\x31\x85\x38\xa5\x30\xc3\x45\x03\x70\xd5\x6a\x14\xa7\x74\x04\x4c\x64\xb9\x29\x5a\xd7\x42\x92\xdc\x24\x52\xb1\x5f\x85\x35\xdc\x7e\x7c\xfb\xed\xb6\x01\xb6\xae\x65\x2d\xe4\x5d\xc2\xf4\xac\xf0\xed\xf6\xc3\xc5\xf5\x4d\x13\xde\xa3\x66\xb5\x60\x82\xa4\xa8\x33\x12\x63\x03\xca\xe6\xfb\x36\x2d\x5f\xde\x5e\x5d\x9f\x5d\x9c\x07\xc8\x59\xb7\xac\xef\x04\x22\xd8\x04\xb5\x81\x09\xe3\x08\x42\x1a\x98\xc8\x5c\x50\x20\x06\x32\x62\x12\x58\x2e\xa3\x4c\xc9\x9f\x18\x9b\x4b\x62\x92\xd5\x2a\xfa\x47\x34\x75\x54\x0f\x24\xef\xb8\x58\x2e\xa3\x05\x49\xf9\x6a\xf5\x3f\xfb\xc9\x7e\x28\xa0\x23\x18\x50\xf3\x3e\xa8\x02\xe2\xcc\xf4\x7d\x2c\x93\xa0\xc3\xfb\xbe\x5c\x46\xb6\x85\x43\xfb\x11\x1a\xed\x2e\x78\xb5\xf2\xfe\xae\xc2\x90\x96\xb8\xce\x00\x26\x52\x01\xc5\x8c\xcb\x45\x8a\xc2\x34\xcb\x09\xb7\xef\x4c\x9f\x8b\x5d\x05\x3c\x44\xa8\x95\x60\x43\xa6\x72\x61\x58\xba\x0e\xa7\xce\xb3\x4c\x2a\x83\x14\xc6\x0b\xb8\xc8\x50\xb8\x59\x95\x71\x62\x26\x52\xa5\xcd\x62\xfa\x61\xd5\x4f\x79\x3d\x73\xe2\x21\x21\x1a\xe2\x44\x6a\x14\x40\x20\x23\xca\xb0\x38\xe7\x44\xad\x89\xac\xa7\x96\x98\xc4\x56\x46\xb3\xb8\x5d\x10\xeb\x3b\x4f\x6c\x9c\xab\x4c\xcd\x22\xc3\x13\xd0\x68\xc0\x48\x10\x92\xe2\x4f\xdd\xd4\x71\x81\xd6\xb5\xd4\x37\x56\x5d\x6e\x12\x14\x86\xc5\x6e\x29\x9f\xe1\xa2\x8a\x79\x2c\xc5\x84\x4d\x73\x85\xb4\x39\x1a\x5d\x10\x1a\x25\xac\x77\xbe\x8e\xc4\x7e\xbb\x46\xba\xf5\x2e\xd1\x95\xaf\xc5\x30\xc8\xbf\xe5\x32\x22\x19\xb3\xff\xad\x56\x27\x30\x51\x32\x2d\x1f\x69\x99\xab\x18\x7d\xab\x6d\x2f\x28\x6f\xbf\x57\x7d\xa5\xd1\x6c\x01\xe4\x26\x09\x13\x13\x0c\x11\xd6\x15\xcb\x65\xb4\xfe\x7f\xdb\xa3\xf5\xc3\x30\x55\xfd\x31\x6b\x65\xbe\x23\x8c\x23\xb5\x33\x69\x8a\x6e\x67\x78\x34\xe1\xb4\x83\xb5\xcb\xd2\xd7\x62\x59\xd2\xa8\xe6\x2c\xc6\xd7\x96\x09\x95\xf2\x29\x1e\x0c\xbe\x56\xfc\xb5\x21\xaa\x58\x05\x72\x91\x12\xa5\x13\xc2\xb7\x16\x4f\x26\x26\xd2\x41\x73\x19\x13\x0e\x73\xc2\x73\xd4\xcd\x52\x7b\x82\x35\x2c\x7a\x3e\x08\x26\x0c\x2a\x81\xbe\xfd\x2a\xd8\xbe\x96\xfe\xcd\x7a\x43\x83\x58\xa6\x19\x47\x1b\x6e\x9d\xc7\x31\x6a\x3d\xc9\x39\x5f\x34\x33\x07\x99\xd6\x92\xbe\x97\x06\x50\x29\xa9\x20\x56\x48\x8c\xdd\x70\x33\x12\xcf\xc8\x14\xe1\x8e\x99\xa4\xfc\x2e\x45\xad\xc9\x74\xab\x73\x81\x08\x5a\xd9\x49\xea\xbe\xb0\x1f\x7c\xa3\x6a\x2f\x54\xa1\x4e\xb9\xfd\xee\x37\xf3\x29\x63\x87\x70\x68\x37\x9a\x50\x67\x54\xce\x0f\x32\xe4\x76\xe4\x69\x71\x47\xa3\x29\x58\x8a\x35\xd3\x10\x93\x6b\x90\x93\x7d\xfb\xb6\x17\xd2\xd0\x7e\x33\x8a\x4d\xa7\xa8\x0e\xd1\x75\xbb\x53\x75\x75\x6a\x82\x48\x0f\xe9\xd9\x8e\x7c\x5d\x57\xf8\x31\x13\xd4\xfe\x7f\xc0\x55\x71\x77\xca\xb6\xbd\x53\x4e\x6c\x76\x8a\x82\xa2\x88\x17\xd6\x94\x62\x76\x4e\x52\x5c\xad\x80\x32\x5a\x1e\x91\xdd\x1e\x69\xb7\xc8\xf5\x0e\x09\x57\xb9\x80\xdb\x4d\x26\x55\x65\x98\xb7\xf6\x74\xa1\x30\x95\x73\x74\x09\x15\xe1\x7c\x51\x26\xc0\x48\x81\x68\x8d\xc6\x73\x40\x79\x0e\xca\x3c\x21\xdb\xda\x1b\x97\xcb\x48\xe6\x26\xcb\xcd\x6a\x05\x51\x14\x79\xfd\xf1\x98\xb5\x90\x15\xcb\x52\x57\xaa\x5a\xa3\x16\xa2\x7b\x73\xaa\x2b\xa1\xd7\xb8\x85\xb8\x1a\xea\x5d\x39\x9b\xec\x02\xe9\xaa\x99\xd5\x97\xb6\xc9\xbe\x85\xfe\xfe\x88\xee\xc4\xec\x31\xad\x25\xbd\xf8\x18\xc1\x5f\x44\xc4\xc8\x79\x69\xde\x7a\x85\xe4\x35\x69\x21\xb1\x06\x61\x17\x55\x7e\x9b\x86\x5c\x63\xd3\xc8\x3f\xfb\x3d\xe9\x46\x07\x88\xb6\x55\xd3\x2d\x23\x3d\xf2\x8d\x26\xc3\xe7\xeb\x75\x85\xf0\x78\x08\x6e\xd6\xe3\xe6\xe1\x1b\x6a\xdd\xee\x7f\xdf\xed\x20\x2c\x34\x3b\xa0\xb7\x1c\x23\x28\x72\x3c\x4c\x4e\x35\x1c\x53\xa8\x4b\x7b\x3e\xa9\x0f\xc5\xf3\x5f\x16\xf2\x20\x9e\xfb\xcf\x42\x06\xa4\xea\xea\xd4\x9e\xb3\x90\xa1\xf9\x42\xdd\xdb\xff\x3d\xd3\x80\x54\xb5\x4e\x7d\x3d\xbd\x3a\x3f\x3b\x7f\xff\x1a\x6e\x12\x84\x91\xbb\xb5\x1d\xc1\xb7\xd3\xcf\x9f\xdc\x0d\xb4\x58\x87\x14\x85\x61\xa6\xb8\x93\xa6\x98\x29\x8c\x89\x41\x1a\xc1\x25\x47\xa2\x11\x72\x8d\x30\xb2\x41\x1f\x01\x13\xda\x20\xb1\x67\x77\xa0\xa8\x63\xc5\xc6\x48\x2d\x8e\xce\x30\x66\x93\xf2\x6d\x86\x27\xdb\x78\x4a\x45\xa1\xfd\x5e\x1d\x34\x0f\xd8\xff\xc3\x51\x36\x9d\xa3\xea\x0e\xb2\x09\xd1\x30\x46\x14\xf7\xce\x46\xeb\xfc\xcc\x7b\xba\xea\x07\x57\x2b\xee\xd2\x73\xbe\xef\xab\x70\x37\x4c\xaf\xcc\x21\xe5\x0d\x20\xeb\xa6\x9c\x2e\x43\xc8\xea\x87\xe5\x95\xf5\x28\x3f\xdd\x55\x5b\x0f\xc0\x5a\x81\x57\x0f\x33\xf6\xbe\xc2\x7a\x00\xd5\x0a\x3a\x7d\x7c\x5b\xd1\x57\x52\x2f\xa8\x80\x85\x63\x73\x42\xaf\x87\xab\x12\xcb\xf0\xb5\xa3\x1b\x62\xdb\x04\x28\xb7\x8e\x6d\xb4\x32\xfb\x0b\x1a\xf3\x7e\x73\xef\x28\xb2\xa7\xc8\x4e\xb4\x01\x86\x2d\xa3\xc4\xa5\x1c\x9d\x48\x03\x8d\x5b\xde\xe8\x32\x31\x97\x33\x2c\x8e\xd1\xee\x20\x96\xa0\x38\xd0\x99\xf0\xc0\x22\xfc\x67\xaa\xcf\x44\x50\x62\xa4\x5a\xc0\x84\x21\xa7\x50\x2d\xea\x5f\x50\x69\x1b\xe6\xaa\x22\x51\xfb\x5e\xc9\xf6\x45\xf3\x4b\x7b\x68\x5c\xd5\x03\x91\xb9\x3b\x1b\xd9\xb0\xc5\xb9\x52\x36\x0f\xdf\x5c\xdb\xce\x5d\xeb\x00\xb1\x3b\xe3\xf7\x8b\xec\x27\x16\xa3\xd0\x38\x50\x64\x1b\xd0\xc2\x22\x5b\x19\xef\x2b\xb2\xbd\xf1\xfd\xf2\x2b\xd8\xe5\x32\xe2\xee\xe3\xd9\x9b\xd5\xaa\x62\x21\x30\x27\x9c\x51\x90\x02\x03\xa4\x76\xc2\xaa\x95\x95\x62\x2a\xd5\xe2\x9a\xfd\x42\x9b\x89\x73\x96\x32\xa3\xad\x93\x55\x39\x1d\xe8\x44\xe6\x9c\xda\xce\x21\xa2\xa8\x4f\xb0\x93\x7a\x8c\xe6\xce\xae\x58\x2f\x5f\xfd\x59\x4c\xdf\x3f\x5e\xbe\x6a\x56\x3b\x28\x45\x7d\x0d\x1f\x4b\x51\xe6\xa6\x17\xfc\x8b\x17\x05\xfc\xff\x5f\xd8\x3f\x4f\x69\xdf\x90\x14\xb5\x4e\x70\x39\xed\x1b\x23\x87\xff\xd2\x23\x7f\x20\x70\xff\xc8\x3e\x13\x6e\xbc\x15\x0c\xae\xa6\x6e\x54\xc6\x6d\x64\x99\xcb\x1b\xba\x6d\x66\xa6\x81\x4d\x85\x54\x5b\x79\x65\x9c\x60\x3c\x73\x1b\x42\x48\x12\xbb\x1f\xd2\xee\x8e\x6e\x46\xf9\x61\x7d\x1d\x84\xb7\xbb\xbb\xe5\x80\x3a\xac\xaf\xbb\x93\xb6\x2d\xcd\xc5\xd4\x70\xcb\x69\xca\x8c\x70\xe7\xe2\x75\xd5\x64\x42\xc4\x94\x8c\x39\x02\xd1\xae\x42\xf5\xee\x04\xee\x12\x16\x27\x70\xc7\x38\xb7\xf3\xa7\xe2\x0f\x59\xba\x07\xe4\xaa\x75\xab\x28\x04\x97\x93\x62\xbf\x8a\x66\xb8\x28\x4a\xc6\x1b\x64\xd5\xb7\x6d\x87\x8d\x51\x99\x60\xdc\x4d\x63\x6f\x5d\x65\xd5\x9e\x64\x19\xaf\x6a\x73\x8b\xfa\xd0\x22\x4f\x71\xaf\x95\xec\x26\x27\xb6\x5e\xd5\xb9\x72\x78\x62\x8a\xc2\xf7\xcd\xe3\x77\xcc\x1e\xed\x7f\x00\x95\xe8\xc2\x9a\x12\x13\x27\x05\x7a\x3b\x53\x55\x6a\xbf\x72\x64\xe9\xbd\xca\xfb\x92\xaa\x7a\x58\x12\x35\xbd\x10\xfa\x2d\x5c\xf3\xcf\x9d\x6d\xa2\x1a\xfd\xc5\xa0\xd5\x52\x0a\x3b\x72\x37\xb7\x89\x27\x90\x6d\x6e\x13\xcb\x5f\x54\x54\xd7\x89\x01\x93\x68\x3f\xa4\x9d\x1c\xbd\x1f\xbb\x83\xb8\x39\x08\x65\xe0\xbb\x47\x57\x26\x5a\x5c\x04\x33\xd4\xde\xd7\x82\x40\x73\x65\x33\xbf\x94\x08\x32\x45\xba\xfd\x22\x7d\x4f\x75\x33\xcf\x56\x6e\x7d\xfa\x5e\xfc\x4a\x67\xf3\xc3\x8a\x7b\x97\x00\x6e\x69\x2f\x6e\xda\x9d\x0f\x45\x3d\xf0\x76\xaa\x51\xf5\xe1\xe6\xa7\x47\x75\x93\x77\x8d\x33\xc6\xed\x3a\x03\xdf\x96\xf4\xf4\xba\x5a\xc2\x65\xea\xee\x87\x9e\x45\xc0\x9e\x4e\x59\x4b\xc8\xb6\xea\x84\xca\x8f\xcf\x25\x64\x4f\xa7\xcc\x86\xec\xe8\xe8\xc7\xd1\xbf\x01\x00\x00\xff\xff\x5f\x5a\x74\xc9\xe0\x3a\x00\x00")
+var _wski18nResourcesEn_usAllJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5b\x5b\x6f\xe3\x36\x16\x7e\xcf\xaf\x38\xc8\x8b\x5f\x02\xed\x4c\x17\x0b\x2c\xe6\x2d\xd8\xe9\x25\x68\xe7\x82\x99\xd9\x16\x45\x77\x80\xd0\xe2\xb1\xc5\x9a\x22\x05\x92\x72\xea\x0a\xfe\xef\x0b\x92\x92\x2f\x89\x44\x51\xb2\xec\x04\x45\xf3\xe4\xd8\x3a\xdf\xf7\x9d\xc3\xdb\x21\x79\xf4\xdb\x15\x40\x75\x05\x00\x70\xcd\xe8\xf5\x1b\xb8\xfe\x01\x39\x97\xd7\x37\xfe\x2b\xa3\x88\xd0\x9c\x18\x26\x85\xfd\xed\x56\xc0\xed\xc7\x3b\xc8\xa4\x36\x90\x97\xda\xc0\x1c\xa1\x50\x72\xcd\x28\xd2\xe4\xfa\x0a\x60\x7b\xf3\x18\xee\x1d\xd3\x9a\x89\x25\xa4\x39\x85\x15\x6e\x3a\x80\x9b\xa7\x66\x69\x4e\x67\xc0\x44\x51\x1a\xf7\x74\x2b\x24\x29\x4d\x26\x15\xfb\xd3\x59\xc3\xfd\x8f\xdf\xfe\x7a\xdf\x01\xdb\xf6\x64\x2b\xe4\x43\xc6\xf4\xca\xf9\x76\xff\xc3\x87\xcf\x5f\xba\xf0\x9e\x3c\xd6\x0a\x26\x48\x8e\xba\x20\x29\x76\xa0\xec\x7f\xef\xd3\xf2\xf3\xb7\x9f\x3e\xdf\x7d\x78\x1f\x21\x67\xf7\x64\x7b\x23\x10\xc1\x16\xa8\x0d\x2c\x18\x47\x10\xd2\xc0\x42\x96\x82\x02\x31\x50\x10\x93\x41\x55\x25\x85\x92\xbf\x63\x6a\x3e\x12\x93\x6d\xb7\xc9\xff\x44\x57\x43\x8d\x40\x0a\xf6\x8b\xaa\x4a\x36\x24\xe7\xdb\xed\x3f\xec\x27\xfb\xc1\x41\x27\x30\xa1\xe6\x73\x50\x45\xc4\x99\xe9\x63\x2c\x93\xa1\xc7\xfb\xad\xaa\x12\xfb\x84\x47\xfb\x1a\x1b\xed\x21\x78\xad\xf2\xfe\xdb\x84\x21\xaf\x71\xbd\x01\x2c\xa4\x02\x8a\x05\x97\x9b\x1c\x85\xe9\x96\x13\x6f\x3f\x98\xbe\x14\xa7\x0a\x78\x8c\xd0\x2a\xc1\x86\x4c\x95\xc2\xb0\x7c\x17\x4e\x5d\x16\x85\x54\x06\x29\xcc\x37\xf0\xa1\x40\xe1\x47\x55\xc1\x89\x59\x48\x95\x77\x8b\x19\x87\xd5\x2a\xeb\x97\xdb\x4f\xef\xef\xde\x7f\xff\x06\x3e\xd5\x78\xba\xc0\x94\x2d\x18\x52\x60\x02\x1a\x67\xe1\xd7\xdb\x77\x3f\x59\xef\x6b\xd6\xed\x16\xa8\x44\xcf\x9c\x13\x93\x66\xf0\xc0\x4c\x06\x24\x75\xb3\x9d\x96\xa5\x4a\xd1\xf7\x1c\xfc\xc3\xa0\xd0\xf6\xdb\xaa\x4a\xf0\x0f\x53\x87\xac\x7e\xb2\xaa\x12\xff\x29\x34\x88\x5e\x94\xc4\x70\x10\x7f\x71\x41\x7f\xeb\x7a\x03\x64\x44\x43\x9a\x49\x8d\x02\x48\x51\x28\x59\x28\x46\xcc\xbe\xe1\x8e\xa4\xce\x89\x46\x0a\x52\xb8\x91\x15\xd4\x68\xa5\x99\x8c\x98\x71\x21\x7c\x7e\x81\xd3\xf6\xc2\xae\xde\xef\xfd\xd4\xa8\xd6\xa8\x6a\x45\x78\x99\x4e\x37\x81\xa2\xab\xf6\x39\x4c\xec\x31\x9b\x26\x32\x9b\x02\x6f\x40\xa3\x01\x23\x41\x48\x8a\xbf\xeb\xae\xf9\x2b\xd2\xba\x95\xfa\x8b\x95\x5a\x9a\x0c\x85\x61\xa9\xcf\x68\x56\xb8\x69\x5c\x4d\xa5\x58\xb0\x65\xa9\x90\x76\x87\x73\x08\x42\xa7\x84\x5d\x02\x38\x90\x38\x6c\xd7\x49\xb7\x4b\x96\x86\xf2\xf5\x18\x46\xf9\x67\xbb\x44\xc1\xec\x7f\xdb\xed\x0d\x2c\x94\xcc\xeb\xaf\xfc\xa0\x0b\x75\xdd\x51\x50\xc1\x76\x6f\xda\x4a\xa3\x39\x00\x28\x4d\x16\x27\x26\x1a\x22\xae\x29\xaa\x2a\xd9\xfd\x7f\xe8\xd1\xee\xcb\x38\x55\xe3\x31\x5b\x65\x7e\x47\x18\x47\x6a\x47\xd2\x12\x7d\x82\xf4\x64\xc0\x69\x0f\x7b\x3c\x1b\xb0\x14\xdf\xb8\x85\x47\xa9\x90\xe2\xc9\xe0\x5b\xc5\x7f\x36\x44\xb9\x59\xa0\x14\x39\x51\x3a\x23\xfc\x20\x87\x60\x62\x21\x3d\x34\x97\x29\xe1\xb0\x26\xbc\x44\xdd\x2d\x75\x24\x58\xc7\xa4\x17\x82\x60\xc2\xa0\x12\x18\x4a\xdb\xa2\xed\x5b\xe9\xdf\xee\xf2\x3a\x48\x65\x5e\x70\xb4\xe1\xd6\x65\x9a\xa2\xd6\x8b\x92\xf3\x4d\x37\x73\x94\x69\x2b\xe9\xf7\xd2\x00\x2a\x25\x15\xa4\x0a\x89\xb1\x79\x67\x41\xd2\x15\x59\xa2\x4f\x61\xfc\x6f\x39\x6a\x4d\x96\x07\x8d\x0b\x44\xd0\xc6\x4e\x52\xff\x83\xfd\x10\xea\x55\x67\xa1\x8a\x75\xaa\x5e\xfc\xfe\x5a\x3e\x15\xec\x12\x0e\x9d\x46\x13\xeb\x8c\x2a\xf9\x45\xba\xdc\x89\x3c\x3d\xee\x68\x34\x8e\xc5\xcd\x99\x86\x98\x52\x83\x5c\x9c\xdb\xb7\xb3\x90\xc6\xb6\x9b\x51\x6c\xb9\x44\x75\x89\xa6\x3b\x9d\x6a\xa8\x53\x0b\x44\x7a\x49\xcf\x4e\xe4\x1b\x3a\xc3\xcf\x99\xa0\xf6\xff\x0b\xce\x8a\xa7\x53\xf6\xad\x9d\x72\x01\x14\x0b\x14\x14\x45\xba\xb1\xa6\x14\x8b\xf7\xc4\xef\xd1\x19\xad\x53\x64\xbf\x46\xda\x25\x72\xb7\x42\xda\xcd\x17\xdc\x3f\xe8\x95\x3f\x5f\xd9\x1d\xb4\xdc\xdb\xec\x42\x61\x2e\xd7\x08\x05\x51\x86\x11\xce\x37\xf5\x39\x10\x52\x20\x5a\xa3\x09\x24\x28\x2f\x41\x59\x20\x64\x07\x6b\x63\x55\x25\xb2\x34\x45\x69\xb6\x5b\x48\x92\x24\xe8\x4f\xc0\xac\x87\xcc\x4d\x4b\x43\xa9\x5a\x8d\x7a\x88\x8e\xc6\xd4\x50\xc2\xa0\x71\x0f\x71\xd3\xd5\x87\x72\x76\xd9\x45\xd2\x35\x23\x6b\x2c\x6d\x97\x7d\x0f\xfd\x71\x8f\x1e\xc4\x1c\x30\x6d\x25\xfd\xf0\x63\x02\xff\x21\x22\x45\xce\x6b\xf3\xde\x93\xd4\xa0\x49\x0f\x89\x35\x88\x3b\xaf\x0d\xdb\x74\xec\x35\xf6\x0f\x85\x47\x7f\x60\xbb\x31\x00\xa2\x6f\xd6\xf4\xd3\xc8\x88\xfd\x46\x97\xe1\xcb\xf5\xba\x41\x78\xda\x05\xf7\xf3\x71\x77\xf7\x8d\xb5\xee\xf7\x7f\xec\x72\x10\x17\x9a\x13\xd0\x7b\xd2\x08\x8a\x1c\x2f\xb3\xa7\x9a\x8e\x29\xd6\xa5\x33\x67\xea\x53\xf1\xfc\xbd\x0b\x79\x14\xcf\xf3\xef\x42\x26\xa4\x1a\xea\xd4\x99\x77\x21\x53\xf3\xc5\xba\x77\xfe\x73\xa6\x09\xa9\xc2\x37\x49\x5f\x32\x84\x99\x3f\xb5\x9d\xf9\x6b\x1a\x77\x02\x2d\x76\x21\x45\x61\x98\x71\x67\xd2\x14\x0b\x85\x29\x31\x48\x13\xf8\xc8\x91\x68\x84\x52\x23\xcc\x6c\xd0\x67\xc0\x84\x36\x48\x6c\xee\x0e\x14\x75\xaa\xd8\xdc\xdf\x01\xd5\x17\x42\xfe\x36\x23\xb0\xdb\x78\x4e\x45\xb1\xed\xde\x24\x9a\x17\x6c\xff\xe9\x28\xbb\xf2\xa8\xb6\x44\x36\x23\x1a\xe6\x88\xe2\x28\x37\xda\xed\xcf\x82\xd9\xd5\x38\xb8\x56\x71\x1f\x03\xf9\xfd\x58\x85\xa7\x61\x06\x65\x4e\x29\x6f\x02\x59\x5f\xea\xe1\x32\x85\xac\x71\x58\x41\x59\x4f\xf6\xa7\xa7\x6a\x1b\x01\xd8\x2a\xf0\xd3\xe3\x1d\xfb\x58\x61\x23\x80\x5a\x05\xdd\x3e\x3d\xad\x18\x2b\x69\x14\x54\xc4\xc4\xb1\xcf\xd0\xdb\xe1\x9a\x8d\x65\xfc\xdc\x31\x0c\xb1\x6f\x00\xd4\x4b\xc7\x21\x5a\xbd\xfb\x8b\xea\xf3\x61\xf3\x60\x2f\xb2\x59\xe4\x20\xda\x08\xc3\x9e\x5e\xd2\xd4\x48\x0c\x20\x8d\x34\xee\xb9\xd1\x65\x62\x2d\x57\xe8\xd2\x68\x9f\x88\x65\x28\x2e\x94\x13\x5e\x58\x44\x38\xa7\x7a\x47\x04\x25\x46\xaa\x0d\x2c\x18\x72\x0a\xcd\xa4\xfe\x33\x2a\x57\xfa\xd3\x14\xe6\xea\xd0\x95\xec\x58\xb4\xb0\xb4\xc7\xc6\x4d\x19\x0e\x59\xfb\xdc\xc8\x86\x2d\x2d\x95\xb2\xfb\xf0\xfd\xb1\xed\xda\x3f\x1d\x21\xf6\x64\xfc\x71\x91\xfd\x89\xa5\x28\x34\x4e\x14\xd9\x0e\xb4\xb8\xc8\x36\xc6\xe7\x8a\xec\x68\xfc\xb0\xfc\x06\xb6\xaa\x12\xee\x3f\xde\xbd\xdd\x97\x69\x11\x58\x13\xce\x28\x48\x81\x11\x52\x07\x61\xb5\xca\xca\x31\x97\x6a\xf3\x99\xfd\x89\x76\x27\xce\x59\xce\x8c\x3e\x2a\x28\xd3\x99\x2c\x39\xb5\x8d\x43\x84\xab\x4f\xb0\x83\x7a\x8e\xe6\xc1\xce\x58\xaf\xbf\xf9\xb7\x1b\xbe\xff\x7a\xfd\x4d\xb7\xda\x49\x29\xda\x4b\x59\x59\x8e\xb2\x34\xa3\xe0\x5f\xbd\x72\xf0\xff\x7c\x65\xff\x02\x15\xae\x53\x52\xb4\x3a\xc1\xe5\x72\x6c\x8c\x3c\xfe\xeb\x80\xfc\x89\xc0\xc3\x3d\xfb\x4e\xf8\xfe\xe6\x18\x7c\x4d\xdd\xac\x8e\xdb\xcc\x32\xd7\x27\x74\x87\xcc\x4c\x03\x5b\x0a\xa9\x0e\xf6\x95\x69\x86\xe9\xca\x2f\x08\x31\x9b\xd8\xf3\x90\x0e\x77\x74\xdf\xcb\x2f\xeb\xeb\x24\xbc\xc3\xdd\xad\x3b\xd4\x65\x7d\x3d\x9d\xb4\x6f\x6a\x76\x43\xc3\x4f\xa7\x39\x33\xc2\xe7\xc5\xbb\xaa\xc9\x8c\x88\x25\x99\x73\x04\xa2\x7d\x85\xea\xc3\x0d\x3c\x64\xcc\x95\x72\x73\x6e\xc7\x4f\xc3\x1f\x33\x75\x4f\xc8\xd5\xea\x96\x7b\x1f\x42\x2e\xdc\x7a\x95\xac\x70\xe3\xea\xa2\x3b\x64\xb5\x3f\xdb\x0f\x9b\xa2\x32\xd1\xb8\xfb\x87\x83\x75\x95\xcd\xf3\xa4\x28\x78\x53\x9b\xeb\xea\x43\xdd\x3e\xc5\x5f\x2b\xd9\x45\x4e\x1c\x5c\xd5\xf9\x9a\x6f\x62\xdc\xfb\x1f\xfb\xaf\xbf\x63\x36\xb5\xff\xfa\xb8\xf0\xde\x44\x31\x35\x6f\x9c\x6c\x3d\x59\x7e\xf4\x02\x4a\x4d\xd5\x7c\x59\x13\x75\x5d\x08\xfd\x25\x5c\x0b\x8f\x9d\x43\xa2\x16\xfd\xae\xd3\x6a\x29\x85\xed\xb9\xfb\xd3\xc4\x1b\x28\xf6\xa7\x89\xf5\x8b\x45\xcd\x71\x62\xc4\x20\x3a\x0f\xe9\x20\x47\x8f\x63\x77\x11\x37\x27\xa1\x8c\xbc\x7b\xf4\x65\xa2\xee\x20\x98\xa1\x0e\x5e\x0b\x02\x2d\x95\xdd\xf9\xe5\x44\x90\x25\xd2\xc3\x8b\xf4\x33\xd5\xcd\xbc\x58\xb9\xed\xdb\x77\xf7\xb2\x5a\xfb\x5b\x16\xf5\xd4\xee\x4e\xda\xbd\x0f\xae\x1e\xf8\x70\xab\xd1\xb4\xe1\xfe\x0d\xbc\xb6\xc1\xbb\xc3\x99\xe3\x61\x9d\x41\x68\x49\x7a\x7e\x5d\x3d\xe1\x32\x6d\xe7\x43\x2f\x22\x60\xcf\xa7\xac\x27\x64\x07\x75\x42\xf5\xc7\x97\x12\xb2\xe7\x53\x66\x43\x76\x75\xf5\xf5\xea\xff\x01\x00\x00\xff\xff\xad\xc0\x83\x15\xe7\x3d\x00\x00")
 
 func wski18nResourcesEn_usAllJsonBytes() ([]byte, error) {
 	return bindataRead(
@@ -129,7 +130,7 @@ func wski18nResourcesEn_usAllJson() (*asset, error) {
 		return nil, err
 	}
 
-	info := bindataFileInfo{name: "wski18n/resources/en_US.all.json", size: 15072, mode: os.FileMode(420), modTime: time.Unix(1510298069, 0)}
+	info := bindataFileInfo{name: "wski18n/resources/en_US.all.json", size: 15847, mode: os.FileMode(420), modTime: time.Unix(1513194493, 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 b5cf545..cb49feb 100644
--- a/wski18n/resources/en_US.all.json
+++ b/wski18n/resources/en_US.all.json
@@ -48,8 +48,16 @@
     "translation": "the runtime is not supported by Openwhisk platform.\n"
   },
   {
-    "id": "wskdeploy has chosen a particular runtime for the action.\n",
-    "translation": "wskdeploy has chosen a particular runtime for the action.\n"
+    "id": "WARNING: Runtime specified in manifest YAML {{.runtime}} does not match with action source file extension {{.ext}} for action {{.action}}.\n",
+    "translation": "WARNING: Runtime specified in manifest YAML {{.runtime}} does not match with action source file extension {{.ext}} for action {{.action}}.\n"
+  },
+  {
+    "id": "WARNING: Whisk Deploy has chosen appropriate runtime {{.runtime}} based on the action source file extension for that action {{.action}}.\n",
+    "translation": "WARNING: Whisk Deploy has chosen appropriate runtime {{.runtime}} based on the action source file extension for that action {{.action}}.\n"
+  },
+  {
+    "id": "WARNING: Runtime specified in manifest YAML {{.runtime}} is not supported by OpenWhisk server for the action {{.action}}.\n",
+    "translation": "WARNING: Runtime specified in manifest YAML {{.runtime}} is not supported by OpenWhisk server for the action {{.action}}.\n"
   },
   {
     "id": "Unsupported runtime type, set to nodejs",


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services