Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Counters and Lists: Remove Bool Returns #3738

Merged
merged 22 commits into from
Apr 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
0ae2d9c
Counters and Lists Methods: Remove Boolean Returns
Kalaiselvi84 Mar 27, 2024
b89c673
change in main.go and gameserver_test.go
Kalaiselvi84 Mar 27, 2024
5b644a8
Modify incrementCounter
Kalaiselvi84 Apr 4, 2024
5c2d4b3
change project name
Kalaiselvi84 Apr 4, 2024
542188c
update sdk-client-test.go
Kalaiselvi84 Apr 4, 2024
e303e6f
C-L methods: remove bool returns
Kalaiselvi84 Apr 5, 2024
bf36272
Merge branch 'main' into cl-rm-bool
Kalaiselvi84 Apr 5, 2024
a628dcc
project update
Kalaiselvi84 Apr 5, 2024
545a95b
error string should not start with uppercase
Kalaiselvi84 Apr 10, 2024
61b137c
change err to nil
Kalaiselvi84 Apr 16, 2024
f10ba34
Merge branch 'cl-rm-bool' of https://github.com/Kalaiselvi84/agones i…
Kalaiselvi84 Apr 16, 2024
af55624
Merge branch 'main' into cl-rm-bool
Kalaiselvi84 Apr 16, 2024
73f5dde
Bump simple-game-server image
Kalaiselvi84 Apr 17, 2024
7081403
Merge branch 'main' into cl-rm-bool
Kalaiselvi84 Apr 17, 2024
50a357f
Merge branch 'main' into cl-rm-bool
Kalaiselvi84 Apr 17, 2024
2062134
SUCCESS response update: remove ACK and include new line
Kalaiselvi84 Apr 18, 2024
0710b86
Merge branch 'main' into cl-rm-bool
zmerlynn Apr 19, 2024
4ff3973
bump sgs:0.30
Kalaiselvi84 Apr 19, 2024
1049c50
Merge branch 'cl-rm-bool' of https://github.com/Kalaiselvi84/agones i…
Kalaiselvi84 Apr 19, 2024
788f7be
Merge branch 'main' into cl-rm-bool
Kalaiselvi84 Apr 19, 2024
1f54fd3
Merge branch 'main' into cl-rm-bool
zmerlynn Apr 19, 2024
8e6d7b3
remove bool from fleet_test.com
Kalaiselvi84 Apr 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ KIND_PROFILE ?= agones
KIND_CONTAINER_NAME=$(KIND_PROFILE)-control-plane

# Game Server image to use while doing end-to-end tests
GS_TEST_IMAGE ?= us-docker.pkg.dev/agones-images/examples/simple-game-server:0.28
GS_TEST_IMAGE ?= us-docker.pkg.dev/agones-images/examples/simple-game-server:0.30

# Enable all alpha feature gates. Keep in sync with `false` (alpha) entries in pkg/util/runtime/features.go:featureDefaults
ALPHA_FEATURE_GATES ?= "PlayerAllocationFilter=true&PlayerTracking=true&CountsAndLists=true&Example=true"
Expand Down
2 changes: 1 addition & 1 deletion build/scripts/bump-image/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

// Package main implements a program to increment the new tag for the given examples image. Run this script using `make bump-image IMAGENAME=<imageName> VERSION=<version>`
// Package main implements a program to increment the new tag for the given examples image. Run this script using `make bump-image IMAGENAME=<imageName> VERSION=<current-version>`
package main

import (
Expand Down
2 changes: 1 addition & 1 deletion examples/crd-client/create-gs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,5 @@ spec:
imagePullPolicy: Always
env:
- name: GAMESERVER_IMAGE
value: us-docker.pkg.dev/agones-images/examples/simple-game-server:0.28
value: us-docker.pkg.dev/agones-images/examples/simple-game-server:0.30
restartPolicy: Never
2 changes: 1 addition & 1 deletion examples/fleet.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,4 @@ spec:
spec:
containers:
- name: simple-game-server
image: us-docker.pkg.dev/agones-images/examples/simple-game-server:0.28
image: us-docker.pkg.dev/agones-images/examples/simple-game-server:0.30
2 changes: 1 addition & 1 deletion examples/gameserver.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ spec:
spec:
containers:
- name: simple-game-server
image: us-docker.pkg.dev/agones-images/examples/simple-game-server:0.28
image: us-docker.pkg.dev/agones-images/examples/simple-game-server:0.30
imagePullPolicy: Always
# nodeSelector is a label that can be used to tell Kubernetes which host
# OS to use. For Windows game servers uncomment the nodeSelector
Expand Down
2 changes: 1 addition & 1 deletion examples/simple-game-server/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ WITH_ARM64 ?= 1

mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
project_path := $(dir $(mkfile_path))
version := 0.28
version := 0.30
ifeq ($(REPOSITORY),)
server_tag := simple-game-server:$(version)
else
Expand Down
2 changes: 1 addition & 1 deletion examples/simple-game-server/dev-gameserver.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,4 @@ spec:
spec:
containers:
- name: simple-game-server
image: us-docker.pkg.dev/agones-images/examples/simple-game-server:0.28
image: us-docker.pkg.dev/agones-images/examples/simple-game-server:0.30
2 changes: 1 addition & 1 deletion examples/simple-game-server/fleet-distributed.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ spec:
spec:
containers:
- name: simple-game-server
image: us-docker.pkg.dev/agones-images/examples/simple-game-server:0.28
image: us-docker.pkg.dev/agones-images/examples/simple-game-server:0.30
resources:
requests:
memory: 64Mi
Expand Down
2 changes: 1 addition & 1 deletion examples/simple-game-server/fleet-tcp.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ spec:
spec:
containers:
- name: simple-game-server
image: us-docker.pkg.dev/agones-images/examples/simple-game-server:0.28
image: us-docker.pkg.dev/agones-images/examples/simple-game-server:0.30
env:
# Disables the UDP listener (Enabled by default)
- name: UDP
Expand Down
2 changes: 1 addition & 1 deletion examples/simple-game-server/fleet.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ spec:
spec:
containers:
- name: simple-game-server
image: us-docker.pkg.dev/agones-images/examples/simple-game-server:0.28
image: us-docker.pkg.dev/agones-images/examples/simple-game-server:0.30
resources:
requests:
memory: 64Mi
Expand Down
2 changes: 1 addition & 1 deletion examples/simple-game-server/gameserver-passthrough.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ spec:
spec:
containers:
- name: simple-game-server
image: us-docker.pkg.dev/agones-images/examples/simple-game-server:0.28
image: us-docker.pkg.dev/agones-images/examples/simple-game-server:0.30
env:
- name: PASSTHROUGH
value: 'TRUE'
Expand Down
2 changes: 1 addition & 1 deletion examples/simple-game-server/gameserver-windows.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ spec:
spec:
containers:
- name: simple-game-server
image: us-docker.pkg.dev/agones-images/examples/simple-game-server:0.28
image: us-docker.pkg.dev/agones-images/examples/simple-game-server:0.30
resources:
requests:
memory: 64Mi
Expand Down
2 changes: 1 addition & 1 deletion examples/simple-game-server/gameserver.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ spec:
spec:
containers:
- name: simple-game-server
image: us-docker.pkg.dev/agones-images/examples/simple-game-server:0.28
image: us-docker.pkg.dev/agones-images/examples/simple-game-server:0.30
resources:
requests:
memory: 64Mi
Expand Down
96 changes: 51 additions & 45 deletions examples/simple-game-server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ func handleResponse(txt string, s *sdk.SDK, cancel context.CancelFunc) (response
response = txt
addACK = true
responseError = nil
var err error

switch parts[0] {
// shuts down the gameserver
Expand Down Expand Up @@ -322,7 +323,7 @@ func handleResponse(txt string, s *sdk.SDK, cancel context.CancelFunc) (response
responseError = fmt.Errorf("Invalid INCREMENT_COUNTER, should have 2 arguments")
return
}
response, responseError = incrementCounter(s, parts[1], parts[2])
response, err = incrementCounter(s, parts[1], parts[2])
addACK = false
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When addACK = true then any response will start with "ACK" which why we're seeing actual : "ACK: SUCCESS\n" as the result.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't made any modifications to the value of this addACK.

Here's the code snippet:

if err != nil {
		return err.Error(), false, err
	}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's in the case where there is an error. In the case where there is no error it returns the default addACK = true.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I understand this part, when there is no error, the default value will be addAck = true.
Sorry, I want to make sure I get it right. Could you please share your suggestion differently?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe @igooch is saying that when you look at the e2e tests:

    fleet_test.go:1745: 
        	Error Trace:	/go/src/agones.dev/agones/test/e2e/fleet_test.go:1745
        	Error:      	Not equal: 
        	            	expected: "SUCCESS: true\n"
        	            	actual  : "ACK: SUCCESS\n"

The reason that the actual response is ACK: SUCCESS, is because you removed the line addACK = false -- whereas it should remain in to remove the "ACK: " from the response we're seeing in e2e tests (and I expect locally as well).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good pickup @igooch - I didn't see the "ACK: SUCCESS" output in #3738 (comment) - whereas the output should just be "SUCCESS".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for explaining. I've made changes to the code in the main.go and gameserver_test.go files. Please review the testing for the success use case. Once you both confirm the changes, will push a new image to production.

$ nc -u localhost 7654
GET_COUNTER_COUNT rooms
COUNTER: 1
INCREMENT_COUNTER rooms 1
SUCCESS
INCREMENT_COUNTER rooms 1
SUCCESS
DECREMENT_COUNTER rooms 1
SUCCESS
SET_COUNTER_COUNT rooms 5
SUCCESS
SET_COUNTER_CAPACITY rooms 6
SUCCESS
SET_LIST_CAPACITY players 1000
SUCCESS
APPEND_LIST_VALUE players test3
SUCCESS
DELETE_LIST_VALUE players test2
SUCCESS

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That looks good!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@igooch I look forward to hearing your thoughts at your convenience!🙂


case "DECREMENT_COUNTER":
Expand All @@ -331,7 +332,7 @@ func handleResponse(txt string, s *sdk.SDK, cancel context.CancelFunc) (response
responseError = fmt.Errorf("Invalid DECREMENT_COUNTER, should have 2 arguments")
return
}
response, responseError = decrementCounter(s, parts[1], parts[2])
response, err = decrementCounter(s, parts[1], parts[2])
addACK = false

case "SET_COUNTER_COUNT":
Expand All @@ -340,7 +341,7 @@ func handleResponse(txt string, s *sdk.SDK, cancel context.CancelFunc) (response
responseError = fmt.Errorf("Invalid SET_COUNTER_COUNT, should have 2 arguments")
return
}
response, responseError = setCounterCount(s, parts[1], parts[2])
response, err = setCounterCount(s, parts[1], parts[2])
addACK = false

case "GET_COUNTER_CAPACITY":
Expand All @@ -358,7 +359,7 @@ func handleResponse(txt string, s *sdk.SDK, cancel context.CancelFunc) (response
responseError = fmt.Errorf("Invalid SET_COUNTER_CAPACITY, should have 2 arguments")
return
}
response, responseError = setCounterCapacity(s, parts[1], parts[2])
response, err = setCounterCapacity(s, parts[1], parts[2])
addACK = false

case "GET_LIST_CAPACITY":
Expand All @@ -376,7 +377,7 @@ func handleResponse(txt string, s *sdk.SDK, cancel context.CancelFunc) (response
responseError = fmt.Errorf("Invalid SET_LIST_CAPACITY, should have 2 arguments")
return
}
response, responseError = setListCapacity(s, parts[1], parts[2])
response, err = setListCapacity(s, parts[1], parts[2])
addACK = false

case "LIST_CONTAINS":
Expand Down Expand Up @@ -412,7 +413,7 @@ func handleResponse(txt string, s *sdk.SDK, cancel context.CancelFunc) (response
responseError = fmt.Errorf("Invalid APPEND_LIST_VALUE, should have 2 arguments")
return
}
response, responseError = appendListValue(s, parts[1], parts[2])
response, err = appendListValue(s, parts[1], parts[2])
addACK = false

case "DELETE_LIST_VALUE":
Expand All @@ -421,9 +422,14 @@ func handleResponse(txt string, s *sdk.SDK, cancel context.CancelFunc) (response
responseError = fmt.Errorf("Invalid DELETE_LIST_VALUE, should have 2 arguments")
return
}
response, responseError = deleteListValue(s, parts[1], parts[2])
response, err = deleteListValue(s, parts[1], parts[2])
addACK = false
}

if err != nil {
return err.Error(), addACK, err
}

return
}

Expand Down Expand Up @@ -692,49 +698,49 @@ func getCounterCount(s *sdk.SDK, counterName string) (string, error) {
return "COUNTER: " + strconv.FormatInt(count, 10) + "\n", nil
}

// incrementCounter returns the if the Counter Count was incremented successfully (true) or not (false)
// incrementCounter returns the if the Counter Count was incremented successfully or not
func incrementCounter(s *sdk.SDK, counterName string, amount string) (string, error) {
amountInt, err := strconv.ParseInt(amount, 10, 64)
if err != nil {
return "false", fmt.Errorf("could not increment Counter %s by unparseable amount %s: %s", counterName, amount, err)
return "", fmt.Errorf("Could not increment Counter %s by unparseable amount %s: %s", counterName, amount, err)
}
log.Printf("Incrementing Counter %s Count by amount %d", counterName, amountInt)
ok, err := s.Alpha().IncrementCounter(counterName, amountInt)
err = s.Alpha().IncrementCounter(counterName, amountInt)
if err != nil {
log.Printf("Error incrementing Counter %s Count by amount %d: %s", counterName, amountInt, err)
return strconv.FormatBool(ok), err
return "", err
}
return "SUCCESS: " + strconv.FormatBool(ok) + "\n", nil
return "SUCCESS\n", nil
}

// decrementCounter returns the if the Counter Count was decremented successfully (true) or not (false)
// decrementCounter returns if the Counter Count was decremented successfully or not
func decrementCounter(s *sdk.SDK, counterName string, amount string) (string, error) {
amountInt, err := strconv.ParseInt(amount, 10, 64)
if err != nil {
return "false", fmt.Errorf("could not decrement Counter %s by unparseable amount %s: %s", counterName, amount, err)
return "", fmt.Errorf("could not decrement Counter %s by unparseable amount %s: %s", counterName, amount, err)
}
log.Printf("Decrementing Counter %s Count by amount %d", counterName, amountInt)
ok, err := s.Alpha().DecrementCounter(counterName, amountInt)
err = s.Alpha().DecrementCounter(counterName, amountInt)
if err != nil {
log.Printf("Error decrementing Counter %s Count by amount %d: %s", counterName, amountInt, err)
return strconv.FormatBool(ok), err
return "", err
}
return "SUCCESS: " + strconv.FormatBool(ok) + "\n", nil
return "SUCCESS\n", nil
}

// setCounterCount returns the if the Counter was set to a new Count successfully (true) or not (false)
// setCounterCount returns the if the Counter was set to a new Count successfully or not
func setCounterCount(s *sdk.SDK, counterName string, amount string) (string, error) {
amountInt, err := strconv.ParseInt(amount, 10, 64)
if err != nil {
return "false", fmt.Errorf("could not set Counter %s to unparseable amount %s: %s", counterName, amount, err)
return "", fmt.Errorf("could not set Counter %s to unparseable amount %s: %s", counterName, amount, err)
}
log.Printf("Setting Counter %s Count to amount %d", counterName, amountInt)
ok, err := s.Alpha().SetCounterCount(counterName, amountInt)
err = s.Alpha().SetCounterCount(counterName, amountInt)
if err != nil {
log.Printf("Error setting Counter %s Count by amount %d: %s", counterName, amountInt, err)
return strconv.FormatBool(ok), err
return "", err
}
return "SUCCESS: " + strconv.FormatBool(ok) + "\n", nil
return "SUCCESS\n", nil
}

// getCounterCapacity returns the Capacity of the given Counter as a string
Expand All @@ -748,19 +754,19 @@ func getCounterCapacity(s *sdk.SDK, counterName string) (string, error) {
return "CAPACITY: " + strconv.FormatInt(count, 10) + "\n", nil
}

// setCounterCapacity returns the if the Counter was set to a new Capacity successfully (true) or not (false)
// setCounterCapacity returns the if the Counter was set to a new Capacity successfully or not
func setCounterCapacity(s *sdk.SDK, counterName string, amount string) (string, error) {
amountInt, err := strconv.ParseInt(amount, 10, 64)
if err != nil {
return "false", fmt.Errorf("could not set Counter %s to unparseable amount %s: %s", counterName, amount, err)
return "", fmt.Errorf("could not set Counter %s to unparseable amount %s: %s", counterName, amount, err)
}
log.Printf("Setting Counter %s Capacity to amount %d", counterName, amountInt)
ok, err := s.Alpha().SetCounterCapacity(counterName, amountInt)
err = s.Alpha().SetCounterCapacity(counterName, amountInt)
if err != nil {
log.Printf("Error setting Counter %s Capacity to amount %d: %s", counterName, amountInt, err)
return strconv.FormatBool(ok), err
return "", err
}
return "SUCCESS: " + strconv.FormatBool(ok) + "\n", nil
return "SUCCESS\n", nil
}

// getListCapacity returns the Capacity of the given List as a string
Expand All @@ -774,19 +780,19 @@ func getListCapacity(s *sdk.SDK, listName string) (string, error) {
return "CAPACITY: " + strconv.FormatInt(capacity, 10) + "\n", nil
}

// setListCapacity returns if the List was set to a new Capacity successfully (true) or not (false)
// setListCapacity returns if the List was set to a new Capacity successfully or not
func setListCapacity(s *sdk.SDK, listName string, amount string) (string, error) {
amountInt, err := strconv.ParseInt(amount, 10, 64)
if err != nil {
return "false", fmt.Errorf("could not set List %s to unparseable amount %s: %s", listName, amount, err)
return "", fmt.Errorf("could not set List %s to unparseable amount %s: %s", listName, amount, err)
}
log.Printf("Setting List %s Capacity to amount %d", listName, amountInt)
ok, err := s.Alpha().SetListCapacity(listName, amountInt)
err = s.Alpha().SetListCapacity(listName, amountInt)
if err != nil {
log.Printf("Error setting List %s Capacity to amount %d: %s", listName, amountInt, err)
return strconv.FormatBool(ok), err
return "", err
}
return "SUCCESS: " + strconv.FormatBool(ok) + "\n", nil
return "SUCCESS\n", nil
}

// listContains returns true if the given value is in the given List, false otherwise
Expand All @@ -796,8 +802,8 @@ func listContains(s *sdk.SDK, listName string, value string) (string, error) {
if err != nil {
log.Printf("Error getting List %s contains value %s: %s", listName, value, err)
return strconv.FormatBool(ok), err
}
return "FOUND: " + strconv.FormatBool(ok) + "\n", nil
}
return "FOUND: " + strconv.FormatBool(ok) + "\n", nil
}

// getListLength returns the length (number of values) of the given List as a string
Expand All @@ -820,31 +826,31 @@ func getListValues(s *sdk.SDK, listName string) (string, error) {
return "INVALID LIST NAME", err
}
if len(values) > 0 {
return "VALUES: " + strings.Join(values, ",") + "\n", nil
}
return "VALUES: <none>\n", err
return "VALUES: " + strings.Join(values, ",") + "\n", nil
}
return "VALUES: <none>\n", nil
}

// appendListValue returns if the given value was successfuly added to the List (true) or not (false)
// appendListValue returns if the given value was successfuly added to the List or not
func appendListValue(s *sdk.SDK, listName string, value string) (string, error) {
log.Printf("Appending Value %s to List %s", value, listName)
ok, err := s.Alpha().AppendListValue(listName, value)
err := s.Alpha().AppendListValue(listName, value)
if err != nil {
log.Printf("Error appending Value %s to List %s: %s", value, listName, err)
return strconv.FormatBool(ok), err
return "", err
}
return "SUCCESS: " + strconv.FormatBool(ok) + "\n", nil
return "SUCCESS\n", nil
}

// deleteListValue returns if the given value was successfuly deleted from the List (true) or not (false)
// deleteListValue returns if the given value was successfuly deleted from the List or not
func deleteListValue(s *sdk.SDK, listName string, value string) (string, error) {
log.Printf("Deleting Value %s from List %s", value, listName)
ok, err := s.Alpha().DeleteListValue(listName, value)
err := s.Alpha().DeleteListValue(listName, value)
if err != nil {
log.Printf("Error deleting Value %s to List %s: %s", value, listName, err)
return strconv.FormatBool(ok), err
return "", err
}
return "SUCCESS: " + strconv.FormatBool(ok) + "\n", nil
return "SUCCESS\n", nil
}

// doHealth sends the regular Health Pings
Expand Down
2 changes: 1 addition & 1 deletion install/helm/agones/templates/tests/test-runner.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ spec:
imagePullPolicy: Always
env:
- name: GAMESERVER_IMAGE
value: "us-docker.pkg.dev/agones-images/examples/simple-game-server:0.28"
value: "us-docker.pkg.dev/agones-images/examples/simple-game-server:0.30"
- name: IS_HELM_TEST
value: "true"
- name: GAMESERVERS_NAMESPACE
Expand Down
2 changes: 1 addition & 1 deletion pkg/util/webhooks/webhooks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ func TestWebHookFleetValidationHandler(t *testing.T) {
"template": {
"spec": {
"containers": [{
"image": "us-docker.pkg.dev/agones-images/examples/simple-game-server:0.28",
"image": "us-docker.pkg.dev/agones-images/examples/simple-game-server:0.30",
"name": false
}]
}
Expand Down
Loading
Loading