annotate rDiff/mex/interval_overlap.cpp @ 2:233c30f91d66

updated python based GFF parsing module which will handle GTF/GFF/GFF3 file types
author vipints <vipin@cbio.mskcc.org>
date Tue, 08 Oct 2013 07:15:44 -0400
parents 0f80a5141704
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
1 /*
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
2 * This program is free software; you can redistribute it and/or modify
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
3 * it under the terms of the GNU General Public License as published by
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
4 * the Free Software Foundation; either version 3 of the License, or
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
5 * (at your option) any later version.
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
6 *
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
7 * Written (W) 2010-2011 Jonas Behr
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
8 * Copyright (C) 2010-2011 Max Planck Society
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
9 */
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
10
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
11
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
12 #include <stdio.h>
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
13 #include <stdarg.h>
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
14 #include <errno.h>
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
15 #include <sys/types.h>
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
16 #include <sys/stat.h>
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
17 #include <fcntl.h>
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
18 #include <ctype.h>
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
19 #include <sys/stat.h>
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
20 #include <stdlib.h>
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
21 #include <unistd.h>
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
22 #include <string.h>
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
23 #include <sys/mman.h>
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
24 #include <time.h>
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
25 #include <math.h>
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
26 #include <limits>
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
27 #include <mex.h>
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
28 #include <assert.h>
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
29 #include <vector>
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
30 using std::vector;
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
31 #include <algorithm>
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
32 using std::sort;
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
33 using std::min;
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
34 using std::max;
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
35
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
36 typedef struct {
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
37 int start;
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
38 int stop;
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
39 int idx;
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
40 int set_id;
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
41 } interval_t;
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
42
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
43 bool compare (interval_t i, interval_t j)
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
44 {
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
45 return (i.start<j.start);
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
46 }
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
47
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
48 bool overlaps(interval_t a, interval_t b)
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
49 {
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
50 int v = min(a.stop,b.stop) - max(a.start,b.start) + 1;
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
51 return (v >= 1);
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
52 }
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
53 bool leftOf(interval_t a, interval_t b)
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
54 {
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
55 return (a.stop < b.start);
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
56 }
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
57
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
58 void scan(interval_t f, vector<interval_t>* Wf, interval_t g, vector<interval_t>* Wg, vector<int>* overlap)
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
59 {
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
60 vector<interval_t>::iterator i;
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
61 i=Wg->begin();
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
62 while (i<Wg->end())
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
63 {
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
64 interval_t g2 = *i;
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
65 if (leftOf(g2,f))
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
66 {
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
67 Wg->erase(i);// inefficient if Wg is large
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
68 // this moves all elements, therefore i is not incremented
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
69 }
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
70 else if (overlaps(g2,f))
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
71 {
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
72 if (g2.set_id==1)
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
73 {
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
74 //printf("overlap: [%i | %i, %i] [%i | %i, %i]\n", g2.idx, g2.start, g2.stop, f.idx, f.start, f.stop);
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
75 overlap->push_back(g2.idx);
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
76 overlap->push_back(f.idx);
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
77 }
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
78 else if (f.set_id==1)
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
79 {
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
80 //printf("overlap: [%i | %i, %i] [%i | %i, %i]\n", f.idx, f.start, f.stop, g2.idx, g2.start, g2.stop);
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
81 overlap->push_back(f.idx);
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
82 overlap->push_back(g2.idx);
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
83 }
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
84 i++;
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
85 }
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
86 else
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
87 {
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
88 printf("never happens??\n");
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
89 i++;
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
90 }
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
91 }
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
92 if (!leftOf(f, g))
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
93 {
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
94 Wf->push_back(f);
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
95 //printf("push: [%i, %i] size:%i\n", f.start, f.stop, Wf->size());
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
96 }
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
97 }
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
98
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
99 /*
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
100 * prhs[0] first interval set starts
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
101 * prhs[1] first interval set stops
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
102 * prhs[2] second interval set starts
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
103 * prhs[3] second interval set stops
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
104 *
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
105 * return:
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
106 * plhs[0] one based index in first interval set overlapping with a interval in the second set
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
107 * plhs[1] corresponding index in the second set
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
108 *
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
109 */
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
110 void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
111 {
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
112 if (nrhs!=4)
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
113 mexErrMsgTxt("Expected 4 arguments: starts1, stops1, starts2, stops2 \n");
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
114 if (nlhs!=2)
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
115 mexErrMsgTxt("Expected 2 output arguments \n");
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
116
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
117 int num_intervals1 = mxGetNumberOfElements(prhs[0]);
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
118 assert(num_intervals1 == mxGetNumberOfElements(prhs[1]));
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
119 int num_intervals2 = mxGetNumberOfElements(prhs[2]);
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
120 assert(num_intervals2 == mxGetNumberOfElements(prhs[3]));
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
121
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
122 //printf("num_intervals1: %i\n", num_intervals1);
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
123 //printf("num_intervals2: %i\n", num_intervals2);
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
124
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
125 double* starts1 = mxGetPr(prhs[0]);
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
126 double* stops1 = mxGetPr(prhs[1]);
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
127 double* starts2 = mxGetPr(prhs[2]);
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
128 double* stops2 = mxGetPr(prhs[3]);
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
129
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
130 vector<interval_t> intervals1;
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
131 for (int i=0; i<num_intervals1; i++)
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
132 {
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
133 interval_t interval;
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
134 interval.start = starts1[i];
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
135 interval.stop = stops1[i];
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
136 interval.set_id = 1;
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
137 interval.idx = i+1;
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
138 intervals1.push_back(interval);
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
139 //printf("int1: [%i, %i] \n",intervals1[i].start, intervals1[i].stop);
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
140 }
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
141 interval_t i;
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
142 i.start = std::numeric_limits<int>::max();
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
143 i.stop = std::numeric_limits<int>::max();
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
144 i.set_id = std::numeric_limits<int>::max();
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
145 i.idx = std::numeric_limits<int>::max();
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
146 intervals1.push_back(i);
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
147
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
148 //printf("num_intervals1: %i\n", intervals1.size());
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
149 vector<interval_t> intervals2;
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
150 for (int i=0; i<num_intervals2; i++)
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
151 {
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
152 interval_t interval;
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
153 interval.start = starts2[i];
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
154 interval.stop = stops2[i];
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
155 interval.set_id = 2;
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
156 interval.idx = i+1;
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
157 intervals2.push_back(interval);
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
158 //printf("int2: [%i, %i] \n",intervals2[i].start, intervals2[i].stop);
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
159 }
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
160 intervals2.push_back(i);
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
161 //printf("num_intervals2: %i\n", intervals2.size());
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
162
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
163 sort(intervals1.begin(), intervals1.end(), compare);
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
164 sort(intervals2.begin(), intervals2.end(), compare);
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
165
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
166
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
167 vector<int> overlap;
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
168 vector<interval_t> Wx;
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
169 vector<interval_t> Wy;
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
170 vector<interval_t>::iterator x = intervals1.begin();
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
171 vector<interval_t>::iterator y = intervals2.begin();
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
172 while (x<intervals1.end() && y<intervals2.end())
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
173 {
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
174 //vector<interval_t>::iterator x;
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
175 //vector<interval_t>::iterator y;
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
176 //if (it1>intervals1.end())
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
177 // x = inf_interval();
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
178 //else
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
179 // x = it1;
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
180 //if (it2>intervals2.end())
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
181 // y = inf_interval();
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
182 //else
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
183 // y=it2;
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
184
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
185 if (x->start <= y->start)
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
186 {
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
187 scan(*x, &Wx, *y, &Wy, &overlap);
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
188 x++;
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
189 }
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
190 else
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
191 {
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
192 if (y<=intervals2.end())
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
193 {
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
194 scan(*y, &Wy, *x, &Wx, &overlap);
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
195 y++;
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
196 }
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
197 }
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
198 }
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
199
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
200 plhs[0] = mxCreateDoubleMatrix(1, overlap.size()/2, mxREAL);
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
201 double* idx1 = mxGetPr(plhs[0]);
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
202
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
203 plhs[1] = mxCreateDoubleMatrix(1, overlap.size()/2, mxREAL);
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
204 double* idx2 = mxGetPr(plhs[1]);
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
205
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
206 for (int i=0; i<overlap.size(); i+=2)
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
207 {
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
208 //printf("ov: %i [%i, %i] \n", i, overlap[i], overlap[i+1]);
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
209 idx1[i/2] = (double) overlap[i];
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
210 idx2[i/2] = (double) overlap[i+1];
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
211 }
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
212 }
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
213
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
214
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
215
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
216
0f80a5141704 version 0.3 uploaded
vipints
parents:
diff changeset
217