Spaces:
Running
Running
Delete prepare_datasets
Browse files
prepare_datasets/0-pipeline.py
DELETED
@@ -1,81 +0,0 @@
|
|
1 |
-
import os, torch, sys
|
2 |
-
from subprocess import Popen
|
3 |
-
|
4 |
-
now_dir = os.getcwd()
|
5 |
-
sys.path.append(now_dir)
|
6 |
-
from config import (
|
7 |
-
text_path,
|
8 |
-
wav_dir,
|
9 |
-
n_card,
|
10 |
-
exp_name,
|
11 |
-
n_parts,
|
12 |
-
exp_dir,
|
13 |
-
)
|
14 |
-
|
15 |
-
os.makedirs("%s/logs_s1" % exp_dir, exist_ok=True)
|
16 |
-
os.makedirs("%s/logs_s2" % exp_dir, exist_ok=True)
|
17 |
-
##############step1
|
18 |
-
ps = []
|
19 |
-
for i_part in range(n_parts):
|
20 |
-
cmd = "python prepare/1-get-text.py %s %s %s %s %s %s" % (
|
21 |
-
text_path,
|
22 |
-
wav_dir,
|
23 |
-
exp_name,
|
24 |
-
i_part,
|
25 |
-
n_parts,
|
26 |
-
i_part % n_card,
|
27 |
-
)
|
28 |
-
print(cmd)
|
29 |
-
p = Popen(cmd, shell=True)
|
30 |
-
ps.append(p)
|
31 |
-
for p in ps:
|
32 |
-
p.wait()
|
33 |
-
|
34 |
-
opt = []
|
35 |
-
for i_part in range(n_parts):
|
36 |
-
txt_path = "%s/2-name2text-%s.txt" % (exp_dir, i_part)
|
37 |
-
with open(txt_path, "r") as f:
|
38 |
-
opt += f.read().strip("\n").split("\n")
|
39 |
-
os.remove(txt_path)
|
40 |
-
with open("%s/2-name2text.txt" % exp_dir, "w") as f:
|
41 |
-
f.write("\n".join(opt) + "\n")
|
42 |
-
|
43 |
-
############step2
|
44 |
-
ps = []
|
45 |
-
for i_part in range(n_parts):
|
46 |
-
cmd = "python prepare/2-get-hubert-wav32k.py %s %s %s %s %s %s" % (
|
47 |
-
text_path,
|
48 |
-
wav_dir,
|
49 |
-
exp_name,
|
50 |
-
i_part,
|
51 |
-
n_parts,
|
52 |
-
i_part % n_card,
|
53 |
-
)
|
54 |
-
print(cmd)
|
55 |
-
p = Popen(cmd, shell=True)
|
56 |
-
ps.append(p)
|
57 |
-
for p in ps:
|
58 |
-
p.wait()
|
59 |
-
#############step3
|
60 |
-
ps = []
|
61 |
-
for i_part in range(n_parts):
|
62 |
-
cmd = "python prepare/3-get-semantic.py %s %s %s %s %s" % (
|
63 |
-
text_path,
|
64 |
-
exp_name,
|
65 |
-
i_part,
|
66 |
-
n_parts,
|
67 |
-
i_part % n_card,
|
68 |
-
)
|
69 |
-
print(cmd)
|
70 |
-
p = Popen(cmd, shell=True)
|
71 |
-
ps.append(p)
|
72 |
-
for p in ps:
|
73 |
-
p.wait()
|
74 |
-
opt = ["item_name semantic_audio"]
|
75 |
-
for i_part in range(n_parts):
|
76 |
-
semantic_path = "%s/6-name2semantic-%s.tsv" % (exp_dir, i_part)
|
77 |
-
with open(semantic_path, "r") as f:
|
78 |
-
opt += f.read().strip("\n").split("\n")
|
79 |
-
os.remove(semantic_path)
|
80 |
-
with open("%s/6-name2semantic.tsv" % exp_dir, "w") as f:
|
81 |
-
f.write("\n".join(opt) + "\n")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
prepare_datasets/1-get-text.py
DELETED
@@ -1,125 +0,0 @@
|
|
1 |
-
# -*- coding: utf-8 -*-
|
2 |
-
|
3 |
-
import os
|
4 |
-
|
5 |
-
inp_text = os.environ.get("inp_text")
|
6 |
-
inp_wav_dir = os.environ.get("inp_wav_dir")
|
7 |
-
exp_name = os.environ.get("exp_name")
|
8 |
-
i_part = os.environ.get("i_part")
|
9 |
-
all_parts = os.environ.get("all_parts")
|
10 |
-
os.environ["CUDA_VISIBLE_DEVICES"] = os.environ.get("_CUDA_VISIBLE_DEVICES")
|
11 |
-
opt_dir = os.environ.get("opt_dir")
|
12 |
-
bert_pretrained_dir = os.environ.get("bert_pretrained_dir")
|
13 |
-
is_half = eval(os.environ.get("is_half", "True"))
|
14 |
-
import sys, numpy as np, traceback, pdb
|
15 |
-
import os.path
|
16 |
-
from glob import glob
|
17 |
-
from tqdm import tqdm
|
18 |
-
from text.cleaner import clean_text
|
19 |
-
import torch
|
20 |
-
from transformers import AutoModelForMaskedLM, AutoTokenizer
|
21 |
-
import numpy as np
|
22 |
-
|
23 |
-
# inp_text=sys.argv[1]
|
24 |
-
# inp_wav_dir=sys.argv[2]
|
25 |
-
# exp_name=sys.argv[3]
|
26 |
-
# i_part=sys.argv[4]
|
27 |
-
# all_parts=sys.argv[5]
|
28 |
-
# os.environ["CUDA_VISIBLE_DEVICES"]=sys.argv[6]#i_gpu
|
29 |
-
# opt_dir="/data/docker/liujing04/gpt-vits/fine_tune_dataset/%s"%exp_name
|
30 |
-
# bert_pretrained_dir="/data/docker/liujing04/bert-vits2/Bert-VITS2-master20231106/bert/chinese-roberta-wwm-ext-large"
|
31 |
-
|
32 |
-
from time import time as ttime
|
33 |
-
import shutil
|
34 |
-
|
35 |
-
|
36 |
-
def my_save(fea, path): #####fix issue: torch.save doesn't support chinese path
|
37 |
-
dir = os.path.dirname(path)
|
38 |
-
name = os.path.basename(path)
|
39 |
-
tmp_path = "%s/%s%s.pth" % (dir, ttime(), i_part)
|
40 |
-
torch.save(fea, tmp_path)
|
41 |
-
shutil.move(tmp_path, "%s/%s" % (dir, name))
|
42 |
-
|
43 |
-
|
44 |
-
txt_path = "%s/2-name2text-%s.txt" % (opt_dir, i_part)
|
45 |
-
if os.path.exists(txt_path) == False:
|
46 |
-
bert_dir = "%s/3-bert" % (opt_dir)
|
47 |
-
os.makedirs(opt_dir, exist_ok=True)
|
48 |
-
os.makedirs(bert_dir, exist_ok=True)
|
49 |
-
device = "cuda:0"
|
50 |
-
tokenizer = AutoTokenizer.from_pretrained(bert_pretrained_dir)
|
51 |
-
bert_model = AutoModelForMaskedLM.from_pretrained(bert_pretrained_dir)
|
52 |
-
if is_half == True:
|
53 |
-
bert_model = bert_model.half().to(device)
|
54 |
-
else:
|
55 |
-
bert_model = bert_model.to(device)
|
56 |
-
|
57 |
-
def get_bert_feature(text, word2ph):
|
58 |
-
with torch.no_grad():
|
59 |
-
inputs = tokenizer(text, return_tensors="pt")
|
60 |
-
for i in inputs:
|
61 |
-
inputs[i] = inputs[i].to(device)
|
62 |
-
res = bert_model(**inputs, output_hidden_states=True)
|
63 |
-
res = torch.cat(res["hidden_states"][-3:-2], -1)[0].cpu()[1:-1]
|
64 |
-
|
65 |
-
assert len(word2ph) == len(text)
|
66 |
-
phone_level_feature = []
|
67 |
-
for i in range(len(word2ph)):
|
68 |
-
repeat_feature = res[i].repeat(word2ph[i], 1)
|
69 |
-
phone_level_feature.append(repeat_feature)
|
70 |
-
|
71 |
-
phone_level_feature = torch.cat(phone_level_feature, dim=0)
|
72 |
-
|
73 |
-
return phone_level_feature.T
|
74 |
-
|
75 |
-
def process(data, res):
|
76 |
-
for name, text, lan in data:
|
77 |
-
try:
|
78 |
-
name = os.path.basename(name)
|
79 |
-
phones, word2ph, norm_text = clean_text(
|
80 |
-
text.replace("%", "-").replace("¥", ","), lan
|
81 |
-
)
|
82 |
-
path_bert = "%s/%s.pt" % (bert_dir, name)
|
83 |
-
if os.path.exists(path_bert) == False and lan == "zh":
|
84 |
-
bert_feature = get_bert_feature(norm_text, word2ph)
|
85 |
-
assert bert_feature.shape[-1] == len(phones)
|
86 |
-
# torch.save(bert_feature, path_bert)
|
87 |
-
my_save(bert_feature, path_bert)
|
88 |
-
phones = " ".join(phones)
|
89 |
-
# res.append([name,phones])
|
90 |
-
res.append([name, phones, word2ph, norm_text])
|
91 |
-
except:
|
92 |
-
print(name, text, traceback.format_exc())
|
93 |
-
|
94 |
-
todo = []
|
95 |
-
res = []
|
96 |
-
with open(inp_text, "r", encoding="utf8") as f:
|
97 |
-
lines = f.read().strip("\n").split("\n")
|
98 |
-
|
99 |
-
language_v1_to_language_v2 = {
|
100 |
-
"ZH": "zh",
|
101 |
-
"zh": "zh",
|
102 |
-
"JP": "ja",
|
103 |
-
"jp": "ja",
|
104 |
-
"JA": "ja",
|
105 |
-
"ja": "ja",
|
106 |
-
"EN": "en",
|
107 |
-
"en": "en",
|
108 |
-
"En": "en",
|
109 |
-
}
|
110 |
-
for line in lines[int(i_part) :: int(all_parts)]:
|
111 |
-
try:
|
112 |
-
wav_name, spk_name, language, text = line.split("|")
|
113 |
-
# todo.append([name,text,"zh"])
|
114 |
-
todo.append(
|
115 |
-
[wav_name, text, language_v1_to_language_v2.get(language, language)]
|
116 |
-
)
|
117 |
-
except:
|
118 |
-
print(line, traceback.format_exc())
|
119 |
-
|
120 |
-
process(todo, res)
|
121 |
-
opt = []
|
122 |
-
for name, phones, word2ph, norm_text in res:
|
123 |
-
opt.append("%s\t%s\t%s\t%s" % (name, phones, word2ph, norm_text))
|
124 |
-
with open(txt_path, "w", encoding="utf8") as f:
|
125 |
-
f.write("\n".join(opt) + "\n")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
prepare_datasets/2-get-hubert-wav32k.py
DELETED
@@ -1,94 +0,0 @@
|
|
1 |
-
# -*- coding: utf-8 -*-
|
2 |
-
|
3 |
-
import sys,os
|
4 |
-
inp_text= os.environ.get("inp_text")
|
5 |
-
inp_wav_dir= os.environ.get("inp_wav_dir")
|
6 |
-
exp_name= os.environ.get("exp_name")
|
7 |
-
i_part= os.environ.get("i_part")
|
8 |
-
all_parts= os.environ.get("all_parts")
|
9 |
-
os.environ["CUDA_VISIBLE_DEVICES"]= os.environ.get("_CUDA_VISIBLE_DEVICES")
|
10 |
-
from feature_extractor import cnhubert
|
11 |
-
opt_dir= os.environ.get("opt_dir")
|
12 |
-
cnhubert.cnhubert_base_path= os.environ.get("cnhubert_base_dir")
|
13 |
-
is_half=eval(os.environ.get("is_half","True"))
|
14 |
-
|
15 |
-
import pdb,traceback,numpy as np,logging
|
16 |
-
from scipy.io import wavfile
|
17 |
-
import librosa,torch
|
18 |
-
now_dir = os.getcwd()
|
19 |
-
sys.path.append(now_dir)
|
20 |
-
from my_utils import load_audio
|
21 |
-
|
22 |
-
# from config import cnhubert_base_path
|
23 |
-
# cnhubert.cnhubert_base_path=cnhubert_base_path
|
24 |
-
# inp_text=sys.argv[1]
|
25 |
-
# inp_wav_dir=sys.argv[2]
|
26 |
-
# exp_name=sys.argv[3]
|
27 |
-
# i_part=sys.argv[4]
|
28 |
-
# all_parts=sys.argv[5]
|
29 |
-
# os.environ["CUDA_VISIBLE_DEVICES"]=sys.argv[6]
|
30 |
-
# cnhubert.cnhubert_base_path=sys.argv[7]
|
31 |
-
# opt_dir="/data/docker/liujing04/gpt-vits/fine_tune_dataset/%s"%exp_name
|
32 |
-
|
33 |
-
from time import time as ttime
|
34 |
-
import shutil
|
35 |
-
def my_save(fea,path):#####fix issue: torch.save doesn't support chinese path
|
36 |
-
dir=os.path.dirname(path)
|
37 |
-
name=os.path.basename(path)
|
38 |
-
tmp_path="%s/%s%s.pth"%(dir,ttime(),i_part)
|
39 |
-
torch.save(fea,tmp_path)
|
40 |
-
shutil.move(tmp_path,"%s/%s"%(dir,name))
|
41 |
-
|
42 |
-
hubert_dir="%s/4-cnhubert"%(opt_dir)
|
43 |
-
wav32dir="%s/5-wav32k"%(opt_dir)
|
44 |
-
os.makedirs(opt_dir,exist_ok=True)
|
45 |
-
os.makedirs(hubert_dir,exist_ok=True)
|
46 |
-
os.makedirs(wav32dir,exist_ok=True)
|
47 |
-
|
48 |
-
maxx=0.95
|
49 |
-
alpha=0.5
|
50 |
-
device="cuda:0"
|
51 |
-
model=cnhubert.get_model()
|
52 |
-
if(is_half==True):
|
53 |
-
model=model.half().to(device)
|
54 |
-
else:
|
55 |
-
model = model.to(device)
|
56 |
-
def name2go(wav_name):
|
57 |
-
hubert_path="%s/%s.pt"%(hubert_dir,wav_name)
|
58 |
-
if(os.path.exists(hubert_path)):return
|
59 |
-
wav_path="%s/%s"%(inp_wav_dir,wav_name)
|
60 |
-
tmp_audio = load_audio(wav_path, 32000)
|
61 |
-
tmp_max = np.abs(tmp_audio).max()
|
62 |
-
if tmp_max > 2.2:
|
63 |
-
print("%s-%s-%s-filtered" % (idx0, idx1, tmp_max))
|
64 |
-
return
|
65 |
-
tmp_audio32 = (tmp_audio / tmp_max * (maxx * alpha*32768)) + ((1 - alpha)*32768) * tmp_audio
|
66 |
-
tmp_audio = librosa.resample(
|
67 |
-
tmp_audio32, orig_sr=32000, target_sr=16000
|
68 |
-
)
|
69 |
-
tensor_wav16 = torch.from_numpy(tmp_audio)
|
70 |
-
if (is_half == True):
|
71 |
-
tensor_wav16=tensor_wav16.half().to(device)
|
72 |
-
else:
|
73 |
-
tensor_wav16 = tensor_wav16.to(device)
|
74 |
-
ssl=model.model(tensor_wav16.unsqueeze(0))["last_hidden_state"].transpose(1,2).cpu()#torch.Size([1, 768, 215])
|
75 |
-
if np.isnan(ssl.detach().numpy()).sum()!= 0:return
|
76 |
-
wavfile.write(
|
77 |
-
"%s/%s"%(wav32dir,wav_name),
|
78 |
-
32000,
|
79 |
-
tmp_audio32.astype("int16"),
|
80 |
-
)
|
81 |
-
# torch.save(ssl,hubert_path )
|
82 |
-
my_save(ssl,hubert_path )
|
83 |
-
|
84 |
-
with open(inp_text,"r",encoding="utf8")as f:
|
85 |
-
lines=f.read().strip("\n").split("\n")
|
86 |
-
|
87 |
-
for line in lines[int(i_part)::int(all_parts)]:
|
88 |
-
try:
|
89 |
-
# wav_name,text=line.split("\t")
|
90 |
-
wav_name, spk_name, language, text = line.split("|")
|
91 |
-
wav_name=os.path.basename(wav_name)
|
92 |
-
name2go(wav_name)
|
93 |
-
except:
|
94 |
-
print(line,traceback.format_exc())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
prepare_datasets/3-get-semantic.py
DELETED
@@ -1,90 +0,0 @@
|
|
1 |
-
import os
|
2 |
-
|
3 |
-
inp_text = os.environ.get("inp_text")
|
4 |
-
exp_name = os.environ.get("exp_name")
|
5 |
-
i_part = os.environ.get("i_part")
|
6 |
-
all_parts = os.environ.get("all_parts")
|
7 |
-
os.environ["CUDA_VISIBLE_DEVICES"] = os.environ.get("_CUDA_VISIBLE_DEVICES")
|
8 |
-
opt_dir = os.environ.get("opt_dir")
|
9 |
-
pretrained_s2G = os.environ.get("pretrained_s2G")
|
10 |
-
s2config_path = os.environ.get("s2config_path")
|
11 |
-
is_half = eval(os.environ.get("is_half", "True"))
|
12 |
-
import math, traceback
|
13 |
-
import multiprocessing
|
14 |
-
import sys, pdb
|
15 |
-
|
16 |
-
now_dir = os.getcwd()
|
17 |
-
sys.path.append(now_dir)
|
18 |
-
from random import shuffle
|
19 |
-
import torch.multiprocessing as mp
|
20 |
-
from glob import glob
|
21 |
-
from tqdm import tqdm
|
22 |
-
import logging, librosa, utils, torch
|
23 |
-
from module.models import SynthesizerTrn
|
24 |
-
|
25 |
-
logging.getLogger("numba").setLevel(logging.WARNING)
|
26 |
-
# from config import pretrained_s2G
|
27 |
-
|
28 |
-
# inp_text=sys.argv[1]
|
29 |
-
# exp_name=sys.argv[2]
|
30 |
-
# i_part=sys.argv[3]
|
31 |
-
# all_parts=sys.argv[4]
|
32 |
-
# os.environ["CUDA_VISIBLE_DEVICES"]=sys.argv[5]
|
33 |
-
# opt_dir="/data/docker/liujing04/gpt-vits/fine_tune_dataset/%s"%exp_name
|
34 |
-
|
35 |
-
|
36 |
-
hubert_dir = "%s/4-cnhubert" % (opt_dir)
|
37 |
-
semantic_path = "%s/6-name2semantic-%s.tsv" % (opt_dir, i_part)
|
38 |
-
if os.path.exists(semantic_path) == False:
|
39 |
-
os.makedirs(opt_dir, exist_ok=True)
|
40 |
-
|
41 |
-
device = "cuda:0"
|
42 |
-
hps = utils.get_hparams_from_file(s2config_path)
|
43 |
-
vq_model = SynthesizerTrn(
|
44 |
-
hps.data.filter_length // 2 + 1,
|
45 |
-
hps.train.segment_size // hps.data.hop_length,
|
46 |
-
n_speakers=hps.data.n_speakers,
|
47 |
-
**hps.model
|
48 |
-
)
|
49 |
-
if is_half == True:
|
50 |
-
vq_model = vq_model.half().to(device)
|
51 |
-
else:
|
52 |
-
vq_model = vq_model.to(device)
|
53 |
-
vq_model.eval()
|
54 |
-
# utils.load_checkpoint(utils.latest_checkpoint_path(hps.s2_ckpt_dir, "G_*.pth"), vq_model, None, True)
|
55 |
-
# utils.load_checkpoint(pretrained_s2G, vq_model, None, True)
|
56 |
-
print(
|
57 |
-
vq_model.load_state_dict(
|
58 |
-
torch.load(pretrained_s2G, map_location="cpu")["weight"], strict=False
|
59 |
-
)
|
60 |
-
)
|
61 |
-
|
62 |
-
def name2go(wav_name, lines):
|
63 |
-
hubert_path = "%s/%s.pt" % (hubert_dir, wav_name)
|
64 |
-
if os.path.exists(hubert_path) == False:
|
65 |
-
return
|
66 |
-
ssl_content = torch.load(hubert_path, map_location="cpu")
|
67 |
-
if is_half == True:
|
68 |
-
ssl_content = ssl_content.half().to(device)
|
69 |
-
else:
|
70 |
-
ssl_content = ssl_content.to(device)
|
71 |
-
codes = vq_model.extract_latent(ssl_content)
|
72 |
-
semantic = " ".join([str(i) for i in codes[0, 0, :].tolist()])
|
73 |
-
lines.append("%s\t%s" % (wav_name, semantic))
|
74 |
-
|
75 |
-
with open(inp_text, "r", encoding="utf8") as f:
|
76 |
-
lines = f.read().strip("\n").split("\n")
|
77 |
-
|
78 |
-
lines1 = []
|
79 |
-
for line in lines[int(i_part) :: int(all_parts)]:
|
80 |
-
# print(line)
|
81 |
-
try:
|
82 |
-
# wav_name,text=line.split("\t")
|
83 |
-
wav_name, spk_name, language, text = line.split("|")
|
84 |
-
wav_name = os.path.basename(wav_name)
|
85 |
-
# name2go(name,lines1)
|
86 |
-
name2go(wav_name, lines1)
|
87 |
-
except:
|
88 |
-
print(line, traceback.format_exc())
|
89 |
-
with open(semantic_path, "w", encoding="utf8") as f:
|
90 |
-
f.write("\n".join(lines1))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|