# HG changeset patch # User azomics # Date 1592862146 14400 # Node ID 3c0e4179be7a0301addb8c234008f60449c35601 # Parent 426650130311bb8516e2e9a830a3a6b7e059f1c2 "planemo upload for repository https://github.com/ImmPortDB/immport-galaxy-tools/tree/master/flowtools/merge_ds_flowtext commit 7858e5b085fc3c60c88fe87b2f343969d50d9b1e" diff -r 426650130311 -r 3c0e4179be7a FCStxtMergeDownsample.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FCStxtMergeDownsample.py Mon Jun 22 17:42:26 2020 -0400 @@ -0,0 +1,243 @@ +#!/usr/bin/env python + +###################################################################### +# Copyright (c) 2016 Northrop Grumman. +# All rights reserved. +###################################################################### + +from __future__ import print_function +from __future__ import division +import sys +import os +import pandas as pd +from argparse import ArgumentParser + + +def is_number(s): + try: + float(s) + return True + except ValueError: + return False + + +def is_integer(s): + try: + int(s) + return True + except ValueError: + return False + + +def compare_headers(files): + headers = {} + for eachfile in files: + with open(eachfile, "r") as ef: + headers[eachfile] = ef.readline().strip().lower().split("\t") + + hdgs_in_common = [] + flag = {} + + for ref_hdgs in headers[files[0]]: + flag[ref_hdgs] = 1 + + for ij in range(1, len(files)): + if ref_hdgs in headers[files[ij]]: + flag[ref_hdgs] += 1 + if flag[ref_hdgs] == len(files): + hdgs_in_common.append(ref_hdgs) + + if not hdgs_in_common: + sys.exit(9) + return(hdgs_in_common) + + +def get_nb_lines(files): + tot_event = 0 + for f in files: + df = pd.read_table(f) + tot_event += (len(df.index) - 1) + return(tot_event) + + +def get_headers_index(list_headings, headings): + idxs = [] + lhdgs = [x.lower() for x in headings] + for element in list_headings: + idxs.append(int(lhdgs.index(element))) + return(idxs) + + +def merge_and_DS_txt(in_files, out_file, col_names, factor_ds): + """Concatenates together tab-separated files. + The output will have only the columns in common to all the files provided + as input, as determined by the headers. + All lines after the header line must contain only numbers. + Potential errors are logged to stderr. If the number of errors reaches 10, + the program stops. + If a downsampling factor is given, returns the indicated fraction of + random lines. + """ + + nb_errors = 0 + max_error = 10 + + # get list of headers in common to all files + list_hdgs = compare_headers(in_files) + total_events = get_nb_lines(in_files) + total_final = total_events * ds_factor + nb_per_file = int(total_final / len(in_files)) + + with open(out_file, "w") as outf: + ff_order = [] + # HEADERS: + with open(in_files[0], "r") as first_file: + headings_ff = first_file.readline().strip() + headings = headings_ff.split("\t") + # Get index of headers in common: + hdrs_idx = get_headers_index(list_hdgs, headings) + + # If column to merge on were provided: + if col_names: + for ix in col_names: + if ix not in hdrs_idx: + nb_errors += 1 + sys.stderr.write(" ".join(["WARNING: column", str(ix), "in", in_files[0], + "does not exist in all files or has a different header.\n"])) + if nb_errors == max_error: + exit_code = 4 + sys.stderr.write("Run aborted - too many errors.") + os.remove(out_file) + hdrs_idx = col_names + + # Print out to output file: + headings_to_write = [] + for cti in range(0, len(headings)): + if cti in hdrs_idx: + headings_to_write.append(headings[cti]) + ff_order.append(headings[cti]) + outf.write("\t".join(headings_to_write) + "\n") + + # DATA + for infile in in_files: + with open(infile, "r") as inf: + headings_inf = inf.readline().strip() + hdgs = headings_inf.split("\t") + # Get the index of columns to keep: + hdgs_idx = [] + for ctc in ff_order: + hdgs_idx.append(int(hdgs.index(ctc))) + if col_names: + for iy in col_names: + if iy not in hdgs_idx: + nb_errors += 1 + sys.stderr.write(" ".join(["WARNING: column", str(iy), "in", infile, + "does not exist in all files or has a different header.\n"])) + if nb_errors == max_error: + exit_code = 4 + sys.stderr.write("Run aborted - too many errors.") + os.remove(out_file) + hdgs_idx = col_names + + df = pd.read_table(infile, usecols=hdrs_idx) + df_ds = df.sample(nb_per_file, replace=False) + + for cols in df_ds.columns.values: + if df_ds[cols].count() != len(df_ds[cols]): + sys.stderr.write(infile + "contains non-numeric data\n") + + with open(infile, "r") as checkfile: + fl = checkfile.readline() + count_lines = 1 + for checklines in checkfile: + to_check = checklines.strip().split("\t") + count_lines += 1 + for item in to_check: + if not is_number(item): + sys.stderr.write(" ".join(["WARNING: line", str(count_lines), + "in", infile, "contains non-numeric results\n"])) + sys.exit(2) + + df_ds = df_ds.ix[:, ff_order] + df_ds.to_csv(outf, sep="\t", header=False, index=False) + + if nb_errors > 0: + exit_code = 3 + if nb_errors == max_error: + exit_code = 4 + sys.stderr.write("Run aborted - too many errors.") + os.remove(out_file) + sys.exit(exit_code) + return + + +if __name__ == "__main__": + parser = ArgumentParser( + prog="FCStxtmerge", + description="Merge based on headers text-converted FCS files into one text file.") + + parser.add_argument( + '-i', + dest="input_files", + required=True, + action='append', + help="File location for the text files.") + + parser.add_argument( + '-o', + dest="output_file", + required=True, + help="Name of the output file.") + + parser.add_argument( + '-c', + dest="columns", + help="Specify which column to keep in output file") + + parser.add_argument( + '-d', + dest="downsampling_factor", + help="How much of each file to keep") + + args = parser.parse_args() + + # Get columns to merge on if any: + default_value_col = ["i.e.:1,2,5", "default", "Default"] + columns = [] + if args.columns: + if args.columns not in default_value_col: + tmp_col = args.columns.split(",") + if len(tmp_col) == 1: + if not tmp_col[0].strip(): + columns = [] + elif not is_integer(tmp_col[0].strip()): + sys.exit(7) + else: + columns.append(int(tmp_col[0].strip()) - 1) + else: + for c in range(0, len(tmp_col)): + if not is_integer(tmp_col[c].strip()): + sys.exit(6) + else: + columns.append(int(tmp_col[c].strip()) - 1) + + # Get down sampling factor if any: + # Note: change '%' to 'X' because somehow that's what Galaxy passes? + default_value_ds = ["i.e.:0.1 or 10X", "default", "Default"] + ds_factor = 0.1 + if args.downsampling_factor: + if args.downsampling_factor not in default_value_ds: + args.downsampling_factor = args.downsampling_factor.strip() + downsampling_factor = args.downsampling_factor.rstrip("X") + if is_number(downsampling_factor): + ds_factor = float(downsampling_factor) + if ds_factor > 1 and ds_factor <= 100: + ds_factor = float(downsampling_factor) / 100 + elif ds_factor > 100 or ds_factor <= 0: + sys.stderr.write(str(ds_factor)) + sys.exit(8) + else: + sys.exit(8) + + input_files = [f for f in args.input_files] + merge_and_DS_txt(input_files, args.output_file, columns, ds_factor) diff -r 426650130311 -r 3c0e4179be7a FCStxtMergeDownsample.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FCStxtMergeDownsample.xml Mon Jun 22 17:42:26 2020 -0400 @@ -0,0 +1,183 @@ + + txt-converted FCS files into one text file based on headers + + pandas + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10.1038/srep02327 + + diff -r 426650130311 -r 3c0e4179be7a merge_ds_flowtext/FCStxtMergeDownsample.py --- a/merge_ds_flowtext/FCStxtMergeDownsample.py Mon Feb 27 13:03:02 2017 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,225 +0,0 @@ -#!/usr/bin/env python - -###################################################################### -# Copyright (c) 2016 Northrop Grumman. -# All rights reserved. -###################################################################### - -from __future__ import print_function -from __future__ import division -import sys -import os -import pandas as pd -from argparse import ArgumentParser - - -def is_number(s): - try: - float(s) - return True - except ValueError: - return False - - -def is_integer(s): - try: - int(s) - return True - except ValueError: - return False - - -def compare_headers(files): - headers = {} - for eachfile in files: - with open(eachfile, "r") as ef: - headers[eachfile] = ef.readline().strip().lower().split("\t") - - hdgs_in_common = [] - flag = {} - - for ref_hdgs in headers[files[0]]: - flag[ref_hdgs] = 1 - - for ij in range(1, len(files)): - if ref_hdgs in headers[files[ij]]: - flag[ref_hdgs] += 1 - if flag[ref_hdgs] == len(files): - hdgs_in_common.append(ref_hdgs) - - if not hdgs_in_common: - sys.exit(9) - return(hdgs_in_common) - - -def get_headers_index(list_headings, headings): - idxs = [] - lhdgs = [x.lower() for x in headings] - for element in list_headings: - idxs.append(int(lhdgs.index(element))) - return(idxs) - - -def merge_and_DS_txt(in_files, out_file, col_names, factor_ds): - """Concatenates together tab-separated files. - The output will have only the columns in common to all the files provided - as input, as determined by the headers. - All lines after the header line must contain only numbers. - Potential errors are logged to stderr. If the number of errors reaches 10, - the program stops. - If a downsampling factor is given, returns the indicated fraction of - random lines. - """ - - nb_errors = 0 - max_error = 10 - - # get list of headers in common to all files - list_hdgs = compare_headers(in_files) - - with open(out_file, "w") as outf: - ff_order = [] - # HEADERS: - with open(in_files[0], "r") as first_file: - headings_ff = first_file.readline().strip() - headings = headings_ff.split("\t") - # Get index of headers in common: - hdrs_idx = get_headers_index(list_hdgs, headings) - - # If column to merge on were provided: - if col_names: - for ix in col_names: - if ix not in hdrs_idx: - nb_errors += 1 - sys.stderr.write(" ".join(["WARNING: column", str(ix), "in", in_files[0], - "does not exist in all files or has a different header.\n"])) - hdrs_idx = col_names - - # Print out to output file: - headings_to_write = [] - for cti in range(0, len(headings)): - if cti in hdrs_idx: - headings_to_write.append(headings[cti]) - ff_order.append(headings[cti]) - outf.write("\t".join(headings_to_write) + "\n") - - # DATA - for infile in in_files: - with open(infile, "r") as inf: - headings_inf = inf.readline().strip() - hdgs = headings_inf.split("\t") - # Get the index of columns to keep: - hdgs_idx = [] - for ctc in ff_order: - hdgs_idx.append(int(hdgs.index(ctc))) - if col_names: - for iy in col_names: - if iy not in hdgs_idx: - nb_errors += 1 - sys.stderr.write(" ".join(["WARNING: column", str(iy), "in", infile, - "does not exist in all files or has a different header.\n"])) - hdgs_idx = col_names - - df = pd.read_table(infile, usecols=hdrs_idx) - wc_file = len(df.index) - 1 - df_ds = df.sample(int(wc_file * factor_ds), replace=False) - - for cols in df_ds.columns.values: - if df_ds[cols].count() != len(df_ds[cols]): - sys.stderr.write(infile + "contains non-numeric data\n") - - with open(infile, "r") as checkfile: - fl = checkfile.readline() - count_lines = 1 - for checklines in checkfile: - to_check = checklines.strip().split("\t") - count_lines += 1 - for item in to_check: - if not is_number(item): - sys.stderr.write(" ".join(["WARNING: line", str(count_lines), - "in", infile, "contains non-numeric results\n"])) - sys.exit(2) - - df_ds = df_ds.ix[:, ff_order] - df_ds.to_csv(outf, sep="\t", header=False, index=False) - - if nb_errors > 0: - exit_code = 3 - if nb_errors == max_error: - exit_code = 4 - sys.stderr.write("Run aborted - too many errors.") - os.remove(out_file) - sys.exit(exit_code) - return - - -if __name__ == "__main__": - parser = ArgumentParser( - prog="FCStxtmerge", - description="Merge based on headers text-converted FCS files into one text file.") - - parser.add_argument( - '-i', - dest="input_files", - required=True, - action='append', - help="File location for the text files.") - - parser.add_argument( - '-o', - dest="output_file", - required=True, - help="Name of the output file.") - - parser.add_argument( - '-c', - dest="columns", - help="Specify which column to keep in output file") - - parser.add_argument( - '-d', - dest="downsampling_factor", - help="How much of each file to keep") - - args = parser.parse_args() - - # Get columns to merge on if any: - default_value_col = ["i.e.:1,2,5", "default", "Default"] - columns = [] - if args.columns: - if args.columns not in default_value_col: - tmp_col = args.columns.split(",") - if len(tmp_col) == 1: - if not tmp_col[0].strip(): - columns = [] - elif not is_integer(tmp_col[0].strip()): - sys.exit(7) - else: - columns.append(int(tmp_col[0].strip()) - 1) - else: - for c in range(0, len(tmp_col)): - if not is_integer(tmp_col[c].strip()): - sys.exit(6) - else: - columns.append(int(tmp_col[c].strip()) - 1) - - # Get down sampling factor if any: - # Note: change '%' to 'X' because somehow that's what Galaxy passes? - default_value_ds = ["i.e.:0.1 or 10X", "default", "Default"] - ds_factor = 1 - if args.downsampling_factor: - if args.downsampling_factor not in default_value_ds: - args.downsampling_factor = args.downsampling_factor.strip() - downsampling_factor = args.downsampling_factor.rstrip("X") - if is_number(downsampling_factor): - ds_factor = float(downsampling_factor) - if ds_factor > 1: - ds_factor = float(downsampling_factor) / 100 - if ds_factor > 100: - sys.exit(8) - else: - sys.exit(8) - - input_files = [f for f in args.input_files] - merge_and_DS_txt(input_files, args.output_file, columns, ds_factor) - sys.exit(0) diff -r 426650130311 -r 3c0e4179be7a merge_ds_flowtext/FCStxtMergeDownsample.xml --- a/merge_ds_flowtext/FCStxtMergeDownsample.xml Mon Feb 27 13:03:02 2017 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,175 +0,0 @@ - - txt-converted FCS files into one text file based on headers. - - numpy - pandas - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 10.1038/srep02327 - - diff -r 426650130311 -r 3c0e4179be7a merge_ds_flowtext/test-data/merge1.flowtext --- a/merge_ds_flowtext/test-data/merge1.flowtext Mon Feb 27 13:03:02 2017 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,19 +0,0 @@ -CD4 CCR3 CD8 CCR7 -437 69 0 146 -551 129 169 292 -199 277 320 227 -83 138 335 194 -534 111 83 177 -499 0 0 224 -175 361 225 237 -216 310 270 294 -519 44 51 148 -550 200 0 127 -552 479 0 62 -525 121 0 138 -438 0 626 480 -139 227 293 259 -0 292 641 327 -30 147 483 386 -537 338 568 201 -156 228 734 408 diff -r 426650130311 -r 3c0e4179be7a merge_ds_flowtext/test-data/merge2.flowtext --- a/merge_ds_flowtext/test-data/merge2.flowtext Mon Feb 27 13:03:02 2017 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -Forward Scatter Side Scatter FITC CD4 -340 115 509 -262 73 437 -894 1023 199 -316 76 50 -449 157 551 -388 97 534 -383 139 499 -394 144 83 -372 126 519 -788 1023 216 -1023 1023 289 -363 76 550 -668 1019 73 -420 211 552 -770 1023 175 -602 578 385 -418 105 561 -352 153 30 -383 190 156 -733 970 139 -451 120 537 -373 104 3 -358 185 0 -289 56 438 diff -r 426650130311 -r 3c0e4179be7a merge_ds_flowtext/test-data/test1/input1.txt --- a/merge_ds_flowtext/test-data/test1/input1.txt Mon Feb 27 13:03:02 2017 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -CD4 CCR3 CD8 CCR7 -551 129 169 292 -199 277 320 227 -437 69 0 146 -509 268 0 74 -50 0 60 129 -83 138 335 194 -499 0 0 224 -239 284 288 280 -534 111 83 177 diff -r 426650130311 -r 3c0e4179be7a merge_ds_flowtext/test-data/test1/input2.txt --- a/merge_ds_flowtext/test-data/test1/input2.txt Mon Feb 27 13:03:02 2017 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -CD4 CCR3 CD8 CCR7 -550 200 0 127 -519 44 51 148 -289 401 362 254 -175 361 225 237 -525 121 0 138 -385 286 222 131 -216 310 270 294 -552 479 0 62 -73 193 227 132 diff -r 426650130311 -r 3c0e4179be7a merge_ds_flowtext/test-data/test1/input3.txt --- a/merge_ds_flowtext/test-data/test1/input3.txt Mon Feb 27 13:03:02 2017 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -CD4 CCR3 CD8 CCR7 -438 0 626 480 -30 147 483 386 -156 228 734 408 -432 121 598 555 -537 338 568 201 -3 110 621 584 -561 0 610 562 -0 292 641 327 -139 227 293 259 diff -r 426650130311 -r 3c0e4179be7a merge_ds_flowtext/test-data/test2/input1.txt --- a/merge_ds_flowtext/test-data/test2/input1.txt Mon Feb 27 13:03:02 2017 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -Forward Scatter Side Scatter FITC CD4 PE CCR3 PP CD8 APC CCR4 -449 157 551 129 169 292 -894 1023 199 277 320 227 -262 73 437 69 0 146 -340 115 509 268 0 74 -316 76 50 0 60 129 -394 144 83 138 335 194 -383 139 499 0 0 224 -800 1023 239 284 288 280 -388 97 534 111 83 177 diff -r 426650130311 -r 3c0e4179be7a merge_ds_flowtext/test-data/test2/input2.txt --- a/merge_ds_flowtext/test-data/test2/input2.txt Mon Feb 27 13:03:02 2017 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -Forward Scatter Side Scatter FITC CD4 PE CXCR3 PP CD8 APC CCR5 -363 76 550 200 0 127 -372 126 519 44 51 148 -1023 1023 289 401 362 254 -770 1023 175 361 225 237 -384 111 525 121 0 138 -602 578 385 286 222 131 -788 1023 216 310 270 294 -420 211 552 479 0 62 -668 1019 73 193 227 132 diff -r 426650130311 -r 3c0e4179be7a merge_ds_flowtext/test-data/test2/input3.txt --- a/merge_ds_flowtext/test-data/test2/input3.txt Mon Feb 27 13:03:02 2017 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -Forward Scatter Side Scatter FITC CD4 PE CD25 PP CD3 APC CD45RA -289 56 438 0 626 480 -352 153 30 147 483 386 -383 190 156 228 734 408 -261 62 432 121 598 555 -451 120 537 338 568 201 -373 104 3 110 621 584 -418 105 561 0 610 562 -358 185 0 292 641 327 -733 970 139 227 293 259 diff -r 426650130311 -r 3c0e4179be7a test-data/merge1.flowtext --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-data/merge1.flowtext Mon Jun 22 17:42:26 2020 -0400 @@ -0,0 +1,19 @@ +CD4 CCR3 CD8 CCR7 +432 121 598 555 +537 338 568 201 +438 0 626 480 +30 147 483 386 +561 0 610 562 +139 227 293 259 +385 286 222 131 +175 361 225 237 +525 121 0 138 +216 310 270 294 +289 401 362 254 +550 200 0 127 +83 138 335 194 +534 111 83 177 +437 69 0 146 +199 277 320 227 +509 268 0 74 +50 0 60 129 diff -r 426650130311 -r 3c0e4179be7a test-data/merge2.flowtext --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-data/merge2.flowtext Mon Jun 22 17:42:26 2020 -0400 @@ -0,0 +1,1 @@ +Forward Scatter Side Scatter FITC CD4 diff -r 426650130311 -r 3c0e4179be7a test-data/test1/input1.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-data/test1/input1.txt Mon Jun 22 17:42:26 2020 -0400 @@ -0,0 +1,10 @@ +CD4 CCR3 CD8 CCR7 +551 129 169 292 +199 277 320 227 +437 69 0 146 +509 268 0 74 +50 0 60 129 +83 138 335 194 +499 0 0 224 +239 284 288 280 +534 111 83 177 diff -r 426650130311 -r 3c0e4179be7a test-data/test1/input2.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-data/test1/input2.txt Mon Jun 22 17:42:26 2020 -0400 @@ -0,0 +1,10 @@ +CD4 CCR3 CD8 CCR7 +550 200 0 127 +519 44 51 148 +289 401 362 254 +175 361 225 237 +525 121 0 138 +385 286 222 131 +216 310 270 294 +552 479 0 62 +73 193 227 132 diff -r 426650130311 -r 3c0e4179be7a test-data/test1/input3.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-data/test1/input3.txt Mon Jun 22 17:42:26 2020 -0400 @@ -0,0 +1,10 @@ +CD4 CCR3 CD8 CCR7 +438 0 626 480 +30 147 483 386 +156 228 734 408 +432 121 598 555 +537 338 568 201 +3 110 621 584 +561 0 610 562 +0 292 641 327 +139 227 293 259 diff -r 426650130311 -r 3c0e4179be7a test-data/test2/input1.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-data/test2/input1.txt Mon Jun 22 17:42:26 2020 -0400 @@ -0,0 +1,10 @@ +Forward Scatter Side Scatter FITC CD4 PE CCR3 PP CD8 APC CCR4 +449 157 551 129 169 292 +894 1023 199 277 320 227 +262 73 437 69 0 146 +340 115 509 268 0 74 +316 76 50 0 60 129 +394 144 83 138 335 194 +383 139 499 0 0 224 +800 1023 239 284 288 280 +388 97 534 111 83 177 diff -r 426650130311 -r 3c0e4179be7a test-data/test2/input2.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-data/test2/input2.txt Mon Jun 22 17:42:26 2020 -0400 @@ -0,0 +1,10 @@ +Forward Scatter Side Scatter FITC CD4 PE CXCR3 PP CD8 APC CCR5 +363 76 550 200 0 127 +372 126 519 44 51 148 +1023 1023 289 401 362 254 +770 1023 175 361 225 237 +384 111 525 121 0 138 +602 578 385 286 222 131 +788 1023 216 310 270 294 +420 211 552 479 0 62 +668 1019 73 193 227 132 diff -r 426650130311 -r 3c0e4179be7a test-data/test2/input3.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-data/test2/input3.txt Mon Jun 22 17:42:26 2020 -0400 @@ -0,0 +1,10 @@ +Forward Scatter Side Scatter FITC CD4 PE CD25 PP CD3 APC CD45RA +289 56 438 0 626 480 +352 153 30 147 483 386 +383 190 156 228 734 408 +261 62 432 121 598 555 +451 120 537 338 568 201 +373 104 3 110 621 584 +418 105 561 0 610 562 +358 185 0 292 641 327 +733 970 139 227 293 259