Upload folder using huggingface_hub
Browse files- .gitattributes +3 -0
- .gitignore +2 -0
- assets/example_case/0001.jpg +3 -0
- assets/example_case/0001.json +5586 -0
- assets/example_case/0002.jpg +3 -0
- assets/example_case/0002.json +6234 -0
- assets/framework.png +3 -0
- configs/infworld_config.yaml +73 -0
- infer_local.sh +31 -0
- infworld/__init__.py +1 -0
- infworld/clip/__init__.py +1 -0
- infworld/clip/clip.py +663 -0
- infworld/clip/tokenizers.py +82 -0
- infworld/clip/xlm_roberta.py +170 -0
- infworld/configs/__init__.py +1 -0
- infworld/configs/bucket_config.py +155 -0
- infworld/context_parallel/__init__.py +1 -0
- infworld/context_parallel/context_parallel_util.py +405 -0
- infworld/models/__init__.py +1 -0
- infworld/models/checkpoint.py +24 -0
- infworld/models/dit_model.py +1285 -0
- infworld/models/scheduler.py +306 -0
- infworld/models/t5.py +321 -0
- infworld/models/umt5.py +605 -0
- infworld/utils/__init__.py +1 -0
- infworld/utils/data_utils.py +854 -0
- infworld/utils/dataset_utils.py +665 -0
- infworld/utils/prepare_dataloader.py +133 -0
- infworld/utils/registry.py +39 -0
- infworld/vae/__init__.py +48 -0
- infworld/vae/vae.py +674 -0
- prompts/demo.yaml +10 -0
- readme.md +144 -0
- requirements.txt +89 -0
- scripts/infworld_inference.py +384 -0
- scripts/upload_to_hf.py +86 -0
- setup_project.py +140 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,6 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
assets/example_case/0001.jpg filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
assets/example_case/0002.jpg filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
assets/framework.png filter=lfs diff=lfs merge=lfs -text
|
.gitignore
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
outputs
|
| 2 |
+
checkpoints
|
assets/example_case/0001.jpg
ADDED
|
Git LFS Details
|
assets/example_case/0001.json
ADDED
|
@@ -0,0 +1,5586 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
{
|
| 3 |
+
"move": "go forward",
|
| 4 |
+
"view": "no-op"
|
| 5 |
+
},
|
| 6 |
+
{
|
| 7 |
+
"move": "go forward",
|
| 8 |
+
"view": "no-op"
|
| 9 |
+
},
|
| 10 |
+
{
|
| 11 |
+
"move": "go forward",
|
| 12 |
+
"view": "no-op"
|
| 13 |
+
},
|
| 14 |
+
{
|
| 15 |
+
"move": "go forward",
|
| 16 |
+
"view": "no-op"
|
| 17 |
+
},
|
| 18 |
+
{
|
| 19 |
+
"move": "go forward",
|
| 20 |
+
"view": "no-op"
|
| 21 |
+
},
|
| 22 |
+
{
|
| 23 |
+
"move": "go forward",
|
| 24 |
+
"view": "no-op"
|
| 25 |
+
},
|
| 26 |
+
{
|
| 27 |
+
"move": "go forward",
|
| 28 |
+
"view": "no-op"
|
| 29 |
+
},
|
| 30 |
+
{
|
| 31 |
+
"move": "go forward",
|
| 32 |
+
"view": "no-op"
|
| 33 |
+
},
|
| 34 |
+
{
|
| 35 |
+
"move": "go forward",
|
| 36 |
+
"view": "no-op"
|
| 37 |
+
},
|
| 38 |
+
{
|
| 39 |
+
"move": "go forward",
|
| 40 |
+
"view": "no-op"
|
| 41 |
+
},
|
| 42 |
+
{
|
| 43 |
+
"move": "go forward",
|
| 44 |
+
"view": "no-op"
|
| 45 |
+
},
|
| 46 |
+
{
|
| 47 |
+
"move": "go forward",
|
| 48 |
+
"view": "no-op"
|
| 49 |
+
},
|
| 50 |
+
{
|
| 51 |
+
"move": "go forward",
|
| 52 |
+
"view": "no-op"
|
| 53 |
+
},
|
| 54 |
+
{
|
| 55 |
+
"move": "go forward",
|
| 56 |
+
"view": "no-op"
|
| 57 |
+
},
|
| 58 |
+
{
|
| 59 |
+
"move": "go forward",
|
| 60 |
+
"view": "no-op"
|
| 61 |
+
},
|
| 62 |
+
{
|
| 63 |
+
"move": "go forward",
|
| 64 |
+
"view": "no-op"
|
| 65 |
+
},
|
| 66 |
+
{
|
| 67 |
+
"move": "go forward",
|
| 68 |
+
"view": "no-op"
|
| 69 |
+
},
|
| 70 |
+
{
|
| 71 |
+
"move": "go forward",
|
| 72 |
+
"view": "no-op"
|
| 73 |
+
},
|
| 74 |
+
{
|
| 75 |
+
"move": "go forward",
|
| 76 |
+
"view": "no-op"
|
| 77 |
+
},
|
| 78 |
+
{
|
| 79 |
+
"move": "go forward",
|
| 80 |
+
"view": "no-op"
|
| 81 |
+
},
|
| 82 |
+
{
|
| 83 |
+
"move": "go forward",
|
| 84 |
+
"view": "no-op"
|
| 85 |
+
},
|
| 86 |
+
{
|
| 87 |
+
"move": "go forward",
|
| 88 |
+
"view": "no-op"
|
| 89 |
+
},
|
| 90 |
+
{
|
| 91 |
+
"move": "go forward",
|
| 92 |
+
"view": "no-op"
|
| 93 |
+
},
|
| 94 |
+
{
|
| 95 |
+
"move": "go forward",
|
| 96 |
+
"view": "no-op"
|
| 97 |
+
},
|
| 98 |
+
{
|
| 99 |
+
"move": "go forward",
|
| 100 |
+
"view": "no-op"
|
| 101 |
+
},
|
| 102 |
+
{
|
| 103 |
+
"move": "go forward",
|
| 104 |
+
"view": "no-op"
|
| 105 |
+
},
|
| 106 |
+
{
|
| 107 |
+
"move": "go forward",
|
| 108 |
+
"view": "no-op"
|
| 109 |
+
},
|
| 110 |
+
{
|
| 111 |
+
"move": "go forward",
|
| 112 |
+
"view": "no-op"
|
| 113 |
+
},
|
| 114 |
+
{
|
| 115 |
+
"move": "go forward",
|
| 116 |
+
"view": "no-op"
|
| 117 |
+
},
|
| 118 |
+
{
|
| 119 |
+
"move": "go forward",
|
| 120 |
+
"view": "no-op"
|
| 121 |
+
},
|
| 122 |
+
{
|
| 123 |
+
"move": "go forward",
|
| 124 |
+
"view": "no-op"
|
| 125 |
+
},
|
| 126 |
+
{
|
| 127 |
+
"move": "go forward",
|
| 128 |
+
"view": "no-op"
|
| 129 |
+
},
|
| 130 |
+
{
|
| 131 |
+
"move": "go forward",
|
| 132 |
+
"view": "no-op"
|
| 133 |
+
},
|
| 134 |
+
{
|
| 135 |
+
"move": "go forward",
|
| 136 |
+
"view": "no-op"
|
| 137 |
+
},
|
| 138 |
+
{
|
| 139 |
+
"move": "go forward",
|
| 140 |
+
"view": "no-op"
|
| 141 |
+
},
|
| 142 |
+
{
|
| 143 |
+
"move": "go forward",
|
| 144 |
+
"view": "no-op"
|
| 145 |
+
},
|
| 146 |
+
{
|
| 147 |
+
"move": "go forward",
|
| 148 |
+
"view": "no-op"
|
| 149 |
+
},
|
| 150 |
+
{
|
| 151 |
+
"move": "go forward",
|
| 152 |
+
"view": "no-op"
|
| 153 |
+
},
|
| 154 |
+
{
|
| 155 |
+
"move": "go forward",
|
| 156 |
+
"view": "no-op"
|
| 157 |
+
},
|
| 158 |
+
{
|
| 159 |
+
"move": "go forward",
|
| 160 |
+
"view": "no-op"
|
| 161 |
+
},
|
| 162 |
+
{
|
| 163 |
+
"move": "go forward",
|
| 164 |
+
"view": "no-op"
|
| 165 |
+
},
|
| 166 |
+
{
|
| 167 |
+
"move": "go forward",
|
| 168 |
+
"view": "no-op"
|
| 169 |
+
},
|
| 170 |
+
{
|
| 171 |
+
"move": "go forward",
|
| 172 |
+
"view": "no-op"
|
| 173 |
+
},
|
| 174 |
+
{
|
| 175 |
+
"move": "go forward",
|
| 176 |
+
"view": "no-op"
|
| 177 |
+
},
|
| 178 |
+
{
|
| 179 |
+
"move": "go forward",
|
| 180 |
+
"view": "no-op"
|
| 181 |
+
},
|
| 182 |
+
{
|
| 183 |
+
"move": "go forward",
|
| 184 |
+
"view": "no-op"
|
| 185 |
+
},
|
| 186 |
+
{
|
| 187 |
+
"move": "go forward",
|
| 188 |
+
"view": "no-op"
|
| 189 |
+
},
|
| 190 |
+
{
|
| 191 |
+
"move": "go forward",
|
| 192 |
+
"view": "no-op"
|
| 193 |
+
},
|
| 194 |
+
{
|
| 195 |
+
"move": "go forward",
|
| 196 |
+
"view": "no-op"
|
| 197 |
+
},
|
| 198 |
+
{
|
| 199 |
+
"move": "go forward",
|
| 200 |
+
"view": "no-op"
|
| 201 |
+
},
|
| 202 |
+
{
|
| 203 |
+
"move": "go forward",
|
| 204 |
+
"view": "no-op"
|
| 205 |
+
},
|
| 206 |
+
{
|
| 207 |
+
"move": "go forward",
|
| 208 |
+
"view": "no-op"
|
| 209 |
+
},
|
| 210 |
+
{
|
| 211 |
+
"move": "go forward",
|
| 212 |
+
"view": "no-op"
|
| 213 |
+
},
|
| 214 |
+
{
|
| 215 |
+
"move": "go forward",
|
| 216 |
+
"view": "no-op"
|
| 217 |
+
},
|
| 218 |
+
{
|
| 219 |
+
"move": "go forward",
|
| 220 |
+
"view": "no-op"
|
| 221 |
+
},
|
| 222 |
+
{
|
| 223 |
+
"move": "go forward",
|
| 224 |
+
"view": "no-op"
|
| 225 |
+
},
|
| 226 |
+
{
|
| 227 |
+
"move": "go forward",
|
| 228 |
+
"view": "no-op"
|
| 229 |
+
},
|
| 230 |
+
{
|
| 231 |
+
"move": "go forward",
|
| 232 |
+
"view": "no-op"
|
| 233 |
+
},
|
| 234 |
+
{
|
| 235 |
+
"move": "go forward",
|
| 236 |
+
"view": "no-op"
|
| 237 |
+
},
|
| 238 |
+
{
|
| 239 |
+
"move": "go forward",
|
| 240 |
+
"view": "no-op"
|
| 241 |
+
},
|
| 242 |
+
{
|
| 243 |
+
"move": "go forward",
|
| 244 |
+
"view": "no-op"
|
| 245 |
+
},
|
| 246 |
+
{
|
| 247 |
+
"move": "go forward",
|
| 248 |
+
"view": "no-op"
|
| 249 |
+
},
|
| 250 |
+
{
|
| 251 |
+
"move": "go forward",
|
| 252 |
+
"view": "no-op"
|
| 253 |
+
},
|
| 254 |
+
{
|
| 255 |
+
"move": "go forward",
|
| 256 |
+
"view": "no-op"
|
| 257 |
+
},
|
| 258 |
+
{
|
| 259 |
+
"move": "go forward",
|
| 260 |
+
"view": "no-op"
|
| 261 |
+
},
|
| 262 |
+
{
|
| 263 |
+
"move": "go forward",
|
| 264 |
+
"view": "no-op"
|
| 265 |
+
},
|
| 266 |
+
{
|
| 267 |
+
"move": "go forward",
|
| 268 |
+
"view": "no-op"
|
| 269 |
+
},
|
| 270 |
+
{
|
| 271 |
+
"move": "go forward",
|
| 272 |
+
"view": "no-op"
|
| 273 |
+
},
|
| 274 |
+
{
|
| 275 |
+
"move": "go forward",
|
| 276 |
+
"view": "no-op"
|
| 277 |
+
},
|
| 278 |
+
{
|
| 279 |
+
"move": "go forward",
|
| 280 |
+
"view": "no-op"
|
| 281 |
+
},
|
| 282 |
+
{
|
| 283 |
+
"move": "go forward",
|
| 284 |
+
"view": "no-op"
|
| 285 |
+
},
|
| 286 |
+
{
|
| 287 |
+
"move": "go forward",
|
| 288 |
+
"view": "no-op"
|
| 289 |
+
},
|
| 290 |
+
{
|
| 291 |
+
"move": "go forward",
|
| 292 |
+
"view": "no-op"
|
| 293 |
+
},
|
| 294 |
+
{
|
| 295 |
+
"move": "go forward",
|
| 296 |
+
"view": "no-op"
|
| 297 |
+
},
|
| 298 |
+
{
|
| 299 |
+
"move": "go forward",
|
| 300 |
+
"view": "no-op"
|
| 301 |
+
},
|
| 302 |
+
{
|
| 303 |
+
"move": "go forward",
|
| 304 |
+
"view": "no-op"
|
| 305 |
+
},
|
| 306 |
+
{
|
| 307 |
+
"move": "go forward",
|
| 308 |
+
"view": "no-op"
|
| 309 |
+
},
|
| 310 |
+
{
|
| 311 |
+
"move": "go forward",
|
| 312 |
+
"view": "no-op"
|
| 313 |
+
},
|
| 314 |
+
{
|
| 315 |
+
"move": "go forward",
|
| 316 |
+
"view": "no-op"
|
| 317 |
+
},
|
| 318 |
+
{
|
| 319 |
+
"move": "go forward",
|
| 320 |
+
"view": "no-op"
|
| 321 |
+
},
|
| 322 |
+
{
|
| 323 |
+
"move": "go forward",
|
| 324 |
+
"view": "no-op"
|
| 325 |
+
},
|
| 326 |
+
{
|
| 327 |
+
"move": "no-op",
|
| 328 |
+
"view": "turn right"
|
| 329 |
+
},
|
| 330 |
+
{
|
| 331 |
+
"move": "no-op",
|
| 332 |
+
"view": "turn right"
|
| 333 |
+
},
|
| 334 |
+
{
|
| 335 |
+
"move": "no-op",
|
| 336 |
+
"view": "turn right"
|
| 337 |
+
},
|
| 338 |
+
{
|
| 339 |
+
"move": "no-op",
|
| 340 |
+
"view": "turn right"
|
| 341 |
+
},
|
| 342 |
+
{
|
| 343 |
+
"move": "no-op",
|
| 344 |
+
"view": "turn right"
|
| 345 |
+
},
|
| 346 |
+
{
|
| 347 |
+
"move": "no-op",
|
| 348 |
+
"view": "turn right"
|
| 349 |
+
},
|
| 350 |
+
{
|
| 351 |
+
"move": "no-op",
|
| 352 |
+
"view": "turn right"
|
| 353 |
+
},
|
| 354 |
+
{
|
| 355 |
+
"move": "no-op",
|
| 356 |
+
"view": "turn right"
|
| 357 |
+
},
|
| 358 |
+
{
|
| 359 |
+
"move": "no-op",
|
| 360 |
+
"view": "turn right"
|
| 361 |
+
},
|
| 362 |
+
{
|
| 363 |
+
"move": "no-op",
|
| 364 |
+
"view": "turn right"
|
| 365 |
+
},
|
| 366 |
+
{
|
| 367 |
+
"move": "no-op",
|
| 368 |
+
"view": "turn right"
|
| 369 |
+
},
|
| 370 |
+
{
|
| 371 |
+
"move": "no-op",
|
| 372 |
+
"view": "turn right"
|
| 373 |
+
},
|
| 374 |
+
{
|
| 375 |
+
"move": "no-op",
|
| 376 |
+
"view": "turn right"
|
| 377 |
+
},
|
| 378 |
+
{
|
| 379 |
+
"move": "no-op",
|
| 380 |
+
"view": "turn right"
|
| 381 |
+
},
|
| 382 |
+
{
|
| 383 |
+
"move": "no-op",
|
| 384 |
+
"view": "turn right"
|
| 385 |
+
},
|
| 386 |
+
{
|
| 387 |
+
"move": "no-op",
|
| 388 |
+
"view": "turn right"
|
| 389 |
+
},
|
| 390 |
+
{
|
| 391 |
+
"move": "no-op",
|
| 392 |
+
"view": "turn right"
|
| 393 |
+
},
|
| 394 |
+
{
|
| 395 |
+
"move": "no-op",
|
| 396 |
+
"view": "turn right"
|
| 397 |
+
},
|
| 398 |
+
{
|
| 399 |
+
"move": "no-op",
|
| 400 |
+
"view": "turn right"
|
| 401 |
+
},
|
| 402 |
+
{
|
| 403 |
+
"move": "no-op",
|
| 404 |
+
"view": "turn right"
|
| 405 |
+
},
|
| 406 |
+
{
|
| 407 |
+
"move": "no-op",
|
| 408 |
+
"view": "turn right"
|
| 409 |
+
},
|
| 410 |
+
{
|
| 411 |
+
"move": "no-op",
|
| 412 |
+
"view": "turn right"
|
| 413 |
+
},
|
| 414 |
+
{
|
| 415 |
+
"move": "no-op",
|
| 416 |
+
"view": "turn right"
|
| 417 |
+
},
|
| 418 |
+
{
|
| 419 |
+
"move": "no-op",
|
| 420 |
+
"view": "turn right"
|
| 421 |
+
},
|
| 422 |
+
{
|
| 423 |
+
"move": "no-op",
|
| 424 |
+
"view": "turn right"
|
| 425 |
+
},
|
| 426 |
+
{
|
| 427 |
+
"move": "no-op",
|
| 428 |
+
"view": "turn right"
|
| 429 |
+
},
|
| 430 |
+
{
|
| 431 |
+
"move": "no-op",
|
| 432 |
+
"view": "turn right"
|
| 433 |
+
},
|
| 434 |
+
{
|
| 435 |
+
"move": "no-op",
|
| 436 |
+
"view": "turn right"
|
| 437 |
+
},
|
| 438 |
+
{
|
| 439 |
+
"move": "no-op",
|
| 440 |
+
"view": "turn right"
|
| 441 |
+
},
|
| 442 |
+
{
|
| 443 |
+
"move": "no-op",
|
| 444 |
+
"view": "turn right"
|
| 445 |
+
},
|
| 446 |
+
{
|
| 447 |
+
"move": "no-op",
|
| 448 |
+
"view": "turn right"
|
| 449 |
+
},
|
| 450 |
+
{
|
| 451 |
+
"move": "no-op",
|
| 452 |
+
"view": "turn right"
|
| 453 |
+
},
|
| 454 |
+
{
|
| 455 |
+
"move": "no-op",
|
| 456 |
+
"view": "turn right"
|
| 457 |
+
},
|
| 458 |
+
{
|
| 459 |
+
"move": "no-op",
|
| 460 |
+
"view": "turn right"
|
| 461 |
+
},
|
| 462 |
+
{
|
| 463 |
+
"move": "no-op",
|
| 464 |
+
"view": "turn right"
|
| 465 |
+
},
|
| 466 |
+
{
|
| 467 |
+
"move": "no-op",
|
| 468 |
+
"view": "turn right"
|
| 469 |
+
},
|
| 470 |
+
{
|
| 471 |
+
"move": "no-op",
|
| 472 |
+
"view": "turn right"
|
| 473 |
+
},
|
| 474 |
+
{
|
| 475 |
+
"move": "no-op",
|
| 476 |
+
"view": "turn right"
|
| 477 |
+
},
|
| 478 |
+
{
|
| 479 |
+
"move": "no-op",
|
| 480 |
+
"view": "turn right"
|
| 481 |
+
},
|
| 482 |
+
{
|
| 483 |
+
"move": "no-op",
|
| 484 |
+
"view": "turn right"
|
| 485 |
+
},
|
| 486 |
+
{
|
| 487 |
+
"move": "no-op",
|
| 488 |
+
"view": "turn right"
|
| 489 |
+
},
|
| 490 |
+
{
|
| 491 |
+
"move": "no-op",
|
| 492 |
+
"view": "turn right"
|
| 493 |
+
},
|
| 494 |
+
{
|
| 495 |
+
"move": "no-op",
|
| 496 |
+
"view": "turn right"
|
| 497 |
+
},
|
| 498 |
+
{
|
| 499 |
+
"move": "no-op",
|
| 500 |
+
"view": "turn right"
|
| 501 |
+
},
|
| 502 |
+
{
|
| 503 |
+
"move": "no-op",
|
| 504 |
+
"view": "turn right"
|
| 505 |
+
},
|
| 506 |
+
{
|
| 507 |
+
"move": "no-op",
|
| 508 |
+
"view": "turn right"
|
| 509 |
+
},
|
| 510 |
+
{
|
| 511 |
+
"move": "no-op",
|
| 512 |
+
"view": "turn right"
|
| 513 |
+
},
|
| 514 |
+
{
|
| 515 |
+
"move": "no-op",
|
| 516 |
+
"view": "turn right"
|
| 517 |
+
},
|
| 518 |
+
{
|
| 519 |
+
"move": "no-op",
|
| 520 |
+
"view": "turn right"
|
| 521 |
+
},
|
| 522 |
+
{
|
| 523 |
+
"move": "no-op",
|
| 524 |
+
"view": "turn right"
|
| 525 |
+
},
|
| 526 |
+
{
|
| 527 |
+
"move": "no-op",
|
| 528 |
+
"view": "turn right"
|
| 529 |
+
},
|
| 530 |
+
{
|
| 531 |
+
"move": "no-op",
|
| 532 |
+
"view": "turn right"
|
| 533 |
+
},
|
| 534 |
+
{
|
| 535 |
+
"move": "no-op",
|
| 536 |
+
"view": "turn right"
|
| 537 |
+
},
|
| 538 |
+
{
|
| 539 |
+
"move": "no-op",
|
| 540 |
+
"view": "turn right"
|
| 541 |
+
},
|
| 542 |
+
{
|
| 543 |
+
"move": "no-op",
|
| 544 |
+
"view": "turn right"
|
| 545 |
+
},
|
| 546 |
+
{
|
| 547 |
+
"move": "no-op",
|
| 548 |
+
"view": "turn right"
|
| 549 |
+
},
|
| 550 |
+
{
|
| 551 |
+
"move": "no-op",
|
| 552 |
+
"view": "turn right"
|
| 553 |
+
},
|
| 554 |
+
{
|
| 555 |
+
"move": "no-op",
|
| 556 |
+
"view": "turn right"
|
| 557 |
+
},
|
| 558 |
+
{
|
| 559 |
+
"move": "no-op",
|
| 560 |
+
"view": "turn right"
|
| 561 |
+
},
|
| 562 |
+
{
|
| 563 |
+
"move": "no-op",
|
| 564 |
+
"view": "turn right"
|
| 565 |
+
},
|
| 566 |
+
{
|
| 567 |
+
"move": "no-op",
|
| 568 |
+
"view": "turn right"
|
| 569 |
+
},
|
| 570 |
+
{
|
| 571 |
+
"move": "no-op",
|
| 572 |
+
"view": "turn right"
|
| 573 |
+
},
|
| 574 |
+
{
|
| 575 |
+
"move": "no-op",
|
| 576 |
+
"view": "turn right"
|
| 577 |
+
},
|
| 578 |
+
{
|
| 579 |
+
"move": "no-op",
|
| 580 |
+
"view": "turn right"
|
| 581 |
+
},
|
| 582 |
+
{
|
| 583 |
+
"move": "no-op",
|
| 584 |
+
"view": "turn right"
|
| 585 |
+
},
|
| 586 |
+
{
|
| 587 |
+
"move": "no-op",
|
| 588 |
+
"view": "turn right"
|
| 589 |
+
},
|
| 590 |
+
{
|
| 591 |
+
"move": "no-op",
|
| 592 |
+
"view": "turn right"
|
| 593 |
+
},
|
| 594 |
+
{
|
| 595 |
+
"move": "no-op",
|
| 596 |
+
"view": "turn right"
|
| 597 |
+
},
|
| 598 |
+
{
|
| 599 |
+
"move": "no-op",
|
| 600 |
+
"view": "turn right"
|
| 601 |
+
},
|
| 602 |
+
{
|
| 603 |
+
"move": "no-op",
|
| 604 |
+
"view": "turn right"
|
| 605 |
+
},
|
| 606 |
+
{
|
| 607 |
+
"move": "no-op",
|
| 608 |
+
"view": "turn right"
|
| 609 |
+
},
|
| 610 |
+
{
|
| 611 |
+
"move": "no-op",
|
| 612 |
+
"view": "turn right"
|
| 613 |
+
},
|
| 614 |
+
{
|
| 615 |
+
"move": "no-op",
|
| 616 |
+
"view": "turn right"
|
| 617 |
+
},
|
| 618 |
+
{
|
| 619 |
+
"move": "no-op",
|
| 620 |
+
"view": "turn right"
|
| 621 |
+
},
|
| 622 |
+
{
|
| 623 |
+
"move": "no-op",
|
| 624 |
+
"view": "turn right"
|
| 625 |
+
},
|
| 626 |
+
{
|
| 627 |
+
"move": "no-op",
|
| 628 |
+
"view": "turn right"
|
| 629 |
+
},
|
| 630 |
+
{
|
| 631 |
+
"move": "no-op",
|
| 632 |
+
"view": "turn right"
|
| 633 |
+
},
|
| 634 |
+
{
|
| 635 |
+
"move": "no-op",
|
| 636 |
+
"view": "turn right"
|
| 637 |
+
},
|
| 638 |
+
{
|
| 639 |
+
"move": "no-op",
|
| 640 |
+
"view": "turn right"
|
| 641 |
+
},
|
| 642 |
+
{
|
| 643 |
+
"move": "no-op",
|
| 644 |
+
"view": "turn right"
|
| 645 |
+
},
|
| 646 |
+
{
|
| 647 |
+
"move": "no-op",
|
| 648 |
+
"view": "turn right"
|
| 649 |
+
},
|
| 650 |
+
{
|
| 651 |
+
"move": "go forward",
|
| 652 |
+
"view": "no-op"
|
| 653 |
+
},
|
| 654 |
+
{
|
| 655 |
+
"move": "go forward",
|
| 656 |
+
"view": "no-op"
|
| 657 |
+
},
|
| 658 |
+
{
|
| 659 |
+
"move": "go forward",
|
| 660 |
+
"view": "no-op"
|
| 661 |
+
},
|
| 662 |
+
{
|
| 663 |
+
"move": "go forward",
|
| 664 |
+
"view": "no-op"
|
| 665 |
+
},
|
| 666 |
+
{
|
| 667 |
+
"move": "go forward",
|
| 668 |
+
"view": "no-op"
|
| 669 |
+
},
|
| 670 |
+
{
|
| 671 |
+
"move": "go forward",
|
| 672 |
+
"view": "no-op"
|
| 673 |
+
},
|
| 674 |
+
{
|
| 675 |
+
"move": "go forward",
|
| 676 |
+
"view": "no-op"
|
| 677 |
+
},
|
| 678 |
+
{
|
| 679 |
+
"move": "go forward",
|
| 680 |
+
"view": "no-op"
|
| 681 |
+
},
|
| 682 |
+
{
|
| 683 |
+
"move": "go forward",
|
| 684 |
+
"view": "no-op"
|
| 685 |
+
},
|
| 686 |
+
{
|
| 687 |
+
"move": "go forward",
|
| 688 |
+
"view": "no-op"
|
| 689 |
+
},
|
| 690 |
+
{
|
| 691 |
+
"move": "go forward",
|
| 692 |
+
"view": "no-op"
|
| 693 |
+
},
|
| 694 |
+
{
|
| 695 |
+
"move": "go forward",
|
| 696 |
+
"view": "no-op"
|
| 697 |
+
},
|
| 698 |
+
{
|
| 699 |
+
"move": "go forward",
|
| 700 |
+
"view": "no-op"
|
| 701 |
+
},
|
| 702 |
+
{
|
| 703 |
+
"move": "go forward",
|
| 704 |
+
"view": "no-op"
|
| 705 |
+
},
|
| 706 |
+
{
|
| 707 |
+
"move": "go forward",
|
| 708 |
+
"view": "no-op"
|
| 709 |
+
},
|
| 710 |
+
{
|
| 711 |
+
"move": "go forward",
|
| 712 |
+
"view": "no-op"
|
| 713 |
+
},
|
| 714 |
+
{
|
| 715 |
+
"move": "go forward",
|
| 716 |
+
"view": "no-op"
|
| 717 |
+
},
|
| 718 |
+
{
|
| 719 |
+
"move": "go forward",
|
| 720 |
+
"view": "no-op"
|
| 721 |
+
},
|
| 722 |
+
{
|
| 723 |
+
"move": "go forward",
|
| 724 |
+
"view": "no-op"
|
| 725 |
+
},
|
| 726 |
+
{
|
| 727 |
+
"move": "go forward",
|
| 728 |
+
"view": "no-op"
|
| 729 |
+
},
|
| 730 |
+
{
|
| 731 |
+
"move": "go forward",
|
| 732 |
+
"view": "no-op"
|
| 733 |
+
},
|
| 734 |
+
{
|
| 735 |
+
"move": "go forward",
|
| 736 |
+
"view": "no-op"
|
| 737 |
+
},
|
| 738 |
+
{
|
| 739 |
+
"move": "go forward",
|
| 740 |
+
"view": "no-op"
|
| 741 |
+
},
|
| 742 |
+
{
|
| 743 |
+
"move": "go forward",
|
| 744 |
+
"view": "no-op"
|
| 745 |
+
},
|
| 746 |
+
{
|
| 747 |
+
"move": "go forward",
|
| 748 |
+
"view": "no-op"
|
| 749 |
+
},
|
| 750 |
+
{
|
| 751 |
+
"move": "go forward",
|
| 752 |
+
"view": "no-op"
|
| 753 |
+
},
|
| 754 |
+
{
|
| 755 |
+
"move": "go forward",
|
| 756 |
+
"view": "no-op"
|
| 757 |
+
},
|
| 758 |
+
{
|
| 759 |
+
"move": "go forward",
|
| 760 |
+
"view": "no-op"
|
| 761 |
+
},
|
| 762 |
+
{
|
| 763 |
+
"move": "go forward",
|
| 764 |
+
"view": "no-op"
|
| 765 |
+
},
|
| 766 |
+
{
|
| 767 |
+
"move": "go forward",
|
| 768 |
+
"view": "no-op"
|
| 769 |
+
},
|
| 770 |
+
{
|
| 771 |
+
"move": "go forward",
|
| 772 |
+
"view": "no-op"
|
| 773 |
+
},
|
| 774 |
+
{
|
| 775 |
+
"move": "go forward",
|
| 776 |
+
"view": "no-op"
|
| 777 |
+
},
|
| 778 |
+
{
|
| 779 |
+
"move": "go forward",
|
| 780 |
+
"view": "no-op"
|
| 781 |
+
},
|
| 782 |
+
{
|
| 783 |
+
"move": "go forward",
|
| 784 |
+
"view": "no-op"
|
| 785 |
+
},
|
| 786 |
+
{
|
| 787 |
+
"move": "go forward",
|
| 788 |
+
"view": "no-op"
|
| 789 |
+
},
|
| 790 |
+
{
|
| 791 |
+
"move": "go forward",
|
| 792 |
+
"view": "no-op"
|
| 793 |
+
},
|
| 794 |
+
{
|
| 795 |
+
"move": "go forward",
|
| 796 |
+
"view": "no-op"
|
| 797 |
+
},
|
| 798 |
+
{
|
| 799 |
+
"move": "go forward",
|
| 800 |
+
"view": "no-op"
|
| 801 |
+
},
|
| 802 |
+
{
|
| 803 |
+
"move": "go forward",
|
| 804 |
+
"view": "no-op"
|
| 805 |
+
},
|
| 806 |
+
{
|
| 807 |
+
"move": "go forward",
|
| 808 |
+
"view": "no-op"
|
| 809 |
+
},
|
| 810 |
+
{
|
| 811 |
+
"move": "go forward",
|
| 812 |
+
"view": "no-op"
|
| 813 |
+
},
|
| 814 |
+
{
|
| 815 |
+
"move": "go forward",
|
| 816 |
+
"view": "no-op"
|
| 817 |
+
},
|
| 818 |
+
{
|
| 819 |
+
"move": "go forward",
|
| 820 |
+
"view": "no-op"
|
| 821 |
+
},
|
| 822 |
+
{
|
| 823 |
+
"move": "go forward",
|
| 824 |
+
"view": "no-op"
|
| 825 |
+
},
|
| 826 |
+
{
|
| 827 |
+
"move": "go forward",
|
| 828 |
+
"view": "no-op"
|
| 829 |
+
},
|
| 830 |
+
{
|
| 831 |
+
"move": "go forward",
|
| 832 |
+
"view": "no-op"
|
| 833 |
+
},
|
| 834 |
+
{
|
| 835 |
+
"move": "go forward",
|
| 836 |
+
"view": "no-op"
|
| 837 |
+
},
|
| 838 |
+
{
|
| 839 |
+
"move": "go forward",
|
| 840 |
+
"view": "no-op"
|
| 841 |
+
},
|
| 842 |
+
{
|
| 843 |
+
"move": "go forward",
|
| 844 |
+
"view": "no-op"
|
| 845 |
+
},
|
| 846 |
+
{
|
| 847 |
+
"move": "go forward",
|
| 848 |
+
"view": "no-op"
|
| 849 |
+
},
|
| 850 |
+
{
|
| 851 |
+
"move": "go forward",
|
| 852 |
+
"view": "no-op"
|
| 853 |
+
},
|
| 854 |
+
{
|
| 855 |
+
"move": "go forward",
|
| 856 |
+
"view": "no-op"
|
| 857 |
+
},
|
| 858 |
+
{
|
| 859 |
+
"move": "go forward",
|
| 860 |
+
"view": "no-op"
|
| 861 |
+
},
|
| 862 |
+
{
|
| 863 |
+
"move": "go forward",
|
| 864 |
+
"view": "no-op"
|
| 865 |
+
},
|
| 866 |
+
{
|
| 867 |
+
"move": "go forward",
|
| 868 |
+
"view": "no-op"
|
| 869 |
+
},
|
| 870 |
+
{
|
| 871 |
+
"move": "go forward",
|
| 872 |
+
"view": "no-op"
|
| 873 |
+
},
|
| 874 |
+
{
|
| 875 |
+
"move": "go forward",
|
| 876 |
+
"view": "no-op"
|
| 877 |
+
},
|
| 878 |
+
{
|
| 879 |
+
"move": "go forward",
|
| 880 |
+
"view": "no-op"
|
| 881 |
+
},
|
| 882 |
+
{
|
| 883 |
+
"move": "go forward",
|
| 884 |
+
"view": "no-op"
|
| 885 |
+
},
|
| 886 |
+
{
|
| 887 |
+
"move": "go forward",
|
| 888 |
+
"view": "no-op"
|
| 889 |
+
},
|
| 890 |
+
{
|
| 891 |
+
"move": "go forward",
|
| 892 |
+
"view": "no-op"
|
| 893 |
+
},
|
| 894 |
+
{
|
| 895 |
+
"move": "go forward",
|
| 896 |
+
"view": "no-op"
|
| 897 |
+
},
|
| 898 |
+
{
|
| 899 |
+
"move": "go forward",
|
| 900 |
+
"view": "no-op"
|
| 901 |
+
},
|
| 902 |
+
{
|
| 903 |
+
"move": "go forward",
|
| 904 |
+
"view": "no-op"
|
| 905 |
+
},
|
| 906 |
+
{
|
| 907 |
+
"move": "go forward",
|
| 908 |
+
"view": "no-op"
|
| 909 |
+
},
|
| 910 |
+
{
|
| 911 |
+
"move": "go forward",
|
| 912 |
+
"view": "no-op"
|
| 913 |
+
},
|
| 914 |
+
{
|
| 915 |
+
"move": "go forward",
|
| 916 |
+
"view": "no-op"
|
| 917 |
+
},
|
| 918 |
+
{
|
| 919 |
+
"move": "go forward",
|
| 920 |
+
"view": "no-op"
|
| 921 |
+
},
|
| 922 |
+
{
|
| 923 |
+
"move": "go forward",
|
| 924 |
+
"view": "no-op"
|
| 925 |
+
},
|
| 926 |
+
{
|
| 927 |
+
"move": "go forward",
|
| 928 |
+
"view": "no-op"
|
| 929 |
+
},
|
| 930 |
+
{
|
| 931 |
+
"move": "go forward",
|
| 932 |
+
"view": "no-op"
|
| 933 |
+
},
|
| 934 |
+
{
|
| 935 |
+
"move": "go forward",
|
| 936 |
+
"view": "no-op"
|
| 937 |
+
},
|
| 938 |
+
{
|
| 939 |
+
"move": "go forward",
|
| 940 |
+
"view": "no-op"
|
| 941 |
+
},
|
| 942 |
+
{
|
| 943 |
+
"move": "go forward",
|
| 944 |
+
"view": "no-op"
|
| 945 |
+
},
|
| 946 |
+
{
|
| 947 |
+
"move": "go forward",
|
| 948 |
+
"view": "no-op"
|
| 949 |
+
},
|
| 950 |
+
{
|
| 951 |
+
"move": "go forward",
|
| 952 |
+
"view": "no-op"
|
| 953 |
+
},
|
| 954 |
+
{
|
| 955 |
+
"move": "go forward",
|
| 956 |
+
"view": "no-op"
|
| 957 |
+
},
|
| 958 |
+
{
|
| 959 |
+
"move": "go forward",
|
| 960 |
+
"view": "no-op"
|
| 961 |
+
},
|
| 962 |
+
{
|
| 963 |
+
"move": "go forward",
|
| 964 |
+
"view": "no-op"
|
| 965 |
+
},
|
| 966 |
+
{
|
| 967 |
+
"move": "go forward",
|
| 968 |
+
"view": "no-op"
|
| 969 |
+
},
|
| 970 |
+
{
|
| 971 |
+
"move": "go forward",
|
| 972 |
+
"view": "no-op"
|
| 973 |
+
},
|
| 974 |
+
{
|
| 975 |
+
"move": "no-op",
|
| 976 |
+
"view": "turn right"
|
| 977 |
+
},
|
| 978 |
+
{
|
| 979 |
+
"move": "no-op",
|
| 980 |
+
"view": "turn right"
|
| 981 |
+
},
|
| 982 |
+
{
|
| 983 |
+
"move": "no-op",
|
| 984 |
+
"view": "turn right"
|
| 985 |
+
},
|
| 986 |
+
{
|
| 987 |
+
"move": "no-op",
|
| 988 |
+
"view": "turn right"
|
| 989 |
+
},
|
| 990 |
+
{
|
| 991 |
+
"move": "no-op",
|
| 992 |
+
"view": "turn right"
|
| 993 |
+
},
|
| 994 |
+
{
|
| 995 |
+
"move": "no-op",
|
| 996 |
+
"view": "turn right"
|
| 997 |
+
},
|
| 998 |
+
{
|
| 999 |
+
"move": "no-op",
|
| 1000 |
+
"view": "turn right"
|
| 1001 |
+
},
|
| 1002 |
+
{
|
| 1003 |
+
"move": "no-op",
|
| 1004 |
+
"view": "turn right"
|
| 1005 |
+
},
|
| 1006 |
+
{
|
| 1007 |
+
"move": "no-op",
|
| 1008 |
+
"view": "turn right"
|
| 1009 |
+
},
|
| 1010 |
+
{
|
| 1011 |
+
"move": "no-op",
|
| 1012 |
+
"view": "turn right"
|
| 1013 |
+
},
|
| 1014 |
+
{
|
| 1015 |
+
"move": "no-op",
|
| 1016 |
+
"view": "turn right"
|
| 1017 |
+
},
|
| 1018 |
+
{
|
| 1019 |
+
"move": "no-op",
|
| 1020 |
+
"view": "turn right"
|
| 1021 |
+
},
|
| 1022 |
+
{
|
| 1023 |
+
"move": "no-op",
|
| 1024 |
+
"view": "turn right"
|
| 1025 |
+
},
|
| 1026 |
+
{
|
| 1027 |
+
"move": "no-op",
|
| 1028 |
+
"view": "turn right"
|
| 1029 |
+
},
|
| 1030 |
+
{
|
| 1031 |
+
"move": "no-op",
|
| 1032 |
+
"view": "turn right"
|
| 1033 |
+
},
|
| 1034 |
+
{
|
| 1035 |
+
"move": "no-op",
|
| 1036 |
+
"view": "turn right"
|
| 1037 |
+
},
|
| 1038 |
+
{
|
| 1039 |
+
"move": "no-op",
|
| 1040 |
+
"view": "turn right"
|
| 1041 |
+
},
|
| 1042 |
+
{
|
| 1043 |
+
"move": "no-op",
|
| 1044 |
+
"view": "turn right"
|
| 1045 |
+
},
|
| 1046 |
+
{
|
| 1047 |
+
"move": "no-op",
|
| 1048 |
+
"view": "turn right"
|
| 1049 |
+
},
|
| 1050 |
+
{
|
| 1051 |
+
"move": "no-op",
|
| 1052 |
+
"view": "turn right"
|
| 1053 |
+
},
|
| 1054 |
+
{
|
| 1055 |
+
"move": "no-op",
|
| 1056 |
+
"view": "turn right"
|
| 1057 |
+
},
|
| 1058 |
+
{
|
| 1059 |
+
"move": "no-op",
|
| 1060 |
+
"view": "turn right"
|
| 1061 |
+
},
|
| 1062 |
+
{
|
| 1063 |
+
"move": "no-op",
|
| 1064 |
+
"view": "turn right"
|
| 1065 |
+
},
|
| 1066 |
+
{
|
| 1067 |
+
"move": "no-op",
|
| 1068 |
+
"view": "turn right"
|
| 1069 |
+
},
|
| 1070 |
+
{
|
| 1071 |
+
"move": "no-op",
|
| 1072 |
+
"view": "turn right"
|
| 1073 |
+
},
|
| 1074 |
+
{
|
| 1075 |
+
"move": "no-op",
|
| 1076 |
+
"view": "turn right"
|
| 1077 |
+
},
|
| 1078 |
+
{
|
| 1079 |
+
"move": "no-op",
|
| 1080 |
+
"view": "turn right"
|
| 1081 |
+
},
|
| 1082 |
+
{
|
| 1083 |
+
"move": "no-op",
|
| 1084 |
+
"view": "turn right"
|
| 1085 |
+
},
|
| 1086 |
+
{
|
| 1087 |
+
"move": "no-op",
|
| 1088 |
+
"view": "turn right"
|
| 1089 |
+
},
|
| 1090 |
+
{
|
| 1091 |
+
"move": "no-op",
|
| 1092 |
+
"view": "turn right"
|
| 1093 |
+
},
|
| 1094 |
+
{
|
| 1095 |
+
"move": "no-op",
|
| 1096 |
+
"view": "turn right"
|
| 1097 |
+
},
|
| 1098 |
+
{
|
| 1099 |
+
"move": "no-op",
|
| 1100 |
+
"view": "turn right"
|
| 1101 |
+
},
|
| 1102 |
+
{
|
| 1103 |
+
"move": "no-op",
|
| 1104 |
+
"view": "turn right"
|
| 1105 |
+
},
|
| 1106 |
+
{
|
| 1107 |
+
"move": "no-op",
|
| 1108 |
+
"view": "turn right"
|
| 1109 |
+
},
|
| 1110 |
+
{
|
| 1111 |
+
"move": "no-op",
|
| 1112 |
+
"view": "turn right"
|
| 1113 |
+
},
|
| 1114 |
+
{
|
| 1115 |
+
"move": "no-op",
|
| 1116 |
+
"view": "turn right"
|
| 1117 |
+
},
|
| 1118 |
+
{
|
| 1119 |
+
"move": "no-op",
|
| 1120 |
+
"view": "turn right"
|
| 1121 |
+
},
|
| 1122 |
+
{
|
| 1123 |
+
"move": "no-op",
|
| 1124 |
+
"view": "turn right"
|
| 1125 |
+
},
|
| 1126 |
+
{
|
| 1127 |
+
"move": "no-op",
|
| 1128 |
+
"view": "turn right"
|
| 1129 |
+
},
|
| 1130 |
+
{
|
| 1131 |
+
"move": "no-op",
|
| 1132 |
+
"view": "turn right"
|
| 1133 |
+
},
|
| 1134 |
+
{
|
| 1135 |
+
"move": "no-op",
|
| 1136 |
+
"view": "turn right"
|
| 1137 |
+
},
|
| 1138 |
+
{
|
| 1139 |
+
"move": "no-op",
|
| 1140 |
+
"view": "turn right"
|
| 1141 |
+
},
|
| 1142 |
+
{
|
| 1143 |
+
"move": "no-op",
|
| 1144 |
+
"view": "turn right"
|
| 1145 |
+
},
|
| 1146 |
+
{
|
| 1147 |
+
"move": "no-op",
|
| 1148 |
+
"view": "turn right"
|
| 1149 |
+
},
|
| 1150 |
+
{
|
| 1151 |
+
"move": "no-op",
|
| 1152 |
+
"view": "turn right"
|
| 1153 |
+
},
|
| 1154 |
+
{
|
| 1155 |
+
"move": "no-op",
|
| 1156 |
+
"view": "turn right"
|
| 1157 |
+
},
|
| 1158 |
+
{
|
| 1159 |
+
"move": "no-op",
|
| 1160 |
+
"view": "turn right"
|
| 1161 |
+
},
|
| 1162 |
+
{
|
| 1163 |
+
"move": "no-op",
|
| 1164 |
+
"view": "turn right"
|
| 1165 |
+
},
|
| 1166 |
+
{
|
| 1167 |
+
"move": "no-op",
|
| 1168 |
+
"view": "turn right"
|
| 1169 |
+
},
|
| 1170 |
+
{
|
| 1171 |
+
"move": "no-op",
|
| 1172 |
+
"view": "turn right"
|
| 1173 |
+
},
|
| 1174 |
+
{
|
| 1175 |
+
"move": "no-op",
|
| 1176 |
+
"view": "turn right"
|
| 1177 |
+
},
|
| 1178 |
+
{
|
| 1179 |
+
"move": "no-op",
|
| 1180 |
+
"view": "turn right"
|
| 1181 |
+
},
|
| 1182 |
+
{
|
| 1183 |
+
"move": "no-op",
|
| 1184 |
+
"view": "turn right"
|
| 1185 |
+
},
|
| 1186 |
+
{
|
| 1187 |
+
"move": "no-op",
|
| 1188 |
+
"view": "turn right"
|
| 1189 |
+
},
|
| 1190 |
+
{
|
| 1191 |
+
"move": "no-op",
|
| 1192 |
+
"view": "turn right"
|
| 1193 |
+
},
|
| 1194 |
+
{
|
| 1195 |
+
"move": "no-op",
|
| 1196 |
+
"view": "turn right"
|
| 1197 |
+
},
|
| 1198 |
+
{
|
| 1199 |
+
"move": "no-op",
|
| 1200 |
+
"view": "turn right"
|
| 1201 |
+
},
|
| 1202 |
+
{
|
| 1203 |
+
"move": "no-op",
|
| 1204 |
+
"view": "turn right"
|
| 1205 |
+
},
|
| 1206 |
+
{
|
| 1207 |
+
"move": "no-op",
|
| 1208 |
+
"view": "turn right"
|
| 1209 |
+
},
|
| 1210 |
+
{
|
| 1211 |
+
"move": "no-op",
|
| 1212 |
+
"view": "turn right"
|
| 1213 |
+
},
|
| 1214 |
+
{
|
| 1215 |
+
"move": "no-op",
|
| 1216 |
+
"view": "turn right"
|
| 1217 |
+
},
|
| 1218 |
+
{
|
| 1219 |
+
"move": "no-op",
|
| 1220 |
+
"view": "turn right"
|
| 1221 |
+
},
|
| 1222 |
+
{
|
| 1223 |
+
"move": "no-op",
|
| 1224 |
+
"view": "turn right"
|
| 1225 |
+
},
|
| 1226 |
+
{
|
| 1227 |
+
"move": "no-op",
|
| 1228 |
+
"view": "turn right"
|
| 1229 |
+
},
|
| 1230 |
+
{
|
| 1231 |
+
"move": "no-op",
|
| 1232 |
+
"view": "turn right"
|
| 1233 |
+
},
|
| 1234 |
+
{
|
| 1235 |
+
"move": "no-op",
|
| 1236 |
+
"view": "turn right"
|
| 1237 |
+
},
|
| 1238 |
+
{
|
| 1239 |
+
"move": "no-op",
|
| 1240 |
+
"view": "turn right"
|
| 1241 |
+
},
|
| 1242 |
+
{
|
| 1243 |
+
"move": "no-op",
|
| 1244 |
+
"view": "turn right"
|
| 1245 |
+
},
|
| 1246 |
+
{
|
| 1247 |
+
"move": "no-op",
|
| 1248 |
+
"view": "turn right"
|
| 1249 |
+
},
|
| 1250 |
+
{
|
| 1251 |
+
"move": "no-op",
|
| 1252 |
+
"view": "turn right"
|
| 1253 |
+
},
|
| 1254 |
+
{
|
| 1255 |
+
"move": "no-op",
|
| 1256 |
+
"view": "turn right"
|
| 1257 |
+
},
|
| 1258 |
+
{
|
| 1259 |
+
"move": "no-op",
|
| 1260 |
+
"view": "turn right"
|
| 1261 |
+
},
|
| 1262 |
+
{
|
| 1263 |
+
"move": "no-op",
|
| 1264 |
+
"view": "turn right"
|
| 1265 |
+
},
|
| 1266 |
+
{
|
| 1267 |
+
"move": "no-op",
|
| 1268 |
+
"view": "turn right"
|
| 1269 |
+
},
|
| 1270 |
+
{
|
| 1271 |
+
"move": "no-op",
|
| 1272 |
+
"view": "turn right"
|
| 1273 |
+
},
|
| 1274 |
+
{
|
| 1275 |
+
"move": "no-op",
|
| 1276 |
+
"view": "turn right"
|
| 1277 |
+
},
|
| 1278 |
+
{
|
| 1279 |
+
"move": "no-op",
|
| 1280 |
+
"view": "turn right"
|
| 1281 |
+
},
|
| 1282 |
+
{
|
| 1283 |
+
"move": "no-op",
|
| 1284 |
+
"view": "turn right"
|
| 1285 |
+
},
|
| 1286 |
+
{
|
| 1287 |
+
"move": "no-op",
|
| 1288 |
+
"view": "turn right"
|
| 1289 |
+
},
|
| 1290 |
+
{
|
| 1291 |
+
"move": "no-op",
|
| 1292 |
+
"view": "turn right"
|
| 1293 |
+
},
|
| 1294 |
+
{
|
| 1295 |
+
"move": "no-op",
|
| 1296 |
+
"view": "turn right"
|
| 1297 |
+
},
|
| 1298 |
+
{
|
| 1299 |
+
"move": "no-op",
|
| 1300 |
+
"view": "turn left"
|
| 1301 |
+
},
|
| 1302 |
+
{
|
| 1303 |
+
"move": "no-op",
|
| 1304 |
+
"view": "turn left"
|
| 1305 |
+
},
|
| 1306 |
+
{
|
| 1307 |
+
"move": "no-op",
|
| 1308 |
+
"view": "turn left"
|
| 1309 |
+
},
|
| 1310 |
+
{
|
| 1311 |
+
"move": "no-op",
|
| 1312 |
+
"view": "turn left"
|
| 1313 |
+
},
|
| 1314 |
+
{
|
| 1315 |
+
"move": "no-op",
|
| 1316 |
+
"view": "turn left"
|
| 1317 |
+
},
|
| 1318 |
+
{
|
| 1319 |
+
"move": "no-op",
|
| 1320 |
+
"view": "turn left"
|
| 1321 |
+
},
|
| 1322 |
+
{
|
| 1323 |
+
"move": "no-op",
|
| 1324 |
+
"view": "turn left"
|
| 1325 |
+
},
|
| 1326 |
+
{
|
| 1327 |
+
"move": "no-op",
|
| 1328 |
+
"view": "turn left"
|
| 1329 |
+
},
|
| 1330 |
+
{
|
| 1331 |
+
"move": "no-op",
|
| 1332 |
+
"view": "turn left"
|
| 1333 |
+
},
|
| 1334 |
+
{
|
| 1335 |
+
"move": "no-op",
|
| 1336 |
+
"view": "turn left"
|
| 1337 |
+
},
|
| 1338 |
+
{
|
| 1339 |
+
"move": "no-op",
|
| 1340 |
+
"view": "turn left"
|
| 1341 |
+
},
|
| 1342 |
+
{
|
| 1343 |
+
"move": "no-op",
|
| 1344 |
+
"view": "turn left"
|
| 1345 |
+
},
|
| 1346 |
+
{
|
| 1347 |
+
"move": "no-op",
|
| 1348 |
+
"view": "turn left"
|
| 1349 |
+
},
|
| 1350 |
+
{
|
| 1351 |
+
"move": "no-op",
|
| 1352 |
+
"view": "turn left"
|
| 1353 |
+
},
|
| 1354 |
+
{
|
| 1355 |
+
"move": "no-op",
|
| 1356 |
+
"view": "turn left"
|
| 1357 |
+
},
|
| 1358 |
+
{
|
| 1359 |
+
"move": "no-op",
|
| 1360 |
+
"view": "turn left"
|
| 1361 |
+
},
|
| 1362 |
+
{
|
| 1363 |
+
"move": "no-op",
|
| 1364 |
+
"view": "turn left"
|
| 1365 |
+
},
|
| 1366 |
+
{
|
| 1367 |
+
"move": "no-op",
|
| 1368 |
+
"view": "turn left"
|
| 1369 |
+
},
|
| 1370 |
+
{
|
| 1371 |
+
"move": "no-op",
|
| 1372 |
+
"view": "turn left"
|
| 1373 |
+
},
|
| 1374 |
+
{
|
| 1375 |
+
"move": "no-op",
|
| 1376 |
+
"view": "turn left"
|
| 1377 |
+
},
|
| 1378 |
+
{
|
| 1379 |
+
"move": "no-op",
|
| 1380 |
+
"view": "turn left"
|
| 1381 |
+
},
|
| 1382 |
+
{
|
| 1383 |
+
"move": "no-op",
|
| 1384 |
+
"view": "turn left"
|
| 1385 |
+
},
|
| 1386 |
+
{
|
| 1387 |
+
"move": "no-op",
|
| 1388 |
+
"view": "turn left"
|
| 1389 |
+
},
|
| 1390 |
+
{
|
| 1391 |
+
"move": "no-op",
|
| 1392 |
+
"view": "turn left"
|
| 1393 |
+
},
|
| 1394 |
+
{
|
| 1395 |
+
"move": "no-op",
|
| 1396 |
+
"view": "turn left"
|
| 1397 |
+
},
|
| 1398 |
+
{
|
| 1399 |
+
"move": "no-op",
|
| 1400 |
+
"view": "turn left"
|
| 1401 |
+
},
|
| 1402 |
+
{
|
| 1403 |
+
"move": "no-op",
|
| 1404 |
+
"view": "turn left"
|
| 1405 |
+
},
|
| 1406 |
+
{
|
| 1407 |
+
"move": "no-op",
|
| 1408 |
+
"view": "turn left"
|
| 1409 |
+
},
|
| 1410 |
+
{
|
| 1411 |
+
"move": "no-op",
|
| 1412 |
+
"view": "turn left"
|
| 1413 |
+
},
|
| 1414 |
+
{
|
| 1415 |
+
"move": "no-op",
|
| 1416 |
+
"view": "turn left"
|
| 1417 |
+
},
|
| 1418 |
+
{
|
| 1419 |
+
"move": "no-op",
|
| 1420 |
+
"view": "turn left"
|
| 1421 |
+
},
|
| 1422 |
+
{
|
| 1423 |
+
"move": "no-op",
|
| 1424 |
+
"view": "turn left"
|
| 1425 |
+
},
|
| 1426 |
+
{
|
| 1427 |
+
"move": "no-op",
|
| 1428 |
+
"view": "turn left"
|
| 1429 |
+
},
|
| 1430 |
+
{
|
| 1431 |
+
"move": "no-op",
|
| 1432 |
+
"view": "turn left"
|
| 1433 |
+
},
|
| 1434 |
+
{
|
| 1435 |
+
"move": "no-op",
|
| 1436 |
+
"view": "turn left"
|
| 1437 |
+
},
|
| 1438 |
+
{
|
| 1439 |
+
"move": "no-op",
|
| 1440 |
+
"view": "turn left"
|
| 1441 |
+
},
|
| 1442 |
+
{
|
| 1443 |
+
"move": "no-op",
|
| 1444 |
+
"view": "turn left"
|
| 1445 |
+
},
|
| 1446 |
+
{
|
| 1447 |
+
"move": "no-op",
|
| 1448 |
+
"view": "turn left"
|
| 1449 |
+
},
|
| 1450 |
+
{
|
| 1451 |
+
"move": "no-op",
|
| 1452 |
+
"view": "turn left"
|
| 1453 |
+
},
|
| 1454 |
+
{
|
| 1455 |
+
"move": "no-op",
|
| 1456 |
+
"view": "turn left"
|
| 1457 |
+
},
|
| 1458 |
+
{
|
| 1459 |
+
"move": "no-op",
|
| 1460 |
+
"view": "turn left"
|
| 1461 |
+
},
|
| 1462 |
+
{
|
| 1463 |
+
"move": "no-op",
|
| 1464 |
+
"view": "turn left"
|
| 1465 |
+
},
|
| 1466 |
+
{
|
| 1467 |
+
"move": "no-op",
|
| 1468 |
+
"view": "turn left"
|
| 1469 |
+
},
|
| 1470 |
+
{
|
| 1471 |
+
"move": "no-op",
|
| 1472 |
+
"view": "turn left"
|
| 1473 |
+
},
|
| 1474 |
+
{
|
| 1475 |
+
"move": "no-op",
|
| 1476 |
+
"view": "turn left"
|
| 1477 |
+
},
|
| 1478 |
+
{
|
| 1479 |
+
"move": "no-op",
|
| 1480 |
+
"view": "turn left"
|
| 1481 |
+
},
|
| 1482 |
+
{
|
| 1483 |
+
"move": "no-op",
|
| 1484 |
+
"view": "turn left"
|
| 1485 |
+
},
|
| 1486 |
+
{
|
| 1487 |
+
"move": "no-op",
|
| 1488 |
+
"view": "turn left"
|
| 1489 |
+
},
|
| 1490 |
+
{
|
| 1491 |
+
"move": "no-op",
|
| 1492 |
+
"view": "turn left"
|
| 1493 |
+
},
|
| 1494 |
+
{
|
| 1495 |
+
"move": "no-op",
|
| 1496 |
+
"view": "turn left"
|
| 1497 |
+
},
|
| 1498 |
+
{
|
| 1499 |
+
"move": "no-op",
|
| 1500 |
+
"view": "turn left"
|
| 1501 |
+
},
|
| 1502 |
+
{
|
| 1503 |
+
"move": "no-op",
|
| 1504 |
+
"view": "turn left"
|
| 1505 |
+
},
|
| 1506 |
+
{
|
| 1507 |
+
"move": "no-op",
|
| 1508 |
+
"view": "turn left"
|
| 1509 |
+
},
|
| 1510 |
+
{
|
| 1511 |
+
"move": "no-op",
|
| 1512 |
+
"view": "turn left"
|
| 1513 |
+
},
|
| 1514 |
+
{
|
| 1515 |
+
"move": "no-op",
|
| 1516 |
+
"view": "turn left"
|
| 1517 |
+
},
|
| 1518 |
+
{
|
| 1519 |
+
"move": "no-op",
|
| 1520 |
+
"view": "turn left"
|
| 1521 |
+
},
|
| 1522 |
+
{
|
| 1523 |
+
"move": "no-op",
|
| 1524 |
+
"view": "turn left"
|
| 1525 |
+
},
|
| 1526 |
+
{
|
| 1527 |
+
"move": "no-op",
|
| 1528 |
+
"view": "turn left"
|
| 1529 |
+
},
|
| 1530 |
+
{
|
| 1531 |
+
"move": "no-op",
|
| 1532 |
+
"view": "turn left"
|
| 1533 |
+
},
|
| 1534 |
+
{
|
| 1535 |
+
"move": "no-op",
|
| 1536 |
+
"view": "turn left"
|
| 1537 |
+
},
|
| 1538 |
+
{
|
| 1539 |
+
"move": "no-op",
|
| 1540 |
+
"view": "turn left"
|
| 1541 |
+
},
|
| 1542 |
+
{
|
| 1543 |
+
"move": "no-op",
|
| 1544 |
+
"view": "turn left"
|
| 1545 |
+
},
|
| 1546 |
+
{
|
| 1547 |
+
"move": "no-op",
|
| 1548 |
+
"view": "turn left"
|
| 1549 |
+
},
|
| 1550 |
+
{
|
| 1551 |
+
"move": "no-op",
|
| 1552 |
+
"view": "turn left"
|
| 1553 |
+
},
|
| 1554 |
+
{
|
| 1555 |
+
"move": "no-op",
|
| 1556 |
+
"view": "turn left"
|
| 1557 |
+
},
|
| 1558 |
+
{
|
| 1559 |
+
"move": "no-op",
|
| 1560 |
+
"view": "turn left"
|
| 1561 |
+
},
|
| 1562 |
+
{
|
| 1563 |
+
"move": "no-op",
|
| 1564 |
+
"view": "turn left"
|
| 1565 |
+
},
|
| 1566 |
+
{
|
| 1567 |
+
"move": "no-op",
|
| 1568 |
+
"view": "turn left"
|
| 1569 |
+
},
|
| 1570 |
+
{
|
| 1571 |
+
"move": "no-op",
|
| 1572 |
+
"view": "turn left"
|
| 1573 |
+
},
|
| 1574 |
+
{
|
| 1575 |
+
"move": "no-op",
|
| 1576 |
+
"view": "turn left"
|
| 1577 |
+
},
|
| 1578 |
+
{
|
| 1579 |
+
"move": "no-op",
|
| 1580 |
+
"view": "turn left"
|
| 1581 |
+
},
|
| 1582 |
+
{
|
| 1583 |
+
"move": "no-op",
|
| 1584 |
+
"view": "turn left"
|
| 1585 |
+
},
|
| 1586 |
+
{
|
| 1587 |
+
"move": "no-op",
|
| 1588 |
+
"view": "turn left"
|
| 1589 |
+
},
|
| 1590 |
+
{
|
| 1591 |
+
"move": "no-op",
|
| 1592 |
+
"view": "turn left"
|
| 1593 |
+
},
|
| 1594 |
+
{
|
| 1595 |
+
"move": "no-op",
|
| 1596 |
+
"view": "turn left"
|
| 1597 |
+
},
|
| 1598 |
+
{
|
| 1599 |
+
"move": "no-op",
|
| 1600 |
+
"view": "turn left"
|
| 1601 |
+
},
|
| 1602 |
+
{
|
| 1603 |
+
"move": "no-op",
|
| 1604 |
+
"view": "turn left"
|
| 1605 |
+
},
|
| 1606 |
+
{
|
| 1607 |
+
"move": "no-op",
|
| 1608 |
+
"view": "turn left"
|
| 1609 |
+
},
|
| 1610 |
+
{
|
| 1611 |
+
"move": "no-op",
|
| 1612 |
+
"view": "turn left"
|
| 1613 |
+
},
|
| 1614 |
+
{
|
| 1615 |
+
"move": "no-op",
|
| 1616 |
+
"view": "turn left"
|
| 1617 |
+
},
|
| 1618 |
+
{
|
| 1619 |
+
"move": "no-op",
|
| 1620 |
+
"view": "turn left"
|
| 1621 |
+
},
|
| 1622 |
+
{
|
| 1623 |
+
"move": "no-op",
|
| 1624 |
+
"view": "turn left"
|
| 1625 |
+
},
|
| 1626 |
+
{
|
| 1627 |
+
"move": "no-op",
|
| 1628 |
+
"view": "turn left"
|
| 1629 |
+
},
|
| 1630 |
+
{
|
| 1631 |
+
"move": "no-op",
|
| 1632 |
+
"view": "turn left"
|
| 1633 |
+
},
|
| 1634 |
+
{
|
| 1635 |
+
"move": "no-op",
|
| 1636 |
+
"view": "turn left"
|
| 1637 |
+
},
|
| 1638 |
+
{
|
| 1639 |
+
"move": "no-op",
|
| 1640 |
+
"view": "turn left"
|
| 1641 |
+
},
|
| 1642 |
+
{
|
| 1643 |
+
"move": "no-op",
|
| 1644 |
+
"view": "turn left"
|
| 1645 |
+
},
|
| 1646 |
+
{
|
| 1647 |
+
"move": "no-op",
|
| 1648 |
+
"view": "turn left"
|
| 1649 |
+
},
|
| 1650 |
+
{
|
| 1651 |
+
"move": "no-op",
|
| 1652 |
+
"view": "turn left"
|
| 1653 |
+
},
|
| 1654 |
+
{
|
| 1655 |
+
"move": "no-op",
|
| 1656 |
+
"view": "turn left"
|
| 1657 |
+
},
|
| 1658 |
+
{
|
| 1659 |
+
"move": "no-op",
|
| 1660 |
+
"view": "turn left"
|
| 1661 |
+
},
|
| 1662 |
+
{
|
| 1663 |
+
"move": "no-op",
|
| 1664 |
+
"view": "turn left"
|
| 1665 |
+
},
|
| 1666 |
+
{
|
| 1667 |
+
"move": "no-op",
|
| 1668 |
+
"view": "turn left"
|
| 1669 |
+
},
|
| 1670 |
+
{
|
| 1671 |
+
"move": "no-op",
|
| 1672 |
+
"view": "turn left"
|
| 1673 |
+
},
|
| 1674 |
+
{
|
| 1675 |
+
"move": "no-op",
|
| 1676 |
+
"view": "turn left"
|
| 1677 |
+
},
|
| 1678 |
+
{
|
| 1679 |
+
"move": "no-op",
|
| 1680 |
+
"view": "turn left"
|
| 1681 |
+
},
|
| 1682 |
+
{
|
| 1683 |
+
"move": "no-op",
|
| 1684 |
+
"view": "turn left"
|
| 1685 |
+
},
|
| 1686 |
+
{
|
| 1687 |
+
"move": "no-op",
|
| 1688 |
+
"view": "turn left"
|
| 1689 |
+
},
|
| 1690 |
+
{
|
| 1691 |
+
"move": "no-op",
|
| 1692 |
+
"view": "turn left"
|
| 1693 |
+
},
|
| 1694 |
+
{
|
| 1695 |
+
"move": "no-op",
|
| 1696 |
+
"view": "turn left"
|
| 1697 |
+
},
|
| 1698 |
+
{
|
| 1699 |
+
"move": "no-op",
|
| 1700 |
+
"view": "turn left"
|
| 1701 |
+
},
|
| 1702 |
+
{
|
| 1703 |
+
"move": "no-op",
|
| 1704 |
+
"view": "turn left"
|
| 1705 |
+
},
|
| 1706 |
+
{
|
| 1707 |
+
"move": "no-op",
|
| 1708 |
+
"view": "turn left"
|
| 1709 |
+
},
|
| 1710 |
+
{
|
| 1711 |
+
"move": "no-op",
|
| 1712 |
+
"view": "turn left"
|
| 1713 |
+
},
|
| 1714 |
+
{
|
| 1715 |
+
"move": "no-op",
|
| 1716 |
+
"view": "turn left"
|
| 1717 |
+
},
|
| 1718 |
+
{
|
| 1719 |
+
"move": "no-op",
|
| 1720 |
+
"view": "turn left"
|
| 1721 |
+
},
|
| 1722 |
+
{
|
| 1723 |
+
"move": "no-op",
|
| 1724 |
+
"view": "turn left"
|
| 1725 |
+
},
|
| 1726 |
+
{
|
| 1727 |
+
"move": "no-op",
|
| 1728 |
+
"view": "turn left"
|
| 1729 |
+
},
|
| 1730 |
+
{
|
| 1731 |
+
"move": "no-op",
|
| 1732 |
+
"view": "turn left"
|
| 1733 |
+
},
|
| 1734 |
+
{
|
| 1735 |
+
"move": "no-op",
|
| 1736 |
+
"view": "turn left"
|
| 1737 |
+
},
|
| 1738 |
+
{
|
| 1739 |
+
"move": "no-op",
|
| 1740 |
+
"view": "turn left"
|
| 1741 |
+
},
|
| 1742 |
+
{
|
| 1743 |
+
"move": "no-op",
|
| 1744 |
+
"view": "turn left"
|
| 1745 |
+
},
|
| 1746 |
+
{
|
| 1747 |
+
"move": "no-op",
|
| 1748 |
+
"view": "turn left"
|
| 1749 |
+
},
|
| 1750 |
+
{
|
| 1751 |
+
"move": "no-op",
|
| 1752 |
+
"view": "turn left"
|
| 1753 |
+
},
|
| 1754 |
+
{
|
| 1755 |
+
"move": "no-op",
|
| 1756 |
+
"view": "turn left"
|
| 1757 |
+
},
|
| 1758 |
+
{
|
| 1759 |
+
"move": "no-op",
|
| 1760 |
+
"view": "turn left"
|
| 1761 |
+
},
|
| 1762 |
+
{
|
| 1763 |
+
"move": "no-op",
|
| 1764 |
+
"view": "turn left"
|
| 1765 |
+
},
|
| 1766 |
+
{
|
| 1767 |
+
"move": "no-op",
|
| 1768 |
+
"view": "turn left"
|
| 1769 |
+
},
|
| 1770 |
+
{
|
| 1771 |
+
"move": "no-op",
|
| 1772 |
+
"view": "turn left"
|
| 1773 |
+
},
|
| 1774 |
+
{
|
| 1775 |
+
"move": "no-op",
|
| 1776 |
+
"view": "turn left"
|
| 1777 |
+
},
|
| 1778 |
+
{
|
| 1779 |
+
"move": "no-op",
|
| 1780 |
+
"view": "turn left"
|
| 1781 |
+
},
|
| 1782 |
+
{
|
| 1783 |
+
"move": "no-op",
|
| 1784 |
+
"view": "turn left"
|
| 1785 |
+
},
|
| 1786 |
+
{
|
| 1787 |
+
"move": "no-op",
|
| 1788 |
+
"view": "turn left"
|
| 1789 |
+
},
|
| 1790 |
+
{
|
| 1791 |
+
"move": "no-op",
|
| 1792 |
+
"view": "turn left"
|
| 1793 |
+
},
|
| 1794 |
+
{
|
| 1795 |
+
"move": "no-op",
|
| 1796 |
+
"view": "turn left"
|
| 1797 |
+
},
|
| 1798 |
+
{
|
| 1799 |
+
"move": "no-op",
|
| 1800 |
+
"view": "turn left"
|
| 1801 |
+
},
|
| 1802 |
+
{
|
| 1803 |
+
"move": "no-op",
|
| 1804 |
+
"view": "turn left"
|
| 1805 |
+
},
|
| 1806 |
+
{
|
| 1807 |
+
"move": "no-op",
|
| 1808 |
+
"view": "turn left"
|
| 1809 |
+
},
|
| 1810 |
+
{
|
| 1811 |
+
"move": "no-op",
|
| 1812 |
+
"view": "turn left"
|
| 1813 |
+
},
|
| 1814 |
+
{
|
| 1815 |
+
"move": "no-op",
|
| 1816 |
+
"view": "turn left"
|
| 1817 |
+
},
|
| 1818 |
+
{
|
| 1819 |
+
"move": "no-op",
|
| 1820 |
+
"view": "turn left"
|
| 1821 |
+
},
|
| 1822 |
+
{
|
| 1823 |
+
"move": "no-op",
|
| 1824 |
+
"view": "turn left"
|
| 1825 |
+
},
|
| 1826 |
+
{
|
| 1827 |
+
"move": "no-op",
|
| 1828 |
+
"view": "turn left"
|
| 1829 |
+
},
|
| 1830 |
+
{
|
| 1831 |
+
"move": "no-op",
|
| 1832 |
+
"view": "turn left"
|
| 1833 |
+
},
|
| 1834 |
+
{
|
| 1835 |
+
"move": "no-op",
|
| 1836 |
+
"view": "turn left"
|
| 1837 |
+
},
|
| 1838 |
+
{
|
| 1839 |
+
"move": "no-op",
|
| 1840 |
+
"view": "turn left"
|
| 1841 |
+
},
|
| 1842 |
+
{
|
| 1843 |
+
"move": "no-op",
|
| 1844 |
+
"view": "turn left"
|
| 1845 |
+
},
|
| 1846 |
+
{
|
| 1847 |
+
"move": "no-op",
|
| 1848 |
+
"view": "turn left"
|
| 1849 |
+
},
|
| 1850 |
+
{
|
| 1851 |
+
"move": "no-op",
|
| 1852 |
+
"view": "turn left"
|
| 1853 |
+
},
|
| 1854 |
+
{
|
| 1855 |
+
"move": "no-op",
|
| 1856 |
+
"view": "turn left"
|
| 1857 |
+
},
|
| 1858 |
+
{
|
| 1859 |
+
"move": "no-op",
|
| 1860 |
+
"view": "turn left"
|
| 1861 |
+
},
|
| 1862 |
+
{
|
| 1863 |
+
"move": "no-op",
|
| 1864 |
+
"view": "turn left"
|
| 1865 |
+
},
|
| 1866 |
+
{
|
| 1867 |
+
"move": "no-op",
|
| 1868 |
+
"view": "turn left"
|
| 1869 |
+
},
|
| 1870 |
+
{
|
| 1871 |
+
"move": "no-op",
|
| 1872 |
+
"view": "turn left"
|
| 1873 |
+
},
|
| 1874 |
+
{
|
| 1875 |
+
"move": "no-op",
|
| 1876 |
+
"view": "turn left"
|
| 1877 |
+
},
|
| 1878 |
+
{
|
| 1879 |
+
"move": "no-op",
|
| 1880 |
+
"view": "turn left"
|
| 1881 |
+
},
|
| 1882 |
+
{
|
| 1883 |
+
"move": "no-op",
|
| 1884 |
+
"view": "turn left"
|
| 1885 |
+
},
|
| 1886 |
+
{
|
| 1887 |
+
"move": "no-op",
|
| 1888 |
+
"view": "turn left"
|
| 1889 |
+
},
|
| 1890 |
+
{
|
| 1891 |
+
"move": "no-op",
|
| 1892 |
+
"view": "turn left"
|
| 1893 |
+
},
|
| 1894 |
+
{
|
| 1895 |
+
"move": "no-op",
|
| 1896 |
+
"view": "turn left"
|
| 1897 |
+
},
|
| 1898 |
+
{
|
| 1899 |
+
"move": "no-op",
|
| 1900 |
+
"view": "turn left"
|
| 1901 |
+
},
|
| 1902 |
+
{
|
| 1903 |
+
"move": "no-op",
|
| 1904 |
+
"view": "turn left"
|
| 1905 |
+
},
|
| 1906 |
+
{
|
| 1907 |
+
"move": "no-op",
|
| 1908 |
+
"view": "turn left"
|
| 1909 |
+
},
|
| 1910 |
+
{
|
| 1911 |
+
"move": "no-op",
|
| 1912 |
+
"view": "turn left"
|
| 1913 |
+
},
|
| 1914 |
+
{
|
| 1915 |
+
"move": "no-op",
|
| 1916 |
+
"view": "turn left"
|
| 1917 |
+
},
|
| 1918 |
+
{
|
| 1919 |
+
"move": "no-op",
|
| 1920 |
+
"view": "turn left"
|
| 1921 |
+
},
|
| 1922 |
+
{
|
| 1923 |
+
"move": "no-op",
|
| 1924 |
+
"view": "turn left"
|
| 1925 |
+
},
|
| 1926 |
+
{
|
| 1927 |
+
"move": "no-op",
|
| 1928 |
+
"view": "turn left"
|
| 1929 |
+
},
|
| 1930 |
+
{
|
| 1931 |
+
"move": "no-op",
|
| 1932 |
+
"view": "turn left"
|
| 1933 |
+
},
|
| 1934 |
+
{
|
| 1935 |
+
"move": "no-op",
|
| 1936 |
+
"view": "turn left"
|
| 1937 |
+
},
|
| 1938 |
+
{
|
| 1939 |
+
"move": "no-op",
|
| 1940 |
+
"view": "turn left"
|
| 1941 |
+
},
|
| 1942 |
+
{
|
| 1943 |
+
"move": "no-op",
|
| 1944 |
+
"view": "turn left"
|
| 1945 |
+
},
|
| 1946 |
+
{
|
| 1947 |
+
"move": "no-op",
|
| 1948 |
+
"view": "turn left"
|
| 1949 |
+
},
|
| 1950 |
+
{
|
| 1951 |
+
"move": "no-op",
|
| 1952 |
+
"view": "turn left"
|
| 1953 |
+
},
|
| 1954 |
+
{
|
| 1955 |
+
"move": "no-op",
|
| 1956 |
+
"view": "turn left"
|
| 1957 |
+
},
|
| 1958 |
+
{
|
| 1959 |
+
"move": "no-op",
|
| 1960 |
+
"view": "turn left"
|
| 1961 |
+
},
|
| 1962 |
+
{
|
| 1963 |
+
"move": "no-op",
|
| 1964 |
+
"view": "turn left"
|
| 1965 |
+
},
|
| 1966 |
+
{
|
| 1967 |
+
"move": "no-op",
|
| 1968 |
+
"view": "turn left"
|
| 1969 |
+
},
|
| 1970 |
+
{
|
| 1971 |
+
"move": "no-op",
|
| 1972 |
+
"view": "turn left"
|
| 1973 |
+
},
|
| 1974 |
+
{
|
| 1975 |
+
"move": "no-op",
|
| 1976 |
+
"view": "turn left"
|
| 1977 |
+
},
|
| 1978 |
+
{
|
| 1979 |
+
"move": "no-op",
|
| 1980 |
+
"view": "turn left"
|
| 1981 |
+
},
|
| 1982 |
+
{
|
| 1983 |
+
"move": "no-op",
|
| 1984 |
+
"view": "turn left"
|
| 1985 |
+
},
|
| 1986 |
+
{
|
| 1987 |
+
"move": "no-op",
|
| 1988 |
+
"view": "turn left"
|
| 1989 |
+
},
|
| 1990 |
+
{
|
| 1991 |
+
"move": "no-op",
|
| 1992 |
+
"view": "turn left"
|
| 1993 |
+
},
|
| 1994 |
+
{
|
| 1995 |
+
"move": "no-op",
|
| 1996 |
+
"view": "turn left"
|
| 1997 |
+
},
|
| 1998 |
+
{
|
| 1999 |
+
"move": "no-op",
|
| 2000 |
+
"view": "turn left"
|
| 2001 |
+
},
|
| 2002 |
+
{
|
| 2003 |
+
"move": "no-op",
|
| 2004 |
+
"view": "turn left"
|
| 2005 |
+
},
|
| 2006 |
+
{
|
| 2007 |
+
"move": "no-op",
|
| 2008 |
+
"view": "turn left"
|
| 2009 |
+
},
|
| 2010 |
+
{
|
| 2011 |
+
"move": "no-op",
|
| 2012 |
+
"view": "turn left"
|
| 2013 |
+
},
|
| 2014 |
+
{
|
| 2015 |
+
"move": "no-op",
|
| 2016 |
+
"view": "turn left"
|
| 2017 |
+
},
|
| 2018 |
+
{
|
| 2019 |
+
"move": "no-op",
|
| 2020 |
+
"view": "turn left"
|
| 2021 |
+
},
|
| 2022 |
+
{
|
| 2023 |
+
"move": "no-op",
|
| 2024 |
+
"view": "turn left"
|
| 2025 |
+
},
|
| 2026 |
+
{
|
| 2027 |
+
"move": "no-op",
|
| 2028 |
+
"view": "turn left"
|
| 2029 |
+
},
|
| 2030 |
+
{
|
| 2031 |
+
"move": "no-op",
|
| 2032 |
+
"view": "turn left"
|
| 2033 |
+
},
|
| 2034 |
+
{
|
| 2035 |
+
"move": "no-op",
|
| 2036 |
+
"view": "turn left"
|
| 2037 |
+
},
|
| 2038 |
+
{
|
| 2039 |
+
"move": "no-op",
|
| 2040 |
+
"view": "turn left"
|
| 2041 |
+
},
|
| 2042 |
+
{
|
| 2043 |
+
"move": "no-op",
|
| 2044 |
+
"view": "turn left"
|
| 2045 |
+
},
|
| 2046 |
+
{
|
| 2047 |
+
"move": "no-op",
|
| 2048 |
+
"view": "turn left"
|
| 2049 |
+
},
|
| 2050 |
+
{
|
| 2051 |
+
"move": "no-op",
|
| 2052 |
+
"view": "turn left"
|
| 2053 |
+
},
|
| 2054 |
+
{
|
| 2055 |
+
"move": "no-op",
|
| 2056 |
+
"view": "turn left"
|
| 2057 |
+
},
|
| 2058 |
+
{
|
| 2059 |
+
"move": "no-op",
|
| 2060 |
+
"view": "turn left"
|
| 2061 |
+
},
|
| 2062 |
+
{
|
| 2063 |
+
"move": "no-op",
|
| 2064 |
+
"view": "turn left"
|
| 2065 |
+
},
|
| 2066 |
+
{
|
| 2067 |
+
"move": "no-op",
|
| 2068 |
+
"view": "turn left"
|
| 2069 |
+
},
|
| 2070 |
+
{
|
| 2071 |
+
"move": "no-op",
|
| 2072 |
+
"view": "turn left"
|
| 2073 |
+
},
|
| 2074 |
+
{
|
| 2075 |
+
"move": "no-op",
|
| 2076 |
+
"view": "turn left"
|
| 2077 |
+
},
|
| 2078 |
+
{
|
| 2079 |
+
"move": "no-op",
|
| 2080 |
+
"view": "turn left"
|
| 2081 |
+
},
|
| 2082 |
+
{
|
| 2083 |
+
"move": "no-op",
|
| 2084 |
+
"view": "turn left"
|
| 2085 |
+
},
|
| 2086 |
+
{
|
| 2087 |
+
"move": "no-op",
|
| 2088 |
+
"view": "turn left"
|
| 2089 |
+
},
|
| 2090 |
+
{
|
| 2091 |
+
"move": "no-op",
|
| 2092 |
+
"view": "turn left"
|
| 2093 |
+
},
|
| 2094 |
+
{
|
| 2095 |
+
"move": "no-op",
|
| 2096 |
+
"view": "turn left"
|
| 2097 |
+
},
|
| 2098 |
+
{
|
| 2099 |
+
"move": "no-op",
|
| 2100 |
+
"view": "turn left"
|
| 2101 |
+
},
|
| 2102 |
+
{
|
| 2103 |
+
"move": "no-op",
|
| 2104 |
+
"view": "turn left"
|
| 2105 |
+
},
|
| 2106 |
+
{
|
| 2107 |
+
"move": "no-op",
|
| 2108 |
+
"view": "turn left"
|
| 2109 |
+
},
|
| 2110 |
+
{
|
| 2111 |
+
"move": "no-op",
|
| 2112 |
+
"view": "turn left"
|
| 2113 |
+
},
|
| 2114 |
+
{
|
| 2115 |
+
"move": "no-op",
|
| 2116 |
+
"view": "turn left"
|
| 2117 |
+
},
|
| 2118 |
+
{
|
| 2119 |
+
"move": "no-op",
|
| 2120 |
+
"view": "turn left"
|
| 2121 |
+
},
|
| 2122 |
+
{
|
| 2123 |
+
"move": "no-op",
|
| 2124 |
+
"view": "turn left"
|
| 2125 |
+
},
|
| 2126 |
+
{
|
| 2127 |
+
"move": "no-op",
|
| 2128 |
+
"view": "turn left"
|
| 2129 |
+
},
|
| 2130 |
+
{
|
| 2131 |
+
"move": "no-op",
|
| 2132 |
+
"view": "turn left"
|
| 2133 |
+
},
|
| 2134 |
+
{
|
| 2135 |
+
"move": "no-op",
|
| 2136 |
+
"view": "turn left"
|
| 2137 |
+
},
|
| 2138 |
+
{
|
| 2139 |
+
"move": "no-op",
|
| 2140 |
+
"view": "turn left"
|
| 2141 |
+
},
|
| 2142 |
+
{
|
| 2143 |
+
"move": "no-op",
|
| 2144 |
+
"view": "turn left"
|
| 2145 |
+
},
|
| 2146 |
+
{
|
| 2147 |
+
"move": "no-op",
|
| 2148 |
+
"view": "turn left"
|
| 2149 |
+
},
|
| 2150 |
+
{
|
| 2151 |
+
"move": "no-op",
|
| 2152 |
+
"view": "turn left"
|
| 2153 |
+
},
|
| 2154 |
+
{
|
| 2155 |
+
"move": "no-op",
|
| 2156 |
+
"view": "turn left"
|
| 2157 |
+
},
|
| 2158 |
+
{
|
| 2159 |
+
"move": "no-op",
|
| 2160 |
+
"view": "turn left"
|
| 2161 |
+
},
|
| 2162 |
+
{
|
| 2163 |
+
"move": "no-op",
|
| 2164 |
+
"view": "turn left"
|
| 2165 |
+
},
|
| 2166 |
+
{
|
| 2167 |
+
"move": "no-op",
|
| 2168 |
+
"view": "turn left"
|
| 2169 |
+
},
|
| 2170 |
+
{
|
| 2171 |
+
"move": "no-op",
|
| 2172 |
+
"view": "turn left"
|
| 2173 |
+
},
|
| 2174 |
+
{
|
| 2175 |
+
"move": "no-op",
|
| 2176 |
+
"view": "turn left"
|
| 2177 |
+
},
|
| 2178 |
+
{
|
| 2179 |
+
"move": "no-op",
|
| 2180 |
+
"view": "turn left"
|
| 2181 |
+
},
|
| 2182 |
+
{
|
| 2183 |
+
"move": "no-op",
|
| 2184 |
+
"view": "turn left"
|
| 2185 |
+
},
|
| 2186 |
+
{
|
| 2187 |
+
"move": "no-op",
|
| 2188 |
+
"view": "turn left"
|
| 2189 |
+
},
|
| 2190 |
+
{
|
| 2191 |
+
"move": "no-op",
|
| 2192 |
+
"view": "turn left"
|
| 2193 |
+
},
|
| 2194 |
+
{
|
| 2195 |
+
"move": "no-op",
|
| 2196 |
+
"view": "turn left"
|
| 2197 |
+
},
|
| 2198 |
+
{
|
| 2199 |
+
"move": "no-op",
|
| 2200 |
+
"view": "turn left"
|
| 2201 |
+
},
|
| 2202 |
+
{
|
| 2203 |
+
"move": "no-op",
|
| 2204 |
+
"view": "turn left"
|
| 2205 |
+
},
|
| 2206 |
+
{
|
| 2207 |
+
"move": "no-op",
|
| 2208 |
+
"view": "turn left"
|
| 2209 |
+
},
|
| 2210 |
+
{
|
| 2211 |
+
"move": "no-op",
|
| 2212 |
+
"view": "turn left"
|
| 2213 |
+
},
|
| 2214 |
+
{
|
| 2215 |
+
"move": "no-op",
|
| 2216 |
+
"view": "turn left"
|
| 2217 |
+
},
|
| 2218 |
+
{
|
| 2219 |
+
"move": "no-op",
|
| 2220 |
+
"view": "turn left"
|
| 2221 |
+
},
|
| 2222 |
+
{
|
| 2223 |
+
"move": "no-op",
|
| 2224 |
+
"view": "turn left"
|
| 2225 |
+
},
|
| 2226 |
+
{
|
| 2227 |
+
"move": "no-op",
|
| 2228 |
+
"view": "turn left"
|
| 2229 |
+
},
|
| 2230 |
+
{
|
| 2231 |
+
"move": "no-op",
|
| 2232 |
+
"view": "turn left"
|
| 2233 |
+
},
|
| 2234 |
+
{
|
| 2235 |
+
"move": "no-op",
|
| 2236 |
+
"view": "turn left"
|
| 2237 |
+
},
|
| 2238 |
+
{
|
| 2239 |
+
"move": "no-op",
|
| 2240 |
+
"view": "turn left"
|
| 2241 |
+
},
|
| 2242 |
+
{
|
| 2243 |
+
"move": "no-op",
|
| 2244 |
+
"view": "turn left"
|
| 2245 |
+
},
|
| 2246 |
+
{
|
| 2247 |
+
"move": "no-op",
|
| 2248 |
+
"view": "turn left"
|
| 2249 |
+
},
|
| 2250 |
+
{
|
| 2251 |
+
"move": "no-op",
|
| 2252 |
+
"view": "turn left"
|
| 2253 |
+
},
|
| 2254 |
+
{
|
| 2255 |
+
"move": "no-op",
|
| 2256 |
+
"view": "turn left"
|
| 2257 |
+
},
|
| 2258 |
+
{
|
| 2259 |
+
"move": "no-op",
|
| 2260 |
+
"view": "turn left"
|
| 2261 |
+
},
|
| 2262 |
+
{
|
| 2263 |
+
"move": "no-op",
|
| 2264 |
+
"view": "turn left"
|
| 2265 |
+
},
|
| 2266 |
+
{
|
| 2267 |
+
"move": "no-op",
|
| 2268 |
+
"view": "turn left"
|
| 2269 |
+
},
|
| 2270 |
+
{
|
| 2271 |
+
"move": "go forward",
|
| 2272 |
+
"view": "no-op"
|
| 2273 |
+
},
|
| 2274 |
+
{
|
| 2275 |
+
"move": "go forward",
|
| 2276 |
+
"view": "no-op"
|
| 2277 |
+
},
|
| 2278 |
+
{
|
| 2279 |
+
"move": "go forward",
|
| 2280 |
+
"view": "no-op"
|
| 2281 |
+
},
|
| 2282 |
+
{
|
| 2283 |
+
"move": "go forward",
|
| 2284 |
+
"view": "no-op"
|
| 2285 |
+
},
|
| 2286 |
+
{
|
| 2287 |
+
"move": "go forward",
|
| 2288 |
+
"view": "no-op"
|
| 2289 |
+
},
|
| 2290 |
+
{
|
| 2291 |
+
"move": "go forward",
|
| 2292 |
+
"view": "no-op"
|
| 2293 |
+
},
|
| 2294 |
+
{
|
| 2295 |
+
"move": "go forward",
|
| 2296 |
+
"view": "no-op"
|
| 2297 |
+
},
|
| 2298 |
+
{
|
| 2299 |
+
"move": "go forward",
|
| 2300 |
+
"view": "no-op"
|
| 2301 |
+
},
|
| 2302 |
+
{
|
| 2303 |
+
"move": "go forward",
|
| 2304 |
+
"view": "no-op"
|
| 2305 |
+
},
|
| 2306 |
+
{
|
| 2307 |
+
"move": "go forward",
|
| 2308 |
+
"view": "no-op"
|
| 2309 |
+
},
|
| 2310 |
+
{
|
| 2311 |
+
"move": "go forward",
|
| 2312 |
+
"view": "no-op"
|
| 2313 |
+
},
|
| 2314 |
+
{
|
| 2315 |
+
"move": "go forward",
|
| 2316 |
+
"view": "no-op"
|
| 2317 |
+
},
|
| 2318 |
+
{
|
| 2319 |
+
"move": "go forward",
|
| 2320 |
+
"view": "no-op"
|
| 2321 |
+
},
|
| 2322 |
+
{
|
| 2323 |
+
"move": "go forward",
|
| 2324 |
+
"view": "no-op"
|
| 2325 |
+
},
|
| 2326 |
+
{
|
| 2327 |
+
"move": "go forward",
|
| 2328 |
+
"view": "no-op"
|
| 2329 |
+
},
|
| 2330 |
+
{
|
| 2331 |
+
"move": "go forward",
|
| 2332 |
+
"view": "no-op"
|
| 2333 |
+
},
|
| 2334 |
+
{
|
| 2335 |
+
"move": "go forward",
|
| 2336 |
+
"view": "no-op"
|
| 2337 |
+
},
|
| 2338 |
+
{
|
| 2339 |
+
"move": "go forward",
|
| 2340 |
+
"view": "no-op"
|
| 2341 |
+
},
|
| 2342 |
+
{
|
| 2343 |
+
"move": "go forward",
|
| 2344 |
+
"view": "no-op"
|
| 2345 |
+
},
|
| 2346 |
+
{
|
| 2347 |
+
"move": "go forward",
|
| 2348 |
+
"view": "no-op"
|
| 2349 |
+
},
|
| 2350 |
+
{
|
| 2351 |
+
"move": "go forward",
|
| 2352 |
+
"view": "no-op"
|
| 2353 |
+
},
|
| 2354 |
+
{
|
| 2355 |
+
"move": "go forward",
|
| 2356 |
+
"view": "no-op"
|
| 2357 |
+
},
|
| 2358 |
+
{
|
| 2359 |
+
"move": "go forward",
|
| 2360 |
+
"view": "no-op"
|
| 2361 |
+
},
|
| 2362 |
+
{
|
| 2363 |
+
"move": "go forward",
|
| 2364 |
+
"view": "no-op"
|
| 2365 |
+
},
|
| 2366 |
+
{
|
| 2367 |
+
"move": "go forward",
|
| 2368 |
+
"view": "no-op"
|
| 2369 |
+
},
|
| 2370 |
+
{
|
| 2371 |
+
"move": "go forward",
|
| 2372 |
+
"view": "no-op"
|
| 2373 |
+
},
|
| 2374 |
+
{
|
| 2375 |
+
"move": "go forward",
|
| 2376 |
+
"view": "no-op"
|
| 2377 |
+
},
|
| 2378 |
+
{
|
| 2379 |
+
"move": "go forward",
|
| 2380 |
+
"view": "no-op"
|
| 2381 |
+
},
|
| 2382 |
+
{
|
| 2383 |
+
"move": "go forward",
|
| 2384 |
+
"view": "no-op"
|
| 2385 |
+
},
|
| 2386 |
+
{
|
| 2387 |
+
"move": "go forward",
|
| 2388 |
+
"view": "no-op"
|
| 2389 |
+
},
|
| 2390 |
+
{
|
| 2391 |
+
"move": "go forward",
|
| 2392 |
+
"view": "no-op"
|
| 2393 |
+
},
|
| 2394 |
+
{
|
| 2395 |
+
"move": "go forward",
|
| 2396 |
+
"view": "no-op"
|
| 2397 |
+
},
|
| 2398 |
+
{
|
| 2399 |
+
"move": "go forward",
|
| 2400 |
+
"view": "no-op"
|
| 2401 |
+
},
|
| 2402 |
+
{
|
| 2403 |
+
"move": "go forward",
|
| 2404 |
+
"view": "no-op"
|
| 2405 |
+
},
|
| 2406 |
+
{
|
| 2407 |
+
"move": "go forward",
|
| 2408 |
+
"view": "no-op"
|
| 2409 |
+
},
|
| 2410 |
+
{
|
| 2411 |
+
"move": "go forward",
|
| 2412 |
+
"view": "no-op"
|
| 2413 |
+
},
|
| 2414 |
+
{
|
| 2415 |
+
"move": "go forward",
|
| 2416 |
+
"view": "no-op"
|
| 2417 |
+
},
|
| 2418 |
+
{
|
| 2419 |
+
"move": "go forward",
|
| 2420 |
+
"view": "no-op"
|
| 2421 |
+
},
|
| 2422 |
+
{
|
| 2423 |
+
"move": "go forward",
|
| 2424 |
+
"view": "no-op"
|
| 2425 |
+
},
|
| 2426 |
+
{
|
| 2427 |
+
"move": "go forward",
|
| 2428 |
+
"view": "no-op"
|
| 2429 |
+
},
|
| 2430 |
+
{
|
| 2431 |
+
"move": "go forward",
|
| 2432 |
+
"view": "no-op"
|
| 2433 |
+
},
|
| 2434 |
+
{
|
| 2435 |
+
"move": "go forward",
|
| 2436 |
+
"view": "no-op"
|
| 2437 |
+
},
|
| 2438 |
+
{
|
| 2439 |
+
"move": "go forward",
|
| 2440 |
+
"view": "no-op"
|
| 2441 |
+
},
|
| 2442 |
+
{
|
| 2443 |
+
"move": "go forward",
|
| 2444 |
+
"view": "no-op"
|
| 2445 |
+
},
|
| 2446 |
+
{
|
| 2447 |
+
"move": "go forward",
|
| 2448 |
+
"view": "no-op"
|
| 2449 |
+
},
|
| 2450 |
+
{
|
| 2451 |
+
"move": "go forward",
|
| 2452 |
+
"view": "no-op"
|
| 2453 |
+
},
|
| 2454 |
+
{
|
| 2455 |
+
"move": "go forward",
|
| 2456 |
+
"view": "no-op"
|
| 2457 |
+
},
|
| 2458 |
+
{
|
| 2459 |
+
"move": "go forward",
|
| 2460 |
+
"view": "no-op"
|
| 2461 |
+
},
|
| 2462 |
+
{
|
| 2463 |
+
"move": "go forward",
|
| 2464 |
+
"view": "no-op"
|
| 2465 |
+
},
|
| 2466 |
+
{
|
| 2467 |
+
"move": "go forward",
|
| 2468 |
+
"view": "no-op"
|
| 2469 |
+
},
|
| 2470 |
+
{
|
| 2471 |
+
"move": "go forward",
|
| 2472 |
+
"view": "no-op"
|
| 2473 |
+
},
|
| 2474 |
+
{
|
| 2475 |
+
"move": "go forward",
|
| 2476 |
+
"view": "no-op"
|
| 2477 |
+
},
|
| 2478 |
+
{
|
| 2479 |
+
"move": "go forward",
|
| 2480 |
+
"view": "no-op"
|
| 2481 |
+
},
|
| 2482 |
+
{
|
| 2483 |
+
"move": "go forward",
|
| 2484 |
+
"view": "no-op"
|
| 2485 |
+
},
|
| 2486 |
+
{
|
| 2487 |
+
"move": "go forward",
|
| 2488 |
+
"view": "no-op"
|
| 2489 |
+
},
|
| 2490 |
+
{
|
| 2491 |
+
"move": "go forward",
|
| 2492 |
+
"view": "no-op"
|
| 2493 |
+
},
|
| 2494 |
+
{
|
| 2495 |
+
"move": "go forward",
|
| 2496 |
+
"view": "no-op"
|
| 2497 |
+
},
|
| 2498 |
+
{
|
| 2499 |
+
"move": "go forward",
|
| 2500 |
+
"view": "no-op"
|
| 2501 |
+
},
|
| 2502 |
+
{
|
| 2503 |
+
"move": "go forward",
|
| 2504 |
+
"view": "no-op"
|
| 2505 |
+
},
|
| 2506 |
+
{
|
| 2507 |
+
"move": "go forward",
|
| 2508 |
+
"view": "no-op"
|
| 2509 |
+
},
|
| 2510 |
+
{
|
| 2511 |
+
"move": "go forward",
|
| 2512 |
+
"view": "no-op"
|
| 2513 |
+
},
|
| 2514 |
+
{
|
| 2515 |
+
"move": "go forward",
|
| 2516 |
+
"view": "no-op"
|
| 2517 |
+
},
|
| 2518 |
+
{
|
| 2519 |
+
"move": "go forward",
|
| 2520 |
+
"view": "no-op"
|
| 2521 |
+
},
|
| 2522 |
+
{
|
| 2523 |
+
"move": "go forward",
|
| 2524 |
+
"view": "no-op"
|
| 2525 |
+
},
|
| 2526 |
+
{
|
| 2527 |
+
"move": "go forward",
|
| 2528 |
+
"view": "no-op"
|
| 2529 |
+
},
|
| 2530 |
+
{
|
| 2531 |
+
"move": "go forward",
|
| 2532 |
+
"view": "no-op"
|
| 2533 |
+
},
|
| 2534 |
+
{
|
| 2535 |
+
"move": "go forward",
|
| 2536 |
+
"view": "no-op"
|
| 2537 |
+
},
|
| 2538 |
+
{
|
| 2539 |
+
"move": "go forward",
|
| 2540 |
+
"view": "no-op"
|
| 2541 |
+
},
|
| 2542 |
+
{
|
| 2543 |
+
"move": "go forward",
|
| 2544 |
+
"view": "no-op"
|
| 2545 |
+
},
|
| 2546 |
+
{
|
| 2547 |
+
"move": "go forward",
|
| 2548 |
+
"view": "no-op"
|
| 2549 |
+
},
|
| 2550 |
+
{
|
| 2551 |
+
"move": "go forward",
|
| 2552 |
+
"view": "no-op"
|
| 2553 |
+
},
|
| 2554 |
+
{
|
| 2555 |
+
"move": "go forward",
|
| 2556 |
+
"view": "no-op"
|
| 2557 |
+
},
|
| 2558 |
+
{
|
| 2559 |
+
"move": "go forward",
|
| 2560 |
+
"view": "no-op"
|
| 2561 |
+
},
|
| 2562 |
+
{
|
| 2563 |
+
"move": "go forward",
|
| 2564 |
+
"view": "no-op"
|
| 2565 |
+
},
|
| 2566 |
+
{
|
| 2567 |
+
"move": "go forward",
|
| 2568 |
+
"view": "no-op"
|
| 2569 |
+
},
|
| 2570 |
+
{
|
| 2571 |
+
"move": "go forward",
|
| 2572 |
+
"view": "no-op"
|
| 2573 |
+
},
|
| 2574 |
+
{
|
| 2575 |
+
"move": "go forward",
|
| 2576 |
+
"view": "no-op"
|
| 2577 |
+
},
|
| 2578 |
+
{
|
| 2579 |
+
"move": "go forward",
|
| 2580 |
+
"view": "no-op"
|
| 2581 |
+
},
|
| 2582 |
+
{
|
| 2583 |
+
"move": "go forward",
|
| 2584 |
+
"view": "no-op"
|
| 2585 |
+
},
|
| 2586 |
+
{
|
| 2587 |
+
"move": "go forward",
|
| 2588 |
+
"view": "no-op"
|
| 2589 |
+
},
|
| 2590 |
+
{
|
| 2591 |
+
"move": "go forward",
|
| 2592 |
+
"view": "no-op"
|
| 2593 |
+
},
|
| 2594 |
+
{
|
| 2595 |
+
"move": "go forward",
|
| 2596 |
+
"view": "no-op"
|
| 2597 |
+
},
|
| 2598 |
+
{
|
| 2599 |
+
"move": "go forward",
|
| 2600 |
+
"view": "no-op"
|
| 2601 |
+
},
|
| 2602 |
+
{
|
| 2603 |
+
"move": "go forward",
|
| 2604 |
+
"view": "no-op"
|
| 2605 |
+
},
|
| 2606 |
+
{
|
| 2607 |
+
"move": "go forward",
|
| 2608 |
+
"view": "no-op"
|
| 2609 |
+
},
|
| 2610 |
+
{
|
| 2611 |
+
"move": "go forward",
|
| 2612 |
+
"view": "no-op"
|
| 2613 |
+
},
|
| 2614 |
+
{
|
| 2615 |
+
"move": "go forward",
|
| 2616 |
+
"view": "no-op"
|
| 2617 |
+
},
|
| 2618 |
+
{
|
| 2619 |
+
"move": "go forward",
|
| 2620 |
+
"view": "no-op"
|
| 2621 |
+
},
|
| 2622 |
+
{
|
| 2623 |
+
"move": "go forward",
|
| 2624 |
+
"view": "no-op"
|
| 2625 |
+
},
|
| 2626 |
+
{
|
| 2627 |
+
"move": "go forward",
|
| 2628 |
+
"view": "no-op"
|
| 2629 |
+
},
|
| 2630 |
+
{
|
| 2631 |
+
"move": "go forward",
|
| 2632 |
+
"view": "no-op"
|
| 2633 |
+
},
|
| 2634 |
+
{
|
| 2635 |
+
"move": "go forward",
|
| 2636 |
+
"view": "no-op"
|
| 2637 |
+
},
|
| 2638 |
+
{
|
| 2639 |
+
"move": "go forward",
|
| 2640 |
+
"view": "no-op"
|
| 2641 |
+
},
|
| 2642 |
+
{
|
| 2643 |
+
"move": "go forward",
|
| 2644 |
+
"view": "no-op"
|
| 2645 |
+
},
|
| 2646 |
+
{
|
| 2647 |
+
"move": "go forward",
|
| 2648 |
+
"view": "no-op"
|
| 2649 |
+
},
|
| 2650 |
+
{
|
| 2651 |
+
"move": "go forward",
|
| 2652 |
+
"view": "no-op"
|
| 2653 |
+
},
|
| 2654 |
+
{
|
| 2655 |
+
"move": "go forward",
|
| 2656 |
+
"view": "no-op"
|
| 2657 |
+
},
|
| 2658 |
+
{
|
| 2659 |
+
"move": "go forward",
|
| 2660 |
+
"view": "no-op"
|
| 2661 |
+
},
|
| 2662 |
+
{
|
| 2663 |
+
"move": "go forward",
|
| 2664 |
+
"view": "no-op"
|
| 2665 |
+
},
|
| 2666 |
+
{
|
| 2667 |
+
"move": "go forward",
|
| 2668 |
+
"view": "no-op"
|
| 2669 |
+
},
|
| 2670 |
+
{
|
| 2671 |
+
"move": "go forward",
|
| 2672 |
+
"view": "no-op"
|
| 2673 |
+
},
|
| 2674 |
+
{
|
| 2675 |
+
"move": "go forward",
|
| 2676 |
+
"view": "no-op"
|
| 2677 |
+
},
|
| 2678 |
+
{
|
| 2679 |
+
"move": "go forward",
|
| 2680 |
+
"view": "no-op"
|
| 2681 |
+
},
|
| 2682 |
+
{
|
| 2683 |
+
"move": "go forward",
|
| 2684 |
+
"view": "no-op"
|
| 2685 |
+
},
|
| 2686 |
+
{
|
| 2687 |
+
"move": "go forward",
|
| 2688 |
+
"view": "no-op"
|
| 2689 |
+
},
|
| 2690 |
+
{
|
| 2691 |
+
"move": "go forward",
|
| 2692 |
+
"view": "no-op"
|
| 2693 |
+
},
|
| 2694 |
+
{
|
| 2695 |
+
"move": "go forward",
|
| 2696 |
+
"view": "no-op"
|
| 2697 |
+
},
|
| 2698 |
+
{
|
| 2699 |
+
"move": "go forward",
|
| 2700 |
+
"view": "no-op"
|
| 2701 |
+
},
|
| 2702 |
+
{
|
| 2703 |
+
"move": "go forward",
|
| 2704 |
+
"view": "no-op"
|
| 2705 |
+
},
|
| 2706 |
+
{
|
| 2707 |
+
"move": "go forward",
|
| 2708 |
+
"view": "no-op"
|
| 2709 |
+
},
|
| 2710 |
+
{
|
| 2711 |
+
"move": "go forward",
|
| 2712 |
+
"view": "no-op"
|
| 2713 |
+
},
|
| 2714 |
+
{
|
| 2715 |
+
"move": "go forward",
|
| 2716 |
+
"view": "no-op"
|
| 2717 |
+
},
|
| 2718 |
+
{
|
| 2719 |
+
"move": "go forward",
|
| 2720 |
+
"view": "no-op"
|
| 2721 |
+
},
|
| 2722 |
+
{
|
| 2723 |
+
"move": "go forward",
|
| 2724 |
+
"view": "no-op"
|
| 2725 |
+
},
|
| 2726 |
+
{
|
| 2727 |
+
"move": "go forward",
|
| 2728 |
+
"view": "no-op"
|
| 2729 |
+
},
|
| 2730 |
+
{
|
| 2731 |
+
"move": "go forward",
|
| 2732 |
+
"view": "no-op"
|
| 2733 |
+
},
|
| 2734 |
+
{
|
| 2735 |
+
"move": "go forward",
|
| 2736 |
+
"view": "no-op"
|
| 2737 |
+
},
|
| 2738 |
+
{
|
| 2739 |
+
"move": "go forward",
|
| 2740 |
+
"view": "no-op"
|
| 2741 |
+
},
|
| 2742 |
+
{
|
| 2743 |
+
"move": "go forward",
|
| 2744 |
+
"view": "no-op"
|
| 2745 |
+
},
|
| 2746 |
+
{
|
| 2747 |
+
"move": "go forward",
|
| 2748 |
+
"view": "no-op"
|
| 2749 |
+
},
|
| 2750 |
+
{
|
| 2751 |
+
"move": "go forward",
|
| 2752 |
+
"view": "no-op"
|
| 2753 |
+
},
|
| 2754 |
+
{
|
| 2755 |
+
"move": "go forward",
|
| 2756 |
+
"view": "no-op"
|
| 2757 |
+
},
|
| 2758 |
+
{
|
| 2759 |
+
"move": "go forward",
|
| 2760 |
+
"view": "no-op"
|
| 2761 |
+
},
|
| 2762 |
+
{
|
| 2763 |
+
"move": "go forward",
|
| 2764 |
+
"view": "no-op"
|
| 2765 |
+
},
|
| 2766 |
+
{
|
| 2767 |
+
"move": "go forward",
|
| 2768 |
+
"view": "no-op"
|
| 2769 |
+
},
|
| 2770 |
+
{
|
| 2771 |
+
"move": "go forward",
|
| 2772 |
+
"view": "no-op"
|
| 2773 |
+
},
|
| 2774 |
+
{
|
| 2775 |
+
"move": "go forward",
|
| 2776 |
+
"view": "no-op"
|
| 2777 |
+
},
|
| 2778 |
+
{
|
| 2779 |
+
"move": "go forward",
|
| 2780 |
+
"view": "no-op"
|
| 2781 |
+
},
|
| 2782 |
+
{
|
| 2783 |
+
"move": "go forward",
|
| 2784 |
+
"view": "no-op"
|
| 2785 |
+
},
|
| 2786 |
+
{
|
| 2787 |
+
"move": "go forward",
|
| 2788 |
+
"view": "no-op"
|
| 2789 |
+
},
|
| 2790 |
+
{
|
| 2791 |
+
"move": "go forward",
|
| 2792 |
+
"view": "no-op"
|
| 2793 |
+
},
|
| 2794 |
+
{
|
| 2795 |
+
"move": "go forward",
|
| 2796 |
+
"view": "no-op"
|
| 2797 |
+
},
|
| 2798 |
+
{
|
| 2799 |
+
"move": "go forward",
|
| 2800 |
+
"view": "no-op"
|
| 2801 |
+
},
|
| 2802 |
+
{
|
| 2803 |
+
"move": "go forward",
|
| 2804 |
+
"view": "no-op"
|
| 2805 |
+
},
|
| 2806 |
+
{
|
| 2807 |
+
"move": "go forward",
|
| 2808 |
+
"view": "no-op"
|
| 2809 |
+
},
|
| 2810 |
+
{
|
| 2811 |
+
"move": "go forward",
|
| 2812 |
+
"view": "no-op"
|
| 2813 |
+
},
|
| 2814 |
+
{
|
| 2815 |
+
"move": "go forward",
|
| 2816 |
+
"view": "no-op"
|
| 2817 |
+
},
|
| 2818 |
+
{
|
| 2819 |
+
"move": "go forward",
|
| 2820 |
+
"view": "no-op"
|
| 2821 |
+
},
|
| 2822 |
+
{
|
| 2823 |
+
"move": "go forward",
|
| 2824 |
+
"view": "no-op"
|
| 2825 |
+
},
|
| 2826 |
+
{
|
| 2827 |
+
"move": "go forward",
|
| 2828 |
+
"view": "no-op"
|
| 2829 |
+
},
|
| 2830 |
+
{
|
| 2831 |
+
"move": "go forward",
|
| 2832 |
+
"view": "no-op"
|
| 2833 |
+
},
|
| 2834 |
+
{
|
| 2835 |
+
"move": "go forward",
|
| 2836 |
+
"view": "no-op"
|
| 2837 |
+
},
|
| 2838 |
+
{
|
| 2839 |
+
"move": "go forward",
|
| 2840 |
+
"view": "no-op"
|
| 2841 |
+
},
|
| 2842 |
+
{
|
| 2843 |
+
"move": "go forward",
|
| 2844 |
+
"view": "no-op"
|
| 2845 |
+
},
|
| 2846 |
+
{
|
| 2847 |
+
"move": "go forward",
|
| 2848 |
+
"view": "no-op"
|
| 2849 |
+
},
|
| 2850 |
+
{
|
| 2851 |
+
"move": "go forward",
|
| 2852 |
+
"view": "no-op"
|
| 2853 |
+
},
|
| 2854 |
+
{
|
| 2855 |
+
"move": "go forward",
|
| 2856 |
+
"view": "no-op"
|
| 2857 |
+
},
|
| 2858 |
+
{
|
| 2859 |
+
"move": "go forward",
|
| 2860 |
+
"view": "no-op"
|
| 2861 |
+
},
|
| 2862 |
+
{
|
| 2863 |
+
"move": "go forward",
|
| 2864 |
+
"view": "no-op"
|
| 2865 |
+
},
|
| 2866 |
+
{
|
| 2867 |
+
"move": "go forward",
|
| 2868 |
+
"view": "no-op"
|
| 2869 |
+
},
|
| 2870 |
+
{
|
| 2871 |
+
"move": "go forward",
|
| 2872 |
+
"view": "no-op"
|
| 2873 |
+
},
|
| 2874 |
+
{
|
| 2875 |
+
"move": "go forward",
|
| 2876 |
+
"view": "no-op"
|
| 2877 |
+
},
|
| 2878 |
+
{
|
| 2879 |
+
"move": "go forward",
|
| 2880 |
+
"view": "no-op"
|
| 2881 |
+
},
|
| 2882 |
+
{
|
| 2883 |
+
"move": "go forward",
|
| 2884 |
+
"view": "no-op"
|
| 2885 |
+
},
|
| 2886 |
+
{
|
| 2887 |
+
"move": "go forward",
|
| 2888 |
+
"view": "no-op"
|
| 2889 |
+
},
|
| 2890 |
+
{
|
| 2891 |
+
"move": "go forward",
|
| 2892 |
+
"view": "no-op"
|
| 2893 |
+
},
|
| 2894 |
+
{
|
| 2895 |
+
"move": "go forward",
|
| 2896 |
+
"view": "no-op"
|
| 2897 |
+
},
|
| 2898 |
+
{
|
| 2899 |
+
"move": "go forward",
|
| 2900 |
+
"view": "no-op"
|
| 2901 |
+
},
|
| 2902 |
+
{
|
| 2903 |
+
"move": "go forward",
|
| 2904 |
+
"view": "no-op"
|
| 2905 |
+
},
|
| 2906 |
+
{
|
| 2907 |
+
"move": "go forward",
|
| 2908 |
+
"view": "no-op"
|
| 2909 |
+
},
|
| 2910 |
+
{
|
| 2911 |
+
"move": "go forward",
|
| 2912 |
+
"view": "no-op"
|
| 2913 |
+
},
|
| 2914 |
+
{
|
| 2915 |
+
"move": "go forward",
|
| 2916 |
+
"view": "no-op"
|
| 2917 |
+
},
|
| 2918 |
+
{
|
| 2919 |
+
"move": "no-op",
|
| 2920 |
+
"view": "turn right"
|
| 2921 |
+
},
|
| 2922 |
+
{
|
| 2923 |
+
"move": "no-op",
|
| 2924 |
+
"view": "turn right"
|
| 2925 |
+
},
|
| 2926 |
+
{
|
| 2927 |
+
"move": "no-op",
|
| 2928 |
+
"view": "turn right"
|
| 2929 |
+
},
|
| 2930 |
+
{
|
| 2931 |
+
"move": "no-op",
|
| 2932 |
+
"view": "turn right"
|
| 2933 |
+
},
|
| 2934 |
+
{
|
| 2935 |
+
"move": "no-op",
|
| 2936 |
+
"view": "turn right"
|
| 2937 |
+
},
|
| 2938 |
+
{
|
| 2939 |
+
"move": "no-op",
|
| 2940 |
+
"view": "turn right"
|
| 2941 |
+
},
|
| 2942 |
+
{
|
| 2943 |
+
"move": "no-op",
|
| 2944 |
+
"view": "turn right"
|
| 2945 |
+
},
|
| 2946 |
+
{
|
| 2947 |
+
"move": "no-op",
|
| 2948 |
+
"view": "turn right"
|
| 2949 |
+
},
|
| 2950 |
+
{
|
| 2951 |
+
"move": "no-op",
|
| 2952 |
+
"view": "turn right"
|
| 2953 |
+
},
|
| 2954 |
+
{
|
| 2955 |
+
"move": "no-op",
|
| 2956 |
+
"view": "turn right"
|
| 2957 |
+
},
|
| 2958 |
+
{
|
| 2959 |
+
"move": "no-op",
|
| 2960 |
+
"view": "turn right"
|
| 2961 |
+
},
|
| 2962 |
+
{
|
| 2963 |
+
"move": "no-op",
|
| 2964 |
+
"view": "turn right"
|
| 2965 |
+
},
|
| 2966 |
+
{
|
| 2967 |
+
"move": "no-op",
|
| 2968 |
+
"view": "turn right"
|
| 2969 |
+
},
|
| 2970 |
+
{
|
| 2971 |
+
"move": "no-op",
|
| 2972 |
+
"view": "turn right"
|
| 2973 |
+
},
|
| 2974 |
+
{
|
| 2975 |
+
"move": "no-op",
|
| 2976 |
+
"view": "turn right"
|
| 2977 |
+
},
|
| 2978 |
+
{
|
| 2979 |
+
"move": "no-op",
|
| 2980 |
+
"view": "turn right"
|
| 2981 |
+
},
|
| 2982 |
+
{
|
| 2983 |
+
"move": "no-op",
|
| 2984 |
+
"view": "turn right"
|
| 2985 |
+
},
|
| 2986 |
+
{
|
| 2987 |
+
"move": "no-op",
|
| 2988 |
+
"view": "turn right"
|
| 2989 |
+
},
|
| 2990 |
+
{
|
| 2991 |
+
"move": "no-op",
|
| 2992 |
+
"view": "turn right"
|
| 2993 |
+
},
|
| 2994 |
+
{
|
| 2995 |
+
"move": "no-op",
|
| 2996 |
+
"view": "turn right"
|
| 2997 |
+
},
|
| 2998 |
+
{
|
| 2999 |
+
"move": "no-op",
|
| 3000 |
+
"view": "turn right"
|
| 3001 |
+
},
|
| 3002 |
+
{
|
| 3003 |
+
"move": "no-op",
|
| 3004 |
+
"view": "turn right"
|
| 3005 |
+
},
|
| 3006 |
+
{
|
| 3007 |
+
"move": "no-op",
|
| 3008 |
+
"view": "turn right"
|
| 3009 |
+
},
|
| 3010 |
+
{
|
| 3011 |
+
"move": "no-op",
|
| 3012 |
+
"view": "turn right"
|
| 3013 |
+
},
|
| 3014 |
+
{
|
| 3015 |
+
"move": "no-op",
|
| 3016 |
+
"view": "turn right"
|
| 3017 |
+
},
|
| 3018 |
+
{
|
| 3019 |
+
"move": "no-op",
|
| 3020 |
+
"view": "turn right"
|
| 3021 |
+
},
|
| 3022 |
+
{
|
| 3023 |
+
"move": "no-op",
|
| 3024 |
+
"view": "turn right"
|
| 3025 |
+
},
|
| 3026 |
+
{
|
| 3027 |
+
"move": "no-op",
|
| 3028 |
+
"view": "turn right"
|
| 3029 |
+
},
|
| 3030 |
+
{
|
| 3031 |
+
"move": "no-op",
|
| 3032 |
+
"view": "turn right"
|
| 3033 |
+
},
|
| 3034 |
+
{
|
| 3035 |
+
"move": "no-op",
|
| 3036 |
+
"view": "turn right"
|
| 3037 |
+
},
|
| 3038 |
+
{
|
| 3039 |
+
"move": "no-op",
|
| 3040 |
+
"view": "turn right"
|
| 3041 |
+
},
|
| 3042 |
+
{
|
| 3043 |
+
"move": "no-op",
|
| 3044 |
+
"view": "turn right"
|
| 3045 |
+
},
|
| 3046 |
+
{
|
| 3047 |
+
"move": "no-op",
|
| 3048 |
+
"view": "turn right"
|
| 3049 |
+
},
|
| 3050 |
+
{
|
| 3051 |
+
"move": "no-op",
|
| 3052 |
+
"view": "turn right"
|
| 3053 |
+
},
|
| 3054 |
+
{
|
| 3055 |
+
"move": "no-op",
|
| 3056 |
+
"view": "turn right"
|
| 3057 |
+
},
|
| 3058 |
+
{
|
| 3059 |
+
"move": "no-op",
|
| 3060 |
+
"view": "turn right"
|
| 3061 |
+
},
|
| 3062 |
+
{
|
| 3063 |
+
"move": "no-op",
|
| 3064 |
+
"view": "turn right"
|
| 3065 |
+
},
|
| 3066 |
+
{
|
| 3067 |
+
"move": "no-op",
|
| 3068 |
+
"view": "turn right"
|
| 3069 |
+
},
|
| 3070 |
+
{
|
| 3071 |
+
"move": "no-op",
|
| 3072 |
+
"view": "turn right"
|
| 3073 |
+
},
|
| 3074 |
+
{
|
| 3075 |
+
"move": "no-op",
|
| 3076 |
+
"view": "turn right"
|
| 3077 |
+
},
|
| 3078 |
+
{
|
| 3079 |
+
"move": "no-op",
|
| 3080 |
+
"view": "turn right"
|
| 3081 |
+
},
|
| 3082 |
+
{
|
| 3083 |
+
"move": "no-op",
|
| 3084 |
+
"view": "turn right"
|
| 3085 |
+
},
|
| 3086 |
+
{
|
| 3087 |
+
"move": "no-op",
|
| 3088 |
+
"view": "turn right"
|
| 3089 |
+
},
|
| 3090 |
+
{
|
| 3091 |
+
"move": "no-op",
|
| 3092 |
+
"view": "turn right"
|
| 3093 |
+
},
|
| 3094 |
+
{
|
| 3095 |
+
"move": "no-op",
|
| 3096 |
+
"view": "turn right"
|
| 3097 |
+
},
|
| 3098 |
+
{
|
| 3099 |
+
"move": "no-op",
|
| 3100 |
+
"view": "turn right"
|
| 3101 |
+
},
|
| 3102 |
+
{
|
| 3103 |
+
"move": "no-op",
|
| 3104 |
+
"view": "turn right"
|
| 3105 |
+
},
|
| 3106 |
+
{
|
| 3107 |
+
"move": "no-op",
|
| 3108 |
+
"view": "turn right"
|
| 3109 |
+
},
|
| 3110 |
+
{
|
| 3111 |
+
"move": "no-op",
|
| 3112 |
+
"view": "turn right"
|
| 3113 |
+
},
|
| 3114 |
+
{
|
| 3115 |
+
"move": "no-op",
|
| 3116 |
+
"view": "turn right"
|
| 3117 |
+
},
|
| 3118 |
+
{
|
| 3119 |
+
"move": "no-op",
|
| 3120 |
+
"view": "turn right"
|
| 3121 |
+
},
|
| 3122 |
+
{
|
| 3123 |
+
"move": "no-op",
|
| 3124 |
+
"view": "turn right"
|
| 3125 |
+
},
|
| 3126 |
+
{
|
| 3127 |
+
"move": "no-op",
|
| 3128 |
+
"view": "turn right"
|
| 3129 |
+
},
|
| 3130 |
+
{
|
| 3131 |
+
"move": "no-op",
|
| 3132 |
+
"view": "turn right"
|
| 3133 |
+
},
|
| 3134 |
+
{
|
| 3135 |
+
"move": "no-op",
|
| 3136 |
+
"view": "turn right"
|
| 3137 |
+
},
|
| 3138 |
+
{
|
| 3139 |
+
"move": "no-op",
|
| 3140 |
+
"view": "turn right"
|
| 3141 |
+
},
|
| 3142 |
+
{
|
| 3143 |
+
"move": "no-op",
|
| 3144 |
+
"view": "turn right"
|
| 3145 |
+
},
|
| 3146 |
+
{
|
| 3147 |
+
"move": "no-op",
|
| 3148 |
+
"view": "turn right"
|
| 3149 |
+
},
|
| 3150 |
+
{
|
| 3151 |
+
"move": "no-op",
|
| 3152 |
+
"view": "turn right"
|
| 3153 |
+
},
|
| 3154 |
+
{
|
| 3155 |
+
"move": "no-op",
|
| 3156 |
+
"view": "turn right"
|
| 3157 |
+
},
|
| 3158 |
+
{
|
| 3159 |
+
"move": "no-op",
|
| 3160 |
+
"view": "turn right"
|
| 3161 |
+
},
|
| 3162 |
+
{
|
| 3163 |
+
"move": "no-op",
|
| 3164 |
+
"view": "turn right"
|
| 3165 |
+
},
|
| 3166 |
+
{
|
| 3167 |
+
"move": "no-op",
|
| 3168 |
+
"view": "turn right"
|
| 3169 |
+
},
|
| 3170 |
+
{
|
| 3171 |
+
"move": "no-op",
|
| 3172 |
+
"view": "turn right"
|
| 3173 |
+
},
|
| 3174 |
+
{
|
| 3175 |
+
"move": "no-op",
|
| 3176 |
+
"view": "turn right"
|
| 3177 |
+
},
|
| 3178 |
+
{
|
| 3179 |
+
"move": "no-op",
|
| 3180 |
+
"view": "turn right"
|
| 3181 |
+
},
|
| 3182 |
+
{
|
| 3183 |
+
"move": "no-op",
|
| 3184 |
+
"view": "turn right"
|
| 3185 |
+
},
|
| 3186 |
+
{
|
| 3187 |
+
"move": "no-op",
|
| 3188 |
+
"view": "turn right"
|
| 3189 |
+
},
|
| 3190 |
+
{
|
| 3191 |
+
"move": "no-op",
|
| 3192 |
+
"view": "turn right"
|
| 3193 |
+
},
|
| 3194 |
+
{
|
| 3195 |
+
"move": "no-op",
|
| 3196 |
+
"view": "turn right"
|
| 3197 |
+
},
|
| 3198 |
+
{
|
| 3199 |
+
"move": "no-op",
|
| 3200 |
+
"view": "turn right"
|
| 3201 |
+
},
|
| 3202 |
+
{
|
| 3203 |
+
"move": "no-op",
|
| 3204 |
+
"view": "turn right"
|
| 3205 |
+
},
|
| 3206 |
+
{
|
| 3207 |
+
"move": "no-op",
|
| 3208 |
+
"view": "turn right"
|
| 3209 |
+
},
|
| 3210 |
+
{
|
| 3211 |
+
"move": "no-op",
|
| 3212 |
+
"view": "turn right"
|
| 3213 |
+
},
|
| 3214 |
+
{
|
| 3215 |
+
"move": "no-op",
|
| 3216 |
+
"view": "turn right"
|
| 3217 |
+
},
|
| 3218 |
+
{
|
| 3219 |
+
"move": "no-op",
|
| 3220 |
+
"view": "turn right"
|
| 3221 |
+
},
|
| 3222 |
+
{
|
| 3223 |
+
"move": "no-op",
|
| 3224 |
+
"view": "turn right"
|
| 3225 |
+
},
|
| 3226 |
+
{
|
| 3227 |
+
"move": "no-op",
|
| 3228 |
+
"view": "turn right"
|
| 3229 |
+
},
|
| 3230 |
+
{
|
| 3231 |
+
"move": "no-op",
|
| 3232 |
+
"view": "turn right"
|
| 3233 |
+
},
|
| 3234 |
+
{
|
| 3235 |
+
"move": "no-op",
|
| 3236 |
+
"view": "turn right"
|
| 3237 |
+
},
|
| 3238 |
+
{
|
| 3239 |
+
"move": "no-op",
|
| 3240 |
+
"view": "turn right"
|
| 3241 |
+
},
|
| 3242 |
+
{
|
| 3243 |
+
"move": "no-op",
|
| 3244 |
+
"view": "turn right"
|
| 3245 |
+
},
|
| 3246 |
+
{
|
| 3247 |
+
"move": "no-op",
|
| 3248 |
+
"view": "turn right"
|
| 3249 |
+
},
|
| 3250 |
+
{
|
| 3251 |
+
"move": "no-op",
|
| 3252 |
+
"view": "turn right"
|
| 3253 |
+
},
|
| 3254 |
+
{
|
| 3255 |
+
"move": "no-op",
|
| 3256 |
+
"view": "turn right"
|
| 3257 |
+
},
|
| 3258 |
+
{
|
| 3259 |
+
"move": "no-op",
|
| 3260 |
+
"view": "turn right"
|
| 3261 |
+
},
|
| 3262 |
+
{
|
| 3263 |
+
"move": "no-op",
|
| 3264 |
+
"view": "turn right"
|
| 3265 |
+
},
|
| 3266 |
+
{
|
| 3267 |
+
"move": "no-op",
|
| 3268 |
+
"view": "turn right"
|
| 3269 |
+
},
|
| 3270 |
+
{
|
| 3271 |
+
"move": "no-op",
|
| 3272 |
+
"view": "turn right"
|
| 3273 |
+
},
|
| 3274 |
+
{
|
| 3275 |
+
"move": "no-op",
|
| 3276 |
+
"view": "turn right"
|
| 3277 |
+
},
|
| 3278 |
+
{
|
| 3279 |
+
"move": "no-op",
|
| 3280 |
+
"view": "turn right"
|
| 3281 |
+
},
|
| 3282 |
+
{
|
| 3283 |
+
"move": "no-op",
|
| 3284 |
+
"view": "turn right"
|
| 3285 |
+
},
|
| 3286 |
+
{
|
| 3287 |
+
"move": "no-op",
|
| 3288 |
+
"view": "turn right"
|
| 3289 |
+
},
|
| 3290 |
+
{
|
| 3291 |
+
"move": "no-op",
|
| 3292 |
+
"view": "turn right"
|
| 3293 |
+
},
|
| 3294 |
+
{
|
| 3295 |
+
"move": "no-op",
|
| 3296 |
+
"view": "turn right"
|
| 3297 |
+
},
|
| 3298 |
+
{
|
| 3299 |
+
"move": "no-op",
|
| 3300 |
+
"view": "turn right"
|
| 3301 |
+
},
|
| 3302 |
+
{
|
| 3303 |
+
"move": "no-op",
|
| 3304 |
+
"view": "turn right"
|
| 3305 |
+
},
|
| 3306 |
+
{
|
| 3307 |
+
"move": "no-op",
|
| 3308 |
+
"view": "turn right"
|
| 3309 |
+
},
|
| 3310 |
+
{
|
| 3311 |
+
"move": "no-op",
|
| 3312 |
+
"view": "turn right"
|
| 3313 |
+
},
|
| 3314 |
+
{
|
| 3315 |
+
"move": "no-op",
|
| 3316 |
+
"view": "turn right"
|
| 3317 |
+
},
|
| 3318 |
+
{
|
| 3319 |
+
"move": "no-op",
|
| 3320 |
+
"view": "turn right"
|
| 3321 |
+
},
|
| 3322 |
+
{
|
| 3323 |
+
"move": "no-op",
|
| 3324 |
+
"view": "turn right"
|
| 3325 |
+
},
|
| 3326 |
+
{
|
| 3327 |
+
"move": "no-op",
|
| 3328 |
+
"view": "turn right"
|
| 3329 |
+
},
|
| 3330 |
+
{
|
| 3331 |
+
"move": "no-op",
|
| 3332 |
+
"view": "turn right"
|
| 3333 |
+
},
|
| 3334 |
+
{
|
| 3335 |
+
"move": "no-op",
|
| 3336 |
+
"view": "turn right"
|
| 3337 |
+
},
|
| 3338 |
+
{
|
| 3339 |
+
"move": "no-op",
|
| 3340 |
+
"view": "turn right"
|
| 3341 |
+
},
|
| 3342 |
+
{
|
| 3343 |
+
"move": "no-op",
|
| 3344 |
+
"view": "turn right"
|
| 3345 |
+
},
|
| 3346 |
+
{
|
| 3347 |
+
"move": "no-op",
|
| 3348 |
+
"view": "turn right"
|
| 3349 |
+
},
|
| 3350 |
+
{
|
| 3351 |
+
"move": "no-op",
|
| 3352 |
+
"view": "turn right"
|
| 3353 |
+
},
|
| 3354 |
+
{
|
| 3355 |
+
"move": "no-op",
|
| 3356 |
+
"view": "turn right"
|
| 3357 |
+
},
|
| 3358 |
+
{
|
| 3359 |
+
"move": "no-op",
|
| 3360 |
+
"view": "turn right"
|
| 3361 |
+
},
|
| 3362 |
+
{
|
| 3363 |
+
"move": "no-op",
|
| 3364 |
+
"view": "turn right"
|
| 3365 |
+
},
|
| 3366 |
+
{
|
| 3367 |
+
"move": "no-op",
|
| 3368 |
+
"view": "turn right"
|
| 3369 |
+
},
|
| 3370 |
+
{
|
| 3371 |
+
"move": "no-op",
|
| 3372 |
+
"view": "turn right"
|
| 3373 |
+
},
|
| 3374 |
+
{
|
| 3375 |
+
"move": "no-op",
|
| 3376 |
+
"view": "turn right"
|
| 3377 |
+
},
|
| 3378 |
+
{
|
| 3379 |
+
"move": "no-op",
|
| 3380 |
+
"view": "turn right"
|
| 3381 |
+
},
|
| 3382 |
+
{
|
| 3383 |
+
"move": "no-op",
|
| 3384 |
+
"view": "turn right"
|
| 3385 |
+
},
|
| 3386 |
+
{
|
| 3387 |
+
"move": "no-op",
|
| 3388 |
+
"view": "turn right"
|
| 3389 |
+
},
|
| 3390 |
+
{
|
| 3391 |
+
"move": "no-op",
|
| 3392 |
+
"view": "turn right"
|
| 3393 |
+
},
|
| 3394 |
+
{
|
| 3395 |
+
"move": "no-op",
|
| 3396 |
+
"view": "turn right"
|
| 3397 |
+
},
|
| 3398 |
+
{
|
| 3399 |
+
"move": "no-op",
|
| 3400 |
+
"view": "turn right"
|
| 3401 |
+
},
|
| 3402 |
+
{
|
| 3403 |
+
"move": "no-op",
|
| 3404 |
+
"view": "turn right"
|
| 3405 |
+
},
|
| 3406 |
+
{
|
| 3407 |
+
"move": "no-op",
|
| 3408 |
+
"view": "turn right"
|
| 3409 |
+
},
|
| 3410 |
+
{
|
| 3411 |
+
"move": "no-op",
|
| 3412 |
+
"view": "turn right"
|
| 3413 |
+
},
|
| 3414 |
+
{
|
| 3415 |
+
"move": "no-op",
|
| 3416 |
+
"view": "turn right"
|
| 3417 |
+
},
|
| 3418 |
+
{
|
| 3419 |
+
"move": "no-op",
|
| 3420 |
+
"view": "turn right"
|
| 3421 |
+
},
|
| 3422 |
+
{
|
| 3423 |
+
"move": "no-op",
|
| 3424 |
+
"view": "turn right"
|
| 3425 |
+
},
|
| 3426 |
+
{
|
| 3427 |
+
"move": "no-op",
|
| 3428 |
+
"view": "turn right"
|
| 3429 |
+
},
|
| 3430 |
+
{
|
| 3431 |
+
"move": "no-op",
|
| 3432 |
+
"view": "turn right"
|
| 3433 |
+
},
|
| 3434 |
+
{
|
| 3435 |
+
"move": "no-op",
|
| 3436 |
+
"view": "turn right"
|
| 3437 |
+
},
|
| 3438 |
+
{
|
| 3439 |
+
"move": "no-op",
|
| 3440 |
+
"view": "turn right"
|
| 3441 |
+
},
|
| 3442 |
+
{
|
| 3443 |
+
"move": "no-op",
|
| 3444 |
+
"view": "turn right"
|
| 3445 |
+
},
|
| 3446 |
+
{
|
| 3447 |
+
"move": "no-op",
|
| 3448 |
+
"view": "turn right"
|
| 3449 |
+
},
|
| 3450 |
+
{
|
| 3451 |
+
"move": "no-op",
|
| 3452 |
+
"view": "turn right"
|
| 3453 |
+
},
|
| 3454 |
+
{
|
| 3455 |
+
"move": "no-op",
|
| 3456 |
+
"view": "turn right"
|
| 3457 |
+
},
|
| 3458 |
+
{
|
| 3459 |
+
"move": "no-op",
|
| 3460 |
+
"view": "turn right"
|
| 3461 |
+
},
|
| 3462 |
+
{
|
| 3463 |
+
"move": "no-op",
|
| 3464 |
+
"view": "turn right"
|
| 3465 |
+
},
|
| 3466 |
+
{
|
| 3467 |
+
"move": "no-op",
|
| 3468 |
+
"view": "turn right"
|
| 3469 |
+
},
|
| 3470 |
+
{
|
| 3471 |
+
"move": "no-op",
|
| 3472 |
+
"view": "turn right"
|
| 3473 |
+
},
|
| 3474 |
+
{
|
| 3475 |
+
"move": "no-op",
|
| 3476 |
+
"view": "turn right"
|
| 3477 |
+
},
|
| 3478 |
+
{
|
| 3479 |
+
"move": "no-op",
|
| 3480 |
+
"view": "turn right"
|
| 3481 |
+
},
|
| 3482 |
+
{
|
| 3483 |
+
"move": "no-op",
|
| 3484 |
+
"view": "turn right"
|
| 3485 |
+
},
|
| 3486 |
+
{
|
| 3487 |
+
"move": "no-op",
|
| 3488 |
+
"view": "turn right"
|
| 3489 |
+
},
|
| 3490 |
+
{
|
| 3491 |
+
"move": "no-op",
|
| 3492 |
+
"view": "turn right"
|
| 3493 |
+
},
|
| 3494 |
+
{
|
| 3495 |
+
"move": "no-op",
|
| 3496 |
+
"view": "turn right"
|
| 3497 |
+
},
|
| 3498 |
+
{
|
| 3499 |
+
"move": "no-op",
|
| 3500 |
+
"view": "turn right"
|
| 3501 |
+
},
|
| 3502 |
+
{
|
| 3503 |
+
"move": "no-op",
|
| 3504 |
+
"view": "turn right"
|
| 3505 |
+
},
|
| 3506 |
+
{
|
| 3507 |
+
"move": "no-op",
|
| 3508 |
+
"view": "turn right"
|
| 3509 |
+
},
|
| 3510 |
+
{
|
| 3511 |
+
"move": "no-op",
|
| 3512 |
+
"view": "turn right"
|
| 3513 |
+
},
|
| 3514 |
+
{
|
| 3515 |
+
"move": "no-op",
|
| 3516 |
+
"view": "turn right"
|
| 3517 |
+
},
|
| 3518 |
+
{
|
| 3519 |
+
"move": "no-op",
|
| 3520 |
+
"view": "turn right"
|
| 3521 |
+
},
|
| 3522 |
+
{
|
| 3523 |
+
"move": "no-op",
|
| 3524 |
+
"view": "turn right"
|
| 3525 |
+
},
|
| 3526 |
+
{
|
| 3527 |
+
"move": "no-op",
|
| 3528 |
+
"view": "turn right"
|
| 3529 |
+
},
|
| 3530 |
+
{
|
| 3531 |
+
"move": "no-op",
|
| 3532 |
+
"view": "turn right"
|
| 3533 |
+
},
|
| 3534 |
+
{
|
| 3535 |
+
"move": "no-op",
|
| 3536 |
+
"view": "turn right"
|
| 3537 |
+
},
|
| 3538 |
+
{
|
| 3539 |
+
"move": "no-op",
|
| 3540 |
+
"view": "turn right"
|
| 3541 |
+
},
|
| 3542 |
+
{
|
| 3543 |
+
"move": "no-op",
|
| 3544 |
+
"view": "turn right"
|
| 3545 |
+
},
|
| 3546 |
+
{
|
| 3547 |
+
"move": "no-op",
|
| 3548 |
+
"view": "turn right"
|
| 3549 |
+
},
|
| 3550 |
+
{
|
| 3551 |
+
"move": "no-op",
|
| 3552 |
+
"view": "turn right"
|
| 3553 |
+
},
|
| 3554 |
+
{
|
| 3555 |
+
"move": "no-op",
|
| 3556 |
+
"view": "turn right"
|
| 3557 |
+
},
|
| 3558 |
+
{
|
| 3559 |
+
"move": "no-op",
|
| 3560 |
+
"view": "turn right"
|
| 3561 |
+
},
|
| 3562 |
+
{
|
| 3563 |
+
"move": "no-op",
|
| 3564 |
+
"view": "turn right"
|
| 3565 |
+
},
|
| 3566 |
+
{
|
| 3567 |
+
"move": "go forward",
|
| 3568 |
+
"view": "no-op"
|
| 3569 |
+
},
|
| 3570 |
+
{
|
| 3571 |
+
"move": "go forward",
|
| 3572 |
+
"view": "no-op"
|
| 3573 |
+
},
|
| 3574 |
+
{
|
| 3575 |
+
"move": "go forward",
|
| 3576 |
+
"view": "no-op"
|
| 3577 |
+
},
|
| 3578 |
+
{
|
| 3579 |
+
"move": "go forward",
|
| 3580 |
+
"view": "no-op"
|
| 3581 |
+
},
|
| 3582 |
+
{
|
| 3583 |
+
"move": "go forward",
|
| 3584 |
+
"view": "no-op"
|
| 3585 |
+
},
|
| 3586 |
+
{
|
| 3587 |
+
"move": "go forward",
|
| 3588 |
+
"view": "no-op"
|
| 3589 |
+
},
|
| 3590 |
+
{
|
| 3591 |
+
"move": "go forward",
|
| 3592 |
+
"view": "no-op"
|
| 3593 |
+
},
|
| 3594 |
+
{
|
| 3595 |
+
"move": "go forward",
|
| 3596 |
+
"view": "no-op"
|
| 3597 |
+
},
|
| 3598 |
+
{
|
| 3599 |
+
"move": "go forward",
|
| 3600 |
+
"view": "no-op"
|
| 3601 |
+
},
|
| 3602 |
+
{
|
| 3603 |
+
"move": "go forward",
|
| 3604 |
+
"view": "no-op"
|
| 3605 |
+
},
|
| 3606 |
+
{
|
| 3607 |
+
"move": "go forward",
|
| 3608 |
+
"view": "no-op"
|
| 3609 |
+
},
|
| 3610 |
+
{
|
| 3611 |
+
"move": "go forward",
|
| 3612 |
+
"view": "no-op"
|
| 3613 |
+
},
|
| 3614 |
+
{
|
| 3615 |
+
"move": "go forward",
|
| 3616 |
+
"view": "no-op"
|
| 3617 |
+
},
|
| 3618 |
+
{
|
| 3619 |
+
"move": "go forward",
|
| 3620 |
+
"view": "no-op"
|
| 3621 |
+
},
|
| 3622 |
+
{
|
| 3623 |
+
"move": "go forward",
|
| 3624 |
+
"view": "no-op"
|
| 3625 |
+
},
|
| 3626 |
+
{
|
| 3627 |
+
"move": "go forward",
|
| 3628 |
+
"view": "no-op"
|
| 3629 |
+
},
|
| 3630 |
+
{
|
| 3631 |
+
"move": "go forward",
|
| 3632 |
+
"view": "no-op"
|
| 3633 |
+
},
|
| 3634 |
+
{
|
| 3635 |
+
"move": "go forward",
|
| 3636 |
+
"view": "no-op"
|
| 3637 |
+
},
|
| 3638 |
+
{
|
| 3639 |
+
"move": "go forward",
|
| 3640 |
+
"view": "no-op"
|
| 3641 |
+
},
|
| 3642 |
+
{
|
| 3643 |
+
"move": "go forward",
|
| 3644 |
+
"view": "no-op"
|
| 3645 |
+
},
|
| 3646 |
+
{
|
| 3647 |
+
"move": "go forward",
|
| 3648 |
+
"view": "no-op"
|
| 3649 |
+
},
|
| 3650 |
+
{
|
| 3651 |
+
"move": "go forward",
|
| 3652 |
+
"view": "no-op"
|
| 3653 |
+
},
|
| 3654 |
+
{
|
| 3655 |
+
"move": "go forward",
|
| 3656 |
+
"view": "no-op"
|
| 3657 |
+
},
|
| 3658 |
+
{
|
| 3659 |
+
"move": "go forward",
|
| 3660 |
+
"view": "no-op"
|
| 3661 |
+
},
|
| 3662 |
+
{
|
| 3663 |
+
"move": "go forward",
|
| 3664 |
+
"view": "no-op"
|
| 3665 |
+
},
|
| 3666 |
+
{
|
| 3667 |
+
"move": "go forward",
|
| 3668 |
+
"view": "no-op"
|
| 3669 |
+
},
|
| 3670 |
+
{
|
| 3671 |
+
"move": "go forward",
|
| 3672 |
+
"view": "no-op"
|
| 3673 |
+
},
|
| 3674 |
+
{
|
| 3675 |
+
"move": "go forward",
|
| 3676 |
+
"view": "no-op"
|
| 3677 |
+
},
|
| 3678 |
+
{
|
| 3679 |
+
"move": "go forward",
|
| 3680 |
+
"view": "no-op"
|
| 3681 |
+
},
|
| 3682 |
+
{
|
| 3683 |
+
"move": "go forward",
|
| 3684 |
+
"view": "no-op"
|
| 3685 |
+
},
|
| 3686 |
+
{
|
| 3687 |
+
"move": "go forward",
|
| 3688 |
+
"view": "no-op"
|
| 3689 |
+
},
|
| 3690 |
+
{
|
| 3691 |
+
"move": "go forward",
|
| 3692 |
+
"view": "no-op"
|
| 3693 |
+
},
|
| 3694 |
+
{
|
| 3695 |
+
"move": "go forward",
|
| 3696 |
+
"view": "no-op"
|
| 3697 |
+
},
|
| 3698 |
+
{
|
| 3699 |
+
"move": "go forward",
|
| 3700 |
+
"view": "no-op"
|
| 3701 |
+
},
|
| 3702 |
+
{
|
| 3703 |
+
"move": "go forward",
|
| 3704 |
+
"view": "no-op"
|
| 3705 |
+
},
|
| 3706 |
+
{
|
| 3707 |
+
"move": "go forward",
|
| 3708 |
+
"view": "no-op"
|
| 3709 |
+
},
|
| 3710 |
+
{
|
| 3711 |
+
"move": "go forward",
|
| 3712 |
+
"view": "no-op"
|
| 3713 |
+
},
|
| 3714 |
+
{
|
| 3715 |
+
"move": "go forward",
|
| 3716 |
+
"view": "no-op"
|
| 3717 |
+
},
|
| 3718 |
+
{
|
| 3719 |
+
"move": "go forward",
|
| 3720 |
+
"view": "no-op"
|
| 3721 |
+
},
|
| 3722 |
+
{
|
| 3723 |
+
"move": "go forward",
|
| 3724 |
+
"view": "no-op"
|
| 3725 |
+
},
|
| 3726 |
+
{
|
| 3727 |
+
"move": "go forward",
|
| 3728 |
+
"view": "no-op"
|
| 3729 |
+
},
|
| 3730 |
+
{
|
| 3731 |
+
"move": "go forward",
|
| 3732 |
+
"view": "no-op"
|
| 3733 |
+
},
|
| 3734 |
+
{
|
| 3735 |
+
"move": "go forward",
|
| 3736 |
+
"view": "no-op"
|
| 3737 |
+
},
|
| 3738 |
+
{
|
| 3739 |
+
"move": "go forward",
|
| 3740 |
+
"view": "no-op"
|
| 3741 |
+
},
|
| 3742 |
+
{
|
| 3743 |
+
"move": "go forward",
|
| 3744 |
+
"view": "no-op"
|
| 3745 |
+
},
|
| 3746 |
+
{
|
| 3747 |
+
"move": "go forward",
|
| 3748 |
+
"view": "no-op"
|
| 3749 |
+
},
|
| 3750 |
+
{
|
| 3751 |
+
"move": "go forward",
|
| 3752 |
+
"view": "no-op"
|
| 3753 |
+
},
|
| 3754 |
+
{
|
| 3755 |
+
"move": "go forward",
|
| 3756 |
+
"view": "no-op"
|
| 3757 |
+
},
|
| 3758 |
+
{
|
| 3759 |
+
"move": "go forward",
|
| 3760 |
+
"view": "no-op"
|
| 3761 |
+
},
|
| 3762 |
+
{
|
| 3763 |
+
"move": "go forward",
|
| 3764 |
+
"view": "no-op"
|
| 3765 |
+
},
|
| 3766 |
+
{
|
| 3767 |
+
"move": "go forward",
|
| 3768 |
+
"view": "no-op"
|
| 3769 |
+
},
|
| 3770 |
+
{
|
| 3771 |
+
"move": "go forward",
|
| 3772 |
+
"view": "no-op"
|
| 3773 |
+
},
|
| 3774 |
+
{
|
| 3775 |
+
"move": "go forward",
|
| 3776 |
+
"view": "no-op"
|
| 3777 |
+
},
|
| 3778 |
+
{
|
| 3779 |
+
"move": "go forward",
|
| 3780 |
+
"view": "no-op"
|
| 3781 |
+
},
|
| 3782 |
+
{
|
| 3783 |
+
"move": "go forward",
|
| 3784 |
+
"view": "no-op"
|
| 3785 |
+
},
|
| 3786 |
+
{
|
| 3787 |
+
"move": "go forward",
|
| 3788 |
+
"view": "no-op"
|
| 3789 |
+
},
|
| 3790 |
+
{
|
| 3791 |
+
"move": "go forward",
|
| 3792 |
+
"view": "no-op"
|
| 3793 |
+
},
|
| 3794 |
+
{
|
| 3795 |
+
"move": "go forward",
|
| 3796 |
+
"view": "no-op"
|
| 3797 |
+
},
|
| 3798 |
+
{
|
| 3799 |
+
"move": "go forward",
|
| 3800 |
+
"view": "no-op"
|
| 3801 |
+
},
|
| 3802 |
+
{
|
| 3803 |
+
"move": "go forward",
|
| 3804 |
+
"view": "no-op"
|
| 3805 |
+
},
|
| 3806 |
+
{
|
| 3807 |
+
"move": "go forward",
|
| 3808 |
+
"view": "no-op"
|
| 3809 |
+
},
|
| 3810 |
+
{
|
| 3811 |
+
"move": "go forward",
|
| 3812 |
+
"view": "no-op"
|
| 3813 |
+
},
|
| 3814 |
+
{
|
| 3815 |
+
"move": "go forward",
|
| 3816 |
+
"view": "no-op"
|
| 3817 |
+
},
|
| 3818 |
+
{
|
| 3819 |
+
"move": "go forward",
|
| 3820 |
+
"view": "no-op"
|
| 3821 |
+
},
|
| 3822 |
+
{
|
| 3823 |
+
"move": "go forward",
|
| 3824 |
+
"view": "no-op"
|
| 3825 |
+
},
|
| 3826 |
+
{
|
| 3827 |
+
"move": "go forward",
|
| 3828 |
+
"view": "no-op"
|
| 3829 |
+
},
|
| 3830 |
+
{
|
| 3831 |
+
"move": "go forward",
|
| 3832 |
+
"view": "no-op"
|
| 3833 |
+
},
|
| 3834 |
+
{
|
| 3835 |
+
"move": "go forward",
|
| 3836 |
+
"view": "no-op"
|
| 3837 |
+
},
|
| 3838 |
+
{
|
| 3839 |
+
"move": "go forward",
|
| 3840 |
+
"view": "no-op"
|
| 3841 |
+
},
|
| 3842 |
+
{
|
| 3843 |
+
"move": "go forward",
|
| 3844 |
+
"view": "no-op"
|
| 3845 |
+
},
|
| 3846 |
+
{
|
| 3847 |
+
"move": "go forward",
|
| 3848 |
+
"view": "no-op"
|
| 3849 |
+
},
|
| 3850 |
+
{
|
| 3851 |
+
"move": "go forward",
|
| 3852 |
+
"view": "no-op"
|
| 3853 |
+
},
|
| 3854 |
+
{
|
| 3855 |
+
"move": "go forward",
|
| 3856 |
+
"view": "no-op"
|
| 3857 |
+
},
|
| 3858 |
+
{
|
| 3859 |
+
"move": "go forward",
|
| 3860 |
+
"view": "no-op"
|
| 3861 |
+
},
|
| 3862 |
+
{
|
| 3863 |
+
"move": "go forward",
|
| 3864 |
+
"view": "no-op"
|
| 3865 |
+
},
|
| 3866 |
+
{
|
| 3867 |
+
"move": "go forward",
|
| 3868 |
+
"view": "no-op"
|
| 3869 |
+
},
|
| 3870 |
+
{
|
| 3871 |
+
"move": "go forward",
|
| 3872 |
+
"view": "no-op"
|
| 3873 |
+
},
|
| 3874 |
+
{
|
| 3875 |
+
"move": "go forward",
|
| 3876 |
+
"view": "no-op"
|
| 3877 |
+
},
|
| 3878 |
+
{
|
| 3879 |
+
"move": "go forward",
|
| 3880 |
+
"view": "no-op"
|
| 3881 |
+
},
|
| 3882 |
+
{
|
| 3883 |
+
"move": "go forward",
|
| 3884 |
+
"view": "no-op"
|
| 3885 |
+
},
|
| 3886 |
+
{
|
| 3887 |
+
"move": "go forward",
|
| 3888 |
+
"view": "no-op"
|
| 3889 |
+
},
|
| 3890 |
+
{
|
| 3891 |
+
"move": "go forward",
|
| 3892 |
+
"view": "no-op"
|
| 3893 |
+
},
|
| 3894 |
+
{
|
| 3895 |
+
"move": "go forward",
|
| 3896 |
+
"view": "no-op"
|
| 3897 |
+
},
|
| 3898 |
+
{
|
| 3899 |
+
"move": "go forward",
|
| 3900 |
+
"view": "no-op"
|
| 3901 |
+
},
|
| 3902 |
+
{
|
| 3903 |
+
"move": "go forward",
|
| 3904 |
+
"view": "no-op"
|
| 3905 |
+
},
|
| 3906 |
+
{
|
| 3907 |
+
"move": "go forward",
|
| 3908 |
+
"view": "no-op"
|
| 3909 |
+
},
|
| 3910 |
+
{
|
| 3911 |
+
"move": "go forward",
|
| 3912 |
+
"view": "no-op"
|
| 3913 |
+
},
|
| 3914 |
+
{
|
| 3915 |
+
"move": "go forward",
|
| 3916 |
+
"view": "no-op"
|
| 3917 |
+
},
|
| 3918 |
+
{
|
| 3919 |
+
"move": "go forward",
|
| 3920 |
+
"view": "no-op"
|
| 3921 |
+
},
|
| 3922 |
+
{
|
| 3923 |
+
"move": "go forward",
|
| 3924 |
+
"view": "no-op"
|
| 3925 |
+
},
|
| 3926 |
+
{
|
| 3927 |
+
"move": "go forward",
|
| 3928 |
+
"view": "no-op"
|
| 3929 |
+
},
|
| 3930 |
+
{
|
| 3931 |
+
"move": "go forward",
|
| 3932 |
+
"view": "no-op"
|
| 3933 |
+
},
|
| 3934 |
+
{
|
| 3935 |
+
"move": "go forward",
|
| 3936 |
+
"view": "no-op"
|
| 3937 |
+
},
|
| 3938 |
+
{
|
| 3939 |
+
"move": "go forward",
|
| 3940 |
+
"view": "no-op"
|
| 3941 |
+
},
|
| 3942 |
+
{
|
| 3943 |
+
"move": "go forward",
|
| 3944 |
+
"view": "no-op"
|
| 3945 |
+
},
|
| 3946 |
+
{
|
| 3947 |
+
"move": "go forward",
|
| 3948 |
+
"view": "no-op"
|
| 3949 |
+
},
|
| 3950 |
+
{
|
| 3951 |
+
"move": "go forward",
|
| 3952 |
+
"view": "no-op"
|
| 3953 |
+
},
|
| 3954 |
+
{
|
| 3955 |
+
"move": "go forward",
|
| 3956 |
+
"view": "no-op"
|
| 3957 |
+
},
|
| 3958 |
+
{
|
| 3959 |
+
"move": "go forward",
|
| 3960 |
+
"view": "no-op"
|
| 3961 |
+
},
|
| 3962 |
+
{
|
| 3963 |
+
"move": "go forward",
|
| 3964 |
+
"view": "no-op"
|
| 3965 |
+
},
|
| 3966 |
+
{
|
| 3967 |
+
"move": "go forward",
|
| 3968 |
+
"view": "no-op"
|
| 3969 |
+
},
|
| 3970 |
+
{
|
| 3971 |
+
"move": "go forward",
|
| 3972 |
+
"view": "no-op"
|
| 3973 |
+
},
|
| 3974 |
+
{
|
| 3975 |
+
"move": "go forward",
|
| 3976 |
+
"view": "no-op"
|
| 3977 |
+
},
|
| 3978 |
+
{
|
| 3979 |
+
"move": "go forward",
|
| 3980 |
+
"view": "no-op"
|
| 3981 |
+
},
|
| 3982 |
+
{
|
| 3983 |
+
"move": "go forward",
|
| 3984 |
+
"view": "no-op"
|
| 3985 |
+
},
|
| 3986 |
+
{
|
| 3987 |
+
"move": "go forward",
|
| 3988 |
+
"view": "no-op"
|
| 3989 |
+
},
|
| 3990 |
+
{
|
| 3991 |
+
"move": "go forward",
|
| 3992 |
+
"view": "no-op"
|
| 3993 |
+
},
|
| 3994 |
+
{
|
| 3995 |
+
"move": "go forward",
|
| 3996 |
+
"view": "no-op"
|
| 3997 |
+
},
|
| 3998 |
+
{
|
| 3999 |
+
"move": "go forward",
|
| 4000 |
+
"view": "no-op"
|
| 4001 |
+
},
|
| 4002 |
+
{
|
| 4003 |
+
"move": "go forward",
|
| 4004 |
+
"view": "no-op"
|
| 4005 |
+
},
|
| 4006 |
+
{
|
| 4007 |
+
"move": "go forward",
|
| 4008 |
+
"view": "no-op"
|
| 4009 |
+
},
|
| 4010 |
+
{
|
| 4011 |
+
"move": "go forward",
|
| 4012 |
+
"view": "no-op"
|
| 4013 |
+
},
|
| 4014 |
+
{
|
| 4015 |
+
"move": "go forward",
|
| 4016 |
+
"view": "no-op"
|
| 4017 |
+
},
|
| 4018 |
+
{
|
| 4019 |
+
"move": "go forward",
|
| 4020 |
+
"view": "no-op"
|
| 4021 |
+
},
|
| 4022 |
+
{
|
| 4023 |
+
"move": "go forward",
|
| 4024 |
+
"view": "no-op"
|
| 4025 |
+
},
|
| 4026 |
+
{
|
| 4027 |
+
"move": "go forward",
|
| 4028 |
+
"view": "no-op"
|
| 4029 |
+
},
|
| 4030 |
+
{
|
| 4031 |
+
"move": "go forward",
|
| 4032 |
+
"view": "no-op"
|
| 4033 |
+
},
|
| 4034 |
+
{
|
| 4035 |
+
"move": "go forward",
|
| 4036 |
+
"view": "no-op"
|
| 4037 |
+
},
|
| 4038 |
+
{
|
| 4039 |
+
"move": "go forward",
|
| 4040 |
+
"view": "no-op"
|
| 4041 |
+
},
|
| 4042 |
+
{
|
| 4043 |
+
"move": "go forward",
|
| 4044 |
+
"view": "no-op"
|
| 4045 |
+
},
|
| 4046 |
+
{
|
| 4047 |
+
"move": "go forward",
|
| 4048 |
+
"view": "no-op"
|
| 4049 |
+
},
|
| 4050 |
+
{
|
| 4051 |
+
"move": "go forward",
|
| 4052 |
+
"view": "no-op"
|
| 4053 |
+
},
|
| 4054 |
+
{
|
| 4055 |
+
"move": "go forward",
|
| 4056 |
+
"view": "no-op"
|
| 4057 |
+
},
|
| 4058 |
+
{
|
| 4059 |
+
"move": "go forward",
|
| 4060 |
+
"view": "no-op"
|
| 4061 |
+
},
|
| 4062 |
+
{
|
| 4063 |
+
"move": "go forward",
|
| 4064 |
+
"view": "no-op"
|
| 4065 |
+
},
|
| 4066 |
+
{
|
| 4067 |
+
"move": "go forward",
|
| 4068 |
+
"view": "no-op"
|
| 4069 |
+
},
|
| 4070 |
+
{
|
| 4071 |
+
"move": "go forward",
|
| 4072 |
+
"view": "no-op"
|
| 4073 |
+
},
|
| 4074 |
+
{
|
| 4075 |
+
"move": "go forward",
|
| 4076 |
+
"view": "no-op"
|
| 4077 |
+
},
|
| 4078 |
+
{
|
| 4079 |
+
"move": "go forward",
|
| 4080 |
+
"view": "no-op"
|
| 4081 |
+
},
|
| 4082 |
+
{
|
| 4083 |
+
"move": "go forward",
|
| 4084 |
+
"view": "no-op"
|
| 4085 |
+
},
|
| 4086 |
+
{
|
| 4087 |
+
"move": "go forward",
|
| 4088 |
+
"view": "no-op"
|
| 4089 |
+
},
|
| 4090 |
+
{
|
| 4091 |
+
"move": "go forward",
|
| 4092 |
+
"view": "no-op"
|
| 4093 |
+
},
|
| 4094 |
+
{
|
| 4095 |
+
"move": "go forward",
|
| 4096 |
+
"view": "no-op"
|
| 4097 |
+
},
|
| 4098 |
+
{
|
| 4099 |
+
"move": "go forward",
|
| 4100 |
+
"view": "no-op"
|
| 4101 |
+
},
|
| 4102 |
+
{
|
| 4103 |
+
"move": "go forward",
|
| 4104 |
+
"view": "no-op"
|
| 4105 |
+
},
|
| 4106 |
+
{
|
| 4107 |
+
"move": "go forward",
|
| 4108 |
+
"view": "no-op"
|
| 4109 |
+
},
|
| 4110 |
+
{
|
| 4111 |
+
"move": "go forward",
|
| 4112 |
+
"view": "no-op"
|
| 4113 |
+
},
|
| 4114 |
+
{
|
| 4115 |
+
"move": "go forward",
|
| 4116 |
+
"view": "no-op"
|
| 4117 |
+
},
|
| 4118 |
+
{
|
| 4119 |
+
"move": "go forward",
|
| 4120 |
+
"view": "no-op"
|
| 4121 |
+
},
|
| 4122 |
+
{
|
| 4123 |
+
"move": "go forward",
|
| 4124 |
+
"view": "no-op"
|
| 4125 |
+
},
|
| 4126 |
+
{
|
| 4127 |
+
"move": "go forward",
|
| 4128 |
+
"view": "no-op"
|
| 4129 |
+
},
|
| 4130 |
+
{
|
| 4131 |
+
"move": "go forward",
|
| 4132 |
+
"view": "no-op"
|
| 4133 |
+
},
|
| 4134 |
+
{
|
| 4135 |
+
"move": "go forward",
|
| 4136 |
+
"view": "no-op"
|
| 4137 |
+
},
|
| 4138 |
+
{
|
| 4139 |
+
"move": "go forward",
|
| 4140 |
+
"view": "no-op"
|
| 4141 |
+
},
|
| 4142 |
+
{
|
| 4143 |
+
"move": "go forward",
|
| 4144 |
+
"view": "no-op"
|
| 4145 |
+
},
|
| 4146 |
+
{
|
| 4147 |
+
"move": "go forward",
|
| 4148 |
+
"view": "no-op"
|
| 4149 |
+
},
|
| 4150 |
+
{
|
| 4151 |
+
"move": "go forward",
|
| 4152 |
+
"view": "no-op"
|
| 4153 |
+
},
|
| 4154 |
+
{
|
| 4155 |
+
"move": "go forward",
|
| 4156 |
+
"view": "no-op"
|
| 4157 |
+
},
|
| 4158 |
+
{
|
| 4159 |
+
"move": "go forward",
|
| 4160 |
+
"view": "no-op"
|
| 4161 |
+
},
|
| 4162 |
+
{
|
| 4163 |
+
"move": "go forward",
|
| 4164 |
+
"view": "no-op"
|
| 4165 |
+
},
|
| 4166 |
+
{
|
| 4167 |
+
"move": "go forward",
|
| 4168 |
+
"view": "no-op"
|
| 4169 |
+
},
|
| 4170 |
+
{
|
| 4171 |
+
"move": "go forward",
|
| 4172 |
+
"view": "no-op"
|
| 4173 |
+
},
|
| 4174 |
+
{
|
| 4175 |
+
"move": "go forward",
|
| 4176 |
+
"view": "no-op"
|
| 4177 |
+
},
|
| 4178 |
+
{
|
| 4179 |
+
"move": "go forward",
|
| 4180 |
+
"view": "no-op"
|
| 4181 |
+
},
|
| 4182 |
+
{
|
| 4183 |
+
"move": "go forward",
|
| 4184 |
+
"view": "no-op"
|
| 4185 |
+
},
|
| 4186 |
+
{
|
| 4187 |
+
"move": "go forward",
|
| 4188 |
+
"view": "no-op"
|
| 4189 |
+
},
|
| 4190 |
+
{
|
| 4191 |
+
"move": "go forward",
|
| 4192 |
+
"view": "no-op"
|
| 4193 |
+
},
|
| 4194 |
+
{
|
| 4195 |
+
"move": "go forward",
|
| 4196 |
+
"view": "no-op"
|
| 4197 |
+
},
|
| 4198 |
+
{
|
| 4199 |
+
"move": "go forward",
|
| 4200 |
+
"view": "no-op"
|
| 4201 |
+
},
|
| 4202 |
+
{
|
| 4203 |
+
"move": "go forward",
|
| 4204 |
+
"view": "no-op"
|
| 4205 |
+
},
|
| 4206 |
+
{
|
| 4207 |
+
"move": "go forward",
|
| 4208 |
+
"view": "no-op"
|
| 4209 |
+
},
|
| 4210 |
+
{
|
| 4211 |
+
"move": "go forward",
|
| 4212 |
+
"view": "no-op"
|
| 4213 |
+
},
|
| 4214 |
+
{
|
| 4215 |
+
"move": "no-op",
|
| 4216 |
+
"view": "turn right"
|
| 4217 |
+
},
|
| 4218 |
+
{
|
| 4219 |
+
"move": "no-op",
|
| 4220 |
+
"view": "turn right"
|
| 4221 |
+
},
|
| 4222 |
+
{
|
| 4223 |
+
"move": "no-op",
|
| 4224 |
+
"view": "turn right"
|
| 4225 |
+
},
|
| 4226 |
+
{
|
| 4227 |
+
"move": "no-op",
|
| 4228 |
+
"view": "turn right"
|
| 4229 |
+
},
|
| 4230 |
+
{
|
| 4231 |
+
"move": "no-op",
|
| 4232 |
+
"view": "turn right"
|
| 4233 |
+
},
|
| 4234 |
+
{
|
| 4235 |
+
"move": "no-op",
|
| 4236 |
+
"view": "turn right"
|
| 4237 |
+
},
|
| 4238 |
+
{
|
| 4239 |
+
"move": "no-op",
|
| 4240 |
+
"view": "turn right"
|
| 4241 |
+
},
|
| 4242 |
+
{
|
| 4243 |
+
"move": "no-op",
|
| 4244 |
+
"view": "turn right"
|
| 4245 |
+
},
|
| 4246 |
+
{
|
| 4247 |
+
"move": "no-op",
|
| 4248 |
+
"view": "turn right"
|
| 4249 |
+
},
|
| 4250 |
+
{
|
| 4251 |
+
"move": "no-op",
|
| 4252 |
+
"view": "turn right"
|
| 4253 |
+
},
|
| 4254 |
+
{
|
| 4255 |
+
"move": "no-op",
|
| 4256 |
+
"view": "turn right"
|
| 4257 |
+
},
|
| 4258 |
+
{
|
| 4259 |
+
"move": "no-op",
|
| 4260 |
+
"view": "turn right"
|
| 4261 |
+
},
|
| 4262 |
+
{
|
| 4263 |
+
"move": "no-op",
|
| 4264 |
+
"view": "turn right"
|
| 4265 |
+
},
|
| 4266 |
+
{
|
| 4267 |
+
"move": "no-op",
|
| 4268 |
+
"view": "turn right"
|
| 4269 |
+
},
|
| 4270 |
+
{
|
| 4271 |
+
"move": "no-op",
|
| 4272 |
+
"view": "turn right"
|
| 4273 |
+
},
|
| 4274 |
+
{
|
| 4275 |
+
"move": "no-op",
|
| 4276 |
+
"view": "turn right"
|
| 4277 |
+
},
|
| 4278 |
+
{
|
| 4279 |
+
"move": "no-op",
|
| 4280 |
+
"view": "turn right"
|
| 4281 |
+
},
|
| 4282 |
+
{
|
| 4283 |
+
"move": "no-op",
|
| 4284 |
+
"view": "turn right"
|
| 4285 |
+
},
|
| 4286 |
+
{
|
| 4287 |
+
"move": "no-op",
|
| 4288 |
+
"view": "turn right"
|
| 4289 |
+
},
|
| 4290 |
+
{
|
| 4291 |
+
"move": "no-op",
|
| 4292 |
+
"view": "turn right"
|
| 4293 |
+
},
|
| 4294 |
+
{
|
| 4295 |
+
"move": "no-op",
|
| 4296 |
+
"view": "turn right"
|
| 4297 |
+
},
|
| 4298 |
+
{
|
| 4299 |
+
"move": "no-op",
|
| 4300 |
+
"view": "turn right"
|
| 4301 |
+
},
|
| 4302 |
+
{
|
| 4303 |
+
"move": "no-op",
|
| 4304 |
+
"view": "turn right"
|
| 4305 |
+
},
|
| 4306 |
+
{
|
| 4307 |
+
"move": "no-op",
|
| 4308 |
+
"view": "turn right"
|
| 4309 |
+
},
|
| 4310 |
+
{
|
| 4311 |
+
"move": "no-op",
|
| 4312 |
+
"view": "turn right"
|
| 4313 |
+
},
|
| 4314 |
+
{
|
| 4315 |
+
"move": "no-op",
|
| 4316 |
+
"view": "turn right"
|
| 4317 |
+
},
|
| 4318 |
+
{
|
| 4319 |
+
"move": "no-op",
|
| 4320 |
+
"view": "turn right"
|
| 4321 |
+
},
|
| 4322 |
+
{
|
| 4323 |
+
"move": "no-op",
|
| 4324 |
+
"view": "turn right"
|
| 4325 |
+
},
|
| 4326 |
+
{
|
| 4327 |
+
"move": "no-op",
|
| 4328 |
+
"view": "turn right"
|
| 4329 |
+
},
|
| 4330 |
+
{
|
| 4331 |
+
"move": "no-op",
|
| 4332 |
+
"view": "turn right"
|
| 4333 |
+
},
|
| 4334 |
+
{
|
| 4335 |
+
"move": "no-op",
|
| 4336 |
+
"view": "turn right"
|
| 4337 |
+
},
|
| 4338 |
+
{
|
| 4339 |
+
"move": "no-op",
|
| 4340 |
+
"view": "turn right"
|
| 4341 |
+
},
|
| 4342 |
+
{
|
| 4343 |
+
"move": "no-op",
|
| 4344 |
+
"view": "turn right"
|
| 4345 |
+
},
|
| 4346 |
+
{
|
| 4347 |
+
"move": "no-op",
|
| 4348 |
+
"view": "turn right"
|
| 4349 |
+
},
|
| 4350 |
+
{
|
| 4351 |
+
"move": "no-op",
|
| 4352 |
+
"view": "turn right"
|
| 4353 |
+
},
|
| 4354 |
+
{
|
| 4355 |
+
"move": "no-op",
|
| 4356 |
+
"view": "turn right"
|
| 4357 |
+
},
|
| 4358 |
+
{
|
| 4359 |
+
"move": "no-op",
|
| 4360 |
+
"view": "turn right"
|
| 4361 |
+
},
|
| 4362 |
+
{
|
| 4363 |
+
"move": "no-op",
|
| 4364 |
+
"view": "turn right"
|
| 4365 |
+
},
|
| 4366 |
+
{
|
| 4367 |
+
"move": "no-op",
|
| 4368 |
+
"view": "turn right"
|
| 4369 |
+
},
|
| 4370 |
+
{
|
| 4371 |
+
"move": "no-op",
|
| 4372 |
+
"view": "turn right"
|
| 4373 |
+
},
|
| 4374 |
+
{
|
| 4375 |
+
"move": "no-op",
|
| 4376 |
+
"view": "turn right"
|
| 4377 |
+
},
|
| 4378 |
+
{
|
| 4379 |
+
"move": "no-op",
|
| 4380 |
+
"view": "turn right"
|
| 4381 |
+
},
|
| 4382 |
+
{
|
| 4383 |
+
"move": "no-op",
|
| 4384 |
+
"view": "turn right"
|
| 4385 |
+
},
|
| 4386 |
+
{
|
| 4387 |
+
"move": "no-op",
|
| 4388 |
+
"view": "turn right"
|
| 4389 |
+
},
|
| 4390 |
+
{
|
| 4391 |
+
"move": "no-op",
|
| 4392 |
+
"view": "turn right"
|
| 4393 |
+
},
|
| 4394 |
+
{
|
| 4395 |
+
"move": "no-op",
|
| 4396 |
+
"view": "turn right"
|
| 4397 |
+
},
|
| 4398 |
+
{
|
| 4399 |
+
"move": "no-op",
|
| 4400 |
+
"view": "turn right"
|
| 4401 |
+
},
|
| 4402 |
+
{
|
| 4403 |
+
"move": "no-op",
|
| 4404 |
+
"view": "turn right"
|
| 4405 |
+
},
|
| 4406 |
+
{
|
| 4407 |
+
"move": "no-op",
|
| 4408 |
+
"view": "turn right"
|
| 4409 |
+
},
|
| 4410 |
+
{
|
| 4411 |
+
"move": "no-op",
|
| 4412 |
+
"view": "turn right"
|
| 4413 |
+
},
|
| 4414 |
+
{
|
| 4415 |
+
"move": "no-op",
|
| 4416 |
+
"view": "turn right"
|
| 4417 |
+
},
|
| 4418 |
+
{
|
| 4419 |
+
"move": "no-op",
|
| 4420 |
+
"view": "turn right"
|
| 4421 |
+
},
|
| 4422 |
+
{
|
| 4423 |
+
"move": "no-op",
|
| 4424 |
+
"view": "turn right"
|
| 4425 |
+
},
|
| 4426 |
+
{
|
| 4427 |
+
"move": "no-op",
|
| 4428 |
+
"view": "turn right"
|
| 4429 |
+
},
|
| 4430 |
+
{
|
| 4431 |
+
"move": "no-op",
|
| 4432 |
+
"view": "turn right"
|
| 4433 |
+
},
|
| 4434 |
+
{
|
| 4435 |
+
"move": "no-op",
|
| 4436 |
+
"view": "turn right"
|
| 4437 |
+
},
|
| 4438 |
+
{
|
| 4439 |
+
"move": "no-op",
|
| 4440 |
+
"view": "turn right"
|
| 4441 |
+
},
|
| 4442 |
+
{
|
| 4443 |
+
"move": "no-op",
|
| 4444 |
+
"view": "turn right"
|
| 4445 |
+
},
|
| 4446 |
+
{
|
| 4447 |
+
"move": "no-op",
|
| 4448 |
+
"view": "turn right"
|
| 4449 |
+
},
|
| 4450 |
+
{
|
| 4451 |
+
"move": "no-op",
|
| 4452 |
+
"view": "turn right"
|
| 4453 |
+
},
|
| 4454 |
+
{
|
| 4455 |
+
"move": "no-op",
|
| 4456 |
+
"view": "turn right"
|
| 4457 |
+
},
|
| 4458 |
+
{
|
| 4459 |
+
"move": "no-op",
|
| 4460 |
+
"view": "turn right"
|
| 4461 |
+
},
|
| 4462 |
+
{
|
| 4463 |
+
"move": "no-op",
|
| 4464 |
+
"view": "turn right"
|
| 4465 |
+
},
|
| 4466 |
+
{
|
| 4467 |
+
"move": "no-op",
|
| 4468 |
+
"view": "turn right"
|
| 4469 |
+
},
|
| 4470 |
+
{
|
| 4471 |
+
"move": "no-op",
|
| 4472 |
+
"view": "turn right"
|
| 4473 |
+
},
|
| 4474 |
+
{
|
| 4475 |
+
"move": "no-op",
|
| 4476 |
+
"view": "turn right"
|
| 4477 |
+
},
|
| 4478 |
+
{
|
| 4479 |
+
"move": "no-op",
|
| 4480 |
+
"view": "turn right"
|
| 4481 |
+
},
|
| 4482 |
+
{
|
| 4483 |
+
"move": "no-op",
|
| 4484 |
+
"view": "turn right"
|
| 4485 |
+
},
|
| 4486 |
+
{
|
| 4487 |
+
"move": "no-op",
|
| 4488 |
+
"view": "turn right"
|
| 4489 |
+
},
|
| 4490 |
+
{
|
| 4491 |
+
"move": "no-op",
|
| 4492 |
+
"view": "turn right"
|
| 4493 |
+
},
|
| 4494 |
+
{
|
| 4495 |
+
"move": "no-op",
|
| 4496 |
+
"view": "turn right"
|
| 4497 |
+
},
|
| 4498 |
+
{
|
| 4499 |
+
"move": "no-op",
|
| 4500 |
+
"view": "turn right"
|
| 4501 |
+
},
|
| 4502 |
+
{
|
| 4503 |
+
"move": "no-op",
|
| 4504 |
+
"view": "turn right"
|
| 4505 |
+
},
|
| 4506 |
+
{
|
| 4507 |
+
"move": "no-op",
|
| 4508 |
+
"view": "turn right"
|
| 4509 |
+
},
|
| 4510 |
+
{
|
| 4511 |
+
"move": "no-op",
|
| 4512 |
+
"view": "turn right"
|
| 4513 |
+
},
|
| 4514 |
+
{
|
| 4515 |
+
"move": "no-op",
|
| 4516 |
+
"view": "turn right"
|
| 4517 |
+
},
|
| 4518 |
+
{
|
| 4519 |
+
"move": "no-op",
|
| 4520 |
+
"view": "turn right"
|
| 4521 |
+
},
|
| 4522 |
+
{
|
| 4523 |
+
"move": "no-op",
|
| 4524 |
+
"view": "turn right"
|
| 4525 |
+
},
|
| 4526 |
+
{
|
| 4527 |
+
"move": "no-op",
|
| 4528 |
+
"view": "turn right"
|
| 4529 |
+
},
|
| 4530 |
+
{
|
| 4531 |
+
"move": "no-op",
|
| 4532 |
+
"view": "turn right"
|
| 4533 |
+
},
|
| 4534 |
+
{
|
| 4535 |
+
"move": "no-op",
|
| 4536 |
+
"view": "turn right"
|
| 4537 |
+
},
|
| 4538 |
+
{
|
| 4539 |
+
"move": "no-op",
|
| 4540 |
+
"view": "turn right"
|
| 4541 |
+
},
|
| 4542 |
+
{
|
| 4543 |
+
"move": "no-op",
|
| 4544 |
+
"view": "turn right"
|
| 4545 |
+
},
|
| 4546 |
+
{
|
| 4547 |
+
"move": "no-op",
|
| 4548 |
+
"view": "turn right"
|
| 4549 |
+
},
|
| 4550 |
+
{
|
| 4551 |
+
"move": "no-op",
|
| 4552 |
+
"view": "turn right"
|
| 4553 |
+
},
|
| 4554 |
+
{
|
| 4555 |
+
"move": "no-op",
|
| 4556 |
+
"view": "turn right"
|
| 4557 |
+
},
|
| 4558 |
+
{
|
| 4559 |
+
"move": "no-op",
|
| 4560 |
+
"view": "turn right"
|
| 4561 |
+
},
|
| 4562 |
+
{
|
| 4563 |
+
"move": "no-op",
|
| 4564 |
+
"view": "turn right"
|
| 4565 |
+
},
|
| 4566 |
+
{
|
| 4567 |
+
"move": "no-op",
|
| 4568 |
+
"view": "turn right"
|
| 4569 |
+
},
|
| 4570 |
+
{
|
| 4571 |
+
"move": "no-op",
|
| 4572 |
+
"view": "turn right"
|
| 4573 |
+
},
|
| 4574 |
+
{
|
| 4575 |
+
"move": "no-op",
|
| 4576 |
+
"view": "turn right"
|
| 4577 |
+
},
|
| 4578 |
+
{
|
| 4579 |
+
"move": "no-op",
|
| 4580 |
+
"view": "turn right"
|
| 4581 |
+
},
|
| 4582 |
+
{
|
| 4583 |
+
"move": "no-op",
|
| 4584 |
+
"view": "turn right"
|
| 4585 |
+
},
|
| 4586 |
+
{
|
| 4587 |
+
"move": "no-op",
|
| 4588 |
+
"view": "turn right"
|
| 4589 |
+
},
|
| 4590 |
+
{
|
| 4591 |
+
"move": "no-op",
|
| 4592 |
+
"view": "turn right"
|
| 4593 |
+
},
|
| 4594 |
+
{
|
| 4595 |
+
"move": "no-op",
|
| 4596 |
+
"view": "turn right"
|
| 4597 |
+
},
|
| 4598 |
+
{
|
| 4599 |
+
"move": "no-op",
|
| 4600 |
+
"view": "turn right"
|
| 4601 |
+
},
|
| 4602 |
+
{
|
| 4603 |
+
"move": "no-op",
|
| 4604 |
+
"view": "turn right"
|
| 4605 |
+
},
|
| 4606 |
+
{
|
| 4607 |
+
"move": "no-op",
|
| 4608 |
+
"view": "turn right"
|
| 4609 |
+
},
|
| 4610 |
+
{
|
| 4611 |
+
"move": "no-op",
|
| 4612 |
+
"view": "turn right"
|
| 4613 |
+
},
|
| 4614 |
+
{
|
| 4615 |
+
"move": "no-op",
|
| 4616 |
+
"view": "turn right"
|
| 4617 |
+
},
|
| 4618 |
+
{
|
| 4619 |
+
"move": "no-op",
|
| 4620 |
+
"view": "turn right"
|
| 4621 |
+
},
|
| 4622 |
+
{
|
| 4623 |
+
"move": "no-op",
|
| 4624 |
+
"view": "turn right"
|
| 4625 |
+
},
|
| 4626 |
+
{
|
| 4627 |
+
"move": "no-op",
|
| 4628 |
+
"view": "turn right"
|
| 4629 |
+
},
|
| 4630 |
+
{
|
| 4631 |
+
"move": "no-op",
|
| 4632 |
+
"view": "turn right"
|
| 4633 |
+
},
|
| 4634 |
+
{
|
| 4635 |
+
"move": "no-op",
|
| 4636 |
+
"view": "turn right"
|
| 4637 |
+
},
|
| 4638 |
+
{
|
| 4639 |
+
"move": "no-op",
|
| 4640 |
+
"view": "turn right"
|
| 4641 |
+
},
|
| 4642 |
+
{
|
| 4643 |
+
"move": "no-op",
|
| 4644 |
+
"view": "turn right"
|
| 4645 |
+
},
|
| 4646 |
+
{
|
| 4647 |
+
"move": "no-op",
|
| 4648 |
+
"view": "turn right"
|
| 4649 |
+
},
|
| 4650 |
+
{
|
| 4651 |
+
"move": "no-op",
|
| 4652 |
+
"view": "turn right"
|
| 4653 |
+
},
|
| 4654 |
+
{
|
| 4655 |
+
"move": "no-op",
|
| 4656 |
+
"view": "turn right"
|
| 4657 |
+
},
|
| 4658 |
+
{
|
| 4659 |
+
"move": "no-op",
|
| 4660 |
+
"view": "turn right"
|
| 4661 |
+
},
|
| 4662 |
+
{
|
| 4663 |
+
"move": "no-op",
|
| 4664 |
+
"view": "turn right"
|
| 4665 |
+
},
|
| 4666 |
+
{
|
| 4667 |
+
"move": "no-op",
|
| 4668 |
+
"view": "turn right"
|
| 4669 |
+
},
|
| 4670 |
+
{
|
| 4671 |
+
"move": "no-op",
|
| 4672 |
+
"view": "turn right"
|
| 4673 |
+
},
|
| 4674 |
+
{
|
| 4675 |
+
"move": "no-op",
|
| 4676 |
+
"view": "turn right"
|
| 4677 |
+
},
|
| 4678 |
+
{
|
| 4679 |
+
"move": "no-op",
|
| 4680 |
+
"view": "turn right"
|
| 4681 |
+
},
|
| 4682 |
+
{
|
| 4683 |
+
"move": "no-op",
|
| 4684 |
+
"view": "turn right"
|
| 4685 |
+
},
|
| 4686 |
+
{
|
| 4687 |
+
"move": "no-op",
|
| 4688 |
+
"view": "turn right"
|
| 4689 |
+
},
|
| 4690 |
+
{
|
| 4691 |
+
"move": "no-op",
|
| 4692 |
+
"view": "turn right"
|
| 4693 |
+
},
|
| 4694 |
+
{
|
| 4695 |
+
"move": "no-op",
|
| 4696 |
+
"view": "turn right"
|
| 4697 |
+
},
|
| 4698 |
+
{
|
| 4699 |
+
"move": "no-op",
|
| 4700 |
+
"view": "turn right"
|
| 4701 |
+
},
|
| 4702 |
+
{
|
| 4703 |
+
"move": "no-op",
|
| 4704 |
+
"view": "turn right"
|
| 4705 |
+
},
|
| 4706 |
+
{
|
| 4707 |
+
"move": "no-op",
|
| 4708 |
+
"view": "turn right"
|
| 4709 |
+
},
|
| 4710 |
+
{
|
| 4711 |
+
"move": "no-op",
|
| 4712 |
+
"view": "turn right"
|
| 4713 |
+
},
|
| 4714 |
+
{
|
| 4715 |
+
"move": "no-op",
|
| 4716 |
+
"view": "turn right"
|
| 4717 |
+
},
|
| 4718 |
+
{
|
| 4719 |
+
"move": "no-op",
|
| 4720 |
+
"view": "turn right"
|
| 4721 |
+
},
|
| 4722 |
+
{
|
| 4723 |
+
"move": "no-op",
|
| 4724 |
+
"view": "turn right"
|
| 4725 |
+
},
|
| 4726 |
+
{
|
| 4727 |
+
"move": "no-op",
|
| 4728 |
+
"view": "turn right"
|
| 4729 |
+
},
|
| 4730 |
+
{
|
| 4731 |
+
"move": "no-op",
|
| 4732 |
+
"view": "turn right"
|
| 4733 |
+
},
|
| 4734 |
+
{
|
| 4735 |
+
"move": "no-op",
|
| 4736 |
+
"view": "turn right"
|
| 4737 |
+
},
|
| 4738 |
+
{
|
| 4739 |
+
"move": "no-op",
|
| 4740 |
+
"view": "turn right"
|
| 4741 |
+
},
|
| 4742 |
+
{
|
| 4743 |
+
"move": "no-op",
|
| 4744 |
+
"view": "turn right"
|
| 4745 |
+
},
|
| 4746 |
+
{
|
| 4747 |
+
"move": "no-op",
|
| 4748 |
+
"view": "turn right"
|
| 4749 |
+
},
|
| 4750 |
+
{
|
| 4751 |
+
"move": "no-op",
|
| 4752 |
+
"view": "turn right"
|
| 4753 |
+
},
|
| 4754 |
+
{
|
| 4755 |
+
"move": "no-op",
|
| 4756 |
+
"view": "turn right"
|
| 4757 |
+
},
|
| 4758 |
+
{
|
| 4759 |
+
"move": "no-op",
|
| 4760 |
+
"view": "turn right"
|
| 4761 |
+
},
|
| 4762 |
+
{
|
| 4763 |
+
"move": "no-op",
|
| 4764 |
+
"view": "turn right"
|
| 4765 |
+
},
|
| 4766 |
+
{
|
| 4767 |
+
"move": "no-op",
|
| 4768 |
+
"view": "turn right"
|
| 4769 |
+
},
|
| 4770 |
+
{
|
| 4771 |
+
"move": "no-op",
|
| 4772 |
+
"view": "turn right"
|
| 4773 |
+
},
|
| 4774 |
+
{
|
| 4775 |
+
"move": "no-op",
|
| 4776 |
+
"view": "turn right"
|
| 4777 |
+
},
|
| 4778 |
+
{
|
| 4779 |
+
"move": "no-op",
|
| 4780 |
+
"view": "turn right"
|
| 4781 |
+
},
|
| 4782 |
+
{
|
| 4783 |
+
"move": "no-op",
|
| 4784 |
+
"view": "turn right"
|
| 4785 |
+
},
|
| 4786 |
+
{
|
| 4787 |
+
"move": "no-op",
|
| 4788 |
+
"view": "turn right"
|
| 4789 |
+
},
|
| 4790 |
+
{
|
| 4791 |
+
"move": "no-op",
|
| 4792 |
+
"view": "turn right"
|
| 4793 |
+
},
|
| 4794 |
+
{
|
| 4795 |
+
"move": "no-op",
|
| 4796 |
+
"view": "turn right"
|
| 4797 |
+
},
|
| 4798 |
+
{
|
| 4799 |
+
"move": "no-op",
|
| 4800 |
+
"view": "turn right"
|
| 4801 |
+
},
|
| 4802 |
+
{
|
| 4803 |
+
"move": "no-op",
|
| 4804 |
+
"view": "turn right"
|
| 4805 |
+
},
|
| 4806 |
+
{
|
| 4807 |
+
"move": "no-op",
|
| 4808 |
+
"view": "turn right"
|
| 4809 |
+
},
|
| 4810 |
+
{
|
| 4811 |
+
"move": "no-op",
|
| 4812 |
+
"view": "turn right"
|
| 4813 |
+
},
|
| 4814 |
+
{
|
| 4815 |
+
"move": "no-op",
|
| 4816 |
+
"view": "turn right"
|
| 4817 |
+
},
|
| 4818 |
+
{
|
| 4819 |
+
"move": "no-op",
|
| 4820 |
+
"view": "turn right"
|
| 4821 |
+
},
|
| 4822 |
+
{
|
| 4823 |
+
"move": "no-op",
|
| 4824 |
+
"view": "turn right"
|
| 4825 |
+
},
|
| 4826 |
+
{
|
| 4827 |
+
"move": "no-op",
|
| 4828 |
+
"view": "turn right"
|
| 4829 |
+
},
|
| 4830 |
+
{
|
| 4831 |
+
"move": "no-op",
|
| 4832 |
+
"view": "turn right"
|
| 4833 |
+
},
|
| 4834 |
+
{
|
| 4835 |
+
"move": "no-op",
|
| 4836 |
+
"view": "turn right"
|
| 4837 |
+
},
|
| 4838 |
+
{
|
| 4839 |
+
"move": "no-op",
|
| 4840 |
+
"view": "turn right"
|
| 4841 |
+
},
|
| 4842 |
+
{
|
| 4843 |
+
"move": "no-op",
|
| 4844 |
+
"view": "turn right"
|
| 4845 |
+
},
|
| 4846 |
+
{
|
| 4847 |
+
"move": "no-op",
|
| 4848 |
+
"view": "turn right"
|
| 4849 |
+
},
|
| 4850 |
+
{
|
| 4851 |
+
"move": "no-op",
|
| 4852 |
+
"view": "turn right"
|
| 4853 |
+
},
|
| 4854 |
+
{
|
| 4855 |
+
"move": "no-op",
|
| 4856 |
+
"view": "turn right"
|
| 4857 |
+
},
|
| 4858 |
+
{
|
| 4859 |
+
"move": "no-op",
|
| 4860 |
+
"view": "turn right"
|
| 4861 |
+
},
|
| 4862 |
+
{
|
| 4863 |
+
"move": "no-op",
|
| 4864 |
+
"view": "turn right"
|
| 4865 |
+
},
|
| 4866 |
+
{
|
| 4867 |
+
"move": "no-op",
|
| 4868 |
+
"view": "turn right"
|
| 4869 |
+
},
|
| 4870 |
+
{
|
| 4871 |
+
"move": "no-op",
|
| 4872 |
+
"view": "turn right"
|
| 4873 |
+
},
|
| 4874 |
+
{
|
| 4875 |
+
"move": "no-op",
|
| 4876 |
+
"view": "turn right"
|
| 4877 |
+
},
|
| 4878 |
+
{
|
| 4879 |
+
"move": "no-op",
|
| 4880 |
+
"view": "turn right"
|
| 4881 |
+
},
|
| 4882 |
+
{
|
| 4883 |
+
"move": "no-op",
|
| 4884 |
+
"view": "turn right"
|
| 4885 |
+
},
|
| 4886 |
+
{
|
| 4887 |
+
"move": "no-op",
|
| 4888 |
+
"view": "turn right"
|
| 4889 |
+
},
|
| 4890 |
+
{
|
| 4891 |
+
"move": "no-op",
|
| 4892 |
+
"view": "turn right"
|
| 4893 |
+
},
|
| 4894 |
+
{
|
| 4895 |
+
"move": "no-op",
|
| 4896 |
+
"view": "turn right"
|
| 4897 |
+
},
|
| 4898 |
+
{
|
| 4899 |
+
"move": "no-op",
|
| 4900 |
+
"view": "turn right"
|
| 4901 |
+
},
|
| 4902 |
+
{
|
| 4903 |
+
"move": "no-op",
|
| 4904 |
+
"view": "turn right"
|
| 4905 |
+
},
|
| 4906 |
+
{
|
| 4907 |
+
"move": "no-op",
|
| 4908 |
+
"view": "turn right"
|
| 4909 |
+
},
|
| 4910 |
+
{
|
| 4911 |
+
"move": "no-op",
|
| 4912 |
+
"view": "turn right"
|
| 4913 |
+
},
|
| 4914 |
+
{
|
| 4915 |
+
"move": "no-op",
|
| 4916 |
+
"view": "turn right"
|
| 4917 |
+
},
|
| 4918 |
+
{
|
| 4919 |
+
"move": "no-op",
|
| 4920 |
+
"view": "turn right"
|
| 4921 |
+
},
|
| 4922 |
+
{
|
| 4923 |
+
"move": "no-op",
|
| 4924 |
+
"view": "turn right"
|
| 4925 |
+
},
|
| 4926 |
+
{
|
| 4927 |
+
"move": "no-op",
|
| 4928 |
+
"view": "turn right"
|
| 4929 |
+
},
|
| 4930 |
+
{
|
| 4931 |
+
"move": "no-op",
|
| 4932 |
+
"view": "turn right"
|
| 4933 |
+
},
|
| 4934 |
+
{
|
| 4935 |
+
"move": "no-op",
|
| 4936 |
+
"view": "turn right"
|
| 4937 |
+
},
|
| 4938 |
+
{
|
| 4939 |
+
"move": "no-op",
|
| 4940 |
+
"view": "turn right"
|
| 4941 |
+
},
|
| 4942 |
+
{
|
| 4943 |
+
"move": "no-op",
|
| 4944 |
+
"view": "turn right"
|
| 4945 |
+
},
|
| 4946 |
+
{
|
| 4947 |
+
"move": "no-op",
|
| 4948 |
+
"view": "turn right"
|
| 4949 |
+
},
|
| 4950 |
+
{
|
| 4951 |
+
"move": "no-op",
|
| 4952 |
+
"view": "turn right"
|
| 4953 |
+
},
|
| 4954 |
+
{
|
| 4955 |
+
"move": "no-op",
|
| 4956 |
+
"view": "turn right"
|
| 4957 |
+
},
|
| 4958 |
+
{
|
| 4959 |
+
"move": "no-op",
|
| 4960 |
+
"view": "turn right"
|
| 4961 |
+
},
|
| 4962 |
+
{
|
| 4963 |
+
"move": "no-op",
|
| 4964 |
+
"view": "turn right"
|
| 4965 |
+
},
|
| 4966 |
+
{
|
| 4967 |
+
"move": "no-op",
|
| 4968 |
+
"view": "turn right"
|
| 4969 |
+
},
|
| 4970 |
+
{
|
| 4971 |
+
"move": "no-op",
|
| 4972 |
+
"view": "turn right"
|
| 4973 |
+
},
|
| 4974 |
+
{
|
| 4975 |
+
"move": "no-op",
|
| 4976 |
+
"view": "turn right"
|
| 4977 |
+
},
|
| 4978 |
+
{
|
| 4979 |
+
"move": "no-op",
|
| 4980 |
+
"view": "turn right"
|
| 4981 |
+
},
|
| 4982 |
+
{
|
| 4983 |
+
"move": "no-op",
|
| 4984 |
+
"view": "turn right"
|
| 4985 |
+
},
|
| 4986 |
+
{
|
| 4987 |
+
"move": "no-op",
|
| 4988 |
+
"view": "turn right"
|
| 4989 |
+
},
|
| 4990 |
+
{
|
| 4991 |
+
"move": "no-op",
|
| 4992 |
+
"view": "turn right"
|
| 4993 |
+
},
|
| 4994 |
+
{
|
| 4995 |
+
"move": "no-op",
|
| 4996 |
+
"view": "turn right"
|
| 4997 |
+
},
|
| 4998 |
+
{
|
| 4999 |
+
"move": "no-op",
|
| 5000 |
+
"view": "turn right"
|
| 5001 |
+
},
|
| 5002 |
+
{
|
| 5003 |
+
"move": "no-op",
|
| 5004 |
+
"view": "turn right"
|
| 5005 |
+
},
|
| 5006 |
+
{
|
| 5007 |
+
"move": "no-op",
|
| 5008 |
+
"view": "turn right"
|
| 5009 |
+
},
|
| 5010 |
+
{
|
| 5011 |
+
"move": "no-op",
|
| 5012 |
+
"view": "turn right"
|
| 5013 |
+
},
|
| 5014 |
+
{
|
| 5015 |
+
"move": "no-op",
|
| 5016 |
+
"view": "turn right"
|
| 5017 |
+
},
|
| 5018 |
+
{
|
| 5019 |
+
"move": "no-op",
|
| 5020 |
+
"view": "turn right"
|
| 5021 |
+
},
|
| 5022 |
+
{
|
| 5023 |
+
"move": "no-op",
|
| 5024 |
+
"view": "turn right"
|
| 5025 |
+
},
|
| 5026 |
+
{
|
| 5027 |
+
"move": "no-op",
|
| 5028 |
+
"view": "turn right"
|
| 5029 |
+
},
|
| 5030 |
+
{
|
| 5031 |
+
"move": "no-op",
|
| 5032 |
+
"view": "turn right"
|
| 5033 |
+
},
|
| 5034 |
+
{
|
| 5035 |
+
"move": "no-op",
|
| 5036 |
+
"view": "turn right"
|
| 5037 |
+
},
|
| 5038 |
+
{
|
| 5039 |
+
"move": "no-op",
|
| 5040 |
+
"view": "turn right"
|
| 5041 |
+
},
|
| 5042 |
+
{
|
| 5043 |
+
"move": "no-op",
|
| 5044 |
+
"view": "turn right"
|
| 5045 |
+
},
|
| 5046 |
+
{
|
| 5047 |
+
"move": "no-op",
|
| 5048 |
+
"view": "turn right"
|
| 5049 |
+
},
|
| 5050 |
+
{
|
| 5051 |
+
"move": "no-op",
|
| 5052 |
+
"view": "turn right"
|
| 5053 |
+
},
|
| 5054 |
+
{
|
| 5055 |
+
"move": "no-op",
|
| 5056 |
+
"view": "turn right"
|
| 5057 |
+
},
|
| 5058 |
+
{
|
| 5059 |
+
"move": "no-op",
|
| 5060 |
+
"view": "turn right"
|
| 5061 |
+
},
|
| 5062 |
+
{
|
| 5063 |
+
"move": "no-op",
|
| 5064 |
+
"view": "turn right"
|
| 5065 |
+
},
|
| 5066 |
+
{
|
| 5067 |
+
"move": "no-op",
|
| 5068 |
+
"view": "turn right"
|
| 5069 |
+
},
|
| 5070 |
+
{
|
| 5071 |
+
"move": "no-op",
|
| 5072 |
+
"view": "turn right"
|
| 5073 |
+
},
|
| 5074 |
+
{
|
| 5075 |
+
"move": "no-op",
|
| 5076 |
+
"view": "turn right"
|
| 5077 |
+
},
|
| 5078 |
+
{
|
| 5079 |
+
"move": "no-op",
|
| 5080 |
+
"view": "turn right"
|
| 5081 |
+
},
|
| 5082 |
+
{
|
| 5083 |
+
"move": "no-op",
|
| 5084 |
+
"view": "turn right"
|
| 5085 |
+
},
|
| 5086 |
+
{
|
| 5087 |
+
"move": "no-op",
|
| 5088 |
+
"view": "turn right"
|
| 5089 |
+
},
|
| 5090 |
+
{
|
| 5091 |
+
"move": "no-op",
|
| 5092 |
+
"view": "turn right"
|
| 5093 |
+
},
|
| 5094 |
+
{
|
| 5095 |
+
"move": "no-op",
|
| 5096 |
+
"view": "turn right"
|
| 5097 |
+
},
|
| 5098 |
+
{
|
| 5099 |
+
"move": "no-op",
|
| 5100 |
+
"view": "turn right"
|
| 5101 |
+
},
|
| 5102 |
+
{
|
| 5103 |
+
"move": "no-op",
|
| 5104 |
+
"view": "turn right"
|
| 5105 |
+
},
|
| 5106 |
+
{
|
| 5107 |
+
"move": "no-op",
|
| 5108 |
+
"view": "turn right"
|
| 5109 |
+
},
|
| 5110 |
+
{
|
| 5111 |
+
"move": "no-op",
|
| 5112 |
+
"view": "turn right"
|
| 5113 |
+
},
|
| 5114 |
+
{
|
| 5115 |
+
"move": "no-op",
|
| 5116 |
+
"view": "turn right"
|
| 5117 |
+
},
|
| 5118 |
+
{
|
| 5119 |
+
"move": "no-op",
|
| 5120 |
+
"view": "turn right"
|
| 5121 |
+
},
|
| 5122 |
+
{
|
| 5123 |
+
"move": "no-op",
|
| 5124 |
+
"view": "turn right"
|
| 5125 |
+
},
|
| 5126 |
+
{
|
| 5127 |
+
"move": "no-op",
|
| 5128 |
+
"view": "turn right"
|
| 5129 |
+
},
|
| 5130 |
+
{
|
| 5131 |
+
"move": "no-op",
|
| 5132 |
+
"view": "turn right"
|
| 5133 |
+
},
|
| 5134 |
+
{
|
| 5135 |
+
"move": "no-op",
|
| 5136 |
+
"view": "turn right"
|
| 5137 |
+
},
|
| 5138 |
+
{
|
| 5139 |
+
"move": "no-op",
|
| 5140 |
+
"view": "turn right"
|
| 5141 |
+
},
|
| 5142 |
+
{
|
| 5143 |
+
"move": "no-op",
|
| 5144 |
+
"view": "turn right"
|
| 5145 |
+
},
|
| 5146 |
+
{
|
| 5147 |
+
"move": "no-op",
|
| 5148 |
+
"view": "turn right"
|
| 5149 |
+
},
|
| 5150 |
+
{
|
| 5151 |
+
"move": "no-op",
|
| 5152 |
+
"view": "turn right"
|
| 5153 |
+
},
|
| 5154 |
+
{
|
| 5155 |
+
"move": "no-op",
|
| 5156 |
+
"view": "turn right"
|
| 5157 |
+
},
|
| 5158 |
+
{
|
| 5159 |
+
"move": "no-op",
|
| 5160 |
+
"view": "turn right"
|
| 5161 |
+
},
|
| 5162 |
+
{
|
| 5163 |
+
"move": "no-op",
|
| 5164 |
+
"view": "turn right"
|
| 5165 |
+
},
|
| 5166 |
+
{
|
| 5167 |
+
"move": "no-op",
|
| 5168 |
+
"view": "turn right"
|
| 5169 |
+
},
|
| 5170 |
+
{
|
| 5171 |
+
"move": "no-op",
|
| 5172 |
+
"view": "turn right"
|
| 5173 |
+
},
|
| 5174 |
+
{
|
| 5175 |
+
"move": "no-op",
|
| 5176 |
+
"view": "turn right"
|
| 5177 |
+
},
|
| 5178 |
+
{
|
| 5179 |
+
"move": "no-op",
|
| 5180 |
+
"view": "turn right"
|
| 5181 |
+
},
|
| 5182 |
+
{
|
| 5183 |
+
"move": "no-op",
|
| 5184 |
+
"view": "turn right"
|
| 5185 |
+
},
|
| 5186 |
+
{
|
| 5187 |
+
"move": "no-op",
|
| 5188 |
+
"view": "turn right"
|
| 5189 |
+
},
|
| 5190 |
+
{
|
| 5191 |
+
"move": "no-op",
|
| 5192 |
+
"view": "turn right"
|
| 5193 |
+
},
|
| 5194 |
+
{
|
| 5195 |
+
"move": "no-op",
|
| 5196 |
+
"view": "turn right"
|
| 5197 |
+
},
|
| 5198 |
+
{
|
| 5199 |
+
"move": "no-op",
|
| 5200 |
+
"view": "turn right"
|
| 5201 |
+
},
|
| 5202 |
+
{
|
| 5203 |
+
"move": "no-op",
|
| 5204 |
+
"view": "turn right"
|
| 5205 |
+
},
|
| 5206 |
+
{
|
| 5207 |
+
"move": "no-op",
|
| 5208 |
+
"view": "turn right"
|
| 5209 |
+
},
|
| 5210 |
+
{
|
| 5211 |
+
"move": "no-op",
|
| 5212 |
+
"view": "turn right"
|
| 5213 |
+
},
|
| 5214 |
+
{
|
| 5215 |
+
"move": "no-op",
|
| 5216 |
+
"view": "turn right"
|
| 5217 |
+
},
|
| 5218 |
+
{
|
| 5219 |
+
"move": "no-op",
|
| 5220 |
+
"view": "turn right"
|
| 5221 |
+
},
|
| 5222 |
+
{
|
| 5223 |
+
"move": "no-op",
|
| 5224 |
+
"view": "turn right"
|
| 5225 |
+
},
|
| 5226 |
+
{
|
| 5227 |
+
"move": "no-op",
|
| 5228 |
+
"view": "turn right"
|
| 5229 |
+
},
|
| 5230 |
+
{
|
| 5231 |
+
"move": "no-op",
|
| 5232 |
+
"view": "turn right"
|
| 5233 |
+
},
|
| 5234 |
+
{
|
| 5235 |
+
"move": "no-op",
|
| 5236 |
+
"view": "turn right"
|
| 5237 |
+
},
|
| 5238 |
+
{
|
| 5239 |
+
"move": "no-op",
|
| 5240 |
+
"view": "turn right"
|
| 5241 |
+
},
|
| 5242 |
+
{
|
| 5243 |
+
"move": "no-op",
|
| 5244 |
+
"view": "turn right"
|
| 5245 |
+
},
|
| 5246 |
+
{
|
| 5247 |
+
"move": "no-op",
|
| 5248 |
+
"view": "turn right"
|
| 5249 |
+
},
|
| 5250 |
+
{
|
| 5251 |
+
"move": "no-op",
|
| 5252 |
+
"view": "turn right"
|
| 5253 |
+
},
|
| 5254 |
+
{
|
| 5255 |
+
"move": "no-op",
|
| 5256 |
+
"view": "turn right"
|
| 5257 |
+
},
|
| 5258 |
+
{
|
| 5259 |
+
"move": "no-op",
|
| 5260 |
+
"view": "turn right"
|
| 5261 |
+
},
|
| 5262 |
+
{
|
| 5263 |
+
"move": "no-op",
|
| 5264 |
+
"view": "turn right"
|
| 5265 |
+
},
|
| 5266 |
+
{
|
| 5267 |
+
"move": "no-op",
|
| 5268 |
+
"view": "turn right"
|
| 5269 |
+
},
|
| 5270 |
+
{
|
| 5271 |
+
"move": "no-op",
|
| 5272 |
+
"view": "turn right"
|
| 5273 |
+
},
|
| 5274 |
+
{
|
| 5275 |
+
"move": "no-op",
|
| 5276 |
+
"view": "turn right"
|
| 5277 |
+
},
|
| 5278 |
+
{
|
| 5279 |
+
"move": "no-op",
|
| 5280 |
+
"view": "turn right"
|
| 5281 |
+
},
|
| 5282 |
+
{
|
| 5283 |
+
"move": "no-op",
|
| 5284 |
+
"view": "turn right"
|
| 5285 |
+
},
|
| 5286 |
+
{
|
| 5287 |
+
"move": "no-op",
|
| 5288 |
+
"view": "turn right"
|
| 5289 |
+
},
|
| 5290 |
+
{
|
| 5291 |
+
"move": "no-op",
|
| 5292 |
+
"view": "turn right"
|
| 5293 |
+
},
|
| 5294 |
+
{
|
| 5295 |
+
"move": "no-op",
|
| 5296 |
+
"view": "turn right"
|
| 5297 |
+
},
|
| 5298 |
+
{
|
| 5299 |
+
"move": "no-op",
|
| 5300 |
+
"view": "turn right"
|
| 5301 |
+
},
|
| 5302 |
+
{
|
| 5303 |
+
"move": "no-op",
|
| 5304 |
+
"view": "turn right"
|
| 5305 |
+
},
|
| 5306 |
+
{
|
| 5307 |
+
"move": "no-op",
|
| 5308 |
+
"view": "turn right"
|
| 5309 |
+
},
|
| 5310 |
+
{
|
| 5311 |
+
"move": "no-op",
|
| 5312 |
+
"view": "turn right"
|
| 5313 |
+
},
|
| 5314 |
+
{
|
| 5315 |
+
"move": "no-op",
|
| 5316 |
+
"view": "turn right"
|
| 5317 |
+
},
|
| 5318 |
+
{
|
| 5319 |
+
"move": "no-op",
|
| 5320 |
+
"view": "turn right"
|
| 5321 |
+
},
|
| 5322 |
+
{
|
| 5323 |
+
"move": "no-op",
|
| 5324 |
+
"view": "turn right"
|
| 5325 |
+
},
|
| 5326 |
+
{
|
| 5327 |
+
"move": "no-op",
|
| 5328 |
+
"view": "turn right"
|
| 5329 |
+
},
|
| 5330 |
+
{
|
| 5331 |
+
"move": "no-op",
|
| 5332 |
+
"view": "turn right"
|
| 5333 |
+
},
|
| 5334 |
+
{
|
| 5335 |
+
"move": "no-op",
|
| 5336 |
+
"view": "turn right"
|
| 5337 |
+
},
|
| 5338 |
+
{
|
| 5339 |
+
"move": "no-op",
|
| 5340 |
+
"view": "turn right"
|
| 5341 |
+
},
|
| 5342 |
+
{
|
| 5343 |
+
"move": "no-op",
|
| 5344 |
+
"view": "turn right"
|
| 5345 |
+
},
|
| 5346 |
+
{
|
| 5347 |
+
"move": "no-op",
|
| 5348 |
+
"view": "turn right"
|
| 5349 |
+
},
|
| 5350 |
+
{
|
| 5351 |
+
"move": "no-op",
|
| 5352 |
+
"view": "turn right"
|
| 5353 |
+
},
|
| 5354 |
+
{
|
| 5355 |
+
"move": "no-op",
|
| 5356 |
+
"view": "turn right"
|
| 5357 |
+
},
|
| 5358 |
+
{
|
| 5359 |
+
"move": "no-op",
|
| 5360 |
+
"view": "turn right"
|
| 5361 |
+
},
|
| 5362 |
+
{
|
| 5363 |
+
"move": "no-op",
|
| 5364 |
+
"view": "turn right"
|
| 5365 |
+
},
|
| 5366 |
+
{
|
| 5367 |
+
"move": "no-op",
|
| 5368 |
+
"view": "turn right"
|
| 5369 |
+
},
|
| 5370 |
+
{
|
| 5371 |
+
"move": "no-op",
|
| 5372 |
+
"view": "turn right"
|
| 5373 |
+
},
|
| 5374 |
+
{
|
| 5375 |
+
"move": "no-op",
|
| 5376 |
+
"view": "turn right"
|
| 5377 |
+
},
|
| 5378 |
+
{
|
| 5379 |
+
"move": "no-op",
|
| 5380 |
+
"view": "turn right"
|
| 5381 |
+
},
|
| 5382 |
+
{
|
| 5383 |
+
"move": "no-op",
|
| 5384 |
+
"view": "turn right"
|
| 5385 |
+
},
|
| 5386 |
+
{
|
| 5387 |
+
"move": "no-op",
|
| 5388 |
+
"view": "turn right"
|
| 5389 |
+
},
|
| 5390 |
+
{
|
| 5391 |
+
"move": "no-op",
|
| 5392 |
+
"view": "turn right"
|
| 5393 |
+
},
|
| 5394 |
+
{
|
| 5395 |
+
"move": "no-op",
|
| 5396 |
+
"view": "turn right"
|
| 5397 |
+
},
|
| 5398 |
+
{
|
| 5399 |
+
"move": "no-op",
|
| 5400 |
+
"view": "turn right"
|
| 5401 |
+
},
|
| 5402 |
+
{
|
| 5403 |
+
"move": "no-op",
|
| 5404 |
+
"view": "turn right"
|
| 5405 |
+
},
|
| 5406 |
+
{
|
| 5407 |
+
"move": "no-op",
|
| 5408 |
+
"view": "turn right"
|
| 5409 |
+
},
|
| 5410 |
+
{
|
| 5411 |
+
"move": "no-op",
|
| 5412 |
+
"view": "turn right"
|
| 5413 |
+
},
|
| 5414 |
+
{
|
| 5415 |
+
"move": "no-op",
|
| 5416 |
+
"view": "turn right"
|
| 5417 |
+
},
|
| 5418 |
+
{
|
| 5419 |
+
"move": "no-op",
|
| 5420 |
+
"view": "turn right"
|
| 5421 |
+
},
|
| 5422 |
+
{
|
| 5423 |
+
"move": "no-op",
|
| 5424 |
+
"view": "turn right"
|
| 5425 |
+
},
|
| 5426 |
+
{
|
| 5427 |
+
"move": "no-op",
|
| 5428 |
+
"view": "turn right"
|
| 5429 |
+
},
|
| 5430 |
+
{
|
| 5431 |
+
"move": "no-op",
|
| 5432 |
+
"view": "turn right"
|
| 5433 |
+
},
|
| 5434 |
+
{
|
| 5435 |
+
"move": "no-op",
|
| 5436 |
+
"view": "turn right"
|
| 5437 |
+
},
|
| 5438 |
+
{
|
| 5439 |
+
"move": "no-op",
|
| 5440 |
+
"view": "turn right"
|
| 5441 |
+
},
|
| 5442 |
+
{
|
| 5443 |
+
"move": "no-op",
|
| 5444 |
+
"view": "turn right"
|
| 5445 |
+
},
|
| 5446 |
+
{
|
| 5447 |
+
"move": "no-op",
|
| 5448 |
+
"view": "turn right"
|
| 5449 |
+
},
|
| 5450 |
+
{
|
| 5451 |
+
"move": "no-op",
|
| 5452 |
+
"view": "turn right"
|
| 5453 |
+
},
|
| 5454 |
+
{
|
| 5455 |
+
"move": "no-op",
|
| 5456 |
+
"view": "turn right"
|
| 5457 |
+
},
|
| 5458 |
+
{
|
| 5459 |
+
"move": "no-op",
|
| 5460 |
+
"view": "turn right"
|
| 5461 |
+
},
|
| 5462 |
+
{
|
| 5463 |
+
"move": "no-op",
|
| 5464 |
+
"view": "turn right"
|
| 5465 |
+
},
|
| 5466 |
+
{
|
| 5467 |
+
"move": "no-op",
|
| 5468 |
+
"view": "turn right"
|
| 5469 |
+
},
|
| 5470 |
+
{
|
| 5471 |
+
"move": "no-op",
|
| 5472 |
+
"view": "turn right"
|
| 5473 |
+
},
|
| 5474 |
+
{
|
| 5475 |
+
"move": "no-op",
|
| 5476 |
+
"view": "turn right"
|
| 5477 |
+
},
|
| 5478 |
+
{
|
| 5479 |
+
"move": "no-op",
|
| 5480 |
+
"view": "turn right"
|
| 5481 |
+
},
|
| 5482 |
+
{
|
| 5483 |
+
"move": "no-op",
|
| 5484 |
+
"view": "turn right"
|
| 5485 |
+
},
|
| 5486 |
+
{
|
| 5487 |
+
"move": "no-op",
|
| 5488 |
+
"view": "turn right"
|
| 5489 |
+
},
|
| 5490 |
+
{
|
| 5491 |
+
"move": "no-op",
|
| 5492 |
+
"view": "turn right"
|
| 5493 |
+
},
|
| 5494 |
+
{
|
| 5495 |
+
"move": "no-op",
|
| 5496 |
+
"view": "turn right"
|
| 5497 |
+
},
|
| 5498 |
+
{
|
| 5499 |
+
"move": "no-op",
|
| 5500 |
+
"view": "turn right"
|
| 5501 |
+
},
|
| 5502 |
+
{
|
| 5503 |
+
"move": "no-op",
|
| 5504 |
+
"view": "turn right"
|
| 5505 |
+
},
|
| 5506 |
+
{
|
| 5507 |
+
"move": "no-op",
|
| 5508 |
+
"view": "turn right"
|
| 5509 |
+
},
|
| 5510 |
+
{
|
| 5511 |
+
"move": "no-op",
|
| 5512 |
+
"view": "turn right"
|
| 5513 |
+
},
|
| 5514 |
+
{
|
| 5515 |
+
"move": "no-op",
|
| 5516 |
+
"view": "turn right"
|
| 5517 |
+
},
|
| 5518 |
+
{
|
| 5519 |
+
"move": "no-op",
|
| 5520 |
+
"view": "turn right"
|
| 5521 |
+
},
|
| 5522 |
+
{
|
| 5523 |
+
"move": "no-op",
|
| 5524 |
+
"view": "turn right"
|
| 5525 |
+
},
|
| 5526 |
+
{
|
| 5527 |
+
"move": "no-op",
|
| 5528 |
+
"view": "turn right"
|
| 5529 |
+
},
|
| 5530 |
+
{
|
| 5531 |
+
"move": "no-op",
|
| 5532 |
+
"view": "turn right"
|
| 5533 |
+
},
|
| 5534 |
+
{
|
| 5535 |
+
"move": "no-op",
|
| 5536 |
+
"view": "turn right"
|
| 5537 |
+
},
|
| 5538 |
+
{
|
| 5539 |
+
"move": "no-op",
|
| 5540 |
+
"view": "turn right"
|
| 5541 |
+
},
|
| 5542 |
+
{
|
| 5543 |
+
"move": "no-op",
|
| 5544 |
+
"view": "turn right"
|
| 5545 |
+
},
|
| 5546 |
+
{
|
| 5547 |
+
"move": "no-op",
|
| 5548 |
+
"view": "turn right"
|
| 5549 |
+
},
|
| 5550 |
+
{
|
| 5551 |
+
"move": "no-op",
|
| 5552 |
+
"view": "turn right"
|
| 5553 |
+
},
|
| 5554 |
+
{
|
| 5555 |
+
"move": "no-op",
|
| 5556 |
+
"view": "turn right"
|
| 5557 |
+
},
|
| 5558 |
+
{
|
| 5559 |
+
"move": "no-op",
|
| 5560 |
+
"view": "turn right"
|
| 5561 |
+
},
|
| 5562 |
+
{
|
| 5563 |
+
"move": "no-op",
|
| 5564 |
+
"view": "turn right"
|
| 5565 |
+
},
|
| 5566 |
+
{
|
| 5567 |
+
"move": "no-op",
|
| 5568 |
+
"view": "turn right"
|
| 5569 |
+
},
|
| 5570 |
+
{
|
| 5571 |
+
"move": "no-op",
|
| 5572 |
+
"view": "turn right"
|
| 5573 |
+
},
|
| 5574 |
+
{
|
| 5575 |
+
"move": "no-op",
|
| 5576 |
+
"view": "turn right"
|
| 5577 |
+
},
|
| 5578 |
+
{
|
| 5579 |
+
"move": "no-op",
|
| 5580 |
+
"view": "turn right"
|
| 5581 |
+
},
|
| 5582 |
+
{
|
| 5583 |
+
"move": "no-op",
|
| 5584 |
+
"view": "turn right"
|
| 5585 |
+
}
|
| 5586 |
+
]
|
assets/example_case/0002.jpg
ADDED
|
Git LFS Details
|
assets/example_case/0002.json
ADDED
|
@@ -0,0 +1,6234 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
{
|
| 3 |
+
"move": "no-op",
|
| 4 |
+
"view": "turn right"
|
| 5 |
+
},
|
| 6 |
+
{
|
| 7 |
+
"move": "no-op",
|
| 8 |
+
"view": "turn right"
|
| 9 |
+
},
|
| 10 |
+
{
|
| 11 |
+
"move": "no-op",
|
| 12 |
+
"view": "turn right"
|
| 13 |
+
},
|
| 14 |
+
{
|
| 15 |
+
"move": "no-op",
|
| 16 |
+
"view": "turn right"
|
| 17 |
+
},
|
| 18 |
+
{
|
| 19 |
+
"move": "no-op",
|
| 20 |
+
"view": "turn right"
|
| 21 |
+
},
|
| 22 |
+
{
|
| 23 |
+
"move": "no-op",
|
| 24 |
+
"view": "turn right"
|
| 25 |
+
},
|
| 26 |
+
{
|
| 27 |
+
"move": "no-op",
|
| 28 |
+
"view": "turn right"
|
| 29 |
+
},
|
| 30 |
+
{
|
| 31 |
+
"move": "no-op",
|
| 32 |
+
"view": "turn right"
|
| 33 |
+
},
|
| 34 |
+
{
|
| 35 |
+
"move": "no-op",
|
| 36 |
+
"view": "turn right"
|
| 37 |
+
},
|
| 38 |
+
{
|
| 39 |
+
"move": "no-op",
|
| 40 |
+
"view": "turn right"
|
| 41 |
+
},
|
| 42 |
+
{
|
| 43 |
+
"move": "no-op",
|
| 44 |
+
"view": "turn right"
|
| 45 |
+
},
|
| 46 |
+
{
|
| 47 |
+
"move": "no-op",
|
| 48 |
+
"view": "turn right"
|
| 49 |
+
},
|
| 50 |
+
{
|
| 51 |
+
"move": "no-op",
|
| 52 |
+
"view": "turn right"
|
| 53 |
+
},
|
| 54 |
+
{
|
| 55 |
+
"move": "no-op",
|
| 56 |
+
"view": "turn right"
|
| 57 |
+
},
|
| 58 |
+
{
|
| 59 |
+
"move": "no-op",
|
| 60 |
+
"view": "turn right"
|
| 61 |
+
},
|
| 62 |
+
{
|
| 63 |
+
"move": "no-op",
|
| 64 |
+
"view": "turn right"
|
| 65 |
+
},
|
| 66 |
+
{
|
| 67 |
+
"move": "no-op",
|
| 68 |
+
"view": "turn right"
|
| 69 |
+
},
|
| 70 |
+
{
|
| 71 |
+
"move": "no-op",
|
| 72 |
+
"view": "turn right"
|
| 73 |
+
},
|
| 74 |
+
{
|
| 75 |
+
"move": "no-op",
|
| 76 |
+
"view": "turn right"
|
| 77 |
+
},
|
| 78 |
+
{
|
| 79 |
+
"move": "no-op",
|
| 80 |
+
"view": "turn right"
|
| 81 |
+
},
|
| 82 |
+
{
|
| 83 |
+
"move": "no-op",
|
| 84 |
+
"view": "turn right"
|
| 85 |
+
},
|
| 86 |
+
{
|
| 87 |
+
"move": "no-op",
|
| 88 |
+
"view": "turn right"
|
| 89 |
+
},
|
| 90 |
+
{
|
| 91 |
+
"move": "no-op",
|
| 92 |
+
"view": "turn right"
|
| 93 |
+
},
|
| 94 |
+
{
|
| 95 |
+
"move": "no-op",
|
| 96 |
+
"view": "turn right"
|
| 97 |
+
},
|
| 98 |
+
{
|
| 99 |
+
"move": "no-op",
|
| 100 |
+
"view": "turn right"
|
| 101 |
+
},
|
| 102 |
+
{
|
| 103 |
+
"move": "no-op",
|
| 104 |
+
"view": "turn right"
|
| 105 |
+
},
|
| 106 |
+
{
|
| 107 |
+
"move": "no-op",
|
| 108 |
+
"view": "turn right"
|
| 109 |
+
},
|
| 110 |
+
{
|
| 111 |
+
"move": "no-op",
|
| 112 |
+
"view": "turn right"
|
| 113 |
+
},
|
| 114 |
+
{
|
| 115 |
+
"move": "no-op",
|
| 116 |
+
"view": "turn right"
|
| 117 |
+
},
|
| 118 |
+
{
|
| 119 |
+
"move": "no-op",
|
| 120 |
+
"view": "turn right"
|
| 121 |
+
},
|
| 122 |
+
{
|
| 123 |
+
"move": "no-op",
|
| 124 |
+
"view": "turn right"
|
| 125 |
+
},
|
| 126 |
+
{
|
| 127 |
+
"move": "no-op",
|
| 128 |
+
"view": "turn right"
|
| 129 |
+
},
|
| 130 |
+
{
|
| 131 |
+
"move": "no-op",
|
| 132 |
+
"view": "turn right"
|
| 133 |
+
},
|
| 134 |
+
{
|
| 135 |
+
"move": "no-op",
|
| 136 |
+
"view": "turn right"
|
| 137 |
+
},
|
| 138 |
+
{
|
| 139 |
+
"move": "no-op",
|
| 140 |
+
"view": "turn right"
|
| 141 |
+
},
|
| 142 |
+
{
|
| 143 |
+
"move": "no-op",
|
| 144 |
+
"view": "turn right"
|
| 145 |
+
},
|
| 146 |
+
{
|
| 147 |
+
"move": "no-op",
|
| 148 |
+
"view": "turn right"
|
| 149 |
+
},
|
| 150 |
+
{
|
| 151 |
+
"move": "no-op",
|
| 152 |
+
"view": "turn right"
|
| 153 |
+
},
|
| 154 |
+
{
|
| 155 |
+
"move": "no-op",
|
| 156 |
+
"view": "turn right"
|
| 157 |
+
},
|
| 158 |
+
{
|
| 159 |
+
"move": "no-op",
|
| 160 |
+
"view": "turn right"
|
| 161 |
+
},
|
| 162 |
+
{
|
| 163 |
+
"move": "no-op",
|
| 164 |
+
"view": "turn right"
|
| 165 |
+
},
|
| 166 |
+
{
|
| 167 |
+
"move": "no-op",
|
| 168 |
+
"view": "turn right"
|
| 169 |
+
},
|
| 170 |
+
{
|
| 171 |
+
"move": "no-op",
|
| 172 |
+
"view": "turn right"
|
| 173 |
+
},
|
| 174 |
+
{
|
| 175 |
+
"move": "no-op",
|
| 176 |
+
"view": "turn right"
|
| 177 |
+
},
|
| 178 |
+
{
|
| 179 |
+
"move": "no-op",
|
| 180 |
+
"view": "turn right"
|
| 181 |
+
},
|
| 182 |
+
{
|
| 183 |
+
"move": "no-op",
|
| 184 |
+
"view": "turn right"
|
| 185 |
+
},
|
| 186 |
+
{
|
| 187 |
+
"move": "no-op",
|
| 188 |
+
"view": "turn right"
|
| 189 |
+
},
|
| 190 |
+
{
|
| 191 |
+
"move": "no-op",
|
| 192 |
+
"view": "turn right"
|
| 193 |
+
},
|
| 194 |
+
{
|
| 195 |
+
"move": "no-op",
|
| 196 |
+
"view": "turn right"
|
| 197 |
+
},
|
| 198 |
+
{
|
| 199 |
+
"move": "no-op",
|
| 200 |
+
"view": "turn right"
|
| 201 |
+
},
|
| 202 |
+
{
|
| 203 |
+
"move": "no-op",
|
| 204 |
+
"view": "turn right"
|
| 205 |
+
},
|
| 206 |
+
{
|
| 207 |
+
"move": "no-op",
|
| 208 |
+
"view": "turn right"
|
| 209 |
+
},
|
| 210 |
+
{
|
| 211 |
+
"move": "no-op",
|
| 212 |
+
"view": "turn right"
|
| 213 |
+
},
|
| 214 |
+
{
|
| 215 |
+
"move": "no-op",
|
| 216 |
+
"view": "turn right"
|
| 217 |
+
},
|
| 218 |
+
{
|
| 219 |
+
"move": "no-op",
|
| 220 |
+
"view": "turn right"
|
| 221 |
+
},
|
| 222 |
+
{
|
| 223 |
+
"move": "no-op",
|
| 224 |
+
"view": "turn right"
|
| 225 |
+
},
|
| 226 |
+
{
|
| 227 |
+
"move": "no-op",
|
| 228 |
+
"view": "turn right"
|
| 229 |
+
},
|
| 230 |
+
{
|
| 231 |
+
"move": "no-op",
|
| 232 |
+
"view": "turn right"
|
| 233 |
+
},
|
| 234 |
+
{
|
| 235 |
+
"move": "no-op",
|
| 236 |
+
"view": "turn right"
|
| 237 |
+
},
|
| 238 |
+
{
|
| 239 |
+
"move": "no-op",
|
| 240 |
+
"view": "turn right"
|
| 241 |
+
},
|
| 242 |
+
{
|
| 243 |
+
"move": "no-op",
|
| 244 |
+
"view": "turn right"
|
| 245 |
+
},
|
| 246 |
+
{
|
| 247 |
+
"move": "no-op",
|
| 248 |
+
"view": "turn right"
|
| 249 |
+
},
|
| 250 |
+
{
|
| 251 |
+
"move": "no-op",
|
| 252 |
+
"view": "turn right"
|
| 253 |
+
},
|
| 254 |
+
{
|
| 255 |
+
"move": "no-op",
|
| 256 |
+
"view": "turn right"
|
| 257 |
+
},
|
| 258 |
+
{
|
| 259 |
+
"move": "no-op",
|
| 260 |
+
"view": "turn right"
|
| 261 |
+
},
|
| 262 |
+
{
|
| 263 |
+
"move": "no-op",
|
| 264 |
+
"view": "turn right"
|
| 265 |
+
},
|
| 266 |
+
{
|
| 267 |
+
"move": "no-op",
|
| 268 |
+
"view": "turn right"
|
| 269 |
+
},
|
| 270 |
+
{
|
| 271 |
+
"move": "no-op",
|
| 272 |
+
"view": "turn right"
|
| 273 |
+
},
|
| 274 |
+
{
|
| 275 |
+
"move": "no-op",
|
| 276 |
+
"view": "turn right"
|
| 277 |
+
},
|
| 278 |
+
{
|
| 279 |
+
"move": "no-op",
|
| 280 |
+
"view": "turn right"
|
| 281 |
+
},
|
| 282 |
+
{
|
| 283 |
+
"move": "no-op",
|
| 284 |
+
"view": "turn right"
|
| 285 |
+
},
|
| 286 |
+
{
|
| 287 |
+
"move": "no-op",
|
| 288 |
+
"view": "turn right"
|
| 289 |
+
},
|
| 290 |
+
{
|
| 291 |
+
"move": "no-op",
|
| 292 |
+
"view": "turn right"
|
| 293 |
+
},
|
| 294 |
+
{
|
| 295 |
+
"move": "no-op",
|
| 296 |
+
"view": "turn right"
|
| 297 |
+
},
|
| 298 |
+
{
|
| 299 |
+
"move": "no-op",
|
| 300 |
+
"view": "turn right"
|
| 301 |
+
},
|
| 302 |
+
{
|
| 303 |
+
"move": "no-op",
|
| 304 |
+
"view": "turn right"
|
| 305 |
+
},
|
| 306 |
+
{
|
| 307 |
+
"move": "no-op",
|
| 308 |
+
"view": "turn right"
|
| 309 |
+
},
|
| 310 |
+
{
|
| 311 |
+
"move": "no-op",
|
| 312 |
+
"view": "turn right"
|
| 313 |
+
},
|
| 314 |
+
{
|
| 315 |
+
"move": "no-op",
|
| 316 |
+
"view": "turn right"
|
| 317 |
+
},
|
| 318 |
+
{
|
| 319 |
+
"move": "no-op",
|
| 320 |
+
"view": "turn right"
|
| 321 |
+
},
|
| 322 |
+
{
|
| 323 |
+
"move": "no-op",
|
| 324 |
+
"view": "turn right"
|
| 325 |
+
},
|
| 326 |
+
{
|
| 327 |
+
"move": "go forward",
|
| 328 |
+
"view": "no-op"
|
| 329 |
+
},
|
| 330 |
+
{
|
| 331 |
+
"move": "go forward",
|
| 332 |
+
"view": "no-op"
|
| 333 |
+
},
|
| 334 |
+
{
|
| 335 |
+
"move": "go forward",
|
| 336 |
+
"view": "no-op"
|
| 337 |
+
},
|
| 338 |
+
{
|
| 339 |
+
"move": "go forward",
|
| 340 |
+
"view": "no-op"
|
| 341 |
+
},
|
| 342 |
+
{
|
| 343 |
+
"move": "go forward",
|
| 344 |
+
"view": "no-op"
|
| 345 |
+
},
|
| 346 |
+
{
|
| 347 |
+
"move": "go forward",
|
| 348 |
+
"view": "no-op"
|
| 349 |
+
},
|
| 350 |
+
{
|
| 351 |
+
"move": "go forward",
|
| 352 |
+
"view": "no-op"
|
| 353 |
+
},
|
| 354 |
+
{
|
| 355 |
+
"move": "go forward",
|
| 356 |
+
"view": "no-op"
|
| 357 |
+
},
|
| 358 |
+
{
|
| 359 |
+
"move": "go forward",
|
| 360 |
+
"view": "no-op"
|
| 361 |
+
},
|
| 362 |
+
{
|
| 363 |
+
"move": "go forward",
|
| 364 |
+
"view": "no-op"
|
| 365 |
+
},
|
| 366 |
+
{
|
| 367 |
+
"move": "go forward",
|
| 368 |
+
"view": "no-op"
|
| 369 |
+
},
|
| 370 |
+
{
|
| 371 |
+
"move": "go forward",
|
| 372 |
+
"view": "no-op"
|
| 373 |
+
},
|
| 374 |
+
{
|
| 375 |
+
"move": "go forward",
|
| 376 |
+
"view": "no-op"
|
| 377 |
+
},
|
| 378 |
+
{
|
| 379 |
+
"move": "go forward",
|
| 380 |
+
"view": "no-op"
|
| 381 |
+
},
|
| 382 |
+
{
|
| 383 |
+
"move": "go forward",
|
| 384 |
+
"view": "no-op"
|
| 385 |
+
},
|
| 386 |
+
{
|
| 387 |
+
"move": "go forward",
|
| 388 |
+
"view": "no-op"
|
| 389 |
+
},
|
| 390 |
+
{
|
| 391 |
+
"move": "go forward",
|
| 392 |
+
"view": "no-op"
|
| 393 |
+
},
|
| 394 |
+
{
|
| 395 |
+
"move": "go forward",
|
| 396 |
+
"view": "no-op"
|
| 397 |
+
},
|
| 398 |
+
{
|
| 399 |
+
"move": "go forward",
|
| 400 |
+
"view": "no-op"
|
| 401 |
+
},
|
| 402 |
+
{
|
| 403 |
+
"move": "go forward",
|
| 404 |
+
"view": "no-op"
|
| 405 |
+
},
|
| 406 |
+
{
|
| 407 |
+
"move": "go forward",
|
| 408 |
+
"view": "no-op"
|
| 409 |
+
},
|
| 410 |
+
{
|
| 411 |
+
"move": "go forward",
|
| 412 |
+
"view": "no-op"
|
| 413 |
+
},
|
| 414 |
+
{
|
| 415 |
+
"move": "go forward",
|
| 416 |
+
"view": "no-op"
|
| 417 |
+
},
|
| 418 |
+
{
|
| 419 |
+
"move": "go forward",
|
| 420 |
+
"view": "no-op"
|
| 421 |
+
},
|
| 422 |
+
{
|
| 423 |
+
"move": "go forward",
|
| 424 |
+
"view": "no-op"
|
| 425 |
+
},
|
| 426 |
+
{
|
| 427 |
+
"move": "go forward",
|
| 428 |
+
"view": "no-op"
|
| 429 |
+
},
|
| 430 |
+
{
|
| 431 |
+
"move": "go forward",
|
| 432 |
+
"view": "no-op"
|
| 433 |
+
},
|
| 434 |
+
{
|
| 435 |
+
"move": "go forward",
|
| 436 |
+
"view": "no-op"
|
| 437 |
+
},
|
| 438 |
+
{
|
| 439 |
+
"move": "go forward",
|
| 440 |
+
"view": "no-op"
|
| 441 |
+
},
|
| 442 |
+
{
|
| 443 |
+
"move": "go forward",
|
| 444 |
+
"view": "no-op"
|
| 445 |
+
},
|
| 446 |
+
{
|
| 447 |
+
"move": "go forward",
|
| 448 |
+
"view": "no-op"
|
| 449 |
+
},
|
| 450 |
+
{
|
| 451 |
+
"move": "go forward",
|
| 452 |
+
"view": "no-op"
|
| 453 |
+
},
|
| 454 |
+
{
|
| 455 |
+
"move": "go forward",
|
| 456 |
+
"view": "no-op"
|
| 457 |
+
},
|
| 458 |
+
{
|
| 459 |
+
"move": "go forward",
|
| 460 |
+
"view": "no-op"
|
| 461 |
+
},
|
| 462 |
+
{
|
| 463 |
+
"move": "go forward",
|
| 464 |
+
"view": "no-op"
|
| 465 |
+
},
|
| 466 |
+
{
|
| 467 |
+
"move": "go forward",
|
| 468 |
+
"view": "no-op"
|
| 469 |
+
},
|
| 470 |
+
{
|
| 471 |
+
"move": "go forward",
|
| 472 |
+
"view": "no-op"
|
| 473 |
+
},
|
| 474 |
+
{
|
| 475 |
+
"move": "go forward",
|
| 476 |
+
"view": "no-op"
|
| 477 |
+
},
|
| 478 |
+
{
|
| 479 |
+
"move": "go forward",
|
| 480 |
+
"view": "no-op"
|
| 481 |
+
},
|
| 482 |
+
{
|
| 483 |
+
"move": "go forward",
|
| 484 |
+
"view": "no-op"
|
| 485 |
+
},
|
| 486 |
+
{
|
| 487 |
+
"move": "go forward",
|
| 488 |
+
"view": "no-op"
|
| 489 |
+
},
|
| 490 |
+
{
|
| 491 |
+
"move": "go forward",
|
| 492 |
+
"view": "no-op"
|
| 493 |
+
},
|
| 494 |
+
{
|
| 495 |
+
"move": "go forward",
|
| 496 |
+
"view": "no-op"
|
| 497 |
+
},
|
| 498 |
+
{
|
| 499 |
+
"move": "go forward",
|
| 500 |
+
"view": "no-op"
|
| 501 |
+
},
|
| 502 |
+
{
|
| 503 |
+
"move": "go forward",
|
| 504 |
+
"view": "no-op"
|
| 505 |
+
},
|
| 506 |
+
{
|
| 507 |
+
"move": "go forward",
|
| 508 |
+
"view": "no-op"
|
| 509 |
+
},
|
| 510 |
+
{
|
| 511 |
+
"move": "go forward",
|
| 512 |
+
"view": "no-op"
|
| 513 |
+
},
|
| 514 |
+
{
|
| 515 |
+
"move": "go forward",
|
| 516 |
+
"view": "no-op"
|
| 517 |
+
},
|
| 518 |
+
{
|
| 519 |
+
"move": "go forward",
|
| 520 |
+
"view": "no-op"
|
| 521 |
+
},
|
| 522 |
+
{
|
| 523 |
+
"move": "go forward",
|
| 524 |
+
"view": "no-op"
|
| 525 |
+
},
|
| 526 |
+
{
|
| 527 |
+
"move": "go forward",
|
| 528 |
+
"view": "no-op"
|
| 529 |
+
},
|
| 530 |
+
{
|
| 531 |
+
"move": "go forward",
|
| 532 |
+
"view": "no-op"
|
| 533 |
+
},
|
| 534 |
+
{
|
| 535 |
+
"move": "go forward",
|
| 536 |
+
"view": "no-op"
|
| 537 |
+
},
|
| 538 |
+
{
|
| 539 |
+
"move": "go forward",
|
| 540 |
+
"view": "no-op"
|
| 541 |
+
},
|
| 542 |
+
{
|
| 543 |
+
"move": "go forward",
|
| 544 |
+
"view": "no-op"
|
| 545 |
+
},
|
| 546 |
+
{
|
| 547 |
+
"move": "go forward",
|
| 548 |
+
"view": "no-op"
|
| 549 |
+
},
|
| 550 |
+
{
|
| 551 |
+
"move": "go forward",
|
| 552 |
+
"view": "no-op"
|
| 553 |
+
},
|
| 554 |
+
{
|
| 555 |
+
"move": "go forward",
|
| 556 |
+
"view": "no-op"
|
| 557 |
+
},
|
| 558 |
+
{
|
| 559 |
+
"move": "go forward",
|
| 560 |
+
"view": "no-op"
|
| 561 |
+
},
|
| 562 |
+
{
|
| 563 |
+
"move": "go forward",
|
| 564 |
+
"view": "no-op"
|
| 565 |
+
},
|
| 566 |
+
{
|
| 567 |
+
"move": "go forward",
|
| 568 |
+
"view": "no-op"
|
| 569 |
+
},
|
| 570 |
+
{
|
| 571 |
+
"move": "go forward",
|
| 572 |
+
"view": "no-op"
|
| 573 |
+
},
|
| 574 |
+
{
|
| 575 |
+
"move": "go forward",
|
| 576 |
+
"view": "no-op"
|
| 577 |
+
},
|
| 578 |
+
{
|
| 579 |
+
"move": "go forward",
|
| 580 |
+
"view": "no-op"
|
| 581 |
+
},
|
| 582 |
+
{
|
| 583 |
+
"move": "go forward",
|
| 584 |
+
"view": "no-op"
|
| 585 |
+
},
|
| 586 |
+
{
|
| 587 |
+
"move": "go forward",
|
| 588 |
+
"view": "no-op"
|
| 589 |
+
},
|
| 590 |
+
{
|
| 591 |
+
"move": "go forward",
|
| 592 |
+
"view": "no-op"
|
| 593 |
+
},
|
| 594 |
+
{
|
| 595 |
+
"move": "go forward",
|
| 596 |
+
"view": "no-op"
|
| 597 |
+
},
|
| 598 |
+
{
|
| 599 |
+
"move": "go forward",
|
| 600 |
+
"view": "no-op"
|
| 601 |
+
},
|
| 602 |
+
{
|
| 603 |
+
"move": "go forward",
|
| 604 |
+
"view": "no-op"
|
| 605 |
+
},
|
| 606 |
+
{
|
| 607 |
+
"move": "go forward",
|
| 608 |
+
"view": "no-op"
|
| 609 |
+
},
|
| 610 |
+
{
|
| 611 |
+
"move": "go forward",
|
| 612 |
+
"view": "no-op"
|
| 613 |
+
},
|
| 614 |
+
{
|
| 615 |
+
"move": "go forward",
|
| 616 |
+
"view": "no-op"
|
| 617 |
+
},
|
| 618 |
+
{
|
| 619 |
+
"move": "go forward",
|
| 620 |
+
"view": "no-op"
|
| 621 |
+
},
|
| 622 |
+
{
|
| 623 |
+
"move": "go forward",
|
| 624 |
+
"view": "no-op"
|
| 625 |
+
},
|
| 626 |
+
{
|
| 627 |
+
"move": "go forward",
|
| 628 |
+
"view": "no-op"
|
| 629 |
+
},
|
| 630 |
+
{
|
| 631 |
+
"move": "go forward",
|
| 632 |
+
"view": "no-op"
|
| 633 |
+
},
|
| 634 |
+
{
|
| 635 |
+
"move": "go forward",
|
| 636 |
+
"view": "no-op"
|
| 637 |
+
},
|
| 638 |
+
{
|
| 639 |
+
"move": "go forward",
|
| 640 |
+
"view": "no-op"
|
| 641 |
+
},
|
| 642 |
+
{
|
| 643 |
+
"move": "go forward",
|
| 644 |
+
"view": "no-op"
|
| 645 |
+
},
|
| 646 |
+
{
|
| 647 |
+
"move": "go forward",
|
| 648 |
+
"view": "no-op"
|
| 649 |
+
},
|
| 650 |
+
{
|
| 651 |
+
"move": "no-op",
|
| 652 |
+
"view": "turn left"
|
| 653 |
+
},
|
| 654 |
+
{
|
| 655 |
+
"move": "no-op",
|
| 656 |
+
"view": "turn left"
|
| 657 |
+
},
|
| 658 |
+
{
|
| 659 |
+
"move": "no-op",
|
| 660 |
+
"view": "turn left"
|
| 661 |
+
},
|
| 662 |
+
{
|
| 663 |
+
"move": "no-op",
|
| 664 |
+
"view": "turn left"
|
| 665 |
+
},
|
| 666 |
+
{
|
| 667 |
+
"move": "no-op",
|
| 668 |
+
"view": "turn left"
|
| 669 |
+
},
|
| 670 |
+
{
|
| 671 |
+
"move": "no-op",
|
| 672 |
+
"view": "turn left"
|
| 673 |
+
},
|
| 674 |
+
{
|
| 675 |
+
"move": "no-op",
|
| 676 |
+
"view": "turn left"
|
| 677 |
+
},
|
| 678 |
+
{
|
| 679 |
+
"move": "no-op",
|
| 680 |
+
"view": "turn left"
|
| 681 |
+
},
|
| 682 |
+
{
|
| 683 |
+
"move": "no-op",
|
| 684 |
+
"view": "turn left"
|
| 685 |
+
},
|
| 686 |
+
{
|
| 687 |
+
"move": "no-op",
|
| 688 |
+
"view": "turn left"
|
| 689 |
+
},
|
| 690 |
+
{
|
| 691 |
+
"move": "no-op",
|
| 692 |
+
"view": "turn left"
|
| 693 |
+
},
|
| 694 |
+
{
|
| 695 |
+
"move": "no-op",
|
| 696 |
+
"view": "turn left"
|
| 697 |
+
},
|
| 698 |
+
{
|
| 699 |
+
"move": "no-op",
|
| 700 |
+
"view": "turn left"
|
| 701 |
+
},
|
| 702 |
+
{
|
| 703 |
+
"move": "no-op",
|
| 704 |
+
"view": "turn left"
|
| 705 |
+
},
|
| 706 |
+
{
|
| 707 |
+
"move": "no-op",
|
| 708 |
+
"view": "turn left"
|
| 709 |
+
},
|
| 710 |
+
{
|
| 711 |
+
"move": "no-op",
|
| 712 |
+
"view": "turn left"
|
| 713 |
+
},
|
| 714 |
+
{
|
| 715 |
+
"move": "no-op",
|
| 716 |
+
"view": "turn left"
|
| 717 |
+
},
|
| 718 |
+
{
|
| 719 |
+
"move": "no-op",
|
| 720 |
+
"view": "turn left"
|
| 721 |
+
},
|
| 722 |
+
{
|
| 723 |
+
"move": "no-op",
|
| 724 |
+
"view": "turn left"
|
| 725 |
+
},
|
| 726 |
+
{
|
| 727 |
+
"move": "no-op",
|
| 728 |
+
"view": "turn left"
|
| 729 |
+
},
|
| 730 |
+
{
|
| 731 |
+
"move": "no-op",
|
| 732 |
+
"view": "turn left"
|
| 733 |
+
},
|
| 734 |
+
{
|
| 735 |
+
"move": "no-op",
|
| 736 |
+
"view": "turn left"
|
| 737 |
+
},
|
| 738 |
+
{
|
| 739 |
+
"move": "no-op",
|
| 740 |
+
"view": "turn left"
|
| 741 |
+
},
|
| 742 |
+
{
|
| 743 |
+
"move": "no-op",
|
| 744 |
+
"view": "turn left"
|
| 745 |
+
},
|
| 746 |
+
{
|
| 747 |
+
"move": "no-op",
|
| 748 |
+
"view": "turn left"
|
| 749 |
+
},
|
| 750 |
+
{
|
| 751 |
+
"move": "no-op",
|
| 752 |
+
"view": "turn left"
|
| 753 |
+
},
|
| 754 |
+
{
|
| 755 |
+
"move": "no-op",
|
| 756 |
+
"view": "turn left"
|
| 757 |
+
},
|
| 758 |
+
{
|
| 759 |
+
"move": "no-op",
|
| 760 |
+
"view": "turn left"
|
| 761 |
+
},
|
| 762 |
+
{
|
| 763 |
+
"move": "no-op",
|
| 764 |
+
"view": "turn left"
|
| 765 |
+
},
|
| 766 |
+
{
|
| 767 |
+
"move": "no-op",
|
| 768 |
+
"view": "turn left"
|
| 769 |
+
},
|
| 770 |
+
{
|
| 771 |
+
"move": "no-op",
|
| 772 |
+
"view": "turn left"
|
| 773 |
+
},
|
| 774 |
+
{
|
| 775 |
+
"move": "no-op",
|
| 776 |
+
"view": "turn left"
|
| 777 |
+
},
|
| 778 |
+
{
|
| 779 |
+
"move": "no-op",
|
| 780 |
+
"view": "turn left"
|
| 781 |
+
},
|
| 782 |
+
{
|
| 783 |
+
"move": "no-op",
|
| 784 |
+
"view": "turn left"
|
| 785 |
+
},
|
| 786 |
+
{
|
| 787 |
+
"move": "no-op",
|
| 788 |
+
"view": "turn left"
|
| 789 |
+
},
|
| 790 |
+
{
|
| 791 |
+
"move": "no-op",
|
| 792 |
+
"view": "turn left"
|
| 793 |
+
},
|
| 794 |
+
{
|
| 795 |
+
"move": "no-op",
|
| 796 |
+
"view": "turn left"
|
| 797 |
+
},
|
| 798 |
+
{
|
| 799 |
+
"move": "no-op",
|
| 800 |
+
"view": "turn left"
|
| 801 |
+
},
|
| 802 |
+
{
|
| 803 |
+
"move": "no-op",
|
| 804 |
+
"view": "turn left"
|
| 805 |
+
},
|
| 806 |
+
{
|
| 807 |
+
"move": "no-op",
|
| 808 |
+
"view": "turn left"
|
| 809 |
+
},
|
| 810 |
+
{
|
| 811 |
+
"move": "no-op",
|
| 812 |
+
"view": "turn left"
|
| 813 |
+
},
|
| 814 |
+
{
|
| 815 |
+
"move": "no-op",
|
| 816 |
+
"view": "turn left"
|
| 817 |
+
},
|
| 818 |
+
{
|
| 819 |
+
"move": "no-op",
|
| 820 |
+
"view": "turn left"
|
| 821 |
+
},
|
| 822 |
+
{
|
| 823 |
+
"move": "no-op",
|
| 824 |
+
"view": "turn left"
|
| 825 |
+
},
|
| 826 |
+
{
|
| 827 |
+
"move": "no-op",
|
| 828 |
+
"view": "turn left"
|
| 829 |
+
},
|
| 830 |
+
{
|
| 831 |
+
"move": "no-op",
|
| 832 |
+
"view": "turn left"
|
| 833 |
+
},
|
| 834 |
+
{
|
| 835 |
+
"move": "no-op",
|
| 836 |
+
"view": "turn left"
|
| 837 |
+
},
|
| 838 |
+
{
|
| 839 |
+
"move": "no-op",
|
| 840 |
+
"view": "turn left"
|
| 841 |
+
},
|
| 842 |
+
{
|
| 843 |
+
"move": "no-op",
|
| 844 |
+
"view": "turn left"
|
| 845 |
+
},
|
| 846 |
+
{
|
| 847 |
+
"move": "no-op",
|
| 848 |
+
"view": "turn left"
|
| 849 |
+
},
|
| 850 |
+
{
|
| 851 |
+
"move": "no-op",
|
| 852 |
+
"view": "turn left"
|
| 853 |
+
},
|
| 854 |
+
{
|
| 855 |
+
"move": "no-op",
|
| 856 |
+
"view": "turn left"
|
| 857 |
+
},
|
| 858 |
+
{
|
| 859 |
+
"move": "no-op",
|
| 860 |
+
"view": "turn left"
|
| 861 |
+
},
|
| 862 |
+
{
|
| 863 |
+
"move": "no-op",
|
| 864 |
+
"view": "turn left"
|
| 865 |
+
},
|
| 866 |
+
{
|
| 867 |
+
"move": "no-op",
|
| 868 |
+
"view": "turn left"
|
| 869 |
+
},
|
| 870 |
+
{
|
| 871 |
+
"move": "no-op",
|
| 872 |
+
"view": "turn left"
|
| 873 |
+
},
|
| 874 |
+
{
|
| 875 |
+
"move": "no-op",
|
| 876 |
+
"view": "turn left"
|
| 877 |
+
},
|
| 878 |
+
{
|
| 879 |
+
"move": "no-op",
|
| 880 |
+
"view": "turn left"
|
| 881 |
+
},
|
| 882 |
+
{
|
| 883 |
+
"move": "no-op",
|
| 884 |
+
"view": "turn left"
|
| 885 |
+
},
|
| 886 |
+
{
|
| 887 |
+
"move": "no-op",
|
| 888 |
+
"view": "turn left"
|
| 889 |
+
},
|
| 890 |
+
{
|
| 891 |
+
"move": "no-op",
|
| 892 |
+
"view": "turn left"
|
| 893 |
+
},
|
| 894 |
+
{
|
| 895 |
+
"move": "no-op",
|
| 896 |
+
"view": "turn left"
|
| 897 |
+
},
|
| 898 |
+
{
|
| 899 |
+
"move": "no-op",
|
| 900 |
+
"view": "turn left"
|
| 901 |
+
},
|
| 902 |
+
{
|
| 903 |
+
"move": "no-op",
|
| 904 |
+
"view": "turn left"
|
| 905 |
+
},
|
| 906 |
+
{
|
| 907 |
+
"move": "no-op",
|
| 908 |
+
"view": "turn left"
|
| 909 |
+
},
|
| 910 |
+
{
|
| 911 |
+
"move": "no-op",
|
| 912 |
+
"view": "turn left"
|
| 913 |
+
},
|
| 914 |
+
{
|
| 915 |
+
"move": "no-op",
|
| 916 |
+
"view": "turn left"
|
| 917 |
+
},
|
| 918 |
+
{
|
| 919 |
+
"move": "no-op",
|
| 920 |
+
"view": "turn left"
|
| 921 |
+
},
|
| 922 |
+
{
|
| 923 |
+
"move": "no-op",
|
| 924 |
+
"view": "turn left"
|
| 925 |
+
},
|
| 926 |
+
{
|
| 927 |
+
"move": "no-op",
|
| 928 |
+
"view": "turn left"
|
| 929 |
+
},
|
| 930 |
+
{
|
| 931 |
+
"move": "no-op",
|
| 932 |
+
"view": "turn left"
|
| 933 |
+
},
|
| 934 |
+
{
|
| 935 |
+
"move": "no-op",
|
| 936 |
+
"view": "turn left"
|
| 937 |
+
},
|
| 938 |
+
{
|
| 939 |
+
"move": "no-op",
|
| 940 |
+
"view": "turn left"
|
| 941 |
+
},
|
| 942 |
+
{
|
| 943 |
+
"move": "no-op",
|
| 944 |
+
"view": "turn left"
|
| 945 |
+
},
|
| 946 |
+
{
|
| 947 |
+
"move": "no-op",
|
| 948 |
+
"view": "turn left"
|
| 949 |
+
},
|
| 950 |
+
{
|
| 951 |
+
"move": "no-op",
|
| 952 |
+
"view": "turn left"
|
| 953 |
+
},
|
| 954 |
+
{
|
| 955 |
+
"move": "no-op",
|
| 956 |
+
"view": "turn left"
|
| 957 |
+
},
|
| 958 |
+
{
|
| 959 |
+
"move": "no-op",
|
| 960 |
+
"view": "turn left"
|
| 961 |
+
},
|
| 962 |
+
{
|
| 963 |
+
"move": "no-op",
|
| 964 |
+
"view": "turn left"
|
| 965 |
+
},
|
| 966 |
+
{
|
| 967 |
+
"move": "no-op",
|
| 968 |
+
"view": "turn left"
|
| 969 |
+
},
|
| 970 |
+
{
|
| 971 |
+
"move": "no-op",
|
| 972 |
+
"view": "turn left"
|
| 973 |
+
},
|
| 974 |
+
{
|
| 975 |
+
"move": "no-op",
|
| 976 |
+
"view": "turn left"
|
| 977 |
+
},
|
| 978 |
+
{
|
| 979 |
+
"move": "no-op",
|
| 980 |
+
"view": "turn left"
|
| 981 |
+
},
|
| 982 |
+
{
|
| 983 |
+
"move": "no-op",
|
| 984 |
+
"view": "turn left"
|
| 985 |
+
},
|
| 986 |
+
{
|
| 987 |
+
"move": "no-op",
|
| 988 |
+
"view": "turn left"
|
| 989 |
+
},
|
| 990 |
+
{
|
| 991 |
+
"move": "no-op",
|
| 992 |
+
"view": "turn left"
|
| 993 |
+
},
|
| 994 |
+
{
|
| 995 |
+
"move": "no-op",
|
| 996 |
+
"view": "turn left"
|
| 997 |
+
},
|
| 998 |
+
{
|
| 999 |
+
"move": "no-op",
|
| 1000 |
+
"view": "turn left"
|
| 1001 |
+
},
|
| 1002 |
+
{
|
| 1003 |
+
"move": "no-op",
|
| 1004 |
+
"view": "turn left"
|
| 1005 |
+
},
|
| 1006 |
+
{
|
| 1007 |
+
"move": "no-op",
|
| 1008 |
+
"view": "turn left"
|
| 1009 |
+
},
|
| 1010 |
+
{
|
| 1011 |
+
"move": "no-op",
|
| 1012 |
+
"view": "turn left"
|
| 1013 |
+
},
|
| 1014 |
+
{
|
| 1015 |
+
"move": "no-op",
|
| 1016 |
+
"view": "turn left"
|
| 1017 |
+
},
|
| 1018 |
+
{
|
| 1019 |
+
"move": "no-op",
|
| 1020 |
+
"view": "turn left"
|
| 1021 |
+
},
|
| 1022 |
+
{
|
| 1023 |
+
"move": "no-op",
|
| 1024 |
+
"view": "turn left"
|
| 1025 |
+
},
|
| 1026 |
+
{
|
| 1027 |
+
"move": "no-op",
|
| 1028 |
+
"view": "turn left"
|
| 1029 |
+
},
|
| 1030 |
+
{
|
| 1031 |
+
"move": "no-op",
|
| 1032 |
+
"view": "turn left"
|
| 1033 |
+
},
|
| 1034 |
+
{
|
| 1035 |
+
"move": "no-op",
|
| 1036 |
+
"view": "turn left"
|
| 1037 |
+
},
|
| 1038 |
+
{
|
| 1039 |
+
"move": "no-op",
|
| 1040 |
+
"view": "turn left"
|
| 1041 |
+
},
|
| 1042 |
+
{
|
| 1043 |
+
"move": "no-op",
|
| 1044 |
+
"view": "turn left"
|
| 1045 |
+
},
|
| 1046 |
+
{
|
| 1047 |
+
"move": "no-op",
|
| 1048 |
+
"view": "turn left"
|
| 1049 |
+
},
|
| 1050 |
+
{
|
| 1051 |
+
"move": "no-op",
|
| 1052 |
+
"view": "turn left"
|
| 1053 |
+
},
|
| 1054 |
+
{
|
| 1055 |
+
"move": "no-op",
|
| 1056 |
+
"view": "turn left"
|
| 1057 |
+
},
|
| 1058 |
+
{
|
| 1059 |
+
"move": "no-op",
|
| 1060 |
+
"view": "turn left"
|
| 1061 |
+
},
|
| 1062 |
+
{
|
| 1063 |
+
"move": "no-op",
|
| 1064 |
+
"view": "turn left"
|
| 1065 |
+
},
|
| 1066 |
+
{
|
| 1067 |
+
"move": "no-op",
|
| 1068 |
+
"view": "turn left"
|
| 1069 |
+
},
|
| 1070 |
+
{
|
| 1071 |
+
"move": "no-op",
|
| 1072 |
+
"view": "turn left"
|
| 1073 |
+
},
|
| 1074 |
+
{
|
| 1075 |
+
"move": "no-op",
|
| 1076 |
+
"view": "turn left"
|
| 1077 |
+
},
|
| 1078 |
+
{
|
| 1079 |
+
"move": "no-op",
|
| 1080 |
+
"view": "turn left"
|
| 1081 |
+
},
|
| 1082 |
+
{
|
| 1083 |
+
"move": "no-op",
|
| 1084 |
+
"view": "turn left"
|
| 1085 |
+
},
|
| 1086 |
+
{
|
| 1087 |
+
"move": "no-op",
|
| 1088 |
+
"view": "turn left"
|
| 1089 |
+
},
|
| 1090 |
+
{
|
| 1091 |
+
"move": "no-op",
|
| 1092 |
+
"view": "turn left"
|
| 1093 |
+
},
|
| 1094 |
+
{
|
| 1095 |
+
"move": "no-op",
|
| 1096 |
+
"view": "turn left"
|
| 1097 |
+
},
|
| 1098 |
+
{
|
| 1099 |
+
"move": "no-op",
|
| 1100 |
+
"view": "turn left"
|
| 1101 |
+
},
|
| 1102 |
+
{
|
| 1103 |
+
"move": "no-op",
|
| 1104 |
+
"view": "turn left"
|
| 1105 |
+
},
|
| 1106 |
+
{
|
| 1107 |
+
"move": "no-op",
|
| 1108 |
+
"view": "turn left"
|
| 1109 |
+
},
|
| 1110 |
+
{
|
| 1111 |
+
"move": "no-op",
|
| 1112 |
+
"view": "turn left"
|
| 1113 |
+
},
|
| 1114 |
+
{
|
| 1115 |
+
"move": "no-op",
|
| 1116 |
+
"view": "turn left"
|
| 1117 |
+
},
|
| 1118 |
+
{
|
| 1119 |
+
"move": "no-op",
|
| 1120 |
+
"view": "turn left"
|
| 1121 |
+
},
|
| 1122 |
+
{
|
| 1123 |
+
"move": "no-op",
|
| 1124 |
+
"view": "turn left"
|
| 1125 |
+
},
|
| 1126 |
+
{
|
| 1127 |
+
"move": "no-op",
|
| 1128 |
+
"view": "turn left"
|
| 1129 |
+
},
|
| 1130 |
+
{
|
| 1131 |
+
"move": "no-op",
|
| 1132 |
+
"view": "turn left"
|
| 1133 |
+
},
|
| 1134 |
+
{
|
| 1135 |
+
"move": "no-op",
|
| 1136 |
+
"view": "turn left"
|
| 1137 |
+
},
|
| 1138 |
+
{
|
| 1139 |
+
"move": "no-op",
|
| 1140 |
+
"view": "turn left"
|
| 1141 |
+
},
|
| 1142 |
+
{
|
| 1143 |
+
"move": "no-op",
|
| 1144 |
+
"view": "turn left"
|
| 1145 |
+
},
|
| 1146 |
+
{
|
| 1147 |
+
"move": "no-op",
|
| 1148 |
+
"view": "turn left"
|
| 1149 |
+
},
|
| 1150 |
+
{
|
| 1151 |
+
"move": "no-op",
|
| 1152 |
+
"view": "turn left"
|
| 1153 |
+
},
|
| 1154 |
+
{
|
| 1155 |
+
"move": "no-op",
|
| 1156 |
+
"view": "turn left"
|
| 1157 |
+
},
|
| 1158 |
+
{
|
| 1159 |
+
"move": "no-op",
|
| 1160 |
+
"view": "turn left"
|
| 1161 |
+
},
|
| 1162 |
+
{
|
| 1163 |
+
"move": "no-op",
|
| 1164 |
+
"view": "turn left"
|
| 1165 |
+
},
|
| 1166 |
+
{
|
| 1167 |
+
"move": "no-op",
|
| 1168 |
+
"view": "turn left"
|
| 1169 |
+
},
|
| 1170 |
+
{
|
| 1171 |
+
"move": "no-op",
|
| 1172 |
+
"view": "turn left"
|
| 1173 |
+
},
|
| 1174 |
+
{
|
| 1175 |
+
"move": "no-op",
|
| 1176 |
+
"view": "turn left"
|
| 1177 |
+
},
|
| 1178 |
+
{
|
| 1179 |
+
"move": "no-op",
|
| 1180 |
+
"view": "turn left"
|
| 1181 |
+
},
|
| 1182 |
+
{
|
| 1183 |
+
"move": "no-op",
|
| 1184 |
+
"view": "turn left"
|
| 1185 |
+
},
|
| 1186 |
+
{
|
| 1187 |
+
"move": "no-op",
|
| 1188 |
+
"view": "turn left"
|
| 1189 |
+
},
|
| 1190 |
+
{
|
| 1191 |
+
"move": "no-op",
|
| 1192 |
+
"view": "turn left"
|
| 1193 |
+
},
|
| 1194 |
+
{
|
| 1195 |
+
"move": "no-op",
|
| 1196 |
+
"view": "turn left"
|
| 1197 |
+
},
|
| 1198 |
+
{
|
| 1199 |
+
"move": "no-op",
|
| 1200 |
+
"view": "turn left"
|
| 1201 |
+
},
|
| 1202 |
+
{
|
| 1203 |
+
"move": "no-op",
|
| 1204 |
+
"view": "turn left"
|
| 1205 |
+
},
|
| 1206 |
+
{
|
| 1207 |
+
"move": "no-op",
|
| 1208 |
+
"view": "turn left"
|
| 1209 |
+
},
|
| 1210 |
+
{
|
| 1211 |
+
"move": "no-op",
|
| 1212 |
+
"view": "turn left"
|
| 1213 |
+
},
|
| 1214 |
+
{
|
| 1215 |
+
"move": "no-op",
|
| 1216 |
+
"view": "turn left"
|
| 1217 |
+
},
|
| 1218 |
+
{
|
| 1219 |
+
"move": "no-op",
|
| 1220 |
+
"view": "turn left"
|
| 1221 |
+
},
|
| 1222 |
+
{
|
| 1223 |
+
"move": "no-op",
|
| 1224 |
+
"view": "turn left"
|
| 1225 |
+
},
|
| 1226 |
+
{
|
| 1227 |
+
"move": "no-op",
|
| 1228 |
+
"view": "turn left"
|
| 1229 |
+
},
|
| 1230 |
+
{
|
| 1231 |
+
"move": "no-op",
|
| 1232 |
+
"view": "turn left"
|
| 1233 |
+
},
|
| 1234 |
+
{
|
| 1235 |
+
"move": "no-op",
|
| 1236 |
+
"view": "turn left"
|
| 1237 |
+
},
|
| 1238 |
+
{
|
| 1239 |
+
"move": "no-op",
|
| 1240 |
+
"view": "turn left"
|
| 1241 |
+
},
|
| 1242 |
+
{
|
| 1243 |
+
"move": "no-op",
|
| 1244 |
+
"view": "turn left"
|
| 1245 |
+
},
|
| 1246 |
+
{
|
| 1247 |
+
"move": "no-op",
|
| 1248 |
+
"view": "turn left"
|
| 1249 |
+
},
|
| 1250 |
+
{
|
| 1251 |
+
"move": "no-op",
|
| 1252 |
+
"view": "turn left"
|
| 1253 |
+
},
|
| 1254 |
+
{
|
| 1255 |
+
"move": "no-op",
|
| 1256 |
+
"view": "turn left"
|
| 1257 |
+
},
|
| 1258 |
+
{
|
| 1259 |
+
"move": "no-op",
|
| 1260 |
+
"view": "turn left"
|
| 1261 |
+
},
|
| 1262 |
+
{
|
| 1263 |
+
"move": "no-op",
|
| 1264 |
+
"view": "turn left"
|
| 1265 |
+
},
|
| 1266 |
+
{
|
| 1267 |
+
"move": "no-op",
|
| 1268 |
+
"view": "turn left"
|
| 1269 |
+
},
|
| 1270 |
+
{
|
| 1271 |
+
"move": "no-op",
|
| 1272 |
+
"view": "turn left"
|
| 1273 |
+
},
|
| 1274 |
+
{
|
| 1275 |
+
"move": "no-op",
|
| 1276 |
+
"view": "turn left"
|
| 1277 |
+
},
|
| 1278 |
+
{
|
| 1279 |
+
"move": "no-op",
|
| 1280 |
+
"view": "turn left"
|
| 1281 |
+
},
|
| 1282 |
+
{
|
| 1283 |
+
"move": "no-op",
|
| 1284 |
+
"view": "turn left"
|
| 1285 |
+
},
|
| 1286 |
+
{
|
| 1287 |
+
"move": "no-op",
|
| 1288 |
+
"view": "turn left"
|
| 1289 |
+
},
|
| 1290 |
+
{
|
| 1291 |
+
"move": "no-op",
|
| 1292 |
+
"view": "turn left"
|
| 1293 |
+
},
|
| 1294 |
+
{
|
| 1295 |
+
"move": "no-op",
|
| 1296 |
+
"view": "turn left"
|
| 1297 |
+
},
|
| 1298 |
+
{
|
| 1299 |
+
"move": "go forward",
|
| 1300 |
+
"view": "no-op"
|
| 1301 |
+
},
|
| 1302 |
+
{
|
| 1303 |
+
"move": "go forward",
|
| 1304 |
+
"view": "no-op"
|
| 1305 |
+
},
|
| 1306 |
+
{
|
| 1307 |
+
"move": "go forward",
|
| 1308 |
+
"view": "no-op"
|
| 1309 |
+
},
|
| 1310 |
+
{
|
| 1311 |
+
"move": "go forward",
|
| 1312 |
+
"view": "no-op"
|
| 1313 |
+
},
|
| 1314 |
+
{
|
| 1315 |
+
"move": "go forward",
|
| 1316 |
+
"view": "no-op"
|
| 1317 |
+
},
|
| 1318 |
+
{
|
| 1319 |
+
"move": "go forward",
|
| 1320 |
+
"view": "no-op"
|
| 1321 |
+
},
|
| 1322 |
+
{
|
| 1323 |
+
"move": "go forward",
|
| 1324 |
+
"view": "no-op"
|
| 1325 |
+
},
|
| 1326 |
+
{
|
| 1327 |
+
"move": "go forward",
|
| 1328 |
+
"view": "no-op"
|
| 1329 |
+
},
|
| 1330 |
+
{
|
| 1331 |
+
"move": "go forward",
|
| 1332 |
+
"view": "no-op"
|
| 1333 |
+
},
|
| 1334 |
+
{
|
| 1335 |
+
"move": "go forward",
|
| 1336 |
+
"view": "no-op"
|
| 1337 |
+
},
|
| 1338 |
+
{
|
| 1339 |
+
"move": "go forward",
|
| 1340 |
+
"view": "no-op"
|
| 1341 |
+
},
|
| 1342 |
+
{
|
| 1343 |
+
"move": "go forward",
|
| 1344 |
+
"view": "no-op"
|
| 1345 |
+
},
|
| 1346 |
+
{
|
| 1347 |
+
"move": "go forward",
|
| 1348 |
+
"view": "no-op"
|
| 1349 |
+
},
|
| 1350 |
+
{
|
| 1351 |
+
"move": "go forward",
|
| 1352 |
+
"view": "no-op"
|
| 1353 |
+
},
|
| 1354 |
+
{
|
| 1355 |
+
"move": "go forward",
|
| 1356 |
+
"view": "no-op"
|
| 1357 |
+
},
|
| 1358 |
+
{
|
| 1359 |
+
"move": "go forward",
|
| 1360 |
+
"view": "no-op"
|
| 1361 |
+
},
|
| 1362 |
+
{
|
| 1363 |
+
"move": "go forward",
|
| 1364 |
+
"view": "no-op"
|
| 1365 |
+
},
|
| 1366 |
+
{
|
| 1367 |
+
"move": "go forward",
|
| 1368 |
+
"view": "no-op"
|
| 1369 |
+
},
|
| 1370 |
+
{
|
| 1371 |
+
"move": "go forward",
|
| 1372 |
+
"view": "no-op"
|
| 1373 |
+
},
|
| 1374 |
+
{
|
| 1375 |
+
"move": "go forward",
|
| 1376 |
+
"view": "no-op"
|
| 1377 |
+
},
|
| 1378 |
+
{
|
| 1379 |
+
"move": "go forward",
|
| 1380 |
+
"view": "no-op"
|
| 1381 |
+
},
|
| 1382 |
+
{
|
| 1383 |
+
"move": "go forward",
|
| 1384 |
+
"view": "no-op"
|
| 1385 |
+
},
|
| 1386 |
+
{
|
| 1387 |
+
"move": "go forward",
|
| 1388 |
+
"view": "no-op"
|
| 1389 |
+
},
|
| 1390 |
+
{
|
| 1391 |
+
"move": "go forward",
|
| 1392 |
+
"view": "no-op"
|
| 1393 |
+
},
|
| 1394 |
+
{
|
| 1395 |
+
"move": "go forward",
|
| 1396 |
+
"view": "no-op"
|
| 1397 |
+
},
|
| 1398 |
+
{
|
| 1399 |
+
"move": "go forward",
|
| 1400 |
+
"view": "no-op"
|
| 1401 |
+
},
|
| 1402 |
+
{
|
| 1403 |
+
"move": "go forward",
|
| 1404 |
+
"view": "no-op"
|
| 1405 |
+
},
|
| 1406 |
+
{
|
| 1407 |
+
"move": "go forward",
|
| 1408 |
+
"view": "no-op"
|
| 1409 |
+
},
|
| 1410 |
+
{
|
| 1411 |
+
"move": "go forward",
|
| 1412 |
+
"view": "no-op"
|
| 1413 |
+
},
|
| 1414 |
+
{
|
| 1415 |
+
"move": "go forward",
|
| 1416 |
+
"view": "no-op"
|
| 1417 |
+
},
|
| 1418 |
+
{
|
| 1419 |
+
"move": "go forward",
|
| 1420 |
+
"view": "no-op"
|
| 1421 |
+
},
|
| 1422 |
+
{
|
| 1423 |
+
"move": "go forward",
|
| 1424 |
+
"view": "no-op"
|
| 1425 |
+
},
|
| 1426 |
+
{
|
| 1427 |
+
"move": "go forward",
|
| 1428 |
+
"view": "no-op"
|
| 1429 |
+
},
|
| 1430 |
+
{
|
| 1431 |
+
"move": "go forward",
|
| 1432 |
+
"view": "no-op"
|
| 1433 |
+
},
|
| 1434 |
+
{
|
| 1435 |
+
"move": "go forward",
|
| 1436 |
+
"view": "no-op"
|
| 1437 |
+
},
|
| 1438 |
+
{
|
| 1439 |
+
"move": "go forward",
|
| 1440 |
+
"view": "no-op"
|
| 1441 |
+
},
|
| 1442 |
+
{
|
| 1443 |
+
"move": "go forward",
|
| 1444 |
+
"view": "no-op"
|
| 1445 |
+
},
|
| 1446 |
+
{
|
| 1447 |
+
"move": "go forward",
|
| 1448 |
+
"view": "no-op"
|
| 1449 |
+
},
|
| 1450 |
+
{
|
| 1451 |
+
"move": "go forward",
|
| 1452 |
+
"view": "no-op"
|
| 1453 |
+
},
|
| 1454 |
+
{
|
| 1455 |
+
"move": "go forward",
|
| 1456 |
+
"view": "no-op"
|
| 1457 |
+
},
|
| 1458 |
+
{
|
| 1459 |
+
"move": "go forward",
|
| 1460 |
+
"view": "no-op"
|
| 1461 |
+
},
|
| 1462 |
+
{
|
| 1463 |
+
"move": "go forward",
|
| 1464 |
+
"view": "no-op"
|
| 1465 |
+
},
|
| 1466 |
+
{
|
| 1467 |
+
"move": "go forward",
|
| 1468 |
+
"view": "no-op"
|
| 1469 |
+
},
|
| 1470 |
+
{
|
| 1471 |
+
"move": "go forward",
|
| 1472 |
+
"view": "no-op"
|
| 1473 |
+
},
|
| 1474 |
+
{
|
| 1475 |
+
"move": "go forward",
|
| 1476 |
+
"view": "no-op"
|
| 1477 |
+
},
|
| 1478 |
+
{
|
| 1479 |
+
"move": "go forward",
|
| 1480 |
+
"view": "no-op"
|
| 1481 |
+
},
|
| 1482 |
+
{
|
| 1483 |
+
"move": "go forward",
|
| 1484 |
+
"view": "no-op"
|
| 1485 |
+
},
|
| 1486 |
+
{
|
| 1487 |
+
"move": "go forward",
|
| 1488 |
+
"view": "no-op"
|
| 1489 |
+
},
|
| 1490 |
+
{
|
| 1491 |
+
"move": "go forward",
|
| 1492 |
+
"view": "no-op"
|
| 1493 |
+
},
|
| 1494 |
+
{
|
| 1495 |
+
"move": "go forward",
|
| 1496 |
+
"view": "no-op"
|
| 1497 |
+
},
|
| 1498 |
+
{
|
| 1499 |
+
"move": "go forward",
|
| 1500 |
+
"view": "no-op"
|
| 1501 |
+
},
|
| 1502 |
+
{
|
| 1503 |
+
"move": "go forward",
|
| 1504 |
+
"view": "no-op"
|
| 1505 |
+
},
|
| 1506 |
+
{
|
| 1507 |
+
"move": "go forward",
|
| 1508 |
+
"view": "no-op"
|
| 1509 |
+
},
|
| 1510 |
+
{
|
| 1511 |
+
"move": "go forward",
|
| 1512 |
+
"view": "no-op"
|
| 1513 |
+
},
|
| 1514 |
+
{
|
| 1515 |
+
"move": "go forward",
|
| 1516 |
+
"view": "no-op"
|
| 1517 |
+
},
|
| 1518 |
+
{
|
| 1519 |
+
"move": "go forward",
|
| 1520 |
+
"view": "no-op"
|
| 1521 |
+
},
|
| 1522 |
+
{
|
| 1523 |
+
"move": "go forward",
|
| 1524 |
+
"view": "no-op"
|
| 1525 |
+
},
|
| 1526 |
+
{
|
| 1527 |
+
"move": "go forward",
|
| 1528 |
+
"view": "no-op"
|
| 1529 |
+
},
|
| 1530 |
+
{
|
| 1531 |
+
"move": "go forward",
|
| 1532 |
+
"view": "no-op"
|
| 1533 |
+
},
|
| 1534 |
+
{
|
| 1535 |
+
"move": "go forward",
|
| 1536 |
+
"view": "no-op"
|
| 1537 |
+
},
|
| 1538 |
+
{
|
| 1539 |
+
"move": "go forward",
|
| 1540 |
+
"view": "no-op"
|
| 1541 |
+
},
|
| 1542 |
+
{
|
| 1543 |
+
"move": "go forward",
|
| 1544 |
+
"view": "no-op"
|
| 1545 |
+
},
|
| 1546 |
+
{
|
| 1547 |
+
"move": "go forward",
|
| 1548 |
+
"view": "no-op"
|
| 1549 |
+
},
|
| 1550 |
+
{
|
| 1551 |
+
"move": "go forward",
|
| 1552 |
+
"view": "no-op"
|
| 1553 |
+
},
|
| 1554 |
+
{
|
| 1555 |
+
"move": "go forward",
|
| 1556 |
+
"view": "no-op"
|
| 1557 |
+
},
|
| 1558 |
+
{
|
| 1559 |
+
"move": "go forward",
|
| 1560 |
+
"view": "no-op"
|
| 1561 |
+
},
|
| 1562 |
+
{
|
| 1563 |
+
"move": "go forward",
|
| 1564 |
+
"view": "no-op"
|
| 1565 |
+
},
|
| 1566 |
+
{
|
| 1567 |
+
"move": "go forward",
|
| 1568 |
+
"view": "no-op"
|
| 1569 |
+
},
|
| 1570 |
+
{
|
| 1571 |
+
"move": "go forward",
|
| 1572 |
+
"view": "no-op"
|
| 1573 |
+
},
|
| 1574 |
+
{
|
| 1575 |
+
"move": "go forward",
|
| 1576 |
+
"view": "no-op"
|
| 1577 |
+
},
|
| 1578 |
+
{
|
| 1579 |
+
"move": "go forward",
|
| 1580 |
+
"view": "no-op"
|
| 1581 |
+
},
|
| 1582 |
+
{
|
| 1583 |
+
"move": "go forward",
|
| 1584 |
+
"view": "no-op"
|
| 1585 |
+
},
|
| 1586 |
+
{
|
| 1587 |
+
"move": "go forward",
|
| 1588 |
+
"view": "no-op"
|
| 1589 |
+
},
|
| 1590 |
+
{
|
| 1591 |
+
"move": "go forward",
|
| 1592 |
+
"view": "no-op"
|
| 1593 |
+
},
|
| 1594 |
+
{
|
| 1595 |
+
"move": "go forward",
|
| 1596 |
+
"view": "no-op"
|
| 1597 |
+
},
|
| 1598 |
+
{
|
| 1599 |
+
"move": "go forward",
|
| 1600 |
+
"view": "no-op"
|
| 1601 |
+
},
|
| 1602 |
+
{
|
| 1603 |
+
"move": "go forward",
|
| 1604 |
+
"view": "no-op"
|
| 1605 |
+
},
|
| 1606 |
+
{
|
| 1607 |
+
"move": "go forward",
|
| 1608 |
+
"view": "no-op"
|
| 1609 |
+
},
|
| 1610 |
+
{
|
| 1611 |
+
"move": "go forward",
|
| 1612 |
+
"view": "no-op"
|
| 1613 |
+
},
|
| 1614 |
+
{
|
| 1615 |
+
"move": "go forward",
|
| 1616 |
+
"view": "no-op"
|
| 1617 |
+
},
|
| 1618 |
+
{
|
| 1619 |
+
"move": "go forward",
|
| 1620 |
+
"view": "no-op"
|
| 1621 |
+
},
|
| 1622 |
+
{
|
| 1623 |
+
"move": "go forward",
|
| 1624 |
+
"view": "no-op"
|
| 1625 |
+
},
|
| 1626 |
+
{
|
| 1627 |
+
"move": "go forward",
|
| 1628 |
+
"view": "no-op"
|
| 1629 |
+
},
|
| 1630 |
+
{
|
| 1631 |
+
"move": "go forward",
|
| 1632 |
+
"view": "no-op"
|
| 1633 |
+
},
|
| 1634 |
+
{
|
| 1635 |
+
"move": "go forward",
|
| 1636 |
+
"view": "no-op"
|
| 1637 |
+
},
|
| 1638 |
+
{
|
| 1639 |
+
"move": "go forward",
|
| 1640 |
+
"view": "no-op"
|
| 1641 |
+
},
|
| 1642 |
+
{
|
| 1643 |
+
"move": "go forward",
|
| 1644 |
+
"view": "no-op"
|
| 1645 |
+
},
|
| 1646 |
+
{
|
| 1647 |
+
"move": "go forward",
|
| 1648 |
+
"view": "no-op"
|
| 1649 |
+
},
|
| 1650 |
+
{
|
| 1651 |
+
"move": "go forward",
|
| 1652 |
+
"view": "no-op"
|
| 1653 |
+
},
|
| 1654 |
+
{
|
| 1655 |
+
"move": "go forward",
|
| 1656 |
+
"view": "no-op"
|
| 1657 |
+
},
|
| 1658 |
+
{
|
| 1659 |
+
"move": "go forward",
|
| 1660 |
+
"view": "no-op"
|
| 1661 |
+
},
|
| 1662 |
+
{
|
| 1663 |
+
"move": "go forward",
|
| 1664 |
+
"view": "no-op"
|
| 1665 |
+
},
|
| 1666 |
+
{
|
| 1667 |
+
"move": "go forward",
|
| 1668 |
+
"view": "no-op"
|
| 1669 |
+
},
|
| 1670 |
+
{
|
| 1671 |
+
"move": "go forward",
|
| 1672 |
+
"view": "no-op"
|
| 1673 |
+
},
|
| 1674 |
+
{
|
| 1675 |
+
"move": "go forward",
|
| 1676 |
+
"view": "no-op"
|
| 1677 |
+
},
|
| 1678 |
+
{
|
| 1679 |
+
"move": "go forward",
|
| 1680 |
+
"view": "no-op"
|
| 1681 |
+
},
|
| 1682 |
+
{
|
| 1683 |
+
"move": "go forward",
|
| 1684 |
+
"view": "no-op"
|
| 1685 |
+
},
|
| 1686 |
+
{
|
| 1687 |
+
"move": "go forward",
|
| 1688 |
+
"view": "no-op"
|
| 1689 |
+
},
|
| 1690 |
+
{
|
| 1691 |
+
"move": "go forward",
|
| 1692 |
+
"view": "no-op"
|
| 1693 |
+
},
|
| 1694 |
+
{
|
| 1695 |
+
"move": "go forward",
|
| 1696 |
+
"view": "no-op"
|
| 1697 |
+
},
|
| 1698 |
+
{
|
| 1699 |
+
"move": "go forward",
|
| 1700 |
+
"view": "no-op"
|
| 1701 |
+
},
|
| 1702 |
+
{
|
| 1703 |
+
"move": "go forward",
|
| 1704 |
+
"view": "no-op"
|
| 1705 |
+
},
|
| 1706 |
+
{
|
| 1707 |
+
"move": "go forward",
|
| 1708 |
+
"view": "no-op"
|
| 1709 |
+
},
|
| 1710 |
+
{
|
| 1711 |
+
"move": "go forward",
|
| 1712 |
+
"view": "no-op"
|
| 1713 |
+
},
|
| 1714 |
+
{
|
| 1715 |
+
"move": "go forward",
|
| 1716 |
+
"view": "no-op"
|
| 1717 |
+
},
|
| 1718 |
+
{
|
| 1719 |
+
"move": "go forward",
|
| 1720 |
+
"view": "no-op"
|
| 1721 |
+
},
|
| 1722 |
+
{
|
| 1723 |
+
"move": "go forward",
|
| 1724 |
+
"view": "no-op"
|
| 1725 |
+
},
|
| 1726 |
+
{
|
| 1727 |
+
"move": "go forward",
|
| 1728 |
+
"view": "no-op"
|
| 1729 |
+
},
|
| 1730 |
+
{
|
| 1731 |
+
"move": "go forward",
|
| 1732 |
+
"view": "no-op"
|
| 1733 |
+
},
|
| 1734 |
+
{
|
| 1735 |
+
"move": "go forward",
|
| 1736 |
+
"view": "no-op"
|
| 1737 |
+
},
|
| 1738 |
+
{
|
| 1739 |
+
"move": "go forward",
|
| 1740 |
+
"view": "no-op"
|
| 1741 |
+
},
|
| 1742 |
+
{
|
| 1743 |
+
"move": "go forward",
|
| 1744 |
+
"view": "no-op"
|
| 1745 |
+
},
|
| 1746 |
+
{
|
| 1747 |
+
"move": "go forward",
|
| 1748 |
+
"view": "no-op"
|
| 1749 |
+
},
|
| 1750 |
+
{
|
| 1751 |
+
"move": "go forward",
|
| 1752 |
+
"view": "no-op"
|
| 1753 |
+
},
|
| 1754 |
+
{
|
| 1755 |
+
"move": "go forward",
|
| 1756 |
+
"view": "no-op"
|
| 1757 |
+
},
|
| 1758 |
+
{
|
| 1759 |
+
"move": "go forward",
|
| 1760 |
+
"view": "no-op"
|
| 1761 |
+
},
|
| 1762 |
+
{
|
| 1763 |
+
"move": "go forward",
|
| 1764 |
+
"view": "no-op"
|
| 1765 |
+
},
|
| 1766 |
+
{
|
| 1767 |
+
"move": "go forward",
|
| 1768 |
+
"view": "no-op"
|
| 1769 |
+
},
|
| 1770 |
+
{
|
| 1771 |
+
"move": "go forward",
|
| 1772 |
+
"view": "no-op"
|
| 1773 |
+
},
|
| 1774 |
+
{
|
| 1775 |
+
"move": "go forward",
|
| 1776 |
+
"view": "no-op"
|
| 1777 |
+
},
|
| 1778 |
+
{
|
| 1779 |
+
"move": "go forward",
|
| 1780 |
+
"view": "no-op"
|
| 1781 |
+
},
|
| 1782 |
+
{
|
| 1783 |
+
"move": "go forward",
|
| 1784 |
+
"view": "no-op"
|
| 1785 |
+
},
|
| 1786 |
+
{
|
| 1787 |
+
"move": "go forward",
|
| 1788 |
+
"view": "no-op"
|
| 1789 |
+
},
|
| 1790 |
+
{
|
| 1791 |
+
"move": "go forward",
|
| 1792 |
+
"view": "no-op"
|
| 1793 |
+
},
|
| 1794 |
+
{
|
| 1795 |
+
"move": "go forward",
|
| 1796 |
+
"view": "no-op"
|
| 1797 |
+
},
|
| 1798 |
+
{
|
| 1799 |
+
"move": "go forward",
|
| 1800 |
+
"view": "no-op"
|
| 1801 |
+
},
|
| 1802 |
+
{
|
| 1803 |
+
"move": "go forward",
|
| 1804 |
+
"view": "no-op"
|
| 1805 |
+
},
|
| 1806 |
+
{
|
| 1807 |
+
"move": "go forward",
|
| 1808 |
+
"view": "no-op"
|
| 1809 |
+
},
|
| 1810 |
+
{
|
| 1811 |
+
"move": "go forward",
|
| 1812 |
+
"view": "no-op"
|
| 1813 |
+
},
|
| 1814 |
+
{
|
| 1815 |
+
"move": "go forward",
|
| 1816 |
+
"view": "no-op"
|
| 1817 |
+
},
|
| 1818 |
+
{
|
| 1819 |
+
"move": "go forward",
|
| 1820 |
+
"view": "no-op"
|
| 1821 |
+
},
|
| 1822 |
+
{
|
| 1823 |
+
"move": "go forward",
|
| 1824 |
+
"view": "no-op"
|
| 1825 |
+
},
|
| 1826 |
+
{
|
| 1827 |
+
"move": "go forward",
|
| 1828 |
+
"view": "no-op"
|
| 1829 |
+
},
|
| 1830 |
+
{
|
| 1831 |
+
"move": "go forward",
|
| 1832 |
+
"view": "no-op"
|
| 1833 |
+
},
|
| 1834 |
+
{
|
| 1835 |
+
"move": "go forward",
|
| 1836 |
+
"view": "no-op"
|
| 1837 |
+
},
|
| 1838 |
+
{
|
| 1839 |
+
"move": "go forward",
|
| 1840 |
+
"view": "no-op"
|
| 1841 |
+
},
|
| 1842 |
+
{
|
| 1843 |
+
"move": "go forward",
|
| 1844 |
+
"view": "no-op"
|
| 1845 |
+
},
|
| 1846 |
+
{
|
| 1847 |
+
"move": "go forward",
|
| 1848 |
+
"view": "no-op"
|
| 1849 |
+
},
|
| 1850 |
+
{
|
| 1851 |
+
"move": "go forward",
|
| 1852 |
+
"view": "no-op"
|
| 1853 |
+
},
|
| 1854 |
+
{
|
| 1855 |
+
"move": "go forward",
|
| 1856 |
+
"view": "no-op"
|
| 1857 |
+
},
|
| 1858 |
+
{
|
| 1859 |
+
"move": "go forward",
|
| 1860 |
+
"view": "no-op"
|
| 1861 |
+
},
|
| 1862 |
+
{
|
| 1863 |
+
"move": "go forward",
|
| 1864 |
+
"view": "no-op"
|
| 1865 |
+
},
|
| 1866 |
+
{
|
| 1867 |
+
"move": "go forward",
|
| 1868 |
+
"view": "no-op"
|
| 1869 |
+
},
|
| 1870 |
+
{
|
| 1871 |
+
"move": "go forward",
|
| 1872 |
+
"view": "no-op"
|
| 1873 |
+
},
|
| 1874 |
+
{
|
| 1875 |
+
"move": "go forward",
|
| 1876 |
+
"view": "no-op"
|
| 1877 |
+
},
|
| 1878 |
+
{
|
| 1879 |
+
"move": "go forward",
|
| 1880 |
+
"view": "no-op"
|
| 1881 |
+
},
|
| 1882 |
+
{
|
| 1883 |
+
"move": "go forward",
|
| 1884 |
+
"view": "no-op"
|
| 1885 |
+
},
|
| 1886 |
+
{
|
| 1887 |
+
"move": "go forward",
|
| 1888 |
+
"view": "no-op"
|
| 1889 |
+
},
|
| 1890 |
+
{
|
| 1891 |
+
"move": "go forward",
|
| 1892 |
+
"view": "no-op"
|
| 1893 |
+
},
|
| 1894 |
+
{
|
| 1895 |
+
"move": "go forward",
|
| 1896 |
+
"view": "no-op"
|
| 1897 |
+
},
|
| 1898 |
+
{
|
| 1899 |
+
"move": "go forward",
|
| 1900 |
+
"view": "no-op"
|
| 1901 |
+
},
|
| 1902 |
+
{
|
| 1903 |
+
"move": "go forward",
|
| 1904 |
+
"view": "no-op"
|
| 1905 |
+
},
|
| 1906 |
+
{
|
| 1907 |
+
"move": "go forward",
|
| 1908 |
+
"view": "no-op"
|
| 1909 |
+
},
|
| 1910 |
+
{
|
| 1911 |
+
"move": "go forward",
|
| 1912 |
+
"view": "no-op"
|
| 1913 |
+
},
|
| 1914 |
+
{
|
| 1915 |
+
"move": "go forward",
|
| 1916 |
+
"view": "no-op"
|
| 1917 |
+
},
|
| 1918 |
+
{
|
| 1919 |
+
"move": "go forward",
|
| 1920 |
+
"view": "no-op"
|
| 1921 |
+
},
|
| 1922 |
+
{
|
| 1923 |
+
"move": "go forward",
|
| 1924 |
+
"view": "no-op"
|
| 1925 |
+
},
|
| 1926 |
+
{
|
| 1927 |
+
"move": "go forward",
|
| 1928 |
+
"view": "no-op"
|
| 1929 |
+
},
|
| 1930 |
+
{
|
| 1931 |
+
"move": "go forward",
|
| 1932 |
+
"view": "no-op"
|
| 1933 |
+
},
|
| 1934 |
+
{
|
| 1935 |
+
"move": "go forward",
|
| 1936 |
+
"view": "no-op"
|
| 1937 |
+
},
|
| 1938 |
+
{
|
| 1939 |
+
"move": "go forward",
|
| 1940 |
+
"view": "no-op"
|
| 1941 |
+
},
|
| 1942 |
+
{
|
| 1943 |
+
"move": "go forward",
|
| 1944 |
+
"view": "no-op"
|
| 1945 |
+
},
|
| 1946 |
+
{
|
| 1947 |
+
"move": "no-op",
|
| 1948 |
+
"view": "turn left"
|
| 1949 |
+
},
|
| 1950 |
+
{
|
| 1951 |
+
"move": "no-op",
|
| 1952 |
+
"view": "turn left"
|
| 1953 |
+
},
|
| 1954 |
+
{
|
| 1955 |
+
"move": "no-op",
|
| 1956 |
+
"view": "turn left"
|
| 1957 |
+
},
|
| 1958 |
+
{
|
| 1959 |
+
"move": "no-op",
|
| 1960 |
+
"view": "turn left"
|
| 1961 |
+
},
|
| 1962 |
+
{
|
| 1963 |
+
"move": "no-op",
|
| 1964 |
+
"view": "turn left"
|
| 1965 |
+
},
|
| 1966 |
+
{
|
| 1967 |
+
"move": "no-op",
|
| 1968 |
+
"view": "turn left"
|
| 1969 |
+
},
|
| 1970 |
+
{
|
| 1971 |
+
"move": "no-op",
|
| 1972 |
+
"view": "turn left"
|
| 1973 |
+
},
|
| 1974 |
+
{
|
| 1975 |
+
"move": "no-op",
|
| 1976 |
+
"view": "turn left"
|
| 1977 |
+
},
|
| 1978 |
+
{
|
| 1979 |
+
"move": "no-op",
|
| 1980 |
+
"view": "turn left"
|
| 1981 |
+
},
|
| 1982 |
+
{
|
| 1983 |
+
"move": "no-op",
|
| 1984 |
+
"view": "turn left"
|
| 1985 |
+
},
|
| 1986 |
+
{
|
| 1987 |
+
"move": "no-op",
|
| 1988 |
+
"view": "turn left"
|
| 1989 |
+
},
|
| 1990 |
+
{
|
| 1991 |
+
"move": "no-op",
|
| 1992 |
+
"view": "turn left"
|
| 1993 |
+
},
|
| 1994 |
+
{
|
| 1995 |
+
"move": "no-op",
|
| 1996 |
+
"view": "turn left"
|
| 1997 |
+
},
|
| 1998 |
+
{
|
| 1999 |
+
"move": "no-op",
|
| 2000 |
+
"view": "turn left"
|
| 2001 |
+
},
|
| 2002 |
+
{
|
| 2003 |
+
"move": "no-op",
|
| 2004 |
+
"view": "turn left"
|
| 2005 |
+
},
|
| 2006 |
+
{
|
| 2007 |
+
"move": "no-op",
|
| 2008 |
+
"view": "turn left"
|
| 2009 |
+
},
|
| 2010 |
+
{
|
| 2011 |
+
"move": "no-op",
|
| 2012 |
+
"view": "turn left"
|
| 2013 |
+
},
|
| 2014 |
+
{
|
| 2015 |
+
"move": "no-op",
|
| 2016 |
+
"view": "turn left"
|
| 2017 |
+
},
|
| 2018 |
+
{
|
| 2019 |
+
"move": "no-op",
|
| 2020 |
+
"view": "turn left"
|
| 2021 |
+
},
|
| 2022 |
+
{
|
| 2023 |
+
"move": "no-op",
|
| 2024 |
+
"view": "turn left"
|
| 2025 |
+
},
|
| 2026 |
+
{
|
| 2027 |
+
"move": "no-op",
|
| 2028 |
+
"view": "turn left"
|
| 2029 |
+
},
|
| 2030 |
+
{
|
| 2031 |
+
"move": "no-op",
|
| 2032 |
+
"view": "turn left"
|
| 2033 |
+
},
|
| 2034 |
+
{
|
| 2035 |
+
"move": "no-op",
|
| 2036 |
+
"view": "turn left"
|
| 2037 |
+
},
|
| 2038 |
+
{
|
| 2039 |
+
"move": "no-op",
|
| 2040 |
+
"view": "turn left"
|
| 2041 |
+
},
|
| 2042 |
+
{
|
| 2043 |
+
"move": "no-op",
|
| 2044 |
+
"view": "turn left"
|
| 2045 |
+
},
|
| 2046 |
+
{
|
| 2047 |
+
"move": "no-op",
|
| 2048 |
+
"view": "turn left"
|
| 2049 |
+
},
|
| 2050 |
+
{
|
| 2051 |
+
"move": "no-op",
|
| 2052 |
+
"view": "turn left"
|
| 2053 |
+
},
|
| 2054 |
+
{
|
| 2055 |
+
"move": "no-op",
|
| 2056 |
+
"view": "turn left"
|
| 2057 |
+
},
|
| 2058 |
+
{
|
| 2059 |
+
"move": "no-op",
|
| 2060 |
+
"view": "turn left"
|
| 2061 |
+
},
|
| 2062 |
+
{
|
| 2063 |
+
"move": "no-op",
|
| 2064 |
+
"view": "turn left"
|
| 2065 |
+
},
|
| 2066 |
+
{
|
| 2067 |
+
"move": "no-op",
|
| 2068 |
+
"view": "turn left"
|
| 2069 |
+
},
|
| 2070 |
+
{
|
| 2071 |
+
"move": "no-op",
|
| 2072 |
+
"view": "turn left"
|
| 2073 |
+
},
|
| 2074 |
+
{
|
| 2075 |
+
"move": "no-op",
|
| 2076 |
+
"view": "turn left"
|
| 2077 |
+
},
|
| 2078 |
+
{
|
| 2079 |
+
"move": "no-op",
|
| 2080 |
+
"view": "turn left"
|
| 2081 |
+
},
|
| 2082 |
+
{
|
| 2083 |
+
"move": "no-op",
|
| 2084 |
+
"view": "turn left"
|
| 2085 |
+
},
|
| 2086 |
+
{
|
| 2087 |
+
"move": "no-op",
|
| 2088 |
+
"view": "turn left"
|
| 2089 |
+
},
|
| 2090 |
+
{
|
| 2091 |
+
"move": "no-op",
|
| 2092 |
+
"view": "turn left"
|
| 2093 |
+
},
|
| 2094 |
+
{
|
| 2095 |
+
"move": "no-op",
|
| 2096 |
+
"view": "turn left"
|
| 2097 |
+
},
|
| 2098 |
+
{
|
| 2099 |
+
"move": "no-op",
|
| 2100 |
+
"view": "turn left"
|
| 2101 |
+
},
|
| 2102 |
+
{
|
| 2103 |
+
"move": "no-op",
|
| 2104 |
+
"view": "turn left"
|
| 2105 |
+
},
|
| 2106 |
+
{
|
| 2107 |
+
"move": "no-op",
|
| 2108 |
+
"view": "turn left"
|
| 2109 |
+
},
|
| 2110 |
+
{
|
| 2111 |
+
"move": "no-op",
|
| 2112 |
+
"view": "turn left"
|
| 2113 |
+
},
|
| 2114 |
+
{
|
| 2115 |
+
"move": "no-op",
|
| 2116 |
+
"view": "turn left"
|
| 2117 |
+
},
|
| 2118 |
+
{
|
| 2119 |
+
"move": "no-op",
|
| 2120 |
+
"view": "turn left"
|
| 2121 |
+
},
|
| 2122 |
+
{
|
| 2123 |
+
"move": "no-op",
|
| 2124 |
+
"view": "turn left"
|
| 2125 |
+
},
|
| 2126 |
+
{
|
| 2127 |
+
"move": "no-op",
|
| 2128 |
+
"view": "turn left"
|
| 2129 |
+
},
|
| 2130 |
+
{
|
| 2131 |
+
"move": "no-op",
|
| 2132 |
+
"view": "turn left"
|
| 2133 |
+
},
|
| 2134 |
+
{
|
| 2135 |
+
"move": "no-op",
|
| 2136 |
+
"view": "turn left"
|
| 2137 |
+
},
|
| 2138 |
+
{
|
| 2139 |
+
"move": "no-op",
|
| 2140 |
+
"view": "turn left"
|
| 2141 |
+
},
|
| 2142 |
+
{
|
| 2143 |
+
"move": "no-op",
|
| 2144 |
+
"view": "turn left"
|
| 2145 |
+
},
|
| 2146 |
+
{
|
| 2147 |
+
"move": "no-op",
|
| 2148 |
+
"view": "turn left"
|
| 2149 |
+
},
|
| 2150 |
+
{
|
| 2151 |
+
"move": "no-op",
|
| 2152 |
+
"view": "turn left"
|
| 2153 |
+
},
|
| 2154 |
+
{
|
| 2155 |
+
"move": "no-op",
|
| 2156 |
+
"view": "turn left"
|
| 2157 |
+
},
|
| 2158 |
+
{
|
| 2159 |
+
"move": "no-op",
|
| 2160 |
+
"view": "turn left"
|
| 2161 |
+
},
|
| 2162 |
+
{
|
| 2163 |
+
"move": "no-op",
|
| 2164 |
+
"view": "turn left"
|
| 2165 |
+
},
|
| 2166 |
+
{
|
| 2167 |
+
"move": "no-op",
|
| 2168 |
+
"view": "turn left"
|
| 2169 |
+
},
|
| 2170 |
+
{
|
| 2171 |
+
"move": "no-op",
|
| 2172 |
+
"view": "turn left"
|
| 2173 |
+
},
|
| 2174 |
+
{
|
| 2175 |
+
"move": "no-op",
|
| 2176 |
+
"view": "turn left"
|
| 2177 |
+
},
|
| 2178 |
+
{
|
| 2179 |
+
"move": "no-op",
|
| 2180 |
+
"view": "turn left"
|
| 2181 |
+
},
|
| 2182 |
+
{
|
| 2183 |
+
"move": "no-op",
|
| 2184 |
+
"view": "turn left"
|
| 2185 |
+
},
|
| 2186 |
+
{
|
| 2187 |
+
"move": "no-op",
|
| 2188 |
+
"view": "turn left"
|
| 2189 |
+
},
|
| 2190 |
+
{
|
| 2191 |
+
"move": "no-op",
|
| 2192 |
+
"view": "turn left"
|
| 2193 |
+
},
|
| 2194 |
+
{
|
| 2195 |
+
"move": "no-op",
|
| 2196 |
+
"view": "turn left"
|
| 2197 |
+
},
|
| 2198 |
+
{
|
| 2199 |
+
"move": "no-op",
|
| 2200 |
+
"view": "turn left"
|
| 2201 |
+
},
|
| 2202 |
+
{
|
| 2203 |
+
"move": "no-op",
|
| 2204 |
+
"view": "turn left"
|
| 2205 |
+
},
|
| 2206 |
+
{
|
| 2207 |
+
"move": "no-op",
|
| 2208 |
+
"view": "turn left"
|
| 2209 |
+
},
|
| 2210 |
+
{
|
| 2211 |
+
"move": "no-op",
|
| 2212 |
+
"view": "turn left"
|
| 2213 |
+
},
|
| 2214 |
+
{
|
| 2215 |
+
"move": "no-op",
|
| 2216 |
+
"view": "turn left"
|
| 2217 |
+
},
|
| 2218 |
+
{
|
| 2219 |
+
"move": "no-op",
|
| 2220 |
+
"view": "turn left"
|
| 2221 |
+
},
|
| 2222 |
+
{
|
| 2223 |
+
"move": "no-op",
|
| 2224 |
+
"view": "turn left"
|
| 2225 |
+
},
|
| 2226 |
+
{
|
| 2227 |
+
"move": "no-op",
|
| 2228 |
+
"view": "turn left"
|
| 2229 |
+
},
|
| 2230 |
+
{
|
| 2231 |
+
"move": "no-op",
|
| 2232 |
+
"view": "turn left"
|
| 2233 |
+
},
|
| 2234 |
+
{
|
| 2235 |
+
"move": "no-op",
|
| 2236 |
+
"view": "turn left"
|
| 2237 |
+
},
|
| 2238 |
+
{
|
| 2239 |
+
"move": "no-op",
|
| 2240 |
+
"view": "turn left"
|
| 2241 |
+
},
|
| 2242 |
+
{
|
| 2243 |
+
"move": "no-op",
|
| 2244 |
+
"view": "turn left"
|
| 2245 |
+
},
|
| 2246 |
+
{
|
| 2247 |
+
"move": "no-op",
|
| 2248 |
+
"view": "turn left"
|
| 2249 |
+
},
|
| 2250 |
+
{
|
| 2251 |
+
"move": "no-op",
|
| 2252 |
+
"view": "turn left"
|
| 2253 |
+
},
|
| 2254 |
+
{
|
| 2255 |
+
"move": "no-op",
|
| 2256 |
+
"view": "turn left"
|
| 2257 |
+
},
|
| 2258 |
+
{
|
| 2259 |
+
"move": "no-op",
|
| 2260 |
+
"view": "turn left"
|
| 2261 |
+
},
|
| 2262 |
+
{
|
| 2263 |
+
"move": "no-op",
|
| 2264 |
+
"view": "turn left"
|
| 2265 |
+
},
|
| 2266 |
+
{
|
| 2267 |
+
"move": "no-op",
|
| 2268 |
+
"view": "turn left"
|
| 2269 |
+
},
|
| 2270 |
+
{
|
| 2271 |
+
"move": "no-op",
|
| 2272 |
+
"view": "turn left"
|
| 2273 |
+
},
|
| 2274 |
+
{
|
| 2275 |
+
"move": "no-op",
|
| 2276 |
+
"view": "turn left"
|
| 2277 |
+
},
|
| 2278 |
+
{
|
| 2279 |
+
"move": "no-op",
|
| 2280 |
+
"view": "turn left"
|
| 2281 |
+
},
|
| 2282 |
+
{
|
| 2283 |
+
"move": "no-op",
|
| 2284 |
+
"view": "turn left"
|
| 2285 |
+
},
|
| 2286 |
+
{
|
| 2287 |
+
"move": "no-op",
|
| 2288 |
+
"view": "turn left"
|
| 2289 |
+
},
|
| 2290 |
+
{
|
| 2291 |
+
"move": "no-op",
|
| 2292 |
+
"view": "turn left"
|
| 2293 |
+
},
|
| 2294 |
+
{
|
| 2295 |
+
"move": "no-op",
|
| 2296 |
+
"view": "turn left"
|
| 2297 |
+
},
|
| 2298 |
+
{
|
| 2299 |
+
"move": "no-op",
|
| 2300 |
+
"view": "turn left"
|
| 2301 |
+
},
|
| 2302 |
+
{
|
| 2303 |
+
"move": "no-op",
|
| 2304 |
+
"view": "turn left"
|
| 2305 |
+
},
|
| 2306 |
+
{
|
| 2307 |
+
"move": "no-op",
|
| 2308 |
+
"view": "turn left"
|
| 2309 |
+
},
|
| 2310 |
+
{
|
| 2311 |
+
"move": "no-op",
|
| 2312 |
+
"view": "turn left"
|
| 2313 |
+
},
|
| 2314 |
+
{
|
| 2315 |
+
"move": "no-op",
|
| 2316 |
+
"view": "turn left"
|
| 2317 |
+
},
|
| 2318 |
+
{
|
| 2319 |
+
"move": "no-op",
|
| 2320 |
+
"view": "turn left"
|
| 2321 |
+
},
|
| 2322 |
+
{
|
| 2323 |
+
"move": "no-op",
|
| 2324 |
+
"view": "turn left"
|
| 2325 |
+
},
|
| 2326 |
+
{
|
| 2327 |
+
"move": "no-op",
|
| 2328 |
+
"view": "turn left"
|
| 2329 |
+
},
|
| 2330 |
+
{
|
| 2331 |
+
"move": "no-op",
|
| 2332 |
+
"view": "turn left"
|
| 2333 |
+
},
|
| 2334 |
+
{
|
| 2335 |
+
"move": "no-op",
|
| 2336 |
+
"view": "turn left"
|
| 2337 |
+
},
|
| 2338 |
+
{
|
| 2339 |
+
"move": "no-op",
|
| 2340 |
+
"view": "turn left"
|
| 2341 |
+
},
|
| 2342 |
+
{
|
| 2343 |
+
"move": "no-op",
|
| 2344 |
+
"view": "turn left"
|
| 2345 |
+
},
|
| 2346 |
+
{
|
| 2347 |
+
"move": "no-op",
|
| 2348 |
+
"view": "turn left"
|
| 2349 |
+
},
|
| 2350 |
+
{
|
| 2351 |
+
"move": "no-op",
|
| 2352 |
+
"view": "turn left"
|
| 2353 |
+
},
|
| 2354 |
+
{
|
| 2355 |
+
"move": "no-op",
|
| 2356 |
+
"view": "turn left"
|
| 2357 |
+
},
|
| 2358 |
+
{
|
| 2359 |
+
"move": "no-op",
|
| 2360 |
+
"view": "turn left"
|
| 2361 |
+
},
|
| 2362 |
+
{
|
| 2363 |
+
"move": "no-op",
|
| 2364 |
+
"view": "turn left"
|
| 2365 |
+
},
|
| 2366 |
+
{
|
| 2367 |
+
"move": "no-op",
|
| 2368 |
+
"view": "turn left"
|
| 2369 |
+
},
|
| 2370 |
+
{
|
| 2371 |
+
"move": "no-op",
|
| 2372 |
+
"view": "turn left"
|
| 2373 |
+
},
|
| 2374 |
+
{
|
| 2375 |
+
"move": "no-op",
|
| 2376 |
+
"view": "turn left"
|
| 2377 |
+
},
|
| 2378 |
+
{
|
| 2379 |
+
"move": "no-op",
|
| 2380 |
+
"view": "turn left"
|
| 2381 |
+
},
|
| 2382 |
+
{
|
| 2383 |
+
"move": "no-op",
|
| 2384 |
+
"view": "turn left"
|
| 2385 |
+
},
|
| 2386 |
+
{
|
| 2387 |
+
"move": "no-op",
|
| 2388 |
+
"view": "turn left"
|
| 2389 |
+
},
|
| 2390 |
+
{
|
| 2391 |
+
"move": "no-op",
|
| 2392 |
+
"view": "turn left"
|
| 2393 |
+
},
|
| 2394 |
+
{
|
| 2395 |
+
"move": "no-op",
|
| 2396 |
+
"view": "turn left"
|
| 2397 |
+
},
|
| 2398 |
+
{
|
| 2399 |
+
"move": "no-op",
|
| 2400 |
+
"view": "turn left"
|
| 2401 |
+
},
|
| 2402 |
+
{
|
| 2403 |
+
"move": "no-op",
|
| 2404 |
+
"view": "turn left"
|
| 2405 |
+
},
|
| 2406 |
+
{
|
| 2407 |
+
"move": "no-op",
|
| 2408 |
+
"view": "turn left"
|
| 2409 |
+
},
|
| 2410 |
+
{
|
| 2411 |
+
"move": "no-op",
|
| 2412 |
+
"view": "turn left"
|
| 2413 |
+
},
|
| 2414 |
+
{
|
| 2415 |
+
"move": "no-op",
|
| 2416 |
+
"view": "turn left"
|
| 2417 |
+
},
|
| 2418 |
+
{
|
| 2419 |
+
"move": "no-op",
|
| 2420 |
+
"view": "turn left"
|
| 2421 |
+
},
|
| 2422 |
+
{
|
| 2423 |
+
"move": "no-op",
|
| 2424 |
+
"view": "turn left"
|
| 2425 |
+
},
|
| 2426 |
+
{
|
| 2427 |
+
"move": "no-op",
|
| 2428 |
+
"view": "turn left"
|
| 2429 |
+
},
|
| 2430 |
+
{
|
| 2431 |
+
"move": "no-op",
|
| 2432 |
+
"view": "turn left"
|
| 2433 |
+
},
|
| 2434 |
+
{
|
| 2435 |
+
"move": "no-op",
|
| 2436 |
+
"view": "turn left"
|
| 2437 |
+
},
|
| 2438 |
+
{
|
| 2439 |
+
"move": "no-op",
|
| 2440 |
+
"view": "turn left"
|
| 2441 |
+
},
|
| 2442 |
+
{
|
| 2443 |
+
"move": "no-op",
|
| 2444 |
+
"view": "turn left"
|
| 2445 |
+
},
|
| 2446 |
+
{
|
| 2447 |
+
"move": "no-op",
|
| 2448 |
+
"view": "turn left"
|
| 2449 |
+
},
|
| 2450 |
+
{
|
| 2451 |
+
"move": "no-op",
|
| 2452 |
+
"view": "turn left"
|
| 2453 |
+
},
|
| 2454 |
+
{
|
| 2455 |
+
"move": "no-op",
|
| 2456 |
+
"view": "turn left"
|
| 2457 |
+
},
|
| 2458 |
+
{
|
| 2459 |
+
"move": "no-op",
|
| 2460 |
+
"view": "turn left"
|
| 2461 |
+
},
|
| 2462 |
+
{
|
| 2463 |
+
"move": "no-op",
|
| 2464 |
+
"view": "turn left"
|
| 2465 |
+
},
|
| 2466 |
+
{
|
| 2467 |
+
"move": "no-op",
|
| 2468 |
+
"view": "turn left"
|
| 2469 |
+
},
|
| 2470 |
+
{
|
| 2471 |
+
"move": "no-op",
|
| 2472 |
+
"view": "turn left"
|
| 2473 |
+
},
|
| 2474 |
+
{
|
| 2475 |
+
"move": "no-op",
|
| 2476 |
+
"view": "turn left"
|
| 2477 |
+
},
|
| 2478 |
+
{
|
| 2479 |
+
"move": "no-op",
|
| 2480 |
+
"view": "turn left"
|
| 2481 |
+
},
|
| 2482 |
+
{
|
| 2483 |
+
"move": "no-op",
|
| 2484 |
+
"view": "turn left"
|
| 2485 |
+
},
|
| 2486 |
+
{
|
| 2487 |
+
"move": "no-op",
|
| 2488 |
+
"view": "turn left"
|
| 2489 |
+
},
|
| 2490 |
+
{
|
| 2491 |
+
"move": "no-op",
|
| 2492 |
+
"view": "turn left"
|
| 2493 |
+
},
|
| 2494 |
+
{
|
| 2495 |
+
"move": "no-op",
|
| 2496 |
+
"view": "turn left"
|
| 2497 |
+
},
|
| 2498 |
+
{
|
| 2499 |
+
"move": "no-op",
|
| 2500 |
+
"view": "turn left"
|
| 2501 |
+
},
|
| 2502 |
+
{
|
| 2503 |
+
"move": "no-op",
|
| 2504 |
+
"view": "turn left"
|
| 2505 |
+
},
|
| 2506 |
+
{
|
| 2507 |
+
"move": "no-op",
|
| 2508 |
+
"view": "turn left"
|
| 2509 |
+
},
|
| 2510 |
+
{
|
| 2511 |
+
"move": "no-op",
|
| 2512 |
+
"view": "turn left"
|
| 2513 |
+
},
|
| 2514 |
+
{
|
| 2515 |
+
"move": "no-op",
|
| 2516 |
+
"view": "turn left"
|
| 2517 |
+
},
|
| 2518 |
+
{
|
| 2519 |
+
"move": "no-op",
|
| 2520 |
+
"view": "turn left"
|
| 2521 |
+
},
|
| 2522 |
+
{
|
| 2523 |
+
"move": "no-op",
|
| 2524 |
+
"view": "turn left"
|
| 2525 |
+
},
|
| 2526 |
+
{
|
| 2527 |
+
"move": "no-op",
|
| 2528 |
+
"view": "turn left"
|
| 2529 |
+
},
|
| 2530 |
+
{
|
| 2531 |
+
"move": "no-op",
|
| 2532 |
+
"view": "turn left"
|
| 2533 |
+
},
|
| 2534 |
+
{
|
| 2535 |
+
"move": "no-op",
|
| 2536 |
+
"view": "turn left"
|
| 2537 |
+
},
|
| 2538 |
+
{
|
| 2539 |
+
"move": "no-op",
|
| 2540 |
+
"view": "turn left"
|
| 2541 |
+
},
|
| 2542 |
+
{
|
| 2543 |
+
"move": "no-op",
|
| 2544 |
+
"view": "turn left"
|
| 2545 |
+
},
|
| 2546 |
+
{
|
| 2547 |
+
"move": "no-op",
|
| 2548 |
+
"view": "turn left"
|
| 2549 |
+
},
|
| 2550 |
+
{
|
| 2551 |
+
"move": "no-op",
|
| 2552 |
+
"view": "turn left"
|
| 2553 |
+
},
|
| 2554 |
+
{
|
| 2555 |
+
"move": "no-op",
|
| 2556 |
+
"view": "turn left"
|
| 2557 |
+
},
|
| 2558 |
+
{
|
| 2559 |
+
"move": "no-op",
|
| 2560 |
+
"view": "turn left"
|
| 2561 |
+
},
|
| 2562 |
+
{
|
| 2563 |
+
"move": "no-op",
|
| 2564 |
+
"view": "turn left"
|
| 2565 |
+
},
|
| 2566 |
+
{
|
| 2567 |
+
"move": "no-op",
|
| 2568 |
+
"view": "turn left"
|
| 2569 |
+
},
|
| 2570 |
+
{
|
| 2571 |
+
"move": "no-op",
|
| 2572 |
+
"view": "turn left"
|
| 2573 |
+
},
|
| 2574 |
+
{
|
| 2575 |
+
"move": "no-op",
|
| 2576 |
+
"view": "turn left"
|
| 2577 |
+
},
|
| 2578 |
+
{
|
| 2579 |
+
"move": "no-op",
|
| 2580 |
+
"view": "turn left"
|
| 2581 |
+
},
|
| 2582 |
+
{
|
| 2583 |
+
"move": "no-op",
|
| 2584 |
+
"view": "turn left"
|
| 2585 |
+
},
|
| 2586 |
+
{
|
| 2587 |
+
"move": "no-op",
|
| 2588 |
+
"view": "turn left"
|
| 2589 |
+
},
|
| 2590 |
+
{
|
| 2591 |
+
"move": "no-op",
|
| 2592 |
+
"view": "turn left"
|
| 2593 |
+
},
|
| 2594 |
+
{
|
| 2595 |
+
"move": "no-op",
|
| 2596 |
+
"view": "turn right"
|
| 2597 |
+
},
|
| 2598 |
+
{
|
| 2599 |
+
"move": "no-op",
|
| 2600 |
+
"view": "turn right"
|
| 2601 |
+
},
|
| 2602 |
+
{
|
| 2603 |
+
"move": "no-op",
|
| 2604 |
+
"view": "turn right"
|
| 2605 |
+
},
|
| 2606 |
+
{
|
| 2607 |
+
"move": "no-op",
|
| 2608 |
+
"view": "turn right"
|
| 2609 |
+
},
|
| 2610 |
+
{
|
| 2611 |
+
"move": "no-op",
|
| 2612 |
+
"view": "turn right"
|
| 2613 |
+
},
|
| 2614 |
+
{
|
| 2615 |
+
"move": "no-op",
|
| 2616 |
+
"view": "turn right"
|
| 2617 |
+
},
|
| 2618 |
+
{
|
| 2619 |
+
"move": "no-op",
|
| 2620 |
+
"view": "turn right"
|
| 2621 |
+
},
|
| 2622 |
+
{
|
| 2623 |
+
"move": "no-op",
|
| 2624 |
+
"view": "turn right"
|
| 2625 |
+
},
|
| 2626 |
+
{
|
| 2627 |
+
"move": "no-op",
|
| 2628 |
+
"view": "turn right"
|
| 2629 |
+
},
|
| 2630 |
+
{
|
| 2631 |
+
"move": "no-op",
|
| 2632 |
+
"view": "turn right"
|
| 2633 |
+
},
|
| 2634 |
+
{
|
| 2635 |
+
"move": "no-op",
|
| 2636 |
+
"view": "turn right"
|
| 2637 |
+
},
|
| 2638 |
+
{
|
| 2639 |
+
"move": "no-op",
|
| 2640 |
+
"view": "turn right"
|
| 2641 |
+
},
|
| 2642 |
+
{
|
| 2643 |
+
"move": "no-op",
|
| 2644 |
+
"view": "turn right"
|
| 2645 |
+
},
|
| 2646 |
+
{
|
| 2647 |
+
"move": "no-op",
|
| 2648 |
+
"view": "turn right"
|
| 2649 |
+
},
|
| 2650 |
+
{
|
| 2651 |
+
"move": "no-op",
|
| 2652 |
+
"view": "turn right"
|
| 2653 |
+
},
|
| 2654 |
+
{
|
| 2655 |
+
"move": "no-op",
|
| 2656 |
+
"view": "turn right"
|
| 2657 |
+
},
|
| 2658 |
+
{
|
| 2659 |
+
"move": "no-op",
|
| 2660 |
+
"view": "turn right"
|
| 2661 |
+
},
|
| 2662 |
+
{
|
| 2663 |
+
"move": "no-op",
|
| 2664 |
+
"view": "turn right"
|
| 2665 |
+
},
|
| 2666 |
+
{
|
| 2667 |
+
"move": "no-op",
|
| 2668 |
+
"view": "turn right"
|
| 2669 |
+
},
|
| 2670 |
+
{
|
| 2671 |
+
"move": "no-op",
|
| 2672 |
+
"view": "turn right"
|
| 2673 |
+
},
|
| 2674 |
+
{
|
| 2675 |
+
"move": "no-op",
|
| 2676 |
+
"view": "turn right"
|
| 2677 |
+
},
|
| 2678 |
+
{
|
| 2679 |
+
"move": "no-op",
|
| 2680 |
+
"view": "turn right"
|
| 2681 |
+
},
|
| 2682 |
+
{
|
| 2683 |
+
"move": "no-op",
|
| 2684 |
+
"view": "turn right"
|
| 2685 |
+
},
|
| 2686 |
+
{
|
| 2687 |
+
"move": "no-op",
|
| 2688 |
+
"view": "turn right"
|
| 2689 |
+
},
|
| 2690 |
+
{
|
| 2691 |
+
"move": "no-op",
|
| 2692 |
+
"view": "turn right"
|
| 2693 |
+
},
|
| 2694 |
+
{
|
| 2695 |
+
"move": "no-op",
|
| 2696 |
+
"view": "turn right"
|
| 2697 |
+
},
|
| 2698 |
+
{
|
| 2699 |
+
"move": "no-op",
|
| 2700 |
+
"view": "turn right"
|
| 2701 |
+
},
|
| 2702 |
+
{
|
| 2703 |
+
"move": "no-op",
|
| 2704 |
+
"view": "turn right"
|
| 2705 |
+
},
|
| 2706 |
+
{
|
| 2707 |
+
"move": "no-op",
|
| 2708 |
+
"view": "turn right"
|
| 2709 |
+
},
|
| 2710 |
+
{
|
| 2711 |
+
"move": "no-op",
|
| 2712 |
+
"view": "turn right"
|
| 2713 |
+
},
|
| 2714 |
+
{
|
| 2715 |
+
"move": "no-op",
|
| 2716 |
+
"view": "turn right"
|
| 2717 |
+
},
|
| 2718 |
+
{
|
| 2719 |
+
"move": "no-op",
|
| 2720 |
+
"view": "turn right"
|
| 2721 |
+
},
|
| 2722 |
+
{
|
| 2723 |
+
"move": "no-op",
|
| 2724 |
+
"view": "turn right"
|
| 2725 |
+
},
|
| 2726 |
+
{
|
| 2727 |
+
"move": "no-op",
|
| 2728 |
+
"view": "turn right"
|
| 2729 |
+
},
|
| 2730 |
+
{
|
| 2731 |
+
"move": "no-op",
|
| 2732 |
+
"view": "turn right"
|
| 2733 |
+
},
|
| 2734 |
+
{
|
| 2735 |
+
"move": "no-op",
|
| 2736 |
+
"view": "turn right"
|
| 2737 |
+
},
|
| 2738 |
+
{
|
| 2739 |
+
"move": "no-op",
|
| 2740 |
+
"view": "turn right"
|
| 2741 |
+
},
|
| 2742 |
+
{
|
| 2743 |
+
"move": "no-op",
|
| 2744 |
+
"view": "turn right"
|
| 2745 |
+
},
|
| 2746 |
+
{
|
| 2747 |
+
"move": "no-op",
|
| 2748 |
+
"view": "turn right"
|
| 2749 |
+
},
|
| 2750 |
+
{
|
| 2751 |
+
"move": "no-op",
|
| 2752 |
+
"view": "turn right"
|
| 2753 |
+
},
|
| 2754 |
+
{
|
| 2755 |
+
"move": "no-op",
|
| 2756 |
+
"view": "turn right"
|
| 2757 |
+
},
|
| 2758 |
+
{
|
| 2759 |
+
"move": "no-op",
|
| 2760 |
+
"view": "turn right"
|
| 2761 |
+
},
|
| 2762 |
+
{
|
| 2763 |
+
"move": "no-op",
|
| 2764 |
+
"view": "turn right"
|
| 2765 |
+
},
|
| 2766 |
+
{
|
| 2767 |
+
"move": "no-op",
|
| 2768 |
+
"view": "turn right"
|
| 2769 |
+
},
|
| 2770 |
+
{
|
| 2771 |
+
"move": "no-op",
|
| 2772 |
+
"view": "turn right"
|
| 2773 |
+
},
|
| 2774 |
+
{
|
| 2775 |
+
"move": "no-op",
|
| 2776 |
+
"view": "turn right"
|
| 2777 |
+
},
|
| 2778 |
+
{
|
| 2779 |
+
"move": "no-op",
|
| 2780 |
+
"view": "turn right"
|
| 2781 |
+
},
|
| 2782 |
+
{
|
| 2783 |
+
"move": "no-op",
|
| 2784 |
+
"view": "turn right"
|
| 2785 |
+
},
|
| 2786 |
+
{
|
| 2787 |
+
"move": "no-op",
|
| 2788 |
+
"view": "turn right"
|
| 2789 |
+
},
|
| 2790 |
+
{
|
| 2791 |
+
"move": "no-op",
|
| 2792 |
+
"view": "turn right"
|
| 2793 |
+
},
|
| 2794 |
+
{
|
| 2795 |
+
"move": "no-op",
|
| 2796 |
+
"view": "turn right"
|
| 2797 |
+
},
|
| 2798 |
+
{
|
| 2799 |
+
"move": "no-op",
|
| 2800 |
+
"view": "turn right"
|
| 2801 |
+
},
|
| 2802 |
+
{
|
| 2803 |
+
"move": "no-op",
|
| 2804 |
+
"view": "turn right"
|
| 2805 |
+
},
|
| 2806 |
+
{
|
| 2807 |
+
"move": "no-op",
|
| 2808 |
+
"view": "turn right"
|
| 2809 |
+
},
|
| 2810 |
+
{
|
| 2811 |
+
"move": "no-op",
|
| 2812 |
+
"view": "turn right"
|
| 2813 |
+
},
|
| 2814 |
+
{
|
| 2815 |
+
"move": "no-op",
|
| 2816 |
+
"view": "turn right"
|
| 2817 |
+
},
|
| 2818 |
+
{
|
| 2819 |
+
"move": "no-op",
|
| 2820 |
+
"view": "turn right"
|
| 2821 |
+
},
|
| 2822 |
+
{
|
| 2823 |
+
"move": "no-op",
|
| 2824 |
+
"view": "turn right"
|
| 2825 |
+
},
|
| 2826 |
+
{
|
| 2827 |
+
"move": "no-op",
|
| 2828 |
+
"view": "turn right"
|
| 2829 |
+
},
|
| 2830 |
+
{
|
| 2831 |
+
"move": "no-op",
|
| 2832 |
+
"view": "turn right"
|
| 2833 |
+
},
|
| 2834 |
+
{
|
| 2835 |
+
"move": "no-op",
|
| 2836 |
+
"view": "turn right"
|
| 2837 |
+
},
|
| 2838 |
+
{
|
| 2839 |
+
"move": "no-op",
|
| 2840 |
+
"view": "turn right"
|
| 2841 |
+
},
|
| 2842 |
+
{
|
| 2843 |
+
"move": "no-op",
|
| 2844 |
+
"view": "turn right"
|
| 2845 |
+
},
|
| 2846 |
+
{
|
| 2847 |
+
"move": "no-op",
|
| 2848 |
+
"view": "turn right"
|
| 2849 |
+
},
|
| 2850 |
+
{
|
| 2851 |
+
"move": "no-op",
|
| 2852 |
+
"view": "turn right"
|
| 2853 |
+
},
|
| 2854 |
+
{
|
| 2855 |
+
"move": "no-op",
|
| 2856 |
+
"view": "turn right"
|
| 2857 |
+
},
|
| 2858 |
+
{
|
| 2859 |
+
"move": "no-op",
|
| 2860 |
+
"view": "turn right"
|
| 2861 |
+
},
|
| 2862 |
+
{
|
| 2863 |
+
"move": "no-op",
|
| 2864 |
+
"view": "turn right"
|
| 2865 |
+
},
|
| 2866 |
+
{
|
| 2867 |
+
"move": "no-op",
|
| 2868 |
+
"view": "turn right"
|
| 2869 |
+
},
|
| 2870 |
+
{
|
| 2871 |
+
"move": "no-op",
|
| 2872 |
+
"view": "turn right"
|
| 2873 |
+
},
|
| 2874 |
+
{
|
| 2875 |
+
"move": "no-op",
|
| 2876 |
+
"view": "turn right"
|
| 2877 |
+
},
|
| 2878 |
+
{
|
| 2879 |
+
"move": "no-op",
|
| 2880 |
+
"view": "turn right"
|
| 2881 |
+
},
|
| 2882 |
+
{
|
| 2883 |
+
"move": "no-op",
|
| 2884 |
+
"view": "turn right"
|
| 2885 |
+
},
|
| 2886 |
+
{
|
| 2887 |
+
"move": "no-op",
|
| 2888 |
+
"view": "turn right"
|
| 2889 |
+
},
|
| 2890 |
+
{
|
| 2891 |
+
"move": "no-op",
|
| 2892 |
+
"view": "turn right"
|
| 2893 |
+
},
|
| 2894 |
+
{
|
| 2895 |
+
"move": "no-op",
|
| 2896 |
+
"view": "turn right"
|
| 2897 |
+
},
|
| 2898 |
+
{
|
| 2899 |
+
"move": "no-op",
|
| 2900 |
+
"view": "turn right"
|
| 2901 |
+
},
|
| 2902 |
+
{
|
| 2903 |
+
"move": "no-op",
|
| 2904 |
+
"view": "turn right"
|
| 2905 |
+
},
|
| 2906 |
+
{
|
| 2907 |
+
"move": "no-op",
|
| 2908 |
+
"view": "turn right"
|
| 2909 |
+
},
|
| 2910 |
+
{
|
| 2911 |
+
"move": "no-op",
|
| 2912 |
+
"view": "turn right"
|
| 2913 |
+
},
|
| 2914 |
+
{
|
| 2915 |
+
"move": "no-op",
|
| 2916 |
+
"view": "turn right"
|
| 2917 |
+
},
|
| 2918 |
+
{
|
| 2919 |
+
"move": "no-op",
|
| 2920 |
+
"view": "turn right"
|
| 2921 |
+
},
|
| 2922 |
+
{
|
| 2923 |
+
"move": "no-op",
|
| 2924 |
+
"view": "turn right"
|
| 2925 |
+
},
|
| 2926 |
+
{
|
| 2927 |
+
"move": "no-op",
|
| 2928 |
+
"view": "turn right"
|
| 2929 |
+
},
|
| 2930 |
+
{
|
| 2931 |
+
"move": "no-op",
|
| 2932 |
+
"view": "turn right"
|
| 2933 |
+
},
|
| 2934 |
+
{
|
| 2935 |
+
"move": "no-op",
|
| 2936 |
+
"view": "turn right"
|
| 2937 |
+
},
|
| 2938 |
+
{
|
| 2939 |
+
"move": "no-op",
|
| 2940 |
+
"view": "turn right"
|
| 2941 |
+
},
|
| 2942 |
+
{
|
| 2943 |
+
"move": "no-op",
|
| 2944 |
+
"view": "turn right"
|
| 2945 |
+
},
|
| 2946 |
+
{
|
| 2947 |
+
"move": "no-op",
|
| 2948 |
+
"view": "turn right"
|
| 2949 |
+
},
|
| 2950 |
+
{
|
| 2951 |
+
"move": "no-op",
|
| 2952 |
+
"view": "turn right"
|
| 2953 |
+
},
|
| 2954 |
+
{
|
| 2955 |
+
"move": "no-op",
|
| 2956 |
+
"view": "turn right"
|
| 2957 |
+
},
|
| 2958 |
+
{
|
| 2959 |
+
"move": "no-op",
|
| 2960 |
+
"view": "turn right"
|
| 2961 |
+
},
|
| 2962 |
+
{
|
| 2963 |
+
"move": "no-op",
|
| 2964 |
+
"view": "turn right"
|
| 2965 |
+
},
|
| 2966 |
+
{
|
| 2967 |
+
"move": "no-op",
|
| 2968 |
+
"view": "turn right"
|
| 2969 |
+
},
|
| 2970 |
+
{
|
| 2971 |
+
"move": "no-op",
|
| 2972 |
+
"view": "turn right"
|
| 2973 |
+
},
|
| 2974 |
+
{
|
| 2975 |
+
"move": "no-op",
|
| 2976 |
+
"view": "turn right"
|
| 2977 |
+
},
|
| 2978 |
+
{
|
| 2979 |
+
"move": "no-op",
|
| 2980 |
+
"view": "turn right"
|
| 2981 |
+
},
|
| 2982 |
+
{
|
| 2983 |
+
"move": "no-op",
|
| 2984 |
+
"view": "turn right"
|
| 2985 |
+
},
|
| 2986 |
+
{
|
| 2987 |
+
"move": "no-op",
|
| 2988 |
+
"view": "turn right"
|
| 2989 |
+
},
|
| 2990 |
+
{
|
| 2991 |
+
"move": "no-op",
|
| 2992 |
+
"view": "turn right"
|
| 2993 |
+
},
|
| 2994 |
+
{
|
| 2995 |
+
"move": "no-op",
|
| 2996 |
+
"view": "turn right"
|
| 2997 |
+
},
|
| 2998 |
+
{
|
| 2999 |
+
"move": "no-op",
|
| 3000 |
+
"view": "turn right"
|
| 3001 |
+
},
|
| 3002 |
+
{
|
| 3003 |
+
"move": "no-op",
|
| 3004 |
+
"view": "turn right"
|
| 3005 |
+
},
|
| 3006 |
+
{
|
| 3007 |
+
"move": "no-op",
|
| 3008 |
+
"view": "turn right"
|
| 3009 |
+
},
|
| 3010 |
+
{
|
| 3011 |
+
"move": "no-op",
|
| 3012 |
+
"view": "turn right"
|
| 3013 |
+
},
|
| 3014 |
+
{
|
| 3015 |
+
"move": "no-op",
|
| 3016 |
+
"view": "turn right"
|
| 3017 |
+
},
|
| 3018 |
+
{
|
| 3019 |
+
"move": "no-op",
|
| 3020 |
+
"view": "turn right"
|
| 3021 |
+
},
|
| 3022 |
+
{
|
| 3023 |
+
"move": "no-op",
|
| 3024 |
+
"view": "turn right"
|
| 3025 |
+
},
|
| 3026 |
+
{
|
| 3027 |
+
"move": "no-op",
|
| 3028 |
+
"view": "turn right"
|
| 3029 |
+
},
|
| 3030 |
+
{
|
| 3031 |
+
"move": "no-op",
|
| 3032 |
+
"view": "turn right"
|
| 3033 |
+
},
|
| 3034 |
+
{
|
| 3035 |
+
"move": "no-op",
|
| 3036 |
+
"view": "turn right"
|
| 3037 |
+
},
|
| 3038 |
+
{
|
| 3039 |
+
"move": "no-op",
|
| 3040 |
+
"view": "turn right"
|
| 3041 |
+
},
|
| 3042 |
+
{
|
| 3043 |
+
"move": "no-op",
|
| 3044 |
+
"view": "turn right"
|
| 3045 |
+
},
|
| 3046 |
+
{
|
| 3047 |
+
"move": "no-op",
|
| 3048 |
+
"view": "turn right"
|
| 3049 |
+
},
|
| 3050 |
+
{
|
| 3051 |
+
"move": "no-op",
|
| 3052 |
+
"view": "turn right"
|
| 3053 |
+
},
|
| 3054 |
+
{
|
| 3055 |
+
"move": "no-op",
|
| 3056 |
+
"view": "turn right"
|
| 3057 |
+
},
|
| 3058 |
+
{
|
| 3059 |
+
"move": "no-op",
|
| 3060 |
+
"view": "turn right"
|
| 3061 |
+
},
|
| 3062 |
+
{
|
| 3063 |
+
"move": "no-op",
|
| 3064 |
+
"view": "turn right"
|
| 3065 |
+
},
|
| 3066 |
+
{
|
| 3067 |
+
"move": "no-op",
|
| 3068 |
+
"view": "turn right"
|
| 3069 |
+
},
|
| 3070 |
+
{
|
| 3071 |
+
"move": "no-op",
|
| 3072 |
+
"view": "turn right"
|
| 3073 |
+
},
|
| 3074 |
+
{
|
| 3075 |
+
"move": "no-op",
|
| 3076 |
+
"view": "turn right"
|
| 3077 |
+
},
|
| 3078 |
+
{
|
| 3079 |
+
"move": "no-op",
|
| 3080 |
+
"view": "turn right"
|
| 3081 |
+
},
|
| 3082 |
+
{
|
| 3083 |
+
"move": "no-op",
|
| 3084 |
+
"view": "turn right"
|
| 3085 |
+
},
|
| 3086 |
+
{
|
| 3087 |
+
"move": "no-op",
|
| 3088 |
+
"view": "turn right"
|
| 3089 |
+
},
|
| 3090 |
+
{
|
| 3091 |
+
"move": "no-op",
|
| 3092 |
+
"view": "turn right"
|
| 3093 |
+
},
|
| 3094 |
+
{
|
| 3095 |
+
"move": "no-op",
|
| 3096 |
+
"view": "turn right"
|
| 3097 |
+
},
|
| 3098 |
+
{
|
| 3099 |
+
"move": "no-op",
|
| 3100 |
+
"view": "turn right"
|
| 3101 |
+
},
|
| 3102 |
+
{
|
| 3103 |
+
"move": "no-op",
|
| 3104 |
+
"view": "turn right"
|
| 3105 |
+
},
|
| 3106 |
+
{
|
| 3107 |
+
"move": "no-op",
|
| 3108 |
+
"view": "turn right"
|
| 3109 |
+
},
|
| 3110 |
+
{
|
| 3111 |
+
"move": "no-op",
|
| 3112 |
+
"view": "turn right"
|
| 3113 |
+
},
|
| 3114 |
+
{
|
| 3115 |
+
"move": "no-op",
|
| 3116 |
+
"view": "turn right"
|
| 3117 |
+
},
|
| 3118 |
+
{
|
| 3119 |
+
"move": "no-op",
|
| 3120 |
+
"view": "turn right"
|
| 3121 |
+
},
|
| 3122 |
+
{
|
| 3123 |
+
"move": "no-op",
|
| 3124 |
+
"view": "turn right"
|
| 3125 |
+
},
|
| 3126 |
+
{
|
| 3127 |
+
"move": "no-op",
|
| 3128 |
+
"view": "turn right"
|
| 3129 |
+
},
|
| 3130 |
+
{
|
| 3131 |
+
"move": "no-op",
|
| 3132 |
+
"view": "turn right"
|
| 3133 |
+
},
|
| 3134 |
+
{
|
| 3135 |
+
"move": "no-op",
|
| 3136 |
+
"view": "turn right"
|
| 3137 |
+
},
|
| 3138 |
+
{
|
| 3139 |
+
"move": "no-op",
|
| 3140 |
+
"view": "turn right"
|
| 3141 |
+
},
|
| 3142 |
+
{
|
| 3143 |
+
"move": "no-op",
|
| 3144 |
+
"view": "turn right"
|
| 3145 |
+
},
|
| 3146 |
+
{
|
| 3147 |
+
"move": "no-op",
|
| 3148 |
+
"view": "turn right"
|
| 3149 |
+
},
|
| 3150 |
+
{
|
| 3151 |
+
"move": "no-op",
|
| 3152 |
+
"view": "turn right"
|
| 3153 |
+
},
|
| 3154 |
+
{
|
| 3155 |
+
"move": "no-op",
|
| 3156 |
+
"view": "turn right"
|
| 3157 |
+
},
|
| 3158 |
+
{
|
| 3159 |
+
"move": "no-op",
|
| 3160 |
+
"view": "turn right"
|
| 3161 |
+
},
|
| 3162 |
+
{
|
| 3163 |
+
"move": "no-op",
|
| 3164 |
+
"view": "turn right"
|
| 3165 |
+
},
|
| 3166 |
+
{
|
| 3167 |
+
"move": "no-op",
|
| 3168 |
+
"view": "turn right"
|
| 3169 |
+
},
|
| 3170 |
+
{
|
| 3171 |
+
"move": "no-op",
|
| 3172 |
+
"view": "turn right"
|
| 3173 |
+
},
|
| 3174 |
+
{
|
| 3175 |
+
"move": "no-op",
|
| 3176 |
+
"view": "turn right"
|
| 3177 |
+
},
|
| 3178 |
+
{
|
| 3179 |
+
"move": "no-op",
|
| 3180 |
+
"view": "turn right"
|
| 3181 |
+
},
|
| 3182 |
+
{
|
| 3183 |
+
"move": "no-op",
|
| 3184 |
+
"view": "turn right"
|
| 3185 |
+
},
|
| 3186 |
+
{
|
| 3187 |
+
"move": "no-op",
|
| 3188 |
+
"view": "turn right"
|
| 3189 |
+
},
|
| 3190 |
+
{
|
| 3191 |
+
"move": "no-op",
|
| 3192 |
+
"view": "turn right"
|
| 3193 |
+
},
|
| 3194 |
+
{
|
| 3195 |
+
"move": "no-op",
|
| 3196 |
+
"view": "turn right"
|
| 3197 |
+
},
|
| 3198 |
+
{
|
| 3199 |
+
"move": "no-op",
|
| 3200 |
+
"view": "turn right"
|
| 3201 |
+
},
|
| 3202 |
+
{
|
| 3203 |
+
"move": "no-op",
|
| 3204 |
+
"view": "turn right"
|
| 3205 |
+
},
|
| 3206 |
+
{
|
| 3207 |
+
"move": "no-op",
|
| 3208 |
+
"view": "turn right"
|
| 3209 |
+
},
|
| 3210 |
+
{
|
| 3211 |
+
"move": "no-op",
|
| 3212 |
+
"view": "turn right"
|
| 3213 |
+
},
|
| 3214 |
+
{
|
| 3215 |
+
"move": "no-op",
|
| 3216 |
+
"view": "turn right"
|
| 3217 |
+
},
|
| 3218 |
+
{
|
| 3219 |
+
"move": "no-op",
|
| 3220 |
+
"view": "turn right"
|
| 3221 |
+
},
|
| 3222 |
+
{
|
| 3223 |
+
"move": "no-op",
|
| 3224 |
+
"view": "turn right"
|
| 3225 |
+
},
|
| 3226 |
+
{
|
| 3227 |
+
"move": "no-op",
|
| 3228 |
+
"view": "turn right"
|
| 3229 |
+
},
|
| 3230 |
+
{
|
| 3231 |
+
"move": "no-op",
|
| 3232 |
+
"view": "turn right"
|
| 3233 |
+
},
|
| 3234 |
+
{
|
| 3235 |
+
"move": "no-op",
|
| 3236 |
+
"view": "turn right"
|
| 3237 |
+
},
|
| 3238 |
+
{
|
| 3239 |
+
"move": "no-op",
|
| 3240 |
+
"view": "turn right"
|
| 3241 |
+
},
|
| 3242 |
+
{
|
| 3243 |
+
"move": "no-op",
|
| 3244 |
+
"view": "turn right"
|
| 3245 |
+
},
|
| 3246 |
+
{
|
| 3247 |
+
"move": "no-op",
|
| 3248 |
+
"view": "turn right"
|
| 3249 |
+
},
|
| 3250 |
+
{
|
| 3251 |
+
"move": "no-op",
|
| 3252 |
+
"view": "turn right"
|
| 3253 |
+
},
|
| 3254 |
+
{
|
| 3255 |
+
"move": "no-op",
|
| 3256 |
+
"view": "turn right"
|
| 3257 |
+
},
|
| 3258 |
+
{
|
| 3259 |
+
"move": "no-op",
|
| 3260 |
+
"view": "turn right"
|
| 3261 |
+
},
|
| 3262 |
+
{
|
| 3263 |
+
"move": "no-op",
|
| 3264 |
+
"view": "turn right"
|
| 3265 |
+
},
|
| 3266 |
+
{
|
| 3267 |
+
"move": "no-op",
|
| 3268 |
+
"view": "turn right"
|
| 3269 |
+
},
|
| 3270 |
+
{
|
| 3271 |
+
"move": "no-op",
|
| 3272 |
+
"view": "turn right"
|
| 3273 |
+
},
|
| 3274 |
+
{
|
| 3275 |
+
"move": "no-op",
|
| 3276 |
+
"view": "turn right"
|
| 3277 |
+
},
|
| 3278 |
+
{
|
| 3279 |
+
"move": "no-op",
|
| 3280 |
+
"view": "turn right"
|
| 3281 |
+
},
|
| 3282 |
+
{
|
| 3283 |
+
"move": "no-op",
|
| 3284 |
+
"view": "turn right"
|
| 3285 |
+
},
|
| 3286 |
+
{
|
| 3287 |
+
"move": "no-op",
|
| 3288 |
+
"view": "turn right"
|
| 3289 |
+
},
|
| 3290 |
+
{
|
| 3291 |
+
"move": "no-op",
|
| 3292 |
+
"view": "turn right"
|
| 3293 |
+
},
|
| 3294 |
+
{
|
| 3295 |
+
"move": "no-op",
|
| 3296 |
+
"view": "turn right"
|
| 3297 |
+
},
|
| 3298 |
+
{
|
| 3299 |
+
"move": "no-op",
|
| 3300 |
+
"view": "turn right"
|
| 3301 |
+
},
|
| 3302 |
+
{
|
| 3303 |
+
"move": "no-op",
|
| 3304 |
+
"view": "turn right"
|
| 3305 |
+
},
|
| 3306 |
+
{
|
| 3307 |
+
"move": "no-op",
|
| 3308 |
+
"view": "turn right"
|
| 3309 |
+
},
|
| 3310 |
+
{
|
| 3311 |
+
"move": "no-op",
|
| 3312 |
+
"view": "turn right"
|
| 3313 |
+
},
|
| 3314 |
+
{
|
| 3315 |
+
"move": "no-op",
|
| 3316 |
+
"view": "turn right"
|
| 3317 |
+
},
|
| 3318 |
+
{
|
| 3319 |
+
"move": "no-op",
|
| 3320 |
+
"view": "turn right"
|
| 3321 |
+
},
|
| 3322 |
+
{
|
| 3323 |
+
"move": "no-op",
|
| 3324 |
+
"view": "turn right"
|
| 3325 |
+
},
|
| 3326 |
+
{
|
| 3327 |
+
"move": "no-op",
|
| 3328 |
+
"view": "turn right"
|
| 3329 |
+
},
|
| 3330 |
+
{
|
| 3331 |
+
"move": "no-op",
|
| 3332 |
+
"view": "turn right"
|
| 3333 |
+
},
|
| 3334 |
+
{
|
| 3335 |
+
"move": "no-op",
|
| 3336 |
+
"view": "turn right"
|
| 3337 |
+
},
|
| 3338 |
+
{
|
| 3339 |
+
"move": "no-op",
|
| 3340 |
+
"view": "turn right"
|
| 3341 |
+
},
|
| 3342 |
+
{
|
| 3343 |
+
"move": "no-op",
|
| 3344 |
+
"view": "turn right"
|
| 3345 |
+
},
|
| 3346 |
+
{
|
| 3347 |
+
"move": "no-op",
|
| 3348 |
+
"view": "turn right"
|
| 3349 |
+
},
|
| 3350 |
+
{
|
| 3351 |
+
"move": "no-op",
|
| 3352 |
+
"view": "turn right"
|
| 3353 |
+
},
|
| 3354 |
+
{
|
| 3355 |
+
"move": "no-op",
|
| 3356 |
+
"view": "turn right"
|
| 3357 |
+
},
|
| 3358 |
+
{
|
| 3359 |
+
"move": "no-op",
|
| 3360 |
+
"view": "turn right"
|
| 3361 |
+
},
|
| 3362 |
+
{
|
| 3363 |
+
"move": "no-op",
|
| 3364 |
+
"view": "turn right"
|
| 3365 |
+
},
|
| 3366 |
+
{
|
| 3367 |
+
"move": "no-op",
|
| 3368 |
+
"view": "turn right"
|
| 3369 |
+
},
|
| 3370 |
+
{
|
| 3371 |
+
"move": "no-op",
|
| 3372 |
+
"view": "turn right"
|
| 3373 |
+
},
|
| 3374 |
+
{
|
| 3375 |
+
"move": "no-op",
|
| 3376 |
+
"view": "turn right"
|
| 3377 |
+
},
|
| 3378 |
+
{
|
| 3379 |
+
"move": "no-op",
|
| 3380 |
+
"view": "turn right"
|
| 3381 |
+
},
|
| 3382 |
+
{
|
| 3383 |
+
"move": "no-op",
|
| 3384 |
+
"view": "turn right"
|
| 3385 |
+
},
|
| 3386 |
+
{
|
| 3387 |
+
"move": "no-op",
|
| 3388 |
+
"view": "turn right"
|
| 3389 |
+
},
|
| 3390 |
+
{
|
| 3391 |
+
"move": "no-op",
|
| 3392 |
+
"view": "turn right"
|
| 3393 |
+
},
|
| 3394 |
+
{
|
| 3395 |
+
"move": "no-op",
|
| 3396 |
+
"view": "turn right"
|
| 3397 |
+
},
|
| 3398 |
+
{
|
| 3399 |
+
"move": "no-op",
|
| 3400 |
+
"view": "turn right"
|
| 3401 |
+
},
|
| 3402 |
+
{
|
| 3403 |
+
"move": "no-op",
|
| 3404 |
+
"view": "turn right"
|
| 3405 |
+
},
|
| 3406 |
+
{
|
| 3407 |
+
"move": "no-op",
|
| 3408 |
+
"view": "turn right"
|
| 3409 |
+
},
|
| 3410 |
+
{
|
| 3411 |
+
"move": "no-op",
|
| 3412 |
+
"view": "turn right"
|
| 3413 |
+
},
|
| 3414 |
+
{
|
| 3415 |
+
"move": "no-op",
|
| 3416 |
+
"view": "turn right"
|
| 3417 |
+
},
|
| 3418 |
+
{
|
| 3419 |
+
"move": "no-op",
|
| 3420 |
+
"view": "turn right"
|
| 3421 |
+
},
|
| 3422 |
+
{
|
| 3423 |
+
"move": "no-op",
|
| 3424 |
+
"view": "turn right"
|
| 3425 |
+
},
|
| 3426 |
+
{
|
| 3427 |
+
"move": "no-op",
|
| 3428 |
+
"view": "turn right"
|
| 3429 |
+
},
|
| 3430 |
+
{
|
| 3431 |
+
"move": "no-op",
|
| 3432 |
+
"view": "turn right"
|
| 3433 |
+
},
|
| 3434 |
+
{
|
| 3435 |
+
"move": "no-op",
|
| 3436 |
+
"view": "turn right"
|
| 3437 |
+
},
|
| 3438 |
+
{
|
| 3439 |
+
"move": "no-op",
|
| 3440 |
+
"view": "turn right"
|
| 3441 |
+
},
|
| 3442 |
+
{
|
| 3443 |
+
"move": "no-op",
|
| 3444 |
+
"view": "turn right"
|
| 3445 |
+
},
|
| 3446 |
+
{
|
| 3447 |
+
"move": "no-op",
|
| 3448 |
+
"view": "turn right"
|
| 3449 |
+
},
|
| 3450 |
+
{
|
| 3451 |
+
"move": "no-op",
|
| 3452 |
+
"view": "turn right"
|
| 3453 |
+
},
|
| 3454 |
+
{
|
| 3455 |
+
"move": "no-op",
|
| 3456 |
+
"view": "turn right"
|
| 3457 |
+
},
|
| 3458 |
+
{
|
| 3459 |
+
"move": "no-op",
|
| 3460 |
+
"view": "turn right"
|
| 3461 |
+
},
|
| 3462 |
+
{
|
| 3463 |
+
"move": "no-op",
|
| 3464 |
+
"view": "turn right"
|
| 3465 |
+
},
|
| 3466 |
+
{
|
| 3467 |
+
"move": "no-op",
|
| 3468 |
+
"view": "turn right"
|
| 3469 |
+
},
|
| 3470 |
+
{
|
| 3471 |
+
"move": "no-op",
|
| 3472 |
+
"view": "turn right"
|
| 3473 |
+
},
|
| 3474 |
+
{
|
| 3475 |
+
"move": "no-op",
|
| 3476 |
+
"view": "turn right"
|
| 3477 |
+
},
|
| 3478 |
+
{
|
| 3479 |
+
"move": "no-op",
|
| 3480 |
+
"view": "turn right"
|
| 3481 |
+
},
|
| 3482 |
+
{
|
| 3483 |
+
"move": "no-op",
|
| 3484 |
+
"view": "turn right"
|
| 3485 |
+
},
|
| 3486 |
+
{
|
| 3487 |
+
"move": "no-op",
|
| 3488 |
+
"view": "turn right"
|
| 3489 |
+
},
|
| 3490 |
+
{
|
| 3491 |
+
"move": "no-op",
|
| 3492 |
+
"view": "turn right"
|
| 3493 |
+
},
|
| 3494 |
+
{
|
| 3495 |
+
"move": "no-op",
|
| 3496 |
+
"view": "turn right"
|
| 3497 |
+
},
|
| 3498 |
+
{
|
| 3499 |
+
"move": "no-op",
|
| 3500 |
+
"view": "turn right"
|
| 3501 |
+
},
|
| 3502 |
+
{
|
| 3503 |
+
"move": "no-op",
|
| 3504 |
+
"view": "turn right"
|
| 3505 |
+
},
|
| 3506 |
+
{
|
| 3507 |
+
"move": "no-op",
|
| 3508 |
+
"view": "turn right"
|
| 3509 |
+
},
|
| 3510 |
+
{
|
| 3511 |
+
"move": "no-op",
|
| 3512 |
+
"view": "turn right"
|
| 3513 |
+
},
|
| 3514 |
+
{
|
| 3515 |
+
"move": "no-op",
|
| 3516 |
+
"view": "turn right"
|
| 3517 |
+
},
|
| 3518 |
+
{
|
| 3519 |
+
"move": "no-op",
|
| 3520 |
+
"view": "turn right"
|
| 3521 |
+
},
|
| 3522 |
+
{
|
| 3523 |
+
"move": "no-op",
|
| 3524 |
+
"view": "turn right"
|
| 3525 |
+
},
|
| 3526 |
+
{
|
| 3527 |
+
"move": "no-op",
|
| 3528 |
+
"view": "turn right"
|
| 3529 |
+
},
|
| 3530 |
+
{
|
| 3531 |
+
"move": "no-op",
|
| 3532 |
+
"view": "turn right"
|
| 3533 |
+
},
|
| 3534 |
+
{
|
| 3535 |
+
"move": "no-op",
|
| 3536 |
+
"view": "turn right"
|
| 3537 |
+
},
|
| 3538 |
+
{
|
| 3539 |
+
"move": "no-op",
|
| 3540 |
+
"view": "turn right"
|
| 3541 |
+
},
|
| 3542 |
+
{
|
| 3543 |
+
"move": "no-op",
|
| 3544 |
+
"view": "turn right"
|
| 3545 |
+
},
|
| 3546 |
+
{
|
| 3547 |
+
"move": "no-op",
|
| 3548 |
+
"view": "turn right"
|
| 3549 |
+
},
|
| 3550 |
+
{
|
| 3551 |
+
"move": "no-op",
|
| 3552 |
+
"view": "turn right"
|
| 3553 |
+
},
|
| 3554 |
+
{
|
| 3555 |
+
"move": "no-op",
|
| 3556 |
+
"view": "turn right"
|
| 3557 |
+
},
|
| 3558 |
+
{
|
| 3559 |
+
"move": "no-op",
|
| 3560 |
+
"view": "turn right"
|
| 3561 |
+
},
|
| 3562 |
+
{
|
| 3563 |
+
"move": "no-op",
|
| 3564 |
+
"view": "turn right"
|
| 3565 |
+
},
|
| 3566 |
+
{
|
| 3567 |
+
"move": "no-op",
|
| 3568 |
+
"view": "turn up"
|
| 3569 |
+
},
|
| 3570 |
+
{
|
| 3571 |
+
"move": "no-op",
|
| 3572 |
+
"view": "turn up"
|
| 3573 |
+
},
|
| 3574 |
+
{
|
| 3575 |
+
"move": "no-op",
|
| 3576 |
+
"view": "turn up"
|
| 3577 |
+
},
|
| 3578 |
+
{
|
| 3579 |
+
"move": "no-op",
|
| 3580 |
+
"view": "turn up"
|
| 3581 |
+
},
|
| 3582 |
+
{
|
| 3583 |
+
"move": "no-op",
|
| 3584 |
+
"view": "turn up"
|
| 3585 |
+
},
|
| 3586 |
+
{
|
| 3587 |
+
"move": "no-op",
|
| 3588 |
+
"view": "turn up"
|
| 3589 |
+
},
|
| 3590 |
+
{
|
| 3591 |
+
"move": "no-op",
|
| 3592 |
+
"view": "turn up"
|
| 3593 |
+
},
|
| 3594 |
+
{
|
| 3595 |
+
"move": "no-op",
|
| 3596 |
+
"view": "turn up"
|
| 3597 |
+
},
|
| 3598 |
+
{
|
| 3599 |
+
"move": "no-op",
|
| 3600 |
+
"view": "turn up"
|
| 3601 |
+
},
|
| 3602 |
+
{
|
| 3603 |
+
"move": "no-op",
|
| 3604 |
+
"view": "turn up"
|
| 3605 |
+
},
|
| 3606 |
+
{
|
| 3607 |
+
"move": "no-op",
|
| 3608 |
+
"view": "turn up"
|
| 3609 |
+
},
|
| 3610 |
+
{
|
| 3611 |
+
"move": "no-op",
|
| 3612 |
+
"view": "turn up"
|
| 3613 |
+
},
|
| 3614 |
+
{
|
| 3615 |
+
"move": "no-op",
|
| 3616 |
+
"view": "turn up"
|
| 3617 |
+
},
|
| 3618 |
+
{
|
| 3619 |
+
"move": "no-op",
|
| 3620 |
+
"view": "turn up"
|
| 3621 |
+
},
|
| 3622 |
+
{
|
| 3623 |
+
"move": "no-op",
|
| 3624 |
+
"view": "turn up"
|
| 3625 |
+
},
|
| 3626 |
+
{
|
| 3627 |
+
"move": "no-op",
|
| 3628 |
+
"view": "turn up"
|
| 3629 |
+
},
|
| 3630 |
+
{
|
| 3631 |
+
"move": "no-op",
|
| 3632 |
+
"view": "turn up"
|
| 3633 |
+
},
|
| 3634 |
+
{
|
| 3635 |
+
"move": "no-op",
|
| 3636 |
+
"view": "turn up"
|
| 3637 |
+
},
|
| 3638 |
+
{
|
| 3639 |
+
"move": "no-op",
|
| 3640 |
+
"view": "turn up"
|
| 3641 |
+
},
|
| 3642 |
+
{
|
| 3643 |
+
"move": "no-op",
|
| 3644 |
+
"view": "turn up"
|
| 3645 |
+
},
|
| 3646 |
+
{
|
| 3647 |
+
"move": "no-op",
|
| 3648 |
+
"view": "turn up"
|
| 3649 |
+
},
|
| 3650 |
+
{
|
| 3651 |
+
"move": "no-op",
|
| 3652 |
+
"view": "turn up"
|
| 3653 |
+
},
|
| 3654 |
+
{
|
| 3655 |
+
"move": "no-op",
|
| 3656 |
+
"view": "turn up"
|
| 3657 |
+
},
|
| 3658 |
+
{
|
| 3659 |
+
"move": "no-op",
|
| 3660 |
+
"view": "turn up"
|
| 3661 |
+
},
|
| 3662 |
+
{
|
| 3663 |
+
"move": "no-op",
|
| 3664 |
+
"view": "turn up"
|
| 3665 |
+
},
|
| 3666 |
+
{
|
| 3667 |
+
"move": "no-op",
|
| 3668 |
+
"view": "turn up"
|
| 3669 |
+
},
|
| 3670 |
+
{
|
| 3671 |
+
"move": "no-op",
|
| 3672 |
+
"view": "turn up"
|
| 3673 |
+
},
|
| 3674 |
+
{
|
| 3675 |
+
"move": "no-op",
|
| 3676 |
+
"view": "turn up"
|
| 3677 |
+
},
|
| 3678 |
+
{
|
| 3679 |
+
"move": "no-op",
|
| 3680 |
+
"view": "turn up"
|
| 3681 |
+
},
|
| 3682 |
+
{
|
| 3683 |
+
"move": "no-op",
|
| 3684 |
+
"view": "turn up"
|
| 3685 |
+
},
|
| 3686 |
+
{
|
| 3687 |
+
"move": "no-op",
|
| 3688 |
+
"view": "turn up"
|
| 3689 |
+
},
|
| 3690 |
+
{
|
| 3691 |
+
"move": "no-op",
|
| 3692 |
+
"view": "turn up"
|
| 3693 |
+
},
|
| 3694 |
+
{
|
| 3695 |
+
"move": "no-op",
|
| 3696 |
+
"view": "turn up"
|
| 3697 |
+
},
|
| 3698 |
+
{
|
| 3699 |
+
"move": "no-op",
|
| 3700 |
+
"view": "turn up"
|
| 3701 |
+
},
|
| 3702 |
+
{
|
| 3703 |
+
"move": "no-op",
|
| 3704 |
+
"view": "turn up"
|
| 3705 |
+
},
|
| 3706 |
+
{
|
| 3707 |
+
"move": "no-op",
|
| 3708 |
+
"view": "turn up"
|
| 3709 |
+
},
|
| 3710 |
+
{
|
| 3711 |
+
"move": "no-op",
|
| 3712 |
+
"view": "turn up"
|
| 3713 |
+
},
|
| 3714 |
+
{
|
| 3715 |
+
"move": "no-op",
|
| 3716 |
+
"view": "turn up"
|
| 3717 |
+
},
|
| 3718 |
+
{
|
| 3719 |
+
"move": "no-op",
|
| 3720 |
+
"view": "turn up"
|
| 3721 |
+
},
|
| 3722 |
+
{
|
| 3723 |
+
"move": "no-op",
|
| 3724 |
+
"view": "turn up"
|
| 3725 |
+
},
|
| 3726 |
+
{
|
| 3727 |
+
"move": "no-op",
|
| 3728 |
+
"view": "turn up"
|
| 3729 |
+
},
|
| 3730 |
+
{
|
| 3731 |
+
"move": "no-op",
|
| 3732 |
+
"view": "turn up"
|
| 3733 |
+
},
|
| 3734 |
+
{
|
| 3735 |
+
"move": "no-op",
|
| 3736 |
+
"view": "turn up"
|
| 3737 |
+
},
|
| 3738 |
+
{
|
| 3739 |
+
"move": "no-op",
|
| 3740 |
+
"view": "turn up"
|
| 3741 |
+
},
|
| 3742 |
+
{
|
| 3743 |
+
"move": "no-op",
|
| 3744 |
+
"view": "turn up"
|
| 3745 |
+
},
|
| 3746 |
+
{
|
| 3747 |
+
"move": "no-op",
|
| 3748 |
+
"view": "turn up"
|
| 3749 |
+
},
|
| 3750 |
+
{
|
| 3751 |
+
"move": "no-op",
|
| 3752 |
+
"view": "turn up"
|
| 3753 |
+
},
|
| 3754 |
+
{
|
| 3755 |
+
"move": "no-op",
|
| 3756 |
+
"view": "turn up"
|
| 3757 |
+
},
|
| 3758 |
+
{
|
| 3759 |
+
"move": "no-op",
|
| 3760 |
+
"view": "turn up"
|
| 3761 |
+
},
|
| 3762 |
+
{
|
| 3763 |
+
"move": "no-op",
|
| 3764 |
+
"view": "turn up"
|
| 3765 |
+
},
|
| 3766 |
+
{
|
| 3767 |
+
"move": "no-op",
|
| 3768 |
+
"view": "turn up"
|
| 3769 |
+
},
|
| 3770 |
+
{
|
| 3771 |
+
"move": "no-op",
|
| 3772 |
+
"view": "turn up"
|
| 3773 |
+
},
|
| 3774 |
+
{
|
| 3775 |
+
"move": "no-op",
|
| 3776 |
+
"view": "turn up"
|
| 3777 |
+
},
|
| 3778 |
+
{
|
| 3779 |
+
"move": "no-op",
|
| 3780 |
+
"view": "turn up"
|
| 3781 |
+
},
|
| 3782 |
+
{
|
| 3783 |
+
"move": "no-op",
|
| 3784 |
+
"view": "turn up"
|
| 3785 |
+
},
|
| 3786 |
+
{
|
| 3787 |
+
"move": "no-op",
|
| 3788 |
+
"view": "turn up"
|
| 3789 |
+
},
|
| 3790 |
+
{
|
| 3791 |
+
"move": "no-op",
|
| 3792 |
+
"view": "turn up"
|
| 3793 |
+
},
|
| 3794 |
+
{
|
| 3795 |
+
"move": "no-op",
|
| 3796 |
+
"view": "turn up"
|
| 3797 |
+
},
|
| 3798 |
+
{
|
| 3799 |
+
"move": "no-op",
|
| 3800 |
+
"view": "turn up"
|
| 3801 |
+
},
|
| 3802 |
+
{
|
| 3803 |
+
"move": "no-op",
|
| 3804 |
+
"view": "turn up"
|
| 3805 |
+
},
|
| 3806 |
+
{
|
| 3807 |
+
"move": "no-op",
|
| 3808 |
+
"view": "turn up"
|
| 3809 |
+
},
|
| 3810 |
+
{
|
| 3811 |
+
"move": "no-op",
|
| 3812 |
+
"view": "turn up"
|
| 3813 |
+
},
|
| 3814 |
+
{
|
| 3815 |
+
"move": "no-op",
|
| 3816 |
+
"view": "turn up"
|
| 3817 |
+
},
|
| 3818 |
+
{
|
| 3819 |
+
"move": "no-op",
|
| 3820 |
+
"view": "turn up"
|
| 3821 |
+
},
|
| 3822 |
+
{
|
| 3823 |
+
"move": "no-op",
|
| 3824 |
+
"view": "turn up"
|
| 3825 |
+
},
|
| 3826 |
+
{
|
| 3827 |
+
"move": "no-op",
|
| 3828 |
+
"view": "turn up"
|
| 3829 |
+
},
|
| 3830 |
+
{
|
| 3831 |
+
"move": "no-op",
|
| 3832 |
+
"view": "turn up"
|
| 3833 |
+
},
|
| 3834 |
+
{
|
| 3835 |
+
"move": "no-op",
|
| 3836 |
+
"view": "turn up"
|
| 3837 |
+
},
|
| 3838 |
+
{
|
| 3839 |
+
"move": "no-op",
|
| 3840 |
+
"view": "turn up"
|
| 3841 |
+
},
|
| 3842 |
+
{
|
| 3843 |
+
"move": "no-op",
|
| 3844 |
+
"view": "turn up"
|
| 3845 |
+
},
|
| 3846 |
+
{
|
| 3847 |
+
"move": "no-op",
|
| 3848 |
+
"view": "turn up"
|
| 3849 |
+
},
|
| 3850 |
+
{
|
| 3851 |
+
"move": "no-op",
|
| 3852 |
+
"view": "turn up"
|
| 3853 |
+
},
|
| 3854 |
+
{
|
| 3855 |
+
"move": "no-op",
|
| 3856 |
+
"view": "turn up"
|
| 3857 |
+
},
|
| 3858 |
+
{
|
| 3859 |
+
"move": "no-op",
|
| 3860 |
+
"view": "turn up"
|
| 3861 |
+
},
|
| 3862 |
+
{
|
| 3863 |
+
"move": "no-op",
|
| 3864 |
+
"view": "turn up"
|
| 3865 |
+
},
|
| 3866 |
+
{
|
| 3867 |
+
"move": "no-op",
|
| 3868 |
+
"view": "turn up"
|
| 3869 |
+
},
|
| 3870 |
+
{
|
| 3871 |
+
"move": "no-op",
|
| 3872 |
+
"view": "turn up"
|
| 3873 |
+
},
|
| 3874 |
+
{
|
| 3875 |
+
"move": "no-op",
|
| 3876 |
+
"view": "turn up"
|
| 3877 |
+
},
|
| 3878 |
+
{
|
| 3879 |
+
"move": "no-op",
|
| 3880 |
+
"view": "turn up"
|
| 3881 |
+
},
|
| 3882 |
+
{
|
| 3883 |
+
"move": "no-op",
|
| 3884 |
+
"view": "turn up"
|
| 3885 |
+
},
|
| 3886 |
+
{
|
| 3887 |
+
"move": "no-op",
|
| 3888 |
+
"view": "turn up"
|
| 3889 |
+
},
|
| 3890 |
+
{
|
| 3891 |
+
"move": "no-op",
|
| 3892 |
+
"view": "turn down"
|
| 3893 |
+
},
|
| 3894 |
+
{
|
| 3895 |
+
"move": "no-op",
|
| 3896 |
+
"view": "turn down"
|
| 3897 |
+
},
|
| 3898 |
+
{
|
| 3899 |
+
"move": "no-op",
|
| 3900 |
+
"view": "turn down"
|
| 3901 |
+
},
|
| 3902 |
+
{
|
| 3903 |
+
"move": "no-op",
|
| 3904 |
+
"view": "turn down"
|
| 3905 |
+
},
|
| 3906 |
+
{
|
| 3907 |
+
"move": "no-op",
|
| 3908 |
+
"view": "turn down"
|
| 3909 |
+
},
|
| 3910 |
+
{
|
| 3911 |
+
"move": "no-op",
|
| 3912 |
+
"view": "turn down"
|
| 3913 |
+
},
|
| 3914 |
+
{
|
| 3915 |
+
"move": "no-op",
|
| 3916 |
+
"view": "turn down"
|
| 3917 |
+
},
|
| 3918 |
+
{
|
| 3919 |
+
"move": "no-op",
|
| 3920 |
+
"view": "turn down"
|
| 3921 |
+
},
|
| 3922 |
+
{
|
| 3923 |
+
"move": "no-op",
|
| 3924 |
+
"view": "turn down"
|
| 3925 |
+
},
|
| 3926 |
+
{
|
| 3927 |
+
"move": "no-op",
|
| 3928 |
+
"view": "turn down"
|
| 3929 |
+
},
|
| 3930 |
+
{
|
| 3931 |
+
"move": "no-op",
|
| 3932 |
+
"view": "turn down"
|
| 3933 |
+
},
|
| 3934 |
+
{
|
| 3935 |
+
"move": "no-op",
|
| 3936 |
+
"view": "turn down"
|
| 3937 |
+
},
|
| 3938 |
+
{
|
| 3939 |
+
"move": "no-op",
|
| 3940 |
+
"view": "turn down"
|
| 3941 |
+
},
|
| 3942 |
+
{
|
| 3943 |
+
"move": "no-op",
|
| 3944 |
+
"view": "turn down"
|
| 3945 |
+
},
|
| 3946 |
+
{
|
| 3947 |
+
"move": "no-op",
|
| 3948 |
+
"view": "turn down"
|
| 3949 |
+
},
|
| 3950 |
+
{
|
| 3951 |
+
"move": "no-op",
|
| 3952 |
+
"view": "turn down"
|
| 3953 |
+
},
|
| 3954 |
+
{
|
| 3955 |
+
"move": "no-op",
|
| 3956 |
+
"view": "turn down"
|
| 3957 |
+
},
|
| 3958 |
+
{
|
| 3959 |
+
"move": "no-op",
|
| 3960 |
+
"view": "turn down"
|
| 3961 |
+
},
|
| 3962 |
+
{
|
| 3963 |
+
"move": "no-op",
|
| 3964 |
+
"view": "turn down"
|
| 3965 |
+
},
|
| 3966 |
+
{
|
| 3967 |
+
"move": "no-op",
|
| 3968 |
+
"view": "turn down"
|
| 3969 |
+
},
|
| 3970 |
+
{
|
| 3971 |
+
"move": "no-op",
|
| 3972 |
+
"view": "turn down"
|
| 3973 |
+
},
|
| 3974 |
+
{
|
| 3975 |
+
"move": "no-op",
|
| 3976 |
+
"view": "turn down"
|
| 3977 |
+
},
|
| 3978 |
+
{
|
| 3979 |
+
"move": "no-op",
|
| 3980 |
+
"view": "turn down"
|
| 3981 |
+
},
|
| 3982 |
+
{
|
| 3983 |
+
"move": "no-op",
|
| 3984 |
+
"view": "turn down"
|
| 3985 |
+
},
|
| 3986 |
+
{
|
| 3987 |
+
"move": "no-op",
|
| 3988 |
+
"view": "turn down"
|
| 3989 |
+
},
|
| 3990 |
+
{
|
| 3991 |
+
"move": "no-op",
|
| 3992 |
+
"view": "turn down"
|
| 3993 |
+
},
|
| 3994 |
+
{
|
| 3995 |
+
"move": "no-op",
|
| 3996 |
+
"view": "turn down"
|
| 3997 |
+
},
|
| 3998 |
+
{
|
| 3999 |
+
"move": "no-op",
|
| 4000 |
+
"view": "turn down"
|
| 4001 |
+
},
|
| 4002 |
+
{
|
| 4003 |
+
"move": "no-op",
|
| 4004 |
+
"view": "turn down"
|
| 4005 |
+
},
|
| 4006 |
+
{
|
| 4007 |
+
"move": "no-op",
|
| 4008 |
+
"view": "turn down"
|
| 4009 |
+
},
|
| 4010 |
+
{
|
| 4011 |
+
"move": "no-op",
|
| 4012 |
+
"view": "turn down"
|
| 4013 |
+
},
|
| 4014 |
+
{
|
| 4015 |
+
"move": "no-op",
|
| 4016 |
+
"view": "turn down"
|
| 4017 |
+
},
|
| 4018 |
+
{
|
| 4019 |
+
"move": "no-op",
|
| 4020 |
+
"view": "turn down"
|
| 4021 |
+
},
|
| 4022 |
+
{
|
| 4023 |
+
"move": "no-op",
|
| 4024 |
+
"view": "turn down"
|
| 4025 |
+
},
|
| 4026 |
+
{
|
| 4027 |
+
"move": "no-op",
|
| 4028 |
+
"view": "turn down"
|
| 4029 |
+
},
|
| 4030 |
+
{
|
| 4031 |
+
"move": "no-op",
|
| 4032 |
+
"view": "turn down"
|
| 4033 |
+
},
|
| 4034 |
+
{
|
| 4035 |
+
"move": "no-op",
|
| 4036 |
+
"view": "turn down"
|
| 4037 |
+
},
|
| 4038 |
+
{
|
| 4039 |
+
"move": "no-op",
|
| 4040 |
+
"view": "turn down"
|
| 4041 |
+
},
|
| 4042 |
+
{
|
| 4043 |
+
"move": "no-op",
|
| 4044 |
+
"view": "turn down"
|
| 4045 |
+
},
|
| 4046 |
+
{
|
| 4047 |
+
"move": "no-op",
|
| 4048 |
+
"view": "turn down"
|
| 4049 |
+
},
|
| 4050 |
+
{
|
| 4051 |
+
"move": "no-op",
|
| 4052 |
+
"view": "turn down"
|
| 4053 |
+
},
|
| 4054 |
+
{
|
| 4055 |
+
"move": "no-op",
|
| 4056 |
+
"view": "turn down"
|
| 4057 |
+
},
|
| 4058 |
+
{
|
| 4059 |
+
"move": "no-op",
|
| 4060 |
+
"view": "turn down"
|
| 4061 |
+
},
|
| 4062 |
+
{
|
| 4063 |
+
"move": "no-op",
|
| 4064 |
+
"view": "turn down"
|
| 4065 |
+
},
|
| 4066 |
+
{
|
| 4067 |
+
"move": "no-op",
|
| 4068 |
+
"view": "turn down"
|
| 4069 |
+
},
|
| 4070 |
+
{
|
| 4071 |
+
"move": "no-op",
|
| 4072 |
+
"view": "turn down"
|
| 4073 |
+
},
|
| 4074 |
+
{
|
| 4075 |
+
"move": "no-op",
|
| 4076 |
+
"view": "turn down"
|
| 4077 |
+
},
|
| 4078 |
+
{
|
| 4079 |
+
"move": "no-op",
|
| 4080 |
+
"view": "turn down"
|
| 4081 |
+
},
|
| 4082 |
+
{
|
| 4083 |
+
"move": "no-op",
|
| 4084 |
+
"view": "turn down"
|
| 4085 |
+
},
|
| 4086 |
+
{
|
| 4087 |
+
"move": "no-op",
|
| 4088 |
+
"view": "turn down"
|
| 4089 |
+
},
|
| 4090 |
+
{
|
| 4091 |
+
"move": "no-op",
|
| 4092 |
+
"view": "turn down"
|
| 4093 |
+
},
|
| 4094 |
+
{
|
| 4095 |
+
"move": "no-op",
|
| 4096 |
+
"view": "turn down"
|
| 4097 |
+
},
|
| 4098 |
+
{
|
| 4099 |
+
"move": "no-op",
|
| 4100 |
+
"view": "turn down"
|
| 4101 |
+
},
|
| 4102 |
+
{
|
| 4103 |
+
"move": "no-op",
|
| 4104 |
+
"view": "turn down"
|
| 4105 |
+
},
|
| 4106 |
+
{
|
| 4107 |
+
"move": "no-op",
|
| 4108 |
+
"view": "turn down"
|
| 4109 |
+
},
|
| 4110 |
+
{
|
| 4111 |
+
"move": "no-op",
|
| 4112 |
+
"view": "turn down"
|
| 4113 |
+
},
|
| 4114 |
+
{
|
| 4115 |
+
"move": "no-op",
|
| 4116 |
+
"view": "turn down"
|
| 4117 |
+
},
|
| 4118 |
+
{
|
| 4119 |
+
"move": "no-op",
|
| 4120 |
+
"view": "turn down"
|
| 4121 |
+
},
|
| 4122 |
+
{
|
| 4123 |
+
"move": "no-op",
|
| 4124 |
+
"view": "turn down"
|
| 4125 |
+
},
|
| 4126 |
+
{
|
| 4127 |
+
"move": "no-op",
|
| 4128 |
+
"view": "turn down"
|
| 4129 |
+
},
|
| 4130 |
+
{
|
| 4131 |
+
"move": "no-op",
|
| 4132 |
+
"view": "turn down"
|
| 4133 |
+
},
|
| 4134 |
+
{
|
| 4135 |
+
"move": "no-op",
|
| 4136 |
+
"view": "turn down"
|
| 4137 |
+
},
|
| 4138 |
+
{
|
| 4139 |
+
"move": "no-op",
|
| 4140 |
+
"view": "turn down"
|
| 4141 |
+
},
|
| 4142 |
+
{
|
| 4143 |
+
"move": "no-op",
|
| 4144 |
+
"view": "turn down"
|
| 4145 |
+
},
|
| 4146 |
+
{
|
| 4147 |
+
"move": "no-op",
|
| 4148 |
+
"view": "turn down"
|
| 4149 |
+
},
|
| 4150 |
+
{
|
| 4151 |
+
"move": "no-op",
|
| 4152 |
+
"view": "turn down"
|
| 4153 |
+
},
|
| 4154 |
+
{
|
| 4155 |
+
"move": "no-op",
|
| 4156 |
+
"view": "turn down"
|
| 4157 |
+
},
|
| 4158 |
+
{
|
| 4159 |
+
"move": "no-op",
|
| 4160 |
+
"view": "turn down"
|
| 4161 |
+
},
|
| 4162 |
+
{
|
| 4163 |
+
"move": "no-op",
|
| 4164 |
+
"view": "turn down"
|
| 4165 |
+
},
|
| 4166 |
+
{
|
| 4167 |
+
"move": "no-op",
|
| 4168 |
+
"view": "turn down"
|
| 4169 |
+
},
|
| 4170 |
+
{
|
| 4171 |
+
"move": "no-op",
|
| 4172 |
+
"view": "turn down"
|
| 4173 |
+
},
|
| 4174 |
+
{
|
| 4175 |
+
"move": "no-op",
|
| 4176 |
+
"view": "turn down"
|
| 4177 |
+
},
|
| 4178 |
+
{
|
| 4179 |
+
"move": "no-op",
|
| 4180 |
+
"view": "turn down"
|
| 4181 |
+
},
|
| 4182 |
+
{
|
| 4183 |
+
"move": "no-op",
|
| 4184 |
+
"view": "turn down"
|
| 4185 |
+
},
|
| 4186 |
+
{
|
| 4187 |
+
"move": "no-op",
|
| 4188 |
+
"view": "turn down"
|
| 4189 |
+
},
|
| 4190 |
+
{
|
| 4191 |
+
"move": "no-op",
|
| 4192 |
+
"view": "turn down"
|
| 4193 |
+
},
|
| 4194 |
+
{
|
| 4195 |
+
"move": "no-op",
|
| 4196 |
+
"view": "turn down"
|
| 4197 |
+
},
|
| 4198 |
+
{
|
| 4199 |
+
"move": "no-op",
|
| 4200 |
+
"view": "turn down"
|
| 4201 |
+
},
|
| 4202 |
+
{
|
| 4203 |
+
"move": "no-op",
|
| 4204 |
+
"view": "turn down"
|
| 4205 |
+
},
|
| 4206 |
+
{
|
| 4207 |
+
"move": "no-op",
|
| 4208 |
+
"view": "turn down"
|
| 4209 |
+
},
|
| 4210 |
+
{
|
| 4211 |
+
"move": "no-op",
|
| 4212 |
+
"view": "turn down"
|
| 4213 |
+
},
|
| 4214 |
+
{
|
| 4215 |
+
"move": "no-op",
|
| 4216 |
+
"view": "turn left"
|
| 4217 |
+
},
|
| 4218 |
+
{
|
| 4219 |
+
"move": "no-op",
|
| 4220 |
+
"view": "turn left"
|
| 4221 |
+
},
|
| 4222 |
+
{
|
| 4223 |
+
"move": "no-op",
|
| 4224 |
+
"view": "turn left"
|
| 4225 |
+
},
|
| 4226 |
+
{
|
| 4227 |
+
"move": "no-op",
|
| 4228 |
+
"view": "turn left"
|
| 4229 |
+
},
|
| 4230 |
+
{
|
| 4231 |
+
"move": "no-op",
|
| 4232 |
+
"view": "turn left"
|
| 4233 |
+
},
|
| 4234 |
+
{
|
| 4235 |
+
"move": "no-op",
|
| 4236 |
+
"view": "turn left"
|
| 4237 |
+
},
|
| 4238 |
+
{
|
| 4239 |
+
"move": "no-op",
|
| 4240 |
+
"view": "turn left"
|
| 4241 |
+
},
|
| 4242 |
+
{
|
| 4243 |
+
"move": "no-op",
|
| 4244 |
+
"view": "turn left"
|
| 4245 |
+
},
|
| 4246 |
+
{
|
| 4247 |
+
"move": "no-op",
|
| 4248 |
+
"view": "turn left"
|
| 4249 |
+
},
|
| 4250 |
+
{
|
| 4251 |
+
"move": "no-op",
|
| 4252 |
+
"view": "turn left"
|
| 4253 |
+
},
|
| 4254 |
+
{
|
| 4255 |
+
"move": "no-op",
|
| 4256 |
+
"view": "turn left"
|
| 4257 |
+
},
|
| 4258 |
+
{
|
| 4259 |
+
"move": "no-op",
|
| 4260 |
+
"view": "turn left"
|
| 4261 |
+
},
|
| 4262 |
+
{
|
| 4263 |
+
"move": "no-op",
|
| 4264 |
+
"view": "turn left"
|
| 4265 |
+
},
|
| 4266 |
+
{
|
| 4267 |
+
"move": "no-op",
|
| 4268 |
+
"view": "turn left"
|
| 4269 |
+
},
|
| 4270 |
+
{
|
| 4271 |
+
"move": "no-op",
|
| 4272 |
+
"view": "turn left"
|
| 4273 |
+
},
|
| 4274 |
+
{
|
| 4275 |
+
"move": "no-op",
|
| 4276 |
+
"view": "turn left"
|
| 4277 |
+
},
|
| 4278 |
+
{
|
| 4279 |
+
"move": "no-op",
|
| 4280 |
+
"view": "turn left"
|
| 4281 |
+
},
|
| 4282 |
+
{
|
| 4283 |
+
"move": "no-op",
|
| 4284 |
+
"view": "turn left"
|
| 4285 |
+
},
|
| 4286 |
+
{
|
| 4287 |
+
"move": "no-op",
|
| 4288 |
+
"view": "turn left"
|
| 4289 |
+
},
|
| 4290 |
+
{
|
| 4291 |
+
"move": "no-op",
|
| 4292 |
+
"view": "turn left"
|
| 4293 |
+
},
|
| 4294 |
+
{
|
| 4295 |
+
"move": "no-op",
|
| 4296 |
+
"view": "turn left"
|
| 4297 |
+
},
|
| 4298 |
+
{
|
| 4299 |
+
"move": "no-op",
|
| 4300 |
+
"view": "turn left"
|
| 4301 |
+
},
|
| 4302 |
+
{
|
| 4303 |
+
"move": "no-op",
|
| 4304 |
+
"view": "turn left"
|
| 4305 |
+
},
|
| 4306 |
+
{
|
| 4307 |
+
"move": "no-op",
|
| 4308 |
+
"view": "turn left"
|
| 4309 |
+
},
|
| 4310 |
+
{
|
| 4311 |
+
"move": "no-op",
|
| 4312 |
+
"view": "turn left"
|
| 4313 |
+
},
|
| 4314 |
+
{
|
| 4315 |
+
"move": "no-op",
|
| 4316 |
+
"view": "turn left"
|
| 4317 |
+
},
|
| 4318 |
+
{
|
| 4319 |
+
"move": "no-op",
|
| 4320 |
+
"view": "turn left"
|
| 4321 |
+
},
|
| 4322 |
+
{
|
| 4323 |
+
"move": "no-op",
|
| 4324 |
+
"view": "turn left"
|
| 4325 |
+
},
|
| 4326 |
+
{
|
| 4327 |
+
"move": "no-op",
|
| 4328 |
+
"view": "turn left"
|
| 4329 |
+
},
|
| 4330 |
+
{
|
| 4331 |
+
"move": "no-op",
|
| 4332 |
+
"view": "turn left"
|
| 4333 |
+
},
|
| 4334 |
+
{
|
| 4335 |
+
"move": "no-op",
|
| 4336 |
+
"view": "turn left"
|
| 4337 |
+
},
|
| 4338 |
+
{
|
| 4339 |
+
"move": "no-op",
|
| 4340 |
+
"view": "turn left"
|
| 4341 |
+
},
|
| 4342 |
+
{
|
| 4343 |
+
"move": "no-op",
|
| 4344 |
+
"view": "turn left"
|
| 4345 |
+
},
|
| 4346 |
+
{
|
| 4347 |
+
"move": "no-op",
|
| 4348 |
+
"view": "turn left"
|
| 4349 |
+
},
|
| 4350 |
+
{
|
| 4351 |
+
"move": "no-op",
|
| 4352 |
+
"view": "turn left"
|
| 4353 |
+
},
|
| 4354 |
+
{
|
| 4355 |
+
"move": "no-op",
|
| 4356 |
+
"view": "turn left"
|
| 4357 |
+
},
|
| 4358 |
+
{
|
| 4359 |
+
"move": "no-op",
|
| 4360 |
+
"view": "turn left"
|
| 4361 |
+
},
|
| 4362 |
+
{
|
| 4363 |
+
"move": "no-op",
|
| 4364 |
+
"view": "turn left"
|
| 4365 |
+
},
|
| 4366 |
+
{
|
| 4367 |
+
"move": "no-op",
|
| 4368 |
+
"view": "turn left"
|
| 4369 |
+
},
|
| 4370 |
+
{
|
| 4371 |
+
"move": "no-op",
|
| 4372 |
+
"view": "turn left"
|
| 4373 |
+
},
|
| 4374 |
+
{
|
| 4375 |
+
"move": "no-op",
|
| 4376 |
+
"view": "turn left"
|
| 4377 |
+
},
|
| 4378 |
+
{
|
| 4379 |
+
"move": "no-op",
|
| 4380 |
+
"view": "turn left"
|
| 4381 |
+
},
|
| 4382 |
+
{
|
| 4383 |
+
"move": "no-op",
|
| 4384 |
+
"view": "turn left"
|
| 4385 |
+
},
|
| 4386 |
+
{
|
| 4387 |
+
"move": "no-op",
|
| 4388 |
+
"view": "turn left"
|
| 4389 |
+
},
|
| 4390 |
+
{
|
| 4391 |
+
"move": "no-op",
|
| 4392 |
+
"view": "turn left"
|
| 4393 |
+
},
|
| 4394 |
+
{
|
| 4395 |
+
"move": "no-op",
|
| 4396 |
+
"view": "turn left"
|
| 4397 |
+
},
|
| 4398 |
+
{
|
| 4399 |
+
"move": "no-op",
|
| 4400 |
+
"view": "turn left"
|
| 4401 |
+
},
|
| 4402 |
+
{
|
| 4403 |
+
"move": "no-op",
|
| 4404 |
+
"view": "turn left"
|
| 4405 |
+
},
|
| 4406 |
+
{
|
| 4407 |
+
"move": "no-op",
|
| 4408 |
+
"view": "turn left"
|
| 4409 |
+
},
|
| 4410 |
+
{
|
| 4411 |
+
"move": "no-op",
|
| 4412 |
+
"view": "turn left"
|
| 4413 |
+
},
|
| 4414 |
+
{
|
| 4415 |
+
"move": "no-op",
|
| 4416 |
+
"view": "turn left"
|
| 4417 |
+
},
|
| 4418 |
+
{
|
| 4419 |
+
"move": "no-op",
|
| 4420 |
+
"view": "turn left"
|
| 4421 |
+
},
|
| 4422 |
+
{
|
| 4423 |
+
"move": "no-op",
|
| 4424 |
+
"view": "turn left"
|
| 4425 |
+
},
|
| 4426 |
+
{
|
| 4427 |
+
"move": "no-op",
|
| 4428 |
+
"view": "turn left"
|
| 4429 |
+
},
|
| 4430 |
+
{
|
| 4431 |
+
"move": "no-op",
|
| 4432 |
+
"view": "turn left"
|
| 4433 |
+
},
|
| 4434 |
+
{
|
| 4435 |
+
"move": "no-op",
|
| 4436 |
+
"view": "turn left"
|
| 4437 |
+
},
|
| 4438 |
+
{
|
| 4439 |
+
"move": "no-op",
|
| 4440 |
+
"view": "turn left"
|
| 4441 |
+
},
|
| 4442 |
+
{
|
| 4443 |
+
"move": "no-op",
|
| 4444 |
+
"view": "turn left"
|
| 4445 |
+
},
|
| 4446 |
+
{
|
| 4447 |
+
"move": "no-op",
|
| 4448 |
+
"view": "turn left"
|
| 4449 |
+
},
|
| 4450 |
+
{
|
| 4451 |
+
"move": "no-op",
|
| 4452 |
+
"view": "turn left"
|
| 4453 |
+
},
|
| 4454 |
+
{
|
| 4455 |
+
"move": "no-op",
|
| 4456 |
+
"view": "turn left"
|
| 4457 |
+
},
|
| 4458 |
+
{
|
| 4459 |
+
"move": "no-op",
|
| 4460 |
+
"view": "turn left"
|
| 4461 |
+
},
|
| 4462 |
+
{
|
| 4463 |
+
"move": "no-op",
|
| 4464 |
+
"view": "turn left"
|
| 4465 |
+
},
|
| 4466 |
+
{
|
| 4467 |
+
"move": "no-op",
|
| 4468 |
+
"view": "turn left"
|
| 4469 |
+
},
|
| 4470 |
+
{
|
| 4471 |
+
"move": "no-op",
|
| 4472 |
+
"view": "turn left"
|
| 4473 |
+
},
|
| 4474 |
+
{
|
| 4475 |
+
"move": "no-op",
|
| 4476 |
+
"view": "turn left"
|
| 4477 |
+
},
|
| 4478 |
+
{
|
| 4479 |
+
"move": "no-op",
|
| 4480 |
+
"view": "turn left"
|
| 4481 |
+
},
|
| 4482 |
+
{
|
| 4483 |
+
"move": "no-op",
|
| 4484 |
+
"view": "turn left"
|
| 4485 |
+
},
|
| 4486 |
+
{
|
| 4487 |
+
"move": "no-op",
|
| 4488 |
+
"view": "turn left"
|
| 4489 |
+
},
|
| 4490 |
+
{
|
| 4491 |
+
"move": "no-op",
|
| 4492 |
+
"view": "turn left"
|
| 4493 |
+
},
|
| 4494 |
+
{
|
| 4495 |
+
"move": "no-op",
|
| 4496 |
+
"view": "turn left"
|
| 4497 |
+
},
|
| 4498 |
+
{
|
| 4499 |
+
"move": "no-op",
|
| 4500 |
+
"view": "turn left"
|
| 4501 |
+
},
|
| 4502 |
+
{
|
| 4503 |
+
"move": "no-op",
|
| 4504 |
+
"view": "turn left"
|
| 4505 |
+
},
|
| 4506 |
+
{
|
| 4507 |
+
"move": "no-op",
|
| 4508 |
+
"view": "turn left"
|
| 4509 |
+
},
|
| 4510 |
+
{
|
| 4511 |
+
"move": "no-op",
|
| 4512 |
+
"view": "turn left"
|
| 4513 |
+
},
|
| 4514 |
+
{
|
| 4515 |
+
"move": "no-op",
|
| 4516 |
+
"view": "turn left"
|
| 4517 |
+
},
|
| 4518 |
+
{
|
| 4519 |
+
"move": "no-op",
|
| 4520 |
+
"view": "turn left"
|
| 4521 |
+
},
|
| 4522 |
+
{
|
| 4523 |
+
"move": "no-op",
|
| 4524 |
+
"view": "turn left"
|
| 4525 |
+
},
|
| 4526 |
+
{
|
| 4527 |
+
"move": "no-op",
|
| 4528 |
+
"view": "turn left"
|
| 4529 |
+
},
|
| 4530 |
+
{
|
| 4531 |
+
"move": "no-op",
|
| 4532 |
+
"view": "turn left"
|
| 4533 |
+
},
|
| 4534 |
+
{
|
| 4535 |
+
"move": "no-op",
|
| 4536 |
+
"view": "turn left"
|
| 4537 |
+
},
|
| 4538 |
+
{
|
| 4539 |
+
"move": "go forward",
|
| 4540 |
+
"view": "no-op"
|
| 4541 |
+
},
|
| 4542 |
+
{
|
| 4543 |
+
"move": "go forward",
|
| 4544 |
+
"view": "no-op"
|
| 4545 |
+
},
|
| 4546 |
+
{
|
| 4547 |
+
"move": "go forward",
|
| 4548 |
+
"view": "no-op"
|
| 4549 |
+
},
|
| 4550 |
+
{
|
| 4551 |
+
"move": "go forward",
|
| 4552 |
+
"view": "no-op"
|
| 4553 |
+
},
|
| 4554 |
+
{
|
| 4555 |
+
"move": "go forward",
|
| 4556 |
+
"view": "no-op"
|
| 4557 |
+
},
|
| 4558 |
+
{
|
| 4559 |
+
"move": "go forward",
|
| 4560 |
+
"view": "no-op"
|
| 4561 |
+
},
|
| 4562 |
+
{
|
| 4563 |
+
"move": "go forward",
|
| 4564 |
+
"view": "no-op"
|
| 4565 |
+
},
|
| 4566 |
+
{
|
| 4567 |
+
"move": "go forward",
|
| 4568 |
+
"view": "no-op"
|
| 4569 |
+
},
|
| 4570 |
+
{
|
| 4571 |
+
"move": "go forward",
|
| 4572 |
+
"view": "no-op"
|
| 4573 |
+
},
|
| 4574 |
+
{
|
| 4575 |
+
"move": "go forward",
|
| 4576 |
+
"view": "no-op"
|
| 4577 |
+
},
|
| 4578 |
+
{
|
| 4579 |
+
"move": "go forward",
|
| 4580 |
+
"view": "no-op"
|
| 4581 |
+
},
|
| 4582 |
+
{
|
| 4583 |
+
"move": "go forward",
|
| 4584 |
+
"view": "no-op"
|
| 4585 |
+
},
|
| 4586 |
+
{
|
| 4587 |
+
"move": "go forward",
|
| 4588 |
+
"view": "no-op"
|
| 4589 |
+
},
|
| 4590 |
+
{
|
| 4591 |
+
"move": "go forward",
|
| 4592 |
+
"view": "no-op"
|
| 4593 |
+
},
|
| 4594 |
+
{
|
| 4595 |
+
"move": "go forward",
|
| 4596 |
+
"view": "no-op"
|
| 4597 |
+
},
|
| 4598 |
+
{
|
| 4599 |
+
"move": "go forward",
|
| 4600 |
+
"view": "no-op"
|
| 4601 |
+
},
|
| 4602 |
+
{
|
| 4603 |
+
"move": "go forward",
|
| 4604 |
+
"view": "no-op"
|
| 4605 |
+
},
|
| 4606 |
+
{
|
| 4607 |
+
"move": "go forward",
|
| 4608 |
+
"view": "no-op"
|
| 4609 |
+
},
|
| 4610 |
+
{
|
| 4611 |
+
"move": "go forward",
|
| 4612 |
+
"view": "no-op"
|
| 4613 |
+
},
|
| 4614 |
+
{
|
| 4615 |
+
"move": "go forward",
|
| 4616 |
+
"view": "no-op"
|
| 4617 |
+
},
|
| 4618 |
+
{
|
| 4619 |
+
"move": "go forward",
|
| 4620 |
+
"view": "no-op"
|
| 4621 |
+
},
|
| 4622 |
+
{
|
| 4623 |
+
"move": "go forward",
|
| 4624 |
+
"view": "no-op"
|
| 4625 |
+
},
|
| 4626 |
+
{
|
| 4627 |
+
"move": "go forward",
|
| 4628 |
+
"view": "no-op"
|
| 4629 |
+
},
|
| 4630 |
+
{
|
| 4631 |
+
"move": "go forward",
|
| 4632 |
+
"view": "no-op"
|
| 4633 |
+
},
|
| 4634 |
+
{
|
| 4635 |
+
"move": "go forward",
|
| 4636 |
+
"view": "no-op"
|
| 4637 |
+
},
|
| 4638 |
+
{
|
| 4639 |
+
"move": "go forward",
|
| 4640 |
+
"view": "no-op"
|
| 4641 |
+
},
|
| 4642 |
+
{
|
| 4643 |
+
"move": "go forward",
|
| 4644 |
+
"view": "no-op"
|
| 4645 |
+
},
|
| 4646 |
+
{
|
| 4647 |
+
"move": "go forward",
|
| 4648 |
+
"view": "no-op"
|
| 4649 |
+
},
|
| 4650 |
+
{
|
| 4651 |
+
"move": "go forward",
|
| 4652 |
+
"view": "no-op"
|
| 4653 |
+
},
|
| 4654 |
+
{
|
| 4655 |
+
"move": "go forward",
|
| 4656 |
+
"view": "no-op"
|
| 4657 |
+
},
|
| 4658 |
+
{
|
| 4659 |
+
"move": "go forward",
|
| 4660 |
+
"view": "no-op"
|
| 4661 |
+
},
|
| 4662 |
+
{
|
| 4663 |
+
"move": "go forward",
|
| 4664 |
+
"view": "no-op"
|
| 4665 |
+
},
|
| 4666 |
+
{
|
| 4667 |
+
"move": "go forward",
|
| 4668 |
+
"view": "no-op"
|
| 4669 |
+
},
|
| 4670 |
+
{
|
| 4671 |
+
"move": "go forward",
|
| 4672 |
+
"view": "no-op"
|
| 4673 |
+
},
|
| 4674 |
+
{
|
| 4675 |
+
"move": "go forward",
|
| 4676 |
+
"view": "no-op"
|
| 4677 |
+
},
|
| 4678 |
+
{
|
| 4679 |
+
"move": "go forward",
|
| 4680 |
+
"view": "no-op"
|
| 4681 |
+
},
|
| 4682 |
+
{
|
| 4683 |
+
"move": "go forward",
|
| 4684 |
+
"view": "no-op"
|
| 4685 |
+
},
|
| 4686 |
+
{
|
| 4687 |
+
"move": "go forward",
|
| 4688 |
+
"view": "no-op"
|
| 4689 |
+
},
|
| 4690 |
+
{
|
| 4691 |
+
"move": "go forward",
|
| 4692 |
+
"view": "no-op"
|
| 4693 |
+
},
|
| 4694 |
+
{
|
| 4695 |
+
"move": "go forward",
|
| 4696 |
+
"view": "no-op"
|
| 4697 |
+
},
|
| 4698 |
+
{
|
| 4699 |
+
"move": "go forward",
|
| 4700 |
+
"view": "no-op"
|
| 4701 |
+
},
|
| 4702 |
+
{
|
| 4703 |
+
"move": "go forward",
|
| 4704 |
+
"view": "no-op"
|
| 4705 |
+
},
|
| 4706 |
+
{
|
| 4707 |
+
"move": "go forward",
|
| 4708 |
+
"view": "no-op"
|
| 4709 |
+
},
|
| 4710 |
+
{
|
| 4711 |
+
"move": "go forward",
|
| 4712 |
+
"view": "no-op"
|
| 4713 |
+
},
|
| 4714 |
+
{
|
| 4715 |
+
"move": "go forward",
|
| 4716 |
+
"view": "no-op"
|
| 4717 |
+
},
|
| 4718 |
+
{
|
| 4719 |
+
"move": "go forward",
|
| 4720 |
+
"view": "no-op"
|
| 4721 |
+
},
|
| 4722 |
+
{
|
| 4723 |
+
"move": "go forward",
|
| 4724 |
+
"view": "no-op"
|
| 4725 |
+
},
|
| 4726 |
+
{
|
| 4727 |
+
"move": "go forward",
|
| 4728 |
+
"view": "no-op"
|
| 4729 |
+
},
|
| 4730 |
+
{
|
| 4731 |
+
"move": "go forward",
|
| 4732 |
+
"view": "no-op"
|
| 4733 |
+
},
|
| 4734 |
+
{
|
| 4735 |
+
"move": "go forward",
|
| 4736 |
+
"view": "no-op"
|
| 4737 |
+
},
|
| 4738 |
+
{
|
| 4739 |
+
"move": "go forward",
|
| 4740 |
+
"view": "no-op"
|
| 4741 |
+
},
|
| 4742 |
+
{
|
| 4743 |
+
"move": "go forward",
|
| 4744 |
+
"view": "no-op"
|
| 4745 |
+
},
|
| 4746 |
+
{
|
| 4747 |
+
"move": "go forward",
|
| 4748 |
+
"view": "no-op"
|
| 4749 |
+
},
|
| 4750 |
+
{
|
| 4751 |
+
"move": "go forward",
|
| 4752 |
+
"view": "no-op"
|
| 4753 |
+
},
|
| 4754 |
+
{
|
| 4755 |
+
"move": "go forward",
|
| 4756 |
+
"view": "no-op"
|
| 4757 |
+
},
|
| 4758 |
+
{
|
| 4759 |
+
"move": "go forward",
|
| 4760 |
+
"view": "no-op"
|
| 4761 |
+
},
|
| 4762 |
+
{
|
| 4763 |
+
"move": "go forward",
|
| 4764 |
+
"view": "no-op"
|
| 4765 |
+
},
|
| 4766 |
+
{
|
| 4767 |
+
"move": "go forward",
|
| 4768 |
+
"view": "no-op"
|
| 4769 |
+
},
|
| 4770 |
+
{
|
| 4771 |
+
"move": "go forward",
|
| 4772 |
+
"view": "no-op"
|
| 4773 |
+
},
|
| 4774 |
+
{
|
| 4775 |
+
"move": "go forward",
|
| 4776 |
+
"view": "no-op"
|
| 4777 |
+
},
|
| 4778 |
+
{
|
| 4779 |
+
"move": "go forward",
|
| 4780 |
+
"view": "no-op"
|
| 4781 |
+
},
|
| 4782 |
+
{
|
| 4783 |
+
"move": "go forward",
|
| 4784 |
+
"view": "no-op"
|
| 4785 |
+
},
|
| 4786 |
+
{
|
| 4787 |
+
"move": "go forward",
|
| 4788 |
+
"view": "no-op"
|
| 4789 |
+
},
|
| 4790 |
+
{
|
| 4791 |
+
"move": "go forward",
|
| 4792 |
+
"view": "no-op"
|
| 4793 |
+
},
|
| 4794 |
+
{
|
| 4795 |
+
"move": "go forward",
|
| 4796 |
+
"view": "no-op"
|
| 4797 |
+
},
|
| 4798 |
+
{
|
| 4799 |
+
"move": "go forward",
|
| 4800 |
+
"view": "no-op"
|
| 4801 |
+
},
|
| 4802 |
+
{
|
| 4803 |
+
"move": "go forward",
|
| 4804 |
+
"view": "no-op"
|
| 4805 |
+
},
|
| 4806 |
+
{
|
| 4807 |
+
"move": "go forward",
|
| 4808 |
+
"view": "no-op"
|
| 4809 |
+
},
|
| 4810 |
+
{
|
| 4811 |
+
"move": "go forward",
|
| 4812 |
+
"view": "no-op"
|
| 4813 |
+
},
|
| 4814 |
+
{
|
| 4815 |
+
"move": "go forward",
|
| 4816 |
+
"view": "no-op"
|
| 4817 |
+
},
|
| 4818 |
+
{
|
| 4819 |
+
"move": "go forward",
|
| 4820 |
+
"view": "no-op"
|
| 4821 |
+
},
|
| 4822 |
+
{
|
| 4823 |
+
"move": "go forward",
|
| 4824 |
+
"view": "no-op"
|
| 4825 |
+
},
|
| 4826 |
+
{
|
| 4827 |
+
"move": "go forward",
|
| 4828 |
+
"view": "no-op"
|
| 4829 |
+
},
|
| 4830 |
+
{
|
| 4831 |
+
"move": "go forward",
|
| 4832 |
+
"view": "no-op"
|
| 4833 |
+
},
|
| 4834 |
+
{
|
| 4835 |
+
"move": "go forward",
|
| 4836 |
+
"view": "no-op"
|
| 4837 |
+
},
|
| 4838 |
+
{
|
| 4839 |
+
"move": "go forward",
|
| 4840 |
+
"view": "no-op"
|
| 4841 |
+
},
|
| 4842 |
+
{
|
| 4843 |
+
"move": "go forward",
|
| 4844 |
+
"view": "no-op"
|
| 4845 |
+
},
|
| 4846 |
+
{
|
| 4847 |
+
"move": "go forward",
|
| 4848 |
+
"view": "no-op"
|
| 4849 |
+
},
|
| 4850 |
+
{
|
| 4851 |
+
"move": "go forward",
|
| 4852 |
+
"view": "no-op"
|
| 4853 |
+
},
|
| 4854 |
+
{
|
| 4855 |
+
"move": "go forward",
|
| 4856 |
+
"view": "no-op"
|
| 4857 |
+
},
|
| 4858 |
+
{
|
| 4859 |
+
"move": "go forward",
|
| 4860 |
+
"view": "no-op"
|
| 4861 |
+
},
|
| 4862 |
+
{
|
| 4863 |
+
"move": "go forward",
|
| 4864 |
+
"view": "no-op"
|
| 4865 |
+
},
|
| 4866 |
+
{
|
| 4867 |
+
"move": "go forward",
|
| 4868 |
+
"view": "no-op"
|
| 4869 |
+
},
|
| 4870 |
+
{
|
| 4871 |
+
"move": "go forward",
|
| 4872 |
+
"view": "no-op"
|
| 4873 |
+
},
|
| 4874 |
+
{
|
| 4875 |
+
"move": "go forward",
|
| 4876 |
+
"view": "no-op"
|
| 4877 |
+
},
|
| 4878 |
+
{
|
| 4879 |
+
"move": "go forward",
|
| 4880 |
+
"view": "no-op"
|
| 4881 |
+
},
|
| 4882 |
+
{
|
| 4883 |
+
"move": "go forward",
|
| 4884 |
+
"view": "no-op"
|
| 4885 |
+
},
|
| 4886 |
+
{
|
| 4887 |
+
"move": "go forward",
|
| 4888 |
+
"view": "no-op"
|
| 4889 |
+
},
|
| 4890 |
+
{
|
| 4891 |
+
"move": "go forward",
|
| 4892 |
+
"view": "no-op"
|
| 4893 |
+
},
|
| 4894 |
+
{
|
| 4895 |
+
"move": "go forward",
|
| 4896 |
+
"view": "no-op"
|
| 4897 |
+
},
|
| 4898 |
+
{
|
| 4899 |
+
"move": "go forward",
|
| 4900 |
+
"view": "no-op"
|
| 4901 |
+
},
|
| 4902 |
+
{
|
| 4903 |
+
"move": "go forward",
|
| 4904 |
+
"view": "no-op"
|
| 4905 |
+
},
|
| 4906 |
+
{
|
| 4907 |
+
"move": "go forward",
|
| 4908 |
+
"view": "no-op"
|
| 4909 |
+
},
|
| 4910 |
+
{
|
| 4911 |
+
"move": "go forward",
|
| 4912 |
+
"view": "no-op"
|
| 4913 |
+
},
|
| 4914 |
+
{
|
| 4915 |
+
"move": "go forward",
|
| 4916 |
+
"view": "no-op"
|
| 4917 |
+
},
|
| 4918 |
+
{
|
| 4919 |
+
"move": "go forward",
|
| 4920 |
+
"view": "no-op"
|
| 4921 |
+
},
|
| 4922 |
+
{
|
| 4923 |
+
"move": "go forward",
|
| 4924 |
+
"view": "no-op"
|
| 4925 |
+
},
|
| 4926 |
+
{
|
| 4927 |
+
"move": "go forward",
|
| 4928 |
+
"view": "no-op"
|
| 4929 |
+
},
|
| 4930 |
+
{
|
| 4931 |
+
"move": "go forward",
|
| 4932 |
+
"view": "no-op"
|
| 4933 |
+
},
|
| 4934 |
+
{
|
| 4935 |
+
"move": "go forward",
|
| 4936 |
+
"view": "no-op"
|
| 4937 |
+
},
|
| 4938 |
+
{
|
| 4939 |
+
"move": "go forward",
|
| 4940 |
+
"view": "no-op"
|
| 4941 |
+
},
|
| 4942 |
+
{
|
| 4943 |
+
"move": "go forward",
|
| 4944 |
+
"view": "no-op"
|
| 4945 |
+
},
|
| 4946 |
+
{
|
| 4947 |
+
"move": "go forward",
|
| 4948 |
+
"view": "no-op"
|
| 4949 |
+
},
|
| 4950 |
+
{
|
| 4951 |
+
"move": "go forward",
|
| 4952 |
+
"view": "no-op"
|
| 4953 |
+
},
|
| 4954 |
+
{
|
| 4955 |
+
"move": "go forward",
|
| 4956 |
+
"view": "no-op"
|
| 4957 |
+
},
|
| 4958 |
+
{
|
| 4959 |
+
"move": "go forward",
|
| 4960 |
+
"view": "no-op"
|
| 4961 |
+
},
|
| 4962 |
+
{
|
| 4963 |
+
"move": "go forward",
|
| 4964 |
+
"view": "no-op"
|
| 4965 |
+
},
|
| 4966 |
+
{
|
| 4967 |
+
"move": "go forward",
|
| 4968 |
+
"view": "no-op"
|
| 4969 |
+
},
|
| 4970 |
+
{
|
| 4971 |
+
"move": "go forward",
|
| 4972 |
+
"view": "no-op"
|
| 4973 |
+
},
|
| 4974 |
+
{
|
| 4975 |
+
"move": "go forward",
|
| 4976 |
+
"view": "no-op"
|
| 4977 |
+
},
|
| 4978 |
+
{
|
| 4979 |
+
"move": "go forward",
|
| 4980 |
+
"view": "no-op"
|
| 4981 |
+
},
|
| 4982 |
+
{
|
| 4983 |
+
"move": "go forward",
|
| 4984 |
+
"view": "no-op"
|
| 4985 |
+
},
|
| 4986 |
+
{
|
| 4987 |
+
"move": "go forward",
|
| 4988 |
+
"view": "no-op"
|
| 4989 |
+
},
|
| 4990 |
+
{
|
| 4991 |
+
"move": "go forward",
|
| 4992 |
+
"view": "no-op"
|
| 4993 |
+
},
|
| 4994 |
+
{
|
| 4995 |
+
"move": "go forward",
|
| 4996 |
+
"view": "no-op"
|
| 4997 |
+
},
|
| 4998 |
+
{
|
| 4999 |
+
"move": "go forward",
|
| 5000 |
+
"view": "no-op"
|
| 5001 |
+
},
|
| 5002 |
+
{
|
| 5003 |
+
"move": "go forward",
|
| 5004 |
+
"view": "no-op"
|
| 5005 |
+
},
|
| 5006 |
+
{
|
| 5007 |
+
"move": "go forward",
|
| 5008 |
+
"view": "no-op"
|
| 5009 |
+
},
|
| 5010 |
+
{
|
| 5011 |
+
"move": "go forward",
|
| 5012 |
+
"view": "no-op"
|
| 5013 |
+
},
|
| 5014 |
+
{
|
| 5015 |
+
"move": "go forward",
|
| 5016 |
+
"view": "no-op"
|
| 5017 |
+
},
|
| 5018 |
+
{
|
| 5019 |
+
"move": "go forward",
|
| 5020 |
+
"view": "no-op"
|
| 5021 |
+
},
|
| 5022 |
+
{
|
| 5023 |
+
"move": "go forward",
|
| 5024 |
+
"view": "no-op"
|
| 5025 |
+
},
|
| 5026 |
+
{
|
| 5027 |
+
"move": "go forward",
|
| 5028 |
+
"view": "no-op"
|
| 5029 |
+
},
|
| 5030 |
+
{
|
| 5031 |
+
"move": "go forward",
|
| 5032 |
+
"view": "no-op"
|
| 5033 |
+
},
|
| 5034 |
+
{
|
| 5035 |
+
"move": "go forward",
|
| 5036 |
+
"view": "no-op"
|
| 5037 |
+
},
|
| 5038 |
+
{
|
| 5039 |
+
"move": "go forward",
|
| 5040 |
+
"view": "no-op"
|
| 5041 |
+
},
|
| 5042 |
+
{
|
| 5043 |
+
"move": "go forward",
|
| 5044 |
+
"view": "no-op"
|
| 5045 |
+
},
|
| 5046 |
+
{
|
| 5047 |
+
"move": "go forward",
|
| 5048 |
+
"view": "no-op"
|
| 5049 |
+
},
|
| 5050 |
+
{
|
| 5051 |
+
"move": "go forward",
|
| 5052 |
+
"view": "no-op"
|
| 5053 |
+
},
|
| 5054 |
+
{
|
| 5055 |
+
"move": "go forward",
|
| 5056 |
+
"view": "no-op"
|
| 5057 |
+
},
|
| 5058 |
+
{
|
| 5059 |
+
"move": "go forward",
|
| 5060 |
+
"view": "no-op"
|
| 5061 |
+
},
|
| 5062 |
+
{
|
| 5063 |
+
"move": "go forward",
|
| 5064 |
+
"view": "no-op"
|
| 5065 |
+
},
|
| 5066 |
+
{
|
| 5067 |
+
"move": "go forward",
|
| 5068 |
+
"view": "no-op"
|
| 5069 |
+
},
|
| 5070 |
+
{
|
| 5071 |
+
"move": "go forward",
|
| 5072 |
+
"view": "no-op"
|
| 5073 |
+
},
|
| 5074 |
+
{
|
| 5075 |
+
"move": "go forward",
|
| 5076 |
+
"view": "no-op"
|
| 5077 |
+
},
|
| 5078 |
+
{
|
| 5079 |
+
"move": "go forward",
|
| 5080 |
+
"view": "no-op"
|
| 5081 |
+
},
|
| 5082 |
+
{
|
| 5083 |
+
"move": "go forward",
|
| 5084 |
+
"view": "no-op"
|
| 5085 |
+
},
|
| 5086 |
+
{
|
| 5087 |
+
"move": "go forward",
|
| 5088 |
+
"view": "no-op"
|
| 5089 |
+
},
|
| 5090 |
+
{
|
| 5091 |
+
"move": "go forward",
|
| 5092 |
+
"view": "no-op"
|
| 5093 |
+
},
|
| 5094 |
+
{
|
| 5095 |
+
"move": "go forward",
|
| 5096 |
+
"view": "no-op"
|
| 5097 |
+
},
|
| 5098 |
+
{
|
| 5099 |
+
"move": "go forward",
|
| 5100 |
+
"view": "no-op"
|
| 5101 |
+
},
|
| 5102 |
+
{
|
| 5103 |
+
"move": "go forward",
|
| 5104 |
+
"view": "no-op"
|
| 5105 |
+
},
|
| 5106 |
+
{
|
| 5107 |
+
"move": "go forward",
|
| 5108 |
+
"view": "no-op"
|
| 5109 |
+
},
|
| 5110 |
+
{
|
| 5111 |
+
"move": "go forward",
|
| 5112 |
+
"view": "no-op"
|
| 5113 |
+
},
|
| 5114 |
+
{
|
| 5115 |
+
"move": "go forward",
|
| 5116 |
+
"view": "no-op"
|
| 5117 |
+
},
|
| 5118 |
+
{
|
| 5119 |
+
"move": "go forward",
|
| 5120 |
+
"view": "no-op"
|
| 5121 |
+
},
|
| 5122 |
+
{
|
| 5123 |
+
"move": "go forward",
|
| 5124 |
+
"view": "no-op"
|
| 5125 |
+
},
|
| 5126 |
+
{
|
| 5127 |
+
"move": "go forward",
|
| 5128 |
+
"view": "no-op"
|
| 5129 |
+
},
|
| 5130 |
+
{
|
| 5131 |
+
"move": "go forward",
|
| 5132 |
+
"view": "no-op"
|
| 5133 |
+
},
|
| 5134 |
+
{
|
| 5135 |
+
"move": "go forward",
|
| 5136 |
+
"view": "no-op"
|
| 5137 |
+
},
|
| 5138 |
+
{
|
| 5139 |
+
"move": "go forward",
|
| 5140 |
+
"view": "no-op"
|
| 5141 |
+
},
|
| 5142 |
+
{
|
| 5143 |
+
"move": "go forward",
|
| 5144 |
+
"view": "no-op"
|
| 5145 |
+
},
|
| 5146 |
+
{
|
| 5147 |
+
"move": "go forward",
|
| 5148 |
+
"view": "no-op"
|
| 5149 |
+
},
|
| 5150 |
+
{
|
| 5151 |
+
"move": "go forward",
|
| 5152 |
+
"view": "no-op"
|
| 5153 |
+
},
|
| 5154 |
+
{
|
| 5155 |
+
"move": "go forward",
|
| 5156 |
+
"view": "no-op"
|
| 5157 |
+
},
|
| 5158 |
+
{
|
| 5159 |
+
"move": "go forward",
|
| 5160 |
+
"view": "no-op"
|
| 5161 |
+
},
|
| 5162 |
+
{
|
| 5163 |
+
"move": "go forward",
|
| 5164 |
+
"view": "no-op"
|
| 5165 |
+
},
|
| 5166 |
+
{
|
| 5167 |
+
"move": "go forward",
|
| 5168 |
+
"view": "no-op"
|
| 5169 |
+
},
|
| 5170 |
+
{
|
| 5171 |
+
"move": "go forward",
|
| 5172 |
+
"view": "no-op"
|
| 5173 |
+
},
|
| 5174 |
+
{
|
| 5175 |
+
"move": "go forward",
|
| 5176 |
+
"view": "no-op"
|
| 5177 |
+
},
|
| 5178 |
+
{
|
| 5179 |
+
"move": "go forward",
|
| 5180 |
+
"view": "no-op"
|
| 5181 |
+
},
|
| 5182 |
+
{
|
| 5183 |
+
"move": "go forward",
|
| 5184 |
+
"view": "no-op"
|
| 5185 |
+
},
|
| 5186 |
+
{
|
| 5187 |
+
"move": "no-op",
|
| 5188 |
+
"view": "turn left"
|
| 5189 |
+
},
|
| 5190 |
+
{
|
| 5191 |
+
"move": "no-op",
|
| 5192 |
+
"view": "turn left"
|
| 5193 |
+
},
|
| 5194 |
+
{
|
| 5195 |
+
"move": "no-op",
|
| 5196 |
+
"view": "turn left"
|
| 5197 |
+
},
|
| 5198 |
+
{
|
| 5199 |
+
"move": "no-op",
|
| 5200 |
+
"view": "turn left"
|
| 5201 |
+
},
|
| 5202 |
+
{
|
| 5203 |
+
"move": "no-op",
|
| 5204 |
+
"view": "turn left"
|
| 5205 |
+
},
|
| 5206 |
+
{
|
| 5207 |
+
"move": "no-op",
|
| 5208 |
+
"view": "turn left"
|
| 5209 |
+
},
|
| 5210 |
+
{
|
| 5211 |
+
"move": "no-op",
|
| 5212 |
+
"view": "turn left"
|
| 5213 |
+
},
|
| 5214 |
+
{
|
| 5215 |
+
"move": "no-op",
|
| 5216 |
+
"view": "turn left"
|
| 5217 |
+
},
|
| 5218 |
+
{
|
| 5219 |
+
"move": "no-op",
|
| 5220 |
+
"view": "turn left"
|
| 5221 |
+
},
|
| 5222 |
+
{
|
| 5223 |
+
"move": "no-op",
|
| 5224 |
+
"view": "turn left"
|
| 5225 |
+
},
|
| 5226 |
+
{
|
| 5227 |
+
"move": "no-op",
|
| 5228 |
+
"view": "turn left"
|
| 5229 |
+
},
|
| 5230 |
+
{
|
| 5231 |
+
"move": "no-op",
|
| 5232 |
+
"view": "turn left"
|
| 5233 |
+
},
|
| 5234 |
+
{
|
| 5235 |
+
"move": "no-op",
|
| 5236 |
+
"view": "turn left"
|
| 5237 |
+
},
|
| 5238 |
+
{
|
| 5239 |
+
"move": "no-op",
|
| 5240 |
+
"view": "turn left"
|
| 5241 |
+
},
|
| 5242 |
+
{
|
| 5243 |
+
"move": "no-op",
|
| 5244 |
+
"view": "turn left"
|
| 5245 |
+
},
|
| 5246 |
+
{
|
| 5247 |
+
"move": "no-op",
|
| 5248 |
+
"view": "turn left"
|
| 5249 |
+
},
|
| 5250 |
+
{
|
| 5251 |
+
"move": "no-op",
|
| 5252 |
+
"view": "turn left"
|
| 5253 |
+
},
|
| 5254 |
+
{
|
| 5255 |
+
"move": "no-op",
|
| 5256 |
+
"view": "turn left"
|
| 5257 |
+
},
|
| 5258 |
+
{
|
| 5259 |
+
"move": "no-op",
|
| 5260 |
+
"view": "turn left"
|
| 5261 |
+
},
|
| 5262 |
+
{
|
| 5263 |
+
"move": "no-op",
|
| 5264 |
+
"view": "turn left"
|
| 5265 |
+
},
|
| 5266 |
+
{
|
| 5267 |
+
"move": "no-op",
|
| 5268 |
+
"view": "turn left"
|
| 5269 |
+
},
|
| 5270 |
+
{
|
| 5271 |
+
"move": "no-op",
|
| 5272 |
+
"view": "turn left"
|
| 5273 |
+
},
|
| 5274 |
+
{
|
| 5275 |
+
"move": "no-op",
|
| 5276 |
+
"view": "turn left"
|
| 5277 |
+
},
|
| 5278 |
+
{
|
| 5279 |
+
"move": "no-op",
|
| 5280 |
+
"view": "turn left"
|
| 5281 |
+
},
|
| 5282 |
+
{
|
| 5283 |
+
"move": "no-op",
|
| 5284 |
+
"view": "turn left"
|
| 5285 |
+
},
|
| 5286 |
+
{
|
| 5287 |
+
"move": "no-op",
|
| 5288 |
+
"view": "turn left"
|
| 5289 |
+
},
|
| 5290 |
+
{
|
| 5291 |
+
"move": "no-op",
|
| 5292 |
+
"view": "turn left"
|
| 5293 |
+
},
|
| 5294 |
+
{
|
| 5295 |
+
"move": "no-op",
|
| 5296 |
+
"view": "turn left"
|
| 5297 |
+
},
|
| 5298 |
+
{
|
| 5299 |
+
"move": "no-op",
|
| 5300 |
+
"view": "turn left"
|
| 5301 |
+
},
|
| 5302 |
+
{
|
| 5303 |
+
"move": "no-op",
|
| 5304 |
+
"view": "turn left"
|
| 5305 |
+
},
|
| 5306 |
+
{
|
| 5307 |
+
"move": "no-op",
|
| 5308 |
+
"view": "turn left"
|
| 5309 |
+
},
|
| 5310 |
+
{
|
| 5311 |
+
"move": "no-op",
|
| 5312 |
+
"view": "turn left"
|
| 5313 |
+
},
|
| 5314 |
+
{
|
| 5315 |
+
"move": "no-op",
|
| 5316 |
+
"view": "turn left"
|
| 5317 |
+
},
|
| 5318 |
+
{
|
| 5319 |
+
"move": "no-op",
|
| 5320 |
+
"view": "turn left"
|
| 5321 |
+
},
|
| 5322 |
+
{
|
| 5323 |
+
"move": "no-op",
|
| 5324 |
+
"view": "turn left"
|
| 5325 |
+
},
|
| 5326 |
+
{
|
| 5327 |
+
"move": "no-op",
|
| 5328 |
+
"view": "turn left"
|
| 5329 |
+
},
|
| 5330 |
+
{
|
| 5331 |
+
"move": "no-op",
|
| 5332 |
+
"view": "turn left"
|
| 5333 |
+
},
|
| 5334 |
+
{
|
| 5335 |
+
"move": "no-op",
|
| 5336 |
+
"view": "turn left"
|
| 5337 |
+
},
|
| 5338 |
+
{
|
| 5339 |
+
"move": "no-op",
|
| 5340 |
+
"view": "turn left"
|
| 5341 |
+
},
|
| 5342 |
+
{
|
| 5343 |
+
"move": "no-op",
|
| 5344 |
+
"view": "turn left"
|
| 5345 |
+
},
|
| 5346 |
+
{
|
| 5347 |
+
"move": "no-op",
|
| 5348 |
+
"view": "turn left"
|
| 5349 |
+
},
|
| 5350 |
+
{
|
| 5351 |
+
"move": "no-op",
|
| 5352 |
+
"view": "turn left"
|
| 5353 |
+
},
|
| 5354 |
+
{
|
| 5355 |
+
"move": "no-op",
|
| 5356 |
+
"view": "turn left"
|
| 5357 |
+
},
|
| 5358 |
+
{
|
| 5359 |
+
"move": "no-op",
|
| 5360 |
+
"view": "turn left"
|
| 5361 |
+
},
|
| 5362 |
+
{
|
| 5363 |
+
"move": "no-op",
|
| 5364 |
+
"view": "turn left"
|
| 5365 |
+
},
|
| 5366 |
+
{
|
| 5367 |
+
"move": "no-op",
|
| 5368 |
+
"view": "turn left"
|
| 5369 |
+
},
|
| 5370 |
+
{
|
| 5371 |
+
"move": "no-op",
|
| 5372 |
+
"view": "turn left"
|
| 5373 |
+
},
|
| 5374 |
+
{
|
| 5375 |
+
"move": "no-op",
|
| 5376 |
+
"view": "turn left"
|
| 5377 |
+
},
|
| 5378 |
+
{
|
| 5379 |
+
"move": "no-op",
|
| 5380 |
+
"view": "turn left"
|
| 5381 |
+
},
|
| 5382 |
+
{
|
| 5383 |
+
"move": "no-op",
|
| 5384 |
+
"view": "turn left"
|
| 5385 |
+
},
|
| 5386 |
+
{
|
| 5387 |
+
"move": "no-op",
|
| 5388 |
+
"view": "turn left"
|
| 5389 |
+
},
|
| 5390 |
+
{
|
| 5391 |
+
"move": "no-op",
|
| 5392 |
+
"view": "turn left"
|
| 5393 |
+
},
|
| 5394 |
+
{
|
| 5395 |
+
"move": "no-op",
|
| 5396 |
+
"view": "turn left"
|
| 5397 |
+
},
|
| 5398 |
+
{
|
| 5399 |
+
"move": "no-op",
|
| 5400 |
+
"view": "turn left"
|
| 5401 |
+
},
|
| 5402 |
+
{
|
| 5403 |
+
"move": "no-op",
|
| 5404 |
+
"view": "turn left"
|
| 5405 |
+
},
|
| 5406 |
+
{
|
| 5407 |
+
"move": "no-op",
|
| 5408 |
+
"view": "turn left"
|
| 5409 |
+
},
|
| 5410 |
+
{
|
| 5411 |
+
"move": "no-op",
|
| 5412 |
+
"view": "turn left"
|
| 5413 |
+
},
|
| 5414 |
+
{
|
| 5415 |
+
"move": "no-op",
|
| 5416 |
+
"view": "turn left"
|
| 5417 |
+
},
|
| 5418 |
+
{
|
| 5419 |
+
"move": "no-op",
|
| 5420 |
+
"view": "turn left"
|
| 5421 |
+
},
|
| 5422 |
+
{
|
| 5423 |
+
"move": "no-op",
|
| 5424 |
+
"view": "turn left"
|
| 5425 |
+
},
|
| 5426 |
+
{
|
| 5427 |
+
"move": "no-op",
|
| 5428 |
+
"view": "turn left"
|
| 5429 |
+
},
|
| 5430 |
+
{
|
| 5431 |
+
"move": "no-op",
|
| 5432 |
+
"view": "turn left"
|
| 5433 |
+
},
|
| 5434 |
+
{
|
| 5435 |
+
"move": "no-op",
|
| 5436 |
+
"view": "turn left"
|
| 5437 |
+
},
|
| 5438 |
+
{
|
| 5439 |
+
"move": "no-op",
|
| 5440 |
+
"view": "turn left"
|
| 5441 |
+
},
|
| 5442 |
+
{
|
| 5443 |
+
"move": "no-op",
|
| 5444 |
+
"view": "turn left"
|
| 5445 |
+
},
|
| 5446 |
+
{
|
| 5447 |
+
"move": "no-op",
|
| 5448 |
+
"view": "turn left"
|
| 5449 |
+
},
|
| 5450 |
+
{
|
| 5451 |
+
"move": "no-op",
|
| 5452 |
+
"view": "turn left"
|
| 5453 |
+
},
|
| 5454 |
+
{
|
| 5455 |
+
"move": "no-op",
|
| 5456 |
+
"view": "turn left"
|
| 5457 |
+
},
|
| 5458 |
+
{
|
| 5459 |
+
"move": "no-op",
|
| 5460 |
+
"view": "turn left"
|
| 5461 |
+
},
|
| 5462 |
+
{
|
| 5463 |
+
"move": "no-op",
|
| 5464 |
+
"view": "turn left"
|
| 5465 |
+
},
|
| 5466 |
+
{
|
| 5467 |
+
"move": "no-op",
|
| 5468 |
+
"view": "turn left"
|
| 5469 |
+
},
|
| 5470 |
+
{
|
| 5471 |
+
"move": "no-op",
|
| 5472 |
+
"view": "turn left"
|
| 5473 |
+
},
|
| 5474 |
+
{
|
| 5475 |
+
"move": "no-op",
|
| 5476 |
+
"view": "turn left"
|
| 5477 |
+
},
|
| 5478 |
+
{
|
| 5479 |
+
"move": "no-op",
|
| 5480 |
+
"view": "turn left"
|
| 5481 |
+
},
|
| 5482 |
+
{
|
| 5483 |
+
"move": "no-op",
|
| 5484 |
+
"view": "turn left"
|
| 5485 |
+
},
|
| 5486 |
+
{
|
| 5487 |
+
"move": "no-op",
|
| 5488 |
+
"view": "turn left"
|
| 5489 |
+
},
|
| 5490 |
+
{
|
| 5491 |
+
"move": "no-op",
|
| 5492 |
+
"view": "turn left"
|
| 5493 |
+
},
|
| 5494 |
+
{
|
| 5495 |
+
"move": "no-op",
|
| 5496 |
+
"view": "turn left"
|
| 5497 |
+
},
|
| 5498 |
+
{
|
| 5499 |
+
"move": "no-op",
|
| 5500 |
+
"view": "turn left"
|
| 5501 |
+
},
|
| 5502 |
+
{
|
| 5503 |
+
"move": "no-op",
|
| 5504 |
+
"view": "turn left"
|
| 5505 |
+
},
|
| 5506 |
+
{
|
| 5507 |
+
"move": "no-op",
|
| 5508 |
+
"view": "turn left"
|
| 5509 |
+
},
|
| 5510 |
+
{
|
| 5511 |
+
"move": "no-op",
|
| 5512 |
+
"view": "turn right"
|
| 5513 |
+
},
|
| 5514 |
+
{
|
| 5515 |
+
"move": "no-op",
|
| 5516 |
+
"view": "turn right"
|
| 5517 |
+
},
|
| 5518 |
+
{
|
| 5519 |
+
"move": "no-op",
|
| 5520 |
+
"view": "turn right"
|
| 5521 |
+
},
|
| 5522 |
+
{
|
| 5523 |
+
"move": "no-op",
|
| 5524 |
+
"view": "turn right"
|
| 5525 |
+
},
|
| 5526 |
+
{
|
| 5527 |
+
"move": "no-op",
|
| 5528 |
+
"view": "turn right"
|
| 5529 |
+
},
|
| 5530 |
+
{
|
| 5531 |
+
"move": "no-op",
|
| 5532 |
+
"view": "turn right"
|
| 5533 |
+
},
|
| 5534 |
+
{
|
| 5535 |
+
"move": "no-op",
|
| 5536 |
+
"view": "turn right"
|
| 5537 |
+
},
|
| 5538 |
+
{
|
| 5539 |
+
"move": "no-op",
|
| 5540 |
+
"view": "turn right"
|
| 5541 |
+
},
|
| 5542 |
+
{
|
| 5543 |
+
"move": "no-op",
|
| 5544 |
+
"view": "turn right"
|
| 5545 |
+
},
|
| 5546 |
+
{
|
| 5547 |
+
"move": "no-op",
|
| 5548 |
+
"view": "turn right"
|
| 5549 |
+
},
|
| 5550 |
+
{
|
| 5551 |
+
"move": "no-op",
|
| 5552 |
+
"view": "turn right"
|
| 5553 |
+
},
|
| 5554 |
+
{
|
| 5555 |
+
"move": "no-op",
|
| 5556 |
+
"view": "turn right"
|
| 5557 |
+
},
|
| 5558 |
+
{
|
| 5559 |
+
"move": "no-op",
|
| 5560 |
+
"view": "turn right"
|
| 5561 |
+
},
|
| 5562 |
+
{
|
| 5563 |
+
"move": "no-op",
|
| 5564 |
+
"view": "turn right"
|
| 5565 |
+
},
|
| 5566 |
+
{
|
| 5567 |
+
"move": "no-op",
|
| 5568 |
+
"view": "turn right"
|
| 5569 |
+
},
|
| 5570 |
+
{
|
| 5571 |
+
"move": "no-op",
|
| 5572 |
+
"view": "turn right"
|
| 5573 |
+
},
|
| 5574 |
+
{
|
| 5575 |
+
"move": "no-op",
|
| 5576 |
+
"view": "turn right"
|
| 5577 |
+
},
|
| 5578 |
+
{
|
| 5579 |
+
"move": "no-op",
|
| 5580 |
+
"view": "turn right"
|
| 5581 |
+
},
|
| 5582 |
+
{
|
| 5583 |
+
"move": "no-op",
|
| 5584 |
+
"view": "turn right"
|
| 5585 |
+
},
|
| 5586 |
+
{
|
| 5587 |
+
"move": "no-op",
|
| 5588 |
+
"view": "turn right"
|
| 5589 |
+
},
|
| 5590 |
+
{
|
| 5591 |
+
"move": "no-op",
|
| 5592 |
+
"view": "turn right"
|
| 5593 |
+
},
|
| 5594 |
+
{
|
| 5595 |
+
"move": "no-op",
|
| 5596 |
+
"view": "turn right"
|
| 5597 |
+
},
|
| 5598 |
+
{
|
| 5599 |
+
"move": "no-op",
|
| 5600 |
+
"view": "turn right"
|
| 5601 |
+
},
|
| 5602 |
+
{
|
| 5603 |
+
"move": "no-op",
|
| 5604 |
+
"view": "turn right"
|
| 5605 |
+
},
|
| 5606 |
+
{
|
| 5607 |
+
"move": "no-op",
|
| 5608 |
+
"view": "turn right"
|
| 5609 |
+
},
|
| 5610 |
+
{
|
| 5611 |
+
"move": "no-op",
|
| 5612 |
+
"view": "turn right"
|
| 5613 |
+
},
|
| 5614 |
+
{
|
| 5615 |
+
"move": "no-op",
|
| 5616 |
+
"view": "turn right"
|
| 5617 |
+
},
|
| 5618 |
+
{
|
| 5619 |
+
"move": "no-op",
|
| 5620 |
+
"view": "turn right"
|
| 5621 |
+
},
|
| 5622 |
+
{
|
| 5623 |
+
"move": "no-op",
|
| 5624 |
+
"view": "turn right"
|
| 5625 |
+
},
|
| 5626 |
+
{
|
| 5627 |
+
"move": "no-op",
|
| 5628 |
+
"view": "turn right"
|
| 5629 |
+
},
|
| 5630 |
+
{
|
| 5631 |
+
"move": "no-op",
|
| 5632 |
+
"view": "turn right"
|
| 5633 |
+
},
|
| 5634 |
+
{
|
| 5635 |
+
"move": "no-op",
|
| 5636 |
+
"view": "turn right"
|
| 5637 |
+
},
|
| 5638 |
+
{
|
| 5639 |
+
"move": "no-op",
|
| 5640 |
+
"view": "turn right"
|
| 5641 |
+
},
|
| 5642 |
+
{
|
| 5643 |
+
"move": "no-op",
|
| 5644 |
+
"view": "turn right"
|
| 5645 |
+
},
|
| 5646 |
+
{
|
| 5647 |
+
"move": "no-op",
|
| 5648 |
+
"view": "turn right"
|
| 5649 |
+
},
|
| 5650 |
+
{
|
| 5651 |
+
"move": "no-op",
|
| 5652 |
+
"view": "turn right"
|
| 5653 |
+
},
|
| 5654 |
+
{
|
| 5655 |
+
"move": "no-op",
|
| 5656 |
+
"view": "turn right"
|
| 5657 |
+
},
|
| 5658 |
+
{
|
| 5659 |
+
"move": "no-op",
|
| 5660 |
+
"view": "turn right"
|
| 5661 |
+
},
|
| 5662 |
+
{
|
| 5663 |
+
"move": "no-op",
|
| 5664 |
+
"view": "turn right"
|
| 5665 |
+
},
|
| 5666 |
+
{
|
| 5667 |
+
"move": "no-op",
|
| 5668 |
+
"view": "turn right"
|
| 5669 |
+
},
|
| 5670 |
+
{
|
| 5671 |
+
"move": "no-op",
|
| 5672 |
+
"view": "turn right"
|
| 5673 |
+
},
|
| 5674 |
+
{
|
| 5675 |
+
"move": "no-op",
|
| 5676 |
+
"view": "turn right"
|
| 5677 |
+
},
|
| 5678 |
+
{
|
| 5679 |
+
"move": "no-op",
|
| 5680 |
+
"view": "turn right"
|
| 5681 |
+
},
|
| 5682 |
+
{
|
| 5683 |
+
"move": "no-op",
|
| 5684 |
+
"view": "turn right"
|
| 5685 |
+
},
|
| 5686 |
+
{
|
| 5687 |
+
"move": "no-op",
|
| 5688 |
+
"view": "turn right"
|
| 5689 |
+
},
|
| 5690 |
+
{
|
| 5691 |
+
"move": "no-op",
|
| 5692 |
+
"view": "turn right"
|
| 5693 |
+
},
|
| 5694 |
+
{
|
| 5695 |
+
"move": "no-op",
|
| 5696 |
+
"view": "turn right"
|
| 5697 |
+
},
|
| 5698 |
+
{
|
| 5699 |
+
"move": "no-op",
|
| 5700 |
+
"view": "turn right"
|
| 5701 |
+
},
|
| 5702 |
+
{
|
| 5703 |
+
"move": "no-op",
|
| 5704 |
+
"view": "turn right"
|
| 5705 |
+
},
|
| 5706 |
+
{
|
| 5707 |
+
"move": "no-op",
|
| 5708 |
+
"view": "turn right"
|
| 5709 |
+
},
|
| 5710 |
+
{
|
| 5711 |
+
"move": "no-op",
|
| 5712 |
+
"view": "turn right"
|
| 5713 |
+
},
|
| 5714 |
+
{
|
| 5715 |
+
"move": "no-op",
|
| 5716 |
+
"view": "turn right"
|
| 5717 |
+
},
|
| 5718 |
+
{
|
| 5719 |
+
"move": "no-op",
|
| 5720 |
+
"view": "turn right"
|
| 5721 |
+
},
|
| 5722 |
+
{
|
| 5723 |
+
"move": "no-op",
|
| 5724 |
+
"view": "turn right"
|
| 5725 |
+
},
|
| 5726 |
+
{
|
| 5727 |
+
"move": "no-op",
|
| 5728 |
+
"view": "turn right"
|
| 5729 |
+
},
|
| 5730 |
+
{
|
| 5731 |
+
"move": "no-op",
|
| 5732 |
+
"view": "turn right"
|
| 5733 |
+
},
|
| 5734 |
+
{
|
| 5735 |
+
"move": "no-op",
|
| 5736 |
+
"view": "turn right"
|
| 5737 |
+
},
|
| 5738 |
+
{
|
| 5739 |
+
"move": "no-op",
|
| 5740 |
+
"view": "turn right"
|
| 5741 |
+
},
|
| 5742 |
+
{
|
| 5743 |
+
"move": "no-op",
|
| 5744 |
+
"view": "turn right"
|
| 5745 |
+
},
|
| 5746 |
+
{
|
| 5747 |
+
"move": "no-op",
|
| 5748 |
+
"view": "turn right"
|
| 5749 |
+
},
|
| 5750 |
+
{
|
| 5751 |
+
"move": "no-op",
|
| 5752 |
+
"view": "turn right"
|
| 5753 |
+
},
|
| 5754 |
+
{
|
| 5755 |
+
"move": "no-op",
|
| 5756 |
+
"view": "turn right"
|
| 5757 |
+
},
|
| 5758 |
+
{
|
| 5759 |
+
"move": "no-op",
|
| 5760 |
+
"view": "turn right"
|
| 5761 |
+
},
|
| 5762 |
+
{
|
| 5763 |
+
"move": "no-op",
|
| 5764 |
+
"view": "turn right"
|
| 5765 |
+
},
|
| 5766 |
+
{
|
| 5767 |
+
"move": "no-op",
|
| 5768 |
+
"view": "turn right"
|
| 5769 |
+
},
|
| 5770 |
+
{
|
| 5771 |
+
"move": "no-op",
|
| 5772 |
+
"view": "turn right"
|
| 5773 |
+
},
|
| 5774 |
+
{
|
| 5775 |
+
"move": "no-op",
|
| 5776 |
+
"view": "turn right"
|
| 5777 |
+
},
|
| 5778 |
+
{
|
| 5779 |
+
"move": "no-op",
|
| 5780 |
+
"view": "turn right"
|
| 5781 |
+
},
|
| 5782 |
+
{
|
| 5783 |
+
"move": "no-op",
|
| 5784 |
+
"view": "turn right"
|
| 5785 |
+
},
|
| 5786 |
+
{
|
| 5787 |
+
"move": "no-op",
|
| 5788 |
+
"view": "turn right"
|
| 5789 |
+
},
|
| 5790 |
+
{
|
| 5791 |
+
"move": "no-op",
|
| 5792 |
+
"view": "turn right"
|
| 5793 |
+
},
|
| 5794 |
+
{
|
| 5795 |
+
"move": "no-op",
|
| 5796 |
+
"view": "turn right"
|
| 5797 |
+
},
|
| 5798 |
+
{
|
| 5799 |
+
"move": "no-op",
|
| 5800 |
+
"view": "turn right"
|
| 5801 |
+
},
|
| 5802 |
+
{
|
| 5803 |
+
"move": "no-op",
|
| 5804 |
+
"view": "turn right"
|
| 5805 |
+
},
|
| 5806 |
+
{
|
| 5807 |
+
"move": "no-op",
|
| 5808 |
+
"view": "turn right"
|
| 5809 |
+
},
|
| 5810 |
+
{
|
| 5811 |
+
"move": "no-op",
|
| 5812 |
+
"view": "turn right"
|
| 5813 |
+
},
|
| 5814 |
+
{
|
| 5815 |
+
"move": "no-op",
|
| 5816 |
+
"view": "turn right"
|
| 5817 |
+
},
|
| 5818 |
+
{
|
| 5819 |
+
"move": "no-op",
|
| 5820 |
+
"view": "turn right"
|
| 5821 |
+
},
|
| 5822 |
+
{
|
| 5823 |
+
"move": "no-op",
|
| 5824 |
+
"view": "turn right"
|
| 5825 |
+
},
|
| 5826 |
+
{
|
| 5827 |
+
"move": "no-op",
|
| 5828 |
+
"view": "turn right"
|
| 5829 |
+
},
|
| 5830 |
+
{
|
| 5831 |
+
"move": "no-op",
|
| 5832 |
+
"view": "turn right"
|
| 5833 |
+
},
|
| 5834 |
+
{
|
| 5835 |
+
"move": "no-op",
|
| 5836 |
+
"view": "turn right"
|
| 5837 |
+
},
|
| 5838 |
+
{
|
| 5839 |
+
"move": "no-op",
|
| 5840 |
+
"view": "turn right"
|
| 5841 |
+
},
|
| 5842 |
+
{
|
| 5843 |
+
"move": "no-op",
|
| 5844 |
+
"view": "turn right"
|
| 5845 |
+
},
|
| 5846 |
+
{
|
| 5847 |
+
"move": "no-op",
|
| 5848 |
+
"view": "turn right"
|
| 5849 |
+
},
|
| 5850 |
+
{
|
| 5851 |
+
"move": "no-op",
|
| 5852 |
+
"view": "turn right"
|
| 5853 |
+
},
|
| 5854 |
+
{
|
| 5855 |
+
"move": "no-op",
|
| 5856 |
+
"view": "turn right"
|
| 5857 |
+
},
|
| 5858 |
+
{
|
| 5859 |
+
"move": "no-op",
|
| 5860 |
+
"view": "turn right"
|
| 5861 |
+
},
|
| 5862 |
+
{
|
| 5863 |
+
"move": "no-op",
|
| 5864 |
+
"view": "turn right"
|
| 5865 |
+
},
|
| 5866 |
+
{
|
| 5867 |
+
"move": "no-op",
|
| 5868 |
+
"view": "turn right"
|
| 5869 |
+
},
|
| 5870 |
+
{
|
| 5871 |
+
"move": "no-op",
|
| 5872 |
+
"view": "turn right"
|
| 5873 |
+
},
|
| 5874 |
+
{
|
| 5875 |
+
"move": "no-op",
|
| 5876 |
+
"view": "turn right"
|
| 5877 |
+
},
|
| 5878 |
+
{
|
| 5879 |
+
"move": "no-op",
|
| 5880 |
+
"view": "turn right"
|
| 5881 |
+
},
|
| 5882 |
+
{
|
| 5883 |
+
"move": "no-op",
|
| 5884 |
+
"view": "turn right"
|
| 5885 |
+
},
|
| 5886 |
+
{
|
| 5887 |
+
"move": "no-op",
|
| 5888 |
+
"view": "turn right"
|
| 5889 |
+
},
|
| 5890 |
+
{
|
| 5891 |
+
"move": "no-op",
|
| 5892 |
+
"view": "turn right"
|
| 5893 |
+
},
|
| 5894 |
+
{
|
| 5895 |
+
"move": "no-op",
|
| 5896 |
+
"view": "turn right"
|
| 5897 |
+
},
|
| 5898 |
+
{
|
| 5899 |
+
"move": "no-op",
|
| 5900 |
+
"view": "turn right"
|
| 5901 |
+
},
|
| 5902 |
+
{
|
| 5903 |
+
"move": "no-op",
|
| 5904 |
+
"view": "turn right"
|
| 5905 |
+
},
|
| 5906 |
+
{
|
| 5907 |
+
"move": "no-op",
|
| 5908 |
+
"view": "turn right"
|
| 5909 |
+
},
|
| 5910 |
+
{
|
| 5911 |
+
"move": "no-op",
|
| 5912 |
+
"view": "turn right"
|
| 5913 |
+
},
|
| 5914 |
+
{
|
| 5915 |
+
"move": "no-op",
|
| 5916 |
+
"view": "turn right"
|
| 5917 |
+
},
|
| 5918 |
+
{
|
| 5919 |
+
"move": "no-op",
|
| 5920 |
+
"view": "turn right"
|
| 5921 |
+
},
|
| 5922 |
+
{
|
| 5923 |
+
"move": "no-op",
|
| 5924 |
+
"view": "turn right"
|
| 5925 |
+
},
|
| 5926 |
+
{
|
| 5927 |
+
"move": "no-op",
|
| 5928 |
+
"view": "turn right"
|
| 5929 |
+
},
|
| 5930 |
+
{
|
| 5931 |
+
"move": "no-op",
|
| 5932 |
+
"view": "turn right"
|
| 5933 |
+
},
|
| 5934 |
+
{
|
| 5935 |
+
"move": "no-op",
|
| 5936 |
+
"view": "turn right"
|
| 5937 |
+
},
|
| 5938 |
+
{
|
| 5939 |
+
"move": "no-op",
|
| 5940 |
+
"view": "turn right"
|
| 5941 |
+
},
|
| 5942 |
+
{
|
| 5943 |
+
"move": "no-op",
|
| 5944 |
+
"view": "turn right"
|
| 5945 |
+
},
|
| 5946 |
+
{
|
| 5947 |
+
"move": "no-op",
|
| 5948 |
+
"view": "turn right"
|
| 5949 |
+
},
|
| 5950 |
+
{
|
| 5951 |
+
"move": "no-op",
|
| 5952 |
+
"view": "turn right"
|
| 5953 |
+
},
|
| 5954 |
+
{
|
| 5955 |
+
"move": "no-op",
|
| 5956 |
+
"view": "turn right"
|
| 5957 |
+
},
|
| 5958 |
+
{
|
| 5959 |
+
"move": "no-op",
|
| 5960 |
+
"view": "turn right"
|
| 5961 |
+
},
|
| 5962 |
+
{
|
| 5963 |
+
"move": "no-op",
|
| 5964 |
+
"view": "turn right"
|
| 5965 |
+
},
|
| 5966 |
+
{
|
| 5967 |
+
"move": "no-op",
|
| 5968 |
+
"view": "turn right"
|
| 5969 |
+
},
|
| 5970 |
+
{
|
| 5971 |
+
"move": "no-op",
|
| 5972 |
+
"view": "turn right"
|
| 5973 |
+
},
|
| 5974 |
+
{
|
| 5975 |
+
"move": "no-op",
|
| 5976 |
+
"view": "turn right"
|
| 5977 |
+
},
|
| 5978 |
+
{
|
| 5979 |
+
"move": "no-op",
|
| 5980 |
+
"view": "turn right"
|
| 5981 |
+
},
|
| 5982 |
+
{
|
| 5983 |
+
"move": "no-op",
|
| 5984 |
+
"view": "turn right"
|
| 5985 |
+
},
|
| 5986 |
+
{
|
| 5987 |
+
"move": "no-op",
|
| 5988 |
+
"view": "turn right"
|
| 5989 |
+
},
|
| 5990 |
+
{
|
| 5991 |
+
"move": "no-op",
|
| 5992 |
+
"view": "turn right"
|
| 5993 |
+
},
|
| 5994 |
+
{
|
| 5995 |
+
"move": "no-op",
|
| 5996 |
+
"view": "turn right"
|
| 5997 |
+
},
|
| 5998 |
+
{
|
| 5999 |
+
"move": "no-op",
|
| 6000 |
+
"view": "turn right"
|
| 6001 |
+
},
|
| 6002 |
+
{
|
| 6003 |
+
"move": "no-op",
|
| 6004 |
+
"view": "turn right"
|
| 6005 |
+
},
|
| 6006 |
+
{
|
| 6007 |
+
"move": "no-op",
|
| 6008 |
+
"view": "turn right"
|
| 6009 |
+
},
|
| 6010 |
+
{
|
| 6011 |
+
"move": "no-op",
|
| 6012 |
+
"view": "turn right"
|
| 6013 |
+
},
|
| 6014 |
+
{
|
| 6015 |
+
"move": "no-op",
|
| 6016 |
+
"view": "turn right"
|
| 6017 |
+
},
|
| 6018 |
+
{
|
| 6019 |
+
"move": "no-op",
|
| 6020 |
+
"view": "turn right"
|
| 6021 |
+
},
|
| 6022 |
+
{
|
| 6023 |
+
"move": "no-op",
|
| 6024 |
+
"view": "turn right"
|
| 6025 |
+
},
|
| 6026 |
+
{
|
| 6027 |
+
"move": "no-op",
|
| 6028 |
+
"view": "turn right"
|
| 6029 |
+
},
|
| 6030 |
+
{
|
| 6031 |
+
"move": "no-op",
|
| 6032 |
+
"view": "turn right"
|
| 6033 |
+
},
|
| 6034 |
+
{
|
| 6035 |
+
"move": "no-op",
|
| 6036 |
+
"view": "turn right"
|
| 6037 |
+
},
|
| 6038 |
+
{
|
| 6039 |
+
"move": "no-op",
|
| 6040 |
+
"view": "turn right"
|
| 6041 |
+
},
|
| 6042 |
+
{
|
| 6043 |
+
"move": "no-op",
|
| 6044 |
+
"view": "turn right"
|
| 6045 |
+
},
|
| 6046 |
+
{
|
| 6047 |
+
"move": "no-op",
|
| 6048 |
+
"view": "turn right"
|
| 6049 |
+
},
|
| 6050 |
+
{
|
| 6051 |
+
"move": "no-op",
|
| 6052 |
+
"view": "turn right"
|
| 6053 |
+
},
|
| 6054 |
+
{
|
| 6055 |
+
"move": "no-op",
|
| 6056 |
+
"view": "turn right"
|
| 6057 |
+
},
|
| 6058 |
+
{
|
| 6059 |
+
"move": "no-op",
|
| 6060 |
+
"view": "turn right"
|
| 6061 |
+
},
|
| 6062 |
+
{
|
| 6063 |
+
"move": "no-op",
|
| 6064 |
+
"view": "turn right"
|
| 6065 |
+
},
|
| 6066 |
+
{
|
| 6067 |
+
"move": "no-op",
|
| 6068 |
+
"view": "turn right"
|
| 6069 |
+
},
|
| 6070 |
+
{
|
| 6071 |
+
"move": "no-op",
|
| 6072 |
+
"view": "turn right"
|
| 6073 |
+
},
|
| 6074 |
+
{
|
| 6075 |
+
"move": "no-op",
|
| 6076 |
+
"view": "turn right"
|
| 6077 |
+
},
|
| 6078 |
+
{
|
| 6079 |
+
"move": "no-op",
|
| 6080 |
+
"view": "turn right"
|
| 6081 |
+
},
|
| 6082 |
+
{
|
| 6083 |
+
"move": "no-op",
|
| 6084 |
+
"view": "turn right"
|
| 6085 |
+
},
|
| 6086 |
+
{
|
| 6087 |
+
"move": "no-op",
|
| 6088 |
+
"view": "turn right"
|
| 6089 |
+
},
|
| 6090 |
+
{
|
| 6091 |
+
"move": "no-op",
|
| 6092 |
+
"view": "turn right"
|
| 6093 |
+
},
|
| 6094 |
+
{
|
| 6095 |
+
"move": "no-op",
|
| 6096 |
+
"view": "turn right"
|
| 6097 |
+
},
|
| 6098 |
+
{
|
| 6099 |
+
"move": "no-op",
|
| 6100 |
+
"view": "turn right"
|
| 6101 |
+
},
|
| 6102 |
+
{
|
| 6103 |
+
"move": "no-op",
|
| 6104 |
+
"view": "turn right"
|
| 6105 |
+
},
|
| 6106 |
+
{
|
| 6107 |
+
"move": "no-op",
|
| 6108 |
+
"view": "turn right"
|
| 6109 |
+
},
|
| 6110 |
+
{
|
| 6111 |
+
"move": "no-op",
|
| 6112 |
+
"view": "turn right"
|
| 6113 |
+
},
|
| 6114 |
+
{
|
| 6115 |
+
"move": "no-op",
|
| 6116 |
+
"view": "turn right"
|
| 6117 |
+
},
|
| 6118 |
+
{
|
| 6119 |
+
"move": "no-op",
|
| 6120 |
+
"view": "turn right"
|
| 6121 |
+
},
|
| 6122 |
+
{
|
| 6123 |
+
"move": "no-op",
|
| 6124 |
+
"view": "turn right"
|
| 6125 |
+
},
|
| 6126 |
+
{
|
| 6127 |
+
"move": "no-op",
|
| 6128 |
+
"view": "turn right"
|
| 6129 |
+
},
|
| 6130 |
+
{
|
| 6131 |
+
"move": "no-op",
|
| 6132 |
+
"view": "turn right"
|
| 6133 |
+
},
|
| 6134 |
+
{
|
| 6135 |
+
"move": "no-op",
|
| 6136 |
+
"view": "turn right"
|
| 6137 |
+
},
|
| 6138 |
+
{
|
| 6139 |
+
"move": "no-op",
|
| 6140 |
+
"view": "turn right"
|
| 6141 |
+
},
|
| 6142 |
+
{
|
| 6143 |
+
"move": "no-op",
|
| 6144 |
+
"view": "turn right"
|
| 6145 |
+
},
|
| 6146 |
+
{
|
| 6147 |
+
"move": "no-op",
|
| 6148 |
+
"view": "turn right"
|
| 6149 |
+
},
|
| 6150 |
+
{
|
| 6151 |
+
"move": "no-op",
|
| 6152 |
+
"view": "turn right"
|
| 6153 |
+
},
|
| 6154 |
+
{
|
| 6155 |
+
"move": "no-op",
|
| 6156 |
+
"view": "turn right"
|
| 6157 |
+
},
|
| 6158 |
+
{
|
| 6159 |
+
"move": "no-op",
|
| 6160 |
+
"view": "turn right"
|
| 6161 |
+
},
|
| 6162 |
+
{
|
| 6163 |
+
"move": "no-op",
|
| 6164 |
+
"view": "turn right"
|
| 6165 |
+
},
|
| 6166 |
+
{
|
| 6167 |
+
"move": "no-op",
|
| 6168 |
+
"view": "turn right"
|
| 6169 |
+
},
|
| 6170 |
+
{
|
| 6171 |
+
"move": "no-op",
|
| 6172 |
+
"view": "turn right"
|
| 6173 |
+
},
|
| 6174 |
+
{
|
| 6175 |
+
"move": "no-op",
|
| 6176 |
+
"view": "turn right"
|
| 6177 |
+
},
|
| 6178 |
+
{
|
| 6179 |
+
"move": "no-op",
|
| 6180 |
+
"view": "turn right"
|
| 6181 |
+
},
|
| 6182 |
+
{
|
| 6183 |
+
"move": "no-op",
|
| 6184 |
+
"view": "turn right"
|
| 6185 |
+
},
|
| 6186 |
+
{
|
| 6187 |
+
"move": "no-op",
|
| 6188 |
+
"view": "turn right"
|
| 6189 |
+
},
|
| 6190 |
+
{
|
| 6191 |
+
"move": "no-op",
|
| 6192 |
+
"view": "turn right"
|
| 6193 |
+
},
|
| 6194 |
+
{
|
| 6195 |
+
"move": "no-op",
|
| 6196 |
+
"view": "turn right"
|
| 6197 |
+
},
|
| 6198 |
+
{
|
| 6199 |
+
"move": "no-op",
|
| 6200 |
+
"view": "turn right"
|
| 6201 |
+
},
|
| 6202 |
+
{
|
| 6203 |
+
"move": "no-op",
|
| 6204 |
+
"view": "turn right"
|
| 6205 |
+
},
|
| 6206 |
+
{
|
| 6207 |
+
"move": "no-op",
|
| 6208 |
+
"view": "turn right"
|
| 6209 |
+
},
|
| 6210 |
+
{
|
| 6211 |
+
"move": "no-op",
|
| 6212 |
+
"view": "turn right"
|
| 6213 |
+
},
|
| 6214 |
+
{
|
| 6215 |
+
"move": "no-op",
|
| 6216 |
+
"view": "turn right"
|
| 6217 |
+
},
|
| 6218 |
+
{
|
| 6219 |
+
"move": "no-op",
|
| 6220 |
+
"view": "turn right"
|
| 6221 |
+
},
|
| 6222 |
+
{
|
| 6223 |
+
"move": "no-op",
|
| 6224 |
+
"view": "turn right"
|
| 6225 |
+
},
|
| 6226 |
+
{
|
| 6227 |
+
"move": "no-op",
|
| 6228 |
+
"view": "turn right"
|
| 6229 |
+
},
|
| 6230 |
+
{
|
| 6231 |
+
"move": "no-op",
|
| 6232 |
+
"view": "turn right"
|
| 6233 |
+
}
|
| 6234 |
+
]
|
assets/framework.png
ADDED
|
Git LFS Details
|
configs/infworld_config.yaml
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Infinite World - Model Configuration
|
| 2 |
+
# Download from https://huggingface.co/Wan-AI/Wan2.1-T2V-1.3B and put files under checkpoints/models/
|
| 3 |
+
# Paths below are relative to project root unless absolute.
|
| 4 |
+
|
| 5 |
+
##########################
|
| 6 |
+
### DiT checkpoint (from config)
|
| 7 |
+
##########################
|
| 8 |
+
# HF: diffusion_pytorch_model.safetensors; or your training .ckpt
|
| 9 |
+
checkpoint_path: "checkpoints/infinite_world_model.ckpt"
|
| 10 |
+
|
| 11 |
+
##########################
|
| 12 |
+
### text encoder config
|
| 13 |
+
##########################
|
| 14 |
+
|
| 15 |
+
text_encoder_target: infworld.models.umt5.T5EncoderModel
|
| 16 |
+
|
| 17 |
+
text_encoder_cfg:
|
| 18 |
+
checkpoint_path: "checkpoints/models/models_t5_umt5-xxl-enc-bf16.pth"
|
| 19 |
+
tokenizer_path: "checkpoints/models/google/umt5-xxl"
|
| 20 |
+
model_max_length: 512
|
| 21 |
+
|
| 22 |
+
##########################
|
| 23 |
+
### scheduler config
|
| 24 |
+
##########################
|
| 25 |
+
|
| 26 |
+
scheduler_target: infworld.models.scheduler.RFlowScheduler
|
| 27 |
+
|
| 28 |
+
val_scheduler_cfg:
|
| 29 |
+
shift: 7.0 # PX256: 3, PX627: 7, PX960: 11
|
| 30 |
+
use_reversed_velocity: true
|
| 31 |
+
use_timestep_transform: true
|
| 32 |
+
num_sampling_steps: 30
|
| 33 |
+
audio_cfg_scale: 5.0
|
| 34 |
+
text_cfg_scale: 5.0
|
| 35 |
+
|
| 36 |
+
##########################
|
| 37 |
+
### model config
|
| 38 |
+
##########################
|
| 39 |
+
|
| 40 |
+
model_target: infworld.models.dit_model.WanModel
|
| 41 |
+
|
| 42 |
+
# 1.3B model config
|
| 43 |
+
model_cfg:
|
| 44 |
+
model_type: t2v
|
| 45 |
+
dim: 1536
|
| 46 |
+
in_channels: 20
|
| 47 |
+
ffn_dim: 8960
|
| 48 |
+
freq_dim: 256
|
| 49 |
+
num_heads: 12
|
| 50 |
+
num_layers: 30
|
| 51 |
+
|
| 52 |
+
##########################
|
| 53 |
+
### VAE config
|
| 54 |
+
##########################
|
| 55 |
+
|
| 56 |
+
vae_target: infworld.vae.WanVAEModelWrapper
|
| 57 |
+
|
| 58 |
+
vae_cfg:
|
| 59 |
+
vae_pth: "checkpoints/models/Wan2.1_VAE.pth"
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
##########################
|
| 63 |
+
### validation config
|
| 64 |
+
##########################
|
| 65 |
+
|
| 66 |
+
validation_data:
|
| 67 |
+
num_frames: 81
|
| 68 |
+
|
| 69 |
+
##########################
|
| 70 |
+
### other config
|
| 71 |
+
##########################
|
| 72 |
+
|
| 73 |
+
amp_dtype: "bfloat16"
|
infer_local.sh
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
# Infinite World - Local Inference Script (Single/Multi GPU)
|
| 3 |
+
# Usage: bash infer_local.sh [num_gpus]
|
| 4 |
+
# Example: bash infer_local.sh 1 (single GPU, no torchrun, avoids port conflict)
|
| 5 |
+
# Example: bash infer_local.sh 8 (8 GPUs via torchrun)
|
| 6 |
+
#
|
| 7 |
+
# Single GPU (num_gpus=1): runs "python scripts/..." directly, no port needed.
|
| 8 |
+
# Multi GPU: runs torchrun. If EADDRINUSE, set: export MASTER_PORT=29500
|
| 9 |
+
|
| 10 |
+
NUM_GPUS=${1:-1}
|
| 11 |
+
WORK_DIR="/mnt/dolphinfs/ssd_pool/docker/user/hadoop-videogen-hl/hadoop-camera3d/wuruiqi/infinite-world"
|
| 12 |
+
|
| 13 |
+
cd $WORK_DIR
|
| 14 |
+
|
| 15 |
+
echo "=============================================="
|
| 16 |
+
echo "Infinite World - Local Inference"
|
| 17 |
+
echo "=============================================="
|
| 18 |
+
echo "Using $NUM_GPUS GPU(s)"
|
| 19 |
+
echo "Working directory: $WORK_DIR"
|
| 20 |
+
|
| 21 |
+
if [ "$NUM_GPUS" -eq 1 ]; then
|
| 22 |
+
# Single GPU: run directly to avoid torchrun port (EADDRINUSE)
|
| 23 |
+
python scripts/infworld_inference.py
|
| 24 |
+
else
|
| 25 |
+
MASTER_PORT=${MASTER_PORT:-29400}
|
| 26 |
+
echo "MASTER_PORT: $MASTER_PORT"
|
| 27 |
+
torchrun --nnodes=1 --nproc_per_node=$NUM_GPUS \
|
| 28 |
+
--rdzv_id=100 --rdzv_backend=c10d \
|
| 29 |
+
--rdzv_endpoint=localhost:$MASTER_PORT \
|
| 30 |
+
scripts/infworld_inference.py
|
| 31 |
+
fi
|
infworld/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
# infworld package
|
infworld/clip/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
# infworld/clip package
|
infworld/clip/clip.py
ADDED
|
@@ -0,0 +1,663 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Modified from ``https://github.com/openai/CLIP'' and ``https://github.com/mlfoundations/open_clip''
|
| 2 |
+
# Copyright 2024-2025 The Alibaba Wan Team Authors. All rights reserved.
|
| 3 |
+
import logging
|
| 4 |
+
import warnings
|
| 5 |
+
import math
|
| 6 |
+
|
| 7 |
+
import torch
|
| 8 |
+
import torch.nn as nn
|
| 9 |
+
import torch.nn.functional as F
|
| 10 |
+
import torchvision.transforms as T
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
try:
|
| 14 |
+
import flash_attn_interface
|
| 15 |
+
FLASH_ATTN_3_AVAILABLE = True
|
| 16 |
+
except ModuleNotFoundError:
|
| 17 |
+
FLASH_ATTN_3_AVAILABLE = False
|
| 18 |
+
|
| 19 |
+
try:
|
| 20 |
+
import flash_attn
|
| 21 |
+
FLASH_ATTN_2_AVAILABLE = True
|
| 22 |
+
except ModuleNotFoundError:
|
| 23 |
+
FLASH_ATTN_2_AVAILABLE = False
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
from infworld.clip.tokenizers import HuggingfaceTokenizer
|
| 27 |
+
from infworld.clip.xlm_roberta import XLMRoberta
|
| 28 |
+
|
| 29 |
+
__all__ = [
|
| 30 |
+
'XLMRobertaCLIP',
|
| 31 |
+
'clip_xlm_roberta_vit_h_14',
|
| 32 |
+
'CLIPModel',
|
| 33 |
+
]
|
| 34 |
+
|
| 35 |
+
def flash_attention(
|
| 36 |
+
q,
|
| 37 |
+
k,
|
| 38 |
+
v,
|
| 39 |
+
q_lens=None,
|
| 40 |
+
k_lens=None,
|
| 41 |
+
dropout_p=0.,
|
| 42 |
+
softmax_scale=None,
|
| 43 |
+
q_scale=None,
|
| 44 |
+
causal=False,
|
| 45 |
+
window_size=(-1, -1),
|
| 46 |
+
deterministic=False,
|
| 47 |
+
dtype=torch.bfloat16,
|
| 48 |
+
version=None,
|
| 49 |
+
):
|
| 50 |
+
"""
|
| 51 |
+
q: [B, Lq, Nq, C1].
|
| 52 |
+
k: [B, Lk, Nk, C1].
|
| 53 |
+
v: [B, Lk, Nk, C2]. Nq must be divisible by Nk.
|
| 54 |
+
q_lens: [B].
|
| 55 |
+
k_lens: [B].
|
| 56 |
+
dropout_p: float. Dropout probability.
|
| 57 |
+
softmax_scale: float. The scaling of QK^T before applying softmax.
|
| 58 |
+
causal: bool. Whether to apply causal attention mask.
|
| 59 |
+
window_size: (left right). If not (-1, -1), apply sliding window local attention.
|
| 60 |
+
deterministic: bool. If True, slightly slower and uses more memory.
|
| 61 |
+
dtype: torch.dtype. Apply when dtype of q/k/v is not float16/bfloat16.
|
| 62 |
+
"""
|
| 63 |
+
half_dtypes = (torch.float16, torch.bfloat16)
|
| 64 |
+
assert dtype in half_dtypes
|
| 65 |
+
assert q.device.type == 'cuda' and q.size(-1) <= 256
|
| 66 |
+
|
| 67 |
+
# params
|
| 68 |
+
b, lq, lk, out_dtype = q.size(0), q.size(1), k.size(1), q.dtype
|
| 69 |
+
|
| 70 |
+
def half(x):
|
| 71 |
+
return x if x.dtype in half_dtypes else x.to(dtype)
|
| 72 |
+
|
| 73 |
+
# preprocess query
|
| 74 |
+
if q_lens is None:
|
| 75 |
+
q = half(q.flatten(0, 1))
|
| 76 |
+
q_lens = torch.tensor(
|
| 77 |
+
[lq] * b, dtype=torch.int32).to(
|
| 78 |
+
device=q.device, non_blocking=True)
|
| 79 |
+
else:
|
| 80 |
+
q = half(torch.cat([u[:v] for u, v in zip(q, q_lens)]))
|
| 81 |
+
|
| 82 |
+
# preprocess key, value
|
| 83 |
+
if k_lens is None:
|
| 84 |
+
k = half(k.flatten(0, 1))
|
| 85 |
+
v = half(v.flatten(0, 1))
|
| 86 |
+
k_lens = torch.tensor(
|
| 87 |
+
[lk] * b, dtype=torch.int32).to(
|
| 88 |
+
device=k.device, non_blocking=True)
|
| 89 |
+
else:
|
| 90 |
+
k = half(torch.cat([u[:v] for u, v in zip(k, k_lens)]))
|
| 91 |
+
v = half(torch.cat([u[:v] for u, v in zip(v, k_lens)]))
|
| 92 |
+
|
| 93 |
+
q = q.to(v.dtype)
|
| 94 |
+
k = k.to(v.dtype)
|
| 95 |
+
|
| 96 |
+
if q_scale is not None:
|
| 97 |
+
q = q * q_scale
|
| 98 |
+
|
| 99 |
+
if version is not None and version == 3 and not FLASH_ATTN_3_AVAILABLE:
|
| 100 |
+
warnings.warn(
|
| 101 |
+
'Flash attention 3 is not available, use flash attention 2 instead.'
|
| 102 |
+
)
|
| 103 |
+
|
| 104 |
+
# apply attention
|
| 105 |
+
if (version is None or version == 3) and FLASH_ATTN_3_AVAILABLE:
|
| 106 |
+
# Note: dropout_p, window_size are not supported in FA3 now.
|
| 107 |
+
x = flash_attn_interface.flash_attn_varlen_func(
|
| 108 |
+
q=q,
|
| 109 |
+
k=k,
|
| 110 |
+
v=v,
|
| 111 |
+
cu_seqlens_q=torch.cat([q_lens.new_zeros([1]), q_lens]).cumsum(
|
| 112 |
+
0, dtype=torch.int32).to(q.device, non_blocking=True),
|
| 113 |
+
cu_seqlens_k=torch.cat([k_lens.new_zeros([1]), k_lens]).cumsum(
|
| 114 |
+
0, dtype=torch.int32).to(q.device, non_blocking=True),
|
| 115 |
+
seqused_q=None,
|
| 116 |
+
seqused_k=None,
|
| 117 |
+
max_seqlen_q=lq,
|
| 118 |
+
max_seqlen_k=lk,
|
| 119 |
+
softmax_scale=softmax_scale,
|
| 120 |
+
causal=causal,
|
| 121 |
+
deterministic=deterministic)[0].unflatten(0, (b, lq))
|
| 122 |
+
else:
|
| 123 |
+
assert FLASH_ATTN_2_AVAILABLE
|
| 124 |
+
x = flash_attn.flash_attn_varlen_func(
|
| 125 |
+
q=q,
|
| 126 |
+
k=k,
|
| 127 |
+
v=v,
|
| 128 |
+
cu_seqlens_q=torch.cat([q_lens.new_zeros([1]), q_lens]).cumsum(
|
| 129 |
+
0, dtype=torch.int32).to(q.device, non_blocking=True),
|
| 130 |
+
cu_seqlens_k=torch.cat([k_lens.new_zeros([1]), k_lens]).cumsum(
|
| 131 |
+
0, dtype=torch.int32).to(q.device, non_blocking=True),
|
| 132 |
+
max_seqlen_q=lq,
|
| 133 |
+
max_seqlen_k=lk,
|
| 134 |
+
dropout_p=dropout_p,
|
| 135 |
+
softmax_scale=softmax_scale,
|
| 136 |
+
causal=causal,
|
| 137 |
+
window_size=window_size,
|
| 138 |
+
deterministic=deterministic).unflatten(0, (b, lq))
|
| 139 |
+
|
| 140 |
+
# output
|
| 141 |
+
return x.type(out_dtype)
|
| 142 |
+
|
| 143 |
+
|
| 144 |
+
def pos_interpolate(pos, seq_len):
|
| 145 |
+
if pos.size(1) == seq_len:
|
| 146 |
+
return pos
|
| 147 |
+
else:
|
| 148 |
+
src_grid = int(math.sqrt(pos.size(1)))
|
| 149 |
+
tar_grid = int(math.sqrt(seq_len))
|
| 150 |
+
n = pos.size(1) - src_grid * src_grid
|
| 151 |
+
return torch.cat([
|
| 152 |
+
pos[:, :n],
|
| 153 |
+
F.interpolate(
|
| 154 |
+
pos[:, n:].float().reshape(1, src_grid, src_grid, -1).permute(
|
| 155 |
+
0, 3, 1, 2),
|
| 156 |
+
size=(tar_grid, tar_grid),
|
| 157 |
+
mode='bicubic',
|
| 158 |
+
align_corners=False).flatten(2).transpose(1, 2)
|
| 159 |
+
],
|
| 160 |
+
dim=1)
|
| 161 |
+
|
| 162 |
+
class QuickGELU(nn.Module):
|
| 163 |
+
|
| 164 |
+
def forward(self, x):
|
| 165 |
+
return x * torch.sigmoid(1.702 * x)
|
| 166 |
+
|
| 167 |
+
|
| 168 |
+
class LayerNorm(nn.LayerNorm):
|
| 169 |
+
|
| 170 |
+
def forward(self, x):
|
| 171 |
+
return super().forward(x.float()).type_as(x)
|
| 172 |
+
|
| 173 |
+
|
| 174 |
+
class SelfAttention(nn.Module):
|
| 175 |
+
|
| 176 |
+
def __init__(self,
|
| 177 |
+
dim,
|
| 178 |
+
num_heads,
|
| 179 |
+
causal=False,
|
| 180 |
+
attn_dropout=0.0,
|
| 181 |
+
proj_dropout=0.0):
|
| 182 |
+
assert dim % num_heads == 0
|
| 183 |
+
super().__init__()
|
| 184 |
+
self.dim = dim
|
| 185 |
+
self.num_heads = num_heads
|
| 186 |
+
self.head_dim = dim // num_heads
|
| 187 |
+
self.causal = causal
|
| 188 |
+
self.attn_dropout = attn_dropout
|
| 189 |
+
self.proj_dropout = proj_dropout
|
| 190 |
+
|
| 191 |
+
# layers
|
| 192 |
+
self.to_qkv = nn.Linear(dim, dim * 3)
|
| 193 |
+
self.proj = nn.Linear(dim, dim)
|
| 194 |
+
|
| 195 |
+
def forward(self, x):
|
| 196 |
+
"""
|
| 197 |
+
x: [B, L, C].
|
| 198 |
+
"""
|
| 199 |
+
b, s, c, n, d = *x.size(), self.num_heads, self.head_dim
|
| 200 |
+
|
| 201 |
+
# compute query, key, value
|
| 202 |
+
q, k, v = self.to_qkv(x).view(b, s, 3, n, d).unbind(2)
|
| 203 |
+
|
| 204 |
+
# compute attention
|
| 205 |
+
p = self.attn_dropout if self.training else 0.0
|
| 206 |
+
x = flash_attention(q, k, v, dropout_p=p, causal=self.causal, version=2)
|
| 207 |
+
x = x.reshape(b, s, c)
|
| 208 |
+
|
| 209 |
+
# output
|
| 210 |
+
x = self.proj(x)
|
| 211 |
+
x = F.dropout(x, self.proj_dropout, self.training)
|
| 212 |
+
return x
|
| 213 |
+
|
| 214 |
+
|
| 215 |
+
class SwiGLU(nn.Module):
|
| 216 |
+
|
| 217 |
+
def __init__(self, dim, mid_dim):
|
| 218 |
+
super().__init__()
|
| 219 |
+
self.dim = dim
|
| 220 |
+
self.mid_dim = mid_dim
|
| 221 |
+
|
| 222 |
+
# layers
|
| 223 |
+
self.fc1 = nn.Linear(dim, mid_dim)
|
| 224 |
+
self.fc2 = nn.Linear(dim, mid_dim)
|
| 225 |
+
self.fc3 = nn.Linear(mid_dim, dim)
|
| 226 |
+
|
| 227 |
+
def forward(self, x):
|
| 228 |
+
x = F.silu(self.fc1(x)) * self.fc2(x)
|
| 229 |
+
x = self.fc3(x)
|
| 230 |
+
return x
|
| 231 |
+
|
| 232 |
+
|
| 233 |
+
class AttentionBlock(nn.Module):
|
| 234 |
+
|
| 235 |
+
def __init__(self,
|
| 236 |
+
dim,
|
| 237 |
+
mlp_ratio,
|
| 238 |
+
num_heads,
|
| 239 |
+
post_norm=False,
|
| 240 |
+
causal=False,
|
| 241 |
+
activation='quick_gelu',
|
| 242 |
+
attn_dropout=0.0,
|
| 243 |
+
proj_dropout=0.0,
|
| 244 |
+
norm_eps=1e-5):
|
| 245 |
+
assert activation in ['quick_gelu', 'gelu', 'swi_glu']
|
| 246 |
+
super().__init__()
|
| 247 |
+
self.dim = dim
|
| 248 |
+
self.mlp_ratio = mlp_ratio
|
| 249 |
+
self.num_heads = num_heads
|
| 250 |
+
self.post_norm = post_norm
|
| 251 |
+
self.causal = causal
|
| 252 |
+
self.norm_eps = norm_eps
|
| 253 |
+
|
| 254 |
+
# layers
|
| 255 |
+
self.norm1 = LayerNorm(dim, eps=norm_eps)
|
| 256 |
+
self.attn = SelfAttention(dim, num_heads, causal, attn_dropout,
|
| 257 |
+
proj_dropout)
|
| 258 |
+
self.norm2 = LayerNorm(dim, eps=norm_eps)
|
| 259 |
+
if activation == 'swi_glu':
|
| 260 |
+
self.mlp = SwiGLU(dim, int(dim * mlp_ratio))
|
| 261 |
+
else:
|
| 262 |
+
self.mlp = nn.Sequential(
|
| 263 |
+
nn.Linear(dim, int(dim * mlp_ratio)),
|
| 264 |
+
QuickGELU() if activation == 'quick_gelu' else nn.GELU(),
|
| 265 |
+
nn.Linear(int(dim * mlp_ratio), dim), nn.Dropout(proj_dropout))
|
| 266 |
+
|
| 267 |
+
def forward(self, x):
|
| 268 |
+
if self.post_norm:
|
| 269 |
+
x = x + self.norm1(self.attn(x))
|
| 270 |
+
x = x + self.norm2(self.mlp(x))
|
| 271 |
+
else:
|
| 272 |
+
x = x + self.attn(self.norm1(x))
|
| 273 |
+
x = x + self.mlp(self.norm2(x))
|
| 274 |
+
return x
|
| 275 |
+
|
| 276 |
+
|
| 277 |
+
class AttentionPool(nn.Module):
|
| 278 |
+
|
| 279 |
+
def __init__(self,
|
| 280 |
+
dim,
|
| 281 |
+
mlp_ratio,
|
| 282 |
+
num_heads,
|
| 283 |
+
activation='gelu',
|
| 284 |
+
proj_dropout=0.0,
|
| 285 |
+
norm_eps=1e-5):
|
| 286 |
+
assert dim % num_heads == 0
|
| 287 |
+
super().__init__()
|
| 288 |
+
self.dim = dim
|
| 289 |
+
self.mlp_ratio = mlp_ratio
|
| 290 |
+
self.num_heads = num_heads
|
| 291 |
+
self.head_dim = dim // num_heads
|
| 292 |
+
self.proj_dropout = proj_dropout
|
| 293 |
+
self.norm_eps = norm_eps
|
| 294 |
+
|
| 295 |
+
# layers
|
| 296 |
+
gain = 1.0 / math.sqrt(dim)
|
| 297 |
+
self.cls_embedding = nn.Parameter(gain * torch.randn(1, 1, dim))
|
| 298 |
+
self.to_q = nn.Linear(dim, dim)
|
| 299 |
+
self.to_kv = nn.Linear(dim, dim * 2)
|
| 300 |
+
self.proj = nn.Linear(dim, dim)
|
| 301 |
+
self.norm = LayerNorm(dim, eps=norm_eps)
|
| 302 |
+
self.mlp = nn.Sequential(
|
| 303 |
+
nn.Linear(dim, int(dim * mlp_ratio)),
|
| 304 |
+
QuickGELU() if activation == 'quick_gelu' else nn.GELU(),
|
| 305 |
+
nn.Linear(int(dim * mlp_ratio), dim), nn.Dropout(proj_dropout))
|
| 306 |
+
|
| 307 |
+
def forward(self, x):
|
| 308 |
+
"""
|
| 309 |
+
x: [B, L, C].
|
| 310 |
+
"""
|
| 311 |
+
b, s, c, n, d = *x.size(), self.num_heads, self.head_dim
|
| 312 |
+
|
| 313 |
+
# compute query, key, value
|
| 314 |
+
q = self.to_q(self.cls_embedding).view(1, 1, n, d).expand(b, -1, -1, -1)
|
| 315 |
+
k, v = self.to_kv(x).view(b, s, 2, n, d).unbind(2)
|
| 316 |
+
|
| 317 |
+
# compute attention
|
| 318 |
+
x = flash_attention(q, k, v, version=2)
|
| 319 |
+
x = x.reshape(b, 1, c)
|
| 320 |
+
|
| 321 |
+
# output
|
| 322 |
+
x = self.proj(x)
|
| 323 |
+
x = F.dropout(x, self.proj_dropout, self.training)
|
| 324 |
+
|
| 325 |
+
# mlp
|
| 326 |
+
x = x + self.mlp(self.norm(x))
|
| 327 |
+
return x[:, 0]
|
| 328 |
+
|
| 329 |
+
|
| 330 |
+
class VisionTransformer(nn.Module):
|
| 331 |
+
|
| 332 |
+
def __init__(self,
|
| 333 |
+
image_size=224,
|
| 334 |
+
patch_size=16,
|
| 335 |
+
dim=768,
|
| 336 |
+
mlp_ratio=4,
|
| 337 |
+
out_dim=512,
|
| 338 |
+
num_heads=12,
|
| 339 |
+
num_layers=12,
|
| 340 |
+
pool_type='token',
|
| 341 |
+
pre_norm=True,
|
| 342 |
+
post_norm=False,
|
| 343 |
+
activation='quick_gelu',
|
| 344 |
+
attn_dropout=0.0,
|
| 345 |
+
proj_dropout=0.0,
|
| 346 |
+
embedding_dropout=0.0,
|
| 347 |
+
norm_eps=1e-5):
|
| 348 |
+
if image_size % patch_size != 0:
|
| 349 |
+
print(
|
| 350 |
+
'[WARNING] image_size is not divisible by patch_size',
|
| 351 |
+
flush=True)
|
| 352 |
+
assert pool_type in ('token', 'token_fc', 'attn_pool')
|
| 353 |
+
out_dim = out_dim or dim
|
| 354 |
+
super().__init__()
|
| 355 |
+
self.image_size = image_size
|
| 356 |
+
self.patch_size = patch_size
|
| 357 |
+
self.num_patches = (image_size // patch_size)**2
|
| 358 |
+
self.dim = dim
|
| 359 |
+
self.mlp_ratio = mlp_ratio
|
| 360 |
+
self.out_dim = out_dim
|
| 361 |
+
self.num_heads = num_heads
|
| 362 |
+
self.num_layers = num_layers
|
| 363 |
+
self.pool_type = pool_type
|
| 364 |
+
self.post_norm = post_norm
|
| 365 |
+
self.norm_eps = norm_eps
|
| 366 |
+
|
| 367 |
+
# embeddings
|
| 368 |
+
gain = 1.0 / math.sqrt(dim)
|
| 369 |
+
self.patch_embedding = nn.Conv2d(
|
| 370 |
+
3,
|
| 371 |
+
dim,
|
| 372 |
+
kernel_size=patch_size,
|
| 373 |
+
stride=patch_size,
|
| 374 |
+
bias=not pre_norm)
|
| 375 |
+
if pool_type in ('token', 'token_fc'):
|
| 376 |
+
self.cls_embedding = nn.Parameter(gain * torch.randn(1, 1, dim))
|
| 377 |
+
self.pos_embedding = nn.Parameter(gain * torch.randn(
|
| 378 |
+
1, self.num_patches +
|
| 379 |
+
(1 if pool_type in ('token', 'token_fc') else 0), dim))
|
| 380 |
+
self.dropout = nn.Dropout(embedding_dropout)
|
| 381 |
+
|
| 382 |
+
# transformer
|
| 383 |
+
self.pre_norm = LayerNorm(dim, eps=norm_eps) if pre_norm else None
|
| 384 |
+
self.transformer = nn.Sequential(*[
|
| 385 |
+
AttentionBlock(dim, mlp_ratio, num_heads, post_norm, False,
|
| 386 |
+
activation, attn_dropout, proj_dropout, norm_eps)
|
| 387 |
+
for _ in range(num_layers)
|
| 388 |
+
])
|
| 389 |
+
self.post_norm = LayerNorm(dim, eps=norm_eps)
|
| 390 |
+
|
| 391 |
+
# head
|
| 392 |
+
if pool_type == 'token':
|
| 393 |
+
self.head = nn.Parameter(gain * torch.randn(dim, out_dim))
|
| 394 |
+
elif pool_type == 'token_fc':
|
| 395 |
+
self.head = nn.Linear(dim, out_dim)
|
| 396 |
+
elif pool_type == 'attn_pool':
|
| 397 |
+
self.head = AttentionPool(dim, mlp_ratio, num_heads, activation,
|
| 398 |
+
proj_dropout, norm_eps)
|
| 399 |
+
|
| 400 |
+
def forward(self, x, interpolation=False, use_31_block=False):
|
| 401 |
+
b = x.size(0)
|
| 402 |
+
|
| 403 |
+
# embeddings
|
| 404 |
+
x = self.patch_embedding(x).flatten(2).permute(0, 2, 1)
|
| 405 |
+
if self.pool_type in ('token', 'token_fc'):
|
| 406 |
+
x = torch.cat([self.cls_embedding.expand(b, -1, -1), x], dim=1)
|
| 407 |
+
if interpolation:
|
| 408 |
+
e = pos_interpolate(self.pos_embedding, x.size(1))
|
| 409 |
+
else:
|
| 410 |
+
e = self.pos_embedding
|
| 411 |
+
x = self.dropout(x + e)
|
| 412 |
+
if self.pre_norm is not None:
|
| 413 |
+
x = self.pre_norm(x)
|
| 414 |
+
|
| 415 |
+
# transformer
|
| 416 |
+
if use_31_block:
|
| 417 |
+
x = self.transformer[:-1](x)
|
| 418 |
+
return x
|
| 419 |
+
else:
|
| 420 |
+
x = self.transformer(x)
|
| 421 |
+
return x
|
| 422 |
+
|
| 423 |
+
|
| 424 |
+
class XLMRobertaWithHead(XLMRoberta):
|
| 425 |
+
|
| 426 |
+
def __init__(self, **kwargs):
|
| 427 |
+
self.out_dim = kwargs.pop('out_dim')
|
| 428 |
+
super().__init__(**kwargs)
|
| 429 |
+
|
| 430 |
+
# head
|
| 431 |
+
mid_dim = (self.dim + self.out_dim) // 2
|
| 432 |
+
self.head = nn.Sequential(
|
| 433 |
+
nn.Linear(self.dim, mid_dim, bias=False), nn.GELU(),
|
| 434 |
+
nn.Linear(mid_dim, self.out_dim, bias=False))
|
| 435 |
+
|
| 436 |
+
def forward(self, ids):
|
| 437 |
+
# xlm-roberta
|
| 438 |
+
x = super().forward(ids)
|
| 439 |
+
|
| 440 |
+
# average pooling
|
| 441 |
+
mask = ids.ne(self.pad_id).unsqueeze(-1).to(x)
|
| 442 |
+
x = (x * mask).sum(dim=1) / mask.sum(dim=1)
|
| 443 |
+
|
| 444 |
+
# head
|
| 445 |
+
x = self.head(x)
|
| 446 |
+
return x
|
| 447 |
+
|
| 448 |
+
|
| 449 |
+
class XLMRobertaCLIP(nn.Module):
|
| 450 |
+
|
| 451 |
+
def __init__(self,
|
| 452 |
+
embed_dim=1024,
|
| 453 |
+
image_size=224,
|
| 454 |
+
patch_size=14,
|
| 455 |
+
vision_dim=1280,
|
| 456 |
+
vision_mlp_ratio=4,
|
| 457 |
+
vision_heads=16,
|
| 458 |
+
vision_layers=32,
|
| 459 |
+
vision_pool='token',
|
| 460 |
+
vision_pre_norm=True,
|
| 461 |
+
vision_post_norm=False,
|
| 462 |
+
activation='gelu',
|
| 463 |
+
vocab_size=250002,
|
| 464 |
+
max_text_len=514,
|
| 465 |
+
type_size=1,
|
| 466 |
+
pad_id=1,
|
| 467 |
+
text_dim=1024,
|
| 468 |
+
text_heads=16,
|
| 469 |
+
text_layers=24,
|
| 470 |
+
text_post_norm=True,
|
| 471 |
+
text_dropout=0.1,
|
| 472 |
+
attn_dropout=0.0,
|
| 473 |
+
proj_dropout=0.0,
|
| 474 |
+
embedding_dropout=0.0,
|
| 475 |
+
norm_eps=1e-5):
|
| 476 |
+
super().__init__()
|
| 477 |
+
self.embed_dim = embed_dim
|
| 478 |
+
self.image_size = image_size
|
| 479 |
+
self.patch_size = patch_size
|
| 480 |
+
self.vision_dim = vision_dim
|
| 481 |
+
self.vision_mlp_ratio = vision_mlp_ratio
|
| 482 |
+
self.vision_heads = vision_heads
|
| 483 |
+
self.vision_layers = vision_layers
|
| 484 |
+
self.vision_pre_norm = vision_pre_norm
|
| 485 |
+
self.vision_post_norm = vision_post_norm
|
| 486 |
+
self.activation = activation
|
| 487 |
+
self.vocab_size = vocab_size
|
| 488 |
+
self.max_text_len = max_text_len
|
| 489 |
+
self.type_size = type_size
|
| 490 |
+
self.pad_id = pad_id
|
| 491 |
+
self.text_dim = text_dim
|
| 492 |
+
self.text_heads = text_heads
|
| 493 |
+
self.text_layers = text_layers
|
| 494 |
+
self.text_post_norm = text_post_norm
|
| 495 |
+
self.norm_eps = norm_eps
|
| 496 |
+
|
| 497 |
+
# models
|
| 498 |
+
self.visual = VisionTransformer(
|
| 499 |
+
image_size=image_size,
|
| 500 |
+
patch_size=patch_size,
|
| 501 |
+
dim=vision_dim,
|
| 502 |
+
mlp_ratio=vision_mlp_ratio,
|
| 503 |
+
out_dim=embed_dim,
|
| 504 |
+
num_heads=vision_heads,
|
| 505 |
+
num_layers=vision_layers,
|
| 506 |
+
pool_type=vision_pool,
|
| 507 |
+
pre_norm=vision_pre_norm,
|
| 508 |
+
post_norm=vision_post_norm,
|
| 509 |
+
activation=activation,
|
| 510 |
+
attn_dropout=attn_dropout,
|
| 511 |
+
proj_dropout=proj_dropout,
|
| 512 |
+
embedding_dropout=embedding_dropout,
|
| 513 |
+
norm_eps=norm_eps)
|
| 514 |
+
self.textual = XLMRobertaWithHead(
|
| 515 |
+
vocab_size=vocab_size,
|
| 516 |
+
max_seq_len=max_text_len,
|
| 517 |
+
type_size=type_size,
|
| 518 |
+
pad_id=pad_id,
|
| 519 |
+
dim=text_dim,
|
| 520 |
+
out_dim=embed_dim,
|
| 521 |
+
num_heads=text_heads,
|
| 522 |
+
num_layers=text_layers,
|
| 523 |
+
post_norm=text_post_norm,
|
| 524 |
+
dropout=text_dropout)
|
| 525 |
+
self.log_scale = nn.Parameter(math.log(1 / 0.07) * torch.ones([]))
|
| 526 |
+
|
| 527 |
+
def forward(self, imgs, txt_ids):
|
| 528 |
+
"""
|
| 529 |
+
imgs: [B, 3, H, W] of torch.float32.
|
| 530 |
+
- mean: [0.48145466, 0.4578275, 0.40821073]
|
| 531 |
+
- std: [0.26862954, 0.26130258, 0.27577711]
|
| 532 |
+
txt_ids: [B, L] of torch.long.
|
| 533 |
+
Encoded by data.CLIPTokenizer.
|
| 534 |
+
"""
|
| 535 |
+
xi = self.visual(imgs)
|
| 536 |
+
xt = self.textual(txt_ids)
|
| 537 |
+
return xi, xt
|
| 538 |
+
|
| 539 |
+
def param_groups(self):
|
| 540 |
+
groups = [{
|
| 541 |
+
'params': [
|
| 542 |
+
p for n, p in self.named_parameters()
|
| 543 |
+
if 'norm' in n or n.endswith('bias')
|
| 544 |
+
],
|
| 545 |
+
'weight_decay': 0.0
|
| 546 |
+
}, {
|
| 547 |
+
'params': [
|
| 548 |
+
p for n, p in self.named_parameters()
|
| 549 |
+
if not ('norm' in n or n.endswith('bias'))
|
| 550 |
+
]
|
| 551 |
+
}]
|
| 552 |
+
return groups
|
| 553 |
+
|
| 554 |
+
|
| 555 |
+
def _clip(pretrained=False,
|
| 556 |
+
pretrained_name=None,
|
| 557 |
+
model_cls=XLMRobertaCLIP,
|
| 558 |
+
return_transforms=False,
|
| 559 |
+
return_tokenizer=False,
|
| 560 |
+
tokenizer_padding='eos',
|
| 561 |
+
dtype=torch.float32,
|
| 562 |
+
device='cpu',
|
| 563 |
+
**kwargs):
|
| 564 |
+
# init a model on device
|
| 565 |
+
with torch.device(device):
|
| 566 |
+
model = model_cls(**kwargs)
|
| 567 |
+
|
| 568 |
+
# set device
|
| 569 |
+
model = model.to(dtype=dtype, device=device)
|
| 570 |
+
output = (model,)
|
| 571 |
+
|
| 572 |
+
# init transforms
|
| 573 |
+
if return_transforms:
|
| 574 |
+
# mean and std
|
| 575 |
+
if 'siglip' in pretrained_name.lower():
|
| 576 |
+
mean, std = [0.5, 0.5, 0.5], [0.5, 0.5, 0.5]
|
| 577 |
+
else:
|
| 578 |
+
mean = [0.48145466, 0.4578275, 0.40821073]
|
| 579 |
+
std = [0.26862954, 0.26130258, 0.27577711]
|
| 580 |
+
|
| 581 |
+
# transforms
|
| 582 |
+
transforms = T.Compose([
|
| 583 |
+
T.Resize((model.image_size, model.image_size),
|
| 584 |
+
interpolation=T.InterpolationMode.BICUBIC),
|
| 585 |
+
T.ToTensor(),
|
| 586 |
+
T.Normalize(mean=mean, std=std)
|
| 587 |
+
])
|
| 588 |
+
output += (transforms,)
|
| 589 |
+
return output[0] if len(output) == 1 else output
|
| 590 |
+
|
| 591 |
+
|
| 592 |
+
def clip_xlm_roberta_vit_h_14(
|
| 593 |
+
pretrained=False,
|
| 594 |
+
pretrained_name='open-clip-xlm-roberta-large-vit-huge-14',
|
| 595 |
+
**kwargs):
|
| 596 |
+
cfg = dict(
|
| 597 |
+
embed_dim=1024,
|
| 598 |
+
image_size=224,
|
| 599 |
+
patch_size=14,
|
| 600 |
+
vision_dim=1280,
|
| 601 |
+
vision_mlp_ratio=4,
|
| 602 |
+
vision_heads=16,
|
| 603 |
+
vision_layers=32,
|
| 604 |
+
vision_pool='token',
|
| 605 |
+
activation='gelu',
|
| 606 |
+
vocab_size=250002,
|
| 607 |
+
max_text_len=514,
|
| 608 |
+
type_size=1,
|
| 609 |
+
pad_id=1,
|
| 610 |
+
text_dim=1024,
|
| 611 |
+
text_heads=16,
|
| 612 |
+
text_layers=24,
|
| 613 |
+
text_post_norm=True,
|
| 614 |
+
text_dropout=0.1,
|
| 615 |
+
attn_dropout=0.0,
|
| 616 |
+
proj_dropout=0.0,
|
| 617 |
+
embedding_dropout=0.0)
|
| 618 |
+
cfg.update(**kwargs)
|
| 619 |
+
return _clip(pretrained, pretrained_name, XLMRobertaCLIP, **cfg)
|
| 620 |
+
|
| 621 |
+
|
| 622 |
+
class CLIPModel:
|
| 623 |
+
|
| 624 |
+
def __init__(self, device, checkpoint_path, tokenizer_path, dtype=torch.float16):
|
| 625 |
+
self.dtype = dtype
|
| 626 |
+
self.device = device
|
| 627 |
+
self.checkpoint_path = checkpoint_path
|
| 628 |
+
self.tokenizer_path = tokenizer_path
|
| 629 |
+
|
| 630 |
+
# init model
|
| 631 |
+
self.model, self.transforms = clip_xlm_roberta_vit_h_14(
|
| 632 |
+
pretrained=False,
|
| 633 |
+
return_transforms=True,
|
| 634 |
+
return_tokenizer=False,
|
| 635 |
+
dtype=dtype,
|
| 636 |
+
device=device)
|
| 637 |
+
self.model = self.model.eval().requires_grad_(False)
|
| 638 |
+
logging.info(f'loading {checkpoint_path}')
|
| 639 |
+
self.model.load_state_dict(
|
| 640 |
+
torch.load(checkpoint_path, map_location='cpu'))
|
| 641 |
+
|
| 642 |
+
# init tokenizer
|
| 643 |
+
self.tokenizer = HuggingfaceTokenizer(
|
| 644 |
+
name=tokenizer_path,
|
| 645 |
+
seq_len=self.model.max_text_len - 2,
|
| 646 |
+
clean='whitespace')
|
| 647 |
+
|
| 648 |
+
def visual(self, videos):
|
| 649 |
+
# preprocess, list, C 1 H W
|
| 650 |
+
size = (self.model.image_size,) * 2 # (224, 224)
|
| 651 |
+
videos = torch.cat([
|
| 652 |
+
F.interpolate(
|
| 653 |
+
u.transpose(0, 1),
|
| 654 |
+
size=size,
|
| 655 |
+
mode='bicubic',
|
| 656 |
+
align_corners=False) for u in videos
|
| 657 |
+
]) # 1 3 224 224
|
| 658 |
+
videos = self.transforms.transforms[-1](videos.mul_(0.5).add_(0.5)) # 1 3 224 224
|
| 659 |
+
|
| 660 |
+
# forward
|
| 661 |
+
with torch.cuda.amp.autocast(dtype=self.dtype):
|
| 662 |
+
out = self.model.visual(videos, use_31_block=True) # 1 257 1280
|
| 663 |
+
return out
|
infworld/clip/tokenizers.py
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024-2025 The Alibaba Wan Team Authors. All rights reserved.
|
| 2 |
+
import html
|
| 3 |
+
import string
|
| 4 |
+
|
| 5 |
+
import ftfy
|
| 6 |
+
import regex as re
|
| 7 |
+
from transformers import AutoTokenizer
|
| 8 |
+
|
| 9 |
+
__all__ = ['HuggingfaceTokenizer']
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
def basic_clean(text):
|
| 13 |
+
text = ftfy.fix_text(text)
|
| 14 |
+
text = html.unescape(html.unescape(text))
|
| 15 |
+
return text.strip()
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def whitespace_clean(text):
|
| 19 |
+
text = re.sub(r'\s+', ' ', text)
|
| 20 |
+
text = text.strip()
|
| 21 |
+
return text
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
def canonicalize(text, keep_punctuation_exact_string=None):
|
| 25 |
+
text = text.replace('_', ' ')
|
| 26 |
+
if keep_punctuation_exact_string:
|
| 27 |
+
text = keep_punctuation_exact_string.join(
|
| 28 |
+
part.translate(str.maketrans('', '', string.punctuation))
|
| 29 |
+
for part in text.split(keep_punctuation_exact_string))
|
| 30 |
+
else:
|
| 31 |
+
text = text.translate(str.maketrans('', '', string.punctuation))
|
| 32 |
+
text = text.lower()
|
| 33 |
+
text = re.sub(r'\s+', ' ', text)
|
| 34 |
+
return text.strip()
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
class HuggingfaceTokenizer:
|
| 38 |
+
|
| 39 |
+
def __init__(self, name, seq_len=None, clean=None, **kwargs):
|
| 40 |
+
assert clean in (None, 'whitespace', 'lower', 'canonicalize')
|
| 41 |
+
self.name = name
|
| 42 |
+
self.seq_len = seq_len
|
| 43 |
+
self.clean = clean
|
| 44 |
+
|
| 45 |
+
# init tokenizer
|
| 46 |
+
self.tokenizer = AutoTokenizer.from_pretrained(name, **kwargs)
|
| 47 |
+
self.vocab_size = self.tokenizer.vocab_size
|
| 48 |
+
|
| 49 |
+
def __call__(self, sequence, **kwargs):
|
| 50 |
+
return_mask = kwargs.pop('return_mask', False)
|
| 51 |
+
|
| 52 |
+
# arguments
|
| 53 |
+
_kwargs = {'return_tensors': 'pt'}
|
| 54 |
+
if self.seq_len is not None:
|
| 55 |
+
_kwargs.update({
|
| 56 |
+
'padding': 'max_length',
|
| 57 |
+
'truncation': True,
|
| 58 |
+
'max_length': self.seq_len
|
| 59 |
+
})
|
| 60 |
+
_kwargs.update(**kwargs)
|
| 61 |
+
|
| 62 |
+
# tokenization
|
| 63 |
+
if isinstance(sequence, str):
|
| 64 |
+
sequence = [sequence]
|
| 65 |
+
if self.clean:
|
| 66 |
+
sequence = [self._clean(u) for u in sequence]
|
| 67 |
+
ids = self.tokenizer(sequence, **_kwargs)
|
| 68 |
+
|
| 69 |
+
# output
|
| 70 |
+
if return_mask:
|
| 71 |
+
return ids.input_ids, ids.attention_mask
|
| 72 |
+
else:
|
| 73 |
+
return ids.input_ids
|
| 74 |
+
|
| 75 |
+
def _clean(self, text):
|
| 76 |
+
if self.clean == 'whitespace':
|
| 77 |
+
text = whitespace_clean(basic_clean(text))
|
| 78 |
+
elif self.clean == 'lower':
|
| 79 |
+
text = whitespace_clean(basic_clean(text)).lower()
|
| 80 |
+
elif self.clean == 'canonicalize':
|
| 81 |
+
text = canonicalize(basic_clean(text))
|
| 82 |
+
return text
|
infworld/clip/xlm_roberta.py
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Modified from transformers.models.xlm_roberta.modeling_xlm_roberta
|
| 2 |
+
# Copyright 2024-2025 The Alibaba Wan Team Authors. All rights reserved.
|
| 3 |
+
import torch
|
| 4 |
+
import torch.nn as nn
|
| 5 |
+
import torch.nn.functional as F
|
| 6 |
+
|
| 7 |
+
__all__ = ['XLMRoberta', 'xlm_roberta_large']
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
class SelfAttention(nn.Module):
|
| 11 |
+
|
| 12 |
+
def __init__(self, dim, num_heads, dropout=0.1, eps=1e-5):
|
| 13 |
+
assert dim % num_heads == 0
|
| 14 |
+
super().__init__()
|
| 15 |
+
self.dim = dim
|
| 16 |
+
self.num_heads = num_heads
|
| 17 |
+
self.head_dim = dim // num_heads
|
| 18 |
+
self.eps = eps
|
| 19 |
+
|
| 20 |
+
# layers
|
| 21 |
+
self.q = nn.Linear(dim, dim)
|
| 22 |
+
self.k = nn.Linear(dim, dim)
|
| 23 |
+
self.v = nn.Linear(dim, dim)
|
| 24 |
+
self.o = nn.Linear(dim, dim)
|
| 25 |
+
self.dropout = nn.Dropout(dropout)
|
| 26 |
+
|
| 27 |
+
def forward(self, x, mask):
|
| 28 |
+
"""
|
| 29 |
+
x: [B, L, C].
|
| 30 |
+
"""
|
| 31 |
+
b, s, c, n, d = *x.size(), self.num_heads, self.head_dim
|
| 32 |
+
|
| 33 |
+
# compute query, key, value
|
| 34 |
+
q = self.q(x).reshape(b, s, n, d).permute(0, 2, 1, 3)
|
| 35 |
+
k = self.k(x).reshape(b, s, n, d).permute(0, 2, 1, 3)
|
| 36 |
+
v = self.v(x).reshape(b, s, n, d).permute(0, 2, 1, 3)
|
| 37 |
+
|
| 38 |
+
# compute attention
|
| 39 |
+
p = self.dropout.p if self.training else 0.0
|
| 40 |
+
x = F.scaled_dot_product_attention(q, k, v, mask, p)
|
| 41 |
+
x = x.permute(0, 2, 1, 3).reshape(b, s, c)
|
| 42 |
+
|
| 43 |
+
# output
|
| 44 |
+
x = self.o(x)
|
| 45 |
+
x = self.dropout(x)
|
| 46 |
+
return x
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
class AttentionBlock(nn.Module):
|
| 50 |
+
|
| 51 |
+
def __init__(self, dim, num_heads, post_norm, dropout=0.1, eps=1e-5):
|
| 52 |
+
super().__init__()
|
| 53 |
+
self.dim = dim
|
| 54 |
+
self.num_heads = num_heads
|
| 55 |
+
self.post_norm = post_norm
|
| 56 |
+
self.eps = eps
|
| 57 |
+
|
| 58 |
+
# layers
|
| 59 |
+
self.attn = SelfAttention(dim, num_heads, dropout, eps)
|
| 60 |
+
self.norm1 = nn.LayerNorm(dim, eps=eps)
|
| 61 |
+
self.ffn = nn.Sequential(
|
| 62 |
+
nn.Linear(dim, dim * 4), nn.GELU(), nn.Linear(dim * 4, dim),
|
| 63 |
+
nn.Dropout(dropout))
|
| 64 |
+
self.norm2 = nn.LayerNorm(dim, eps=eps)
|
| 65 |
+
|
| 66 |
+
def forward(self, x, mask):
|
| 67 |
+
if self.post_norm:
|
| 68 |
+
x = self.norm1(x + self.attn(x, mask))
|
| 69 |
+
x = self.norm2(x + self.ffn(x))
|
| 70 |
+
else:
|
| 71 |
+
x = x + self.attn(self.norm1(x), mask)
|
| 72 |
+
x = x + self.ffn(self.norm2(x))
|
| 73 |
+
return x
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
class XLMRoberta(nn.Module):
|
| 77 |
+
"""
|
| 78 |
+
XLMRobertaModel with no pooler and no LM head.
|
| 79 |
+
"""
|
| 80 |
+
|
| 81 |
+
def __init__(self,
|
| 82 |
+
vocab_size=250002,
|
| 83 |
+
max_seq_len=514,
|
| 84 |
+
type_size=1,
|
| 85 |
+
pad_id=1,
|
| 86 |
+
dim=1024,
|
| 87 |
+
num_heads=16,
|
| 88 |
+
num_layers=24,
|
| 89 |
+
post_norm=True,
|
| 90 |
+
dropout=0.1,
|
| 91 |
+
eps=1e-5):
|
| 92 |
+
super().__init__()
|
| 93 |
+
self.vocab_size = vocab_size
|
| 94 |
+
self.max_seq_len = max_seq_len
|
| 95 |
+
self.type_size = type_size
|
| 96 |
+
self.pad_id = pad_id
|
| 97 |
+
self.dim = dim
|
| 98 |
+
self.num_heads = num_heads
|
| 99 |
+
self.num_layers = num_layers
|
| 100 |
+
self.post_norm = post_norm
|
| 101 |
+
self.eps = eps
|
| 102 |
+
|
| 103 |
+
# embeddings
|
| 104 |
+
self.token_embedding = nn.Embedding(vocab_size, dim, padding_idx=pad_id)
|
| 105 |
+
self.type_embedding = nn.Embedding(type_size, dim)
|
| 106 |
+
self.pos_embedding = nn.Embedding(max_seq_len, dim, padding_idx=pad_id)
|
| 107 |
+
self.dropout = nn.Dropout(dropout)
|
| 108 |
+
|
| 109 |
+
# blocks
|
| 110 |
+
self.blocks = nn.ModuleList([
|
| 111 |
+
AttentionBlock(dim, num_heads, post_norm, dropout, eps)
|
| 112 |
+
for _ in range(num_layers)
|
| 113 |
+
])
|
| 114 |
+
|
| 115 |
+
# norm layer
|
| 116 |
+
self.norm = nn.LayerNorm(dim, eps=eps)
|
| 117 |
+
|
| 118 |
+
def forward(self, ids):
|
| 119 |
+
"""
|
| 120 |
+
ids: [B, L] of torch.LongTensor.
|
| 121 |
+
"""
|
| 122 |
+
b, s = ids.shape
|
| 123 |
+
mask = ids.ne(self.pad_id).long()
|
| 124 |
+
|
| 125 |
+
# embeddings
|
| 126 |
+
x = self.token_embedding(ids) + \
|
| 127 |
+
self.type_embedding(torch.zeros_like(ids)) + \
|
| 128 |
+
self.pos_embedding(self.pad_id + torch.cumsum(mask, dim=1) * mask)
|
| 129 |
+
if self.post_norm:
|
| 130 |
+
x = self.norm(x)
|
| 131 |
+
x = self.dropout(x)
|
| 132 |
+
|
| 133 |
+
# blocks
|
| 134 |
+
mask = torch.where(
|
| 135 |
+
mask.view(b, 1, 1, s).gt(0), 0.0,
|
| 136 |
+
torch.finfo(x.dtype).min)
|
| 137 |
+
for block in self.blocks:
|
| 138 |
+
x = block(x, mask)
|
| 139 |
+
|
| 140 |
+
# output
|
| 141 |
+
if not self.post_norm:
|
| 142 |
+
x = self.norm(x)
|
| 143 |
+
return x
|
| 144 |
+
|
| 145 |
+
|
| 146 |
+
def xlm_roberta_large(pretrained=False,
|
| 147 |
+
return_tokenizer=False,
|
| 148 |
+
device='cpu',
|
| 149 |
+
**kwargs):
|
| 150 |
+
"""
|
| 151 |
+
XLMRobertaLarge adapted from Huggingface.
|
| 152 |
+
"""
|
| 153 |
+
# params
|
| 154 |
+
cfg = dict(
|
| 155 |
+
vocab_size=250002,
|
| 156 |
+
max_seq_len=514,
|
| 157 |
+
type_size=1,
|
| 158 |
+
pad_id=1,
|
| 159 |
+
dim=1024,
|
| 160 |
+
num_heads=16,
|
| 161 |
+
num_layers=24,
|
| 162 |
+
post_norm=True,
|
| 163 |
+
dropout=0.1,
|
| 164 |
+
eps=1e-5)
|
| 165 |
+
cfg.update(**kwargs)
|
| 166 |
+
|
| 167 |
+
# init a model on device
|
| 168 |
+
with torch.device(device):
|
| 169 |
+
model = XLMRoberta(**cfg)
|
| 170 |
+
return model
|
infworld/configs/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
# infworld/configs package
|
infworld/configs/bucket_config.py
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
ASPECT_RATIO_200 = {
|
| 2 |
+
'0.23': ([96, 416], 1), '0.40': ([128, 320], 1), '0.62': ([160, 256], 1), '0.86': ([192, 224], 1),
|
| 3 |
+
'1.17': ([224, 192], 1), '1.60': ([256, 160], 1), '2.25': ([288, 128], 1), '2.50': ([320, 128], 1),
|
| 4 |
+
'2.75': ([352, 128], 1), '4.00': ([384, 96], 1)
|
| 5 |
+
}
|
| 6 |
+
|
| 7 |
+
ASPECT_RATIO_256 = {
|
| 8 |
+
'0.25': ([128, 512], 1), '0.38': ([160, 416], 1), '0.55': ([192, 352], 1), '0.78': ([224, 288], 1),
|
| 9 |
+
'1.00': ([256, 256], 1), '1.29': ([288, 224], 1), '1.67': ([320, 192], 1), '1.83': ([352, 192], 1),
|
| 10 |
+
'2.40': ([384, 160], 1), '2.60': ([416, 160], 1), '2.80': ([448, 160], 1), '3.75': ([480, 128], 1),
|
| 11 |
+
'4.00': ([512, 128], 1)
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
ASPECT_RATIO_256_SQUARE = {
|
| 15 |
+
'1.00': ([256, 256], 1),
|
| 16 |
+
}
|
| 17 |
+
|
| 18 |
+
ASPECT_RATIO_320 = {
|
| 19 |
+
'0.26': ([160, 608], 1), '0.38': ([192, 512], 1), '0.50': ([224, 448], 1), '0.67': ([256, 384], 1),
|
| 20 |
+
'0.82': ([288, 352], 1), '1.00': ([320, 320], 1), '1.22': ([352, 288], 1), '1.50': ([384, 256], 1),
|
| 21 |
+
'1.86': ([416, 224], 1), '2.00': ([448, 224], 1), '2.50': ([480, 192], 1), '2.83': ([544, 192], 1),
|
| 22 |
+
'3.60': ([576, 160], 1), '3.80': ([608, 160], 1), '4.00': ([640, 160], 1)
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
ASPECT_RATIO_400 = {
|
| 26 |
+
'0.23': ([192, 832], 1), '0.32': ([224, 704], 1), '0.40': ([256, 640], 1), '0.53': ([288, 544], 1),
|
| 27 |
+
'0.62': ([320, 512], 1), '0.79': ([352, 448], 1), '0.92': ([384, 416], 1), '1.08': ([416, 384], 1),
|
| 28 |
+
'1.27': ([448, 352], 1), '1.50': ([480, 320], 1), '1.60': ([512, 320], 1), '1.89': ([544, 288], 1),
|
| 29 |
+
'2.00': ([576, 288], 1), '2.38': ([608, 256], 1), '2.50': ([640, 256], 1), '3.00': ([672, 224], 1),
|
| 30 |
+
'3.14': ([704, 224], 1), '3.43': ([768, 224], 1), '4.17': ([800, 192], 1)
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
ASPECT_RATIO_400_F64 = {
|
| 34 |
+
'0.23': ([192, 832], 1), '0.40': ([256, 640], 1), '0.62': ([320, 512], 1), '0.86': ([384, 448], 1),
|
| 35 |
+
'1.17': ([448, 384], 1), '1.60': ([512, 320], 1), '2.25': ([576, 256], 1), '2.50': ([640, 256], 1),
|
| 36 |
+
'2.75': ([704, 256], 1), '4.00': ([768, 192], 1)
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
ASPECT_RATIO_400_F64_SQUARE = {
|
| 40 |
+
'0.23': ([192, 832], 1), '0.40': ([256, 640], 1), '0.62': ([320, 512], 1), '0.86': ([384, 448], 1), '1.0': ([448, 448], 1),
|
| 41 |
+
'1.17': ([448, 384], 1), '1.60': ([512, 320], 1), '2.25': ([576, 256], 1), '2.50': ([640, 256], 1),
|
| 42 |
+
'2.75': ([704, 256], 1), '4.00': ([768, 192], 1)
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
ASPECT_RATIO_512x512 = {
|
| 46 |
+
'1.0': ([512, 512], 1),
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
ASPECT_RATIO_512 = {
|
| 50 |
+
'0.25': ([256, 1024], 1), '0.26': ([256, 992], 1), '0.27': ([256, 960], 1), '0.28': ([256, 928], 1),
|
| 51 |
+
'0.32': ([288, 896], 1), '0.33': ([288, 864], 1), '0.35': ([288, 832], 1), '0.4': ([320, 800], 1),
|
| 52 |
+
'0.42': ([320, 768], 1), '0.48': ([352, 736], 1), '0.5': ([352, 704], 1), '0.52': ([352, 672], 1),
|
| 53 |
+
'0.57': ([384, 672], 1), '0.6': ([384, 640], 1), '0.68': ([416, 608], 1), '0.72': ([416, 576], 1),
|
| 54 |
+
'0.78': ([448, 576], 1), '0.82': ([448, 544], 1), '0.88': ([480, 544], 1), '0.94': ([480, 512], 1),
|
| 55 |
+
'1.0': ([512, 512], 1), '1.07': ([512, 480], 1), '1.13': ([544, 480], 1), '1.21': ([544, 448], 1),
|
| 56 |
+
'1.29': ([576, 448], 1), '1.38': ([576, 416], 1), '1.46': ([608, 416], 1), '1.67': ([640, 384], 1),
|
| 57 |
+
'1.75': ([672, 384], 1), '2.0': ([704, 352], 1), '2.09': ([736, 352], 1), '2.4': ([768, 320], 1),
|
| 58 |
+
'2.5': ([800, 320], 1), '2.89': ([832, 288], 1), '3.0': ([864, 288], 1), '3.11': ([896, 288], 1),
|
| 59 |
+
'3.62': ([928, 256], 1), '3.75': ([960, 256], 1), '3.88': ([992, 256], 1), '4.0': ([1024, 256], 1),
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
# ASPECT_RATIO_627 = {
|
| 63 |
+
# '0.26': ([320, 1216], 1), '0.31': ([352, 1120], 1), '0.38': ([384, 1024], 1), '0.43': ([416, 960], 1),
|
| 64 |
+
# '0.52': ([448, 864], 1), '0.58': ([448, 768], 1), '0.67': ([512, 768], 1), '0.74': ([544, 736], 1),
|
| 65 |
+
# '0.86': ([576, 672], 1), '0.95': ([608, 640], 1), '1.05': ([640, 608], 1), '1.17': ([672, 576], 1),
|
| 66 |
+
# '1.29': ([704, 544], 1), '1.35': ([736, 544], 1), '1.50': ([768, 512], 1), '1.67': ([800, 480], 1),
|
| 67 |
+
# '1.73': ([832, 480], 1), '2.00': ([896, 448], 1), '2.31': ([960, 416], 1), '2.58': ([992, 384], 1),
|
| 68 |
+
# '2.75': ([1056, 384], 1), '3.09': ([1088, 352], 1), '3.70': ([1184, 320], 1), '3.80': ([1216, 320], 1),
|
| 69 |
+
# '3.90': ([1248, 320], 1), '4.00': ([1280, 320], 1)
|
| 70 |
+
# }
|
| 71 |
+
|
| 72 |
+
ASPECT_RATIO_627 = {
|
| 73 |
+
'0.26': ([320, 1216], 1), '0.31': ([352, 1120], 1), '0.38': ([384, 1024], 1), '0.43': ([416, 960], 1),
|
| 74 |
+
'0.52': ([448, 864], 1), '0.58': ([480, 832], 1), '0.67': ([512, 768], 1), '0.74': ([544, 736], 1),
|
| 75 |
+
'0.86': ([576, 672], 1), '0.95': ([608, 640], 1), '1.05': ([640, 608], 1), '1.17': ([672, 576], 1),
|
| 76 |
+
'1.29': ([704, 544], 1), '1.35': ([736, 544], 1), '1.50': ([768, 512], 1), '1.67': ([800, 480], 1),
|
| 77 |
+
'1.73': ([832, 480], 1), '2.00': ([896, 448], 1), '2.31': ([960, 416], 1), '2.58': ([992, 384], 1),
|
| 78 |
+
'2.75': ([1056, 384], 1), '3.09': ([1088, 352], 1), '3.70': ([1184, 320], 1), '3.80': ([1216, 320], 1),
|
| 79 |
+
'3.90': ([1248, 320], 1), '4.00': ([1280, 320], 1)
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
ASPECT_RATIO_627_F64 = {
|
| 84 |
+
'0.26': ([320, 1216], 1), '0.38': ([384, 1024], 1), '0.50': ([448, 896], 1), '0.67': ([512, 768], 1),
|
| 85 |
+
'0.82': ([576, 704], 1), '1.00': ([640, 640], 1), '1.22': ([704, 576], 1), '1.50': ([768, 512], 1),
|
| 86 |
+
'1.86': ([832, 448], 1), '2.00': ([896, 448], 1), '2.50': ([960, 384], 1), '2.83': ([1088, 384], 1),
|
| 87 |
+
'3.60': ([1152, 320], 1), '3.80': ([1216, 320], 1), '4.00': ([1280, 320], 1)}
|
| 88 |
+
|
| 89 |
+
ASPECT_RATIO_960 = {
|
| 90 |
+
'0.25': ([480, 1920], 1), '0.29': ([512, 1792], 1), '0.32': ([544, 1696], 1), '0.36': ([576, 1600], 1),
|
| 91 |
+
'0.40': ([608, 1504], 1), '0.49': ([672, 1376], 1), '0.54': ([704, 1312], 1), '0.59': ([736, 1248], 1),
|
| 92 |
+
'0.69': ([800, 1152], 1), '0.74': ([832, 1120], 1), '0.82': ([864, 1056], 1), '0.88': ([896, 1024], 1),
|
| 93 |
+
'0.94': ([928, 992], 1), '1.00': ([960, 960], 1), '1.07': ([992, 928], 1), '1.14': ([1024, 896], 1),
|
| 94 |
+
'1.22': ([1056, 864], 1), '1.31': ([1088, 832], 1), '1.35': ([1120, 832], 1), '1.44': ([1152, 800], 1),
|
| 95 |
+
'1.70': ([1248, 736], 1), '2.00': ([1344, 672], 1), '2.05': ([1376, 672], 1), '2.47': ([1504, 608], 1),
|
| 96 |
+
'2.53': ([1536, 608], 1), '2.83': ([1632, 576], 1), '3.06': ([1664, 544], 1), '3.12': ([1696, 544], 1),
|
| 97 |
+
'3.62': ([1856, 512], 1), '3.93': ([1888, 480], 1), '4.00': ([1920, 480], 1)
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
+
ASPECT_RATIO_960_F64 = {
|
| 101 |
+
'0.22': ([448, 2048], 1), '0.29': ([512, 1792], 1), '0.36': ([576, 1600], 1), '0.45': ([640, 1408], 1),
|
| 102 |
+
'0.55': ([704, 1280], 1), '0.63': ([768, 1216], 1), '0.76': ([832, 1088], 1), '0.88': ([896, 1024], 1),
|
| 103 |
+
'1.00': ([960, 960], 1), '1.14': ([1024, 896], 1), '1.31': ([1088, 832], 1), '1.50': ([1152, 768], 1),
|
| 104 |
+
'1.58': ([1216, 768], 1), '1.82': ([1280, 704], 1), '1.91': ([1344, 704], 1), '2.20': ([1408, 640], 1),
|
| 105 |
+
'2.30': ([1472, 640], 1), '2.67': ([1536, 576], 1), '2.89': ([1664, 576], 1), '3.62': ([1856, 512], 1),
|
| 106 |
+
'3.75': ([1920, 512], 1)}
|
| 107 |
+
|
| 108 |
+
|
| 109 |
+
ASPECT_RATIO_1440_F64 = {
|
| 110 |
+
'0.24': ([704, 2944], 1), '0.29': ([768, 2688], 1), '0.33': ([832, 2496], 1), '0.39': ([896, 2304], 1),
|
| 111 |
+
'0.44': ([960, 2176], 1), '0.50': ([1024, 2048], 1), '0.57': ([1088, 1920], 1), '0.70': ([1216, 1728], 1),
|
| 112 |
+
'0.80': ([1280, 1600], 1), '0.88': ([1344, 1536], 1), '0.96': ([1408, 1472], 1), '1.05': ([1472, 1408], 1),
|
| 113 |
+
'1.14': ([1536, 1344], 1), '1.25': ([1600, 1280], 1), '1.37': ([1664, 1216], 1), '1.42': ([1728, 1216], 1),
|
| 114 |
+
'1.71': ([1856, 1088], 1), '1.76': ([1920, 1088], 1), '2.00': ([2048, 1024], 1), '2.50': ([2240, 896], 1),
|
| 115 |
+
'2.92': ([2432, 832], 1), '3.00': ([2496, 832], 1), '3.08': ([2560, 832], 1), '3.58': ([2752, 768], 1),
|
| 116 |
+
'3.67': ([2816, 768], 1), '4.09': ([2880, 704], 1)
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
# this func is only used for bucket config generation
|
| 120 |
+
def find_hw(target_area, target_ratio, factor=32):
|
| 121 |
+
|
| 122 |
+
min_side = factor
|
| 123 |
+
max_side = target_area // factor // factor * factor + factor
|
| 124 |
+
min_error = float('inf')
|
| 125 |
+
best_solution = None
|
| 126 |
+
|
| 127 |
+
for height in range(max_side, min_side-1, -factor):
|
| 128 |
+
width = round(target_area / height / factor) * factor
|
| 129 |
+
if width < min_side:
|
| 130 |
+
continue
|
| 131 |
+
|
| 132 |
+
ratio = height / width
|
| 133 |
+
|
| 134 |
+
ratio_error = abs(ratio - target_ratio)
|
| 135 |
+
|
| 136 |
+
if ratio_error < min_error:
|
| 137 |
+
min_error = ratio_error
|
| 138 |
+
best_solution = (height, width)
|
| 139 |
+
|
| 140 |
+
if ratio_error == 0:
|
| 141 |
+
break
|
| 142 |
+
|
| 143 |
+
return best_solution
|
| 144 |
+
|
| 145 |
+
if __name__ == "__main__":
|
| 146 |
+
ratios = list(map(float, ASPECT_RATIO_512.keys()))
|
| 147 |
+
res = {}
|
| 148 |
+
for ratio in ratios:
|
| 149 |
+
h,w = find_hw(400**2, ratio, 64)
|
| 150 |
+
res[f"{h/w:.2f}"] = ([h,w], 1)
|
| 151 |
+
print((h*w)**0.5)
|
| 152 |
+
|
| 153 |
+
print(res)
|
| 154 |
+
|
| 155 |
+
|
infworld/context_parallel/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
# infworld/context_parallel package
|
infworld/context_parallel/context_parallel_util.py
ADDED
|
@@ -0,0 +1,405 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import math
|
| 3 |
+
import random
|
| 4 |
+
import argparse
|
| 5 |
+
import datetime
|
| 6 |
+
import logging
|
| 7 |
+
import inspect
|
| 8 |
+
import subprocess
|
| 9 |
+
|
| 10 |
+
import torch
|
| 11 |
+
import torch.distributed as dist
|
| 12 |
+
from torch.distributed.device_mesh import init_device_mesh
|
| 13 |
+
from einops import rearrange, repeat
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
dp_size = None
|
| 17 |
+
cp_size = None
|
| 18 |
+
dp_group = None
|
| 19 |
+
cp_group = None
|
| 20 |
+
cp_stream = None
|
| 21 |
+
dp_ranks = None
|
| 22 |
+
cp_ranks = None
|
| 23 |
+
dp_rank = None
|
| 24 |
+
cp_rank = None
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
def init_context_parallel(context_parallel_size: int = 1,
|
| 28 |
+
global_rank: int = 1,
|
| 29 |
+
world_size: int = 1,):
|
| 30 |
+
|
| 31 |
+
global dp_size
|
| 32 |
+
global cp_size
|
| 33 |
+
global dp_group
|
| 34 |
+
global cp_group
|
| 35 |
+
global dp_ranks
|
| 36 |
+
global cp_ranks
|
| 37 |
+
global dp_rank
|
| 38 |
+
global cp_rank
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
if world_size%context_parallel_size != 0:
|
| 42 |
+
raise RuntimeError(f'world_size {world_size} must be multiple of context_parallel_size {context_parallel_size}!!!')
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
cp_size = context_parallel_size
|
| 46 |
+
dp_size = world_size//context_parallel_size
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
print(f'[rank {global_rank}] init_device_mesh [dp_size x cp_size]: [{dp_size} x {cp_size}]')
|
| 50 |
+
|
| 51 |
+
mesh_2d = init_device_mesh("cuda", (dp_size, cp_size), mesh_dim_names=("dp", "cp"))
|
| 52 |
+
|
| 53 |
+
print(f'[rank {global_rank}] mesh_2d: {mesh_2d}')
|
| 54 |
+
|
| 55 |
+
dp_group = mesh_2d.get_group(mesh_dim="dp")
|
| 56 |
+
cp_group = mesh_2d.get_group(mesh_dim="cp")
|
| 57 |
+
|
| 58 |
+
dp_ranks = torch.distributed.get_process_group_ranks(dp_group)
|
| 59 |
+
cp_ranks = torch.distributed.get_process_group_ranks(cp_group)
|
| 60 |
+
|
| 61 |
+
dp_rank = dist.get_rank(group=dp_group)
|
| 62 |
+
cp_rank = dist.get_rank(group=cp_group)
|
| 63 |
+
|
| 64 |
+
global_rank_1 = torch.distributed.get_rank()
|
| 65 |
+
print(f'[rank {global_rank_1}] [dp_rank, cp_rank]: [{dp_rank}, {cp_rank}], dp_ranks: {dp_ranks}, cp_ranks: {cp_ranks}')
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
def get_cp_size():
|
| 69 |
+
|
| 70 |
+
global cp_size
|
| 71 |
+
return cp_size
|
| 72 |
+
|
| 73 |
+
def get_dp_size():
|
| 74 |
+
|
| 75 |
+
global dp_size
|
| 76 |
+
return dp_size
|
| 77 |
+
|
| 78 |
+
def get_cp_stream():
|
| 79 |
+
|
| 80 |
+
global cp_stream
|
| 81 |
+
if cp_stream == None:
|
| 82 |
+
cp_stream = torch.cuda.Stream()
|
| 83 |
+
|
| 84 |
+
return cp_stream
|
| 85 |
+
|
| 86 |
+
def get_dp_group():
|
| 87 |
+
|
| 88 |
+
global dp_group
|
| 89 |
+
return dp_group
|
| 90 |
+
|
| 91 |
+
def get_cp_group():
|
| 92 |
+
|
| 93 |
+
global cp_group
|
| 94 |
+
return cp_group
|
| 95 |
+
|
| 96 |
+
|
| 97 |
+
def get_dp_rank():
|
| 98 |
+
|
| 99 |
+
global dp_rank
|
| 100 |
+
global cp_rank
|
| 101 |
+
|
| 102 |
+
return dp_rank
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
def get_cp_rank():
|
| 106 |
+
|
| 107 |
+
global dp_rank
|
| 108 |
+
global cp_rank
|
| 109 |
+
|
| 110 |
+
return cp_rank
|
| 111 |
+
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
def get_cp_rank_list():
|
| 115 |
+
|
| 116 |
+
global cp_ranks
|
| 117 |
+
if cp_ranks == None:
|
| 118 |
+
cp_ranks = torch.distributed.get_process_group_ranks(cp_group)
|
| 119 |
+
return cp_ranks
|
| 120 |
+
|
| 121 |
+
|
| 122 |
+
def cp_broadcast(tensor, cp_index=0):
|
| 123 |
+
|
| 124 |
+
global dp_group
|
| 125 |
+
global cp_group
|
| 126 |
+
|
| 127 |
+
cp_ranks = get_cp_rank_list()
|
| 128 |
+
|
| 129 |
+
torch.distributed.broadcast(tensor, cp_ranks[cp_index], group=cp_group)
|
| 130 |
+
|
| 131 |
+
|
| 132 |
+
|
| 133 |
+
|
| 134 |
+
def cp_broadcast_objects(tensor):
|
| 135 |
+
|
| 136 |
+
global dp_group
|
| 137 |
+
global cp_group
|
| 138 |
+
|
| 139 |
+
raise NotImplementedError("cp_broadcast_objects method is not yet implemented!!!")
|
| 140 |
+
|
| 141 |
+
|
| 142 |
+
|
| 143 |
+
|
| 144 |
+
def split_tensor_in_cp(input, seq_dim):
|
| 145 |
+
|
| 146 |
+
global cp_size
|
| 147 |
+
|
| 148 |
+
seq_size = input.shape[seq_dim]
|
| 149 |
+
|
| 150 |
+
if seq_size%cp_size != 0:
|
| 151 |
+
raise RuntimeError(f'seq_length {seq_size} in dim {seq_dim} must be multiple of cp_size {cp_size}!!!')
|
| 152 |
+
|
| 153 |
+
split_seq_size = seq_size//cp_size
|
| 154 |
+
|
| 155 |
+
tensor_splits = input.split(split_seq_size, dim=seq_dim)
|
| 156 |
+
|
| 157 |
+
cp_rank = get_cp_rank()
|
| 158 |
+
|
| 159 |
+
split_tensor = tensor_splits[cp_rank]
|
| 160 |
+
|
| 161 |
+
return split_tensor
|
| 162 |
+
|
| 163 |
+
|
| 164 |
+
|
| 165 |
+
|
| 166 |
+
|
| 167 |
+
class GatherFunction(torch.autograd.Function):
|
| 168 |
+
|
| 169 |
+
@staticmethod
|
| 170 |
+
def forward(ctx, input, process_group, seq_dim, frames):
|
| 171 |
+
ctx.cp_group = process_group
|
| 172 |
+
ctx.seq_dim = seq_dim
|
| 173 |
+
ctx.frames = frames
|
| 174 |
+
ctx.cp_size = get_cp_size()
|
| 175 |
+
|
| 176 |
+
input = rearrange(input, "B (T S) C -> B T S C", T=frames)
|
| 177 |
+
|
| 178 |
+
with torch.no_grad():
|
| 179 |
+
|
| 180 |
+
input = input.contiguous()
|
| 181 |
+
|
| 182 |
+
output_tensors = [torch.zeros_like(input) for _ in range(ctx.cp_size)]
|
| 183 |
+
|
| 184 |
+
dist.all_gather(output_tensors, input, group=ctx.cp_group)
|
| 185 |
+
|
| 186 |
+
output_tensor = torch.cat(output_tensors, dim=seq_dim)
|
| 187 |
+
|
| 188 |
+
|
| 189 |
+
|
| 190 |
+
output_tensor = rearrange(output_tensor, "B T S C -> B (T S) C", T=frames)
|
| 191 |
+
|
| 192 |
+
|
| 193 |
+
return output_tensor
|
| 194 |
+
|
| 195 |
+
@staticmethod
|
| 196 |
+
def backward(ctx, grad_output):
|
| 197 |
+
|
| 198 |
+
|
| 199 |
+
with torch.no_grad():
|
| 200 |
+
|
| 201 |
+
grad_output = grad_output * ctx.cp_size
|
| 202 |
+
|
| 203 |
+
grad_output = rearrange(grad_output, "B (T S) C -> B T S C", T=ctx.frames)
|
| 204 |
+
|
| 205 |
+
grad_input = split_tensor_in_cp(grad_output, ctx.seq_dim)
|
| 206 |
+
|
| 207 |
+
grad_input = rearrange(grad_input, "B T S C -> B (T S) C", T=ctx.frames)
|
| 208 |
+
|
| 209 |
+
|
| 210 |
+
return grad_input, None, None, None
|
| 211 |
+
|
| 212 |
+
|
| 213 |
+
|
| 214 |
+
|
| 215 |
+
class SplitFunction(torch.autograd.Function):
|
| 216 |
+
|
| 217 |
+
@staticmethod
|
| 218 |
+
def forward(ctx, input, process_group, seq_dim):
|
| 219 |
+
ctx.cp_group = process_group
|
| 220 |
+
ctx.seq_dim = seq_dim
|
| 221 |
+
ctx.cp_size = get_cp_size()
|
| 222 |
+
|
| 223 |
+
output_tensor = split_tensor_in_cp(input, ctx.seq_dim)
|
| 224 |
+
|
| 225 |
+
return output_tensor
|
| 226 |
+
|
| 227 |
+
@staticmethod
|
| 228 |
+
def backward(ctx, grad_output):
|
| 229 |
+
|
| 230 |
+
|
| 231 |
+
with torch.no_grad():
|
| 232 |
+
|
| 233 |
+
|
| 234 |
+
grad_output = grad_output / ctx.cp_size
|
| 235 |
+
|
| 236 |
+
output_tensors = [torch.zeros_like(grad_output) for _ in range(ctx.cp_size)]
|
| 237 |
+
|
| 238 |
+
dist.all_gather(output_tensors, grad_output, group=ctx.cp_group)
|
| 239 |
+
|
| 240 |
+
grad_input = torch.cat(output_tensors, dim=ctx.seq_dim)
|
| 241 |
+
|
| 242 |
+
|
| 243 |
+
return grad_input, None, None
|
| 244 |
+
|
| 245 |
+
|
| 246 |
+
|
| 247 |
+
def gather_cp(input, frames):
|
| 248 |
+
|
| 249 |
+
cp_process_group = get_cp_group()
|
| 250 |
+
|
| 251 |
+
output_tensor = GatherFunction.apply(input, cp_process_group, 2, frames)
|
| 252 |
+
|
| 253 |
+
return output_tensor
|
| 254 |
+
|
| 255 |
+
|
| 256 |
+
def split_cp(input, seq_dim):
|
| 257 |
+
|
| 258 |
+
cp_process_group = get_cp_group()
|
| 259 |
+
|
| 260 |
+
output_tensor = SplitFunction.apply(input, cp_process_group, seq_dim)
|
| 261 |
+
|
| 262 |
+
return output_tensor
|
| 263 |
+
|
| 264 |
+
|
| 265 |
+
|
| 266 |
+
|
| 267 |
+
class ReduceFunction(torch.autograd.Function):
|
| 268 |
+
|
| 269 |
+
@staticmethod
|
| 270 |
+
def forward(ctx, input, process_group):
|
| 271 |
+
ctx.cp_group = process_group
|
| 272 |
+
|
| 273 |
+
output = input.detach().clone()
|
| 274 |
+
|
| 275 |
+
dist.all_reduce(output, group=ctx.cp_group)
|
| 276 |
+
|
| 277 |
+
return output
|
| 278 |
+
|
| 279 |
+
@staticmethod
|
| 280 |
+
def backward(ctx, grad_output):
|
| 281 |
+
|
| 282 |
+
grad_input = grad_output.detach().clone()
|
| 283 |
+
|
| 284 |
+
return grad_input, None
|
| 285 |
+
|
| 286 |
+
|
| 287 |
+
|
| 288 |
+
class ReplicateFunction(torch.autograd.Function):
|
| 289 |
+
|
| 290 |
+
@staticmethod
|
| 291 |
+
def forward(ctx, input, process_group):
|
| 292 |
+
ctx.cp_group = process_group
|
| 293 |
+
|
| 294 |
+
output = input.detach().clone()
|
| 295 |
+
|
| 296 |
+
|
| 297 |
+
return output
|
| 298 |
+
|
| 299 |
+
@staticmethod
|
| 300 |
+
def backward(ctx, grad_output):
|
| 301 |
+
|
| 302 |
+
grad_input = grad_output.detach().clone()
|
| 303 |
+
|
| 304 |
+
dist.all_reduce(grad_input, group=ctx.cp_group)
|
| 305 |
+
|
| 306 |
+
|
| 307 |
+
return grad_input, None
|
| 308 |
+
|
| 309 |
+
|
| 310 |
+
def reduce_cp(partial_sum, partial_square_sum):
|
| 311 |
+
|
| 312 |
+
cp_process_group = get_cp_group()
|
| 313 |
+
|
| 314 |
+
all_sum = ReduceFunction.apply(partial_sum, cp_process_group)
|
| 315 |
+
all_square_sum = ReduceFunction.apply(partial_square_sum, cp_process_group)
|
| 316 |
+
|
| 317 |
+
return all_sum, all_square_sum
|
| 318 |
+
|
| 319 |
+
|
| 320 |
+
def replicate_cp(all_mean, all_var):
|
| 321 |
+
|
| 322 |
+
cp_process_group = get_cp_group()
|
| 323 |
+
|
| 324 |
+
all_mean = ReplicateFunction.apply(all_mean, cp_process_group)
|
| 325 |
+
all_var = ReplicateFunction.apply(all_var, cp_process_group)
|
| 326 |
+
|
| 327 |
+
return all_mean, all_var
|
| 328 |
+
|
| 329 |
+
|
| 330 |
+
|
| 331 |
+
def _all_to_all_func(input_, world_size, group, scatter_dim, gather_dim):
|
| 332 |
+
input_list = [t.contiguous() for t in torch.tensor_split(input_, world_size, scatter_dim)]
|
| 333 |
+
output_list = [torch.empty_like(input_list[0]) for _ in range(world_size)]
|
| 334 |
+
dist.all_to_all(output_list, input_list, group=group)
|
| 335 |
+
return torch.cat(output_list, dim=gather_dim).contiguous()
|
| 336 |
+
|
| 337 |
+
|
| 338 |
+
class _AllToAll(torch.autograd.Function):
|
| 339 |
+
"""All-to-all communication.
|
| 340 |
+
|
| 341 |
+
Args:
|
| 342 |
+
input_: input matrix
|
| 343 |
+
process_group: communication group
|
| 344 |
+
scatter_dim: scatter dimension
|
| 345 |
+
gather_dim: gather dimension
|
| 346 |
+
"""
|
| 347 |
+
|
| 348 |
+
@staticmethod
|
| 349 |
+
def forward(ctx, input_, process_group, scatter_dim, gather_dim):
|
| 350 |
+
ctx.process_group = process_group
|
| 351 |
+
ctx.scatter_dim = scatter_dim
|
| 352 |
+
ctx.gather_dim = gather_dim
|
| 353 |
+
world_size = dist.get_world_size(process_group)
|
| 354 |
+
|
| 355 |
+
return _all_to_all_func(input_, world_size, process_group, scatter_dim, gather_dim)
|
| 356 |
+
|
| 357 |
+
@staticmethod
|
| 358 |
+
def backward(ctx, *grad_output):
|
| 359 |
+
process_group = ctx.process_group
|
| 360 |
+
scatter_dim = ctx.gather_dim
|
| 361 |
+
gather_dim = ctx.scatter_dim
|
| 362 |
+
return_grad = _AllToAll.apply(*grad_output, process_group, scatter_dim, gather_dim)
|
| 363 |
+
return (return_grad, None, None, None)
|
| 364 |
+
|
| 365 |
+
|
| 366 |
+
def all_to_all_with_pad(
|
| 367 |
+
input_: torch.Tensor,
|
| 368 |
+
process_group: dist.ProcessGroup,
|
| 369 |
+
scatter_dim: int = 2,
|
| 370 |
+
gather_dim: int = 1,
|
| 371 |
+
scatter_pad: int = 0,
|
| 372 |
+
gather_pad: int = 0,
|
| 373 |
+
):
|
| 374 |
+
if scatter_pad > 0:
|
| 375 |
+
pad_shape = list(input_.shape)
|
| 376 |
+
pad_shape[scatter_dim] = scatter_pad
|
| 377 |
+
pad_tensor = torch.zeros(pad_shape, device=input_.device, dtype=input_.dtype)
|
| 378 |
+
input_ = torch.cat([input_, pad_tensor], dim=scatter_dim)
|
| 379 |
+
|
| 380 |
+
assert (
|
| 381 |
+
input_.shape[scatter_dim] % dist.get_world_size(process_group) == 0
|
| 382 |
+
), f"Dimension to scatter ({input_.shape[scatter_dim]}) is not divisible by world size ({dist.get_world_size(process_group)})"
|
| 383 |
+
input_ = _AllToAll.apply(input_, process_group, scatter_dim, gather_dim)
|
| 384 |
+
|
| 385 |
+
if gather_pad > 0:
|
| 386 |
+
input_ = input_.narrow(gather_dim, 0, input_.size(gather_dim) - gather_pad)
|
| 387 |
+
|
| 388 |
+
return input_
|
| 389 |
+
|
| 390 |
+
|
| 391 |
+
def dynamic_switch(x, scatter_dim, gather_dim):
|
| 392 |
+
|
| 393 |
+
scatter_pad = 0
|
| 394 |
+
gather_pad = 0
|
| 395 |
+
cp_process_group = get_cp_group()
|
| 396 |
+
|
| 397 |
+
x = all_to_all_with_pad(
|
| 398 |
+
x,
|
| 399 |
+
cp_process_group,
|
| 400 |
+
scatter_dim=scatter_dim,
|
| 401 |
+
gather_dim=gather_dim,
|
| 402 |
+
scatter_pad=scatter_pad,
|
| 403 |
+
gather_pad=gather_pad,
|
| 404 |
+
)
|
| 405 |
+
return x
|
infworld/models/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
# infworld/models package
|
infworld/models/checkpoint.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from collections.abc import Iterable
|
| 2 |
+
|
| 3 |
+
import torch.nn as nn
|
| 4 |
+
from torch.utils.checkpoint import checkpoint, checkpoint_sequential
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
def set_grad_checkpoint(model, use_fp32_attention=False, gc_step=1):
|
| 8 |
+
assert isinstance(model, nn.Module)
|
| 9 |
+
|
| 10 |
+
def set_attr(module):
|
| 11 |
+
module.grad_checkpointing = True
|
| 12 |
+
module.fp32_attention = use_fp32_attention
|
| 13 |
+
module.grad_checkpointing_step = gc_step
|
| 14 |
+
|
| 15 |
+
model.apply(set_attr)
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def auto_grad_checkpoint(module, *args, **kwargs):
|
| 19 |
+
if getattr(module, "grad_checkpointing", False):
|
| 20 |
+
if not isinstance(module, Iterable):
|
| 21 |
+
return checkpoint(module, *args, **kwargs)
|
| 22 |
+
gc_step = module[0].grad_checkpointing_step
|
| 23 |
+
return checkpoint_sequential(module, gc_step, *args, **kwargs)
|
| 24 |
+
return module(*args, **kwargs)
|
infworld/models/dit_model.py
ADDED
|
@@ -0,0 +1,1285 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024-2025 The Alibaba Wan Team Authors. All rights reserved.
|
| 2 |
+
import math
|
| 3 |
+
import os
|
| 4 |
+
import torch
|
| 5 |
+
import torch.cuda.amp as amp
|
| 6 |
+
import torch.nn as nn
|
| 7 |
+
import torch.nn.functional as F
|
| 8 |
+
|
| 9 |
+
from einops import rearrange
|
| 10 |
+
from infworld.context_parallel import context_parallel_util
|
| 11 |
+
|
| 12 |
+
from infworld.models.checkpoint import auto_grad_checkpoint
|
| 13 |
+
|
| 14 |
+
try:
|
| 15 |
+
from transformer_engine.pytorch.attention import DotProductAttention
|
| 16 |
+
except:
|
| 17 |
+
print("Import transformer_engine failed, may cause bug.")
|
| 18 |
+
|
| 19 |
+
try:
|
| 20 |
+
import flash_attn_interface
|
| 21 |
+
FLASH_ATTN_3_AVAILABLE = True
|
| 22 |
+
except ModuleNotFoundError:
|
| 23 |
+
FLASH_ATTN_3_AVAILABLE = False
|
| 24 |
+
|
| 25 |
+
try:
|
| 26 |
+
import flash_attn
|
| 27 |
+
FLASH_ATTN_2_AVAILABLE = True
|
| 28 |
+
except ModuleNotFoundError:
|
| 29 |
+
FLASH_ATTN_2_AVAILABLE = False
|
| 30 |
+
|
| 31 |
+
import warnings
|
| 32 |
+
|
| 33 |
+
__all__ = ['WanModel']
|
| 34 |
+
|
| 35 |
+
class ResnetBlock3D(nn.Module):
|
| 36 |
+
def __init__(self, in_channels, out_channels=None, dropout=0.0):
|
| 37 |
+
super().__init__()
|
| 38 |
+
out_channels = out_channels or in_channels
|
| 39 |
+
|
| 40 |
+
self.norm1 = nn.GroupNorm(num_groups=32, num_channels=in_channels, eps=1e-6, affine=True)
|
| 41 |
+
self.conv1 = nn.Conv3d(in_channels, out_channels, kernel_size=3, stride=1, padding=1)
|
| 42 |
+
|
| 43 |
+
self.norm2 = nn.GroupNorm(num_groups=32, num_channels=out_channels, eps=1e-6, affine=True)
|
| 44 |
+
self.dropout = nn.Dropout(dropout)
|
| 45 |
+
self.conv2 = nn.Conv3d(out_channels, out_channels, kernel_size=3, stride=1, padding=1)
|
| 46 |
+
|
| 47 |
+
self.nonlinearity = nn.SiLU()
|
| 48 |
+
|
| 49 |
+
# Shortcut connection
|
| 50 |
+
if in_channels != out_channels:
|
| 51 |
+
self.shortcut = nn.Conv3d(in_channels, out_channels, kernel_size=1, stride=1, padding=0)
|
| 52 |
+
else:
|
| 53 |
+
self.shortcut = nn.Identity()
|
| 54 |
+
|
| 55 |
+
def forward(self, x):
|
| 56 |
+
h = x
|
| 57 |
+
h = self.norm1(h)
|
| 58 |
+
h = self.nonlinearity(h)
|
| 59 |
+
h = self.conv1(h)
|
| 60 |
+
|
| 61 |
+
h = self.norm2(h)
|
| 62 |
+
h = self.nonlinearity(h)
|
| 63 |
+
h = self.dropout(h)
|
| 64 |
+
h = self.conv2(h)
|
| 65 |
+
|
| 66 |
+
return h + self.shortcut(x)
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
class TemporalDownsample(nn.Module):
|
| 70 |
+
def __init__(self, channels):
|
| 71 |
+
super().__init__()
|
| 72 |
+
# 时序下采样: kernel=3, stride=(2,1,1), padding=(1,1,1)
|
| 73 |
+
# T -> T/2, H, W 保持不变
|
| 74 |
+
self.conv = nn.Conv3d(channels, channels, kernel_size=3, stride=(2, 1, 1), padding=(1, 1, 1))
|
| 75 |
+
|
| 76 |
+
def forward(self, x):
|
| 77 |
+
return self.conv(x)
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
class WanEncoderAttentionBlock(nn.Module):
|
| 81 |
+
def __init__(self, dim, num_heads=8, window_size=(-1, -1), eps=1e-6):
|
| 82 |
+
super().__init__()
|
| 83 |
+
self.dim = dim
|
| 84 |
+
self.num_heads = num_heads
|
| 85 |
+
self.head_dim = dim // num_heads
|
| 86 |
+
|
| 87 |
+
# 内部使用 WanSelfAttention,保持与主干网络一致的 3D RoPE 和 FlashAttention
|
| 88 |
+
self.attn = WanSelfAttention(
|
| 89 |
+
dim,
|
| 90 |
+
num_heads,
|
| 91 |
+
window_size=window_size,
|
| 92 |
+
qk_norm=True,
|
| 93 |
+
eps=eps
|
| 94 |
+
)
|
| 95 |
+
|
| 96 |
+
# Pre-Norm
|
| 97 |
+
self.norm = WanLayerNorm(dim, eps)
|
| 98 |
+
|
| 99 |
+
def _build_freqs(self, device):
|
| 100 |
+
# 构建 RoPE 频率参数
|
| 101 |
+
d = self.head_dim
|
| 102 |
+
freqs = torch.cat([
|
| 103 |
+
rope_params(1024, d - 4 * (d // 6)),
|
| 104 |
+
rope_params(1024, 2 * (d // 6)),
|
| 105 |
+
rope_params(1024, 2 * (d // 6))
|
| 106 |
+
], dim=1)
|
| 107 |
+
return freqs.to(device)
|
| 108 |
+
|
| 109 |
+
def forward(self, x):
|
| 110 |
+
# Input: (B, C, T, H, W)
|
| 111 |
+
B, C, T, H, W = x.shape
|
| 112 |
+
|
| 113 |
+
# 1. 转换格式: (B, C, T, H, W) -> (B, L, C)
|
| 114 |
+
# 先 permute 到 (B, T, H, W, C),再 flatten
|
| 115 |
+
x_in = x.permute(0, 2, 3, 4, 1).flatten(1, 3)
|
| 116 |
+
|
| 117 |
+
# 2. Norm
|
| 118 |
+
x_norm = self.norm(x_in)
|
| 119 |
+
|
| 120 |
+
# 3. 构造 Metadata
|
| 121 |
+
# grid_sizes: [B, 3] -> [[T, H, W], ...]
|
| 122 |
+
grid_sizes = torch.tensor([T, H, W], device=x.device).unsqueeze(0).repeat(B, 1)
|
| 123 |
+
|
| 124 |
+
# seq_lens: [B]
|
| 125 |
+
seq_lens = torch.tensor([T * H * W] * B, device=x.device, dtype=torch.long)
|
| 126 |
+
|
| 127 |
+
# freqs: RoPE (可以考虑缓存,这里为了独立性实时生成)
|
| 128 |
+
freqs = self._build_freqs(x.device)
|
| 129 |
+
|
| 130 |
+
# 4. Attention Forward
|
| 131 |
+
# Encoder 内部通常不需要 causal mask 或 ignore mask
|
| 132 |
+
x_out = self.attn(
|
| 133 |
+
x_norm,
|
| 134 |
+
seq_lens=seq_lens,
|
| 135 |
+
grid_sizes=grid_sizes,
|
| 136 |
+
freqs=freqs,
|
| 137 |
+
token_ignore_mask=None
|
| 138 |
+
)
|
| 139 |
+
|
| 140 |
+
# 5. Residual + 恢复形状
|
| 141 |
+
x_out = x_in + x_out
|
| 142 |
+
|
| 143 |
+
# (B, L, C) -> (B, T, H, W, C) -> (B, C, T, H, W)
|
| 144 |
+
x_out = x_out.view(B, T, H, W, C).permute(0, 4, 1, 2, 3)
|
| 145 |
+
|
| 146 |
+
return x_out
|
| 147 |
+
|
| 148 |
+
|
| 149 |
+
class TemporalLatentEncoder(nn.Module):
|
| 150 |
+
def __init__(self, in_channels=16, hidden_dim=256, num_heads=8, use_checkpoint=True):
|
| 151 |
+
"""
|
| 152 |
+
高配版时序 Encoder
|
| 153 |
+
结构: ConvIn -> ResBlock*2 -> Down -> ResBlock*2 -> Down -> ResBlock -> WanAttn -> ResBlock -> ConvOut
|
| 154 |
+
输入输出: (B, 16, T, H, W) -> (B, 16, T/4, H, W)
|
| 155 |
+
|
| 156 |
+
Args:
|
| 157 |
+
use_checkpoint: 是否使用 gradient checkpointing 节省显存(默认开启)
|
| 158 |
+
"""
|
| 159 |
+
super().__init__()
|
| 160 |
+
self.use_checkpoint = use_checkpoint
|
| 161 |
+
|
| 162 |
+
# 1. Initial Conv
|
| 163 |
+
self.conv_in = nn.Conv3d(in_channels, hidden_dim, kernel_size=3, stride=1, padding=1)
|
| 164 |
+
|
| 165 |
+
# 2. Down Block 1 (T -> T/2)
|
| 166 |
+
self.down_block1 = nn.Sequential(
|
| 167 |
+
ResnetBlock3D(hidden_dim, hidden_dim),
|
| 168 |
+
ResnetBlock3D(hidden_dim, hidden_dim),
|
| 169 |
+
TemporalDownsample(hidden_dim)
|
| 170 |
+
)
|
| 171 |
+
|
| 172 |
+
# 3. Down Block 2 (T/2 -> T/4)
|
| 173 |
+
self.down_block2 = nn.Sequential(
|
| 174 |
+
ResnetBlock3D(hidden_dim, hidden_dim),
|
| 175 |
+
ResnetBlock3D(hidden_dim, hidden_dim),
|
| 176 |
+
TemporalDownsample(hidden_dim)
|
| 177 |
+
)
|
| 178 |
+
|
| 179 |
+
# 4. Mid Block (Res + WanAttention + Res)
|
| 180 |
+
self.mid_block = nn.Sequential(
|
| 181 |
+
ResnetBlock3D(hidden_dim, hidden_dim),
|
| 182 |
+
WanEncoderAttentionBlock(dim=hidden_dim, num_heads=num_heads), # 使用 Wanx 风格 Attention
|
| 183 |
+
ResnetBlock3D(hidden_dim, hidden_dim),
|
| 184 |
+
)
|
| 185 |
+
|
| 186 |
+
# 5. Output Projection
|
| 187 |
+
self.norm_out = nn.GroupNorm(num_groups=32, num_channels=hidden_dim, eps=1e-6, affine=True)
|
| 188 |
+
self.act_out = nn.SiLU()
|
| 189 |
+
self.conv_out = nn.Conv3d(hidden_dim, in_channels, kernel_size=3, stride=1, padding=1)
|
| 190 |
+
|
| 191 |
+
def _forward_down_block1(self, x):
|
| 192 |
+
return self.down_block1(x)
|
| 193 |
+
|
| 194 |
+
def _forward_down_block2(self, x):
|
| 195 |
+
return self.down_block2(x)
|
| 196 |
+
|
| 197 |
+
def _forward_mid_block(self, x):
|
| 198 |
+
return self.mid_block(x)
|
| 199 |
+
|
| 200 |
+
def forward(self, x):
|
| 201 |
+
# x: (B, C, T, H, W)
|
| 202 |
+
from torch.utils.checkpoint import checkpoint
|
| 203 |
+
|
| 204 |
+
x = self.conv_in(x)
|
| 205 |
+
|
| 206 |
+
# 🔴 使用 gradient checkpointing 节省显存
|
| 207 |
+
if self.use_checkpoint and self.training:
|
| 208 |
+
x = checkpoint(self._forward_down_block1, x, use_reentrant=False)
|
| 209 |
+
x = checkpoint(self._forward_down_block2, x, use_reentrant=False)
|
| 210 |
+
x = checkpoint(self._forward_mid_block, x, use_reentrant=False)
|
| 211 |
+
else:
|
| 212 |
+
x = self.down_block1(x)
|
| 213 |
+
x = self.down_block2(x)
|
| 214 |
+
x = self.mid_block(x)
|
| 215 |
+
|
| 216 |
+
x = self.norm_out(x)
|
| 217 |
+
x = self.act_out(x)
|
| 218 |
+
x = self.conv_out(x)
|
| 219 |
+
|
| 220 |
+
return x
|
| 221 |
+
|
| 222 |
+
def temporal_sample(x: torch.Tensor, rate: int, dim: int = 2) -> torch.Tensor:
|
| 223 |
+
"""
|
| 224 |
+
在指定维度采样,首尾必保留
|
| 225 |
+
|
| 226 |
+
Args:
|
| 227 |
+
x (torch.Tensor): 输入张量,默认 shape = (B, C, T, H, W)
|
| 228 |
+
rate (int): 采样率(步长)
|
| 229 |
+
dim (int): 采样的维度,默认=2 (T维)
|
| 230 |
+
|
| 231 |
+
Returns:
|
| 232 |
+
torch.Tensor: 采样后的张量
|
| 233 |
+
"""
|
| 234 |
+
assert x.dim() >= dim + 1, f"输入维度 {x.dim()} 小于 dim={dim}"
|
| 235 |
+
N = x.shape[dim]
|
| 236 |
+
|
| 237 |
+
# 初步采样下标
|
| 238 |
+
indices = torch.arange(0, N, step=rate, device=x.device)
|
| 239 |
+
|
| 240 |
+
# 确保首尾都在
|
| 241 |
+
if indices[0] != 0:
|
| 242 |
+
indices = torch.cat([torch.tensor([0], device=x.device), indices])
|
| 243 |
+
if indices[-1] != N - 1:
|
| 244 |
+
indices = torch.cat([indices, torch.tensor([N - 1], device=x.device)])
|
| 245 |
+
|
| 246 |
+
# 去重并排序
|
| 247 |
+
indices = torch.unique(indices, sorted=True)
|
| 248 |
+
|
| 249 |
+
return torch.index_select(x, dim, indices)
|
| 250 |
+
|
| 251 |
+
def flash_attention(
|
| 252 |
+
q,
|
| 253 |
+
k,
|
| 254 |
+
v,
|
| 255 |
+
q_lens=None,
|
| 256 |
+
k_lens=None,
|
| 257 |
+
dropout_p=0.,
|
| 258 |
+
softmax_scale=None,
|
| 259 |
+
q_scale=None,
|
| 260 |
+
causal=False,
|
| 261 |
+
window_size=(-1, -1),
|
| 262 |
+
deterministic=False,
|
| 263 |
+
dtype=torch.bfloat16,
|
| 264 |
+
version=None,
|
| 265 |
+
):
|
| 266 |
+
"""
|
| 267 |
+
q: [B, Lq, Nq, C1].
|
| 268 |
+
k: [B, Lk, Nk, C1].
|
| 269 |
+
v: [B, Lk, Nk, C2]. Nq must be divisible by Nk.
|
| 270 |
+
q_lens: [B].
|
| 271 |
+
k_lens: [B].
|
| 272 |
+
dropout_p: float. Dropout probability.
|
| 273 |
+
softmax_scale: float. The scaling of QK^T before applying softmax.
|
| 274 |
+
causal: bool. Whether to apply causal attention mask.
|
| 275 |
+
window_size: (left right). If not (-1, -1), apply sliding window local attention.
|
| 276 |
+
deterministic: bool. If True, slightly slower and uses more memory.
|
| 277 |
+
dtype: torch.dtype. Apply when dtype of q/k/v is not float16/bfloat16.
|
| 278 |
+
"""
|
| 279 |
+
half_dtypes = (torch.float16, torch.bfloat16)
|
| 280 |
+
assert dtype in half_dtypes
|
| 281 |
+
assert q.device.type == 'cuda' and q.size(-1) <= 256
|
| 282 |
+
|
| 283 |
+
# params
|
| 284 |
+
b, lq, lk, out_dtype = q.size(0), q.size(1), k.size(1), q.dtype
|
| 285 |
+
|
| 286 |
+
def half(x):
|
| 287 |
+
return x if x.dtype in half_dtypes else x.to(dtype)
|
| 288 |
+
|
| 289 |
+
# preprocess query
|
| 290 |
+
if q_lens is None:
|
| 291 |
+
q = half(q.flatten(0, 1))
|
| 292 |
+
q_lens = torch.tensor(
|
| 293 |
+
[lq] * b, dtype=torch.int32).to(
|
| 294 |
+
device=q.device, non_blocking=True)
|
| 295 |
+
else:
|
| 296 |
+
q = half(torch.cat([u[:v] for u, v in zip(q, q_lens)]))
|
| 297 |
+
|
| 298 |
+
# preprocess key, value
|
| 299 |
+
if k_lens is None:
|
| 300 |
+
k = half(k.flatten(0, 1))
|
| 301 |
+
v = half(v.flatten(0, 1))
|
| 302 |
+
k_lens = torch.tensor(
|
| 303 |
+
[lk] * b, dtype=torch.int32).to(
|
| 304 |
+
device=k.device, non_blocking=True)
|
| 305 |
+
else:
|
| 306 |
+
k = half(torch.cat([u[:v] for u, v in zip(k, k_lens)]))
|
| 307 |
+
v = half(torch.cat([u[:v] for u, v in zip(v, k_lens)]))
|
| 308 |
+
|
| 309 |
+
q = q.to(v.dtype)
|
| 310 |
+
k = k.to(v.dtype)
|
| 311 |
+
|
| 312 |
+
if q_scale is not None:
|
| 313 |
+
q = q * q_scale
|
| 314 |
+
|
| 315 |
+
if version is not None and version == 3 and not FLASH_ATTN_3_AVAILABLE:
|
| 316 |
+
warnings.warn(
|
| 317 |
+
'Flash attention 3 is not available, use flash attention 2 instead.'
|
| 318 |
+
)
|
| 319 |
+
|
| 320 |
+
# apply attention
|
| 321 |
+
if (version is None or version == 3) and FLASH_ATTN_3_AVAILABLE:
|
| 322 |
+
# Note: dropout_p, window_size are not supported in FA3 now.
|
| 323 |
+
x = flash_attn_interface.flash_attn_varlen_func(
|
| 324 |
+
q=q,
|
| 325 |
+
k=k,
|
| 326 |
+
v=v,
|
| 327 |
+
cu_seqlens_q=torch.cat([q_lens.new_zeros([1]), q_lens]).cumsum(
|
| 328 |
+
0, dtype=torch.int32).to(q.device, non_blocking=True),
|
| 329 |
+
cu_seqlens_k=torch.cat([k_lens.new_zeros([1]), k_lens]).cumsum(
|
| 330 |
+
0, dtype=torch.int32).to(q.device, non_blocking=True),
|
| 331 |
+
seqused_q=None,
|
| 332 |
+
seqused_k=None,
|
| 333 |
+
max_seqlen_q=lq,
|
| 334 |
+
max_seqlen_k=lk,
|
| 335 |
+
softmax_scale=softmax_scale,
|
| 336 |
+
causal=causal,
|
| 337 |
+
deterministic=deterministic)[0].unflatten(0, (b, lq))
|
| 338 |
+
else:
|
| 339 |
+
assert FLASH_ATTN_2_AVAILABLE
|
| 340 |
+
x = flash_attn.flash_attn_varlen_func(
|
| 341 |
+
q=q,
|
| 342 |
+
k=k,
|
| 343 |
+
v=v,
|
| 344 |
+
cu_seqlens_q=torch.cat([q_lens.new_zeros([1]), q_lens]).cumsum(
|
| 345 |
+
0, dtype=torch.int32).to(q.device, non_blocking=True),
|
| 346 |
+
cu_seqlens_k=torch.cat([k_lens.new_zeros([1]), k_lens]).cumsum(
|
| 347 |
+
0, dtype=torch.int32).to(q.device, non_blocking=True),
|
| 348 |
+
max_seqlen_q=lq,
|
| 349 |
+
max_seqlen_k=lk,
|
| 350 |
+
dropout_p=dropout_p,
|
| 351 |
+
softmax_scale=softmax_scale,
|
| 352 |
+
causal=causal,
|
| 353 |
+
window_size=window_size,
|
| 354 |
+
deterministic=deterministic).unflatten(0, (b, lq))
|
| 355 |
+
|
| 356 |
+
# output
|
| 357 |
+
return x.type(out_dtype)
|
| 358 |
+
|
| 359 |
+
def sinusoidal_embedding_1d(dim, position):
|
| 360 |
+
# preprocess
|
| 361 |
+
assert dim % 2 == 0
|
| 362 |
+
half = dim // 2
|
| 363 |
+
position = position.type(torch.float64)
|
| 364 |
+
|
| 365 |
+
# calculation
|
| 366 |
+
sinusoid = torch.outer(
|
| 367 |
+
position, torch.pow(10000, -torch.arange(half).to(position).div(half)))
|
| 368 |
+
x = torch.cat([torch.cos(sinusoid), torch.sin(sinusoid)], dim=1)
|
| 369 |
+
return x
|
| 370 |
+
|
| 371 |
+
|
| 372 |
+
@amp.autocast(enabled=False)
|
| 373 |
+
def rope_params(max_seq_len, dim, theta=10000):
|
| 374 |
+
assert dim % 2 == 0
|
| 375 |
+
freqs = torch.outer(
|
| 376 |
+
torch.arange(max_seq_len),
|
| 377 |
+
1.0 / torch.pow(theta,
|
| 378 |
+
torch.arange(0, dim, 2).to(torch.float64).div(dim)))
|
| 379 |
+
freqs = torch.polar(torch.ones_like(freqs), freqs)
|
| 380 |
+
return freqs
|
| 381 |
+
|
| 382 |
+
|
| 383 |
+
@amp.autocast(enabled=False)
|
| 384 |
+
def rope_apply(x, grid_sizes, freqs, enable_context_parallel=False):
|
| 385 |
+
s, n, c = x.size(1), x.size(2), x.size(3) // 2
|
| 386 |
+
|
| 387 |
+
# split freqs
|
| 388 |
+
freqs = freqs.split([c - 2 * (c // 3), c // 3, c // 3], dim=1)
|
| 389 |
+
|
| 390 |
+
# loop over samples
|
| 391 |
+
output = []
|
| 392 |
+
for i, (f, h, w) in enumerate(grid_sizes.tolist()):
|
| 393 |
+
seq_len = f * h * w
|
| 394 |
+
|
| 395 |
+
# precompute multipliers
|
| 396 |
+
x_i = torch.view_as_complex(x[i, :s].to(torch.float64).reshape(
|
| 397 |
+
s, n, -1, 2))
|
| 398 |
+
freqs_i = torch.cat([
|
| 399 |
+
freqs[0][:f].view(f, 1, 1, -1).expand(f, h, w, -1),
|
| 400 |
+
freqs[1][:h].view(1, h, 1, -1).expand(f, h, w, -1),
|
| 401 |
+
freqs[2][:w].view(1, 1, w, -1).expand(f, h, w, -1)
|
| 402 |
+
],
|
| 403 |
+
dim=-1).reshape(seq_len, 1, -1)
|
| 404 |
+
|
| 405 |
+
if enable_context_parallel:
|
| 406 |
+
freqs_i = rearrange(freqs_i, "(T S) B C -> T S B C", T=f)
|
| 407 |
+
freqs_i = context_parallel_util.split_cp(freqs_i, seq_dim=1)
|
| 408 |
+
freqs_i = rearrange(freqs_i, "T S B C -> (T S) B C")
|
| 409 |
+
|
| 410 |
+
# apply rotary embedding
|
| 411 |
+
x_i = torch.view_as_real(x_i * freqs_i).flatten(2)
|
| 412 |
+
x_i = torch.cat([x_i, x[i, seq_len:]])
|
| 413 |
+
|
| 414 |
+
# append to collection
|
| 415 |
+
output.append(x_i)
|
| 416 |
+
return torch.stack(output).float()
|
| 417 |
+
|
| 418 |
+
|
| 419 |
+
class WanRMSNorm(nn.Module):
|
| 420 |
+
|
| 421 |
+
def __init__(self, dim, eps=1e-5):
|
| 422 |
+
super().__init__()
|
| 423 |
+
self.dim = dim
|
| 424 |
+
self.eps = eps
|
| 425 |
+
self.weight = nn.Parameter(torch.ones(dim))
|
| 426 |
+
|
| 427 |
+
def forward(self, x):
|
| 428 |
+
r"""
|
| 429 |
+
Args:
|
| 430 |
+
x(Tensor): Shape [B, L, C]
|
| 431 |
+
"""
|
| 432 |
+
return self._norm(x.float()).type_as(x) * self.weight
|
| 433 |
+
|
| 434 |
+
def _norm(self, x):
|
| 435 |
+
return x * torch.rsqrt(x.pow(2).mean(dim=-1, keepdim=True) + self.eps)
|
| 436 |
+
|
| 437 |
+
class ActionEncoder(nn.Module):
|
| 438 |
+
def __init__(self, vocab_size=10, embed_dim=256, hidden_dim=512, out_dim=1536):
|
| 439 |
+
super().__init__()
|
| 440 |
+
# 将整数映射到向量
|
| 441 |
+
self.embedding_move = nn.Embedding(vocab_size, embed_dim)
|
| 442 |
+
self.embedding_view = nn.Embedding(vocab_size, embed_dim)
|
| 443 |
+
|
| 444 |
+
self.encode_1 = nn.Sequential(
|
| 445 |
+
nn.Conv1d(embed_dim * 2, hidden_dim, kernel_size=3, stride=2, padding=1),
|
| 446 |
+
nn.GroupNorm(2, hidden_dim),
|
| 447 |
+
nn.ReLU(),
|
| 448 |
+
)
|
| 449 |
+
|
| 450 |
+
self.encode_2 = nn.Sequential(
|
| 451 |
+
nn.Conv1d(hidden_dim, hidden_dim, kernel_size=3, stride=2, padding=1),
|
| 452 |
+
nn.GroupNorm(2, hidden_dim),
|
| 453 |
+
nn.ReLU(),
|
| 454 |
+
)
|
| 455 |
+
|
| 456 |
+
self.proj = nn.Linear(hidden_dim, out_dim)
|
| 457 |
+
|
| 458 |
+
def forward(self, move, view):
|
| 459 |
+
# x: (B, L+1),整数输入
|
| 460 |
+
x_move = self.embedding_move(move).transpose(1, 2)
|
| 461 |
+
x_view = self.embedding_view(view).transpose(1, 2)
|
| 462 |
+
x = torch.cat([x_move, x_view], dim=1)
|
| 463 |
+
|
| 464 |
+
x = self.encode_2(self.encode_1(x)) # (B, out_dim, (L+1)/4)
|
| 465 |
+
|
| 466 |
+
x = x.transpose(1, 2) # (B, (L/4)+1, out_dim)
|
| 467 |
+
x = self.proj(x)
|
| 468 |
+
return x
|
| 469 |
+
|
| 470 |
+
class WanLayerNorm(nn.LayerNorm):
|
| 471 |
+
|
| 472 |
+
def __init__(self, dim, eps=1e-6, elementwise_affine=False):
|
| 473 |
+
super().__init__(dim, elementwise_affine=elementwise_affine, eps=eps)
|
| 474 |
+
|
| 475 |
+
def forward(self, inputs: torch.Tensor) -> torch.Tensor:
|
| 476 |
+
origin_dtype = inputs.dtype
|
| 477 |
+
out = F.layer_norm(
|
| 478 |
+
inputs.float(),
|
| 479 |
+
self.normalized_shape,
|
| 480 |
+
None if self.weight is None else self.weight.float(),
|
| 481 |
+
None if self.bias is None else self.bias.float() ,
|
| 482 |
+
self.eps
|
| 483 |
+
).to(origin_dtype)
|
| 484 |
+
return out
|
| 485 |
+
|
| 486 |
+
|
| 487 |
+
class WanSelfAttention(nn.Module):
|
| 488 |
+
|
| 489 |
+
def __init__(
|
| 490 |
+
self,
|
| 491 |
+
dim,
|
| 492 |
+
num_heads,
|
| 493 |
+
window_size=(-1, -1),
|
| 494 |
+
qk_norm=True,
|
| 495 |
+
eps=1e-6,
|
| 496 |
+
enable_context_parallel=False,
|
| 497 |
+
fp32_infer=False,
|
| 498 |
+
):
|
| 499 |
+
assert dim % num_heads == 0
|
| 500 |
+
super().__init__()
|
| 501 |
+
self.dim = dim
|
| 502 |
+
self.num_heads = num_heads
|
| 503 |
+
self.head_dim = dim // num_heads
|
| 504 |
+
self.window_size = window_size
|
| 505 |
+
self.qk_norm = qk_norm
|
| 506 |
+
self.eps = eps
|
| 507 |
+
self.enable_context_parallel = enable_context_parallel
|
| 508 |
+
|
| 509 |
+
# layers
|
| 510 |
+
self.q = nn.Linear(dim, dim)
|
| 511 |
+
self.k = nn.Linear(dim, dim)
|
| 512 |
+
self.v = nn.Linear(dim, dim)
|
| 513 |
+
self.o = nn.Linear(dim, dim)
|
| 514 |
+
self.norm_q = WanRMSNorm(dim, eps=eps) if qk_norm else nn.Identity()
|
| 515 |
+
self.norm_k = WanRMSNorm(dim, eps=eps) if qk_norm else nn.Identity()
|
| 516 |
+
|
| 517 |
+
if self.enable_context_parallel:
|
| 518 |
+
qkv_format = "bshd"
|
| 519 |
+
attn_mask_type = "no_mask"
|
| 520 |
+
os.environ["NVTE_FUSED_ATTN"] = "0"
|
| 521 |
+
os.environ["NVTE_FLASH_ATTN"] = "1"
|
| 522 |
+
self.core_attn = DotProductAttention(
|
| 523 |
+
self.num_heads,
|
| 524 |
+
self.head_dim,
|
| 525 |
+
num_gqa_groups=self.num_heads,
|
| 526 |
+
qkv_format=qkv_format,
|
| 527 |
+
attn_mask_type=attn_mask_type,
|
| 528 |
+
)
|
| 529 |
+
self.core_attn.set_context_parallel_group(context_parallel_util.get_cp_group(),
|
| 530 |
+
context_parallel_util.get_cp_rank_list(),
|
| 531 |
+
context_parallel_util.get_cp_stream())
|
| 532 |
+
|
| 533 |
+
self.fp32_infer = fp32_infer
|
| 534 |
+
self.out_c = None
|
| 535 |
+
|
| 536 |
+
def forward(self, x, seq_lens, grid_sizes, freqs, token_ignore_mask=None, dtype=torch.bfloat16):
|
| 537 |
+
r"""
|
| 538 |
+
Args:
|
| 539 |
+
x(Tensor): Shape [B, L, num_heads, C / num_heads]
|
| 540 |
+
seq_lens(Tensor): Shape [B]
|
| 541 |
+
grid_sizes(Tensor): Shape [B, 3], the second dimension contains (F, H, W)
|
| 542 |
+
freqs(Tensor): Rope freqs, shape [1024, C / num_heads / 2]
|
| 543 |
+
token_ignore_mask: [B, N]; bool tensor indicating tokens to be ignored
|
| 544 |
+
"""
|
| 545 |
+
b, s, n, d = *x.shape[:2], self.num_heads, self.head_dim
|
| 546 |
+
|
| 547 |
+
# query, key, value function
|
| 548 |
+
def qkv_fn(x):
|
| 549 |
+
q = self.norm_q(self.q(x)).view(b, s, n, d)
|
| 550 |
+
k = self.norm_k(self.k(x)).view(b, s, n, d)
|
| 551 |
+
v = self.v(x).view(b, s, n, d)
|
| 552 |
+
return q, k, v
|
| 553 |
+
|
| 554 |
+
q, k, v = qkv_fn(x)
|
| 555 |
+
|
| 556 |
+
q = rope_apply(q, grid_sizes, freqs, enable_context_parallel=self.enable_context_parallel)
|
| 557 |
+
k = rope_apply(k, grid_sizes, freqs, enable_context_parallel=self.enable_context_parallel)
|
| 558 |
+
|
| 559 |
+
# maks implementation by setting KV to zero
|
| 560 |
+
# this is a hack for the sake of cp support
|
| 561 |
+
if token_ignore_mask is not None:
|
| 562 |
+
select_mask = ~token_ignore_mask
|
| 563 |
+
expanded_select_mask = select_mask.unsqueeze(-1).unsqueeze(-1).expand(-1, -1, self.num_heads, self.head_dim) # [B, N, H, D]
|
| 564 |
+
expanded_select_mask = expanded_select_mask.to(k.dtype)
|
| 565 |
+
k = k * expanded_select_mask
|
| 566 |
+
v = v * expanded_select_mask
|
| 567 |
+
|
| 568 |
+
if self.enable_context_parallel:
|
| 569 |
+
# cp_size = context_parallel_util.get_cp_size()
|
| 570 |
+
# half_dtypes = (torch.float16, torch.bfloat16)
|
| 571 |
+
# def half(x):
|
| 572 |
+
# return x if x.dtype in half_dtypes else x.to(dtype)
|
| 573 |
+
|
| 574 |
+
# max_seqlen_q = s * cp_size
|
| 575 |
+
# max_seqlen_kv = max_seqlen_q
|
| 576 |
+
# x = self.core_attn(
|
| 577 |
+
# half(q) if self.fp32_infer else q.type_as(x),
|
| 578 |
+
# half(k) if self.fp32_infer else k.type_as(x),
|
| 579 |
+
# half(v) if self.fp32_infer else v.type_as(x),
|
| 580 |
+
# core_attention_bias_type="no_bias",
|
| 581 |
+
# core_attention_bias=None,
|
| 582 |
+
# cu_seqlens_q=None,
|
| 583 |
+
# cu_seqlens_kv=None,
|
| 584 |
+
# max_seqlen_q=max_seqlen_q,
|
| 585 |
+
# max_seqlen_kv=max_seqlen_kv,
|
| 586 |
+
# )
|
| 587 |
+
# x = rearrange(x, "B S (H D) -> B S H D", H=self.num_heads)
|
| 588 |
+
raise(NotImplementedError)
|
| 589 |
+
else:
|
| 590 |
+
B, S, H, D = q.shape
|
| 591 |
+
# 👉 你需要提前传入 num_c(或在这里根据场景算出)
|
| 592 |
+
num_c = getattr(self, "num_c", 0)
|
| 593 |
+
if num_c > 0 and num_c < S:
|
| 594 |
+
# 2️⃣ 当前 noisy 帧 Qz 看 [Kc; Kz]
|
| 595 |
+
q_z, k_z, v_z = q[:, num_c:], k, v
|
| 596 |
+
x = flash_attention(q_z, k_z, v_z, window_size=self.window_size).type_as(x)
|
| 597 |
+
else:
|
| 598 |
+
# 没有分段信息,默认用标准路径
|
| 599 |
+
x = flash_attention(q, k, v, k_lens=seq_lens, window_size=self.window_size).type_as(x)
|
| 600 |
+
# output
|
| 601 |
+
x = x.flatten(2)
|
| 602 |
+
x = self.o(x)
|
| 603 |
+
return x
|
| 604 |
+
|
| 605 |
+
|
| 606 |
+
class WanT2VCrossAttention(WanSelfAttention):
|
| 607 |
+
|
| 608 |
+
def forward(self, x, context, context_lens):
|
| 609 |
+
r"""
|
| 610 |
+
Args:
|
| 611 |
+
x(Tensor): Shape [B, L1, C]
|
| 612 |
+
context(Tensor): Shape [B, L2, C]
|
| 613 |
+
context_lens(Tensor): Shape [B]
|
| 614 |
+
"""
|
| 615 |
+
b, n, d = x.size(0), self.num_heads, self.head_dim
|
| 616 |
+
|
| 617 |
+
# compute query, key, value
|
| 618 |
+
q = self.norm_q(self.q(x)).view(b, -1, n, d)
|
| 619 |
+
k = self.norm_k(self.k(context)).view(b, -1, n, d)
|
| 620 |
+
v = self.v(context).view(b, -1, n, d)
|
| 621 |
+
|
| 622 |
+
# compute attention
|
| 623 |
+
x = flash_attention(q, k, v, k_lens=context_lens)
|
| 624 |
+
|
| 625 |
+
# output
|
| 626 |
+
x = x.flatten(2)
|
| 627 |
+
x = self.o(x)
|
| 628 |
+
return x
|
| 629 |
+
|
| 630 |
+
|
| 631 |
+
class WanI2VCrossAttention(WanSelfAttention):
|
| 632 |
+
|
| 633 |
+
def __init__(self,
|
| 634 |
+
dim,
|
| 635 |
+
num_heads,
|
| 636 |
+
window_size=(-1, -1),
|
| 637 |
+
qk_norm=True,
|
| 638 |
+
eps=1e-6):
|
| 639 |
+
super().__init__(dim, num_heads, window_size, qk_norm, eps)
|
| 640 |
+
|
| 641 |
+
self.k_img = nn.Linear(dim, dim)
|
| 642 |
+
self.v_img = nn.Linear(dim, dim)
|
| 643 |
+
# self.alpha = nn.Parameter(torch.zeros((1, )))
|
| 644 |
+
self.norm_k_img = WanRMSNorm(dim, eps=eps) if qk_norm else nn.Identity()
|
| 645 |
+
|
| 646 |
+
def forward(self, x, context, context_lens):
|
| 647 |
+
r"""
|
| 648 |
+
Args:
|
| 649 |
+
x(Tensor): Shape [B, L1, C]
|
| 650 |
+
context(Tensor): Shape [B, L2, C]
|
| 651 |
+
context_lens(Tensor): Shape [B]
|
| 652 |
+
"""
|
| 653 |
+
context_img = context[:, :257]
|
| 654 |
+
context = context[:, 257:]
|
| 655 |
+
b, n, d = x.size(0), self.num_heads, self.head_dim
|
| 656 |
+
|
| 657 |
+
# compute query, key, value
|
| 658 |
+
q = self.norm_q(self.q(x)).view(b, -1, n, d)
|
| 659 |
+
k = self.norm_k(self.k(context)).view(b, -1, n, d)
|
| 660 |
+
v = self.v(context).view(b, -1, n, d)
|
| 661 |
+
k_img = self.norm_k_img(self.k_img(context_img)).view(b, -1, n, d)
|
| 662 |
+
v_img = self.v_img(context_img).view(b, -1, n, d)
|
| 663 |
+
img_x = flash_attention(q, k_img, v_img, k_lens=None)
|
| 664 |
+
# compute attention
|
| 665 |
+
x = flash_attention(q, k, v, k_lens=context_lens)
|
| 666 |
+
|
| 667 |
+
# output
|
| 668 |
+
x = x.flatten(2)
|
| 669 |
+
img_x = img_x.flatten(2)
|
| 670 |
+
x = x + img_x
|
| 671 |
+
x = self.o(x)
|
| 672 |
+
return x
|
| 673 |
+
|
| 674 |
+
|
| 675 |
+
WAN_CROSSATTENTION_CLASSES = {
|
| 676 |
+
't2v_cross_attn': WanT2VCrossAttention,
|
| 677 |
+
'i2v_cross_attn': WanI2VCrossAttention,
|
| 678 |
+
}
|
| 679 |
+
|
| 680 |
+
|
| 681 |
+
class WanAttentionBlock(nn.Module):
|
| 682 |
+
|
| 683 |
+
def __init__(
|
| 684 |
+
self,
|
| 685 |
+
cross_attn_type,
|
| 686 |
+
dim,
|
| 687 |
+
ffn_dim,
|
| 688 |
+
num_heads,
|
| 689 |
+
window_size=(-1, -1),
|
| 690 |
+
qk_norm=True,
|
| 691 |
+
cross_attn_norm=False,
|
| 692 |
+
eps=1e-6,
|
| 693 |
+
enable_context_parallel=False,
|
| 694 |
+
):
|
| 695 |
+
super().__init__()
|
| 696 |
+
self.dim = dim
|
| 697 |
+
self.ffn_dim = ffn_dim
|
| 698 |
+
self.num_heads = num_heads
|
| 699 |
+
self.window_size = window_size
|
| 700 |
+
self.qk_norm = qk_norm
|
| 701 |
+
self.cross_attn_norm = cross_attn_norm
|
| 702 |
+
self.eps = eps
|
| 703 |
+
self.enable_context_parallel = enable_context_parallel
|
| 704 |
+
|
| 705 |
+
# layers
|
| 706 |
+
self.norm1 = WanLayerNorm(dim, eps)
|
| 707 |
+
self.self_attn = WanSelfAttention(dim, num_heads, window_size, qk_norm,
|
| 708 |
+
eps, enable_context_parallel=enable_context_parallel)
|
| 709 |
+
self.norm3 = WanLayerNorm(
|
| 710 |
+
dim, eps,
|
| 711 |
+
elementwise_affine=True) if cross_attn_norm else nn.Identity()
|
| 712 |
+
self.cross_attn = WAN_CROSSATTENTION_CLASSES[cross_attn_type](dim,
|
| 713 |
+
num_heads,
|
| 714 |
+
(-1, -1),
|
| 715 |
+
qk_norm,
|
| 716 |
+
eps)
|
| 717 |
+
self.norm2 = WanLayerNorm(dim, eps)
|
| 718 |
+
self.ffn = nn.Sequential(
|
| 719 |
+
nn.Linear(dim, ffn_dim), nn.GELU(approximate='tanh'),
|
| 720 |
+
nn.Linear(ffn_dim, dim))
|
| 721 |
+
|
| 722 |
+
# modulation
|
| 723 |
+
self.modulation = nn.Parameter(torch.randn(1, 6, dim) / dim**0.5)
|
| 724 |
+
self.hist = None
|
| 725 |
+
self.hist_cross = None
|
| 726 |
+
|
| 727 |
+
def forward(
|
| 728 |
+
self,
|
| 729 |
+
x,
|
| 730 |
+
e_all,
|
| 731 |
+
seq_lens,
|
| 732 |
+
grid_sizes,
|
| 733 |
+
freqs,
|
| 734 |
+
context,
|
| 735 |
+
context_lens,
|
| 736 |
+
token_ignore_mask=None,
|
| 737 |
+
training=True
|
| 738 |
+
):
|
| 739 |
+
r"""
|
| 740 |
+
Args:
|
| 741 |
+
x(Tensor): Shape [B, L, C]
|
| 742 |
+
e(Tensor): Shape [B, 6, C]
|
| 743 |
+
seq_lens(Tensor): Shape [B], length of each sequence in batch
|
| 744 |
+
grid_sizes(Tensor): Shape [B, 3], the second dimension contains (F, H, W)
|
| 745 |
+
freqs(Tensor): Rope freqs, shape [1024, C / num_heads / 2]
|
| 746 |
+
token_ignore_mask: [B, N]; bool tensor indicating tokens to be ignored in self attention
|
| 747 |
+
"""
|
| 748 |
+
dtype = x.dtype
|
| 749 |
+
e, e_no_noise = e_all[0], e_all[1]
|
| 750 |
+
assert e.dtype == torch.float32
|
| 751 |
+
assert e_no_noise.dtype == torch.float32
|
| 752 |
+
with amp.autocast(dtype=torch.float32):
|
| 753 |
+
e = (self.modulation + e).chunk(6, dim=1)
|
| 754 |
+
e_no_noise = (self.modulation + e_no_noise).chunk(6, dim=1)
|
| 755 |
+
assert e[0].dtype == torch.float32
|
| 756 |
+
|
| 757 |
+
num_hist = getattr(self.self_attn, "num_c", 0)
|
| 758 |
+
hist, noisy = x[:, :num_hist], x[:, num_hist:]
|
| 759 |
+
_, H, W = grid_sizes[0].tolist() # 假设所有样本一致
|
| 760 |
+
B = grid_sizes.shape[0]
|
| 761 |
+
T_noisy = noisy.shape[1] // (H * W)
|
| 762 |
+
T_hist= hist.shape[1] // (H * W)
|
| 763 |
+
|
| 764 |
+
grid_sizes_noisy = torch.tensor([T_noisy, H, W], device=grid_sizes.device).unsqueeze(0).repeat(B, 1)
|
| 765 |
+
grid_sizes_hist = torch.tensor([T_hist, H, W], device=grid_sizes.device).unsqueeze(0).repeat(B, 1)
|
| 766 |
+
|
| 767 |
+
# print(x.shape, e[1].shape, e[0].shape)
|
| 768 |
+
# self-attention
|
| 769 |
+
|
| 770 |
+
seq_len_hist = torch.tensor([u.size(0) for u in hist], dtype=torch.long)
|
| 771 |
+
if training or self.hist is None or self.hist.shape[1] != num_hist:
|
| 772 |
+
if token_ignore_mask is not None:
|
| 773 |
+
hist_token_ignore_mask = token_ignore_mask[:, :num_hist]
|
| 774 |
+
else:
|
| 775 |
+
hist_token_ignore_mask = token_ignore_mask
|
| 776 |
+
y = self.self_attn(
|
| 777 |
+
(self.norm1(hist).float() * (1 + e_no_noise[1]) + e_no_noise[0]).type_as(x), seq_len_hist, grid_sizes_hist,
|
| 778 |
+
freqs, hist_token_ignore_mask)
|
| 779 |
+
with amp.autocast(dtype=torch.float32):
|
| 780 |
+
self.hist = hist + y * e_no_noise[2]
|
| 781 |
+
|
| 782 |
+
# print('recompute condition', x.shape)
|
| 783 |
+
y = self.self_attn(
|
| 784 |
+
(self.norm1(x).float() * (1 + e[1]) + e[0]).type_as(x), seq_lens, grid_sizes,
|
| 785 |
+
freqs, token_ignore_mask)
|
| 786 |
+
with amp.autocast(dtype=torch.float32):
|
| 787 |
+
noisy = noisy + y * e[2]
|
| 788 |
+
|
| 789 |
+
x = torch.cat([self.hist, noisy], dim=1)
|
| 790 |
+
x = x.to(dtype)
|
| 791 |
+
# print('after self attn', x.shape)
|
| 792 |
+
|
| 793 |
+
# cross-attention & ffn function
|
| 794 |
+
def cross_attn_ffn(x, context, context_lens, e):
|
| 795 |
+
# print('before cross attn', x.shape)
|
| 796 |
+
x = x + self.cross_attn(self.norm3(x), context, context_lens)
|
| 797 |
+
# print('after cross attn', x.shape)
|
| 798 |
+
hist, noisy = x[:, :num_hist], x[:, num_hist:]
|
| 799 |
+
|
| 800 |
+
y = self.ffn((self.norm2(noisy).float() * (1 + e[4]) + e[3]).to(dtype))
|
| 801 |
+
with amp.autocast(dtype=torch.float32):
|
| 802 |
+
noisy = noisy + y * e[5]
|
| 803 |
+
|
| 804 |
+
if training or self.hist_cross is None or self.hist_cross.shape[1] != num_hist:
|
| 805 |
+
y = self.ffn((self.norm2(hist).float() * (1 + e_no_noise[4]) + e_no_noise[3]).to(dtype))
|
| 806 |
+
with amp.autocast(dtype=torch.float32):
|
| 807 |
+
self.hist_cross = hist + y * e_no_noise[5]
|
| 808 |
+
# print('compute hist cross', self.hist_cross.shape, hist.shape, noisy.shape, x.shape)
|
| 809 |
+
x = torch.cat([self.hist_cross, noisy], dim=1)
|
| 810 |
+
# print('after ffn', self.hist_cross.shape, hist.shape, noisy.shape, x.shape)
|
| 811 |
+
|
| 812 |
+
return x
|
| 813 |
+
|
| 814 |
+
x = cross_attn_ffn(x, context, context_lens, e)
|
| 815 |
+
x = x.to(dtype)
|
| 816 |
+
return x
|
| 817 |
+
|
| 818 |
+
|
| 819 |
+
class Head(nn.Module):
|
| 820 |
+
|
| 821 |
+
def __init__(self, dim, out_dim, patch_size, eps=1e-6):
|
| 822 |
+
super().__init__()
|
| 823 |
+
self.dim = dim
|
| 824 |
+
self.out_dim = out_dim
|
| 825 |
+
self.patch_size = patch_size
|
| 826 |
+
self.eps = eps
|
| 827 |
+
|
| 828 |
+
# layers
|
| 829 |
+
out_dim = math.prod(patch_size) * out_dim
|
| 830 |
+
self.norm = WanLayerNorm(dim, eps)
|
| 831 |
+
self.head = nn.Linear(dim, out_dim)
|
| 832 |
+
|
| 833 |
+
# modulation
|
| 834 |
+
self.modulation = nn.Parameter(torch.randn(1, 2, dim) / dim**0.5)
|
| 835 |
+
|
| 836 |
+
def forward(self, x, e):
|
| 837 |
+
r"""
|
| 838 |
+
Args:
|
| 839 |
+
x(Tensor): Shape [B, L1, C]
|
| 840 |
+
e(Tensor): Shape [B, C]
|
| 841 |
+
"""
|
| 842 |
+
assert e.dtype == torch.float32
|
| 843 |
+
with amp.autocast(dtype=torch.float32):
|
| 844 |
+
e = (self.modulation + e.unsqueeze(1)).chunk(2, dim=1)
|
| 845 |
+
x = (self.head(self.norm(x) * (1 + e[1]) + e[0]))
|
| 846 |
+
return x
|
| 847 |
+
|
| 848 |
+
|
| 849 |
+
class MLPProj(torch.nn.Module):
|
| 850 |
+
|
| 851 |
+
def __init__(self, in_dim, out_dim):
|
| 852 |
+
super().__init__()
|
| 853 |
+
|
| 854 |
+
self.proj = torch.nn.Sequential(
|
| 855 |
+
torch.nn.LayerNorm(in_dim), torch.nn.Linear(in_dim, in_dim),
|
| 856 |
+
torch.nn.GELU(), torch.nn.Linear(in_dim, out_dim),
|
| 857 |
+
torch.nn.LayerNorm(out_dim))
|
| 858 |
+
|
| 859 |
+
def forward(self, image_embeds):
|
| 860 |
+
clip_extra_context_tokens = self.proj(image_embeds)
|
| 861 |
+
return clip_extra_context_tokens
|
| 862 |
+
|
| 863 |
+
|
| 864 |
+
class WanModel(nn.Module):
|
| 865 |
+
r"""
|
| 866 |
+
Wan diffusion backbone supporting both text-to-video and image-to-video.
|
| 867 |
+
"""
|
| 868 |
+
|
| 869 |
+
def __init__(
|
| 870 |
+
self,
|
| 871 |
+
model_type='t2v',
|
| 872 |
+
patch_size=(1, 2, 2),
|
| 873 |
+
model_max_length=512,
|
| 874 |
+
in_channels=16,
|
| 875 |
+
dim=2048,
|
| 876 |
+
ffn_dim=8192,
|
| 877 |
+
freq_dim=256,
|
| 878 |
+
caption_channels=4096,
|
| 879 |
+
out_channels=16,
|
| 880 |
+
num_heads=16,
|
| 881 |
+
num_layers=32,
|
| 882 |
+
window_size=(-1, -1),
|
| 883 |
+
qk_norm=True,
|
| 884 |
+
cross_attn_norm=True,
|
| 885 |
+
eps=1e-6,
|
| 886 |
+
enable_context_parallel=False,
|
| 887 |
+
use_convenc=True, # 🔴 新增参数:是否使用卷积编码器进行时序压缩
|
| 888 |
+
):
|
| 889 |
+
r"""
|
| 890 |
+
Initialize the diffusion model backbone.
|
| 891 |
+
|
| 892 |
+
Args:
|
| 893 |
+
model_type (`str`, *optional*, defaults to 't2v'):
|
| 894 |
+
Model variant - 't2v' (text-to-video) or 'i2v' (image-to-video)
|
| 895 |
+
patch_size (`tuple`, *optional*, defaults to (1, 2, 2)):
|
| 896 |
+
3D patch dimensions for video embedding (t_patch, h_patch, w_patch)
|
| 897 |
+
model_max_length (`int`, *optional*, defaults to 512):
|
| 898 |
+
Fixed length for text embeddings
|
| 899 |
+
in_channels (`int`, *optional*, defaults to 16):
|
| 900 |
+
Input video channels (C_in)
|
| 901 |
+
dim (`int`, *optional*, defaults to 2048):
|
| 902 |
+
Hidden dimension of the transformer
|
| 903 |
+
ffn_dim (`int`, *optional*, defaults to 8192):
|
| 904 |
+
Intermediate dimension in feed-forward network
|
| 905 |
+
freq_dim (`int`, *optional*, defaults to 256):
|
| 906 |
+
Dimension for sinusoidal time embeddings
|
| 907 |
+
caption_channels (`int`, *optional*, defaults to 4096):
|
| 908 |
+
Input dimension for text embeddings
|
| 909 |
+
out_channels (`int`, *optional*, defaults to 16):
|
| 910 |
+
Output video channels (C_out)
|
| 911 |
+
num_heads (`int`, *optional*, defaults to 16):
|
| 912 |
+
Number of attention heads
|
| 913 |
+
num_layers (`int`, *optional*, defaults to 32):
|
| 914 |
+
Number of transformer blocks
|
| 915 |
+
window_size (`tuple`, *optional*, defaults to (-1, -1)):
|
| 916 |
+
Window size for local attention (-1 indicates global attention)
|
| 917 |
+
qk_norm (`bool`, *optional*, defaults to True):
|
| 918 |
+
Enable query/key normalization
|
| 919 |
+
cross_attn_norm (`bool`, *optional*, defaults to False):
|
| 920 |
+
Enable cross-attention normalization
|
| 921 |
+
eps (`float`, *optional*, defaults to 1e-6):
|
| 922 |
+
Epsilon value for normalization layers
|
| 923 |
+
"""
|
| 924 |
+
|
| 925 |
+
super().__init__()
|
| 926 |
+
|
| 927 |
+
assert model_type in ['t2v', 'i2v']
|
| 928 |
+
self.model_type = model_type
|
| 929 |
+
|
| 930 |
+
self.patch_size = patch_size
|
| 931 |
+
self.model_max_length = model_max_length
|
| 932 |
+
self.in_channels = in_channels
|
| 933 |
+
self.dim = dim
|
| 934 |
+
self.ffn_dim = ffn_dim
|
| 935 |
+
self.freq_dim = freq_dim
|
| 936 |
+
self.caption_channels = caption_channels
|
| 937 |
+
self.out_channels = out_channels
|
| 938 |
+
self.num_heads = num_heads
|
| 939 |
+
self.num_layers = num_layers
|
| 940 |
+
self.window_size = window_size
|
| 941 |
+
self.qk_norm = qk_norm
|
| 942 |
+
self.cross_attn_norm = cross_attn_norm
|
| 943 |
+
self.eps = eps
|
| 944 |
+
self.enable_context_parallel = enable_context_parallel
|
| 945 |
+
self.use_convenc = use_convenc # 🔴 保存参数
|
| 946 |
+
|
| 947 |
+
# hack y_embedder, not support uncond training now, pls use negative prompt for uncond
|
| 948 |
+
self.y_embedder = None
|
| 949 |
+
|
| 950 |
+
# embeddings
|
| 951 |
+
self.patch_embedding = nn.Conv3d(
|
| 952 |
+
in_channels, dim, kernel_size=patch_size, stride=patch_size)
|
| 953 |
+
self.text_embedding = nn.Sequential(
|
| 954 |
+
nn.Linear(caption_channels, dim), nn.GELU(approximate='tanh'),
|
| 955 |
+
nn.Linear(dim, dim))
|
| 956 |
+
|
| 957 |
+
self.time_embedding = nn.Sequential(
|
| 958 |
+
nn.Linear(freq_dim, dim), nn.SiLU(), nn.Linear(dim, dim))
|
| 959 |
+
self.time_projection = nn.Sequential(nn.SiLU(), nn.Linear(dim, dim * 6))
|
| 960 |
+
|
| 961 |
+
self.action_encoder = ActionEncoder()
|
| 962 |
+
# 🔴 只在 use_convenc=True 时创建时序编码器
|
| 963 |
+
if self.use_convenc:
|
| 964 |
+
self.latent_encoder = TemporalLatentEncoder()
|
| 965 |
+
else:
|
| 966 |
+
self.latent_encoder = None
|
| 967 |
+
# blocks
|
| 968 |
+
cross_attn_type = 't2v_cross_attn' if model_type == 't2v' else 'i2v_cross_attn'
|
| 969 |
+
self.blocks = nn.ModuleList([
|
| 970 |
+
WanAttentionBlock(cross_attn_type, dim, ffn_dim, num_heads,
|
| 971 |
+
window_size, qk_norm, cross_attn_norm, eps,
|
| 972 |
+
enable_context_parallel=enable_context_parallel,)
|
| 973 |
+
for _ in range(num_layers)
|
| 974 |
+
])
|
| 975 |
+
|
| 976 |
+
# head
|
| 977 |
+
self.head = Head(dim, out_channels, patch_size, eps)
|
| 978 |
+
|
| 979 |
+
# buffers (don't use register_buffer otherwise dtype will be changed in to())
|
| 980 |
+
assert (dim % num_heads) == 0 and (dim // num_heads) % 2 == 0
|
| 981 |
+
d = dim // num_heads
|
| 982 |
+
self.freqs = torch.cat([
|
| 983 |
+
rope_params(1024, d - 4 * (d // 6)),
|
| 984 |
+
rope_params(1024, 2 * (d // 6)),
|
| 985 |
+
rope_params(1024, 2 * (d // 6))
|
| 986 |
+
],
|
| 987 |
+
dim=1)
|
| 988 |
+
|
| 989 |
+
if model_type == 'i2v':
|
| 990 |
+
self.img_emb = MLPProj(1280, dim)
|
| 991 |
+
|
| 992 |
+
# initialize weights
|
| 993 |
+
self.init_weights()
|
| 994 |
+
|
| 995 |
+
def forward(
|
| 996 |
+
self,
|
| 997 |
+
x,
|
| 998 |
+
t,
|
| 999 |
+
y,
|
| 1000 |
+
y_mask=None,
|
| 1001 |
+
x_ignore_mask=None,
|
| 1002 |
+
clip_fea=None,
|
| 1003 |
+
image_cond=None,
|
| 1004 |
+
move=None,
|
| 1005 |
+
view=None
|
| 1006 |
+
):
|
| 1007 |
+
r"""
|
| 1008 |
+
Forward pass through the diffusion model
|
| 1009 |
+
"""
|
| 1010 |
+
|
| 1011 |
+
COMPRESSION_RATE = 4
|
| 1012 |
+
MAX_T_OUT = 20
|
| 1013 |
+
TARGET_T_MID = MAX_T_OUT * COMPRESSION_RATE # 80
|
| 1014 |
+
W_IN = 64
|
| 1015 |
+
W_OUT_PER_CHUNK = W_IN // COMPRESSION_RATE # 16
|
| 1016 |
+
TARGET_N_CHUNKS = 5 # 确保 T_mid = 80
|
| 1017 |
+
|
| 1018 |
+
dtype = self.patch_embedding.weight.dtype
|
| 1019 |
+
B, _, T, H, W = x.shape
|
| 1020 |
+
device = x.device # 获取当前设备
|
| 1021 |
+
T_in = image_cond.shape[2] # 原始输入的时间维度长度
|
| 1022 |
+
|
| 1023 |
+
# 1. 提取局部记忆 (Last Frame Memory) - 必须在压缩前进行
|
| 1024 |
+
loc_mem = image_cond[:,:,-1:,:,:].to(dtype)
|
| 1025 |
+
|
| 1026 |
+
# 2. 确保输入数据类型正确
|
| 1027 |
+
image_cond = image_cond.to(dtype)
|
| 1028 |
+
|
| 1029 |
+
# ----------------- [NEW LOGIC START] 时序压缩逻辑 -----------------
|
| 1030 |
+
|
| 1031 |
+
# 🔴 只在 use_convenc=True 时执行时序压缩
|
| 1032 |
+
if T_in <= TARGET_T_MID:
|
| 1033 |
+
# 情况 A: T_in <= 80,直接一次编码
|
| 1034 |
+
image_cond = self.latent_encoder(image_cond)
|
| 1035 |
+
|
| 1036 |
+
else:
|
| 1037 |
+
# 情况 B: T_in > 80,滑动窗口 + 二次压缩
|
| 1038 |
+
|
| 1039 |
+
# --- Step 1: 滑动窗口分块编码 (T_in -> T_mid=80) ---
|
| 1040 |
+
|
| 1041 |
+
# 计算步长 S,确保 5 个 Chunk 覆盖 T_in
|
| 1042 |
+
S_denom = TARGET_N_CHUNKS - 1
|
| 1043 |
+
# S = floor( (T_in - W_IN) / (N_chunks - 1) )
|
| 1044 |
+
S = math.floor((T_in - W_IN) / S_denom)
|
| 1045 |
+
S = max(1, S) # 最小步长为 1
|
| 1046 |
+
|
| 1047 |
+
latent_chunks = []
|
| 1048 |
+
|
| 1049 |
+
for i in range(TARGET_N_CHUNKS):
|
| 1050 |
+
start = i * S
|
| 1051 |
+
end = start + W_IN
|
| 1052 |
+
|
| 1053 |
+
chunk = image_cond[:, :, start:end, :, :]
|
| 1054 |
+
|
| 1055 |
+
# 处理填充:如果 end > T_in,则需要填充
|
| 1056 |
+
padding_len = W_IN - chunk.shape[2]
|
| 1057 |
+
if padding_len > 0:
|
| 1058 |
+
# 在时序维度 (dim=2) 末尾填充 0
|
| 1059 |
+
# F.pad 参数: (W_pad_start, W_pad_end, H_pad_start, H_pad_end, T_pad_start, T_pad_end)
|
| 1060 |
+
chunk = F.pad(chunk, (0, 0, 0, 0, 0, padding_len))
|
| 1061 |
+
|
| 1062 |
+
# 编码块 (W_IN -> W_OUT_PER_CHUNK=16)
|
| 1063 |
+
# 第一次编码通常冻结
|
| 1064 |
+
# with torch.no_grad():
|
| 1065 |
+
# self.latent_encoder.eval()
|
| 1066 |
+
encoded_chunk = self.latent_encoder(chunk)
|
| 1067 |
+
# self.latent_encoder.train()
|
| 1068 |
+
|
| 1069 |
+
# 裁剪到预期的输出长度 (防止 padding 导致的额外输出)
|
| 1070 |
+
encoded_chunk = encoded_chunk[:, :, :W_OUT_PER_CHUNK, :, :]
|
| 1071 |
+
latent_chunks.append(encoded_chunk)
|
| 1072 |
+
|
| 1073 |
+
# 拼接中间序列 T_mid (T_mid = 80)
|
| 1074 |
+
image_cond = torch.cat(latent_chunks, dim=2)
|
| 1075 |
+
T_mid = image_cond.shape[2]
|
| 1076 |
+
|
| 1077 |
+
# --- Step 2: 二次压缩 (T_mid=80 -> T_out=20) ---
|
| 1078 |
+
|
| 1079 |
+
if T_mid > MAX_T_OUT:
|
| 1080 |
+
# 此时 T_mid = 80,是 4 的倍数,直接编码即可
|
| 1081 |
+
image_cond = self.latent_encoder(image_cond)
|
| 1082 |
+
# T_out = 20
|
| 1083 |
+
|
| 1084 |
+
# ----------------- [NEW LOGIC END] -----------------
|
| 1085 |
+
|
| 1086 |
+
# 3. 拼接压缩后的 Condition 和 Loc_Mem
|
| 1087 |
+
image_cond = torch.cat((image_cond, loc_mem), dim=2)
|
| 1088 |
+
|
| 1089 |
+
# 4. 拼接 Condition 和 Noisy Input
|
| 1090 |
+
x = torch.cat((image_cond, x.to(dtype)), dim=2) # B, C, T_all, H, W
|
| 1091 |
+
# print("x init shape: ", x.shape)
|
| 1092 |
+
# print("image_cond init shape: ", image_cond.shape)
|
| 1093 |
+
|
| 1094 |
+
T_all = x.shape[2]
|
| 1095 |
+
mask = torch.ones(B, T_all, H, W, device=x.device, dtype=x.dtype) # B, T_all, H, W
|
| 1096 |
+
mask[:, -T:] = 0
|
| 1097 |
+
mask = mask.unsqueeze(1).expand(-1, 4, -1, -1, -1) # B, 4, T_all, H, W
|
| 1098 |
+
|
| 1099 |
+
x = torch.cat((x, mask), dim=1) # B, C+4, T_all, H, W
|
| 1100 |
+
T_x = T
|
| 1101 |
+
T = T_all
|
| 1102 |
+
N_t = T // self.patch_size[0]
|
| 1103 |
+
N_h = H // self.patch_size[1]
|
| 1104 |
+
N_w = W // self.patch_size[2]
|
| 1105 |
+
T_cond = image_cond.shape[2] # 新的 T_cond 约为 21 (20 + 1 loc_mem)
|
| 1106 |
+
num_c = (T_cond // self.patch_size[0]) * (H // self.patch_size[1]) * (W // self.patch_size[2])
|
| 1107 |
+
for block in self.blocks:
|
| 1108 |
+
block.self_attn.num_c = num_c
|
| 1109 |
+
dtype = self.patch_embedding.weight.dtype
|
| 1110 |
+
x = x.to(dtype)
|
| 1111 |
+
t = t.to(dtype)
|
| 1112 |
+
y = y.to(dtype)
|
| 1113 |
+
|
| 1114 |
+
if self.model_type == 'i2v':
|
| 1115 |
+
assert clip_fea is not None and image_cond is not None
|
| 1116 |
+
# clip_fea = clip_fea.to(dtype)
|
| 1117 |
+
|
| 1118 |
+
|
| 1119 |
+
# params
|
| 1120 |
+
device = self.patch_embedding.weight.device
|
| 1121 |
+
if self.freqs.device != device:
|
| 1122 |
+
self.freqs = self.freqs.to(device)
|
| 1123 |
+
|
| 1124 |
+
if self.model_type == 'i2v' and image_cond is not None:
|
| 1125 |
+
# image_cond = image_cond.to(dtype)
|
| 1126 |
+
x = [torch.cat([u, v], dim=0) for u, v in zip(x, image_cond)]
|
| 1127 |
+
|
| 1128 |
+
# embeddings
|
| 1129 |
+
x = [self.patch_embedding(u.unsqueeze(0)) for u in x] # fp32 -> bf16
|
| 1130 |
+
|
| 1131 |
+
# *******************************************************************
|
| 1132 |
+
# 注意:这里的 action_encoder 调用已经更新为 move 和 view
|
| 1133 |
+
# 假设 self.action_encoder 现在接收 move 和 view 两个参数
|
| 1134 |
+
# *******************************************************************
|
| 1135 |
+
|
| 1136 |
+
# Action Embedding Logic
|
| 1137 |
+
action_embedding_2 = self.action_encoder(move[:, -81:], view[:, -81:]).to(dtype).permute(0, 2, 1).unsqueeze(-1).unsqueeze(-1)
|
| 1138 |
+
|
| 1139 |
+
|
| 1140 |
+
# padding action embedding2 with a tensor of all zeros, the tensor has a same time length of image cond
|
| 1141 |
+
action_shape = list(action_embedding_2.shape)
|
| 1142 |
+
action_shape[2] = T_cond
|
| 1143 |
+
padding_embedding = torch.zeros(action_shape, device=device)
|
| 1144 |
+
|
| 1145 |
+
# make data type and device right with action embedding 1
|
| 1146 |
+
padding_embedding = padding_embedding.to(dtype).to(device)
|
| 1147 |
+
|
| 1148 |
+
# concat action embedding 1 and 2
|
| 1149 |
+
action_embedding = torch.cat((padding_embedding, action_embedding_2), dim=2)
|
| 1150 |
+
|
| 1151 |
+
# 切片 action embedding to meet the length of x (the last action)
|
| 1152 |
+
action_embedding = action_embedding[:, :, -T_all:]
|
| 1153 |
+
# print("action", action_embedding.shape)
|
| 1154 |
+
# print("u shape 1", x[0].shape)
|
| 1155 |
+
x = [u + action_embedding for u in x]
|
| 1156 |
+
grid_sizes = torch.stack(
|
| 1157 |
+
[torch.tensor(u.shape[2:], dtype=torch.long) for u in x])
|
| 1158 |
+
x = [u.flatten(2).transpose(1, 2) for u in x]
|
| 1159 |
+
seq_lens = torch.tensor([u.size(1) for u in x], dtype=torch.long)
|
| 1160 |
+
|
| 1161 |
+
# print("u shape", x[0].shape)
|
| 1162 |
+
# hack seq_len
|
| 1163 |
+
seq_len = seq_lens.max()
|
| 1164 |
+
x = torch.cat([
|
| 1165 |
+
torch.cat([u, u.new_zeros(u.size(0), seq_len - u.size(1), u.size(2))],
|
| 1166 |
+
dim=1) for u in x
|
| 1167 |
+
])
|
| 1168 |
+
# print("x now", x.shape)
|
| 1169 |
+
# time embeddings
|
| 1170 |
+
with amp.autocast(dtype=torch.float32):
|
| 1171 |
+
e = self.time_embedding(
|
| 1172 |
+
sinusoidal_embedding_1d(self.freq_dim, t).float())
|
| 1173 |
+
e0 = self.time_projection(e).unflatten(1, (6, self.dim))
|
| 1174 |
+
assert e.dtype == torch.float32 and e0.dtype == torch.float32
|
| 1175 |
+
t_no_noise = torch.zeros_like(t) # 对应 t = 0
|
| 1176 |
+
|
| 1177 |
+
with amp.autocast(dtype=torch.float32):
|
| 1178 |
+
e_no_noise = self.time_embedding(
|
| 1179 |
+
sinusoidal_embedding_1d(self.freq_dim, t_no_noise).float())
|
| 1180 |
+
e0_no_noise = self.time_projection(e_no_noise).unflatten(1, (6, self.dim))
|
| 1181 |
+
assert e_no_noise.dtype == torch.float32 and e0_no_noise.dtype == torch.float32
|
| 1182 |
+
y = y[:,0]
|
| 1183 |
+
y = y * y_mask[...,None]
|
| 1184 |
+
|
| 1185 |
+
# context
|
| 1186 |
+
context_lens = None
|
| 1187 |
+
context = self.text_embedding(
|
| 1188 |
+
torch.stack(
|
| 1189 |
+
[torch.cat([u, u.new_zeros(self.model_max_length - u.size(0), u.size(1))]) for u in y] #padding
|
| 1190 |
+
)
|
| 1191 |
+
)
|
| 1192 |
+
|
| 1193 |
+
# # sync context among cp ranks to avoid the following situation:
|
| 1194 |
+
# # cp_rank 0 dropped the context but cp_rank 1 did not, then they have different y embeeding in a forward pass
|
| 1195 |
+
# if context_parallel_util.get_cp_size() > 1:
|
| 1196 |
+
# context_parallel_util.cp_broadcast(context)
|
| 1197 |
+
|
| 1198 |
+
if self.model_type == 'i2v' and clip_fea is not None:
|
| 1199 |
+
context_clip = self.img_emb(clip_fea) # bs x 257 x dim
|
| 1200 |
+
context = torch.concat([context_clip, context], dim=1) # bf16 --> tf32
|
| 1201 |
+
|
| 1202 |
+
if self.enable_context_parallel:
|
| 1203 |
+
x = rearrange(x, "B (T S) C -> B T S C", T=N_t)
|
| 1204 |
+
x = context_parallel_util.split_cp(x, seq_dim=2)
|
| 1205 |
+
x = rearrange(x, "B T S C -> B (T S) C")
|
| 1206 |
+
|
| 1207 |
+
# convert x_mask to token_ignore_mask
|
| 1208 |
+
token_ignore_mask = None
|
| 1209 |
+
if x_ignore_mask is not None:
|
| 1210 |
+
x_ignore_mask = x_ignore_mask.to(torch.float32) # [B, T, H, W]; cast for interpolation
|
| 1211 |
+
# x_ignore_mask_temp_sample_cond = temporal_sample(x_ignore_mask[:, :-T_x], rate=2, dim=1)
|
| 1212 |
+
# print(x_ignore_mask_temp_sample_cond.shape)
|
| 1213 |
+
x_ignore_mask_temp_sample = torch.cat((x_ignore_mask, x_ignore_mask[:, -T_x:]), dim=1)
|
| 1214 |
+
token_ignore_mask = nn.functional.interpolate(x_ignore_mask_temp_sample, size=(N_h, N_w), mode='nearest')[:, -T_all:] # [B, T, N_h, N_w]
|
| 1215 |
+
token_ignore_mask = token_ignore_mask.reshape(B, T * N_h * N_w) # [B, N]
|
| 1216 |
+
token_ignore_mask = (token_ignore_mask > 0)
|
| 1217 |
+
|
| 1218 |
+
if self.enable_context_parallel and x_ignore_mask is not None:
|
| 1219 |
+
token_ignore_mask = rearrange(token_ignore_mask, "B (T S) -> B T S", T=T)
|
| 1220 |
+
token_ignore_mask = context_parallel_util.split_cp(token_ignore_mask, seq_dim=2)
|
| 1221 |
+
token_ignore_mask = rearrange(token_ignore_mask, "B T S -> B (T S)")
|
| 1222 |
+
|
| 1223 |
+
for block in self.blocks:
|
| 1224 |
+
# support grad checkpointing
|
| 1225 |
+
x = auto_grad_checkpoint(block, x, [e0, e0_no_noise], seq_lens, grid_sizes, self.freqs, context, context_lens, token_ignore_mask)
|
| 1226 |
+
|
| 1227 |
+
if self.enable_context_parallel:
|
| 1228 |
+
x = context_parallel_util.gather_cp(x, N_t)
|
| 1229 |
+
|
| 1230 |
+
# head
|
| 1231 |
+
x = self.head(x, e)
|
| 1232 |
+
|
| 1233 |
+
# unpatchify
|
| 1234 |
+
x = self.unpatchify(x, grid_sizes)
|
| 1235 |
+
|
| 1236 |
+
return torch.stack(x).float()
|
| 1237 |
+
|
| 1238 |
+
def unpatchify(self, x, grid_sizes):
|
| 1239 |
+
r"""
|
| 1240 |
+
Reconstruct video tensors from patch embeddings.
|
| 1241 |
+
|
| 1242 |
+
Args:
|
| 1243 |
+
x (List[Tensor]):
|
| 1244 |
+
List of patchified features, each with shape [L, C_out * prod(patch_size)]
|
| 1245 |
+
grid_sizes (Tensor):
|
| 1246 |
+
Original spatial-temporal grid dimensions before patching,
|
| 1247 |
+
shape [B, 3] (3 dimensions correspond to F_patches, H_patches, W_patches)
|
| 1248 |
+
|
| 1249 |
+
Returns:
|
| 1250 |
+
List[Tensor]:
|
| 1251 |
+
Reconstructed video tensors with shape [C_out, F, H / 8, W / 8]
|
| 1252 |
+
"""
|
| 1253 |
+
|
| 1254 |
+
c = self.out_channels
|
| 1255 |
+
out = []
|
| 1256 |
+
for u, v in zip(x, grid_sizes.tolist()):
|
| 1257 |
+
u = u[:math.prod(v)].view(*v, *self.patch_size, c)
|
| 1258 |
+
u = torch.einsum('fhwpqrc->cfphqwr', u)
|
| 1259 |
+
u = u.reshape(c, *[i * j for i, j in zip(v, self.patch_size)])
|
| 1260 |
+
out.append(u)
|
| 1261 |
+
return out
|
| 1262 |
+
|
| 1263 |
+
def init_weights(self):
|
| 1264 |
+
r"""
|
| 1265 |
+
Initialize model parameters using Xavier initialization.
|
| 1266 |
+
"""
|
| 1267 |
+
|
| 1268 |
+
# basic init
|
| 1269 |
+
for m in self.modules():
|
| 1270 |
+
if isinstance(m, nn.Linear):
|
| 1271 |
+
nn.init.xavier_uniform_(m.weight)
|
| 1272 |
+
if m.bias is not None:
|
| 1273 |
+
nn.init.zeros_(m.bias)
|
| 1274 |
+
|
| 1275 |
+
# init embeddings
|
| 1276 |
+
nn.init.xavier_uniform_(self.patch_embedding.weight.flatten(1))
|
| 1277 |
+
for m in self.text_embedding.modules():
|
| 1278 |
+
if isinstance(m, nn.Linear):
|
| 1279 |
+
nn.init.normal_(m.weight, std=.02)
|
| 1280 |
+
for m in self.time_embedding.modules():
|
| 1281 |
+
if isinstance(m, nn.Linear):
|
| 1282 |
+
nn.init.normal_(m.weight, std=.02)
|
| 1283 |
+
|
| 1284 |
+
# init output layer
|
| 1285 |
+
nn.init.zeros_(self.head.head.weight)
|
infworld/models/scheduler.py
ADDED
|
@@ -0,0 +1,306 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import math
|
| 2 |
+
import time
|
| 3 |
+
import numpy as np
|
| 4 |
+
|
| 5 |
+
from tqdm import tqdm
|
| 6 |
+
from typing import Callable
|
| 7 |
+
from einops import rearrange
|
| 8 |
+
from functools import partial
|
| 9 |
+
|
| 10 |
+
import torch
|
| 11 |
+
from torch.distributions import LogisticNormal
|
| 12 |
+
|
| 13 |
+
from infworld.context_parallel import context_parallel_util
|
| 14 |
+
|
| 15 |
+
# some code are inspired by https://github.com/magic-research/piecewise-rectified-flow/blob/main/scripts/train_perflow.py
|
| 16 |
+
# and https://github.com/magic-research/piecewise-rectified-flow/blob/main/src/scheduler_perflow.py
|
| 17 |
+
# and https://github.com/black-forest-labs/flux/blob/main/src/flux/sampling.py
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
def _extract_into_tensor(arr, timesteps, broadcast_shape):
|
| 21 |
+
"""
|
| 22 |
+
Extract values from a 1-D numpy array for a batch of indices.
|
| 23 |
+
:param arr: the 1-D numpy array.
|
| 24 |
+
:param timesteps: a tensor of indices into the array to extract.
|
| 25 |
+
:param broadcast_shape: a larger shape of K dimensions with the batch
|
| 26 |
+
dimension equal to the length of timesteps.
|
| 27 |
+
:return: a tensor of shape [batch_size, 1, ...] where the shape has K dims.
|
| 28 |
+
"""
|
| 29 |
+
res = torch.from_numpy(arr).to(device=timesteps.device)[timesteps].float()
|
| 30 |
+
while len(res.shape) < len(broadcast_shape):
|
| 31 |
+
res = res[..., None]
|
| 32 |
+
return res + torch.zeros(broadcast_shape, device=timesteps.device)
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def mean_flat(tensor: torch.Tensor, stoploss_mask=None):
|
| 36 |
+
"""
|
| 37 |
+
Take the mean over all non-batch dimensions.
|
| 38 |
+
tensor: [B, C, T, H, W]
|
| 39 |
+
stoploss_mask: [B, T, H, W]
|
| 40 |
+
"""
|
| 41 |
+
if stoploss_mask is None:
|
| 42 |
+
return tensor.mean(dim=list(range(1, len(tensor.shape))))
|
| 43 |
+
else:
|
| 44 |
+
stoploss_mask = stoploss_mask.unsqueeze(1).expand_as(tensor) # [B, T, H, W] --> [B, C, T, H, W]
|
| 45 |
+
assert tensor.shape == stoploss_mask.shape, f"shape of tensor {tensor.shape} and stoploss_mask {stoploss_mask.shape} should be the same"
|
| 46 |
+
loss_mask = ~stoploss_mask
|
| 47 |
+
masked_loss = tensor * loss_mask
|
| 48 |
+
sum_loss = masked_loss.sum(dim=list(range(1, len(tensor.shape))))
|
| 49 |
+
count_nonzero = loss_mask.sum(dim=list(range(1, len(tensor.shape))))
|
| 50 |
+
mean_loss = sum_loss / count_nonzero.clamp(min=1)
|
| 51 |
+
|
| 52 |
+
return mean_loss
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
def clamp(value, min_value, max_value):
|
| 56 |
+
return max(min_value, min(value, max_value))
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
def timestep_transform(
|
| 61 |
+
t,
|
| 62 |
+
shift=5.0,
|
| 63 |
+
num_timesteps=1000,
|
| 64 |
+
):
|
| 65 |
+
t = t / num_timesteps
|
| 66 |
+
# shift the timestep based on ratio
|
| 67 |
+
new_t = shift * t / (1 + (shift - 1) * t)
|
| 68 |
+
new_t = new_t * num_timesteps
|
| 69 |
+
return new_t
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
class RFlowScheduler:
|
| 73 |
+
def __init__(
|
| 74 |
+
self,
|
| 75 |
+
num_timesteps=1000,
|
| 76 |
+
num_sampling_steps=10,
|
| 77 |
+
use_discrete_timesteps=False,
|
| 78 |
+
sample_method="uniform",
|
| 79 |
+
loc=0.0,
|
| 80 |
+
scale=1.0,
|
| 81 |
+
shift=5.0,
|
| 82 |
+
use_timestep_transform=False,
|
| 83 |
+
transform_scale=1.0,
|
| 84 |
+
use_reversed_velocity=False,
|
| 85 |
+
cfg_scale=7.0,
|
| 86 |
+
**kwargs,
|
| 87 |
+
):
|
| 88 |
+
self.num_timesteps = num_timesteps
|
| 89 |
+
self.num_sampling_steps = num_sampling_steps
|
| 90 |
+
self.use_discrete_timesteps = use_discrete_timesteps
|
| 91 |
+
self.use_reversed_velocity = use_reversed_velocity
|
| 92 |
+
self.cfg_scale = cfg_scale
|
| 93 |
+
|
| 94 |
+
# sample method
|
| 95 |
+
assert sample_method in ["uniform", "logit-normal"]
|
| 96 |
+
assert (
|
| 97 |
+
sample_method == "uniform" or not use_discrete_timesteps
|
| 98 |
+
), "Only uniform sampling is supported for discrete timesteps"
|
| 99 |
+
self.sample_method = sample_method
|
| 100 |
+
if sample_method == "logit-normal":
|
| 101 |
+
self.distribution = LogisticNormal(torch.tensor([loc]), torch.tensor([scale]))
|
| 102 |
+
self.sample_t = lambda x: self.distribution.sample((x.shape[0],))[:, 0].to(x.device)
|
| 103 |
+
|
| 104 |
+
# timestep transform
|
| 105 |
+
self.use_timestep_transform = use_timestep_transform
|
| 106 |
+
self.transform_scale = transform_scale
|
| 107 |
+
|
| 108 |
+
self.shift = shift
|
| 109 |
+
sigmas = torch.linspace(0, 1, num_timesteps)
|
| 110 |
+
sigmas = shift * sigmas / (1 + (shift - 1) * sigmas)
|
| 111 |
+
self.timesteps = sigmas * num_timesteps
|
| 112 |
+
|
| 113 |
+
y = torch.exp(-2 * ((self.timesteps - num_timesteps/2) / num_timesteps)**2)
|
| 114 |
+
y_shifted = y - y.min()
|
| 115 |
+
self.bsmntw_weighing = y_shifted * (num_timesteps / y_shifted.sum())
|
| 116 |
+
|
| 117 |
+
def training_losses(self, model, x_start, model_kwargs=None, noise=None, x_ignore_mask=None, t=None):
|
| 118 |
+
"""
|
| 119 |
+
Compute training losses for a single timestep.
|
| 120 |
+
Arguments format copied from opensora/schedulers/iddpm/gaussian_diffusion.py/training_losses
|
| 121 |
+
Note: t is int tensor and should be rescaled from [0, num_timesteps-1] to [1,0]
|
| 122 |
+
"""
|
| 123 |
+
|
| 124 |
+
if t is None:
|
| 125 |
+
if self.use_discrete_timesteps:
|
| 126 |
+
t = torch.randint(0, self.num_timesteps, (x_start.shape[0],), device=x_start.device)
|
| 127 |
+
elif self.sample_method == "uniform":
|
| 128 |
+
t = torch.rand((x_start.shape[0],), device=x_start.device) * self.num_timesteps
|
| 129 |
+
elif self.sample_method == "logit-normal":
|
| 130 |
+
t = self.sample_t(x_start) * self.num_timesteps
|
| 131 |
+
|
| 132 |
+
if self.use_timestep_transform:
|
| 133 |
+
latent_size = x_start.shape[-3:]
|
| 134 |
+
t = timestep_transform(t, shift=self.shift, num_timesteps=self.num_timesteps)
|
| 135 |
+
|
| 136 |
+
if model_kwargs is None:
|
| 137 |
+
model_kwargs = {}
|
| 138 |
+
if noise is None:
|
| 139 |
+
noise = torch.randn_like(x_start)
|
| 140 |
+
assert noise.shape == x_start.shape
|
| 141 |
+
|
| 142 |
+
|
| 143 |
+
if context_parallel_util.get_cp_size() > 1:
|
| 144 |
+
context_parallel_util.cp_broadcast(noise)
|
| 145 |
+
context_parallel_util.cp_broadcast(t)
|
| 146 |
+
|
| 147 |
+
x_t = self.add_noise(x_start, noise, t)
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
target = x_start - noise
|
| 151 |
+
if self.use_reversed_velocity:
|
| 152 |
+
target = -target
|
| 153 |
+
|
| 154 |
+
terms = {}
|
| 155 |
+
model_output = model(x_t, t, x_ignore_mask=x_ignore_mask, **model_kwargs)
|
| 156 |
+
velocity_pred = model_output
|
| 157 |
+
|
| 158 |
+
T = target.shape[2]
|
| 159 |
+
loss = mean_flat((velocity_pred[:, :, -T:] - target).pow(2), stoploss_mask=x_ignore_mask[:, -T:])
|
| 160 |
+
|
| 161 |
+
# # get loss weight
|
| 162 |
+
# timestep_id = torch.argmin((self.timesteps.unsqueeze(0) - t.unsqueeze(1).to(self.timesteps.device)).abs(), dim=1)
|
| 163 |
+
# weights = self.bsmntw_weighing[timestep_id]
|
| 164 |
+
# loss = weights.to(loss) * loss
|
| 165 |
+
|
| 166 |
+
terms["loss"] = loss
|
| 167 |
+
|
| 168 |
+
return terms
|
| 169 |
+
|
| 170 |
+
def add_noise(
|
| 171 |
+
self,
|
| 172 |
+
original_samples: torch.FloatTensor,
|
| 173 |
+
noise: torch.FloatTensor,
|
| 174 |
+
timesteps: torch.IntTensor,
|
| 175 |
+
) -> torch.FloatTensor:
|
| 176 |
+
"""
|
| 177 |
+
compatible with diffusers add_noise()
|
| 178 |
+
"""
|
| 179 |
+
timesteps = timesteps.float() / self.num_timesteps
|
| 180 |
+
timesteps = timesteps.view(timesteps.shape + (1,) * (len(noise.shape)-1))
|
| 181 |
+
|
| 182 |
+
return (1 - timesteps) * original_samples + timesteps * noise
|
| 183 |
+
|
| 184 |
+
def sample(
|
| 185 |
+
self,
|
| 186 |
+
model,
|
| 187 |
+
text_encoder,
|
| 188 |
+
null_embedder,
|
| 189 |
+
z_size,
|
| 190 |
+
prompts,
|
| 191 |
+
device,
|
| 192 |
+
mask=None,
|
| 193 |
+
guidance_scale=None,
|
| 194 |
+
negative_prompts=None,
|
| 195 |
+
additional_args=None,
|
| 196 |
+
progress=True,
|
| 197 |
+
):
|
| 198 |
+
# if no specific guidance scale is provided, use the default scale when initializing the scheduler
|
| 199 |
+
if guidance_scale is None:
|
| 200 |
+
guidance_scale = self.cfg_scale
|
| 201 |
+
|
| 202 |
+
n = len(prompts)
|
| 203 |
+
z = torch.randn(*z_size, device=device)
|
| 204 |
+
|
| 205 |
+
if context_parallel_util.get_cp_size() > 1:
|
| 206 |
+
context_parallel_util.cp_broadcast(z)
|
| 207 |
+
|
| 208 |
+
# For performance alignment
|
| 209 |
+
# from source.opensora.utils.inference_utils import apply_mask_strategy
|
| 210 |
+
# mask = apply_mask_strategy(z, [[]], [""], 0, align=5)
|
| 211 |
+
|
| 212 |
+
assert negative_prompts is None or len(negative_prompts) in [n, 1], \
|
| 213 |
+
"Invalid negative prompts."
|
| 214 |
+
|
| 215 |
+
if negative_prompts:
|
| 216 |
+
if len(negative_prompts) == 1: negative_prompts *= n
|
| 217 |
+
prompts = prompts + negative_prompts
|
| 218 |
+
|
| 219 |
+
batch_size = len(prompts)
|
| 220 |
+
if context_parallel_util.get_cp_rank() == 0:
|
| 221 |
+
model_args = text_encoder.encode(prompts)
|
| 222 |
+
if context_parallel_util.get_cp_size() > 1:
|
| 223 |
+
context_parallel_util.cp_broadcast(model_args['y'])
|
| 224 |
+
context_parallel_util.cp_broadcast(model_args['y_mask'])
|
| 225 |
+
elif context_parallel_util.get_cp_size() > 1:
|
| 226 |
+
caption_channels = text_encoder.output_dim
|
| 227 |
+
model_max_length = text_encoder.model_max_length
|
| 228 |
+
y_tensor = torch.zeros([batch_size, 1, model_max_length, caption_channels], dtype=torch.float32, device=device)
|
| 229 |
+
y_mask_tensor = torch.zeros([batch_size, model_max_length], dtype=torch.int64, device=device)
|
| 230 |
+
context_parallel_util.cp_broadcast(y_tensor)
|
| 231 |
+
context_parallel_util.cp_broadcast(y_mask_tensor)
|
| 232 |
+
model_args = {
|
| 233 |
+
"y" : y_tensor,
|
| 234 |
+
"y_mask": y_mask_tensor,
|
| 235 |
+
}
|
| 236 |
+
|
| 237 |
+
assert negative_prompts, "Not support uncond training now, pls use negative prompt for uncond."
|
| 238 |
+
if not negative_prompts:
|
| 239 |
+
uncond = null_embedder.y_embedding[None].repeat(n, 1, 1)[:, None]
|
| 240 |
+
model_args["y"] = torch.concat([model_args["y"], uncond])
|
| 241 |
+
|
| 242 |
+
if additional_args is not None:
|
| 243 |
+
model_args.update(additional_args)
|
| 244 |
+
|
| 245 |
+
# prepare timesteps
|
| 246 |
+
timesteps = list(np.linspace(self.num_timesteps, 1, self.num_sampling_steps, dtype=np.float32))
|
| 247 |
+
if self.use_discrete_timesteps:
|
| 248 |
+
timesteps = [int(round(t)) for t in timesteps]
|
| 249 |
+
timesteps = [torch.tensor([t] * z.shape[0], device=device) for t in timesteps]
|
| 250 |
+
if self.use_timestep_transform:
|
| 251 |
+
latent_size = z_size[-3:]
|
| 252 |
+
timesteps = [timestep_transform(t, shift=self.shift, num_timesteps=self.num_timesteps) for t in timesteps]
|
| 253 |
+
|
| 254 |
+
if mask is not None:
|
| 255 |
+
noise_added = torch.zeros_like(mask, dtype=torch.bool)
|
| 256 |
+
noise_added = noise_added | (mask == 1)
|
| 257 |
+
|
| 258 |
+
if context_parallel_util.get_cp_size() > 1:
|
| 259 |
+
torch.distributed.barrier(group=context_parallel_util.get_cp_group())
|
| 260 |
+
|
| 261 |
+
model_args["image_cond"] = model_args["image_cond"].repeat(2, 1, 1, 1, 1)
|
| 262 |
+
progress_wrap = partial(tqdm, total=len(timesteps)) if progress else (lambda x: x)
|
| 263 |
+
for i, t in progress_wrap(enumerate(timesteps)):
|
| 264 |
+
# mask for adding noise
|
| 265 |
+
if mask is not None:
|
| 266 |
+
mask_t = mask * self.num_timesteps
|
| 267 |
+
x0 = z.clone()
|
| 268 |
+
|
| 269 |
+
x0_noise = torch.randn_like(x0)
|
| 270 |
+
if context_parallel_util.get_cp_size() > 1:
|
| 271 |
+
context_parallel_util.cp_broadcast(x0_noise)
|
| 272 |
+
|
| 273 |
+
x_noise = self.scheduler.add_noise(x0, x0_noise, t)
|
| 274 |
+
|
| 275 |
+
mask_t_upper = mask_t >= t.unsqueeze(1)
|
| 276 |
+
model_args["x_mask"] = mask_t_upper.repeat(2, 1)
|
| 277 |
+
mask_add_noise = mask_t_upper & ~noise_added
|
| 278 |
+
|
| 279 |
+
z = torch.where(mask_add_noise[:, None, :, None, None], x_noise, x0)
|
| 280 |
+
noise_added = mask_t_upper
|
| 281 |
+
|
| 282 |
+
# classifier-free guidance
|
| 283 |
+
z_in = torch.cat([z, z], 0)
|
| 284 |
+
|
| 285 |
+
t = torch.cat([t, t], 0)
|
| 286 |
+
start = time.time()
|
| 287 |
+
pred = model(z_in, t, **model_args)
|
| 288 |
+
pred = pred[:, :, -z_in.shape[2]:]
|
| 289 |
+
end = time.time()
|
| 290 |
+
|
| 291 |
+
print(f"Step {i} Forward time: {end - start:.4f} seconds")
|
| 292 |
+
pred_cond, pred_uncond = pred.chunk(2, dim=0)
|
| 293 |
+
v_pred = pred_uncond + guidance_scale * (pred_cond - pred_uncond)
|
| 294 |
+
|
| 295 |
+
# When model predict noise-z0, the actual velocity is (v_pred * -1)
|
| 296 |
+
if self.use_reversed_velocity:
|
| 297 |
+
v_pred = -v_pred
|
| 298 |
+
|
| 299 |
+
# update z
|
| 300 |
+
dt = timesteps[i] - timesteps[i + 1] if i < len(timesteps) - 1 else timesteps[i]
|
| 301 |
+
dt = dt / self.num_timesteps
|
| 302 |
+
z = z + v_pred * dt[:, None, None, None, None]
|
| 303 |
+
|
| 304 |
+
if mask is not None:
|
| 305 |
+
z = torch.where(mask_t_upper[:, None, :, None, None], z, x0)
|
| 306 |
+
return z
|
infworld/models/t5.py
ADDED
|
@@ -0,0 +1,321 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Adapted from PixArt
|
| 2 |
+
#
|
| 3 |
+
# Copyright (C) 2023 PixArt-alpha/PixArt-alpha
|
| 4 |
+
#
|
| 5 |
+
# This program is free software: you can redistribute it and/or modify
|
| 6 |
+
# it under the terms of the GNU Affero General Public License as published
|
| 7 |
+
# by the Free Software Foundation, either version 3 of the License, or
|
| 8 |
+
# (at your option) any later version.
|
| 9 |
+
#
|
| 10 |
+
# This program is distributed in the hope that it will be useful,
|
| 11 |
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 12 |
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 13 |
+
# GNU Affero General Public License for more details.
|
| 14 |
+
#
|
| 15 |
+
#
|
| 16 |
+
# This source code is licensed under the license found in the
|
| 17 |
+
# LICENSE file in the root directory of this source tree.
|
| 18 |
+
# --------------------------------------------------------
|
| 19 |
+
# References:
|
| 20 |
+
# PixArt: https://github.com/PixArt-alpha/PixArt-alpha
|
| 21 |
+
# T5: https://github.com/google-research/text-to-text-transfer-transformer
|
| 22 |
+
# --------------------------------------------------------
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
import html
|
| 26 |
+
import os
|
| 27 |
+
import re
|
| 28 |
+
import urllib.parse as ul
|
| 29 |
+
|
| 30 |
+
import ftfy
|
| 31 |
+
import torch
|
| 32 |
+
from bs4 import BeautifulSoup
|
| 33 |
+
from huggingface_hub import hf_hub_download
|
| 34 |
+
from transformers import AutoTokenizer, T5EncoderModel
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
class T5Embedder:
|
| 38 |
+
available_models = ["t5-v1_1-xxl"]
|
| 39 |
+
bad_punct_regex = re.compile(
|
| 40 |
+
r"[" + "#®•©™&@·º½¾¿¡§~" + "\)" + "\(" + "\]" + "\[" + "\}" + "\{" + "\|" + "\\" + "\/" + "\*" + r"]{1,}"
|
| 41 |
+
) # noqa
|
| 42 |
+
|
| 43 |
+
def __init__(
|
| 44 |
+
self,
|
| 45 |
+
device,
|
| 46 |
+
from_pretrained,
|
| 47 |
+
*,
|
| 48 |
+
cache_dir=None,
|
| 49 |
+
hf_token=None,
|
| 50 |
+
use_text_preprocessing=True,
|
| 51 |
+
t5_model_kwargs=None,
|
| 52 |
+
torch_dtype=None,
|
| 53 |
+
use_offload_folder=None,
|
| 54 |
+
model_max_length=120,
|
| 55 |
+
):
|
| 56 |
+
self.device = torch.device(device)
|
| 57 |
+
self.torch_dtype = torch_dtype or torch.bfloat16
|
| 58 |
+
if t5_model_kwargs is None:
|
| 59 |
+
t5_model_kwargs = {"low_cpu_mem_usage": True, "torch_dtype": self.torch_dtype}
|
| 60 |
+
if use_offload_folder is not None:
|
| 61 |
+
t5_model_kwargs["offload_folder"] = use_offload_folder
|
| 62 |
+
t5_model_kwargs["device_map"] = {
|
| 63 |
+
"shared": self.device,
|
| 64 |
+
"encoder.embed_tokens": self.device,
|
| 65 |
+
"encoder.block.0": self.device,
|
| 66 |
+
"encoder.block.1": self.device,
|
| 67 |
+
"encoder.block.2": self.device,
|
| 68 |
+
"encoder.block.3": self.device,
|
| 69 |
+
"encoder.block.4": self.device,
|
| 70 |
+
"encoder.block.5": self.device,
|
| 71 |
+
"encoder.block.6": self.device,
|
| 72 |
+
"encoder.block.7": self.device,
|
| 73 |
+
"encoder.block.8": self.device,
|
| 74 |
+
"encoder.block.9": self.device,
|
| 75 |
+
"encoder.block.10": self.device,
|
| 76 |
+
"encoder.block.11": self.device,
|
| 77 |
+
"encoder.block.12": "disk",
|
| 78 |
+
"encoder.block.13": "disk",
|
| 79 |
+
"encoder.block.14": "disk",
|
| 80 |
+
"encoder.block.15": "disk",
|
| 81 |
+
"encoder.block.16": "disk",
|
| 82 |
+
"encoder.block.17": "disk",
|
| 83 |
+
"encoder.block.18": "disk",
|
| 84 |
+
"encoder.block.19": "disk",
|
| 85 |
+
"encoder.block.20": "disk",
|
| 86 |
+
"encoder.block.21": "disk",
|
| 87 |
+
"encoder.block.22": "disk",
|
| 88 |
+
"encoder.block.23": "disk",
|
| 89 |
+
"encoder.final_layer_norm": "disk",
|
| 90 |
+
"encoder.dropout": "disk",
|
| 91 |
+
}
|
| 92 |
+
else:
|
| 93 |
+
t5_model_kwargs["device_map"] = {"shared": self.device, "encoder": self.device}
|
| 94 |
+
|
| 95 |
+
self.use_text_preprocessing = use_text_preprocessing
|
| 96 |
+
|
| 97 |
+
tokenizer_path = from_pretrained
|
| 98 |
+
path = from_pretrained
|
| 99 |
+
|
| 100 |
+
|
| 101 |
+
print(tokenizer_path)
|
| 102 |
+
self.tokenizer = AutoTokenizer.from_pretrained(tokenizer_path)
|
| 103 |
+
self.model = T5EncoderModel.from_pretrained(path, **t5_model_kwargs).eval()
|
| 104 |
+
self.model_max_length = model_max_length
|
| 105 |
+
|
| 106 |
+
def get_text_embeddings(self, texts):
|
| 107 |
+
texts = [self.text_preprocessing(text) for text in texts]
|
| 108 |
+
|
| 109 |
+
text_tokens_and_mask = self.tokenizer(
|
| 110 |
+
texts,
|
| 111 |
+
max_length=self.model_max_length,
|
| 112 |
+
padding="max_length",
|
| 113 |
+
truncation=True,
|
| 114 |
+
return_attention_mask=True,
|
| 115 |
+
add_special_tokens=True,
|
| 116 |
+
return_tensors="pt",
|
| 117 |
+
)
|
| 118 |
+
|
| 119 |
+
text_tokens_and_mask["input_ids"] = text_tokens_and_mask["input_ids"]
|
| 120 |
+
text_tokens_and_mask["attention_mask"] = text_tokens_and_mask["attention_mask"]
|
| 121 |
+
|
| 122 |
+
with torch.no_grad():
|
| 123 |
+
text_encoder_embs = self.model(
|
| 124 |
+
input_ids=text_tokens_and_mask["input_ids"].to(self.device),
|
| 125 |
+
attention_mask=text_tokens_and_mask["attention_mask"].to(self.device),
|
| 126 |
+
)["last_hidden_state"].detach()
|
| 127 |
+
return text_encoder_embs, text_tokens_and_mask["attention_mask"].to(self.device)
|
| 128 |
+
|
| 129 |
+
def text_preprocessing(self, text):
|
| 130 |
+
if self.use_text_preprocessing:
|
| 131 |
+
# The exact text cleaning as was in the training stage:
|
| 132 |
+
text = self.clean_caption(text)
|
| 133 |
+
text = self.clean_caption(text)
|
| 134 |
+
return text
|
| 135 |
+
else:
|
| 136 |
+
return text.lower().strip()
|
| 137 |
+
|
| 138 |
+
@staticmethod
|
| 139 |
+
def basic_clean(text):
|
| 140 |
+
text = ftfy.fix_text(text)
|
| 141 |
+
text = html.unescape(html.unescape(text))
|
| 142 |
+
return text.strip()
|
| 143 |
+
|
| 144 |
+
def clean_caption(self, caption):
|
| 145 |
+
caption = str(caption)
|
| 146 |
+
caption = ul.unquote_plus(caption)
|
| 147 |
+
caption = caption.strip().lower()
|
| 148 |
+
caption = re.sub("<person>", "person", caption)
|
| 149 |
+
# urls:
|
| 150 |
+
caption = re.sub(
|
| 151 |
+
r"\b((?:https?:(?:\/{1,3}|[a-zA-Z0-9%])|[a-zA-Z0-9.\-]+[.](?:com|co|ru|net|org|edu|gov|it)[\w/-]*\b\/?(?!@)))", # noqa
|
| 152 |
+
"",
|
| 153 |
+
caption,
|
| 154 |
+
) # regex for urls
|
| 155 |
+
caption = re.sub(
|
| 156 |
+
r"\b((?:www:(?:\/{1,3}|[a-zA-Z0-9%])|[a-zA-Z0-9.\-]+[.](?:com|co|ru|net|org|edu|gov|it)[\w/-]*\b\/?(?!@)))", # noqa
|
| 157 |
+
"",
|
| 158 |
+
caption,
|
| 159 |
+
) # regex for urls
|
| 160 |
+
# html:
|
| 161 |
+
caption = BeautifulSoup(caption, features="html.parser").text
|
| 162 |
+
|
| 163 |
+
# @<nickname>
|
| 164 |
+
caption = re.sub(r"@[\w\d]+\b", "", caption)
|
| 165 |
+
|
| 166 |
+
# 31C0—31EF CJK Strokes
|
| 167 |
+
# 31F0—31FF Katakana Phonetic Extensions
|
| 168 |
+
# 3200—32FF Enclosed CJK Letters and Months
|
| 169 |
+
# 3300—33FF CJK Compatibility
|
| 170 |
+
# 3400—4DBF CJK Unified Ideographs Extension A
|
| 171 |
+
# 4DC0—4DFF Yijing Hexagram Symbols
|
| 172 |
+
# 4E00—9FFF CJK Unified Ideographs
|
| 173 |
+
caption = re.sub(r"[\u31c0-\u31ef]+", "", caption)
|
| 174 |
+
caption = re.sub(r"[\u31f0-\u31ff]+", "", caption)
|
| 175 |
+
caption = re.sub(r"[\u3200-\u32ff]+", "", caption)
|
| 176 |
+
caption = re.sub(r"[\u3300-\u33ff]+", "", caption)
|
| 177 |
+
caption = re.sub(r"[\u3400-\u4dbf]+", "", caption)
|
| 178 |
+
caption = re.sub(r"[\u4dc0-\u4dff]+", "", caption)
|
| 179 |
+
caption = re.sub(r"[\u4e00-\u9fff]+", "", caption)
|
| 180 |
+
#######################################################
|
| 181 |
+
|
| 182 |
+
# все виды тире / all types of dash --> "-"
|
| 183 |
+
caption = re.sub(
|
| 184 |
+
r"[\u002D\u058A\u05BE\u1400\u1806\u2010-\u2015\u2E17\u2E1A\u2E3A\u2E3B\u2E40\u301C\u3030\u30A0\uFE31\uFE32\uFE58\uFE63\uFF0D]+", # noqa
|
| 185 |
+
"-",
|
| 186 |
+
caption,
|
| 187 |
+
)
|
| 188 |
+
|
| 189 |
+
# кавычки к одному стандарту
|
| 190 |
+
caption = re.sub(r"[`´«»“”¨]", '"', caption)
|
| 191 |
+
caption = re.sub(r"[‘’]", "'", caption)
|
| 192 |
+
|
| 193 |
+
# "
|
| 194 |
+
caption = re.sub(r""?", "", caption)
|
| 195 |
+
# &
|
| 196 |
+
caption = re.sub(r"&", "", caption)
|
| 197 |
+
|
| 198 |
+
# ip adresses:
|
| 199 |
+
caption = re.sub(r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}", " ", caption)
|
| 200 |
+
|
| 201 |
+
# article ids:
|
| 202 |
+
caption = re.sub(r"\d:\d\d\s+$", "", caption)
|
| 203 |
+
|
| 204 |
+
# \n
|
| 205 |
+
caption = re.sub(r"\\n", " ", caption)
|
| 206 |
+
|
| 207 |
+
# "#123"
|
| 208 |
+
caption = re.sub(r"#\d{1,3}\b", "", caption)
|
| 209 |
+
# "#12345.."
|
| 210 |
+
caption = re.sub(r"#\d{5,}\b", "", caption)
|
| 211 |
+
# "123456.."
|
| 212 |
+
caption = re.sub(r"\b\d{6,}\b", "", caption)
|
| 213 |
+
# filenames:
|
| 214 |
+
caption = re.sub(r"[\S]+\.(?:png|jpg|jpeg|bmp|webp|eps|pdf|apk|mp4)", "", caption)
|
| 215 |
+
|
| 216 |
+
#
|
| 217 |
+
caption = re.sub(r"[\"\']{2,}", r'"', caption) # """AUSVERKAUFT"""
|
| 218 |
+
caption = re.sub(r"[\.]{2,}", r" ", caption) # """AUSVERKAUFT"""
|
| 219 |
+
|
| 220 |
+
caption = re.sub(self.bad_punct_regex, r" ", caption) # ***AUSVERKAUFT***, #AUSVERKAUFT
|
| 221 |
+
caption = re.sub(r"\s+\.\s+", r" ", caption) # " . "
|
| 222 |
+
|
| 223 |
+
# this-is-my-cute-cat / this_is_my_cute_cat
|
| 224 |
+
regex2 = re.compile(r"(?:\-|\_)")
|
| 225 |
+
if len(re.findall(regex2, caption)) > 3:
|
| 226 |
+
caption = re.sub(regex2, " ", caption)
|
| 227 |
+
|
| 228 |
+
caption = self.basic_clean(caption)
|
| 229 |
+
|
| 230 |
+
caption = re.sub(r"\b[a-zA-Z]{1,3}\d{3,15}\b", "", caption) # jc6640
|
| 231 |
+
caption = re.sub(r"\b[a-zA-Z]+\d+[a-zA-Z]+\b", "", caption) # jc6640vc
|
| 232 |
+
caption = re.sub(r"\b\d+[a-zA-Z]+\d+\b", "", caption) # 6640vc231
|
| 233 |
+
|
| 234 |
+
caption = re.sub(r"(worldwide\s+)?(free\s+)?shipping", "", caption)
|
| 235 |
+
caption = re.sub(r"(free\s)?download(\sfree)?", "", caption)
|
| 236 |
+
caption = re.sub(r"\bclick\b\s(?:for|on)\s\w+", "", caption)
|
| 237 |
+
caption = re.sub(r"\b(?:png|jpg|jpeg|bmp|webp|eps|pdf|apk|mp4)(\simage[s]?)?", "", caption)
|
| 238 |
+
caption = re.sub(r"\bpage\s+\d+\b", "", caption)
|
| 239 |
+
|
| 240 |
+
caption = re.sub(r"\b\d*[a-zA-Z]+\d+[a-zA-Z]+\d+[a-zA-Z\d]*\b", r" ", caption) # j2d1a2a...
|
| 241 |
+
|
| 242 |
+
caption = re.sub(r"\b\d+\.?\d*[xх×]\d+\.?\d*\b", "", caption)
|
| 243 |
+
|
| 244 |
+
caption = re.sub(r"\b\s+\:\s+", r": ", caption)
|
| 245 |
+
caption = re.sub(r"(\D[,\./])\b", r"\1 ", caption)
|
| 246 |
+
caption = re.sub(r"\s+", " ", caption)
|
| 247 |
+
|
| 248 |
+
caption.strip()
|
| 249 |
+
|
| 250 |
+
caption = re.sub(r"^[\"\']([\w\W]+)[\"\']$", r"\1", caption)
|
| 251 |
+
caption = re.sub(r"^[\'\_,\-\:;]", r"", caption)
|
| 252 |
+
caption = re.sub(r"[\'\_,\-\:\-\+]$", r"", caption)
|
| 253 |
+
caption = re.sub(r"^\.\S+$", "", caption)
|
| 254 |
+
|
| 255 |
+
return caption.strip()
|
| 256 |
+
|
| 257 |
+
|
| 258 |
+
class T5Encoder:
|
| 259 |
+
def __init__(
|
| 260 |
+
self,
|
| 261 |
+
from_pretrained=None,
|
| 262 |
+
model_max_length=120,
|
| 263 |
+
device="cuda",
|
| 264 |
+
dtype=torch.float,
|
| 265 |
+
shardformer=False,
|
| 266 |
+
allow_tf32=True,
|
| 267 |
+
):
|
| 268 |
+
assert from_pretrained is not None, "Please specify the path to the T5 model"
|
| 269 |
+
|
| 270 |
+
self.t5 = T5Embedder(
|
| 271 |
+
device=device,
|
| 272 |
+
torch_dtype=dtype,
|
| 273 |
+
from_pretrained=from_pretrained,
|
| 274 |
+
model_max_length=model_max_length,
|
| 275 |
+
)
|
| 276 |
+
self.t5.model.to(dtype=dtype)
|
| 277 |
+
self.y_embedder = None
|
| 278 |
+
|
| 279 |
+
self.model_max_length = model_max_length
|
| 280 |
+
self.output_dim = self.t5.model.config.d_model
|
| 281 |
+
|
| 282 |
+
self.allow_tf32 = allow_tf32
|
| 283 |
+
|
| 284 |
+
if shardformer:
|
| 285 |
+
self.shardformer_t5()
|
| 286 |
+
|
| 287 |
+
def shardformer_t5(self):
|
| 288 |
+
from colossalai.shardformer import ShardConfig, ShardFormer
|
| 289 |
+
|
| 290 |
+
from opensora.acceleration.shardformer.policy.t5_encoder import T5EncoderPolicy
|
| 291 |
+
from opensora.utils.misc import requires_grad
|
| 292 |
+
|
| 293 |
+
shard_config = ShardConfig(
|
| 294 |
+
tensor_parallel_process_group=None,
|
| 295 |
+
pipeline_stage_manager=None,
|
| 296 |
+
enable_tensor_parallelism=False,
|
| 297 |
+
enable_fused_normalization=False,
|
| 298 |
+
enable_flash_attention=False,
|
| 299 |
+
enable_jit_fused=True,
|
| 300 |
+
enable_sequence_parallelism=False,
|
| 301 |
+
enable_sequence_overlap=False,
|
| 302 |
+
)
|
| 303 |
+
shard_former = ShardFormer(shard_config=shard_config)
|
| 304 |
+
optim_model, _ = shard_former.optimize(self.t5.model, policy=T5EncoderPolicy())
|
| 305 |
+
self.t5.model = optim_model.half()
|
| 306 |
+
|
| 307 |
+
# ensure the weights are frozen
|
| 308 |
+
requires_grad(self.t5.model, False)
|
| 309 |
+
|
| 310 |
+
def encode(self, text):
|
| 311 |
+
original_value = torch.backends.cuda.matmul.allow_tf32
|
| 312 |
+
if self.allow_tf32:
|
| 313 |
+
torch.backends.cuda.matmul.allow_tf32 = True
|
| 314 |
+
caption_embs, emb_masks = self.t5.get_text_embeddings(text)
|
| 315 |
+
caption_embs = caption_embs[:, None]
|
| 316 |
+
torch.backends.cuda.matmul.allow_tf32 = original_value
|
| 317 |
+
return dict(y=caption_embs, y_mask=emb_masks)
|
| 318 |
+
|
| 319 |
+
def null(self, n):
|
| 320 |
+
null_y = self.y_embedder.y_embedding[None].repeat(n, 1, 1)[:, None]
|
| 321 |
+
return null_y
|
infworld/models/umt5.py
ADDED
|
@@ -0,0 +1,605 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Modified from transformers.models.t5.modeling_t5
|
| 2 |
+
# Copyright 2024-2025 The Alibaba Wan Team Authors. All rights reserved.
|
| 3 |
+
import os
|
| 4 |
+
import html
|
| 5 |
+
import math
|
| 6 |
+
import ftfy
|
| 7 |
+
import string
|
| 8 |
+
import logging
|
| 9 |
+
import regex as re
|
| 10 |
+
|
| 11 |
+
import torch
|
| 12 |
+
import torch.nn as nn
|
| 13 |
+
import torch.nn.functional as F
|
| 14 |
+
|
| 15 |
+
from transformers import AutoTokenizer
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
__all__ = [
|
| 19 |
+
'T5Model',
|
| 20 |
+
'T5Encoder',
|
| 21 |
+
'T5Decoder',
|
| 22 |
+
'T5EncoderModel',
|
| 23 |
+
'HuggingfaceTokenizer',
|
| 24 |
+
]
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
def basic_clean(text):
|
| 28 |
+
text = ftfy.fix_text(text)
|
| 29 |
+
text = html.unescape(html.unescape(text))
|
| 30 |
+
return text.strip()
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
def whitespace_clean(text):
|
| 34 |
+
text = re.sub(r'\s+', ' ', text)
|
| 35 |
+
text = text.strip()
|
| 36 |
+
return text
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
def canonicalize(text, keep_punctuation_exact_string=None):
|
| 40 |
+
text = text.replace('_', ' ')
|
| 41 |
+
if keep_punctuation_exact_string:
|
| 42 |
+
text = keep_punctuation_exact_string.join(
|
| 43 |
+
part.translate(str.maketrans('', '', string.punctuation))
|
| 44 |
+
for part in text.split(keep_punctuation_exact_string))
|
| 45 |
+
else:
|
| 46 |
+
text = text.translate(str.maketrans('', '', string.punctuation))
|
| 47 |
+
text = text.lower()
|
| 48 |
+
text = re.sub(r'\s+', ' ', text)
|
| 49 |
+
return text.strip()
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
class HuggingfaceTokenizer:
|
| 53 |
+
|
| 54 |
+
def __init__(self, name, seq_len=None, clean=None, **kwargs):
|
| 55 |
+
assert clean in (None, 'whitespace', 'lower', 'canonicalize')
|
| 56 |
+
self.name = name
|
| 57 |
+
self.seq_len = seq_len
|
| 58 |
+
self.clean = clean
|
| 59 |
+
|
| 60 |
+
# init tokenizer
|
| 61 |
+
self.tokenizer = AutoTokenizer.from_pretrained(name, **kwargs)
|
| 62 |
+
self.vocab_size = self.tokenizer.vocab_size
|
| 63 |
+
|
| 64 |
+
def __call__(self, sequence, **kwargs):
|
| 65 |
+
return_mask = kwargs.pop('return_mask', False)
|
| 66 |
+
|
| 67 |
+
# arguments
|
| 68 |
+
_kwargs = {'return_tensors': 'pt'}
|
| 69 |
+
if self.seq_len is not None:
|
| 70 |
+
_kwargs.update({
|
| 71 |
+
'padding': 'max_length',
|
| 72 |
+
'truncation': True,
|
| 73 |
+
'max_length': self.seq_len
|
| 74 |
+
})
|
| 75 |
+
_kwargs.update(**kwargs)
|
| 76 |
+
|
| 77 |
+
# tokenization
|
| 78 |
+
if isinstance(sequence, str):
|
| 79 |
+
sequence = [sequence]
|
| 80 |
+
if self.clean:
|
| 81 |
+
sequence = [self._clean(u) for u in sequence]
|
| 82 |
+
ids = self.tokenizer(sequence, **_kwargs)
|
| 83 |
+
|
| 84 |
+
# output
|
| 85 |
+
if return_mask:
|
| 86 |
+
return ids.input_ids, ids.attention_mask
|
| 87 |
+
else:
|
| 88 |
+
return ids.input_ids
|
| 89 |
+
|
| 90 |
+
def _clean(self, text):
|
| 91 |
+
if self.clean == 'whitespace':
|
| 92 |
+
text = whitespace_clean(basic_clean(text))
|
| 93 |
+
elif self.clean == 'lower':
|
| 94 |
+
text = whitespace_clean(basic_clean(text)).lower()
|
| 95 |
+
elif self.clean == 'canonicalize':
|
| 96 |
+
text = canonicalize(basic_clean(text))
|
| 97 |
+
return text
|
| 98 |
+
|
| 99 |
+
def fp16_clamp(x):
|
| 100 |
+
if x.dtype == torch.float16 and torch.isinf(x).any():
|
| 101 |
+
clamp = torch.finfo(x.dtype).max - 1000
|
| 102 |
+
x = torch.clamp(x, min=-clamp, max=clamp)
|
| 103 |
+
return x
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
def init_weights(m):
|
| 107 |
+
if isinstance(m, T5LayerNorm):
|
| 108 |
+
nn.init.ones_(m.weight)
|
| 109 |
+
elif isinstance(m, T5Model):
|
| 110 |
+
nn.init.normal_(m.token_embedding.weight, std=1.0)
|
| 111 |
+
elif isinstance(m, T5FeedForward):
|
| 112 |
+
nn.init.normal_(m.gate[0].weight, std=m.dim**-0.5)
|
| 113 |
+
nn.init.normal_(m.fc1.weight, std=m.dim**-0.5)
|
| 114 |
+
nn.init.normal_(m.fc2.weight, std=m.dim_ffn**-0.5)
|
| 115 |
+
elif isinstance(m, T5Attention):
|
| 116 |
+
nn.init.normal_(m.q.weight, std=(m.dim * m.dim_attn)**-0.5)
|
| 117 |
+
nn.init.normal_(m.k.weight, std=m.dim**-0.5)
|
| 118 |
+
nn.init.normal_(m.v.weight, std=m.dim**-0.5)
|
| 119 |
+
nn.init.normal_(m.o.weight, std=(m.num_heads * m.dim_attn)**-0.5)
|
| 120 |
+
elif isinstance(m, T5RelativeEmbedding):
|
| 121 |
+
nn.init.normal_(
|
| 122 |
+
m.embedding.weight, std=(2 * m.num_buckets * m.num_heads)**-0.5)
|
| 123 |
+
|
| 124 |
+
|
| 125 |
+
class GELU(nn.Module):
|
| 126 |
+
|
| 127 |
+
def forward(self, x):
|
| 128 |
+
return 0.5 * x * (1.0 + torch.tanh(
|
| 129 |
+
math.sqrt(2.0 / math.pi) * (x + 0.044715 * torch.pow(x, 3.0))))
|
| 130 |
+
|
| 131 |
+
|
| 132 |
+
class T5LayerNorm(nn.Module):
|
| 133 |
+
|
| 134 |
+
def __init__(self, dim, eps=1e-6):
|
| 135 |
+
super(T5LayerNorm, self).__init__()
|
| 136 |
+
self.dim = dim
|
| 137 |
+
self.eps = eps
|
| 138 |
+
self.weight = nn.Parameter(torch.ones(dim))
|
| 139 |
+
|
| 140 |
+
def forward(self, x):
|
| 141 |
+
x = x * torch.rsqrt(x.float().pow(2).mean(dim=-1, keepdim=True) +
|
| 142 |
+
self.eps)
|
| 143 |
+
if self.weight.dtype in [torch.float16, torch.bfloat16]:
|
| 144 |
+
x = x.type_as(self.weight)
|
| 145 |
+
return self.weight * x
|
| 146 |
+
|
| 147 |
+
|
| 148 |
+
class T5Attention(nn.Module):
|
| 149 |
+
|
| 150 |
+
def __init__(self, dim, dim_attn, num_heads, dropout=0.1):
|
| 151 |
+
assert dim_attn % num_heads == 0
|
| 152 |
+
super(T5Attention, self).__init__()
|
| 153 |
+
self.dim = dim
|
| 154 |
+
self.dim_attn = dim_attn
|
| 155 |
+
self.num_heads = num_heads
|
| 156 |
+
self.head_dim = dim_attn // num_heads
|
| 157 |
+
|
| 158 |
+
# layers
|
| 159 |
+
self.q = nn.Linear(dim, dim_attn, bias=False)
|
| 160 |
+
self.k = nn.Linear(dim, dim_attn, bias=False)
|
| 161 |
+
self.v = nn.Linear(dim, dim_attn, bias=False)
|
| 162 |
+
self.o = nn.Linear(dim_attn, dim, bias=False)
|
| 163 |
+
self.dropout = nn.Dropout(dropout)
|
| 164 |
+
|
| 165 |
+
def forward(self, x, context=None, mask=None, pos_bias=None):
|
| 166 |
+
"""
|
| 167 |
+
x: [B, L1, C].
|
| 168 |
+
context: [B, L2, C] or None.
|
| 169 |
+
mask: [B, L2] or [B, L1, L2] or None.
|
| 170 |
+
"""
|
| 171 |
+
# check inputs
|
| 172 |
+
context = x if context is None else context
|
| 173 |
+
b, n, c = x.size(0), self.num_heads, self.head_dim
|
| 174 |
+
|
| 175 |
+
# compute query, key, value
|
| 176 |
+
q = self.q(x).view(b, -1, n, c)
|
| 177 |
+
k = self.k(context).view(b, -1, n, c)
|
| 178 |
+
v = self.v(context).view(b, -1, n, c)
|
| 179 |
+
|
| 180 |
+
# attention bias
|
| 181 |
+
attn_bias = x.new_zeros(b, n, q.size(1), k.size(1))
|
| 182 |
+
if pos_bias is not None:
|
| 183 |
+
attn_bias += pos_bias
|
| 184 |
+
if mask is not None:
|
| 185 |
+
assert mask.ndim in [2, 3]
|
| 186 |
+
mask = mask.view(b, 1, 1,
|
| 187 |
+
-1) if mask.ndim == 2 else mask.unsqueeze(1)
|
| 188 |
+
attn_bias.masked_fill_(mask == 0, torch.finfo(x.dtype).min)
|
| 189 |
+
|
| 190 |
+
# compute attention (T5 does not use scaling)
|
| 191 |
+
attn = torch.einsum('binc,bjnc->bnij', q, k) + attn_bias
|
| 192 |
+
attn = F.softmax(attn.float(), dim=-1).type_as(attn)
|
| 193 |
+
x = torch.einsum('bnij,bjnc->binc', attn, v)
|
| 194 |
+
|
| 195 |
+
# output
|
| 196 |
+
x = x.reshape(b, -1, n * c)
|
| 197 |
+
x = self.o(x)
|
| 198 |
+
x = self.dropout(x)
|
| 199 |
+
return x
|
| 200 |
+
|
| 201 |
+
|
| 202 |
+
class T5FeedForward(nn.Module):
|
| 203 |
+
|
| 204 |
+
def __init__(self, dim, dim_ffn, dropout=0.1):
|
| 205 |
+
super(T5FeedForward, self).__init__()
|
| 206 |
+
self.dim = dim
|
| 207 |
+
self.dim_ffn = dim_ffn
|
| 208 |
+
|
| 209 |
+
# layers
|
| 210 |
+
self.gate = nn.Sequential(nn.Linear(dim, dim_ffn, bias=False), GELU())
|
| 211 |
+
self.fc1 = nn.Linear(dim, dim_ffn, bias=False)
|
| 212 |
+
self.fc2 = nn.Linear(dim_ffn, dim, bias=False)
|
| 213 |
+
self.dropout = nn.Dropout(dropout)
|
| 214 |
+
|
| 215 |
+
def forward(self, x):
|
| 216 |
+
x = self.fc1(x) * self.gate(x)
|
| 217 |
+
x = self.dropout(x)
|
| 218 |
+
x = self.fc2(x)
|
| 219 |
+
x = self.dropout(x)
|
| 220 |
+
return x
|
| 221 |
+
|
| 222 |
+
|
| 223 |
+
class T5SelfAttention(nn.Module):
|
| 224 |
+
|
| 225 |
+
def __init__(self,
|
| 226 |
+
dim,
|
| 227 |
+
dim_attn,
|
| 228 |
+
dim_ffn,
|
| 229 |
+
num_heads,
|
| 230 |
+
num_buckets,
|
| 231 |
+
shared_pos=True,
|
| 232 |
+
dropout=0.1):
|
| 233 |
+
super(T5SelfAttention, self).__init__()
|
| 234 |
+
self.dim = dim
|
| 235 |
+
self.dim_attn = dim_attn
|
| 236 |
+
self.dim_ffn = dim_ffn
|
| 237 |
+
self.num_heads = num_heads
|
| 238 |
+
self.num_buckets = num_buckets
|
| 239 |
+
self.shared_pos = shared_pos
|
| 240 |
+
|
| 241 |
+
# layers
|
| 242 |
+
self.norm1 = T5LayerNorm(dim)
|
| 243 |
+
self.attn = T5Attention(dim, dim_attn, num_heads, dropout)
|
| 244 |
+
self.norm2 = T5LayerNorm(dim)
|
| 245 |
+
self.ffn = T5FeedForward(dim, dim_ffn, dropout)
|
| 246 |
+
self.pos_embedding = None if shared_pos else T5RelativeEmbedding(
|
| 247 |
+
num_buckets, num_heads, bidirectional=True)
|
| 248 |
+
|
| 249 |
+
def forward(self, x, mask=None, pos_bias=None):
|
| 250 |
+
e = pos_bias if self.shared_pos else self.pos_embedding(
|
| 251 |
+
x.size(1), x.size(1))
|
| 252 |
+
x = fp16_clamp(x + self.attn(self.norm1(x), mask=mask, pos_bias=e))
|
| 253 |
+
x = fp16_clamp(x + self.ffn(self.norm2(x)))
|
| 254 |
+
return x
|
| 255 |
+
|
| 256 |
+
|
| 257 |
+
class T5CrossAttention(nn.Module):
|
| 258 |
+
|
| 259 |
+
def __init__(self,
|
| 260 |
+
dim,
|
| 261 |
+
dim_attn,
|
| 262 |
+
dim_ffn,
|
| 263 |
+
num_heads,
|
| 264 |
+
num_buckets,
|
| 265 |
+
shared_pos=True,
|
| 266 |
+
dropout=0.1):
|
| 267 |
+
super(T5CrossAttention, self).__init__()
|
| 268 |
+
self.dim = dim
|
| 269 |
+
self.dim_attn = dim_attn
|
| 270 |
+
self.dim_ffn = dim_ffn
|
| 271 |
+
self.num_heads = num_heads
|
| 272 |
+
self.num_buckets = num_buckets
|
| 273 |
+
self.shared_pos = shared_pos
|
| 274 |
+
|
| 275 |
+
# layers
|
| 276 |
+
self.norm1 = T5LayerNorm(dim)
|
| 277 |
+
self.self_attn = T5Attention(dim, dim_attn, num_heads, dropout)
|
| 278 |
+
self.norm2 = T5LayerNorm(dim)
|
| 279 |
+
self.cross_attn = T5Attention(dim, dim_attn, num_heads, dropout)
|
| 280 |
+
self.norm3 = T5LayerNorm(dim)
|
| 281 |
+
self.ffn = T5FeedForward(dim, dim_ffn, dropout)
|
| 282 |
+
self.pos_embedding = None if shared_pos else T5RelativeEmbedding(
|
| 283 |
+
num_buckets, num_heads, bidirectional=False)
|
| 284 |
+
|
| 285 |
+
def forward(self,
|
| 286 |
+
x,
|
| 287 |
+
mask=None,
|
| 288 |
+
encoder_states=None,
|
| 289 |
+
encoder_mask=None,
|
| 290 |
+
pos_bias=None):
|
| 291 |
+
e = pos_bias if self.shared_pos else self.pos_embedding(
|
| 292 |
+
x.size(1), x.size(1))
|
| 293 |
+
x = fp16_clamp(x + self.self_attn(self.norm1(x), mask=mask, pos_bias=e))
|
| 294 |
+
x = fp16_clamp(x + self.cross_attn(
|
| 295 |
+
self.norm2(x), context=encoder_states, mask=encoder_mask))
|
| 296 |
+
x = fp16_clamp(x + self.ffn(self.norm3(x)))
|
| 297 |
+
return x
|
| 298 |
+
|
| 299 |
+
|
| 300 |
+
class T5RelativeEmbedding(nn.Module):
|
| 301 |
+
|
| 302 |
+
def __init__(self, num_buckets, num_heads, bidirectional, max_dist=128):
|
| 303 |
+
super(T5RelativeEmbedding, self).__init__()
|
| 304 |
+
self.num_buckets = num_buckets
|
| 305 |
+
self.num_heads = num_heads
|
| 306 |
+
self.bidirectional = bidirectional
|
| 307 |
+
self.max_dist = max_dist
|
| 308 |
+
|
| 309 |
+
# layers
|
| 310 |
+
self.embedding = nn.Embedding(num_buckets, num_heads)
|
| 311 |
+
|
| 312 |
+
def forward(self, lq, lk):
|
| 313 |
+
device = self.embedding.weight.device
|
| 314 |
+
# rel_pos = torch.arange(lk).unsqueeze(0).to(device) - \
|
| 315 |
+
# torch.arange(lq).unsqueeze(1).to(device)
|
| 316 |
+
rel_pos = torch.arange(lk, device=device).unsqueeze(0) - \
|
| 317 |
+
torch.arange(lq, device=device).unsqueeze(1)
|
| 318 |
+
rel_pos = self._relative_position_bucket(rel_pos)
|
| 319 |
+
rel_pos_embeds = self.embedding(rel_pos)
|
| 320 |
+
rel_pos_embeds = rel_pos_embeds.permute(2, 0, 1).unsqueeze(
|
| 321 |
+
0) # [1, N, Lq, Lk]
|
| 322 |
+
return rel_pos_embeds.contiguous()
|
| 323 |
+
|
| 324 |
+
def _relative_position_bucket(self, rel_pos):
|
| 325 |
+
# preprocess
|
| 326 |
+
if self.bidirectional:
|
| 327 |
+
num_buckets = self.num_buckets // 2
|
| 328 |
+
rel_buckets = (rel_pos > 0).long() * num_buckets
|
| 329 |
+
rel_pos = torch.abs(rel_pos)
|
| 330 |
+
else:
|
| 331 |
+
num_buckets = self.num_buckets
|
| 332 |
+
rel_buckets = 0
|
| 333 |
+
rel_pos = -torch.min(rel_pos, torch.zeros_like(rel_pos))
|
| 334 |
+
|
| 335 |
+
# embeddings for small and large positions
|
| 336 |
+
max_exact = num_buckets // 2
|
| 337 |
+
rel_pos_large = max_exact + (torch.log(rel_pos.float() / max_exact) /
|
| 338 |
+
math.log(self.max_dist / max_exact) *
|
| 339 |
+
(num_buckets - max_exact)).long()
|
| 340 |
+
rel_pos_large = torch.min(
|
| 341 |
+
rel_pos_large, torch.full_like(rel_pos_large, num_buckets - 1))
|
| 342 |
+
rel_buckets += torch.where(rel_pos < max_exact, rel_pos, rel_pos_large)
|
| 343 |
+
return rel_buckets
|
| 344 |
+
|
| 345 |
+
|
| 346 |
+
class T5Encoder(nn.Module):
|
| 347 |
+
|
| 348 |
+
def __init__(self,
|
| 349 |
+
vocab,
|
| 350 |
+
dim,
|
| 351 |
+
dim_attn,
|
| 352 |
+
dim_ffn,
|
| 353 |
+
num_heads,
|
| 354 |
+
num_layers,
|
| 355 |
+
num_buckets,
|
| 356 |
+
shared_pos=True,
|
| 357 |
+
dropout=0.1):
|
| 358 |
+
super(T5Encoder, self).__init__()
|
| 359 |
+
self.dim = dim
|
| 360 |
+
self.dim_attn = dim_attn
|
| 361 |
+
self.dim_ffn = dim_ffn
|
| 362 |
+
self.num_heads = num_heads
|
| 363 |
+
self.num_layers = num_layers
|
| 364 |
+
self.num_buckets = num_buckets
|
| 365 |
+
self.shared_pos = shared_pos
|
| 366 |
+
|
| 367 |
+
# layers
|
| 368 |
+
self.token_embedding = vocab if isinstance(vocab, nn.Embedding) \
|
| 369 |
+
else nn.Embedding(vocab, dim)
|
| 370 |
+
self.pos_embedding = T5RelativeEmbedding(
|
| 371 |
+
num_buckets, num_heads, bidirectional=True) if shared_pos else None
|
| 372 |
+
self.dropout = nn.Dropout(dropout)
|
| 373 |
+
self.blocks = nn.ModuleList([
|
| 374 |
+
T5SelfAttention(dim, dim_attn, dim_ffn, num_heads, num_buckets,
|
| 375 |
+
shared_pos, dropout) for _ in range(num_layers)
|
| 376 |
+
])
|
| 377 |
+
self.norm = T5LayerNorm(dim)
|
| 378 |
+
|
| 379 |
+
# initialize weights
|
| 380 |
+
self.apply(init_weights)
|
| 381 |
+
|
| 382 |
+
def forward(self, ids, mask=None):
|
| 383 |
+
x = self.token_embedding(ids)
|
| 384 |
+
x = self.dropout(x)
|
| 385 |
+
e = self.pos_embedding(x.size(1),
|
| 386 |
+
x.size(1)) if self.shared_pos else None
|
| 387 |
+
for block in self.blocks:
|
| 388 |
+
x = block(x, mask, pos_bias=e)
|
| 389 |
+
x = self.norm(x)
|
| 390 |
+
x = self.dropout(x)
|
| 391 |
+
return x
|
| 392 |
+
|
| 393 |
+
|
| 394 |
+
class T5Decoder(nn.Module):
|
| 395 |
+
|
| 396 |
+
def __init__(self,
|
| 397 |
+
vocab,
|
| 398 |
+
dim,
|
| 399 |
+
dim_attn,
|
| 400 |
+
dim_ffn,
|
| 401 |
+
num_heads,
|
| 402 |
+
num_layers,
|
| 403 |
+
num_buckets,
|
| 404 |
+
shared_pos=True,
|
| 405 |
+
dropout=0.1):
|
| 406 |
+
super(T5Decoder, self).__init__()
|
| 407 |
+
self.dim = dim
|
| 408 |
+
self.dim_attn = dim_attn
|
| 409 |
+
self.dim_ffn = dim_ffn
|
| 410 |
+
self.num_heads = num_heads
|
| 411 |
+
self.num_layers = num_layers
|
| 412 |
+
self.num_buckets = num_buckets
|
| 413 |
+
self.shared_pos = shared_pos
|
| 414 |
+
|
| 415 |
+
# layers
|
| 416 |
+
self.token_embedding = vocab if isinstance(vocab, nn.Embedding) \
|
| 417 |
+
else nn.Embedding(vocab, dim)
|
| 418 |
+
self.pos_embedding = T5RelativeEmbedding(
|
| 419 |
+
num_buckets, num_heads, bidirectional=False) if shared_pos else None
|
| 420 |
+
self.dropout = nn.Dropout(dropout)
|
| 421 |
+
self.blocks = nn.ModuleList([
|
| 422 |
+
T5CrossAttention(dim, dim_attn, dim_ffn, num_heads, num_buckets,
|
| 423 |
+
shared_pos, dropout) for _ in range(num_layers)
|
| 424 |
+
])
|
| 425 |
+
self.norm = T5LayerNorm(dim)
|
| 426 |
+
|
| 427 |
+
# initialize weights
|
| 428 |
+
self.apply(init_weights)
|
| 429 |
+
|
| 430 |
+
def forward(self, ids, mask=None, encoder_states=None, encoder_mask=None):
|
| 431 |
+
b, s = ids.size()
|
| 432 |
+
|
| 433 |
+
# causal mask
|
| 434 |
+
if mask is None:
|
| 435 |
+
mask = torch.tril(torch.ones(1, s, s).to(ids.device))
|
| 436 |
+
elif mask.ndim == 2:
|
| 437 |
+
mask = torch.tril(mask.unsqueeze(1).expand(-1, s, -1))
|
| 438 |
+
|
| 439 |
+
# layers
|
| 440 |
+
x = self.token_embedding(ids)
|
| 441 |
+
x = self.dropout(x)
|
| 442 |
+
e = self.pos_embedding(x.size(1),
|
| 443 |
+
x.size(1)) if self.shared_pos else None
|
| 444 |
+
for block in self.blocks:
|
| 445 |
+
x = block(x, mask, encoder_states, encoder_mask, pos_bias=e)
|
| 446 |
+
x = self.norm(x)
|
| 447 |
+
x = self.dropout(x)
|
| 448 |
+
return x
|
| 449 |
+
|
| 450 |
+
|
| 451 |
+
class T5Model(nn.Module):
|
| 452 |
+
|
| 453 |
+
def __init__(self,
|
| 454 |
+
vocab_size,
|
| 455 |
+
dim,
|
| 456 |
+
dim_attn,
|
| 457 |
+
dim_ffn,
|
| 458 |
+
num_heads,
|
| 459 |
+
encoder_layers,
|
| 460 |
+
decoder_layers,
|
| 461 |
+
num_buckets,
|
| 462 |
+
shared_pos=True,
|
| 463 |
+
dropout=0.1):
|
| 464 |
+
super(T5Model, self).__init__()
|
| 465 |
+
self.vocab_size = vocab_size
|
| 466 |
+
self.dim = dim
|
| 467 |
+
self.dim_attn = dim_attn
|
| 468 |
+
self.dim_ffn = dim_ffn
|
| 469 |
+
self.num_heads = num_heads
|
| 470 |
+
self.encoder_layers = encoder_layers
|
| 471 |
+
self.decoder_layers = decoder_layers
|
| 472 |
+
self.num_buckets = num_buckets
|
| 473 |
+
|
| 474 |
+
# layers
|
| 475 |
+
self.token_embedding = nn.Embedding(vocab_size, dim)
|
| 476 |
+
self.encoder = T5Encoder(self.token_embedding, dim, dim_attn, dim_ffn,
|
| 477 |
+
num_heads, encoder_layers, num_buckets,
|
| 478 |
+
shared_pos, dropout)
|
| 479 |
+
self.decoder = T5Decoder(self.token_embedding, dim, dim_attn, dim_ffn,
|
| 480 |
+
num_heads, decoder_layers, num_buckets,
|
| 481 |
+
shared_pos, dropout)
|
| 482 |
+
self.head = nn.Linear(dim, vocab_size, bias=False)
|
| 483 |
+
|
| 484 |
+
# initialize weights
|
| 485 |
+
self.apply(init_weights)
|
| 486 |
+
|
| 487 |
+
def forward(self, encoder_ids, encoder_mask, decoder_ids, decoder_mask):
|
| 488 |
+
x = self.encoder(encoder_ids, encoder_mask)
|
| 489 |
+
x = self.decoder(decoder_ids, decoder_mask, x, encoder_mask)
|
| 490 |
+
x = self.head(x)
|
| 491 |
+
return x
|
| 492 |
+
|
| 493 |
+
|
| 494 |
+
def _t5(name,
|
| 495 |
+
encoder_only=False,
|
| 496 |
+
decoder_only=False,
|
| 497 |
+
return_tokenizer=False,
|
| 498 |
+
tokenizer_kwargs={},
|
| 499 |
+
dtype=torch.float32,
|
| 500 |
+
device='cpu',
|
| 501 |
+
**kwargs):
|
| 502 |
+
# sanity check
|
| 503 |
+
assert not (encoder_only and decoder_only)
|
| 504 |
+
|
| 505 |
+
# params
|
| 506 |
+
if encoder_only:
|
| 507 |
+
model_cls = T5Encoder
|
| 508 |
+
kwargs['vocab'] = kwargs.pop('vocab_size')
|
| 509 |
+
kwargs['num_layers'] = kwargs.pop('encoder_layers')
|
| 510 |
+
_ = kwargs.pop('decoder_layers')
|
| 511 |
+
elif decoder_only:
|
| 512 |
+
model_cls = T5Decoder
|
| 513 |
+
kwargs['vocab'] = kwargs.pop('vocab_size')
|
| 514 |
+
kwargs['num_layers'] = kwargs.pop('decoder_layers')
|
| 515 |
+
_ = kwargs.pop('encoder_layers')
|
| 516 |
+
else:
|
| 517 |
+
model_cls = T5Model
|
| 518 |
+
|
| 519 |
+
# init model
|
| 520 |
+
with torch.device(device):
|
| 521 |
+
model = model_cls(**kwargs)
|
| 522 |
+
|
| 523 |
+
# set device
|
| 524 |
+
model = model.to(dtype=dtype, device=device)
|
| 525 |
+
|
| 526 |
+
# init tokenizer
|
| 527 |
+
if return_tokenizer:
|
| 528 |
+
tokenizer = HuggingfaceTokenizer(f'google/{name}', **tokenizer_kwargs)
|
| 529 |
+
return model, tokenizer
|
| 530 |
+
else:
|
| 531 |
+
return model
|
| 532 |
+
|
| 533 |
+
|
| 534 |
+
def umt5_xxl(**kwargs):
|
| 535 |
+
cfg = dict(
|
| 536 |
+
vocab_size=256384,
|
| 537 |
+
dim=4096,
|
| 538 |
+
dim_attn=4096,
|
| 539 |
+
dim_ffn=10240,
|
| 540 |
+
num_heads=64,
|
| 541 |
+
encoder_layers=24,
|
| 542 |
+
decoder_layers=24,
|
| 543 |
+
num_buckets=32,
|
| 544 |
+
shared_pos=False,
|
| 545 |
+
dropout=0.1)
|
| 546 |
+
cfg.update(**kwargs)
|
| 547 |
+
return _t5('umt5-xxl', **cfg)
|
| 548 |
+
|
| 549 |
+
|
| 550 |
+
class T5EncoderModel:
|
| 551 |
+
|
| 552 |
+
def __init__(
|
| 553 |
+
self,
|
| 554 |
+
model_max_length,
|
| 555 |
+
dtype=torch.bfloat16,
|
| 556 |
+
device=torch.cuda.current_device(),
|
| 557 |
+
checkpoint_path=None,
|
| 558 |
+
tokenizer_path=None,
|
| 559 |
+
shard_fn=None,
|
| 560 |
+
):
|
| 561 |
+
|
| 562 |
+
os.environ["TOKENIZERS_PARALLELISM"]="false"
|
| 563 |
+
|
| 564 |
+
self.model_max_length = model_max_length
|
| 565 |
+
self.dtype = dtype
|
| 566 |
+
self.device = device
|
| 567 |
+
self.checkpoint_path = checkpoint_path
|
| 568 |
+
self.tokenizer_path = tokenizer_path
|
| 569 |
+
|
| 570 |
+
# init model
|
| 571 |
+
model = umt5_xxl(
|
| 572 |
+
encoder_only=True,
|
| 573 |
+
return_tokenizer=False,
|
| 574 |
+
dtype=dtype,
|
| 575 |
+
device=device).eval().requires_grad_(False)
|
| 576 |
+
logging.info(f'loading {checkpoint_path}')
|
| 577 |
+
model.load_state_dict(torch.load(checkpoint_path, map_location='cpu'))
|
| 578 |
+
self.model = model
|
| 579 |
+
if shard_fn is not None:
|
| 580 |
+
self.model = shard_fn(self.model, sync_module_states=False)
|
| 581 |
+
else:
|
| 582 |
+
self.model.to(self.device)
|
| 583 |
+
# init tokenizer
|
| 584 |
+
self.tokenizer = HuggingfaceTokenizer(
|
| 585 |
+
name=tokenizer_path, seq_len=model_max_length, clean='whitespace')
|
| 586 |
+
|
| 587 |
+
self.output_dim = self.model.dim
|
| 588 |
+
self.y_embedder = None
|
| 589 |
+
|
| 590 |
+
@property
|
| 591 |
+
def t5(self,):
|
| 592 |
+
return self
|
| 593 |
+
|
| 594 |
+
def encode(self, texts):
|
| 595 |
+
ids, mask = self.tokenizer(
|
| 596 |
+
texts, return_mask=True, add_special_tokens=True)
|
| 597 |
+
ids = ids.to(self.device)
|
| 598 |
+
mask = mask.to(self.device)
|
| 599 |
+
seq_lens = mask.gt(0).sum(dim=1).long()
|
| 600 |
+
context = self.model(ids, mask).float()
|
| 601 |
+
return dict(y=context[:,None], y_mask=mask)
|
| 602 |
+
|
| 603 |
+
def null(self, n):
|
| 604 |
+
null_y = self.y_embedder.y_embedding[None].repeat(n, 1, 1)[:, None]
|
| 605 |
+
return null_y
|
infworld/utils/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
# infworld/utils package
|
infworld/utils/data_utils.py
ADDED
|
@@ -0,0 +1,854 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import io
|
| 3 |
+
import re
|
| 4 |
+
import math
|
| 5 |
+
import tempfile
|
| 6 |
+
import imageio
|
| 7 |
+
import random
|
| 8 |
+
from tqdm import tqdm
|
| 9 |
+
import subprocess
|
| 10 |
+
|
| 11 |
+
import cv2
|
| 12 |
+
import numpy as np
|
| 13 |
+
from decord import VideoReader
|
| 14 |
+
from PIL import Image
|
| 15 |
+
from moviepy.editor import AudioFileClip, VideoClip
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
import torch
|
| 19 |
+
from torchvision.io import write_video
|
| 20 |
+
from torchvision.utils import save_image
|
| 21 |
+
import torchvision.transforms as transforms
|
| 22 |
+
|
| 23 |
+
import binascii
|
| 24 |
+
import torchvision
|
| 25 |
+
import imageio
|
| 26 |
+
import os.path as osp
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
def infinite_iterator(iter):
|
| 30 |
+
while True:
|
| 31 |
+
for sample in iter:
|
| 32 |
+
yield sample
|
| 33 |
+
|
| 34 |
+
### Moved from opensora dataset utils
|
| 35 |
+
def save_sample(x, fps=8, save_path=None, normalize=True, value_range=(-1, 1)):
|
| 36 |
+
"""
|
| 37 |
+
Args:
|
| 38 |
+
x (Tensor): shape [C, T, H, W]
|
| 39 |
+
Returns:
|
| 40 |
+
x (Tensor): shape [T, H, W, C]
|
| 41 |
+
"""
|
| 42 |
+
assert x.ndim == 4
|
| 43 |
+
|
| 44 |
+
os.makedirs(os.path.dirname(save_path),exist_ok=True)
|
| 45 |
+
|
| 46 |
+
if x.shape[1] == 1: # T = 1: save as image
|
| 47 |
+
save_path += ".png"
|
| 48 |
+
x = x.squeeze(1) # [C, H, W]
|
| 49 |
+
save_image([x], save_path, normalize=normalize, value_range=value_range)
|
| 50 |
+
x = x.unsqueeze(0) # [1, C, H, W]
|
| 51 |
+
x = x.permute(0, 2, 3, 1) # [1, H, W, C]
|
| 52 |
+
else:
|
| 53 |
+
save_path += ".mp4"
|
| 54 |
+
if normalize:
|
| 55 |
+
low, high = value_range
|
| 56 |
+
x = x.clamp(min=low, max=high)
|
| 57 |
+
x = x.sub(low).div(max(high - low, 1e-5))
|
| 58 |
+
|
| 59 |
+
x = x.mul(255).add(0.5).clamp(0, 255).permute(1, 2, 3, 0).to("cpu", torch.uint8)
|
| 60 |
+
write_video(save_path, x, fps=fps, video_codec="h264")
|
| 61 |
+
print(f"Saved to {save_path}")
|
| 62 |
+
return x
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
def video_reader_from_data_meta(datameta, use_tempfile, num_threads_decord):
|
| 66 |
+
""" Get VideoReader from data meta; data meta needs to be video.
|
| 67 |
+
"""
|
| 68 |
+
if not datameta.is_video:
|
| 69 |
+
raise NotImplementedError('Unknown data type.')
|
| 70 |
+
|
| 71 |
+
if 'raw_frames' in datameta:
|
| 72 |
+
raw_data = datameta.raw_frames
|
| 73 |
+
if use_tempfile:
|
| 74 |
+
# write raw frames to a temp file before loading
|
| 75 |
+
# this avoids some codec problems
|
| 76 |
+
with tempfile.NamedTemporaryFile() as temp:
|
| 77 |
+
temp.write(raw_data)
|
| 78 |
+
video_reader = VideoReader(temp.name, num_threads=num_threads_decord)
|
| 79 |
+
else:
|
| 80 |
+
# Use io.BytesIO to read image data from memory
|
| 81 |
+
dataBytesIO = io.BytesIO(raw_data)
|
| 82 |
+
# Convert raw data to numpy array
|
| 83 |
+
# Use decord to read video data from memory
|
| 84 |
+
video_reader = VideoReader(dataBytesIO, num_threads=num_threads_decord)
|
| 85 |
+
elif "tar_dir" in datameta and "tar_filename" in datameta and "tar_key" in datameta:
|
| 86 |
+
raw_data = datameta.load_tar_videodata()
|
| 87 |
+
if use_tempfile:
|
| 88 |
+
# write raw frames to a temp file before loading
|
| 89 |
+
# this avoids some codec problems
|
| 90 |
+
with tempfile.NamedTemporaryFile() as temp:
|
| 91 |
+
temp.write(raw_data)
|
| 92 |
+
video_reader = VideoReader(temp.name, num_threads=num_threads_decord)
|
| 93 |
+
else:
|
| 94 |
+
# Use io.BytesIO to read image data from memory
|
| 95 |
+
dataBytesIO = io.BytesIO(raw_data)
|
| 96 |
+
# Convert raw data to numpy array
|
| 97 |
+
# Use decord to read video data from memory
|
| 98 |
+
video_reader = VideoReader(dataBytesIO, num_threads=num_threads_decord)
|
| 99 |
+
elif os.path.exists(datameta.filename):
|
| 100 |
+
video_reader = VideoReader(datameta.filename, num_threads=num_threads_decord)
|
| 101 |
+
else:
|
| 102 |
+
raise NotImplementedError('Not supported data format. rawframes or filename is needed.')
|
| 103 |
+
|
| 104 |
+
return video_reader
|
| 105 |
+
|
| 106 |
+
|
| 107 |
+
def cap_from_data_meta(datameta):
|
| 108 |
+
if not datameta.is_video:
|
| 109 |
+
raise NotImplementedError('Unknown data type.')
|
| 110 |
+
|
| 111 |
+
if 'raw_frames' in datameta:
|
| 112 |
+
raw_data = datameta.raw_frames
|
| 113 |
+
# write raw frames to a temp file before loading
|
| 114 |
+
# this avoids some codec problems
|
| 115 |
+
with tempfile.NamedTemporaryFile() as temp:
|
| 116 |
+
temp.write(raw_data)
|
| 117 |
+
cap = cv2.VideoCapture(temp.name)
|
| 118 |
+
elif "tar_dir" in datameta and "tar_filename" in datameta and "tar_key" in datameta:
|
| 119 |
+
raw_data = datameta.load_tar_videodata()
|
| 120 |
+
# write raw frames to a temp file before loading
|
| 121 |
+
# this avoids some codec problems
|
| 122 |
+
with tempfile.NamedTemporaryFile() as temp:
|
| 123 |
+
temp.write(raw_data)
|
| 124 |
+
cap = cv2.VideoCapture(temp.name)
|
| 125 |
+
elif os.path.exists(datameta.filename):
|
| 126 |
+
cap = cv2.VideoCapture(datameta.filename)
|
| 127 |
+
else:
|
| 128 |
+
raise NotImplementedError('Not supported data format. rawframes or filename is needed.')
|
| 129 |
+
|
| 130 |
+
return cap
|
| 131 |
+
|
| 132 |
+
|
| 133 |
+
def none_node_splitter(src, group=None):
|
| 134 |
+
yield from src
|
| 135 |
+
|
| 136 |
+
|
| 137 |
+
def resize_and_covert_to_gray(np_frames, pixel_value=16, interpolation=cv2.INTER_LINEAR, resize_only=False):
|
| 138 |
+
# Get the dimensions of the first frame
|
| 139 |
+
height, width, *_ = np_frames[0].shape
|
| 140 |
+
# Determine the new dimensions based on the aspect ratio of the original frame
|
| 141 |
+
if width < height:
|
| 142 |
+
new_width = pixel_value
|
| 143 |
+
new_height = int((new_width / width) * height)
|
| 144 |
+
else:
|
| 145 |
+
new_height = pixel_value
|
| 146 |
+
new_width = int((new_height / height) * width)
|
| 147 |
+
|
| 148 |
+
# Function to preprocess each frame
|
| 149 |
+
def transform(frame):
|
| 150 |
+
# Resize the frame
|
| 151 |
+
frame = cv2.resize(frame, (new_width, new_height), interpolation=interpolation)
|
| 152 |
+
# Convert the frame to grayscale
|
| 153 |
+
if not resize_only:
|
| 154 |
+
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
|
| 155 |
+
return frame
|
| 156 |
+
|
| 157 |
+
# Apply the transformation to each frame
|
| 158 |
+
resize_frames = [transform(frame) for frame in np_frames]
|
| 159 |
+
resize_frames = np.stack(resize_frames)
|
| 160 |
+
|
| 161 |
+
return resize_frames
|
| 162 |
+
|
| 163 |
+
def get_top_m_percent(arr, m_percent):
|
| 164 |
+
B, H, W = arr.shape
|
| 165 |
+
N = int(H * W * m_percent / 100)
|
| 166 |
+
result = np.zeros((B, N))
|
| 167 |
+
for i in range(B):
|
| 168 |
+
flattened_frame = arr[i].flatten()
|
| 169 |
+
flattened_frame = flattened_frame[~np.isnan(flattened_frame)]
|
| 170 |
+
top_m_percent_values = np.partition(flattened_frame, -N)[-N:]
|
| 171 |
+
result[i] = top_m_percent_values
|
| 172 |
+
return np.nanmean(result,axis=1)
|
| 173 |
+
|
| 174 |
+
def compute_optical_flow_score(np_frames, pixel_value=16):
|
| 175 |
+
video_length = np_frames.shape[0]
|
| 176 |
+
# Calculate the optical flow for each pair of frames
|
| 177 |
+
flow_scores = []
|
| 178 |
+
for i in range(1, video_length):
|
| 179 |
+
# Calculate the optical flow between the current and previous frame
|
| 180 |
+
flow = cv2.calcOpticalFlowFarneback(np_frames[i - 1], np_frames[i], None, 0.5, 3, 15, 3, 5, 1.2, 0)
|
| 181 |
+
# Convert the flow vectors to polar coordinates
|
| 182 |
+
magnitude, angle = cv2.cartToPolar(flow[..., 0], flow[..., 1])
|
| 183 |
+
# Append the mean magnitude of the flow vectors to the list of scores
|
| 184 |
+
flow_scores.append(magnitude)
|
| 185 |
+
|
| 186 |
+
# Return the flow score
|
| 187 |
+
return np.array(flow_scores)
|
| 188 |
+
|
| 189 |
+
def get_first_frame_from_video_path(video_path):
|
| 190 |
+
# get cv2 video capture data meta
|
| 191 |
+
cap = cv2.VideoCapture(video_path)
|
| 192 |
+
cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
|
| 193 |
+
|
| 194 |
+
# get first frame, ret will be False if the read operation fails.
|
| 195 |
+
ret, frame = cap.read()
|
| 196 |
+
if ret is False:
|
| 197 |
+
return None
|
| 198 |
+
cap.release()
|
| 199 |
+
|
| 200 |
+
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
| 201 |
+
# convert the numpy frame to Image.
|
| 202 |
+
frame = Image.fromarray(frame)
|
| 203 |
+
|
| 204 |
+
return frame
|
| 205 |
+
|
| 206 |
+
def get_first_clip_from_video(video_path, clip_len=1):
|
| 207 |
+
"""
|
| 208 |
+
获取视频前n帧(默认第1帧)
|
| 209 |
+
|
| 210 |
+
参数:
|
| 211 |
+
video_path: 视频文件路径
|
| 212 |
+
n: 需要获取的帧数(从第1帧开始)
|
| 213 |
+
|
| 214 |
+
返回:
|
| 215 |
+
list: 包含前n帧PIL.Image对象的列表,空列表表示读取失败
|
| 216 |
+
"""
|
| 217 |
+
frames = []
|
| 218 |
+
cap = cv2.VideoCapture(video_path)
|
| 219 |
+
if not cap.isOpened():
|
| 220 |
+
return frames
|
| 221 |
+
|
| 222 |
+
if clip_len is None:
|
| 223 |
+
clip_len = 100000000
|
| 224 |
+
# 循环读取前n帧
|
| 225 |
+
for frame_idx in range(clip_len):
|
| 226 |
+
# 设置当前帧位置
|
| 227 |
+
cap.set(cv2.CAP_PROP_POS_FRAMES, frame_idx)
|
| 228 |
+
ret, frame = cap.read()
|
| 229 |
+
|
| 230 |
+
if not ret:
|
| 231 |
+
break # 视频长度不足时提前终止
|
| 232 |
+
|
| 233 |
+
# 格式转换
|
| 234 |
+
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
| 235 |
+
frames.append(frame)
|
| 236 |
+
|
| 237 |
+
cap.release()
|
| 238 |
+
return frames
|
| 239 |
+
|
| 240 |
+
def get_last_clip_from_video(video_path, clip_len=1):
|
| 241 |
+
"""
|
| 242 |
+
获取视频最后n帧
|
| 243 |
+
|
| 244 |
+
参数:
|
| 245 |
+
video_path: 视频文件路径
|
| 246 |
+
clip_len: 需要获取的帧数(从末尾开始)
|
| 247 |
+
|
| 248 |
+
返回:
|
| 249 |
+
list: 包含最后n帧的RGB帧列表,空列表表示读取失败
|
| 250 |
+
"""
|
| 251 |
+
frames = []
|
| 252 |
+
cap = cv2.VideoCapture(video_path)
|
| 253 |
+
if not cap.isOpened():
|
| 254 |
+
return frames
|
| 255 |
+
|
| 256 |
+
# 获取视频总帧数
|
| 257 |
+
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
|
| 258 |
+
|
| 259 |
+
# 计算起始帧位置
|
| 260 |
+
start_frame = max(0, total_frames - clip_len)
|
| 261 |
+
|
| 262 |
+
# 设置起始位置
|
| 263 |
+
cap.set(cv2.CAP_PROP_POS_FRAMES, start_frame)
|
| 264 |
+
|
| 265 |
+
# 读取剩余所有帧
|
| 266 |
+
while len(frames) < clip_len:
|
| 267 |
+
ret, frame = cap.read()
|
| 268 |
+
if not ret:
|
| 269 |
+
break
|
| 270 |
+
|
| 271 |
+
# 转换颜色空间并存储
|
| 272 |
+
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
| 273 |
+
frames.append(frame)
|
| 274 |
+
|
| 275 |
+
cap.release()
|
| 276 |
+
|
| 277 |
+
# 如果视频长度不足,返回实际能读取的帧
|
| 278 |
+
return frames[-clip_len:] if len(frames) >= clip_len else frames
|
| 279 |
+
|
| 280 |
+
|
| 281 |
+
def pad_to_square_ndarray(image, pad_value=255):
|
| 282 |
+
H, W, C = image.shape
|
| 283 |
+
max_size = max(H, W)
|
| 284 |
+
|
| 285 |
+
padded_image = np.full((max_size, max_size, C), pad_value, dtype=image.dtype)
|
| 286 |
+
|
| 287 |
+
top_left_y = (max_size - H) // 2
|
| 288 |
+
top_left_x = (max_size - W) // 2
|
| 289 |
+
|
| 290 |
+
padded_image[top_left_y:top_left_y + H, top_left_x:top_left_x + W, :] = image
|
| 291 |
+
|
| 292 |
+
return padded_image
|
| 293 |
+
|
| 294 |
+
def pad_to_square_pil(image, pad_value=255):
|
| 295 |
+
width, height = image.size
|
| 296 |
+
|
| 297 |
+
max_size = max(width, height)
|
| 298 |
+
|
| 299 |
+
new_image = Image.new("RGB", (max_size, max_size), (pad_value, pad_value, pad_value))
|
| 300 |
+
|
| 301 |
+
top_left_x = (max_size - width) // 2
|
| 302 |
+
top_left_y = (max_size - height) // 2
|
| 303 |
+
|
| 304 |
+
new_image.paste(image, (top_left_x, top_left_y))
|
| 305 |
+
|
| 306 |
+
return new_image
|
| 307 |
+
|
| 308 |
+
def separate_connected_components(mask):
|
| 309 |
+
|
| 310 |
+
labeled_array, num_features = label(mask)
|
| 311 |
+
|
| 312 |
+
separate_masks = []
|
| 313 |
+
bboxes = []
|
| 314 |
+
|
| 315 |
+
slices = find_objects(labeled_array)
|
| 316 |
+
|
| 317 |
+
for i in range(1, num_features + 1):
|
| 318 |
+
|
| 319 |
+
component_mask = (labeled_array == i).astype(np.uint8)
|
| 320 |
+
separate_masks.append(component_mask)
|
| 321 |
+
|
| 322 |
+
slice_ = slices[i - 1]
|
| 323 |
+
|
| 324 |
+
bbox = (slice_[1].start, slice_[0].start, slice_[1].stop, slice_[0].stop) # (xmin, ymin, xmax, ymax)
|
| 325 |
+
bboxes.append(bbox)
|
| 326 |
+
|
| 327 |
+
return separate_masks, bboxes
|
| 328 |
+
|
| 329 |
+
def bbox_random_crop(bbox):
|
| 330 |
+
|
| 331 |
+
xmin, ymin, xmax, ymax = bbox
|
| 332 |
+
|
| 333 |
+
width = xmax - xmin
|
| 334 |
+
height = ymax - ymin
|
| 335 |
+
|
| 336 |
+
if height > width:
|
| 337 |
+
square_size = width
|
| 338 |
+
max_y_start = ymax - square_size
|
| 339 |
+
y_start = random.randint(ymin, max_y_start)
|
| 340 |
+
return (xmin, y_start, xmin + square_size, y_start + square_size)
|
| 341 |
+
else:
|
| 342 |
+
square_size = height
|
| 343 |
+
max_x_start = xmax - square_size
|
| 344 |
+
x_start = random.randint(xmin, max_x_start)
|
| 345 |
+
return (x_start, ymin, x_start + square_size, ymin + square_size)
|
| 346 |
+
|
| 347 |
+
def inflate_bbox(bbox, d):
|
| 348 |
+
|
| 349 |
+
x_min, y_min, x_max, y_max = bbox
|
| 350 |
+
|
| 351 |
+
original_width = x_max - x_min
|
| 352 |
+
original_height = y_max - y_min
|
| 353 |
+
|
| 354 |
+
new_width = d * original_width
|
| 355 |
+
new_height = new_width
|
| 356 |
+
|
| 357 |
+
center_x = (x_min + x_max) / 2
|
| 358 |
+
center_y = (y_min + y_max) / 2
|
| 359 |
+
|
| 360 |
+
half_new_width = new_width / 2
|
| 361 |
+
half_new_height = new_height / 2
|
| 362 |
+
|
| 363 |
+
new_x_min = int(center_x - half_new_width)
|
| 364 |
+
new_x_max = int(center_x + half_new_width)
|
| 365 |
+
new_y_min = int(center_y - half_new_height)
|
| 366 |
+
new_y_max = int(center_y + half_new_height)
|
| 367 |
+
|
| 368 |
+
return (new_x_min, new_y_min, new_x_max, new_y_max)
|
| 369 |
+
|
| 370 |
+
def get_frame_by_idx(cap, frame_idxs):
|
| 371 |
+
if isinstance(frame_idxs, np.ndarray) or isinstance(frame_idxs, list):
|
| 372 |
+
frames = []
|
| 373 |
+
for frame_idx in frame_idxs:
|
| 374 |
+
cap.set(cv2.CAP_PROP_POS_FRAMES, frame_idx)
|
| 375 |
+
|
| 376 |
+
ret, frame = cap.read()
|
| 377 |
+
assert ret
|
| 378 |
+
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
| 379 |
+
frames.append(frame)
|
| 380 |
+
|
| 381 |
+
return frames
|
| 382 |
+
else:
|
| 383 |
+
cap.set(cv2.CAP_PROP_POS_FRAMES, frame_idxs)
|
| 384 |
+
ret, frame = cap.read()
|
| 385 |
+
assert ret
|
| 386 |
+
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
| 387 |
+
return frame
|
| 388 |
+
|
| 389 |
+
|
| 390 |
+
def recover_mask(array, shape):
|
| 391 |
+
size = np.prod(shape)
|
| 392 |
+
mask = np.unpackbits(array)[:size].reshape(shape).astype(np.uint8)
|
| 393 |
+
return mask
|
| 394 |
+
|
| 395 |
+
|
| 396 |
+
def calculate_iou(box1, box2):
|
| 397 |
+
x1_min, y1_min, x1_max, y1_max = box1
|
| 398 |
+
x2_min, y2_min, x2_max, y2_max = box2
|
| 399 |
+
|
| 400 |
+
inter_x_min = max(x1_min, x2_min)
|
| 401 |
+
inter_x_max = min(x1_max, x2_max)
|
| 402 |
+
inter_y_min = max(y1_min, y2_min)
|
| 403 |
+
inter_y_max = min(y1_max, y2_max)
|
| 404 |
+
|
| 405 |
+
if inter_x_max > inter_x_min and inter_y_max > inter_y_min:
|
| 406 |
+
inter_area = (inter_x_max - inter_x_min) * (inter_y_max - inter_y_min)
|
| 407 |
+
else:
|
| 408 |
+
inter_area = 0
|
| 409 |
+
|
| 410 |
+
area1 = (x1_max - x1_min) * (y1_max - y1_min)
|
| 411 |
+
area2 = (x2_max - x2_min) * (y2_max - y2_min)
|
| 412 |
+
|
| 413 |
+
union_area = area1 + area2 - inter_area
|
| 414 |
+
iou = inter_area / union_area if union_area != 0 else 0
|
| 415 |
+
return iou
|
| 416 |
+
|
| 417 |
+
def extract_number_from_suffix(s):
|
| 418 |
+
match = re.search(r'_\[([\d.]+)\]$', s)
|
| 419 |
+
if match:
|
| 420 |
+
return float(match.group(1))
|
| 421 |
+
else:
|
| 422 |
+
return 0
|
| 423 |
+
|
| 424 |
+
def tensor_to_video(tensor, output_video_path, input_audio_path, fps=30, dynamic_fps=True, audio_range=None, video_length=None):
|
| 425 |
+
"""
|
| 426 |
+
Converts a Tensor with shape [c, f, h, w] into a video and adds an audio track from the specified audio file.
|
| 427 |
+
|
| 428 |
+
Args:
|
| 429 |
+
tensor (Tensor): The Tensor to be converted, shaped [c, f, h, w].
|
| 430 |
+
output_video_path (str): The file path where the output video will be saved.
|
| 431 |
+
input_audio_path (str): The path to the audio file (WAV file) that contains the audio track to be added.
|
| 432 |
+
fps (int): The frame rate of the output video. Default is 30 fps.
|
| 433 |
+
"""
|
| 434 |
+
if tensor.shape[1] == 1:
|
| 435 |
+
output_video_path += '.png'
|
| 436 |
+
else:
|
| 437 |
+
output_video_path += '.mp4'
|
| 438 |
+
|
| 439 |
+
os.makedirs(os.path.dirname(output_video_path), exist_ok=True)
|
| 440 |
+
|
| 441 |
+
tensor = tensor.permute(1, 2, 3, 0).cpu().numpy() # convert to [f, h, w, c]
|
| 442 |
+
tensor = np.clip(tensor * 255, 0, 255).astype(np.uint8) # to [0, 255]
|
| 443 |
+
|
| 444 |
+
def make_frame(t):
|
| 445 |
+
frame_index = min(int(t * fps), tensor.shape[0] - 1)
|
| 446 |
+
return tensor[frame_index]
|
| 447 |
+
|
| 448 |
+
if not dynamic_fps:
|
| 449 |
+
video_duration = tensor.shape[0] / fps
|
| 450 |
+
|
| 451 |
+
audio_clip = AudioFileClip(input_audio_path)
|
| 452 |
+
audio_duration = audio_clip.duration
|
| 453 |
+
|
| 454 |
+
if not dynamic_fps:
|
| 455 |
+
final_duration = min(video_duration, audio_duration)
|
| 456 |
+
audio_clip = audio_clip.subclip(0, final_duration)
|
| 457 |
+
else:
|
| 458 |
+
select_start, select_end = audio_range[0] / video_length, audio_range[1] / video_length
|
| 459 |
+
audio_clip = audio_clip.subclip(select_start * audio_duration, select_end * audio_duration)
|
| 460 |
+
final_duration = (select_end - select_start) * audio_duration
|
| 461 |
+
fps = tensor.shape[0] / final_duration
|
| 462 |
+
|
| 463 |
+
new_video_clip = VideoClip(make_frame, duration=final_duration)
|
| 464 |
+
new_video_clip = new_video_clip.set_audio(audio_clip)
|
| 465 |
+
print(f"video save fps is: {fps}")
|
| 466 |
+
new_video_clip.write_videofile(output_video_path, fps=fps, audio_codec="aac")
|
| 467 |
+
|
| 468 |
+
def resize_and_centercrop(cond_image, target_size):
|
| 469 |
+
"""
|
| 470 |
+
Resize image to the target size without padding.
|
| 471 |
+
"""
|
| 472 |
+
|
| 473 |
+
# Get the original size
|
| 474 |
+
orig_h, orig_w = cond_image.height, cond_image.width
|
| 475 |
+
|
| 476 |
+
target_h, target_w = target_size
|
| 477 |
+
|
| 478 |
+
# Calculate the scaling factor for resizing
|
| 479 |
+
scale_h = target_h / orig_h
|
| 480 |
+
scale_w = target_w / orig_w
|
| 481 |
+
|
| 482 |
+
# Compute the final size
|
| 483 |
+
scale = max(scale_h, scale_w)
|
| 484 |
+
final_h = math.ceil(scale * orig_h)
|
| 485 |
+
final_w = math.ceil(scale * orig_w)
|
| 486 |
+
|
| 487 |
+
# Resize
|
| 488 |
+
resized_image = cond_image.resize((final_w, final_h), resample=Image.BILINEAR)
|
| 489 |
+
resized_image = np.array(resized_image)
|
| 490 |
+
|
| 491 |
+
# tensor and crop
|
| 492 |
+
resized_tensor = torch.from_numpy(resized_image)[None, ...].permute(0, 3, 1, 2).contiguous()
|
| 493 |
+
cropped_tensor = transforms.functional.center_crop(resized_tensor, target_size) # 1 C H W
|
| 494 |
+
cropped_tensor = cropped_tensor[:, :, None, :, :] # 1 C H W --> 1 C 1 H W
|
| 495 |
+
|
| 496 |
+
return cropped_tensor
|
| 497 |
+
|
| 498 |
+
|
| 499 |
+
def compute_face_to_front_angle(rvec):
|
| 500 |
+
# 参考姿态(正对镜头)
|
| 501 |
+
rvec_ref = np.zeros((3, 1), dtype=np.float32)
|
| 502 |
+
# rvec_ref = np.array([[0], [0], [1]], dtype=np.float32)
|
| 503 |
+
R_ref, _ = cv2.Rodrigues(rvec_ref)
|
| 504 |
+
R_face, _ = cv2.Rodrigues(rvec)
|
| 505 |
+
R_diff = R_face @ R_ref.T
|
| 506 |
+
angle_rad = np.arccos(np.clip((np.trace(R_diff) - 1) / 2, -1.0, 1.0))
|
| 507 |
+
return 180 - angle_rad * 180 / np.pi
|
| 508 |
+
|
| 509 |
+
|
| 510 |
+
|
| 511 |
+
def rotation_vector_to_euler_angles(rvec):
|
| 512 |
+
R, _ = cv2.Rodrigues(rvec)
|
| 513 |
+
sy = np.sqrt(R[0,0] * R[0,0] + R[1,0] * R[1,0])
|
| 514 |
+
singular = sy < 1e-6
|
| 515 |
+
|
| 516 |
+
if not singular:
|
| 517 |
+
pitch = np.arctan2(R[2,1], R[2,2])
|
| 518 |
+
yaw = np.arctan2(-R[2,0], sy)
|
| 519 |
+
roll = np.arctan2(R[1,0], R[0,0])
|
| 520 |
+
else:
|
| 521 |
+
pitch = np.arctan2(-R[1,2], R[1,1])
|
| 522 |
+
yaw = np.arctan2(-R[2,0], sy)
|
| 523 |
+
roll = 0
|
| 524 |
+
|
| 525 |
+
return np.degrees(yaw), np.degrees(pitch), np.degrees(roll)
|
| 526 |
+
|
| 527 |
+
|
| 528 |
+
def head_pose_calculation(face_landmarks, image_size=(720, 480)):
|
| 529 |
+
# ========== 可选:模型中的 3D 点定义 ==========
|
| 530 |
+
# 依照通用五点模型(左眼、右眼、鼻尖、左嘴角、右嘴角)
|
| 531 |
+
model_points = np.array([
|
| 532 |
+
[-30.0, 35.0, 0.0], # 左眼
|
| 533 |
+
[30.0, 35.0, 0.0], # 右眼
|
| 534 |
+
[0.0, 0.0, 0.0], # 鼻尖
|
| 535 |
+
[-25.0, -35.0, 0.0], # 左嘴角
|
| 536 |
+
[25.0, -35.0, 0.0], # 右嘴角
|
| 537 |
+
])
|
| 538 |
+
|
| 539 |
+
# ========== 相机内参 ==========
|
| 540 |
+
focal_length = image_size[0]
|
| 541 |
+
center = (image_size[0] / 2, image_size[1] / 2)
|
| 542 |
+
camera_matrix = np.array([
|
| 543 |
+
[focal_length, 0, center[0]],
|
| 544 |
+
[0, focal_length, center[1]],
|
| 545 |
+
[0, 0, 1]
|
| 546 |
+
], dtype=np.float32)
|
| 547 |
+
dist_coeffs = np.zeros((4, 1)) # 假设无畸变
|
| 548 |
+
|
| 549 |
+
success, rvec, tvec = cv2.solvePnP(
|
| 550 |
+
model_points, face_landmarks,
|
| 551 |
+
camera_matrix, dist_coeffs,
|
| 552 |
+
flags=cv2.SOLVEPNP_ITERATIVE
|
| 553 |
+
)
|
| 554 |
+
|
| 555 |
+
# # # 转换为旋转矩阵
|
| 556 |
+
# # R1, _ = cv2.Rodrigues(rvec)
|
| 557 |
+
# angle_face_to_front = compute_face_to_front_angle(rvec)
|
| 558 |
+
|
| 559 |
+
|
| 560 |
+
# 转换为欧拉角(单位:度)
|
| 561 |
+
yaw, pitch, roll = rotation_vector_to_euler_angles(rvec)
|
| 562 |
+
|
| 563 |
+
|
| 564 |
+
return abs(yaw), abs(pitch)
|
| 565 |
+
|
| 566 |
+
|
| 567 |
+
|
| 568 |
+
|
| 569 |
+
def rand_name(length=8, suffix=''):
|
| 570 |
+
name = binascii.b2a_hex(os.urandom(length)).decode('utf-8')
|
| 571 |
+
if suffix:
|
| 572 |
+
if not suffix.startswith('.'):
|
| 573 |
+
suffix = '.' + suffix
|
| 574 |
+
name += suffix
|
| 575 |
+
return name
|
| 576 |
+
|
| 577 |
+
|
| 578 |
+
|
| 579 |
+
def cache_video(tensor,
|
| 580 |
+
save_file=None,
|
| 581 |
+
fps=30,
|
| 582 |
+
suffix='.mp4',
|
| 583 |
+
nrow=8,
|
| 584 |
+
normalize=True,
|
| 585 |
+
value_range=(-1, 1),
|
| 586 |
+
retry=5):
|
| 587 |
+
|
| 588 |
+
# cache file
|
| 589 |
+
cache_file = osp.join('/tmp', rand_name(
|
| 590 |
+
suffix=suffix)) if save_file is None else save_file
|
| 591 |
+
|
| 592 |
+
# save to cache
|
| 593 |
+
error = None
|
| 594 |
+
for _ in range(retry):
|
| 595 |
+
|
| 596 |
+
# preprocess
|
| 597 |
+
tensor = tensor.clamp(min(value_range), max(value_range))
|
| 598 |
+
tensor = torch.stack([
|
| 599 |
+
torchvision.utils.make_grid(
|
| 600 |
+
u, nrow=nrow, normalize=normalize, value_range=value_range)
|
| 601 |
+
for u in tensor.unbind(2)
|
| 602 |
+
],
|
| 603 |
+
dim=1).permute(1, 2, 3, 0)
|
| 604 |
+
tensor = (tensor * 255).type(torch.uint8).cpu()
|
| 605 |
+
|
| 606 |
+
# write video
|
| 607 |
+
writer = imageio.get_writer(cache_file, fps=fps, codec='libx264', quality=10, ffmpeg_params=["-crf", "10"])
|
| 608 |
+
for frame in tensor.numpy():
|
| 609 |
+
writer.append_data(frame)
|
| 610 |
+
writer.close()
|
| 611 |
+
return cache_file
|
| 612 |
+
|
| 613 |
+
def save_silent_video(gen_video_samples, save_path, fps=25, quality=10, high_quality_save=True):
|
| 614 |
+
"""
|
| 615 |
+
保存无声音视频(支持追加���到已有视频)
|
| 616 |
+
|
| 617 |
+
参数:
|
| 618 |
+
gen_video_samples: 生成的视频张量 [B,C,T,H,W]
|
| 619 |
+
save_path: 保存路径(不带扩展名)
|
| 620 |
+
fps: 视频帧率
|
| 621 |
+
quality: 视频质量 (0-10)
|
| 622 |
+
high_quality_save: 是否启用高质量模式
|
| 623 |
+
"""
|
| 624 |
+
gen_video_samples = gen_video_samples[0] # 取第一个样本
|
| 625 |
+
|
| 626 |
+
# 创建保存目录
|
| 627 |
+
os.makedirs(os.path.dirname(save_path), exist_ok=True)
|
| 628 |
+
|
| 629 |
+
# 统一保存为MP4格式
|
| 630 |
+
final_save_path = f"{save_path}.mp4"
|
| 631 |
+
|
| 632 |
+
# 张量转视频帧
|
| 633 |
+
video_frames = (gen_video_samples + 1) / 2 # [-1,1] -> [0,1]
|
| 634 |
+
video_frames = video_frames.permute(1, 2, 3, 0).cpu().numpy() # T H W C
|
| 635 |
+
video_frames = np.clip(video_frames * 255, 0, 255).astype(np.uint8)
|
| 636 |
+
|
| 637 |
+
# 处理已有视频
|
| 638 |
+
all_frames = []
|
| 639 |
+
existing_fps = fps # 默认使用新视频的fps
|
| 640 |
+
if os.path.exists(final_save_path):
|
| 641 |
+
# 读取已有视频信息
|
| 642 |
+
with imageio.get_reader(final_save_path) as reader:
|
| 643 |
+
# 先获取元数据再读取帧
|
| 644 |
+
meta_data = reader.get_meta_data()
|
| 645 |
+
existing_fps = meta_data['fps']
|
| 646 |
+
existing_frames = [frame for frame in reader]
|
| 647 |
+
|
| 648 |
+
# 检查参数一致性
|
| 649 |
+
if existing_fps != fps:
|
| 650 |
+
raise ValueError(f"Existing video fps {existing_fps} conflicts with new fps {fps}")
|
| 651 |
+
if existing_frames[0].shape != video_frames[0].shape:
|
| 652 |
+
raise ValueError("Frame resolution mismatch between existing and new video")
|
| 653 |
+
|
| 654 |
+
all_frames.extend(existing_frames)
|
| 655 |
+
|
| 656 |
+
# 添加新帧
|
| 657 |
+
all_frames.extend(video_frames)
|
| 658 |
+
|
| 659 |
+
# 设置编码参数
|
| 660 |
+
if high_quality_save:
|
| 661 |
+
ffmpeg_params = [
|
| 662 |
+
'-c:v', 'libx264',
|
| 663 |
+
'-crf', '0', # 无损模式
|
| 664 |
+
'-preset', 'veryslow' # 最高压缩率
|
| 665 |
+
]
|
| 666 |
+
else:
|
| 667 |
+
ffmpeg_params = [
|
| 668 |
+
'-c:v', 'libx264',
|
| 669 |
+
'-crf', '23', # 默认质量 (0-51, 越小质量越高)
|
| 670 |
+
'-preset', 'medium'
|
| 671 |
+
]
|
| 672 |
+
|
| 673 |
+
# 使用imageio保存
|
| 674 |
+
with imageio.get_writer(
|
| 675 |
+
final_save_path,
|
| 676 |
+
fps=existing_fps, # 使用已有视频的fps(当存在时)
|
| 677 |
+
codec='libx264',
|
| 678 |
+
quality=quality,
|
| 679 |
+
ffmpeg_params=ffmpeg_params
|
| 680 |
+
) as writer:
|
| 681 |
+
for frame in all_frames:
|
| 682 |
+
writer.append_data(frame)
|
| 683 |
+
|
| 684 |
+
print(f"Silent video saved to: {final_save_path}")
|
| 685 |
+
|
| 686 |
+
def save_silent_video_overwrite(gen_video_samples, save_path, fps=25, quality=5, high_quality_save=False):
|
| 687 |
+
"""
|
| 688 |
+
保存无声音视频(支持追加帧到已有视频)
|
| 689 |
+
|
| 690 |
+
参数:
|
| 691 |
+
gen_video_samples: 生成的视频张量 [B,C,T,H,W]
|
| 692 |
+
save_path: 保存路径(不带扩展名)
|
| 693 |
+
fps: 视频帧率
|
| 694 |
+
quality: 视频质量 (0-10)
|
| 695 |
+
high_quality_save: 是否启用高质量模式
|
| 696 |
+
"""
|
| 697 |
+
gen_video_samples = gen_video_samples[0] # 取第一个样本
|
| 698 |
+
|
| 699 |
+
# 创建保存目录
|
| 700 |
+
os.makedirs(os.path.dirname(save_path), exist_ok=True)
|
| 701 |
+
|
| 702 |
+
# 统一保存为MP4格式
|
| 703 |
+
final_save_path = f"{save_path}.mp4"
|
| 704 |
+
|
| 705 |
+
# 张量转视频帧
|
| 706 |
+
video_frames = (gen_video_samples + 1) / 2 # [-1,1] -> [0,1]
|
| 707 |
+
video_frames = video_frames.permute(1, 2, 3, 0).cpu().numpy() # T H W C
|
| 708 |
+
video_frames = np.clip(video_frames * 255, 0, 255).astype(np.uint8)
|
| 709 |
+
|
| 710 |
+
# 处理已有视频
|
| 711 |
+
all_frames = []
|
| 712 |
+
|
| 713 |
+
# 添加新帧
|
| 714 |
+
all_frames.extend(video_frames)
|
| 715 |
+
|
| 716 |
+
# 设置编码参数
|
| 717 |
+
if high_quality_save:
|
| 718 |
+
ffmpeg_params = [
|
| 719 |
+
'-c:v', 'libx264',
|
| 720 |
+
'-crf', '0', # 无损模式
|
| 721 |
+
'-preset', 'veryslow' # 最高压缩率
|
| 722 |
+
]
|
| 723 |
+
else:
|
| 724 |
+
ffmpeg_params = [
|
| 725 |
+
'-c:v', 'libx264',
|
| 726 |
+
'-crf', '23', # 默认质量 (0-51, 越小质量越高)
|
| 727 |
+
'-preset', 'medium'
|
| 728 |
+
]
|
| 729 |
+
|
| 730 |
+
# 使用imageio保存
|
| 731 |
+
with imageio.get_writer(
|
| 732 |
+
final_save_path,
|
| 733 |
+
fps=fps, # 使用已有视频的fps(当存在时)
|
| 734 |
+
codec='libx264',
|
| 735 |
+
quality=quality,
|
| 736 |
+
ffmpeg_params=ffmpeg_params
|
| 737 |
+
) as writer:
|
| 738 |
+
for frame in all_frames:
|
| 739 |
+
writer.append_data(frame)
|
| 740 |
+
|
| 741 |
+
print(f"Silent video saved to: {final_save_path}")
|
| 742 |
+
|
| 743 |
+
def save_video_ffmpeg(gen_video_samples, save_path, vocal_audio_list, fps=25, quality=5, high_quality_save=False):
|
| 744 |
+
|
| 745 |
+
gen_video_samples = gen_video_samples[0]
|
| 746 |
+
|
| 747 |
+
def save_video(frames, save_path, fps, quality=9, ffmpeg_params=None):
|
| 748 |
+
writer = imageio.get_writer(
|
| 749 |
+
save_path, fps=fps, quality=quality, ffmpeg_params=ffmpeg_params
|
| 750 |
+
)
|
| 751 |
+
for frame in tqdm(frames, desc="Saving video"):
|
| 752 |
+
frame = np.array(frame)
|
| 753 |
+
writer.append_data(frame)
|
| 754 |
+
writer.close()
|
| 755 |
+
save_path_tmp = save_path + "-temp.mp4"
|
| 756 |
+
|
| 757 |
+
os.makedirs(os.path.dirname(save_path_tmp), exist_ok=True)
|
| 758 |
+
|
| 759 |
+
|
| 760 |
+
if high_quality_save:
|
| 761 |
+
# Experiment version
|
| 762 |
+
# NOTE: to be verified effects
|
| 763 |
+
cache_video(
|
| 764 |
+
tensor=gen_video_samples.unsqueeze(0),
|
| 765 |
+
save_file=save_path_tmp,
|
| 766 |
+
fps=fps,
|
| 767 |
+
nrow=1,
|
| 768 |
+
normalize=True,
|
| 769 |
+
value_range=(-1, 1)
|
| 770 |
+
)
|
| 771 |
+
else:
|
| 772 |
+
video_audio = (gen_video_samples+1)/2 # C T H W
|
| 773 |
+
video_audio = video_audio.permute(1, 2, 3, 0).cpu().numpy()
|
| 774 |
+
video_audio = np.clip(video_audio * 255, 0, 255).astype(np.uint8) # to [0, 255]
|
| 775 |
+
save_video(video_audio, save_path_tmp, fps=fps, quality=quality)
|
| 776 |
+
|
| 777 |
+
|
| 778 |
+
# crop audio according to video length
|
| 779 |
+
_, T, _, _ = gen_video_samples.shape
|
| 780 |
+
duration = T / fps
|
| 781 |
+
save_path_crop_audio = save_path + "-cropaudio.wav"
|
| 782 |
+
final_command = [
|
| 783 |
+
"/mnt/dolphinfs/ssd_pool/docker/user/hadoop-videogen-hl/hadoop-camera3d/gaofeng49/conda/memo/bin/ffmpeg",
|
| 784 |
+
"-i",
|
| 785 |
+
vocal_audio_list[0],
|
| 786 |
+
"-t",
|
| 787 |
+
f'{duration}',
|
| 788 |
+
save_path_crop_audio,
|
| 789 |
+
]
|
| 790 |
+
subprocess.run(final_command, check=True)
|
| 791 |
+
|
| 792 |
+
# generate video with audio
|
| 793 |
+
save_path = save_path + ".mp4"
|
| 794 |
+
if high_quality_save:
|
| 795 |
+
final_command = [
|
| 796 |
+
"/mnt/dolphinfs/ssd_pool/docker/user/hadoop-videogen-hl/hadoop-camera3d/gaofeng49/conda/memo/bin/ffmpeg",
|
| 797 |
+
"-y",
|
| 798 |
+
"-i", save_path_tmp,
|
| 799 |
+
"-i", save_path_crop_audio,
|
| 800 |
+
"-c:v", "libx264",
|
| 801 |
+
"-crf", "0",
|
| 802 |
+
"-preset", "veryslow", # 可选,压缩率更高但更慢
|
| 803 |
+
"-c:a", "aac", # mp4下只能用aac或copy
|
| 804 |
+
"-shortest",
|
| 805 |
+
save_path,
|
| 806 |
+
]
|
| 807 |
+
subprocess.run(final_command, check=True)
|
| 808 |
+
os.remove(save_path_tmp)
|
| 809 |
+
os.remove(save_path_crop_audio)
|
| 810 |
+
else:
|
| 811 |
+
final_command = [
|
| 812 |
+
"/mnt/dolphinfs/ssd_pool/docker/user/hadoop-videogen-hl/hadoop-camera3d/gaofeng49/conda/memo/bin/ffmpeg",
|
| 813 |
+
"-y",
|
| 814 |
+
"-i",
|
| 815 |
+
save_path_tmp,
|
| 816 |
+
"-i",
|
| 817 |
+
save_path_crop_audio,
|
| 818 |
+
"-c:v",
|
| 819 |
+
"libx264",
|
| 820 |
+
"-c:a",
|
| 821 |
+
"aac",
|
| 822 |
+
"-shortest",
|
| 823 |
+
save_path,
|
| 824 |
+
]
|
| 825 |
+
subprocess.run(final_command, check=True)
|
| 826 |
+
os.remove(save_path_tmp)
|
| 827 |
+
os.remove(save_path_crop_audio)
|
| 828 |
+
|
| 829 |
+
def audio_move_from_hdfs(src_path):
|
| 830 |
+
map_dict = {
|
| 831 |
+
"/mnt/dolphinfs/ssd_pool/docker/user/hadoop-videogen-hl/hadoop-camera3d/data_digitalhuman/talkingbody/yt_runway_sub/singlehuman_lipsync/yt_runway_0808_35w_merge/tar_record_caption_qwen2vlm_pose_audioemb_lipsync_camera_face_chinese":
|
| 832 |
+
"/mnt/hdfs/user/hadoop-vision-data/llm/dataset/videogen_dataset/data/digital_human_video/talkingbody/runway_chinese/singlehuman_lipsync/yt_runway_0808_35w_merge/tar_record_caption_qwen2vlm_pose_audioemb_lipsync_camera_face_chinese",
|
| 833 |
+
|
| 834 |
+
"/mnt/dolphinfs/ssd_pool/docker/user/hadoop-videogen-hl/hadoop-camera3d/data_digitalhuman/talkingbody/yt_runway_sub/singlehuman_lipsync/yt_runway_0829_52w_merge/tar_record_caption_qwen2vlm_pose_audioemb_part2_lipsync_camera_face_chinese":
|
| 835 |
+
"/mnt/hdfs/user/hadoop-vision-data/llm/dataset/videogen_dataset/data/digital_human_video/talkingbody/runway_chinese/singlehuman_lipsync/yt_runway_0829_52w_merge/tar_record_caption_qwen2vlm_pose_audioemb_part2_lipsync_camera_face_chinese",
|
| 836 |
+
|
| 837 |
+
"/mnt/dolphinfs/ssd_pool/docker/user/hadoop-videogen-hl/hadoop-camera3d/data_digitalhuman/talkingbody/yt_runway_sub/singlehuman_lipsync/yt_runway_0912_28w_merge/tar_record_caption_qwen2vlm_pose_audioemb_lipsync_camera_face_chinese":
|
| 838 |
+
"/mnt/hdfs/user/hadoop-vision-data/llm/dataset/videogen_dataset/data/digital_human_video/talkingbody/runway_chinese/singlehuman_lipsync/yt_runway_0912_28w_merge/tar_record_caption_qwen2vlm_pose_audioemb_lipsync_camera_face_chinese",
|
| 839 |
+
|
| 840 |
+
"/mnt/dolphinfs/ssd_pool/docker/user/hadoop-videogen-hl/hadoop-camera3d/data_digitalhuman/talkingbody/yt_runway_sub/singlehuman_lipsync/yt_runway_0926_105w_merge/tar_record_caption_qwen2vlm_pose_audioemb_lipsync_camera_face_chinese":
|
| 841 |
+
"/mnt/hdfs/user/hadoop-vision-data/llm/dataset/videogen_dataset/data/digital_human_video/talkingbody/runway_chinese/singlehuman_lipsync/yt_runway_0926_105w_merge/tar_record_caption_qwen2vlm_pose_audioemb_lipsync_camera_face_chinese",
|
| 842 |
+
|
| 843 |
+
"/mnt/dolphinfs/ssd_pool/docker/user/hadoop-videogen-hl/hadoop-camera3d/data_digitalhuman/talkingbody/yt_runway_sub/singlehuman_lipsync/yt_runway_1129_65w_part1/tar_record_caption_qwen2vlm_pose_audioemb_lipsync_camera_face_facecropcaption_chinese":
|
| 844 |
+
"/mnt/hdfs/user/hadoop-vision-data/llm/dataset/videogen_dataset/data/digital_human_video/talkingbody/runway_chinese/singlehuman_lipsync/yt_runway_1129_65w_part1/tar_record_caption_qwen2vlm_pose_audioemb_lipsync_camera_face_facecropcaption_chinese",
|
| 845 |
+
|
| 846 |
+
"/mnt/dolphinfs/ssd_pool/docker/user/hadoop-videogen-hl/hadoop-camera3d/data_digitalhuman/talkingbody/yt_runway_sub/singlehuman_lipsync/yt_runway_1129_65w_part2/tar_record_caption_qwen2vlm_pose_audioemb_lipsync_camera_face_facecropcaption_chinese":
|
| 847 |
+
"/mnt/hdfs/user/hadoop-vision-data/llm/dataset/videogen_dataset/data/digital_human_video/talkingbody/runway_chinese/singlehuman_lipsync/yt_runway_1129_65w_part2/tar_record_caption_qwen2vlm_pose_audioemb_lipsync_camera_face_facecropcaption_chinese"
|
| 848 |
+
}
|
| 849 |
+
|
| 850 |
+
for src_p in map_dict:
|
| 851 |
+
if src_p in src_path:
|
| 852 |
+
src_path = src_path.replace(src_p, map_dict[src_p])
|
| 853 |
+
|
| 854 |
+
return src_path
|
infworld/utils/dataset_utils.py
ADDED
|
@@ -0,0 +1,665 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import re
|
| 3 |
+
|
| 4 |
+
import numpy as np
|
| 5 |
+
import pandas as pd
|
| 6 |
+
import requests
|
| 7 |
+
import torch
|
| 8 |
+
import torchvision
|
| 9 |
+
import torchvision.transforms as transforms
|
| 10 |
+
from PIL import Image
|
| 11 |
+
from torchvision.datasets.folder import IMG_EXTENSIONS, pil_loader
|
| 12 |
+
from torchvision.io import write_video
|
| 13 |
+
from torchvision.utils import save_image
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
VID_EXTENSIONS = (".mp4", ".avi", ".mov", ".mkv")
|
| 17 |
+
|
| 18 |
+
regex = re.compile(
|
| 19 |
+
r"^(?:http|ftp)s?://" # http:// or https://
|
| 20 |
+
r"(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|" # domain...
|
| 21 |
+
r"localhost|" # localhost...
|
| 22 |
+
r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})" # ...or ip
|
| 23 |
+
r"(?::\d+)?" # optional port
|
| 24 |
+
r"(?:/?|[/?]\S+)$",
|
| 25 |
+
re.IGNORECASE,
|
| 26 |
+
)
|
| 27 |
+
|
| 28 |
+
import numbers
|
| 29 |
+
import random
|
| 30 |
+
|
| 31 |
+
import numpy as np
|
| 32 |
+
import torch
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def _is_tensor_video_clip(clip):
|
| 36 |
+
if not torch.is_tensor(clip):
|
| 37 |
+
raise TypeError("clip should be Tensor. Got %s" % type(clip))
|
| 38 |
+
|
| 39 |
+
if not clip.ndimension() == 4:
|
| 40 |
+
raise ValueError("clip should be 4D. Got %dD" % clip.dim())
|
| 41 |
+
|
| 42 |
+
return True
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
def crop(clip, i, j, h, w):
|
| 46 |
+
"""
|
| 47 |
+
Args:
|
| 48 |
+
clip (torch.tensor): Video clip to be cropped. Size is (T, C, H, W)
|
| 49 |
+
"""
|
| 50 |
+
if len(clip.size()) != 4:
|
| 51 |
+
raise ValueError("clip should be a 4D tensor")
|
| 52 |
+
return clip[..., i : i + h, j : j + w]
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
def resize(clip, target_size, interpolation_mode):
|
| 56 |
+
if len(target_size) != 2:
|
| 57 |
+
raise ValueError(f"target size should be tuple (height, width), instead got {target_size}")
|
| 58 |
+
return torch.nn.functional.interpolate(clip, size=target_size, mode=interpolation_mode, align_corners=False)
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
def resize_scale(clip, target_size, interpolation_mode):
|
| 62 |
+
if len(target_size) != 2:
|
| 63 |
+
raise ValueError(f"target size should be tuple (height, width), instead got {target_size}")
|
| 64 |
+
H, W = clip.size(-2), clip.size(-1)
|
| 65 |
+
scale_ = target_size[0] / min(H, W)
|
| 66 |
+
return torch.nn.functional.interpolate(clip, scale_factor=scale_, mode=interpolation_mode, align_corners=False)
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
def resized_crop(clip, i, j, h, w, size, interpolation_mode="bilinear"):
|
| 70 |
+
"""
|
| 71 |
+
Do spatial cropping and resizing to the video clip
|
| 72 |
+
Args:
|
| 73 |
+
clip (torch.tensor): Video clip to be cropped. Size is (T, C, H, W)
|
| 74 |
+
i (int): i in (i,j) i.e coordinates of the upper left corner.
|
| 75 |
+
j (int): j in (i,j) i.e coordinates of the upper left corner.
|
| 76 |
+
h (int): Height of the cropped region.
|
| 77 |
+
w (int): Width of the cropped region.
|
| 78 |
+
size (tuple(int, int)): height and width of resized clip
|
| 79 |
+
Returns:
|
| 80 |
+
clip (torch.tensor): Resized and cropped clip. Size is (T, C, H, W)
|
| 81 |
+
"""
|
| 82 |
+
if not _is_tensor_video_clip(clip):
|
| 83 |
+
raise ValueError("clip should be a 4D torch.tensor")
|
| 84 |
+
clip = crop(clip, i, j, h, w)
|
| 85 |
+
clip = resize(clip, size, interpolation_mode)
|
| 86 |
+
return clip
|
| 87 |
+
|
| 88 |
+
|
| 89 |
+
def center_crop(clip, crop_size):
|
| 90 |
+
if not _is_tensor_video_clip(clip):
|
| 91 |
+
raise ValueError("clip should be a 4D torch.tensor")
|
| 92 |
+
h, w = clip.size(-2), clip.size(-1)
|
| 93 |
+
th, tw = crop_size
|
| 94 |
+
if h < th or w < tw:
|
| 95 |
+
raise ValueError("height and width must be no smaller than crop_size")
|
| 96 |
+
|
| 97 |
+
i = int(round((h - th) / 2.0))
|
| 98 |
+
j = int(round((w - tw) / 2.0))
|
| 99 |
+
return crop(clip, i, j, th, tw)
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
def center_crop_using_short_edge(clip):
|
| 103 |
+
if not _is_tensor_video_clip(clip):
|
| 104 |
+
raise ValueError("clip should be a 4D torch.tensor")
|
| 105 |
+
h, w = clip.size(-2), clip.size(-1)
|
| 106 |
+
if h < w:
|
| 107 |
+
th, tw = h, h
|
| 108 |
+
i = 0
|
| 109 |
+
j = int(round((w - tw) / 2.0))
|
| 110 |
+
else:
|
| 111 |
+
th, tw = w, w
|
| 112 |
+
i = int(round((h - th) / 2.0))
|
| 113 |
+
j = 0
|
| 114 |
+
return crop(clip, i, j, th, tw)
|
| 115 |
+
|
| 116 |
+
|
| 117 |
+
def resize_crop_to_fill(clip, target_size):
|
| 118 |
+
if not _is_tensor_video_clip(clip):
|
| 119 |
+
raise ValueError("clip should be a 4D torch.tensor")
|
| 120 |
+
h, w = clip.size(-2), clip.size(-1)
|
| 121 |
+
th, tw = target_size[0], target_size[1]
|
| 122 |
+
rh, rw = th / h, tw / w
|
| 123 |
+
if rh > rw:
|
| 124 |
+
sh, sw = th, round(w * rh)
|
| 125 |
+
clip = resize(clip, (sh, sw), "bilinear")
|
| 126 |
+
i = 0
|
| 127 |
+
j = int(round(sw - tw) / 2.0)
|
| 128 |
+
else:
|
| 129 |
+
sh, sw = round(h * rw), tw
|
| 130 |
+
clip = resize(clip, (sh, sw), "bilinear")
|
| 131 |
+
i = int(round(sh - th) / 2.0)
|
| 132 |
+
j = 0
|
| 133 |
+
assert i + th <= clip.size(-2) and j + tw <= clip.size(-1)
|
| 134 |
+
return crop(clip, i, j, th, tw)
|
| 135 |
+
|
| 136 |
+
|
| 137 |
+
def random_shift_crop(clip):
|
| 138 |
+
"""
|
| 139 |
+
Slide along the long edge, with the short edge as crop size
|
| 140 |
+
"""
|
| 141 |
+
if not _is_tensor_video_clip(clip):
|
| 142 |
+
raise ValueError("clip should be a 4D torch.tensor")
|
| 143 |
+
h, w = clip.size(-2), clip.size(-1)
|
| 144 |
+
|
| 145 |
+
if h <= w:
|
| 146 |
+
short_edge = h
|
| 147 |
+
else:
|
| 148 |
+
short_edge = w
|
| 149 |
+
|
| 150 |
+
th, tw = short_edge, short_edge
|
| 151 |
+
|
| 152 |
+
i = torch.randint(0, h - th + 1, size=(1,)).item()
|
| 153 |
+
j = torch.randint(0, w - tw + 1, size=(1,)).item()
|
| 154 |
+
return crop(clip, i, j, th, tw)
|
| 155 |
+
|
| 156 |
+
|
| 157 |
+
def to_tensor(clip):
|
| 158 |
+
"""
|
| 159 |
+
Convert tensor data type from uint8 to float, divide value by 255.0 and
|
| 160 |
+
permute the dimensions of clip tensor
|
| 161 |
+
Args:
|
| 162 |
+
clip (torch.tensor, dtype=torch.uint8): Size is (T, C, H, W)
|
| 163 |
+
Return:
|
| 164 |
+
clip (torch.tensor, dtype=torch.float): Size is (T, C, H, W)
|
| 165 |
+
"""
|
| 166 |
+
_is_tensor_video_clip(clip)
|
| 167 |
+
if not clip.dtype == torch.uint8:
|
| 168 |
+
raise TypeError("clip tensor should have data type uint8. Got %s" % str(clip.dtype))
|
| 169 |
+
# return clip.float().permute(3, 0, 1, 2) / 255.0
|
| 170 |
+
return clip.float() / 255.0
|
| 171 |
+
|
| 172 |
+
|
| 173 |
+
def normalize(clip, mean, std, inplace=False):
|
| 174 |
+
"""
|
| 175 |
+
Args:
|
| 176 |
+
clip (torch.tensor): Video clip to be normalized. Size is (T, C, H, W)
|
| 177 |
+
mean (tuple): pixel RGB mean. Size is (3)
|
| 178 |
+
std (tuple): pixel standard deviation. Size is (3)
|
| 179 |
+
Returns:
|
| 180 |
+
normalized clip (torch.tensor): Size is (T, C, H, W)
|
| 181 |
+
"""
|
| 182 |
+
if not _is_tensor_video_clip(clip):
|
| 183 |
+
raise ValueError("clip should be a 4D torch.tensor")
|
| 184 |
+
if not inplace:
|
| 185 |
+
clip = clip.clone()
|
| 186 |
+
mean = torch.as_tensor(mean, dtype=clip.dtype, device=clip.device)
|
| 187 |
+
# print(mean)
|
| 188 |
+
std = torch.as_tensor(std, dtype=clip.dtype, device=clip.device)
|
| 189 |
+
clip.sub_(mean[:, None, None, None]).div_(std[:, None, None, None])
|
| 190 |
+
return clip
|
| 191 |
+
|
| 192 |
+
|
| 193 |
+
def hflip(clip):
|
| 194 |
+
"""
|
| 195 |
+
Args:
|
| 196 |
+
clip (torch.tensor): Video clip to be normalized. Size is (T, C, H, W)
|
| 197 |
+
Returns:
|
| 198 |
+
flipped clip (torch.tensor): Size is (T, C, H, W)
|
| 199 |
+
"""
|
| 200 |
+
if not _is_tensor_video_clip(clip):
|
| 201 |
+
raise ValueError("clip should be a 4D torch.tensor")
|
| 202 |
+
return clip.flip(-1)
|
| 203 |
+
|
| 204 |
+
|
| 205 |
+
class ResizeCrop:
|
| 206 |
+
def __init__(self, size):
|
| 207 |
+
if isinstance(size, numbers.Number):
|
| 208 |
+
self.size = (int(size), int(size))
|
| 209 |
+
else:
|
| 210 |
+
self.size = size
|
| 211 |
+
|
| 212 |
+
def __call__(self, clip):
|
| 213 |
+
clip = resize_crop_to_fill(clip, self.size)
|
| 214 |
+
return clip
|
| 215 |
+
|
| 216 |
+
def __repr__(self) -> str:
|
| 217 |
+
return f"{self.__class__.__name__}(size={self.size})"
|
| 218 |
+
|
| 219 |
+
|
| 220 |
+
class RandomCropVideo:
|
| 221 |
+
def __init__(self, size):
|
| 222 |
+
if isinstance(size, numbers.Number):
|
| 223 |
+
self.size = (int(size), int(size))
|
| 224 |
+
else:
|
| 225 |
+
self.size = size
|
| 226 |
+
|
| 227 |
+
def __call__(self, clip):
|
| 228 |
+
"""
|
| 229 |
+
Args:
|
| 230 |
+
clip (torch.tensor): Video clip to be cropped. Size is (T, C, H, W)
|
| 231 |
+
Returns:
|
| 232 |
+
torch.tensor: randomly cropped video clip.
|
| 233 |
+
size is (T, C, OH, OW)
|
| 234 |
+
"""
|
| 235 |
+
i, j, h, w = self.get_params(clip)
|
| 236 |
+
return crop(clip, i, j, h, w)
|
| 237 |
+
|
| 238 |
+
def get_params(self, clip):
|
| 239 |
+
h, w = clip.shape[-2:]
|
| 240 |
+
th, tw = self.size
|
| 241 |
+
|
| 242 |
+
if h < th or w < tw:
|
| 243 |
+
raise ValueError(f"Required crop size {(th, tw)} is larger than input image size {(h, w)}")
|
| 244 |
+
|
| 245 |
+
if w == tw and h == th:
|
| 246 |
+
return 0, 0, h, w
|
| 247 |
+
|
| 248 |
+
i = torch.randint(0, h - th + 1, size=(1,)).item()
|
| 249 |
+
j = torch.randint(0, w - tw + 1, size=(1,)).item()
|
| 250 |
+
|
| 251 |
+
return i, j, th, tw
|
| 252 |
+
|
| 253 |
+
def __repr__(self) -> str:
|
| 254 |
+
return f"{self.__class__.__name__}(size={self.size})"
|
| 255 |
+
|
| 256 |
+
|
| 257 |
+
class CenterCropResizeVideo:
|
| 258 |
+
"""
|
| 259 |
+
First use the short side for cropping length,
|
| 260 |
+
center crop video, then resize to the specified size
|
| 261 |
+
"""
|
| 262 |
+
|
| 263 |
+
def __init__(
|
| 264 |
+
self,
|
| 265 |
+
size,
|
| 266 |
+
interpolation_mode="bilinear",
|
| 267 |
+
):
|
| 268 |
+
if isinstance(size, tuple):
|
| 269 |
+
if len(size) != 2:
|
| 270 |
+
raise ValueError(f"size should be tuple (height, width), instead got {size}")
|
| 271 |
+
self.size = size
|
| 272 |
+
else:
|
| 273 |
+
self.size = (size, size)
|
| 274 |
+
|
| 275 |
+
self.interpolation_mode = interpolation_mode
|
| 276 |
+
|
| 277 |
+
def __call__(self, clip):
|
| 278 |
+
"""
|
| 279 |
+
Args:
|
| 280 |
+
clip (torch.tensor): Video clip to be cropped. Size is (T, C, H, W)
|
| 281 |
+
Returns:
|
| 282 |
+
torch.tensor: scale resized / center cropped video clip.
|
| 283 |
+
size is (T, C, crop_size, crop_size)
|
| 284 |
+
"""
|
| 285 |
+
clip_center_crop = center_crop_using_short_edge(clip)
|
| 286 |
+
clip_center_crop_resize = resize(
|
| 287 |
+
clip_center_crop, target_size=self.size, interpolation_mode=self.interpolation_mode
|
| 288 |
+
)
|
| 289 |
+
return clip_center_crop_resize
|
| 290 |
+
|
| 291 |
+
def __repr__(self) -> str:
|
| 292 |
+
return f"{self.__class__.__name__}(size={self.size}, interpolation_mode={self.interpolation_mode}"
|
| 293 |
+
|
| 294 |
+
|
| 295 |
+
class UCFCenterCropVideo:
|
| 296 |
+
"""
|
| 297 |
+
First scale to the specified size in equal proportion to the short edge,
|
| 298 |
+
then center cropping
|
| 299 |
+
"""
|
| 300 |
+
|
| 301 |
+
def __init__(
|
| 302 |
+
self,
|
| 303 |
+
size,
|
| 304 |
+
interpolation_mode="bilinear",
|
| 305 |
+
):
|
| 306 |
+
if isinstance(size, tuple):
|
| 307 |
+
if len(size) != 2:
|
| 308 |
+
raise ValueError(f"size should be tuple (height, width), instead got {size}")
|
| 309 |
+
self.size = size
|
| 310 |
+
else:
|
| 311 |
+
self.size = (size, size)
|
| 312 |
+
|
| 313 |
+
self.interpolation_mode = interpolation_mode
|
| 314 |
+
|
| 315 |
+
def __call__(self, clip):
|
| 316 |
+
"""
|
| 317 |
+
Args:
|
| 318 |
+
clip (torch.tensor): Video clip to be cropped. Size is (T, C, H, W)
|
| 319 |
+
Returns:
|
| 320 |
+
torch.tensor: scale resized / center cropped video clip.
|
| 321 |
+
size is (T, C, crop_size, crop_size)
|
| 322 |
+
"""
|
| 323 |
+
clip_resize = resize_scale(clip=clip, target_size=self.size, interpolation_mode=self.interpolation_mode)
|
| 324 |
+
clip_center_crop = center_crop(clip_resize, self.size)
|
| 325 |
+
return clip_center_crop
|
| 326 |
+
|
| 327 |
+
def __repr__(self) -> str:
|
| 328 |
+
return f"{self.__class__.__name__}(size={self.size}, interpolation_mode={self.interpolation_mode}"
|
| 329 |
+
|
| 330 |
+
|
| 331 |
+
class KineticsRandomCropResizeVideo:
|
| 332 |
+
"""
|
| 333 |
+
Slide along the long edge, with the short edge as crop size. And resie to the desired size.
|
| 334 |
+
"""
|
| 335 |
+
|
| 336 |
+
def __init__(
|
| 337 |
+
self,
|
| 338 |
+
size,
|
| 339 |
+
interpolation_mode="bilinear",
|
| 340 |
+
):
|
| 341 |
+
if isinstance(size, tuple):
|
| 342 |
+
if len(size) != 2:
|
| 343 |
+
raise ValueError(f"size should be tuple (height, width), instead got {size}")
|
| 344 |
+
self.size = size
|
| 345 |
+
else:
|
| 346 |
+
self.size = (size, size)
|
| 347 |
+
|
| 348 |
+
self.interpolation_mode = interpolation_mode
|
| 349 |
+
|
| 350 |
+
def __call__(self, clip):
|
| 351 |
+
clip_random_crop = random_shift_crop(clip)
|
| 352 |
+
clip_resize = resize(clip_random_crop, self.size, self.interpolation_mode)
|
| 353 |
+
return clip_resize
|
| 354 |
+
|
| 355 |
+
|
| 356 |
+
class CenterCropVideo:
|
| 357 |
+
def __init__(
|
| 358 |
+
self,
|
| 359 |
+
size,
|
| 360 |
+
interpolation_mode="bilinear",
|
| 361 |
+
):
|
| 362 |
+
if isinstance(size, tuple):
|
| 363 |
+
if len(size) != 2:
|
| 364 |
+
raise ValueError(f"size should be tuple (height, width), instead got {size}")
|
| 365 |
+
self.size = size
|
| 366 |
+
else:
|
| 367 |
+
self.size = (size, size)
|
| 368 |
+
|
| 369 |
+
self.interpolation_mode = interpolation_mode
|
| 370 |
+
|
| 371 |
+
def __call__(self, clip):
|
| 372 |
+
"""
|
| 373 |
+
Args:
|
| 374 |
+
clip (torch.tensor): Video clip to be cropped. Size is (T, C, H, W)
|
| 375 |
+
Returns:
|
| 376 |
+
torch.tensor: center cropped video clip.
|
| 377 |
+
size is (T, C, crop_size, crop_size)
|
| 378 |
+
"""
|
| 379 |
+
clip_center_crop = center_crop(clip, self.size)
|
| 380 |
+
return clip_center_crop
|
| 381 |
+
|
| 382 |
+
def __repr__(self) -> str:
|
| 383 |
+
return f"{self.__class__.__name__}(size={self.size}, interpolation_mode={self.interpolation_mode}"
|
| 384 |
+
|
| 385 |
+
|
| 386 |
+
class NormalizeVideo:
|
| 387 |
+
"""
|
| 388 |
+
Normalize the video clip by mean subtraction and division by standard deviation
|
| 389 |
+
Args:
|
| 390 |
+
mean (3-tuple): pixel RGB mean
|
| 391 |
+
std (3-tuple): pixel RGB standard deviation
|
| 392 |
+
inplace (boolean): whether do in-place normalization
|
| 393 |
+
"""
|
| 394 |
+
|
| 395 |
+
def __init__(self, mean, std, inplace=False):
|
| 396 |
+
self.mean = mean
|
| 397 |
+
self.std = std
|
| 398 |
+
self.inplace = inplace
|
| 399 |
+
|
| 400 |
+
def __call__(self, clip):
|
| 401 |
+
"""
|
| 402 |
+
Args:
|
| 403 |
+
clip (torch.tensor): video clip must be normalized. Size is (C, T, H, W)
|
| 404 |
+
"""
|
| 405 |
+
return normalize(clip, self.mean, self.std, self.inplace)
|
| 406 |
+
|
| 407 |
+
def __repr__(self) -> str:
|
| 408 |
+
return f"{self.__class__.__name__}(mean={self.mean}, std={self.std}, inplace={self.inplace})"
|
| 409 |
+
|
| 410 |
+
|
| 411 |
+
class ToTensorVideo:
|
| 412 |
+
"""
|
| 413 |
+
Convert tensor data type from uint8 to float, divide value by 255.0 and
|
| 414 |
+
permute the dimensions of clip tensor
|
| 415 |
+
"""
|
| 416 |
+
|
| 417 |
+
def __init__(self):
|
| 418 |
+
pass
|
| 419 |
+
|
| 420 |
+
def __call__(self, clip):
|
| 421 |
+
"""
|
| 422 |
+
Args:
|
| 423 |
+
clip (torch.tensor, dtype=torch.uint8): Size is (T, C, H, W)
|
| 424 |
+
Return:
|
| 425 |
+
clip (torch.tensor, dtype=torch.float): Size is (T, C, H, W)
|
| 426 |
+
"""
|
| 427 |
+
return to_tensor(clip)
|
| 428 |
+
|
| 429 |
+
def __repr__(self) -> str:
|
| 430 |
+
return self.__class__.__name__
|
| 431 |
+
|
| 432 |
+
|
| 433 |
+
class RandomHorizontalFlipVideo:
|
| 434 |
+
"""
|
| 435 |
+
Flip the video clip along the horizontal direction with a given probability
|
| 436 |
+
Args:
|
| 437 |
+
p (float): probability of the clip being flipped. Default value is 0.5
|
| 438 |
+
"""
|
| 439 |
+
|
| 440 |
+
def __init__(self, p=0.5):
|
| 441 |
+
self.p = p
|
| 442 |
+
|
| 443 |
+
def __call__(self, clip):
|
| 444 |
+
"""
|
| 445 |
+
Args:
|
| 446 |
+
clip (torch.tensor): Size is (T, C, H, W)
|
| 447 |
+
Return:
|
| 448 |
+
clip (torch.tensor): Size is (T, C, H, W)
|
| 449 |
+
"""
|
| 450 |
+
if random.random() < self.p:
|
| 451 |
+
clip = hflip(clip)
|
| 452 |
+
return clip
|
| 453 |
+
|
| 454 |
+
def __repr__(self) -> str:
|
| 455 |
+
return f"{self.__class__.__name__}(p={self.p})"
|
| 456 |
+
|
| 457 |
+
|
| 458 |
+
# ------------------------------------------------------------
|
| 459 |
+
# --------------------- Sampling ---------------------------
|
| 460 |
+
# ------------------------------------------------------------
|
| 461 |
+
class TemporalRandomCrop(object):
|
| 462 |
+
"""Temporally crop the given frame indices at a random location.
|
| 463 |
+
|
| 464 |
+
Args:
|
| 465 |
+
size (int): Desired length of frames will be seen in the model.
|
| 466 |
+
"""
|
| 467 |
+
|
| 468 |
+
def __init__(self, size):
|
| 469 |
+
self.size = size
|
| 470 |
+
|
| 471 |
+
def __call__(self, total_frames):
|
| 472 |
+
rand_end = max(0, total_frames - self.size - 1)
|
| 473 |
+
begin_index = random.randint(0, rand_end)
|
| 474 |
+
end_index = min(begin_index + self.size, total_frames)
|
| 475 |
+
return begin_index, end_index
|
| 476 |
+
|
| 477 |
+
|
| 478 |
+
def is_img(path):
|
| 479 |
+
ext = os.path.splitext(path)[-1].lower()
|
| 480 |
+
return ext in IMG_EXTENSIONS
|
| 481 |
+
|
| 482 |
+
|
| 483 |
+
def is_vid(path):
|
| 484 |
+
ext = os.path.splitext(path)[-1].lower()
|
| 485 |
+
return ext in VID_EXTENSIONS
|
| 486 |
+
|
| 487 |
+
|
| 488 |
+
def is_url(url):
|
| 489 |
+
return re.match(regex, url) is not None
|
| 490 |
+
|
| 491 |
+
|
| 492 |
+
def read_file(input_path):
|
| 493 |
+
if input_path.endswith(".csv"):
|
| 494 |
+
return pd.read_csv(input_path)
|
| 495 |
+
elif input_path.endswith(".parquet"):
|
| 496 |
+
return pd.read_parquet(input_path)
|
| 497 |
+
else:
|
| 498 |
+
raise NotImplementedError(f"Unsupported file format: {input_path}")
|
| 499 |
+
|
| 500 |
+
|
| 501 |
+
def download_url(input_path):
|
| 502 |
+
output_dir = "cache"
|
| 503 |
+
os.makedirs(output_dir, exist_ok=True)
|
| 504 |
+
base_name = os.path.basename(input_path)
|
| 505 |
+
output_path = os.path.join(output_dir, base_name)
|
| 506 |
+
img_data = requests.get(input_path).content
|
| 507 |
+
with open(output_path, "wb") as handler:
|
| 508 |
+
handler.write(img_data)
|
| 509 |
+
print(f"URL {input_path} downloaded to {output_path}")
|
| 510 |
+
return output_path
|
| 511 |
+
|
| 512 |
+
|
| 513 |
+
def temporal_random_crop(vframes, num_frames, frame_interval):
|
| 514 |
+
temporal_sample = TemporalRandomCrop(num_frames * frame_interval)
|
| 515 |
+
total_frames = len(vframes)
|
| 516 |
+
start_frame_ind, end_frame_ind = temporal_sample(total_frames)
|
| 517 |
+
assert (
|
| 518 |
+
end_frame_ind - start_frame_ind >= num_frames
|
| 519 |
+
), f"Not enough frames to sample, {end_frame_ind} - {start_frame_ind} < {num_frames}"
|
| 520 |
+
frame_indice = np.linspace(start_frame_ind, end_frame_ind - 1, num_frames, dtype=int)
|
| 521 |
+
video = vframes[frame_indice]
|
| 522 |
+
return video
|
| 523 |
+
|
| 524 |
+
|
| 525 |
+
def get_transforms_video(name="center", image_size=(256, 256)):
|
| 526 |
+
if name is None:
|
| 527 |
+
return None
|
| 528 |
+
elif name == "center":
|
| 529 |
+
assert image_size[0] == image_size[1], "image_size must be square for center crop"
|
| 530 |
+
transform_video = transforms.Compose(
|
| 531 |
+
[
|
| 532 |
+
ToTensorVideo(), # TCHW
|
| 533 |
+
# video_transforms.RandomHorizontalFlipVideo(),
|
| 534 |
+
UCFCenterCropVideo(image_size[0]),
|
| 535 |
+
transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5], inplace=True),
|
| 536 |
+
]
|
| 537 |
+
)
|
| 538 |
+
elif name == "resize_crop":
|
| 539 |
+
transform_video = transforms.Compose(
|
| 540 |
+
[
|
| 541 |
+
ToTensorVideo(), # TCHW
|
| 542 |
+
ResizeCrop(image_size),
|
| 543 |
+
transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5], inplace=True),
|
| 544 |
+
]
|
| 545 |
+
)
|
| 546 |
+
else:
|
| 547 |
+
raise NotImplementedError(f"Transform {name} not implemented")
|
| 548 |
+
return transform_video
|
| 549 |
+
|
| 550 |
+
|
| 551 |
+
def get_transforms_image(name="center", image_size=(256, 256)):
|
| 552 |
+
if name is None:
|
| 553 |
+
return None
|
| 554 |
+
elif name == "center":
|
| 555 |
+
assert image_size[0] == image_size[1], "Image size must be square for center crop"
|
| 556 |
+
transform = transforms.Compose(
|
| 557 |
+
[
|
| 558 |
+
transforms.Lambda(lambda pil_image: center_crop_arr(pil_image, image_size[0])),
|
| 559 |
+
# transforms.RandomHorizontalFlip(),
|
| 560 |
+
transforms.ToTensor(),
|
| 561 |
+
transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5], inplace=True),
|
| 562 |
+
]
|
| 563 |
+
)
|
| 564 |
+
elif name == "resize_crop":
|
| 565 |
+
transform = transforms.Compose(
|
| 566 |
+
[
|
| 567 |
+
transforms.Lambda(lambda pil_image: resize_crop_to_fill(pil_image, image_size)),
|
| 568 |
+
transforms.ToTensor(),
|
| 569 |
+
transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5], inplace=True),
|
| 570 |
+
]
|
| 571 |
+
)
|
| 572 |
+
else:
|
| 573 |
+
raise NotImplementedError(f"Transform {name} not implemented")
|
| 574 |
+
return transform
|
| 575 |
+
|
| 576 |
+
|
| 577 |
+
def read_image_from_path(path, transform=None, transform_name="center", num_frames=1, image_size=(256, 256)):
|
| 578 |
+
image = pil_loader(path)
|
| 579 |
+
if transform is None:
|
| 580 |
+
transform = get_transforms_image(image_size=image_size, name=transform_name)
|
| 581 |
+
image = transform(image)
|
| 582 |
+
video = image.unsqueeze(0).repeat(num_frames, 1, 1, 1)
|
| 583 |
+
video = video.permute(1, 0, 2, 3)
|
| 584 |
+
return video
|
| 585 |
+
|
| 586 |
+
|
| 587 |
+
def read_video_from_path(path, transform=None, transform_name="center", image_size=(256, 256)):
|
| 588 |
+
vframes, aframes, info = torchvision.io.read_video(filename=path, pts_unit="sec", output_format="TCHW")
|
| 589 |
+
if transform is None:
|
| 590 |
+
transform = get_transforms_video(image_size=image_size, name=transform_name)
|
| 591 |
+
video = transform(vframes) # T C H W
|
| 592 |
+
video = video.permute(1, 0, 2, 3)
|
| 593 |
+
return video
|
| 594 |
+
|
| 595 |
+
|
| 596 |
+
def read_from_path(path, image_size, transform_name="center"):
|
| 597 |
+
if is_url(path):
|
| 598 |
+
path = download_url(path)
|
| 599 |
+
ext = os.path.splitext(path)[-1].lower()
|
| 600 |
+
if ext.lower() in VID_EXTENSIONS:
|
| 601 |
+
return read_video_from_path(path, image_size=image_size, transform_name=transform_name)
|
| 602 |
+
else:
|
| 603 |
+
assert ext.lower() in IMG_EXTENSIONS, f"Unsupported file format: {ext}"
|
| 604 |
+
return read_image_from_path(path, image_size=image_size, transform_name=transform_name)
|
| 605 |
+
|
| 606 |
+
|
| 607 |
+
def save_sample(x, save_path=None, fps=8, normalize=True, value_range=(-1, 1), force_video=False, verbose=True):
|
| 608 |
+
"""
|
| 609 |
+
Args:
|
| 610 |
+
x (Tensor): shape [C, T, H, W]
|
| 611 |
+
"""
|
| 612 |
+
assert x.ndim == 4
|
| 613 |
+
|
| 614 |
+
if not force_video and x.shape[1] == 1: # T = 1: save as image
|
| 615 |
+
save_path += ".png"
|
| 616 |
+
x = x.squeeze(1)
|
| 617 |
+
save_image([x], save_path, normalize=normalize, value_range=value_range)
|
| 618 |
+
else:
|
| 619 |
+
save_path += ".mp4"
|
| 620 |
+
if normalize:
|
| 621 |
+
low, high = value_range
|
| 622 |
+
x.clamp_(min=low, max=high)
|
| 623 |
+
x.sub_(low).div_(max(high - low, 1e-5))
|
| 624 |
+
|
| 625 |
+
x = x.mul(255).add_(0.5).clamp_(0, 255).permute(1, 2, 3, 0).to("cpu", torch.uint8)
|
| 626 |
+
write_video(save_path, x, fps=fps, video_codec="h264")
|
| 627 |
+
if verbose:
|
| 628 |
+
print(f"Saved to {save_path}")
|
| 629 |
+
return save_path
|
| 630 |
+
|
| 631 |
+
|
| 632 |
+
def center_crop_arr(pil_image, image_size):
|
| 633 |
+
"""
|
| 634 |
+
Center cropping implementation from ADM.
|
| 635 |
+
https://github.com/openai/guided-diffusion/blob/8fb3ad9197f16bbc40620447b2742e13458d2831/guided_diffusion/image_datasets.py#L126
|
| 636 |
+
"""
|
| 637 |
+
while min(*pil_image.size) >= 2 * image_size:
|
| 638 |
+
pil_image = pil_image.resize(tuple(x // 2 for x in pil_image.size), resample=Image.BOX)
|
| 639 |
+
|
| 640 |
+
scale = image_size / min(*pil_image.size)
|
| 641 |
+
pil_image = pil_image.resize(tuple(round(x * scale) for x in pil_image.size), resample=Image.BICUBIC)
|
| 642 |
+
|
| 643 |
+
arr = np.array(pil_image)
|
| 644 |
+
crop_y = (arr.shape[0] - image_size) // 2
|
| 645 |
+
crop_x = (arr.shape[1] - image_size) // 2
|
| 646 |
+
return Image.fromarray(arr[crop_y : crop_y + image_size, crop_x : crop_x + image_size])
|
| 647 |
+
|
| 648 |
+
|
| 649 |
+
def resize_crop_to_fill(pil_image, image_size):
|
| 650 |
+
w, h = pil_image.size # PIL is (W, H)
|
| 651 |
+
th, tw = image_size
|
| 652 |
+
rh, rw = th / h, tw / w
|
| 653 |
+
if rh > rw:
|
| 654 |
+
sh, sw = th, round(w * rh)
|
| 655 |
+
image = pil_image.resize((sw, sh), Image.BICUBIC)
|
| 656 |
+
i = 0
|
| 657 |
+
j = int(round((sw - tw) / 2.0))
|
| 658 |
+
else:
|
| 659 |
+
sh, sw = round(h * rw), tw
|
| 660 |
+
image = pil_image.resize((sw, sh), Image.BICUBIC)
|
| 661 |
+
i = int(round((sh - th) / 2.0))
|
| 662 |
+
j = 0
|
| 663 |
+
arr = np.array(image)
|
| 664 |
+
assert i + th <= arr.shape[0] and j + tw <= arr.shape[1]
|
| 665 |
+
return Image.fromarray(arr[i : i + th, j : j + tw])
|
infworld/utils/prepare_dataloader.py
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import sys
|
| 2 |
+
import os
|
| 3 |
+
import importlib
|
| 4 |
+
|
| 5 |
+
from omegaconf import OmegaConf
|
| 6 |
+
from tqdm.auto import tqdm
|
| 7 |
+
|
| 8 |
+
import torch
|
| 9 |
+
|
| 10 |
+
sys.path.append(os.path.join(os.path.dirname(__file__),'../..'))
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
def get_obj_from_str(string, reload=False, invalidate_cache=True):
|
| 15 |
+
module, cls = string.rsplit(".", 1)
|
| 16 |
+
if invalidate_cache:
|
| 17 |
+
importlib.invalidate_caches()
|
| 18 |
+
if reload:
|
| 19 |
+
module_imp = importlib.import_module(module)
|
| 20 |
+
importlib.reload(module_imp)
|
| 21 |
+
return getattr(importlib.import_module(module, package=None), cls)
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
def prepare_dataloader_for_rank(config, global_rank, num_processes=-1, repeat_cp_size=1):
|
| 25 |
+
""" Get the dataloader given config and the current global rank.
|
| 26 |
+
"dataset_setting" provides the list of dataset configs
|
| 27 |
+
"rank_index_map" provides how to distribute the config across ranks
|
| 28 |
+
"""
|
| 29 |
+
# repeat each elements in CP; [a b c] --> [a a ... b b ... c c ...]
|
| 30 |
+
if repeat_cp_size > 1:
|
| 31 |
+
print(f'before repeat config.rank_index_map: {config.rank_index_map}')
|
| 32 |
+
repeated_rank_index_map = [element for element in config.rank_index_map for _ in range(repeat_cp_size)]
|
| 33 |
+
config.rank_index_map = repeated_rank_index_map
|
| 34 |
+
print(f'after repeat repeated_rank_index_map: {config.rank_index_map}')
|
| 35 |
+
|
| 36 |
+
# get the dataset index
|
| 37 |
+
num_total_indices = len(config.rank_index_map)
|
| 38 |
+
dataset_index = config.rank_index_map[global_rank % num_total_indices]
|
| 39 |
+
|
| 40 |
+
# get the correct partition
|
| 41 |
+
num_partitions = 1
|
| 42 |
+
partition_id = 0
|
| 43 |
+
if num_processes > 0:
|
| 44 |
+
rank_to_dataset_index_map = list(config.rank_index_map) * num_processes
|
| 45 |
+
rank_to_dataset_index_map = rank_to_dataset_index_map[:num_processes]
|
| 46 |
+
num_partitions = rank_to_dataset_index_map.count(dataset_index)
|
| 47 |
+
partition_id = rank_to_dataset_index_map[:global_rank].count(dataset_index)
|
| 48 |
+
print(f'rank_to_dataset_index_map: {rank_to_dataset_index_map}')
|
| 49 |
+
print(f'dataset_index: {dataset_index} partition_id: {partition_id} num_partitions: {num_partitions} ')
|
| 50 |
+
|
| 51 |
+
# get the loss weight scale factor to normalize loss weight to 1.0
|
| 52 |
+
sum_loss_weight = 0.0
|
| 53 |
+
for i in range(num_total_indices):
|
| 54 |
+
dataset_setting = config.dataset_setting[config.rank_index_map[i]]
|
| 55 |
+
sum_loss_weight += dataset_setting.get("loss_weight", 1.0)
|
| 56 |
+
loss_weight_scale = float(num_total_indices) / sum_loss_weight
|
| 57 |
+
|
| 58 |
+
# fetch the config
|
| 59 |
+
dataset_setting = config.dataset_setting[dataset_index]
|
| 60 |
+
loss_weight = dataset_setting.get("loss_weight", 1.0) * loss_weight_scale
|
| 61 |
+
print(f'global_rank: {global_rank} -- dataset_index: {dataset_index} - loss_weight_scale: {loss_weight_scale} - loss weight: {loss_weight} - dataset_setting: {dataset_setting}')
|
| 62 |
+
|
| 63 |
+
# set prompt function
|
| 64 |
+
utils_prompt_module = importlib.import_module(dataset_setting.get_prompt_module)
|
| 65 |
+
get_prompt_func = getattr(utils_prompt_module, dataset_setting.get_prompt_func)
|
| 66 |
+
get_prompt_frame_spans_func = None
|
| 67 |
+
if hasattr(dataset_setting, "get_prompt_frame_spans_func"):
|
| 68 |
+
get_prompt_frame_spans_func = getattr(utils_prompt_module, dataset_setting.get_prompt_frame_spans_func)
|
| 69 |
+
|
| 70 |
+
# get dataset from setting
|
| 71 |
+
dataset_kwargs = dataset_setting.get("dataset_kwargs", dict())
|
| 72 |
+
|
| 73 |
+
# get bucket configs
|
| 74 |
+
assert hasattr(dataset_kwargs, "bucket_configs")
|
| 75 |
+
bucket_configs = dataset_kwargs.get("bucket_configs", dict())
|
| 76 |
+
|
| 77 |
+
dataset = get_obj_from_str(dataset_setting.dataset_target)(
|
| 78 |
+
get_prompt_func=get_prompt_func,
|
| 79 |
+
get_prompt_frame_spans_func=get_prompt_frame_spans_func,
|
| 80 |
+
partition_id=partition_id,
|
| 81 |
+
num_partitions=num_partitions,
|
| 82 |
+
**dataset_kwargs
|
| 83 |
+
)
|
| 84 |
+
|
| 85 |
+
# get dataloader from setting
|
| 86 |
+
dataloader_kwargs = dataset_setting.get("dataloader_kwargs", dict())
|
| 87 |
+
dataloader = torch.utils.data.DataLoader(
|
| 88 |
+
dataset,
|
| 89 |
+
**dataloader_kwargs,
|
| 90 |
+
shuffle=False,
|
| 91 |
+
pin_memory=True,
|
| 92 |
+
drop_last=True,
|
| 93 |
+
collate_fn = dataset.collate_fn if hasattr(dataset,"collate_fn") else None,
|
| 94 |
+
)
|
| 95 |
+
|
| 96 |
+
return dataloader, loss_weight, bucket_configs
|
| 97 |
+
|
| 98 |
+
|
| 99 |
+
|
| 100 |
+
if __name__ == '__main__':
|
| 101 |
+
# example_config_path = 'source/dataset/example_config.yaml'
|
| 102 |
+
example_config_path = "configs/train_t2v_opensora_v2_ms_long32_hq400.yaml"
|
| 103 |
+
config = OmegaConf.load(example_config_path)
|
| 104 |
+
|
| 105 |
+
dataloader = prepare_dataloader_for_rank(config.video_training_data_config, global_rank=7, num_processes=28)
|
| 106 |
+
|
| 107 |
+
num_train_steps = 1000
|
| 108 |
+
progress_bar = tqdm(range(0, num_train_steps))
|
| 109 |
+
|
| 110 |
+
# output_dir = "assets/webvid-trimming_aes-tfreader"
|
| 111 |
+
# os.makedirs(output_dir, exist_ok=True)
|
| 112 |
+
|
| 113 |
+
# for step, batch in enumerate(tfreader):
|
| 114 |
+
for step, batch in enumerate(dataloader):
|
| 115 |
+
progress_bar.update(1)
|
| 116 |
+
|
| 117 |
+
# # save data for visualization
|
| 118 |
+
# pixel_values = batch['pixel_values'].cpu()
|
| 119 |
+
# pixel_values = rearrange(pixel_values, "b f c h w -> b c f h w")
|
| 120 |
+
# for idx, pixel_value in enumerate(pixel_values):
|
| 121 |
+
# pixel_value = pixel_value[None, ...]
|
| 122 |
+
# text_value = batch['text'][idx]
|
| 123 |
+
# of_score = batch['of_score'][idx]
|
| 124 |
+
# fps_value = batch['fps'][idx]
|
| 125 |
+
# text_value = (text_value[:70] + '..') if len(text_value) > 70 else text_value
|
| 126 |
+
# output_filename = f"{output_dir}/{f'{fps_value}-{of_score}-{text_value}'}.gif"
|
| 127 |
+
# print(f'saving data to {output_filename}')
|
| 128 |
+
# save_videos_grid(pixel_value, output_filename, rescale=True)
|
| 129 |
+
|
| 130 |
+
# print(f'step: {step} / num_train_steps: {num_train_steps}')
|
| 131 |
+
|
| 132 |
+
if step >= num_train_steps:
|
| 133 |
+
break
|
infworld/utils/registry.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from copy import deepcopy
|
| 2 |
+
|
| 3 |
+
import torch.nn as nn
|
| 4 |
+
from mmengine.registry import Registry
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
def build_module(module, builder, **kwargs):
|
| 8 |
+
"""Build module from config or return the module itself.
|
| 9 |
+
|
| 10 |
+
Args:
|
| 11 |
+
module (Union[dict, nn.Module]): The module to build.
|
| 12 |
+
builder (Registry): The registry to build module.
|
| 13 |
+
*args, **kwargs: Arguments passed to build function.
|
| 14 |
+
|
| 15 |
+
Returns:
|
| 16 |
+
Any: The built module.
|
| 17 |
+
"""
|
| 18 |
+
if isinstance(module, dict):
|
| 19 |
+
cfg = deepcopy(module)
|
| 20 |
+
for k, v in kwargs.items():
|
| 21 |
+
cfg[k] = v
|
| 22 |
+
return builder.build(cfg)
|
| 23 |
+
elif isinstance(module, nn.Module):
|
| 24 |
+
return module
|
| 25 |
+
elif module is None:
|
| 26 |
+
return None
|
| 27 |
+
else:
|
| 28 |
+
raise TypeError(f"Only support dict and nn.Module, but got {type(module)}.")
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
MODELS = Registry(
|
| 32 |
+
"model",
|
| 33 |
+
locations=["opensora.models"],
|
| 34 |
+
)
|
| 35 |
+
|
| 36 |
+
SCHEDULERS = Registry(
|
| 37 |
+
"scheduler",
|
| 38 |
+
locations=["opensora.schedulers"],
|
| 39 |
+
)
|
infworld/vae/__init__.py
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from einops import rearrange
|
| 2 |
+
import torch
|
| 3 |
+
from torch import nn
|
| 4 |
+
|
| 5 |
+
# Standalone: only Wan VAE (used by infworld_config.yaml)
|
| 6 |
+
from .vae import WanVAE
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
class WanVAEModelWrapper(nn.Module):
|
| 10 |
+
def __init__(self, vae_pth, dtype=torch.float, device="cuda", patch_size=(4, 8, 8)):
|
| 11 |
+
super(WanVAEModelWrapper, self).__init__()
|
| 12 |
+
self.module = WanVAE(
|
| 13 |
+
vae_pth=vae_pth,
|
| 14 |
+
dtype=dtype,
|
| 15 |
+
device=device,
|
| 16 |
+
)
|
| 17 |
+
self.dtype = dtype
|
| 18 |
+
self.device = device
|
| 19 |
+
self.out_channels = 16
|
| 20 |
+
self.patch_size = patch_size
|
| 21 |
+
|
| 22 |
+
def encode(self, x):
|
| 23 |
+
# input: x: B, C, T, H, W or B, C, H, W
|
| 24 |
+
# return: x: B, C, T, H, W
|
| 25 |
+
if len(x.shape) == 4:
|
| 26 |
+
x = rearrange(x, "B C H W -> B C 1 H W")
|
| 27 |
+
x = self.module.encode_batch(x)
|
| 28 |
+
return x
|
| 29 |
+
|
| 30 |
+
def decode(self, x):
|
| 31 |
+
# input: x: B, C, T, H, W or B, C, H, W
|
| 32 |
+
# return: x: B, C, T, H, W
|
| 33 |
+
if len(x.shape) == 4:
|
| 34 |
+
x = rearrange(x, "T C H W -> 1 C T H W")
|
| 35 |
+
x = self.module.decode_batch(x)
|
| 36 |
+
return x
|
| 37 |
+
|
| 38 |
+
def get_latent_size(self, input_size):
|
| 39 |
+
latent_size = []
|
| 40 |
+
for i in range(3):
|
| 41 |
+
if i == 0:
|
| 42 |
+
target_size = 1 + (input_size[i] - 1) // self.patch_size[i]
|
| 43 |
+
latent_size.append(target_size)
|
| 44 |
+
else:
|
| 45 |
+
assert input_size[i] % self.patch_size[i] == 0, "Input spatial size must be divisible by patch size"
|
| 46 |
+
target_size = input_size[i] // self.patch_size[i]
|
| 47 |
+
latent_size.append(target_size)
|
| 48 |
+
return latent_size
|
infworld/vae/vae.py
ADDED
|
@@ -0,0 +1,674 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024-2025 The Alibaba Wan Team Authors. All rights reserved.
|
| 2 |
+
import logging
|
| 3 |
+
|
| 4 |
+
import torch
|
| 5 |
+
import torch.cuda.amp as amp
|
| 6 |
+
import torch.nn as nn
|
| 7 |
+
import torch.nn.functional as F
|
| 8 |
+
from einops import rearrange
|
| 9 |
+
|
| 10 |
+
__all__ = [
|
| 11 |
+
'WanVAE',
|
| 12 |
+
]
|
| 13 |
+
|
| 14 |
+
CACHE_T = 2
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
class CausalConv3d(nn.Conv3d):
|
| 18 |
+
"""
|
| 19 |
+
Causal 3d convolusion.
|
| 20 |
+
"""
|
| 21 |
+
|
| 22 |
+
def __init__(self, *args, **kwargs):
|
| 23 |
+
super().__init__(*args, **kwargs)
|
| 24 |
+
self._padding = (self.padding[2], self.padding[2], self.padding[1],
|
| 25 |
+
self.padding[1], 2 * self.padding[0], 0)
|
| 26 |
+
self.padding = (0, 0, 0)
|
| 27 |
+
|
| 28 |
+
def forward(self, x, cache_x=None):
|
| 29 |
+
padding = list(self._padding)
|
| 30 |
+
if cache_x is not None and self._padding[4] > 0:
|
| 31 |
+
cache_x = cache_x.to(x.device)
|
| 32 |
+
x = torch.cat([cache_x, x], dim=2)
|
| 33 |
+
padding[4] -= cache_x.shape[2]
|
| 34 |
+
x = F.pad(x, padding)
|
| 35 |
+
|
| 36 |
+
return super().forward(x)
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
class RMS_norm(nn.Module):
|
| 40 |
+
|
| 41 |
+
def __init__(self, dim, channel_first=True, images=True, bias=False):
|
| 42 |
+
super().__init__()
|
| 43 |
+
broadcastable_dims = (1, 1, 1) if not images else (1, 1)
|
| 44 |
+
shape = (dim, *broadcastable_dims) if channel_first else (dim,)
|
| 45 |
+
|
| 46 |
+
self.channel_first = channel_first
|
| 47 |
+
self.scale = dim**0.5
|
| 48 |
+
self.gamma = nn.Parameter(torch.ones(shape))
|
| 49 |
+
self.bias = nn.Parameter(torch.zeros(shape)) if bias else 0.
|
| 50 |
+
|
| 51 |
+
def forward(self, x):
|
| 52 |
+
return F.normalize(
|
| 53 |
+
x, dim=(1 if self.channel_first else
|
| 54 |
+
-1)) * self.scale * self.gamma + self.bias
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
class Upsample(nn.Upsample):
|
| 58 |
+
|
| 59 |
+
def forward(self, x):
|
| 60 |
+
"""
|
| 61 |
+
Fix bfloat16 support for nearest neighbor interpolation.
|
| 62 |
+
"""
|
| 63 |
+
return super().forward(x.float()).type_as(x)
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
class Resample(nn.Module):
|
| 67 |
+
|
| 68 |
+
def __init__(self, dim, mode):
|
| 69 |
+
assert mode in ('none', 'upsample2d', 'upsample3d', 'downsample2d',
|
| 70 |
+
'downsample3d')
|
| 71 |
+
super().__init__()
|
| 72 |
+
self.dim = dim
|
| 73 |
+
self.mode = mode
|
| 74 |
+
|
| 75 |
+
# layers
|
| 76 |
+
if mode == 'upsample2d':
|
| 77 |
+
self.resample = nn.Sequential(
|
| 78 |
+
Upsample(scale_factor=(2., 2.), mode='nearest-exact'),
|
| 79 |
+
nn.Conv2d(dim, dim // 2, 3, padding=1))
|
| 80 |
+
elif mode == 'upsample3d':
|
| 81 |
+
self.resample = nn.Sequential(
|
| 82 |
+
Upsample(scale_factor=(2., 2.), mode='nearest-exact'),
|
| 83 |
+
nn.Conv2d(dim, dim // 2, 3, padding=1))
|
| 84 |
+
self.time_conv = CausalConv3d(
|
| 85 |
+
dim, dim * 2, (3, 1, 1), padding=(1, 0, 0))
|
| 86 |
+
|
| 87 |
+
elif mode == 'downsample2d':
|
| 88 |
+
self.resample = nn.Sequential(
|
| 89 |
+
nn.ZeroPad2d((0, 1, 0, 1)),
|
| 90 |
+
nn.Conv2d(dim, dim, 3, stride=(2, 2)))
|
| 91 |
+
elif mode == 'downsample3d':
|
| 92 |
+
self.resample = nn.Sequential(
|
| 93 |
+
nn.ZeroPad2d((0, 1, 0, 1)),
|
| 94 |
+
nn.Conv2d(dim, dim, 3, stride=(2, 2)))
|
| 95 |
+
self.time_conv = CausalConv3d(
|
| 96 |
+
dim, dim, (3, 1, 1), stride=(2, 1, 1), padding=(0, 0, 0))
|
| 97 |
+
|
| 98 |
+
else:
|
| 99 |
+
self.resample = nn.Identity()
|
| 100 |
+
|
| 101 |
+
def forward(self, x, feat_cache=None, feat_idx=[0]):
|
| 102 |
+
b, c, t, h, w = x.size()
|
| 103 |
+
if self.mode == 'upsample3d':
|
| 104 |
+
if feat_cache is not None:
|
| 105 |
+
idx = feat_idx[0]
|
| 106 |
+
if feat_cache[idx] is None:
|
| 107 |
+
feat_cache[idx] = 'Rep'
|
| 108 |
+
feat_idx[0] += 1
|
| 109 |
+
else:
|
| 110 |
+
|
| 111 |
+
cache_x = x[:, :, -CACHE_T:, :, :].clone()
|
| 112 |
+
if cache_x.shape[2] < 2 and feat_cache[
|
| 113 |
+
idx] is not None and feat_cache[idx] != 'Rep':
|
| 114 |
+
# cache last frame of last two chunk
|
| 115 |
+
cache_x = torch.cat([
|
| 116 |
+
feat_cache[idx][:, :, -1, :, :].unsqueeze(2).to(
|
| 117 |
+
cache_x.device), cache_x
|
| 118 |
+
],
|
| 119 |
+
dim=2)
|
| 120 |
+
if cache_x.shape[2] < 2 and feat_cache[
|
| 121 |
+
idx] is not None and feat_cache[idx] == 'Rep':
|
| 122 |
+
cache_x = torch.cat([
|
| 123 |
+
torch.zeros_like(cache_x).to(cache_x.device),
|
| 124 |
+
cache_x
|
| 125 |
+
],
|
| 126 |
+
dim=2)
|
| 127 |
+
if feat_cache[idx] == 'Rep':
|
| 128 |
+
x = self.time_conv(x)
|
| 129 |
+
else:
|
| 130 |
+
x = self.time_conv(x, feat_cache[idx])
|
| 131 |
+
feat_cache[idx] = cache_x
|
| 132 |
+
feat_idx[0] += 1
|
| 133 |
+
|
| 134 |
+
x = x.reshape(b, 2, c, t, h, w)
|
| 135 |
+
x = torch.stack((x[:, 0, :, :, :, :], x[:, 1, :, :, :, :]),
|
| 136 |
+
3)
|
| 137 |
+
x = x.reshape(b, c, t * 2, h, w)
|
| 138 |
+
t = x.shape[2]
|
| 139 |
+
x = rearrange(x, 'b c t h w -> (b t) c h w')
|
| 140 |
+
x = self.resample(x)
|
| 141 |
+
x = rearrange(x, '(b t) c h w -> b c t h w', t=t)
|
| 142 |
+
|
| 143 |
+
if self.mode == 'downsample3d':
|
| 144 |
+
if feat_cache is not None:
|
| 145 |
+
idx = feat_idx[0]
|
| 146 |
+
if feat_cache[idx] is None:
|
| 147 |
+
feat_cache[idx] = x.clone()
|
| 148 |
+
feat_idx[0] += 1
|
| 149 |
+
else:
|
| 150 |
+
|
| 151 |
+
cache_x = x[:, :, -1:, :, :].clone()
|
| 152 |
+
# if cache_x.shape[2] < 2 and feat_cache[idx] is not None and feat_cache[idx]!='Rep':
|
| 153 |
+
# # cache last frame of last two chunk
|
| 154 |
+
# cache_x = torch.cat([feat_cache[idx][:, :, -1, :, :].unsqueeze(2).to(cache_x.device), cache_x], dim=2)
|
| 155 |
+
|
| 156 |
+
x = self.time_conv(
|
| 157 |
+
torch.cat([feat_cache[idx][:, :, -1:, :, :], x], 2))
|
| 158 |
+
feat_cache[idx] = cache_x
|
| 159 |
+
feat_idx[0] += 1
|
| 160 |
+
return x
|
| 161 |
+
|
| 162 |
+
def init_weight(self, conv):
|
| 163 |
+
conv_weight = conv.weight
|
| 164 |
+
nn.init.zeros_(conv_weight)
|
| 165 |
+
c1, c2, t, h, w = conv_weight.size()
|
| 166 |
+
one_matrix = torch.eye(c1, c2)
|
| 167 |
+
init_matrix = one_matrix
|
| 168 |
+
nn.init.zeros_(conv_weight)
|
| 169 |
+
#conv_weight.data[:,:,-1,1,1] = init_matrix * 0.5
|
| 170 |
+
conv_weight.data[:, :, 1, 0, 0] = init_matrix #* 0.5
|
| 171 |
+
conv.weight.data.copy_(conv_weight)
|
| 172 |
+
nn.init.zeros_(conv.bias.data)
|
| 173 |
+
|
| 174 |
+
def init_weight2(self, conv):
|
| 175 |
+
conv_weight = conv.weight.data
|
| 176 |
+
nn.init.zeros_(conv_weight)
|
| 177 |
+
c1, c2, t, h, w = conv_weight.size()
|
| 178 |
+
init_matrix = torch.eye(c1 // 2, c2)
|
| 179 |
+
#init_matrix = repeat(init_matrix, 'o ... -> (o 2) ...').permute(1,0,2).contiguous().reshape(c1,c2)
|
| 180 |
+
conv_weight[:c1 // 2, :, -1, 0, 0] = init_matrix
|
| 181 |
+
conv_weight[c1 // 2:, :, -1, 0, 0] = init_matrix
|
| 182 |
+
conv.weight.data.copy_(conv_weight)
|
| 183 |
+
nn.init.zeros_(conv.bias.data)
|
| 184 |
+
|
| 185 |
+
|
| 186 |
+
class ResidualBlock(nn.Module):
|
| 187 |
+
|
| 188 |
+
def __init__(self, in_dim, out_dim, dropout=0.0):
|
| 189 |
+
super().__init__()
|
| 190 |
+
self.in_dim = in_dim
|
| 191 |
+
self.out_dim = out_dim
|
| 192 |
+
|
| 193 |
+
# layers
|
| 194 |
+
self.residual = nn.Sequential(
|
| 195 |
+
RMS_norm(in_dim, images=False), nn.SiLU(),
|
| 196 |
+
CausalConv3d(in_dim, out_dim, 3, padding=1),
|
| 197 |
+
RMS_norm(out_dim, images=False), nn.SiLU(), nn.Dropout(dropout),
|
| 198 |
+
CausalConv3d(out_dim, out_dim, 3, padding=1))
|
| 199 |
+
self.shortcut = CausalConv3d(in_dim, out_dim, 1) \
|
| 200 |
+
if in_dim != out_dim else nn.Identity()
|
| 201 |
+
|
| 202 |
+
def forward(self, x, feat_cache=None, feat_idx=[0]):
|
| 203 |
+
h = self.shortcut(x)
|
| 204 |
+
for layer in self.residual:
|
| 205 |
+
if isinstance(layer, CausalConv3d) and feat_cache is not None:
|
| 206 |
+
idx = feat_idx[0]
|
| 207 |
+
cache_x = x[:, :, -CACHE_T:, :, :].clone()
|
| 208 |
+
if cache_x.shape[2] < 2 and feat_cache[idx] is not None:
|
| 209 |
+
# cache last frame of last two chunk
|
| 210 |
+
cache_x = torch.cat([
|
| 211 |
+
feat_cache[idx][:, :, -1, :, :].unsqueeze(2).to(
|
| 212 |
+
cache_x.device), cache_x
|
| 213 |
+
],
|
| 214 |
+
dim=2)
|
| 215 |
+
x = layer(x, feat_cache[idx])
|
| 216 |
+
feat_cache[idx] = cache_x
|
| 217 |
+
feat_idx[0] += 1
|
| 218 |
+
else:
|
| 219 |
+
x = layer(x)
|
| 220 |
+
return x + h
|
| 221 |
+
|
| 222 |
+
|
| 223 |
+
class AttentionBlock(nn.Module):
|
| 224 |
+
"""
|
| 225 |
+
Causal self-attention with a single head.
|
| 226 |
+
"""
|
| 227 |
+
|
| 228 |
+
def __init__(self, dim):
|
| 229 |
+
super().__init__()
|
| 230 |
+
self.dim = dim
|
| 231 |
+
|
| 232 |
+
# layers
|
| 233 |
+
self.norm = RMS_norm(dim)
|
| 234 |
+
self.to_qkv = nn.Conv2d(dim, dim * 3, 1)
|
| 235 |
+
self.proj = nn.Conv2d(dim, dim, 1)
|
| 236 |
+
|
| 237 |
+
# zero out the last layer params
|
| 238 |
+
nn.init.zeros_(self.proj.weight)
|
| 239 |
+
|
| 240 |
+
def forward(self, x):
|
| 241 |
+
identity = x
|
| 242 |
+
b, c, t, h, w = x.size()
|
| 243 |
+
x = rearrange(x, 'b c t h w -> (b t) c h w')
|
| 244 |
+
x = self.norm(x)
|
| 245 |
+
# compute query, key, value
|
| 246 |
+
q, k, v = self.to_qkv(x).reshape(b * t, 1, c * 3,
|
| 247 |
+
-1).permute(0, 1, 3,
|
| 248 |
+
2).contiguous().chunk(
|
| 249 |
+
3, dim=-1)
|
| 250 |
+
|
| 251 |
+
# apply attention
|
| 252 |
+
x = F.scaled_dot_product_attention(
|
| 253 |
+
q,
|
| 254 |
+
k,
|
| 255 |
+
v,
|
| 256 |
+
)
|
| 257 |
+
x = x.squeeze(1).permute(0, 2, 1).reshape(b * t, c, h, w)
|
| 258 |
+
|
| 259 |
+
# output
|
| 260 |
+
x = self.proj(x)
|
| 261 |
+
x = rearrange(x, '(b t) c h w-> b c t h w', t=t)
|
| 262 |
+
return x + identity
|
| 263 |
+
|
| 264 |
+
|
| 265 |
+
class Encoder3d(nn.Module):
|
| 266 |
+
|
| 267 |
+
def __init__(self,
|
| 268 |
+
dim=128,
|
| 269 |
+
z_dim=4,
|
| 270 |
+
dim_mult=[1, 2, 4, 4],
|
| 271 |
+
num_res_blocks=2,
|
| 272 |
+
attn_scales=[],
|
| 273 |
+
temperal_downsample=[True, True, False],
|
| 274 |
+
dropout=0.0):
|
| 275 |
+
super().__init__()
|
| 276 |
+
self.dim = dim
|
| 277 |
+
self.z_dim = z_dim
|
| 278 |
+
self.dim_mult = dim_mult
|
| 279 |
+
self.num_res_blocks = num_res_blocks
|
| 280 |
+
self.attn_scales = attn_scales
|
| 281 |
+
self.temperal_downsample = temperal_downsample
|
| 282 |
+
|
| 283 |
+
# dimensions
|
| 284 |
+
dims = [dim * u for u in [1] + dim_mult]
|
| 285 |
+
scale = 1.0
|
| 286 |
+
|
| 287 |
+
# init block
|
| 288 |
+
self.conv1 = CausalConv3d(3, dims[0], 3, padding=1)
|
| 289 |
+
|
| 290 |
+
# downsample blocks
|
| 291 |
+
downsamples = []
|
| 292 |
+
for i, (in_dim, out_dim) in enumerate(zip(dims[:-1], dims[1:])):
|
| 293 |
+
# residual (+attention) blocks
|
| 294 |
+
for _ in range(num_res_blocks):
|
| 295 |
+
downsamples.append(ResidualBlock(in_dim, out_dim, dropout))
|
| 296 |
+
if scale in attn_scales:
|
| 297 |
+
downsamples.append(AttentionBlock(out_dim))
|
| 298 |
+
in_dim = out_dim
|
| 299 |
+
|
| 300 |
+
# downsample block
|
| 301 |
+
if i != len(dim_mult) - 1:
|
| 302 |
+
mode = 'downsample3d' if temperal_downsample[
|
| 303 |
+
i] else 'downsample2d'
|
| 304 |
+
downsamples.append(Resample(out_dim, mode=mode))
|
| 305 |
+
scale /= 2.0
|
| 306 |
+
self.downsamples = nn.Sequential(*downsamples)
|
| 307 |
+
|
| 308 |
+
# middle blocks
|
| 309 |
+
self.middle = nn.Sequential(
|
| 310 |
+
ResidualBlock(out_dim, out_dim, dropout), AttentionBlock(out_dim),
|
| 311 |
+
ResidualBlock(out_dim, out_dim, dropout))
|
| 312 |
+
|
| 313 |
+
# output blocks
|
| 314 |
+
self.head = nn.Sequential(
|
| 315 |
+
RMS_norm(out_dim, images=False), nn.SiLU(),
|
| 316 |
+
CausalConv3d(out_dim, z_dim, 3, padding=1))
|
| 317 |
+
|
| 318 |
+
def forward(self, x, feat_cache=None, feat_idx=[0]):
|
| 319 |
+
if feat_cache is not None:
|
| 320 |
+
idx = feat_idx[0]
|
| 321 |
+
cache_x = x[:, :, -CACHE_T:, :, :].clone()
|
| 322 |
+
if cache_x.shape[2] < 2 and feat_cache[idx] is not None:
|
| 323 |
+
# cache last frame of last two chunk
|
| 324 |
+
cache_x = torch.cat([
|
| 325 |
+
feat_cache[idx][:, :, -1, :, :].unsqueeze(2).to(
|
| 326 |
+
cache_x.device), cache_x
|
| 327 |
+
],
|
| 328 |
+
dim=2)
|
| 329 |
+
x = self.conv1(x, feat_cache[idx])
|
| 330 |
+
feat_cache[idx] = cache_x
|
| 331 |
+
feat_idx[0] += 1
|
| 332 |
+
else:
|
| 333 |
+
x = self.conv1(x)
|
| 334 |
+
|
| 335 |
+
## downsamples
|
| 336 |
+
for layer in self.downsamples:
|
| 337 |
+
if feat_cache is not None:
|
| 338 |
+
x = layer(x, feat_cache, feat_idx)
|
| 339 |
+
else:
|
| 340 |
+
x = layer(x)
|
| 341 |
+
|
| 342 |
+
## middle
|
| 343 |
+
for layer in self.middle:
|
| 344 |
+
if isinstance(layer, ResidualBlock) and feat_cache is not None:
|
| 345 |
+
x = layer(x, feat_cache, feat_idx)
|
| 346 |
+
else:
|
| 347 |
+
x = layer(x)
|
| 348 |
+
|
| 349 |
+
## head
|
| 350 |
+
for layer in self.head:
|
| 351 |
+
if isinstance(layer, CausalConv3d) and feat_cache is not None:
|
| 352 |
+
idx = feat_idx[0]
|
| 353 |
+
cache_x = x[:, :, -CACHE_T:, :, :].clone()
|
| 354 |
+
if cache_x.shape[2] < 2 and feat_cache[idx] is not None:
|
| 355 |
+
# cache last frame of last two chunk
|
| 356 |
+
cache_x = torch.cat([
|
| 357 |
+
feat_cache[idx][:, :, -1, :, :].unsqueeze(2).to(
|
| 358 |
+
cache_x.device), cache_x
|
| 359 |
+
],
|
| 360 |
+
dim=2)
|
| 361 |
+
x = layer(x, feat_cache[idx])
|
| 362 |
+
feat_cache[idx] = cache_x
|
| 363 |
+
feat_idx[0] += 1
|
| 364 |
+
else:
|
| 365 |
+
x = layer(x)
|
| 366 |
+
return x
|
| 367 |
+
|
| 368 |
+
|
| 369 |
+
class Decoder3d(nn.Module):
|
| 370 |
+
|
| 371 |
+
def __init__(self,
|
| 372 |
+
dim=128,
|
| 373 |
+
z_dim=4,
|
| 374 |
+
dim_mult=[1, 2, 4, 4],
|
| 375 |
+
num_res_blocks=2,
|
| 376 |
+
attn_scales=[],
|
| 377 |
+
temperal_upsample=[False, True, True],
|
| 378 |
+
dropout=0.0):
|
| 379 |
+
super().__init__()
|
| 380 |
+
self.dim = dim
|
| 381 |
+
self.z_dim = z_dim
|
| 382 |
+
self.dim_mult = dim_mult
|
| 383 |
+
self.num_res_blocks = num_res_blocks
|
| 384 |
+
self.attn_scales = attn_scales
|
| 385 |
+
self.temperal_upsample = temperal_upsample
|
| 386 |
+
|
| 387 |
+
# dimensions
|
| 388 |
+
dims = [dim * u for u in [dim_mult[-1]] + dim_mult[::-1]]
|
| 389 |
+
scale = 1.0 / 2**(len(dim_mult) - 2)
|
| 390 |
+
|
| 391 |
+
# init block
|
| 392 |
+
self.conv1 = CausalConv3d(z_dim, dims[0], 3, padding=1)
|
| 393 |
+
|
| 394 |
+
# middle blocks
|
| 395 |
+
self.middle = nn.Sequential(
|
| 396 |
+
ResidualBlock(dims[0], dims[0], dropout), AttentionBlock(dims[0]),
|
| 397 |
+
ResidualBlock(dims[0], dims[0], dropout))
|
| 398 |
+
|
| 399 |
+
# upsample blocks
|
| 400 |
+
upsamples = []
|
| 401 |
+
for i, (in_dim, out_dim) in enumerate(zip(dims[:-1], dims[1:])):
|
| 402 |
+
# residual (+attention) blocks
|
| 403 |
+
if i == 1 or i == 2 or i == 3:
|
| 404 |
+
in_dim = in_dim // 2
|
| 405 |
+
for _ in range(num_res_blocks + 1):
|
| 406 |
+
upsamples.append(ResidualBlock(in_dim, out_dim, dropout))
|
| 407 |
+
if scale in attn_scales:
|
| 408 |
+
upsamples.append(AttentionBlock(out_dim))
|
| 409 |
+
in_dim = out_dim
|
| 410 |
+
|
| 411 |
+
# upsample block
|
| 412 |
+
if i != len(dim_mult) - 1:
|
| 413 |
+
mode = 'upsample3d' if temperal_upsample[i] else 'upsample2d'
|
| 414 |
+
upsamples.append(Resample(out_dim, mode=mode))
|
| 415 |
+
scale *= 2.0
|
| 416 |
+
self.upsamples = nn.Sequential(*upsamples)
|
| 417 |
+
|
| 418 |
+
# output blocks
|
| 419 |
+
self.head = nn.Sequential(
|
| 420 |
+
RMS_norm(out_dim, images=False), nn.SiLU(),
|
| 421 |
+
CausalConv3d(out_dim, 3, 3, padding=1))
|
| 422 |
+
|
| 423 |
+
def forward(self, x, feat_cache=None, feat_idx=[0]):
|
| 424 |
+
## conv1
|
| 425 |
+
if feat_cache is not None:
|
| 426 |
+
idx = feat_idx[0]
|
| 427 |
+
cache_x = x[:, :, -CACHE_T:, :, :].clone()
|
| 428 |
+
if cache_x.shape[2] < 2 and feat_cache[idx] is not None:
|
| 429 |
+
# cache last frame of last two chunk
|
| 430 |
+
cache_x = torch.cat([
|
| 431 |
+
feat_cache[idx][:, :, -1, :, :].unsqueeze(2).to(
|
| 432 |
+
cache_x.device), cache_x
|
| 433 |
+
],
|
| 434 |
+
dim=2)
|
| 435 |
+
x = self.conv1(x, feat_cache[idx])
|
| 436 |
+
feat_cache[idx] = cache_x
|
| 437 |
+
feat_idx[0] += 1
|
| 438 |
+
else:
|
| 439 |
+
x = self.conv1(x)
|
| 440 |
+
|
| 441 |
+
## middle
|
| 442 |
+
for layer in self.middle:
|
| 443 |
+
if isinstance(layer, ResidualBlock) and feat_cache is not None:
|
| 444 |
+
x = layer(x, feat_cache, feat_idx)
|
| 445 |
+
else:
|
| 446 |
+
x = layer(x)
|
| 447 |
+
|
| 448 |
+
## upsamples
|
| 449 |
+
for layer in self.upsamples:
|
| 450 |
+
if feat_cache is not None:
|
| 451 |
+
x = layer(x, feat_cache, feat_idx)
|
| 452 |
+
else:
|
| 453 |
+
x = layer(x)
|
| 454 |
+
|
| 455 |
+
## head
|
| 456 |
+
for layer in self.head:
|
| 457 |
+
if isinstance(layer, CausalConv3d) and feat_cache is not None:
|
| 458 |
+
idx = feat_idx[0]
|
| 459 |
+
cache_x = x[:, :, -CACHE_T:, :, :].clone()
|
| 460 |
+
if cache_x.shape[2] < 2 and feat_cache[idx] is not None:
|
| 461 |
+
# cache last frame of last two chunk
|
| 462 |
+
cache_x = torch.cat([
|
| 463 |
+
feat_cache[idx][:, :, -1, :, :].unsqueeze(2).to(
|
| 464 |
+
cache_x.device), cache_x
|
| 465 |
+
],
|
| 466 |
+
dim=2)
|
| 467 |
+
x = layer(x, feat_cache[idx])
|
| 468 |
+
feat_cache[idx] = cache_x
|
| 469 |
+
feat_idx[0] += 1
|
| 470 |
+
else:
|
| 471 |
+
x = layer(x)
|
| 472 |
+
return x
|
| 473 |
+
|
| 474 |
+
|
| 475 |
+
def count_conv3d(model):
|
| 476 |
+
count = 0
|
| 477 |
+
for m in model.modules():
|
| 478 |
+
if isinstance(m, CausalConv3d):
|
| 479 |
+
count += 1
|
| 480 |
+
return count
|
| 481 |
+
|
| 482 |
+
|
| 483 |
+
class WanVAE_(nn.Module):
|
| 484 |
+
|
| 485 |
+
def __init__(self,
|
| 486 |
+
dim=128,
|
| 487 |
+
z_dim=4,
|
| 488 |
+
dim_mult=[1, 2, 4, 4],
|
| 489 |
+
num_res_blocks=2,
|
| 490 |
+
attn_scales=[],
|
| 491 |
+
temperal_downsample=[True, True, False],
|
| 492 |
+
dropout=0.0):
|
| 493 |
+
super().__init__()
|
| 494 |
+
self.dim = dim
|
| 495 |
+
self.z_dim = z_dim
|
| 496 |
+
self.dim_mult = dim_mult
|
| 497 |
+
self.num_res_blocks = num_res_blocks
|
| 498 |
+
self.attn_scales = attn_scales
|
| 499 |
+
self.temperal_downsample = temperal_downsample
|
| 500 |
+
self.temperal_upsample = temperal_downsample[::-1]
|
| 501 |
+
|
| 502 |
+
# modules
|
| 503 |
+
self.encoder = Encoder3d(dim, z_dim * 2, dim_mult, num_res_blocks,
|
| 504 |
+
attn_scales, self.temperal_downsample, dropout)
|
| 505 |
+
self.conv1 = CausalConv3d(z_dim * 2, z_dim * 2, 1)
|
| 506 |
+
self.conv2 = CausalConv3d(z_dim, z_dim, 1)
|
| 507 |
+
self.decoder = Decoder3d(dim, z_dim, dim_mult, num_res_blocks,
|
| 508 |
+
attn_scales, self.temperal_upsample, dropout)
|
| 509 |
+
|
| 510 |
+
def forward(self, x):
|
| 511 |
+
mu, log_var = self.encode(x)
|
| 512 |
+
z = self.reparameterize(mu, log_var)
|
| 513 |
+
x_recon = self.decode(z)
|
| 514 |
+
return x_recon, mu, log_var
|
| 515 |
+
|
| 516 |
+
def encode(self, x, scale):
|
| 517 |
+
self.clear_cache()
|
| 518 |
+
## cache
|
| 519 |
+
t = x.shape[2]
|
| 520 |
+
iter_ = 1 + (t - 1) // 4
|
| 521 |
+
## 对encode输入的x,按时间拆分为1、4、4、4....
|
| 522 |
+
for i in range(iter_):
|
| 523 |
+
self._enc_conv_idx = [0]
|
| 524 |
+
if i == 0:
|
| 525 |
+
out = self.encoder(
|
| 526 |
+
x[:, :, :1, :, :],
|
| 527 |
+
feat_cache=self._enc_feat_map,
|
| 528 |
+
feat_idx=self._enc_conv_idx)
|
| 529 |
+
else:
|
| 530 |
+
out_ = self.encoder(
|
| 531 |
+
x[:, :, 1 + 4 * (i - 1):1 + 4 * i, :, :],
|
| 532 |
+
feat_cache=self._enc_feat_map,
|
| 533 |
+
feat_idx=self._enc_conv_idx)
|
| 534 |
+
out = torch.cat([out, out_], 2)
|
| 535 |
+
mu, log_var = self.conv1(out).chunk(2, dim=1)
|
| 536 |
+
if isinstance(scale[0], torch.Tensor):
|
| 537 |
+
mu = (mu - scale[0].view(1, self.z_dim, 1, 1, 1)) * scale[1].view(
|
| 538 |
+
1, self.z_dim, 1, 1, 1)
|
| 539 |
+
else:
|
| 540 |
+
mu = (mu - scale[0]) * scale[1]
|
| 541 |
+
self.clear_cache()
|
| 542 |
+
return mu
|
| 543 |
+
|
| 544 |
+
def decode(self, z, scale):
|
| 545 |
+
self.clear_cache()
|
| 546 |
+
# z: [b,c,t,h,w]
|
| 547 |
+
if isinstance(scale[0], torch.Tensor):
|
| 548 |
+
z = z / scale[1].view(1, self.z_dim, 1, 1, 1) + scale[0].view(
|
| 549 |
+
1, self.z_dim, 1, 1, 1)
|
| 550 |
+
else:
|
| 551 |
+
z = z / scale[1] + scale[0]
|
| 552 |
+
iter_ = z.shape[2]
|
| 553 |
+
x = self.conv2(z)
|
| 554 |
+
for i in range(iter_):
|
| 555 |
+
self._conv_idx = [0]
|
| 556 |
+
if i == 0:
|
| 557 |
+
out = self.decoder(
|
| 558 |
+
x[:, :, i:i + 1, :, :],
|
| 559 |
+
feat_cache=self._feat_map,
|
| 560 |
+
feat_idx=self._conv_idx)
|
| 561 |
+
else:
|
| 562 |
+
out_ = self.decoder(
|
| 563 |
+
x[:, :, i:i + 1, :, :],
|
| 564 |
+
feat_cache=self._feat_map,
|
| 565 |
+
feat_idx=self._conv_idx)
|
| 566 |
+
out = torch.cat([out, out_], 2)
|
| 567 |
+
self.clear_cache()
|
| 568 |
+
return out
|
| 569 |
+
|
| 570 |
+
def reparameterize(self, mu, log_var):
|
| 571 |
+
std = torch.exp(0.5 * log_var)
|
| 572 |
+
eps = torch.randn_like(std)
|
| 573 |
+
return eps * std + mu
|
| 574 |
+
|
| 575 |
+
def sample(self, imgs, deterministic=False):
|
| 576 |
+
mu, log_var = self.encode(imgs)
|
| 577 |
+
if deterministic:
|
| 578 |
+
return mu
|
| 579 |
+
std = torch.exp(0.5 * log_var.clamp(-30.0, 20.0))
|
| 580 |
+
return mu + std * torch.randn_like(std)
|
| 581 |
+
|
| 582 |
+
def clear_cache(self):
|
| 583 |
+
self._conv_num = count_conv3d(self.decoder)
|
| 584 |
+
self._conv_idx = [0]
|
| 585 |
+
self._feat_map = [None] * self._conv_num
|
| 586 |
+
#cache encode
|
| 587 |
+
self._enc_conv_num = count_conv3d(self.encoder)
|
| 588 |
+
self._enc_conv_idx = [0]
|
| 589 |
+
self._enc_feat_map = [None] * self._enc_conv_num
|
| 590 |
+
|
| 591 |
+
|
| 592 |
+
def _video_vae(pretrained_path=None, z_dim=None, device='cpu', **kwargs):
|
| 593 |
+
"""
|
| 594 |
+
Autoencoder3d adapted from Stable Diffusion 1.x, 2.x and XL.
|
| 595 |
+
"""
|
| 596 |
+
# params
|
| 597 |
+
cfg = dict(
|
| 598 |
+
dim=96,
|
| 599 |
+
z_dim=z_dim,
|
| 600 |
+
dim_mult=[1, 2, 4, 4],
|
| 601 |
+
num_res_blocks=2,
|
| 602 |
+
attn_scales=[],
|
| 603 |
+
temperal_downsample=[False, True, True],
|
| 604 |
+
dropout=0.0)
|
| 605 |
+
cfg.update(**kwargs)
|
| 606 |
+
|
| 607 |
+
# init model
|
| 608 |
+
with torch.device('meta'):
|
| 609 |
+
model = WanVAE_(**cfg)
|
| 610 |
+
|
| 611 |
+
# load checkpoint
|
| 612 |
+
logging.info(f'loading {pretrained_path}')
|
| 613 |
+
model.load_state_dict(
|
| 614 |
+
torch.load(pretrained_path, map_location=device), assign=True)
|
| 615 |
+
|
| 616 |
+
return model
|
| 617 |
+
|
| 618 |
+
|
| 619 |
+
class WanVAE:
|
| 620 |
+
|
| 621 |
+
def __init__(self,
|
| 622 |
+
z_dim=16,
|
| 623 |
+
vae_pth='cache/vae_step_411000.pth',
|
| 624 |
+
dtype=torch.float,
|
| 625 |
+
device="cuda"):
|
| 626 |
+
self.dtype = dtype
|
| 627 |
+
self.device = device
|
| 628 |
+
|
| 629 |
+
mean = [
|
| 630 |
+
-0.7571, -0.7089, -0.9113, 0.1075, -0.1745, 0.9653, -0.1517, 1.5508,
|
| 631 |
+
0.4134, -0.0715, 0.5517, -0.3632, -0.1922, -0.9497, 0.2503, -0.2921
|
| 632 |
+
]
|
| 633 |
+
std = [
|
| 634 |
+
2.8184, 1.4541, 2.3275, 2.6558, 1.2196, 1.7708, 2.6052, 2.0743,
|
| 635 |
+
3.2687, 2.1526, 2.8652, 1.5579, 1.6382, 1.1253, 2.8251, 1.9160
|
| 636 |
+
]
|
| 637 |
+
self.mean = torch.tensor(mean, dtype=dtype, device=device)
|
| 638 |
+
self.std = torch.tensor(std, dtype=dtype, device=device)
|
| 639 |
+
self.scale = [self.mean, 1.0 / self.std]
|
| 640 |
+
|
| 641 |
+
# init model
|
| 642 |
+
self.model = _video_vae(
|
| 643 |
+
pretrained_path=vae_pth,
|
| 644 |
+
z_dim=z_dim,
|
| 645 |
+
).eval().requires_grad_(False).to(device)
|
| 646 |
+
|
| 647 |
+
def encode(self, videos):
|
| 648 |
+
"""
|
| 649 |
+
videos: A list of videos each with shape [C, T, H, W].
|
| 650 |
+
"""
|
| 651 |
+
with amp.autocast(dtype=self.dtype):
|
| 652 |
+
return [
|
| 653 |
+
self.model.encode(u.unsqueeze(0), self.scale).float().squeeze(0)
|
| 654 |
+
for u in videos
|
| 655 |
+
]
|
| 656 |
+
|
| 657 |
+
def decode(self, zs):
|
| 658 |
+
with amp.autocast(dtype=self.dtype):
|
| 659 |
+
return [
|
| 660 |
+
self.model.decode(u.unsqueeze(0),
|
| 661 |
+
self.scale).float().clamp_(-1, 1).squeeze(0)
|
| 662 |
+
for u in zs
|
| 663 |
+
]
|
| 664 |
+
|
| 665 |
+
def encode_batch(self, videos):
|
| 666 |
+
"""
|
| 667 |
+
videos: A list of videos each with shape [C, T, H, W].
|
| 668 |
+
"""
|
| 669 |
+
with amp.autocast(dtype=self.dtype):
|
| 670 |
+
return self.model.encode(videos, self.scale).float()
|
| 671 |
+
|
| 672 |
+
def decode_batch(self, zs):
|
| 673 |
+
with amp.autocast(dtype=self.dtype):
|
| 674 |
+
return self.model.decode(zs, self.scale).float().clamp_(-1, 1)
|
prompts/demo.yaml
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Infinite World - Demo Prompts
|
| 2 |
+
# Format: [prompt, condition_image_path, action_json_path]
|
| 3 |
+
prompts:
|
| 4 |
+
- - A serene campus walkway lined with modern glass buildings, green ivy climbing some walls, empty benches, soft dappled sunlight through maple trees.
|
| 5 |
+
- ./assets/example_case/0001.jpg
|
| 6 |
+
- ./assets/example_case/0001.json
|
| 7 |
+
|
| 8 |
+
- - A street in a fantasy city where buildings are carved into gargantuan ancient trees, glowing sap running through bark, misty floor.
|
| 9 |
+
- ./assets/example_case/0002.jpg
|
| 10 |
+
- ./assets/example_case/0002.json
|
readme.md
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<h1 align="center">Infinite-World</h1>
|
| 2 |
+
|
| 3 |
+
<h3 align="center">Scaling Interactive World Models to 1000-Frame Horizons via Pose-Free Hierarchical Memory</h3>
|
| 4 |
+
|
| 5 |
+
<p align="center">
|
| 6 |
+
<a href="http://arxiv.org/abs/2602.02393"><img src="https://img.shields.io/badge/arXiv-2602.02393-b31b1b.svg" alt="arXiv"></a>
|
| 7 |
+
<a href="https://rq-wu.github.io/projects/infinite_world"><img src="https://img.shields.io/badge/Project-Page-blue.svg" alt="Project Page"></a>
|
| 8 |
+
</p>
|
| 9 |
+
|
| 10 |
+
<p align="center">
|
| 11 |
+
<strong>Ruiqi Wu</strong><sup>1,2,3*</sup>, <strong>Xuanhua He</strong><sup>4,2*</sup>, <strong>Meng Cheng</strong><sup>2*</sup>, <strong>Tianyu Yang</strong><sup>2</sup>, <strong>Yong Zhang</strong><sup>2‡</sup>, <strong>Chunle Guo</strong><sup>1,3†</sup>, <strong>Chongyi Li</strong><sup>1,3</sup>, <strong>Ming-Ming Cheng</strong><sup>1,3</sup>
|
| 12 |
+
</p>
|
| 13 |
+
|
| 14 |
+
<p align="center">
|
| 15 |
+
<sup>1</sup>Nankai University <sup>2</sup>Meituan <sup>3</sup>NKIARI <sup>4</sup>HKUST
|
| 16 |
+
</p>
|
| 17 |
+
|
| 18 |
+
<p align="center">
|
| 19 |
+
<sup>*</sup>Equal Contribution <sup>†</sup>Corresponding Author <sup>‡</sup>Project Leader
|
| 20 |
+
</p>
|
| 21 |
+
|
| 22 |
+
---
|
| 23 |
+
|
| 24 |
+
## Highlights
|
| 25 |
+
|
| 26 |
+
**Infinite-World** is a robust interactive world model with:
|
| 27 |
+
|
| 28 |
+
- **Real-World Training** — Trained on real-world videos without requiring perfect pose annotations or synthetic data
|
| 29 |
+
- **1000+ Frame Memory** — Maintains coherent visual memory over 1000+ frames via Hierarchical Pose-free Memory Compressor (HPMC)
|
| 30 |
+
- **Robust Action Control** — Uncertainty-aware action labeling ensures accurate action-response learning from noisy trajectories
|
| 31 |
+
|
| 32 |
+
<p align="center">
|
| 33 |
+
<img src="./assets/framework.png" alt="Infinite-World Framework" width="100%">
|
| 34 |
+
</p>
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
## Installation
|
| 38 |
+
|
| 39 |
+
**Environment:** Python 3.10, CUDA 12.4 recommended.
|
| 40 |
+
|
| 41 |
+
### 1. Create conda environment
|
| 42 |
+
|
| 43 |
+
```bash
|
| 44 |
+
conda create -n infworld python=3.10
|
| 45 |
+
conda activate infworld
|
| 46 |
+
```
|
| 47 |
+
|
| 48 |
+
### 2. Install PyTorch with CUDA 12.4
|
| 49 |
+
|
| 50 |
+
Install from the official PyTorch index (no local whl):
|
| 51 |
+
|
| 52 |
+
```bash
|
| 53 |
+
pip install torch==2.6.0 torchvision==0.21.0 --index-url https://download.pytorch.org/whl/cu124
|
| 54 |
+
```
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
### 3. Install Python dependencies
|
| 58 |
+
|
| 59 |
+
```bash
|
| 60 |
+
pip install -r requirements.txt
|
| 61 |
+
```
|
| 62 |
+
|
| 63 |
+
---
|
| 64 |
+
|
| 65 |
+
## Checkpoint Configuration
|
| 66 |
+
|
| 67 |
+
All model paths are configured in **`configs/infworld_config.yaml`**. Paths are relative to the project root unless absolute.
|
| 68 |
+
|
| 69 |
+
### Download checkpoints
|
| 70 |
+
|
| 71 |
+
Download from [Wan-AI/Wan2.1-T2V-1.3B](https://huggingface.co/Wan-AI/Wan2.1-T2V-1.3B) and place files under `checkpoints/`:
|
| 72 |
+
|
| 73 |
+
| File / directory | Config key | Description |
|
| 74 |
+
|------------------|------------|-------------|
|
| 75 |
+
| `models/Wan2.1_VAE.pth` | `vae_cfg.vae_pth` | VAE weights |
|
| 76 |
+
| `models/models_t5_umt5-xxl-enc-bf16.pth` | `text_encoder_cfg.checkpoint_path` | T5 text encoder |
|
| 77 |
+
| `models/google/umt5-xxl` (folder) | `text_encoder_cfg.tokenizer_path` | T5 tokenizer |
|
| 78 |
+
| `infinite_world_model.ckpt` | `checkpoint_path` | DiT model weights |
|
| 79 |
+
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
- **DiT checkpoint:** Can be downloaded from [TBD]().
|
| 83 |
+
|
| 84 |
+
---
|
| 85 |
+
|
| 86 |
+
## Upload to Hugging Face (including checkpoints)
|
| 87 |
+
|
| 88 |
+
To upload this repo to Hugging Face Hub (code + `checkpoints/`):
|
| 89 |
+
|
| 90 |
+
1. **Login**
|
| 91 |
+
```bash
|
| 92 |
+
pip install huggingface_hub
|
| 93 |
+
huggingface-cli login
|
| 94 |
+
```
|
| 95 |
+
Use a token from [https://huggingface.co/settings/tokens](https://huggingface.co/settings/tokens) (need write permission).
|
| 96 |
+
|
| 97 |
+
2. **Upload**
|
| 98 |
+
From the project root (`infinite-world/`):
|
| 99 |
+
```bash
|
| 100 |
+
python scripts/upload_to_hf.py YOUR_USERNAME/infinite-world
|
| 101 |
+
```
|
| 102 |
+
Or set the repo and run:
|
| 103 |
+
```bash
|
| 104 |
+
export HF_REPO_ID=YOUR_USERNAME/infinite-world
|
| 105 |
+
python scripts/upload_to_hf.py
|
| 106 |
+
```
|
| 107 |
+
|
| 108 |
+
The script uploads the whole directory (including `checkpoints/`) and skips `__pycache__`, `outputs`, `.git`, etc. Large checkpoint files are uploaded via the Hub API; the first run may take a while depending on size and network.
|
| 109 |
+
|
| 110 |
+
3. **Create repo manually (optional)**
|
| 111 |
+
You can create the model repo first at [https://huggingface.co/new](https://huggingface.co/new) (type: **Model**), then run the script with that `repo_id`.
|
| 112 |
+
|
| 113 |
+
---
|
| 114 |
+
|
| 115 |
+
## Results
|
| 116 |
+
|
| 117 |
+
### Quantitative Comparison
|
| 118 |
+
|
| 119 |
+
| Model | Mot. Smo.↑ | Dyn. Deg.↑ | Aes. Qual.↑ | Img. Qual.↑ | Avg. Score↑ | Memory↓ | Fidelity↓ | Action↓ | ELO Rating↑ |
|
| 120 |
+
|:------|:----------:|:----------:|:-----------:|:-----------:|:-----------:|:-------:|:---------:|:-------:|:-----------:|
|
| 121 |
+
| Hunyuan-GameCraft | 0.9855 | 0.9896 | 0.5380 | 0.6010 | 0.7785 | 2.67 | 2.49 | 2.56 | 1311 |
|
| 122 |
+
| Matrix-Game 2.0 | 0.9788 | **1.0000** | 0.5267 | **0.7215** | 0.8068 | 2.98 | 2.91 | 1.78 | 1432 |
|
| 123 |
+
| Yume 1.5 | 0.9861 | 0.9896 | **0.5840** | <u>0.6969</u> | **0.8141** | <u>2.43</u> | <u>1.91</u> | 2.47 | 1495 |
|
| 124 |
+
| HY-World-1.5 | **0.9905** | **1.0000** | 0.5280 | 0.6611 | 0.7949 | 2.59 | 2.78 | **1.50** | <u>1542</u> |
|
| 125 |
+
| **Infinite-World** | <u>0.9876</u> | **1.0000** | <u>0.5440</u> | <u>0.7159</u> | <u>0.8119</u> | **1.92** | **1.67** | <u>1.54</u> | **1719** |
|
| 126 |
+
|
| 127 |
+
|
| 128 |
+
## Citation
|
| 129 |
+
|
| 130 |
+
If you find this work useful, please consider citing:
|
| 131 |
+
|
| 132 |
+
```bibtex
|
| 133 |
+
@article{wu2026infiniteworld,
|
| 134 |
+
title={Infinite-World: Scaling Interactive World Models to 1000-Frame Horizons via Pose-Free Hierarchical Memory},
|
| 135 |
+
author={Wu, Ruiqi and He, Xuanhua and Cheng, Meng and Yang, Tianyu and Zhang, Yong and Kang, Zhuoliang and Cai, Xunliang and Wei, Xiaoming and Guo, Chunle and Li, Chongyi and Cheng, Ming-Ming},
|
| 136 |
+
journal={arXiv preprint arXiv:2602.02393},
|
| 137 |
+
year={2026}
|
| 138 |
+
}
|
| 139 |
+
```
|
| 140 |
+
|
| 141 |
+
|
| 142 |
+
## License
|
| 143 |
+
|
| 144 |
+
This project is released under the [MIT License](LICENSE).
|
requirements.txt
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Infinite World - Python dependencies (PyPI only)
|
| 2 |
+
# Install PyTorch with CUDA first (see README), then: pip install -r requirements.txt
|
| 3 |
+
|
| 4 |
+
flash_attn==2.7.4.post1
|
| 5 |
+
absl-py==2.1.0
|
| 6 |
+
accelerate==1.9.0
|
| 7 |
+
addict==2.4.0
|
| 8 |
+
annotated-types==0.7.0
|
| 9 |
+
antlr4-python3-runtime==4.9.3
|
| 10 |
+
av==12.0.0
|
| 11 |
+
beautifulsoup4==4.12.3
|
| 12 |
+
braceexpand==0.1.7
|
| 13 |
+
certifi==2024.8.30
|
| 14 |
+
charset-normalizer==3.3.2
|
| 15 |
+
contourpy==1.3.0
|
| 16 |
+
crc32c==2.7.1
|
| 17 |
+
cycler==0.12.1
|
| 18 |
+
decorator==4.4.2
|
| 19 |
+
decord==0.6.0
|
| 20 |
+
diffusers==0.24.0
|
| 21 |
+
docopt==0.6.2
|
| 22 |
+
einops==0.8.0
|
| 23 |
+
ffmpeg-python==0.2.0
|
| 24 |
+
filelock==3.16.1
|
| 25 |
+
fonttools==4.54.1
|
| 26 |
+
fsspec==2024.9.0
|
| 27 |
+
ftfy==6.2.0
|
| 28 |
+
future==1.0.0
|
| 29 |
+
huggingface-hub==0.25.1
|
| 30 |
+
idna==3.10
|
| 31 |
+
imageio==2.34.1
|
| 32 |
+
imageio-ffmpeg==0.4.9
|
| 33 |
+
importlib_metadata==8.5.0
|
| 34 |
+
Jinja2==3.1.4
|
| 35 |
+
kiwisolver==1.4.7
|
| 36 |
+
loguru==0.7.2
|
| 37 |
+
Markdown==3.7
|
| 38 |
+
markdown-it-py==3.0.0
|
| 39 |
+
MarkupSafe==2.1.5
|
| 40 |
+
matplotlib==3.9.2
|
| 41 |
+
mdurl==0.1.2
|
| 42 |
+
moviepy==1.0.3
|
| 43 |
+
mpmath==1.3.0
|
| 44 |
+
networkx==3.3
|
| 45 |
+
ninja==1.11.1.1
|
| 46 |
+
numpy==1.26.4
|
| 47 |
+
omegaconf==2.3.0
|
| 48 |
+
opencv-python==4.9.0.80
|
| 49 |
+
packaging==24.1
|
| 50 |
+
pillow==10.4.0
|
| 51 |
+
ply==3.11
|
| 52 |
+
prettytable==3.10.0
|
| 53 |
+
proglog==0.1.10
|
| 54 |
+
protobuf==3.20.1
|
| 55 |
+
psutil==6.0.0
|
| 56 |
+
py-cpuinfo==9.0.0
|
| 57 |
+
pybind11==2.13.6
|
| 58 |
+
pydantic==2.9.2
|
| 59 |
+
pydantic_core==2.23.4
|
| 60 |
+
Pygments==2.18.0
|
| 61 |
+
pynvml==11.5.3
|
| 62 |
+
pyparsing==3.1.4
|
| 63 |
+
python-dateutil==2.9.0.post0
|
| 64 |
+
pytz==2024.2
|
| 65 |
+
PyYAML==6.0.2
|
| 66 |
+
regex==2024.9.11
|
| 67 |
+
requests==2.32.3
|
| 68 |
+
rich==13.8.1
|
| 69 |
+
safetensors==0.4.5
|
| 70 |
+
sentencepiece==0.2.0
|
| 71 |
+
six==1.16.0
|
| 72 |
+
soupsieve==2.6
|
| 73 |
+
sympy==1.13.1
|
| 74 |
+
tensorboard==2.16.2
|
| 75 |
+
tensorboard-data-server==0.7.2
|
| 76 |
+
termcolor==2.4.0
|
| 77 |
+
timm==1.0.9
|
| 78 |
+
tokenizers==0.19.1
|
| 79 |
+
tqdm==4.66.4
|
| 80 |
+
transformers==4.41.0
|
| 81 |
+
# triton: do not pin; it is installed with torch and must match your torch version
|
| 82 |
+
typing_extensions==4.12.2
|
| 83 |
+
urllib3==2.2.3
|
| 84 |
+
wcwidth==0.2.13
|
| 85 |
+
Werkzeug==3.0.4
|
| 86 |
+
yapf==0.32.0
|
| 87 |
+
zipp==3.20.2
|
| 88 |
+
pytest==8.3.5
|
| 89 |
+
pandas==2.2.3
|
scripts/infworld_inference.py
ADDED
|
@@ -0,0 +1,384 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Infinite World - Action-Conditioned Video Generation Inference Script
|
| 3 |
+
======================================================================
|
| 4 |
+
A standalone inference script for generating long videos with action control.
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
import sys
|
| 8 |
+
import os
|
| 9 |
+
import cv2
|
| 10 |
+
import math
|
| 11 |
+
import torch
|
| 12 |
+
import random
|
| 13 |
+
import json
|
| 14 |
+
import datetime
|
| 15 |
+
import importlib
|
| 16 |
+
import numpy as np
|
| 17 |
+
from PIL import Image
|
| 18 |
+
from omegaconf import OmegaConf
|
| 19 |
+
import torch.distributed as dist
|
| 20 |
+
import torchvision.transforms as transforms
|
| 21 |
+
import re
|
| 22 |
+
|
| 23 |
+
# Add project root to path
|
| 24 |
+
PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
| 25 |
+
sys.path.insert(0, PROJECT_ROOT)
|
| 26 |
+
|
| 27 |
+
from infworld.utils.prepare_dataloader import get_obj_from_str
|
| 28 |
+
from infworld.utils.data_utils import get_first_clip_from_video, save_silent_video
|
| 29 |
+
from infworld.utils.dataset_utils import is_vid, is_img
|
| 30 |
+
|
| 31 |
+
# ============================================================================
|
| 32 |
+
# Action Mapping Dictionaries
|
| 33 |
+
# ============================================================================
|
| 34 |
+
MOVE_ACTION_MAP = {
|
| 35 |
+
'no-op': 0,
|
| 36 |
+
'go forward': 1,
|
| 37 |
+
'go back': 2,
|
| 38 |
+
'go left': 3,
|
| 39 |
+
'go right': 4,
|
| 40 |
+
'go forward and go left': 5,
|
| 41 |
+
'go forward and go right': 6,
|
| 42 |
+
'go back and go left': 7,
|
| 43 |
+
'go back and go right': 8,
|
| 44 |
+
'uncertain': 9
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
VIEW_ACTION_MAP = {
|
| 48 |
+
'no-op': 0,
|
| 49 |
+
'turn up': 1,
|
| 50 |
+
'turn down': 2,
|
| 51 |
+
'turn left': 3,
|
| 52 |
+
'turn right': 4,
|
| 53 |
+
'turn up and turn left': 5,
|
| 54 |
+
'turn up and turn right': 6,
|
| 55 |
+
'turn down and turn left': 7,
|
| 56 |
+
'turn down and turn right': 8,
|
| 57 |
+
'uncertain': 9
|
| 58 |
+
}
|
| 59 |
+
|
| 60 |
+
# ============================================================================
|
| 61 |
+
# Utility Functions
|
| 62 |
+
# ============================================================================
|
| 63 |
+
def extract_ckpt_step(path):
|
| 64 |
+
"""Extract checkpoint step number from path."""
|
| 65 |
+
match = re.search(r'checkpoint-(\d+)\.ckpt', path)
|
| 66 |
+
return int(match.group(1)) if match else 0
|
| 67 |
+
|
| 68 |
+
def resize_and_center_crop(image, target_size):
|
| 69 |
+
"""Resize image and center crop to target size."""
|
| 70 |
+
orig_h, orig_w = image.shape[:2]
|
| 71 |
+
target_h, target_w = target_size
|
| 72 |
+
|
| 73 |
+
scale = max(target_h / orig_h, target_w / orig_w)
|
| 74 |
+
final_h = math.ceil(scale * orig_h)
|
| 75 |
+
final_w = math.ceil(scale * orig_w)
|
| 76 |
+
|
| 77 |
+
resized = cv2.resize(image, (final_w, final_h), interpolation=cv2.INTER_AREA)
|
| 78 |
+
tensor = torch.from_numpy(resized)[None, ...].permute(0, 3, 1, 2).contiguous()
|
| 79 |
+
cropped = transforms.functional.center_crop(tensor, target_size)
|
| 80 |
+
return cropped[:, :, None, :, :] # [1, C, 1, H, W]
|
| 81 |
+
|
| 82 |
+
def setup_seed(seed):
|
| 83 |
+
"""Set random seeds for reproducibility."""
|
| 84 |
+
torch.manual_seed(seed)
|
| 85 |
+
torch.cuda.manual_seed_all(seed)
|
| 86 |
+
np.random.seed(seed)
|
| 87 |
+
random.seed(seed)
|
| 88 |
+
torch.backends.cudnn.deterministic = True
|
| 89 |
+
|
| 90 |
+
def torch_gc():
|
| 91 |
+
"""Clear GPU memory cache."""
|
| 92 |
+
torch.cuda.empty_cache()
|
| 93 |
+
torch.cuda.ipc_collect()
|
| 94 |
+
|
| 95 |
+
def load_action_sequence(action_path):
|
| 96 |
+
"""Load action sequence from JSON file."""
|
| 97 |
+
with open(action_path, 'r') as f:
|
| 98 |
+
actions = json.load(f)
|
| 99 |
+
|
| 100 |
+
move_indices = [MOVE_ACTION_MAP[a['move']] for a in actions]
|
| 101 |
+
view_indices = [VIEW_ACTION_MAP[a['view']] for a in actions]
|
| 102 |
+
return move_indices, view_indices
|
| 103 |
+
|
| 104 |
+
def load_condition_image(image_path, bucket_config):
|
| 105 |
+
"""Load and preprocess condition image."""
|
| 106 |
+
if is_vid(image_path):
|
| 107 |
+
frames = get_first_clip_from_video(image_path, clip_len=1)
|
| 108 |
+
elif is_img(image_path):
|
| 109 |
+
image = cv2.imread(image_path)
|
| 110 |
+
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
|
| 111 |
+
frames = [image]
|
| 112 |
+
else:
|
| 113 |
+
raise ValueError(f'Unsupported file format: {image_path}')
|
| 114 |
+
|
| 115 |
+
processed_frames = []
|
| 116 |
+
for frame in frames:
|
| 117 |
+
ratio = frame.shape[0] / frame.shape[1]
|
| 118 |
+
closest_bucket = sorted(bucket_config.keys(), key=lambda x: abs(float(x) - ratio))[0]
|
| 119 |
+
target_h, target_w = bucket_config[closest_bucket][0]
|
| 120 |
+
|
| 121 |
+
tensor = resize_and_center_crop(frame, (target_h, target_w))
|
| 122 |
+
tensor = (tensor / 255 - 0.5) * 2 # Normalize to [-1, 1]
|
| 123 |
+
processed_frames.append(tensor)
|
| 124 |
+
|
| 125 |
+
return torch.cat(processed_frames, dim=2)
|
| 126 |
+
|
| 127 |
+
# ============================================================================
|
| 128 |
+
# Distributed Setup (support single-GPU without torchrun to avoid port conflict)
|
| 129 |
+
# ============================================================================
|
| 130 |
+
def setup_distributed():
|
| 131 |
+
"""Setup distributed or single-GPU mode."""
|
| 132 |
+
if 'RANK' in os.environ:
|
| 133 |
+
# Launched by torchrun or similar
|
| 134 |
+
rank = int(os.environ['RANK'])
|
| 135 |
+
world_size = int(os.environ.get('WORLD_SIZE', 1))
|
| 136 |
+
local_rank = int(os.environ.get('LOCAL_RANK', rank % torch.cuda.device_count()))
|
| 137 |
+
torch.cuda.set_device(local_rank)
|
| 138 |
+
dist.init_process_group(backend="nccl", timeout=datetime.timedelta(seconds=3600*24))
|
| 139 |
+
global_rank = dist.get_rank()
|
| 140 |
+
num_processes = dist.get_world_size()
|
| 141 |
+
return local_rank, global_rank, num_processes, True # use_cp_init=True
|
| 142 |
+
else:
|
| 143 |
+
# Single process (no torchrun) - avoid port conflict, no dist init
|
| 144 |
+
local_rank = 0
|
| 145 |
+
global_rank = 0
|
| 146 |
+
num_processes = 1
|
| 147 |
+
torch.cuda.set_device(local_rank)
|
| 148 |
+
return local_rank, global_rank, num_processes, False # use_cp_init=False
|
| 149 |
+
|
| 150 |
+
local_rank, global_rank, num_processes, use_dist = setup_distributed()
|
| 151 |
+
print(f"[InfWorld] local_rank: {local_rank} | global_rank: {global_rank} | world_size: {num_processes}")
|
| 152 |
+
|
| 153 |
+
# Context parallel setup
|
| 154 |
+
context_parallel_size = 1
|
| 155 |
+
import infworld.context_parallel.context_parallel_util as cp_util
|
| 156 |
+
if use_dist:
|
| 157 |
+
from infworld.context_parallel.context_parallel_util import init_context_parallel, get_dp_size, get_dp_rank
|
| 158 |
+
init_context_parallel(context_parallel_size=context_parallel_size, global_rank=global_rank, world_size=num_processes)
|
| 159 |
+
dp_rank = get_dp_rank()
|
| 160 |
+
dp_size = get_dp_size()
|
| 161 |
+
else:
|
| 162 |
+
# Single process: set globals so get_dp_rank/get_dp_size work without dist
|
| 163 |
+
cp_util.dp_rank = 0
|
| 164 |
+
cp_util.dp_size = 1
|
| 165 |
+
cp_util.cp_rank = 0
|
| 166 |
+
cp_util.cp_size = 1
|
| 167 |
+
dp_rank = 0
|
| 168 |
+
dp_size = 1
|
| 169 |
+
enable_context_parallel = (context_parallel_size > 1)
|
| 170 |
+
|
| 171 |
+
# ============================================================================
|
| 172 |
+
# Configuration
|
| 173 |
+
# ============================================================================
|
| 174 |
+
# Inference settings
|
| 175 |
+
GLOBAL_SEED = 42
|
| 176 |
+
setup_seed(GLOBAL_SEED + global_rank)
|
| 177 |
+
|
| 178 |
+
TEXT_CFG_SCALE = 5.0
|
| 179 |
+
NUM_SAMPLING_STEPS = 30
|
| 180 |
+
SHIFT = 7 # PX256: 3, PX627: 7, PX960: 11
|
| 181 |
+
NUM_CHUNKS = 13 # Number of video chunks to generate
|
| 182 |
+
HIGH_QUALITY_SAVE = True
|
| 183 |
+
|
| 184 |
+
# Paths - checkpoint_path is read from config (configs/infworld_config.yaml)
|
| 185 |
+
# Model config - use standalone config
|
| 186 |
+
CONFIG_PATH = os.path.join(PROJECT_ROOT, 'configs', 'infworld_config.yaml')
|
| 187 |
+
|
| 188 |
+
PROMPTS_YAML = os.path.join(PROJECT_ROOT, 'prompts', 'demo.yaml')
|
| 189 |
+
BUCKET_CONFIG_NAME = 'ASPECT_RATIO_627_F64'
|
| 190 |
+
|
| 191 |
+
# Output directory
|
| 192 |
+
OUTPUT_BASE = os.path.join(PROJECT_ROOT, 'outputs')
|
| 193 |
+
|
| 194 |
+
# Negative prompt for generation quality
|
| 195 |
+
NEGATIVE_PROMPT = "many cars, crowds, Vivid hues, overexposed, static, blurry details, subtitles, style, work, artwork, image, still, overall grayish, worst quality, low quality, JPEG compression artifacts, ugly, incomplete, extra fingers, poorly drawn hands, poorly drawn face, deformed, disfigured, deformed limbs, fused fingers, motionless image, cluttered background, three legs, crowded background, walking backwards."
|
| 196 |
+
|
| 197 |
+
# ============================================================================
|
| 198 |
+
# Main Inference Loop
|
| 199 |
+
# ============================================================================
|
| 200 |
+
def resolve_path(path, root=PROJECT_ROOT):
|
| 201 |
+
"""Resolve path: if relative, join with project root."""
|
| 202 |
+
if path is None:
|
| 203 |
+
return path
|
| 204 |
+
path = str(path).strip()
|
| 205 |
+
if not os.path.isabs(path):
|
| 206 |
+
path = os.path.join(root, path)
|
| 207 |
+
return path
|
| 208 |
+
|
| 209 |
+
|
| 210 |
+
def load_dit_state_dict(checkpoint_path):
|
| 211 |
+
"""Load DiT state dict from .ckpt (torch) or .safetensors."""
|
| 212 |
+
checkpoint_path = resolve_path(checkpoint_path)
|
| 213 |
+
if checkpoint_path.endswith(".safetensors"):
|
| 214 |
+
from safetensors.torch import load_file
|
| 215 |
+
state_dict = load_file(checkpoint_path)
|
| 216 |
+
else:
|
| 217 |
+
state_dict = torch.load(checkpoint_path, map_location="cpu")
|
| 218 |
+
if "state_dict" in state_dict:
|
| 219 |
+
state_dict = state_dict["state_dict"]
|
| 220 |
+
return state_dict
|
| 221 |
+
|
| 222 |
+
|
| 223 |
+
def main():
|
| 224 |
+
torch_gc()
|
| 225 |
+
|
| 226 |
+
config_path = CONFIG_PATH
|
| 227 |
+
args = OmegaConf.load(config_path)
|
| 228 |
+
checkpoint_path = resolve_path(args.get("checkpoint_path", "checkpoints/models/diffusion_pytorch_model.safetensors"))
|
| 229 |
+
|
| 230 |
+
ckpt_step = extract_ckpt_step(checkpoint_path)
|
| 231 |
+
|
| 232 |
+
# Create output directory
|
| 233 |
+
output_dir = os.path.join(OUTPUT_BASE, f"infworld-ckpt{ckpt_step}-step{NUM_SAMPLING_STEPS}-cfg{TEXT_CFG_SCALE}")
|
| 234 |
+
os.makedirs(output_dir, exist_ok=True)
|
| 235 |
+
|
| 236 |
+
print(f"[InfWorld] Loading checkpoint: {checkpoint_path}")
|
| 237 |
+
print(f"[InfWorld] Config: {config_path}")
|
| 238 |
+
print(f"[InfWorld] Output directory: {output_dir}")
|
| 239 |
+
|
| 240 |
+
# Resolve relative paths in config for models that load from disk
|
| 241 |
+
if hasattr(args, "vae_cfg") and "vae_pth" in args.vae_cfg:
|
| 242 |
+
args.vae_cfg.vae_pth = resolve_path(args.vae_cfg.vae_pth)
|
| 243 |
+
if hasattr(args, "text_encoder_cfg"):
|
| 244 |
+
if "checkpoint_path" in args.text_encoder_cfg:
|
| 245 |
+
args.text_encoder_cfg.checkpoint_path = resolve_path(args.text_encoder_cfg.checkpoint_path)
|
| 246 |
+
if "tokenizer_path" in args.text_encoder_cfg:
|
| 247 |
+
args.text_encoder_cfg.tokenizer_path = resolve_path(args.text_encoder_cfg.tokenizer_path)
|
| 248 |
+
|
| 249 |
+
# Initialize models
|
| 250 |
+
print("[InfWorld] Loading VAE...")
|
| 251 |
+
vae = get_obj_from_str(args.vae_target)(**args.vae_cfg).to(local_rank)
|
| 252 |
+
|
| 253 |
+
print("[InfWorld] Loading Text Encoder...")
|
| 254 |
+
text_encoder = get_obj_from_str(args.text_encoder_target)(device=local_rank, **args.text_encoder_cfg)
|
| 255 |
+
text_encoder.t5.model.to(local_rank)
|
| 256 |
+
|
| 257 |
+
print("[InfWorld] Loading Scheduler...")
|
| 258 |
+
scheduler = get_obj_from_str(args.scheduler_target)(**args.val_scheduler_cfg)
|
| 259 |
+
scheduler.num_sampling_steps = NUM_SAMPLING_STEPS
|
| 260 |
+
scheduler.shift = SHIFT
|
| 261 |
+
|
| 262 |
+
print("[InfWorld] Loading DiT Model...")
|
| 263 |
+
dtype = getattr(torch, args.amp_dtype)
|
| 264 |
+
dit = get_obj_from_str(args.model_target)(
|
| 265 |
+
out_channels=vae.out_channels,
|
| 266 |
+
caption_channels=text_encoder.output_dim,
|
| 267 |
+
model_max_length=text_encoder.model_max_length,
|
| 268 |
+
enable_context_parallel=enable_context_parallel,
|
| 269 |
+
**args.model_cfg
|
| 270 |
+
).to(dtype)
|
| 271 |
+
dit.eval()
|
| 272 |
+
|
| 273 |
+
# Load DiT checkpoint (from config)
|
| 274 |
+
state_dict = load_dit_state_dict(args.checkpoint_path)
|
| 275 |
+
|
| 276 |
+
# Remove position embeddings (will be recomputed)
|
| 277 |
+
state_dict.pop("pos_embed_temporal", None)
|
| 278 |
+
state_dict.pop("pos_embed", None)
|
| 279 |
+
|
| 280 |
+
missing, unexpected = dit.load_state_dict(state_dict, strict=False)
|
| 281 |
+
print(f"[InfWorld] Model loaded! Missing: {len(missing)}, Unexpected: {len(unexpected)}")
|
| 282 |
+
|
| 283 |
+
dit.to(local_rank)
|
| 284 |
+
|
| 285 |
+
# Load bucket config
|
| 286 |
+
from infworld.configs import bucket_config as bucket_config_module
|
| 287 |
+
bucket_config = getattr(bucket_config_module, BUCKET_CONFIG_NAME)
|
| 288 |
+
|
| 289 |
+
# Load prompts
|
| 290 |
+
prompts_path = os.path.abspath(PROMPTS_YAML)
|
| 291 |
+
target_prompts = OmegaConf.load(prompts_path).prompts
|
| 292 |
+
print(f"[InfWorld] Loaded {len(target_prompts)} prompts")
|
| 293 |
+
|
| 294 |
+
# Process each prompt
|
| 295 |
+
for task_idx, (prompt, image_path, action_path) in enumerate(target_prompts):
|
| 296 |
+
if task_idx % dp_size != dp_rank:
|
| 297 |
+
continue
|
| 298 |
+
|
| 299 |
+
if not os.path.exists(image_path):
|
| 300 |
+
print(f"[InfWorld] Skipping task {task_idx}: Image not found - {image_path}")
|
| 301 |
+
continue
|
| 302 |
+
|
| 303 |
+
if not os.path.exists(action_path):
|
| 304 |
+
print(f"[InfWorld] Skipping task {task_idx}: Action not found - {action_path}")
|
| 305 |
+
continue
|
| 306 |
+
|
| 307 |
+
print(f"[InfWorld] Task {task_idx}: {prompt[:50]}...")
|
| 308 |
+
|
| 309 |
+
# Load condition image
|
| 310 |
+
cond_video = load_condition_image(image_path, bucket_config).to(local_rank)
|
| 311 |
+
|
| 312 |
+
with torch.no_grad():
|
| 313 |
+
cond_latent = vae.encode(cond_video)
|
| 314 |
+
|
| 315 |
+
# Load action sequence
|
| 316 |
+
move_indices, view_indices = load_action_sequence(action_path)
|
| 317 |
+
|
| 318 |
+
# Initialize video buffer
|
| 319 |
+
video_buffer = cond_video.clone().cpu()
|
| 320 |
+
|
| 321 |
+
# Latent size for generation
|
| 322 |
+
latent_size = list(cond_latent.shape)
|
| 323 |
+
latent_size[2] = 21 # Output frames per chunk
|
| 324 |
+
latent_size = torch.Size(latent_size)
|
| 325 |
+
|
| 326 |
+
# Generate video chunks
|
| 327 |
+
for chunk_idx in range(NUM_CHUNKS):
|
| 328 |
+
print(f"[InfWorld] Generating chunk {chunk_idx + 1}/{NUM_CHUNKS}")
|
| 329 |
+
|
| 330 |
+
with torch.no_grad():
|
| 331 |
+
current_cond = video_buffer.to(local_rank)
|
| 332 |
+
current_latent = vae.encode(current_cond)
|
| 333 |
+
|
| 334 |
+
# Get action slice for current chunk
|
| 335 |
+
curr_start = video_buffer.shape[2] - 1
|
| 336 |
+
curr_end = curr_start + args.validation_data.num_frames
|
| 337 |
+
|
| 338 |
+
move = torch.tensor(move_indices[curr_start:curr_end], dtype=torch.long, device=local_rank)
|
| 339 |
+
view = torch.tensor(view_indices[curr_start:curr_end], dtype=torch.long, device=local_rank)
|
| 340 |
+
|
| 341 |
+
# Pad if needed
|
| 342 |
+
num_frames = args.validation_data.num_frames
|
| 343 |
+
if move.shape[0] < num_frames:
|
| 344 |
+
pad_len = num_frames - move.shape[0]
|
| 345 |
+
move = torch.cat([move, torch.zeros(pad_len, dtype=torch.long, device=local_rank)])
|
| 346 |
+
view = torch.cat([view, torch.zeros(pad_len, dtype=torch.long, device=local_rank)])
|
| 347 |
+
|
| 348 |
+
additional_args = {
|
| 349 |
+
"image_cond": current_latent,
|
| 350 |
+
"move": move.unsqueeze(0),
|
| 351 |
+
"view": view.unsqueeze(0),
|
| 352 |
+
}
|
| 353 |
+
|
| 354 |
+
torch_gc()
|
| 355 |
+
|
| 356 |
+
with torch.no_grad():
|
| 357 |
+
samples = scheduler.sample(
|
| 358 |
+
model=dit,
|
| 359 |
+
text_encoder=text_encoder,
|
| 360 |
+
null_embedder=dit.y_embedder,
|
| 361 |
+
z_size=latent_size,
|
| 362 |
+
prompts=[prompt],
|
| 363 |
+
guidance_scale=TEXT_CFG_SCALE,
|
| 364 |
+
negative_prompts=[NEGATIVE_PROMPT],
|
| 365 |
+
device=torch.device(local_rank),
|
| 366 |
+
additional_args=additional_args,
|
| 367 |
+
)
|
| 368 |
+
|
| 369 |
+
decoded_chunk = vae.decode(samples).cpu()
|
| 370 |
+
video_buffer = torch.cat([video_buffer, decoded_chunk[:, :, 1:]], dim=2)
|
| 371 |
+
|
| 372 |
+
print(f"[InfWorld] Chunk {chunk_idx + 1} done. Total frames: {video_buffer.shape[2]}")
|
| 373 |
+
torch_gc()
|
| 374 |
+
|
| 375 |
+
# Save final video
|
| 376 |
+
video_name = f"{task_idx:04d}_{prompt[:30].replace(' ', '_')}"
|
| 377 |
+
save_path = os.path.join(output_dir, video_name)
|
| 378 |
+
|
| 379 |
+
quality = 10 if HIGH_QUALITY_SAVE else 5
|
| 380 |
+
save_silent_video(video_buffer.to(local_rank), save_path, fps=30, quality=quality)
|
| 381 |
+
print(f"[InfWorld] Saved: {save_path}.mp4")
|
| 382 |
+
|
| 383 |
+
if __name__ == "__main__":
|
| 384 |
+
main()
|
scripts/upload_to_hf.py
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
Upload Infinite-World repo to Hugging Face Hub (including checkpoints).
|
| 4 |
+
|
| 5 |
+
Prerequisites:
|
| 6 |
+
1. pip install huggingface_hub
|
| 7 |
+
2. huggingface-cli login # or: from huggingface_hub import login; login()
|
| 8 |
+
|
| 9 |
+
Usage:
|
| 10 |
+
cd infinite-world
|
| 11 |
+
python scripts/upload_to_hf.py [REPO_ID]
|
| 12 |
+
|
| 13 |
+
Examples:
|
| 14 |
+
python scripts/upload_to_hf.py
|
| 15 |
+
python scripts/upload_to_hf.py your-username/infinite-world
|
| 16 |
+
"""
|
| 17 |
+
|
| 18 |
+
import os
|
| 19 |
+
import sys
|
| 20 |
+
|
| 21 |
+
# Project root = parent of scripts/
|
| 22 |
+
PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
def main():
|
| 26 |
+
try:
|
| 27 |
+
from huggingface_hub import HfApi, create_repo, whoami
|
| 28 |
+
except ImportError:
|
| 29 |
+
print("Install: pip install huggingface_hub")
|
| 30 |
+
sys.exit(1)
|
| 31 |
+
|
| 32 |
+
repo_id = (
|
| 33 |
+
(sys.argv[1] if len(sys.argv) > 1 else None)
|
| 34 |
+
or os.environ.get("HF_REPO_ID")
|
| 35 |
+
or "MeiGen-AI/Infinite-World"
|
| 36 |
+
)
|
| 37 |
+
|
| 38 |
+
# Check login first (avoid 401 later)
|
| 39 |
+
try:
|
| 40 |
+
info = whoami()
|
| 41 |
+
print(f"[HF] Logged in as: {info.get('name', info.get('type', '?'))}")
|
| 42 |
+
except Exception as e:
|
| 43 |
+
print("[HF] Not logged in or token invalid (401).")
|
| 44 |
+
print(" Run: huggingface-cli login")
|
| 45 |
+
print(" Get a token with WRITE at: https://huggingface.co/settings/tokens")
|
| 46 |
+
print(" For org repo MeiGen-AI/Infinite-World, your account must have write access to the MeiGen-AI org.")
|
| 47 |
+
sys.exit(1)
|
| 48 |
+
|
| 49 |
+
api = HfApi()
|
| 50 |
+
repo_type = "model"
|
| 51 |
+
|
| 52 |
+
# Create repo if it doesn't exist (skip if 401; repo may already exist)
|
| 53 |
+
try:
|
| 54 |
+
create_repo(repo_id, repo_type=repo_type, exist_ok=True)
|
| 55 |
+
print(f"[HF] Repo ready: https://huggingface.co/{repo_id}")
|
| 56 |
+
except Exception as e:
|
| 57 |
+
err = str(e).lower()
|
| 58 |
+
if "401" in err or "unauthorized" in err:
|
| 59 |
+
print("[HF] No write permission for this repo. Fix: use a token with write access; for MeiGen-AI/Infinite-World, be a member of MeiGen-AI org or use the org token.")
|
| 60 |
+
sys.exit(1)
|
| 61 |
+
print(f"[HF] Create repo: {e}")
|
| 62 |
+
# Continue; repo might already exist
|
| 63 |
+
|
| 64 |
+
# Exclude cache/outputs, keep checkpoints and code
|
| 65 |
+
ignore_patterns = [
|
| 66 |
+
"__pycache__",
|
| 67 |
+
"*.pyc",
|
| 68 |
+
".git",
|
| 69 |
+
"outputs",
|
| 70 |
+
".cursor",
|
| 71 |
+
"*.egg-info",
|
| 72 |
+
".eggs",
|
| 73 |
+
]
|
| 74 |
+
|
| 75 |
+
print(f"[HF] Uploading from {PROJECT_ROOT} to {repo_id} ...")
|
| 76 |
+
api.upload_folder(
|
| 77 |
+
folder_path=PROJECT_ROOT,
|
| 78 |
+
repo_id=repo_id,
|
| 79 |
+
repo_type=repo_type,
|
| 80 |
+
ignore_patterns=ignore_patterns,
|
| 81 |
+
)
|
| 82 |
+
print(f"[HF] Done: https://huggingface.co/{repo_id}")
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
if __name__ == "__main__":
|
| 86 |
+
main()
|
setup_project.py
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Setup script to copy and adapt source files from hg-research-hub to infinite-world.
|
| 3 |
+
This creates a standalone project without external dependencies.
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
import os
|
| 7 |
+
import re
|
| 8 |
+
import shutil
|
| 9 |
+
|
| 10 |
+
# Source and target directories
|
| 11 |
+
SRC_BASE = '/mnt/dolphinfs/ssd_pool/docker/user/hadoop-videogen-hl/hadoop-camera3d/wuruiqi/hg-research-hub/source'
|
| 12 |
+
DST_BASE = '/mnt/dolphinfs/ssd_pool/docker/user/hadoop-videogen-hl/hadoop-camera3d/wuruiqi/infinite-world/infworld'
|
| 13 |
+
|
| 14 |
+
# Files to copy and their destination subdirectories
|
| 15 |
+
FILES_TO_COPY = {
|
| 16 |
+
# Models
|
| 17 |
+
'meigen/model_wanx_multi_action_v2v_convenc_locmem_slidewindow_temp_sample_mask_attn_real_checkpointing.py': 'models/dit_model.py',
|
| 18 |
+
'meigen/rectified_flow_wanx_t2v_action.py': 'models/scheduler.py',
|
| 19 |
+
'meigen/checkpoint.py': 'models/checkpoint.py',
|
| 20 |
+
'meigen/umt5.py': 'models/umt5.py',
|
| 21 |
+
'meigen/t5.py': 'models/t5.py',
|
| 22 |
+
|
| 23 |
+
# VAE
|
| 24 |
+
'vae/__init__.py': 'vae/__init__.py',
|
| 25 |
+
'vae/wan/vae.py': 'vae/vae.py',
|
| 26 |
+
|
| 27 |
+
# CLIP
|
| 28 |
+
'clip/clip.py': 'clip/clip.py',
|
| 29 |
+
'clip/tokenizers.py': 'clip/tokenizers.py',
|
| 30 |
+
'clip/xlm_roberta.py': 'clip/xlm_roberta.py',
|
| 31 |
+
|
| 32 |
+
# Context Parallel
|
| 33 |
+
'context_parallel/context_parallel_util.py': 'context_parallel/context_parallel_util.py',
|
| 34 |
+
|
| 35 |
+
# Utils
|
| 36 |
+
'dataset/utils.py': 'utils/data_utils.py',
|
| 37 |
+
'dataset/prepare_dataloader.py': 'utils/prepare_dataloader.py',
|
| 38 |
+
|
| 39 |
+
# OpenSora (for registry and dataset utils)
|
| 40 |
+
'opensora/utils/dataset_utils.py': 'utils/dataset_utils.py',
|
| 41 |
+
'opensora/registry.py': 'utils/registry.py',
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
# Import replacements (old pattern -> new pattern)
|
| 45 |
+
IMPORT_REPLACEMENTS = [
|
| 46 |
+
# Models
|
| 47 |
+
(r'from source\.meigen\.checkpoint', 'from infworld.models.checkpoint'),
|
| 48 |
+
(r'from source\.meigen\.model_wanx_multi_action', 'from infworld.models.dit_model'),
|
| 49 |
+
(r'from source\.meigen\.rectified_flow_wanx_t2v_action', 'from infworld.models.scheduler'),
|
| 50 |
+
(r'from source\.meigen\.umt5', 'from infworld.models.umt5'),
|
| 51 |
+
(r'from source\.meigen\.t5', 'from infworld.models.t5'),
|
| 52 |
+
(r'from source\.meigen', 'from infworld.models'),
|
| 53 |
+
|
| 54 |
+
# Context Parallel
|
| 55 |
+
(r'from source\.context_parallel\.context_parallel_util', 'from infworld.context_parallel.context_parallel_util'),
|
| 56 |
+
(r'from source\.context_parallel import context_parallel_util', 'from infworld.context_parallel import context_parallel_util'),
|
| 57 |
+
|
| 58 |
+
# VAE
|
| 59 |
+
(r'from source\.vae\.wan\.vae', 'from infworld.vae.vae'),
|
| 60 |
+
(r'from source\.vae\.cogvideo\.autoencoder_kl_cogvideox', 'from infworld.vae.vae'),
|
| 61 |
+
(r'from source\.vae', 'from infworld.vae'),
|
| 62 |
+
(r'from source\.opensora\.registry import MODELS', '# Registry disabled for standalone'),
|
| 63 |
+
|
| 64 |
+
# CLIP
|
| 65 |
+
(r'from source\.clip\.clip', 'from infworld.clip.clip'),
|
| 66 |
+
(r'from source\.clip\.tokenizers', 'from infworld.clip.tokenizers'),
|
| 67 |
+
(r'from source\.clip\.xlm_roberta', 'from infworld.clip.xlm_roberta'),
|
| 68 |
+
(r'from source\.clip', 'from infworld.clip'),
|
| 69 |
+
|
| 70 |
+
# Dataset utils
|
| 71 |
+
(r'from source\.dataset\.utils', 'from infworld.utils.data_utils'),
|
| 72 |
+
(r'from source\.dataset\.prepare_dataloader', 'from infworld.utils.prepare_dataloader'),
|
| 73 |
+
(r'from source\.opensora\.utils\.dataset_utils', 'from infworld.utils.dataset_utils'),
|
| 74 |
+
(r'from source\.opensora\.registry', 'from infworld.utils.registry'),
|
| 75 |
+
]
|
| 76 |
+
|
| 77 |
+
|
| 78 |
+
def ensure_dir(path):
|
| 79 |
+
"""Create directory if it doesn't exist."""
|
| 80 |
+
os.makedirs(os.path.dirname(path), exist_ok=True)
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
def copy_and_transform(src_path, dst_path):
|
| 84 |
+
"""Copy file and transform imports."""
|
| 85 |
+
print(f"Copying: {src_path} -> {dst_path}")
|
| 86 |
+
|
| 87 |
+
ensure_dir(dst_path)
|
| 88 |
+
|
| 89 |
+
with open(src_path, 'r', encoding='utf-8') as f:
|
| 90 |
+
content = f.read()
|
| 91 |
+
|
| 92 |
+
# Apply import replacements
|
| 93 |
+
for old_pattern, new_pattern in IMPORT_REPLACEMENTS:
|
| 94 |
+
content = re.sub(old_pattern, new_pattern, content)
|
| 95 |
+
|
| 96 |
+
with open(dst_path, 'w', encoding='utf-8') as f:
|
| 97 |
+
f.write(content)
|
| 98 |
+
|
| 99 |
+
|
| 100 |
+
def create_init_files():
|
| 101 |
+
"""Create __init__.py files for all packages."""
|
| 102 |
+
packages = ['infworld', 'infworld/models', 'infworld/vae', 'infworld/clip',
|
| 103 |
+
'infworld/context_parallel', 'infworld/utils', 'infworld/configs']
|
| 104 |
+
|
| 105 |
+
for pkg in packages:
|
| 106 |
+
init_path = os.path.join(DST_BASE, '..', pkg, '__init__.py')
|
| 107 |
+
init_path = os.path.normpath(init_path)
|
| 108 |
+
ensure_dir(init_path)
|
| 109 |
+
|
| 110 |
+
if not os.path.exists(init_path):
|
| 111 |
+
with open(init_path, 'w') as f:
|
| 112 |
+
f.write(f'# {pkg} package\n')
|
| 113 |
+
print(f"Created: {init_path}")
|
| 114 |
+
|
| 115 |
+
|
| 116 |
+
def main():
|
| 117 |
+
print("=" * 60)
|
| 118 |
+
print("Setting up Infinite World standalone project")
|
| 119 |
+
print("=" * 60)
|
| 120 |
+
|
| 121 |
+
# Create package directories
|
| 122 |
+
create_init_files()
|
| 123 |
+
|
| 124 |
+
# Copy and transform files
|
| 125 |
+
for src_rel, dst_rel in FILES_TO_COPY.items():
|
| 126 |
+
src_path = os.path.join(SRC_BASE, src_rel)
|
| 127 |
+
dst_path = os.path.join(DST_BASE, dst_rel)
|
| 128 |
+
|
| 129 |
+
if os.path.exists(src_path):
|
| 130 |
+
copy_and_transform(src_path, dst_path)
|
| 131 |
+
else:
|
| 132 |
+
print(f"WARNING: Source file not found: {src_path}")
|
| 133 |
+
|
| 134 |
+
print("\n" + "=" * 60)
|
| 135 |
+
print("Setup complete!")
|
| 136 |
+
print("=" * 60)
|
| 137 |
+
|
| 138 |
+
|
| 139 |
+
if __name__ == '__main__':
|
| 140 |
+
main()
|