Spaces:
Sleeping
Sleeping
Muhammad Waqas
commited on
Commit
·
db6bd44
1
Parent(s):
c9dba17
Added: Generate image to video
Browse files- .env +3 -2
- app.py +5 -17
- sample-response.json +0 -54
- static/.DS_Store +0 -0
- workflows/cogvideox_image_to_video_workflow_api_old.json +0 -176
.env
CHANGED
|
@@ -1,5 +1,6 @@
|
|
| 1 |
-
SERVER_ADDRESS=https://gosign-de-
|
| 2 |
-
WS_ADDRESS=wss://gosign-de-
|
| 3 |
|
|
|
|
| 4 |
# SERVER_ADDRESS=http://127.0.0.1:8188/
|
| 5 |
# WS_ADDRESS=ws://127.0.0.1:8188/ws
|
|
|
|
| 1 |
+
SERVER_ADDRESS=https://gosign-de-comfyui-stg.hf.space
|
| 2 |
+
WS_ADDRESS=wss://gosign-de-comfyui-stg.hf.space/ws
|
| 3 |
|
| 4 |
+
# For Development Environment
|
| 5 |
# SERVER_ADDRESS=http://127.0.0.1:8188/
|
| 6 |
# WS_ADDRESS=ws://127.0.0.1:8188/ws
|
app.py
CHANGED
|
@@ -30,7 +30,6 @@ ws_address = os.getenv("WS_ADDRESS")
|
|
| 30 |
# Generate a unique client ID
|
| 31 |
client_id = str(uuid.uuid4())
|
| 32 |
|
| 33 |
-
|
| 34 |
def allowed_file(filename):
|
| 35 |
"""Check if the uploaded file has an allowed extension."""
|
| 36 |
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
|
|
@@ -80,7 +79,6 @@ def get_image(filename, subfolder, image_type, token):
|
|
| 80 |
print(e.read())
|
| 81 |
raise
|
| 82 |
|
| 83 |
-
|
| 84 |
def get_images(ws, workflow, token):
|
| 85 |
prompt_id = queue_prompt(workflow, token)
|
| 86 |
output_images = {}
|
|
@@ -111,9 +109,9 @@ def get_images(ws, workflow, token):
|
|
| 111 |
def home():
|
| 112 |
return render_template('home.html')
|
| 113 |
|
| 114 |
-
|
| 115 |
-
# Generate text to image using FLUX1.DEV
|
| 116 |
-
|
| 117 |
|
| 118 |
# Generate image route
|
| 119 |
@app.route('/generate_image', methods=['POST'])
|
|
@@ -146,10 +144,6 @@ def generate_image():
|
|
| 146 |
workflow = json.loads(workflow_jsondata)
|
| 147 |
workflow["6"]["inputs"]["text"] = text_prompt
|
| 148 |
|
| 149 |
-
# workflow["7"]["inputs"]["text"] = "text, watermark, low quality, extra hands, extra legs."
|
| 150 |
-
# seednum = random.randint(1, 9999999999999)
|
| 151 |
-
# workflow["3"]["inputs"]["seed"] = seednum
|
| 152 |
-
|
| 153 |
# Generate a random 15-digit seed as an integer
|
| 154 |
seednum = random.randint(100000000000000, 999999999999999)
|
| 155 |
workflow["31"]["inputs"]["seed"] = seednum
|
|
@@ -183,12 +177,12 @@ def get_image_file(filename):
|
|
| 183 |
return send_file(filename, mimetype='image/png')
|
| 184 |
|
| 185 |
|
| 186 |
-
|
| 187 |
# Route to serve images
|
| 188 |
@app.route('/static/<path:filename>')
|
| 189 |
def serve_static(filename):
|
| 190 |
return send_from_directory('static', filename)
|
| 191 |
|
|
|
|
| 192 |
def make_request(url, data=None, headers=None):
|
| 193 |
req = urllib.request.Request(url, data=data, headers=headers)
|
| 194 |
try:
|
|
@@ -214,6 +208,7 @@ def queue_prompt(workflow, token):
|
|
| 214 |
raise ValueError("Failed to queue the prompt. Check the request or API response.")
|
| 215 |
return response['prompt_id']
|
| 216 |
|
|
|
|
| 217 |
def get_history(prompt_id, token):
|
| 218 |
headers = {
|
| 219 |
'Authorization': f'Bearer {token}',
|
|
@@ -228,13 +223,6 @@ def get_video_data(filename, subfolder, token):
|
|
| 228 |
# Handle empty subfolder case gracefully
|
| 229 |
subfolder = subfolder or '' # Default to empty string if None
|
| 230 |
|
| 231 |
-
# Construct query parameters
|
| 232 |
-
# url_values = {
|
| 233 |
-
# 'filename': filename,
|
| 234 |
-
# 'subfolder': subfolder,
|
| 235 |
-
# 'type': 'video'
|
| 236 |
-
# }
|
| 237 |
-
|
| 238 |
# Construct query parameters
|
| 239 |
url_values = {
|
| 240 |
'filename': filename
|
|
|
|
| 30 |
# Generate a unique client ID
|
| 31 |
client_id = str(uuid.uuid4())
|
| 32 |
|
|
|
|
| 33 |
def allowed_file(filename):
|
| 34 |
"""Check if the uploaded file has an allowed extension."""
|
| 35 |
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
|
|
|
|
| 79 |
print(e.read())
|
| 80 |
raise
|
| 81 |
|
|
|
|
| 82 |
def get_images(ws, workflow, token):
|
| 83 |
prompt_id = queue_prompt(workflow, token)
|
| 84 |
output_images = {}
|
|
|
|
| 109 |
def home():
|
| 110 |
return render_template('home.html')
|
| 111 |
|
| 112 |
+
###############################################
|
| 113 |
+
# Generate text to image using FLUX1.DEV Model#
|
| 114 |
+
###############################################
|
| 115 |
|
| 116 |
# Generate image route
|
| 117 |
@app.route('/generate_image', methods=['POST'])
|
|
|
|
| 144 |
workflow = json.loads(workflow_jsondata)
|
| 145 |
workflow["6"]["inputs"]["text"] = text_prompt
|
| 146 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 147 |
# Generate a random 15-digit seed as an integer
|
| 148 |
seednum = random.randint(100000000000000, 999999999999999)
|
| 149 |
workflow["31"]["inputs"]["seed"] = seednum
|
|
|
|
| 177 |
return send_file(filename, mimetype='image/png')
|
| 178 |
|
| 179 |
|
|
|
|
| 180 |
# Route to serve images
|
| 181 |
@app.route('/static/<path:filename>')
|
| 182 |
def serve_static(filename):
|
| 183 |
return send_from_directory('static', filename)
|
| 184 |
|
| 185 |
+
# Make a request route
|
| 186 |
def make_request(url, data=None, headers=None):
|
| 187 |
req = urllib.request.Request(url, data=data, headers=headers)
|
| 188 |
try:
|
|
|
|
| 208 |
raise ValueError("Failed to queue the prompt. Check the request or API response.")
|
| 209 |
return response['prompt_id']
|
| 210 |
|
| 211 |
+
# Get ComfyUI prompt history
|
| 212 |
def get_history(prompt_id, token):
|
| 213 |
headers = {
|
| 214 |
'Authorization': f'Bearer {token}',
|
|
|
|
| 223 |
# Handle empty subfolder case gracefully
|
| 224 |
subfolder = subfolder or '' # Default to empty string if None
|
| 225 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 226 |
# Construct query parameters
|
| 227 |
url_values = {
|
| 228 |
'filename': filename
|
sample-response.json
DELETED
|
@@ -1,54 +0,0 @@
|
|
| 1 |
-
{'prompt': [
|
| 2 |
-
3, '2d7683a1-f132-4f75-bb02-ced4975a745b',
|
| 3 |
-
{'1': {'inputs': {'model': 'THUDM/CogVideoX-5b-I2V', 'precision': 'bf16', 'fp8_transformer': 'disabled', 'compile': 'disabled', 'enable_sequential_cpu_offload': False
|
| 4 |
-
}, 'class_type': 'DownloadAndLoadCogVideoModel', '_meta': {'title': '(Down)load CogVideo Model'
|
| 5 |
-
}
|
| 6 |
-
}, '20': {'inputs': {'clip_name': 't5\\google_t5-v1_1-xxl_encoderonly-fp8_e4m3fn.safetensors', 'type': 'sd3'
|
| 7 |
-
}, 'class_type': 'CLIPLoader', '_meta': {'title': 'Load CLIP'
|
| 8 |
-
}
|
| 9 |
-
}, '30': {'inputs': {'prompt': 'A beautiful sunset over the mountains', 'strength': 1.0, 'force_offload': True, 'clip': ['20',
|
| 10 |
-
0
|
| 11 |
-
]
|
| 12 |
-
}, 'class_type': 'CogVideoTextEncode', '_meta': {'title': 'CogVideo TextEncode'
|
| 13 |
-
}
|
| 14 |
-
}, '31': {'inputs': {'prompt': 'Low quality, watermark, strange motion', 'strength': 1.0, 'force_offload': True, 'clip': ['20',
|
| 15 |
-
0
|
| 16 |
-
]
|
| 17 |
-
}, 'class_type': 'CogVideoTextEncode', '_meta': {'title': 'CogVideo TextEncode'
|
| 18 |
-
}
|
| 19 |
-
}, '37': {'inputs': {'width': 720, 'height': 480, 'upscale_method': 'lanczos', 'keep_proportion': False, 'divisible_by': 16, 'crop': 'disabled', 'image': ['73',
|
| 20 |
-
0
|
| 21 |
-
]
|
| 22 |
-
}, 'class_type': 'ImageResizeKJ', '_meta': {'title': 'Resize Image'
|
| 23 |
-
}
|
| 24 |
-
}, '44': {'inputs': {'frame_rate': 12.0, 'loop_count': 0, 'filename_prefix': 'CogVideoX-I2V', 'format': 'video/h264-mp4', 'pix_fmt': 'yuv420p', 'crf': 19, 'save_metadata': True, 'pingpong': False, 'save_output': True, 'images': ['56',
|
| 25 |
-
0
|
| 26 |
-
]
|
| 27 |
-
}, 'class_type': 'VHS_VideoCombine', '_meta': {'title': 'Video Combine 🎥🅥🅗🅢'
|
| 28 |
-
}
|
| 29 |
-
}, '56': {'inputs': {'enable_vae_tiling': False, 'tile_sample_min_height': 96, 'tile_sample_min_width': 96, 'tile_overlap_factor_height': 0.083, 'tile_overlap_factor_width': 0.083, 'auto_tile_size': True, 'pipeline': ['57',
|
| 30 |
-
0
|
| 31 |
-
], 'samples': ['57',
|
| 32 |
-
1
|
| 33 |
-
]
|
| 34 |
-
}, 'class_type': 'CogVideoDecode', '_meta': {'title': 'CogVideo Decode'
|
| 35 |
-
}
|
| 36 |
-
}, '57': {'inputs': {'height': 480, 'width': 720, 'num_frames': 49, 'steps': 5, 'cfg': 6.0, 'seed': 660821088584312, 'scheduler': 'DPM++', 'denoise_strength': 1.0, 'pipeline': ['1',
|
| 37 |
-
0
|
| 38 |
-
], 'positive': ['30',
|
| 39 |
-
0
|
| 40 |
-
], 'negative': ['31',
|
| 41 |
-
0
|
| 42 |
-
], 'image_cond_latents': ['58',
|
| 43 |
-
0
|
| 44 |
-
]
|
| 45 |
-
}, 'class_type': 'CogVideoSampler', '_meta': {'title': 'CogVideo Sampler'
|
| 46 |
-
}
|
| 47 |
-
}, '58': {'inputs': {'chunk_size': 16, 'enable_tiling': True, 'pipeline': ['1',
|
| 48 |
-
0
|
| 49 |
-
], 'image': ['37',
|
| 50 |
-
0
|
| 51 |
-
]
|
| 52 |
-
}, 'class_type': 'CogVideoImageEncode', '_meta': {'title': 'CogVideo ImageEncode'
|
| 53 |
-
}
|
| 54 |
-
}, '73': {'inputs': {'url': 'https: //huggingface.co/spaces/gosign-de/comfyui-api/resolve/main/images/iStock_000014226797_Small.jpg', 'cache': True}, 'class_type': 'LoadImageByUrl //Browser', '_meta': {'title': 'Load Image By URL'}}, '75': {'inputs': {'images': ['73', 0]}, 'class_type': 'PreviewImage', '_meta': {'title': 'Preview Image'}}}, {'client_id': 'bb7de022-33ad-4c01-b272-bf2b1eb05e4e'}, ['75', '44']], 'outputs': {'44': {'gifs': [{'filename': 'CogVideoX-I2V_00003.mp4', 'subfolder': '', 'type': 'output', 'format': 'video/h264-mp4', 'frame_rate': 12.0}]}, '75': {'images': [{'filename': 'ComfyUI_temp_favdf_00001_.png', 'subfolder': '', 'type': 'temp'}]}}, 'status': {'status_str': 'success', 'completed': True, 'messages': [['execution_start', {'prompt_id': '2d7683a1-f132-4f75-bb02-ced4975a745b', 'timestamp': 1729158615147}], ['execution_cached', {'nodes': ['1', '20', '30', '31', '37', '58', '73', '75'], 'prompt_id': '2d7683a1-f132-4f75-bb02-ced4975a745b', 'timestamp': 1729158615162}], ['execution_success', {'prompt_id': '2d7683a1-f132-4f75-bb02-ced4975a745b', 'timestamp': 1729158723213}]]}, 'meta': {'44': {'node_id': '44', 'display_node': '44', 'parent_node': None, 'real_node_id': '44'}, '75': {'node_id': '75', 'display_node': '75', 'parent_node': None, 'real_node_id': '75'}}}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static/.DS_Store
ADDED
|
Binary file (6.15 kB). View file
|
|
|
workflows/cogvideox_image_to_video_workflow_api_old.json
DELETED
|
@@ -1,176 +0,0 @@
|
|
| 1 |
-
{
|
| 2 |
-
"1": {
|
| 3 |
-
"inputs": {
|
| 4 |
-
"model": "THUDM/CogVideoX-5b-I2V",
|
| 5 |
-
"precision": "bf16",
|
| 6 |
-
"fp8_transformer": "disabled",
|
| 7 |
-
"compile": "disabled",
|
| 8 |
-
"enable_sequential_cpu_offload": false
|
| 9 |
-
},
|
| 10 |
-
"class_type": "DownloadAndLoadCogVideoModel",
|
| 11 |
-
"_meta": {
|
| 12 |
-
"title": "(Down)load CogVideo Model"
|
| 13 |
-
}
|
| 14 |
-
},
|
| 15 |
-
"20": {
|
| 16 |
-
"inputs": {
|
| 17 |
-
"clip_name": "t5\\google_t5-v1_1-xxl_encoderonly-fp8_e4m3fn.safetensors",
|
| 18 |
-
"type": "sd3"
|
| 19 |
-
},
|
| 20 |
-
"class_type": "CLIPLoader",
|
| 21 |
-
"_meta": {
|
| 22 |
-
"title": "Load CLIP"
|
| 23 |
-
}
|
| 24 |
-
},
|
| 25 |
-
"30": {
|
| 26 |
-
"inputs": {
|
| 27 |
-
"prompt": "Darth Vader is a vampire and blood is dripping from his steel fangs. The camera is slowly rotating around him. The background is filled with smoke and a strong light.",
|
| 28 |
-
"strength": 1,
|
| 29 |
-
"force_offload": true,
|
| 30 |
-
"clip": [
|
| 31 |
-
"20",
|
| 32 |
-
0
|
| 33 |
-
]
|
| 34 |
-
},
|
| 35 |
-
"class_type": "CogVideoTextEncode",
|
| 36 |
-
"_meta": {
|
| 37 |
-
"title": "CogVideo TextEncode"
|
| 38 |
-
}
|
| 39 |
-
},
|
| 40 |
-
"31": {
|
| 41 |
-
"inputs": {
|
| 42 |
-
"prompt": "The video is not of a high quality, it has a low resolution. Watermark present in each frame. Strange motion trajectory. ",
|
| 43 |
-
"strength": 1,
|
| 44 |
-
"force_offload": true,
|
| 45 |
-
"clip": [
|
| 46 |
-
"20",
|
| 47 |
-
0
|
| 48 |
-
]
|
| 49 |
-
},
|
| 50 |
-
"class_type": "CogVideoTextEncode",
|
| 51 |
-
"_meta": {
|
| 52 |
-
"title": "CogVideo TextEncode"
|
| 53 |
-
}
|
| 54 |
-
},
|
| 55 |
-
"36": {
|
| 56 |
-
"inputs": {
|
| 57 |
-
"image": "https://images.unsplash.com/photo-1506748686214-e9df14d4d9d0",
|
| 58 |
-
"upload": "image"
|
| 59 |
-
},
|
| 60 |
-
"class_type": "LoadImage",
|
| 61 |
-
"_meta": {
|
| 62 |
-
"title": "Load Image"
|
| 63 |
-
}
|
| 64 |
-
},
|
| 65 |
-
"37": {
|
| 66 |
-
"inputs": {
|
| 67 |
-
"width": 720,
|
| 68 |
-
"height": 480,
|
| 69 |
-
"upscale_method": "lanczos",
|
| 70 |
-
"keep_proportion": false,
|
| 71 |
-
"divisible_by": 16,
|
| 72 |
-
"crop": "disabled",
|
| 73 |
-
"image": [
|
| 74 |
-
"36",
|
| 75 |
-
0
|
| 76 |
-
]
|
| 77 |
-
},
|
| 78 |
-
"class_type": "ImageResizeKJ",
|
| 79 |
-
"_meta": {
|
| 80 |
-
"title": "Resize Image"
|
| 81 |
-
}
|
| 82 |
-
},
|
| 83 |
-
"44": {
|
| 84 |
-
"inputs": {
|
| 85 |
-
"frame_rate": 24,
|
| 86 |
-
"loop_count": 0,
|
| 87 |
-
"filename_prefix": "CogVideoX-I2V",
|
| 88 |
-
"format": "video/h264-mp4",
|
| 89 |
-
"pix_fmt": "yuv420p",
|
| 90 |
-
"crf": 19,
|
| 91 |
-
"save_metadata": true,
|
| 92 |
-
"pingpong": false,
|
| 93 |
-
"save_output": true,
|
| 94 |
-
"images": [
|
| 95 |
-
"56",
|
| 96 |
-
0
|
| 97 |
-
]
|
| 98 |
-
},
|
| 99 |
-
"class_type": "VHS_VideoCombine",
|
| 100 |
-
"_meta": {
|
| 101 |
-
"title": "Video Combine 🎥🅥🅗🅢"
|
| 102 |
-
}
|
| 103 |
-
},
|
| 104 |
-
"56": {
|
| 105 |
-
"inputs": {
|
| 106 |
-
"enable_vae_tiling": false,
|
| 107 |
-
"tile_sample_min_height": 96,
|
| 108 |
-
"tile_sample_min_width": 96,
|
| 109 |
-
"tile_overlap_factor_height": 0.083,
|
| 110 |
-
"tile_overlap_factor_width": 0.083,
|
| 111 |
-
"auto_tile_size": true,
|
| 112 |
-
"pipeline": [
|
| 113 |
-
"57",
|
| 114 |
-
0
|
| 115 |
-
],
|
| 116 |
-
"samples": [
|
| 117 |
-
"57",
|
| 118 |
-
1
|
| 119 |
-
]
|
| 120 |
-
},
|
| 121 |
-
"class_type": "CogVideoDecode",
|
| 122 |
-
"_meta": {
|
| 123 |
-
"title": "CogVideo Decode"
|
| 124 |
-
}
|
| 125 |
-
},
|
| 126 |
-
"57": {
|
| 127 |
-
"inputs": {
|
| 128 |
-
"height": 480,
|
| 129 |
-
"width": 720,
|
| 130 |
-
"num_frames": 49,
|
| 131 |
-
"steps": 50,
|
| 132 |
-
"cfg": 6,
|
| 133 |
-
"seed": 65334758276105,
|
| 134 |
-
"scheduler": "DPM++",
|
| 135 |
-
"denoise_strength": 1.0,
|
| 136 |
-
"pipeline": [
|
| 137 |
-
"1",
|
| 138 |
-
0
|
| 139 |
-
],
|
| 140 |
-
"positive": [
|
| 141 |
-
"30",
|
| 142 |
-
0
|
| 143 |
-
],
|
| 144 |
-
"negative": [
|
| 145 |
-
"31",
|
| 146 |
-
0
|
| 147 |
-
],
|
| 148 |
-
"image_cond_latents": [
|
| 149 |
-
"58",
|
| 150 |
-
0
|
| 151 |
-
]
|
| 152 |
-
},
|
| 153 |
-
"class_type": "CogVideoSampler",
|
| 154 |
-
"_meta": {
|
| 155 |
-
"title": "CogVideo Sampler"
|
| 156 |
-
}
|
| 157 |
-
},
|
| 158 |
-
"58": {
|
| 159 |
-
"inputs": {
|
| 160 |
-
"chunk_size": 16,
|
| 161 |
-
"enable_tiling": true,
|
| 162 |
-
"pipeline": [
|
| 163 |
-
"1",
|
| 164 |
-
0
|
| 165 |
-
],
|
| 166 |
-
"image": [
|
| 167 |
-
"37",
|
| 168 |
-
0
|
| 169 |
-
]
|
| 170 |
-
},
|
| 171 |
-
"class_type": "CogVideoImageEncode",
|
| 172 |
-
"_meta": {
|
| 173 |
-
"title": "CogVideo ImageEncode"
|
| 174 |
-
}
|
| 175 |
-
}
|
| 176 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|