Eurojackpot results for Friday 14th April 2017
The winning numbers for the 15th Eurojackpot draw in 2017 that took place on Friday 14th April at 21:00 CEST (20:00 GMT) were:
Winners
Winners
Amount
Slovenian Prize Breakdown
View prize breakdowns for other countries| Numbers Matched | Prize Per Winner | Winners from Slovenia | Prize Fund Amount | Total Winners |
|---|---|---|---|---|
|
Match 5 and 2 Euro Numbers |
€86,970,702.80 | 0 | €0 | 1 |
|
Match 5 and 1 Euro Number |
€821,662 | 0 | €0 | 3 |
|
Match 5 |
€86,999.50 | 1 | €86,999.50 | 10 |
|
Match 4 and 2 Euro Numbers |
€5,178.50 | 0 | €0 | 56 |
|
Match 4 and 1 Euro Number |
€258.60 | 20 | €5,172 | 1,009 |
|
Match 4 |
€103.60 | 21 | €2,175.60 | 1,958 |
|
Match 3 and 2 Euro Numbers |
€64.20 | 29 | €1,861.80 | 2,708 |
|
Match 2 and 2 Euro Numbers |
€22.90 | 502 | €11,495.80 | 39,240 |
|
Match 3 and 1 Euro Number |
€17.90 | 693 | €12,404.70 | 48,409 |
|
Match 3 |
€14.60 | 1,203 | €17,563.80 | 85,379 |
|
Match 1 and 2 Euro Numbers |
€10.90 | 2,552 | €27,816.80 | 206,245 |
|
Match 2 and 1 Euro Number |
€8.20 | 9,117 | €74,759.40 | 668,674 |
|
Total |
- | 14,138 | €240,249.40 | 1,053,692 |
Eurojackpot prizes in Slovenia must be claimed within 90 days of the draw date, so tickets purchased for this draw were valid until Thursday 13th July 2017.
Additional Draw Information
In total there were 28,999,838 entries into this draw from all participating countries.
Draw Number: 15
European Prize Breakdown
| Numbers Matched | Prize Per Winner | Winners from Croatia | Prize Fund Amount | Total Winners |
|---|---|---|---|---|
|
Match 5 and 2 Euro Numbers |
kn646,474,106.88 | 0 | kn0 | 1 |
|
Match 5 and 1 Euro Number |
kn6,107,610.84 | 0 | kn0 | 3 |
|
Match 5 |
kn646,688.16 | 1 | kn646,688.16 | 10 |
|
Match 4 and 2 Euro Numbers |
kn38,493.03 | 1 | kn38,493.03 | 56 |
|
Match 4 and 1 Euro Number |
kn1,922.24 | 17 | kn32,678.08 | 1,009 |
|
Match 4 |
kn770.08 | 29 | kn22,332.32 | 1,958 |
|
Match 3 and 2 Euro Numbers |
kn477.21 | 35 | kn16,702.35 | 2,708 |
|
Match 2 and 2 Euro Numbers |
kn170.22 | 465 | kn79,152.30 | 39,240 |
|
Match 3 and 1 Euro Number |
kn133.05 | 754 | kn100,319.70 | 48,409 |
|
Match 3 |
kn108.53 | 1,332 | kn144,561.96 | 85,379 |
|
Match 1 and 2 Euro Numbers |
kn81.02 | 2,805 | kn227,261.10 | 206,245 |
|
Match 2 and 1 Euro Number |
kn60.95 | 9,928 | kn605,111.60 | 668,674 |
|
Total |
- | 15,367 | kn1,913,300.60 | 1,053,692 |
Eurojackpot prizes in Croatia must be claimed within 60 days of the draw date, so tickets purchased for this draw were valid until Tuesday 13th June 2017.
The estimated jackpot advertised in Croatia prior to the draw was kn640,000,000.
| Numbers Matched | Prize Per Winner | Winners from Czech Republic | Prize Fund Amount | Total Winners |
|---|---|---|---|---|
|
Match 5 and 2 Euro Numbers |
Kč2,322,552,618 | 0 | Kč0 | 1 |
|
Match 5 and 1 Euro Number |
Kč21,942,483 | 0 | Kč0 | 3 |
|
Match 5 |
Kč2,323,321 | 0 | Kč0 | 10 |
|
Match 4 and 2 Euro Numbers |
Kč138,291 | 1 | Kč138,291 | 56 |
|
Match 4 and 1 Euro Number |
Kč6,905 | 23 | Kč158,815 | 1,009 |
|
Match 4 |
Kč2,766 | 59 | Kč163,194 | 1,958 |
|
Match 3 and 2 Euro Numbers |
Kč1,714 | 72 | Kč123,408 | 2,708 |
|
Match 2 and 2 Euro Numbers |
Kč611 | 930 | Kč568,230 | 39,240 |
|
Match 3 and 1 Euro Number |
Kč478 | 1,229 | Kč587,462 | 48,409 |
|
Match 3 |
Kč389 | 2,085 | Kč811,065 | 85,379 |
|
Match 1 and 2 Euro Numbers |
Kč291 | 5,278 | Kč1,535,898 | 206,245 |
|
Match 2 and 1 Euro Number |
Kč218 | 16,913 | Kč3,687,034 | 668,674 |
|
Total |
- | 26,590 | Kč7,773,397 | 1,053,692 |
Eurojackpot prizes in Czech Republic must be claimed within 35 days of the draw date, so tickets purchased for this draw were valid until Friday 19th May 2017.
The estimated jackpot advertised in Czech Republic prior to the draw was Kč2,337,000,000.
| Numbers Matched | Prize Per Winner | Winners from Denmark | Prize Fund Amount | Total Winners |
|---|---|---|---|---|
|
Match 5 and 2 Euro Numbers |
kr.549,773,586 | 0 | kr.0 | 1 |
|
Match 5 and 1 Euro Number |
kr.5,238,125 | 1 | kr.5,238,125 | 3 |
|
Match 5 |
kr.554,651 | 0 | kr.0 | 10 |
|
Match 4 and 2 Euro Numbers |
kr.33,042 | 3 | kr.99,126 | 56 |
|
Match 4 and 1 Euro Number |
kr.1,678 | 103 | kr.172,834 | 1,009 |
|
Match 4 |
kr.690 | 140 | kr.96,600 | 1,958 |
|
Match 3 and 2 Euro Numbers |
kr.439 | 265 | kr.116,335 | 2,708 |
|
Match 2 and 2 Euro Numbers |
kr.171 | 3,684 | kr.629,964 | 39,240 |
|
Match 3 and 1 Euro Number |
kr.134 | 4,195 | kr.562,130 | 48,409 |
|
Match 3 |
kr.109 | 7,156 | kr.780,004 | 85,379 |
|
Match 1 and 2 Euro Numbers |
kr.81 | 19,778 | kr.1,602,018 | 206,245 |
|
Match 2 and 1 Euro Number |
kr.61 | 60,259 | kr.3,675,799 | 668,674 |
|
Total |
- | 95,584 | kr.12,972,935 | 1,053,692 |
Eurojackpot prizes in Denmark must be claimed within a set period of time depending on how much you have won. Visit the How to Claim page to find specific claim periods, with some prizes needing to be claimed within 90 days of the draw (valid until Thursday 13th July 2017).
The estimated jackpot advertised in Denmark prior to the draw was kr.543,000,000.
| Numbers Matched | Prize Per Winner | Winners from Estonia | Prize Fund Amount | Total Winners |
|---|---|---|---|---|
|
Match 5 and 2 Euro Numbers |
€86,970,702.80 | 0 | €0 | 1 |
|
Match 5 and 1 Euro Number |
€821,662 | 0 | €0 | 3 |
|
Match 5 |
€86,999.50 | 0 | €0 | 10 |
|
Match 4 and 2 Euro Numbers |
€5,178.50 | 0 | €0 | 56 |
|
Match 4 and 1 Euro Number |
€258.60 | 8 | €2,068.80 | 1,009 |
|
Match 4 |
€103.60 | 14 | €1,450.40 | 1,958 |
|
Match 3 and 2 Euro Numbers |
€64.20 | 21 | €1,348.20 | 2,708 |
|
Match 2 and 2 Euro Numbers |
€22.90 | 308 | €7,053.20 | 39,240 |
|
Match 3 and 1 Euro Number |
€17.90 | 313 | €5,602.70 | 48,409 |
|
Match 3 |
€14.60 | 524 | €7,650.40 | 85,379 |
|
Match 1 and 2 Euro Numbers |
€10.90 | 1,417 | €15,445.30 | 206,245 |
|
Match 2 and 1 Euro Number |
€8.20 | 4,553 | €37,334.60 | 668,674 |
|
Total |
- | 7,158 | €77,953.60 | 1,053,692 |
Eurojackpot prizes in Estonia must be claimed within 90 days of the draw date, so tickets purchased for this draw were valid until Thursday 13th July 2017.
The estimated jackpot advertised in Estonia prior to the draw was €86,000,000.
| Numbers Matched | Prize Per Winner | Winners from Finland | Prize Fund Amount | Total Winners |
|---|---|---|---|---|
|
Match 5 and 2 Euro Numbers |
€86,970,702.80 | 1 | €86,970,702.80 | 1 |
|
Match 5 and 1 Euro Number |
€821,662 | 1 | €821,662 | 3 |
|
Match 5 |
€86,999.50 | 2 | €173,999 | 10 |
|
Match 4 and 2 Euro Numbers |
€5,178.50 | At present this information is not released by the lottery operator of Finland | 56 | |
|
Match 4 and 1 Euro Number |
€258.60 | 1,009 | ||
|
Match 4 |
€103.60 | 1,958 | ||
|
Match 3 and 2 Euro Numbers |
€64.20 | 2,708 | ||
|
Match 2 and 2 Euro Numbers |
€22.90 | 39,240 | ||
|
Match 3 and 1 Euro Number |
€17.90 | 48,409 | ||
|
Match 3 |
€14.60 | 85,379 | ||
|
Match 1 and 2 Euro Numbers |
€10.90 | 206,245 | ||
|
Match 2 and 1 Euro Number |
€8.20 | 668,674 | ||
|
Total |
- | 1,053,692 |
Eurojackpot prizes in Finland must be claimed within 365 days of the draw date, so tickets purchased for this draw were valid until Saturday 14th April 2018.
The estimated jackpot advertised in Finland prior to the draw was €86,000,000.
| Numbers Matched | Prize Per Winner | Winners from Germany | Prize Fund Amount | Total Winners |
|---|---|---|---|---|
|
Match 5 and 2 Euro Numbers |
€86,970,702.80 | 0 | €0 | 1 |
|
Match 5 and 1 Euro Number |
€821,662 | 1 | €821,662 | 3 |
|
Match 5 |
€86,999.50 | 4 | €347,998 | 10 |
|
Match 4 and 2 Euro Numbers |
€5,178.50 | At present this information is not released by the lottery operator of Germany | 56 | |
|
Match 4 and 1 Euro Number |
€258.60 | 1,009 | ||
|
Match 4 |
€103.60 | 1,958 | ||
|
Match 3 and 2 Euro Numbers |
€64.20 | 2,708 | ||
|
Match 2 and 2 Euro Numbers |
€22.90 | 39,240 | ||
|
Match 3 and 1 Euro Number |
€17.90 | 48,409 | ||
|
Match 3 |
€14.60 | 85,379 | ||
|
Match 1 and 2 Euro Numbers |
€10.90 | 206,245 | ||
|
Match 2 and 1 Euro Number |
€8.20 | 668,674 | ||
|
Total |
- | 1,053,692 |
Eurojackpot prizes in Germany must be claimed within 3 years of the draw date, so tickets purchased for this draw are valid until Tuesday 14th April 2020.
The estimated jackpot advertised in Germany prior to the draw was €86,000,000.
| Numbers Matched | Prize Per Winner | Winners from Hungary | Prize Fund Amount | Total Winners |
|---|---|---|---|---|
|
Match 5 and 2 Euro Numbers |
€86,970,702.80 | 0 | €0 | 1 |
|
Match 5 and 1 Euro Number |
€821,662 | 0 | €0 | 3 |
|
Match 5 |
Ft24,403,360 | 0 | Ft0 | 10 |
|
Match 4 and 2 Euro Numbers |
Ft1,452,570 | 1 | Ft1,452,570 | 56 |
|
Match 4 and 1 Euro Number |
Ft72,535 | 20 | Ft1,450,700 | 1,009 |
|
Match 4 |
Ft29,060 | 39 | Ft1,133,340 | 1,958 |
|
Match 3 and 2 Euro Numbers |
Ft18,010 | 24 | Ft432,240 | 2,708 |
|
Match 2 and 2 Euro Numbers |
Ft6,425 | 505 | Ft3,244,625 | 39,240 |
|
Match 3 and 1 Euro Number |
Ft5,020 | 740 | Ft3,714,800 | 48,409 |
|
Match 3 |
Ft4,095 | 1,580 | Ft6,470,100 | 85,379 |
|
Match 1 and 2 Euro Numbers |
Ft3,055 | 3,001 | Ft9,168,055 | 206,245 |
|
Match 2 and 1 Euro Number |
Ft2,300 | 10,581 | Ft24,336,300 | 668,674 |
|
Total |
- | 16,491 | Ft51,402,730 | 1,053,692 |
Eurojackpot prizes in Hungary must be claimed within 180 days of the draw date, so tickets purchased for this draw were valid until Wednesday 11th October 2017.
The estimated jackpot advertised in Hungary prior to the draw was €86,000,000.
| Numbers Matched | Prize Per Winner | Winners from Iceland | Prize Fund Amount | Total Winners |
|---|---|---|---|---|
|
Match 5 and 2 Euro Numbers |
kr.10,239,930,540 | 0 | kr.0 | 1 |
|
Match 5 and 1 Euro Number |
kr.96,742,480 | 0 | kr.0 | 3 |
|
Match 5 |
kr.10,243,320 | 0 | kr.0 | 10 |
|
Match 4 and 2 Euro Numbers |
kr.609,710 | At present this information is not released by the lottery operator of Iceland | 56 | |
|
Match 4 and 1 Euro Number |
kr.30,440 | 1,009 | ||
|
Match 4 |
kr.12,190 | 1,958 | ||
|
Match 3 and 2 Euro Numbers |
kr.75,540 | 2,708 | ||
|
Match 2 and 2 Euro Numbers |
kr.2,690 | 39,240 | ||
|
Match 3 and 1 Euro Number |
kr.2,100 | 48,409 | ||
|
Match 3 |
kr.1,710 | 85,379 | ||
|
Match 1 and 2 Euro Numbers |
kr.1,280 | 206,245 | ||
|
Match 2 and 1 Euro Number |
kr.960 | 668,674 | ||
|
Total |
- | 1,053,692 |
Eurojackpot prizes in Iceland must be claimed within 1 year of the draw date, so tickets purchased for this draw were valid until Saturday 14th April 2018.
The estimated jackpot advertised in Iceland prior to the draw was kr.10,200,000,000.
| Numbers Matched | Prize Per Winner | Winners from Italy | Prize Fund Amount | Total Winners |
|---|---|---|---|---|
|
Match 5 and 2 Euro Numbers |
€86,970,702.80 | 0 | €0 | 1 |
|
Match 5 and 1 Euro Number |
€821,662 | 0 | €0 | 3 |
|
Match 5 |
€86,999.50 | 0 | €0 | 10 |
|
Match 4 and 2 Euro Numbers |
€5,178.50 | 3 | €15,535.50 | 56 |
|
Match 4 and 1 Euro Number |
€258.60 | 26 | €6,723.60 | 1,009 |
|
Match 4 |
€103.60 | 68 | €7,044.80 | 1,958 |
|
Match 3 and 2 Euro Numbers |
€64.20 | 90 | €5,778 | 2,708 |
|
Match 2 and 2 Euro Numbers |
€22.90 | 1,002 | €22,945.80 | 39,240 |
|
Match 3 and 1 Euro Number |
€17.90 | 1,297 | €23,216.30 | 48,409 |
|
Match 3 |
€14.60 | 2,337 | €34,120.20 | 85,379 |
|
Match 1 and 2 Euro Numbers |
€10.90 | 5,085 | €55,426.50 | 206,245 |
|
Match 2 and 1 Euro Number |
€8.20 | 17,164 | €140,744.80 | 668,674 |
|
Total |
- | 27,072 | €311,535.50 | 1,053,692 |
Eurojackpot prizes in Italy must be claimed within a set period of time depending on how much you have won. Visit the How to Claim page to find specific claim periods, with some prizes needing to be claimed within 30 days of the draw (valid until Sunday 14th May 2017).
The estimated jackpot advertised in Italy prior to the draw was €86,000,000.
| Numbers Matched | Prize Per Winner | Winners from Latvia | Prize Fund Amount | Total Winners |
|---|---|---|---|---|
|
Match 5 and 2 Euro Numbers |
€86,970,702.80 | 0 | €0 | 1 |
|
Match 5 and 1 Euro Number |
€821,662 | 0 | €0 | 3 |
|
Match 5 |
€86,999.50 | 1 | €86,999.50 | 10 |
|
Match 4 and 2 Euro Numbers |
€5,178.50 | At present this information is not released by the lottery operator of Latvia | 56 | |
|
Match 4 and 1 Euro Number |
€258.60 | 1,009 | ||
|
Match 4 |
€103.60 | 1,958 | ||
|
Match 3 and 2 Euro Numbers |
€64.20 | 2,708 | ||
|
Match 2 and 2 Euro Numbers |
€22.90 | 39,240 | ||
|
Match 3 and 1 Euro Number |
€17.90 | 48,409 | ||
|
Match 3 |
€14.60 | 85,379 | ||
|
Match 1 and 2 Euro Numbers |
€10.90 | 206,245 | ||
|
Match 2 and 1 Euro Number |
€8.20 | 668,674 | ||
|
Total |
- | 1,053,692 |
Eurojackpot prizes in Latvia must be claimed within 30 days of the draw date, so tickets purchased for this draw were valid until Sunday 14th May 2017.
The estimated jackpot advertised in Latvia prior to the draw was €86,000,000.
| Numbers Matched | Prize Per Winner | Winners from Lithuania | Prize Fund Amount | Total Winners |
|---|---|---|---|---|
|
Match 5 and 2 Euro Numbers |
€86,970,702.80 | 0 | €0 | 1 |
|
Match 5 and 1 Euro Number |
€821,662 | 0 | €0 | 3 |
|
Match 5 |
€86,999.50 | 0 | €0 | 10 |
|
Match 4 and 2 Euro Numbers |
€5,178.50 | 1 | €5,178.50 | 56 |
|
Match 4 and 1 Euro Number |
€258.60 | 0 | €0 | 1,009 |
|
Match 4 |
€103.60 | 4 | €414.40 | 1,958 |
|
Match 3 and 2 Euro Numbers |
€64.20 | 11 | €706.20 | 2,708 |
|
Match 2 and 2 Euro Numbers |
€22.90 | 123 | €2,816.70 | 39,240 |
|
Match 3 and 1 Euro Number |
€17.90 | 167 | €2,989.30 | 48,409 |
|
Match 3 |
€14.60 | 244 | €3,562.40 | 85,379 |
|
Match 1 and 2 Euro Numbers |
€10.90 | 592 | €6,452.80 | 206,245 |
|
Match 2 and 1 Euro Number |
€8.20 | 2,026 | €16,613.20 | 668,674 |
|
Total |
- | 3,168 | €38,733.50 | 1,053,692 |
Eurojackpot prizes in Lithuania must be claimed within 60 days of the draw date, so tickets purchased for this draw were valid until Tuesday 13th June 2017.
The estimated jackpot advertised in Lithuania prior to the draw was €86,000,000.
| Numbers Matched | Prize Per Winner | Winners from Netherlands | Prize Fund Amount | Total Winners |
|---|---|---|---|---|
|
Match 5 and 2 Euro Numbers |
€86,970,702.80 | 0 | €0 | 1 |
|
Match 5 and 1 Euro Number |
€821,662 | 0 | €0 | 3 |
|
Match 5 |
€86,999.50 | 0 | €0 | 10 |
|
Match 4 and 2 Euro Numbers |
€5,178.50 | At present this information is not released by the lottery operator of Netherlands | 56 | |
|
Match 4 and 1 Euro Number |
€258.60 | 1,009 | ||
|
Match 4 |
€103.60 | 1,958 | ||
|
Match 3 and 2 Euro Numbers |
€64.20 | 2,708 | ||
|
Match 2 and 2 Euro Numbers |
€22.90 | 39,240 | ||
|
Match 3 and 1 Euro Number |
€17.90 | 48,409 | ||
|
Match 3 |
€14.60 | 85,379 | ||
|
Match 1 and 2 Euro Numbers |
€10.90 | 206,245 | ||
|
Match 2 and 1 Euro Number |
€8.20 | 668,674 | ||
|
Total |
- | 1,053,692 |
Eurojackpot prizes in Netherlands must be claimed within 365 days of the draw date, so tickets purchased for this draw were valid until Saturday 14th April 2018.
The estimated jackpot advertised in Netherlands prior to the draw was €86,000,000.
| Numbers Matched | Prize Per Winner | Winners from Norway | Prize Fund Amount | Total Winners |
|---|---|---|---|---|
|
Match 5 and 2 Euro Numbers |
kr.791,737,790 | 0 | kr.0 | 1 |
|
Match 5 and 1 Euro Number |
kr.7,480,000 | 0 | kr.0 | 3 |
|
Match 5 |
kr.791,995 | 0 | kr.0 | 10 |
|
Match 4 and 2 Euro Numbers |
kr.47,140 | At present this information is not released by the lottery operator of Norway | 56 | |
|
Match 4 and 1 Euro Number |
kr.2,350 | 1,009 | ||
|
Match 4 |
kr.940 | 1,958 | ||
|
Match 3 and 2 Euro Numbers |
kr.580 | 2,708 | ||
|
Match 2 and 2 Euro Numbers |
kr.205 | 39,240 | ||
|
Match 3 and 1 Euro Number |
kr.160 | 48,409 | ||
|
Match 3 |
kr.130 | 85,379 | ||
|
Match 1 and 2 Euro Numbers |
kr.95 | 206,245 | ||
|
Match 2 and 1 Euro Number |
kr.70 | 668,674 | ||
|
Total |
- | 1,053,692 |
Eurojackpot prizes in Norway must be claimed within 3 months of the draw date, so tickets purchased for this draw were valid until Friday 14th July 2017.
The estimated jackpot advertised in Norway prior to the draw was kr.787,000,000.
| Numbers Matched | Prize Per Winner | Winners from Slovakia | Prize Fund Amount | Total Winners |
|---|---|---|---|---|
|
Match 5 and 2 Euro Numbers |
€86,970,702.80 | 0 | €0 | 1 |
|
Match 5 and 1 Euro Number |
€821,662 | 0 | €0 | 3 |
|
Match 5 |
€86,999.50 | 1 | €86,999.50 | 10 |
|
Match 4 and 2 Euro Numbers |
€5,178.50 | 1 | €5,178.50 | 56 |
|
Match 4 and 1 Euro Number |
€258.60 | 11 | €2,844.60 | 1,009 |
|
Match 4 |
€103.60 | 27 | €2,797.20 | 1,958 |
|
Match 3 and 2 Euro Numbers |
€64.20 | 37 | €2,375.40 | 2,708 |
|
Match 2 and 2 Euro Numbers |
€22.90 | 458 | €10,488.20 | 39,240 |
|
Match 3 and 1 Euro Number |
€17.90 | 560 | €10,024 | 48,409 |
|
Match 3 |
€14.60 | 1,046 | €15,271.60 | 85,379 |
|
Match 1 and 2 Euro Numbers |
€10.90 | 2,564 | €27,947.60 | 206,245 |
|
Match 2 and 1 Euro Number |
€8.20 | 8,779 | €71,987.80 | 668,674 |
|
Total |
- | 13,484 | €235,914.40 | 1,053,692 |
Eurojackpot prizes in Slovakia must be claimed within 35 days of the draw date, so tickets purchased for this draw were valid until Friday 19th May 2017.
The estimated jackpot advertised in Slovakia prior to the draw was €86,000,000.
| Numbers Matched | Prize Per Winner | Winners from Spain | Prize Fund Amount | Total Winners |
|---|---|---|---|---|
|
Match 5 and 2 Euro Numbers |
€86,970,702.80 | 0 | €0 | 1 |
|
Match 5 and 1 Euro Number |
€821,662 | 0 | €0 | 3 |
|
Match 5 |
€86,999.50 | 0 | €0 | 10 |
|
Match 4 and 2 Euro Numbers |
€5,178.50 | 0 | €0 | 56 |
|
Match 4 and 1 Euro Number |
€258.60 | 32 | €8,275.20 | 1,009 |
|
Match 4 |
€103.60 | 64 | €6,630.40 | 1,958 |
|
Match 3 and 2 Euro Numbers |
€64.20 | 95 | €6,099 | 2,708 |
|
Match 2 and 2 Euro Numbers |
€22.90 | 1,418 | €32,472.20 | 39,240 |
|
Match 3 and 1 Euro Number |
€17.90 | 1,657 | €29,660.30 | 48,409 |
|
Match 3 |
€14.60 | 2,990 | €43,654 | 85,379 |
|
Match 1 and 2 Euro Numbers |
€10.90 | 7,215 | €78,643.50 | 206,245 |
|
Match 2 and 1 Euro Number |
€8.20 | 22,581 | €185,164.20 | 668,674 |
|
Total |
- | 36,052 | €390,598.80 | 1,053,692 |
Eurojackpot prizes in Spain must be claimed within 30 days of the draw date, so tickets purchased for this draw were valid until Sunday 14th May 2017.
The estimated jackpot advertised in Spain prior to the draw was €86,000,000.
| Numbers Matched | Prize Per Winner | Winners from Sweden | Prize Fund Amount | Total Winners |
|---|---|---|---|---|
|
Match 5 and 2 Euro Numbers |
kr.834,127,313 | 0 | kr.0 | 1 |
|
Match 5 and 1 Euro Number |
kr.7,880,478 | 0 | kr.0 | 3 |
|
Match 5 |
kr.834,403 | 0 | kr.0 | 10 |
|
Match 4 and 2 Euro Numbers |
kr.333,978 | 1 | kr.333,978 | 56 |
|
Match 4 and 1 Euro Number |
kr.21,625 | 27 | kr.583,875 | 1,009 |
|
Match 4 |
kr.8,262 | 64 | kr.528,768 | 1,958 |
|
Match 3 and 2 Euro Numbers |
kr.3,131 | 113 | kr.353,803 | 2,708 |
|
Match 2 and 2 Euro Numbers |
kr.219 | 1,350 | kr.295,650 | 39,240 |
|
Match 3 and 1 Euro Number |
kr.171 | 1,400 | kr.239,400 | 48,409 |
|
Match 3 |
kr.140 | 2,488 | kr.348,320 | 85,379 |
|
Match 1 and 2 Euro Numbers |
kr.104 | 6,646 | kr.691,184 | 206,245 |
|
Match 2 and 1 Euro Number |
kr.78 | 20,183 | kr.1,574,274 | 668,674 |
|
Total |
- | 32,272 | kr.4,949,252 | 1,053,692 |
Eurojackpot prizes in Sweden must be claimed within 3 months of the draw date, so tickets purchased for this draw were valid until Friday 14th July 2017.
The estimated jackpot advertised in Sweden prior to the draw was kr.848,000,000.
Associated Draw Results
- 5
- 7
- 4
- 1
- 4
- 4
| Numbers Matched | Prize Per Winner | Total Winners |
|---|---|---|
| Match 6 in Exact Order | €50,000 | 0 |
| Match Last 5 in Exact Order | €5,000 | 1 |
| Match Last 4 in Exact Order | €500 | 9 |
| Match Last 3 in Exact Order | €50 | 100 |
| Match Last 2 in Exact Order | €5 | 1,035 |
| Match Last 1 in Exact Order | €3 | 10,652 |
- 3
- 2
- 3
- 4
- 9
- 3
| Numbers Matched | Prize Per Winner | Total Winners |
|---|---|---|
| Match 6 | CZK2,000,000 | 0 |
| Match 5 | CZK200,000 | 2 |
| Match 4 | CZK20,000 | 13 |
| Match 3 | CZK2,000 | 122 |
| Match 2 | CZK200 | 1,280 |
| Match 1 | CZK120 | 13,152 |
- 2
- 0
- 2
- 3
- 6
- 9
- 3
| Numbers Matched | Prize Per Winner | Total Winners |
|---|---|---|
| Match 7 in Exact Order | €0 | 0 |
| Match Any 6 in the Right Spot | €20,000 | 2 |
| Match Any 5 in the Right Spot | €500 | 51 |
| Match Any 4 in the Right Spot | €50 | 643 |
| Match Any 3 in the Right Spot | €6 | 6,096 |
| Match Any 2 in the Right Spot | €3 | 33,681 |
- Lissabon
- 76
| Numbers Matched | Prize Per Winner | Total Winners |
|---|---|---|
| City and Number | €1,000 | 27 |
| City | €5 | 2,256 |
- 5
- 8
- 4
- 5
- 0
| Numbers Matched | Prize Per Winner | Total Winners |
|---|---|---|
| Match 5 in Exact Order | kr2,000,000 | 1 |
| Match First/Last 4 in Exact Order | kr100,000 | 1 |
| Match First/Last 3 in Exact Order | kr10,000 | 4 |
| Match First/Last 2 in Exact Order | kr2,000 | 104 |
- Trondheim
Related Eurojackpot Results Links
- Automatically check your Eurojackpot ticket
- View average prizes and winners for each prize tiers
- View the largest jackpot winners and total winners from each country
- View previous Eurojackpot results by year
Buy Eurojackpot Tickets Online
By buying your Eurojackpot tickets online you don’t have to worry about ever losing your Eurojackpot lottery tickets. When you play the Eurojackpot online all your lottery tickets purchased on the internet are stored in your personal account, meaning that you can view them anytime you wish.


Carbon Calculator
Petrol(in liters) used per week
Approx number of Km traveled by plane per week
Approx number of Km traveled by train per week
Approx number of Km traveled by metro per week


module StringLabels: sig .. end
let length: string => int;
let get: (string, int) => char;
String.get s n
returns the character at index n
in string s
.
You can also write s.[n]
instead of String.get s n
.
Raise Invalid_argument
if n
not a valid index in s
.
let set: (bytes, int, char) => unit;
BytesLabels.set
.String.set s n c
modifies byte sequence s
in place,
replacing the byte at index n
with c
.
You can also write s.[n] <- c
instead of String.set s n c
.
Raise Invalid_argument
if n
is not a valid index in s
.
let create: int => bytes;
BytesLabels.create
.String.create n
returns a fresh byte sequence of length n
.
The sequence is uninitialized and contains arbitrary bytes.
Raise Invalid_argument
if n < 0
or n >
Sys.max_string_length
.
let make: (int, char) => string;
String.make n c
returns a fresh string of length n
,
filled with the character c
.
Raise Invalid_argument
if n < 0
or n >
Sys.max_string_length
.
let init: (int, ~f: int => char) => string;
init n f
returns a string of length n
,
with character i
initialized to the result of f i
.
Raise Invalid_argument
if n < 0
or n >
Sys.max_string_length
.
let copy: string => string;
let sub: (string, ~pos: int, ~len: int) => string;
String.sub s start len
returns a fresh string of length len
,
containing the substring of s
that starts at position start
and
has length len
.
Raise Invalid_argument
if start
and len
do not
designate a valid substring of s
.
let fill: (bytes, ~pos: int, ~len: int, char) => unit;
BytesLabels.fill
.String.fill s start len c
modifies byte sequence s
in place,
replacing len
bytes by c
, starting at start
.
Raise Invalid_argument
if start
and len
do not
designate a valid substring of s
.
let blit:
(~src: string, ~src_pos: int, ~dst: bytes, ~dst_pos: int, ~len: int) => unit;
String.blit src srcoff dst dstoff len
copies len
bytes
from the string src
, starting at index srcoff
,
to byte sequence dst
, starting at character number dstoff
.
Raise Invalid_argument
if srcoff
and len
do not
designate a valid range of src
, or if dstoff
and len
do not designate a valid range of dst
.
let concat: (~sep: string, list(string)) => string;
String.concat sep sl
concatenates the list of strings sl
,
inserting the separator string sep
between each.let iter: (~f: char => unit, string) => unit;
String.iter f s
applies function f
in turn to all
the characters of s
. It is equivalent to
f s.[0]; f s.[1]; ...; f s.[String.length s - 1]; ()
.let iteri: (~f: (int, char) => unit, string) => unit;
String.iter
, but the
function is applied to the index of the element as first argument
(counting from 0), and the character itself as second argument.let map: (~f: char => char, string) => string;
String.map f s
applies function f
in turn to all
the characters of s
and stores the results in a new string that
is returned.let mapi: (~f: (int, char) => char, string) => string;
String.mapi f s
calls f
with each character of s
and its
index (in increasing index order) and stores the results in a new
string that is returned.let trim: string => string;
' '
,
'\012'
, '\n'
, '\r'
, and '\t'
. If there is no leading nor
trailing whitespace character in the argument, return the original
string itself, not a copy.let escaped: string => string;
let index: (string, char) => int;
String.index s c
returns the index of the first
occurrence of character c
in string s
.
Raise Not_found
if c
does not occur in s
.
let rindex: (string, char) => int;
String.rindex s c
returns the index of the last
occurrence of character c
in string s
.
Raise Not_found
if c
does not occur in s
.
let index_from: (string, int, char) => int;
String.index_from s i c
returns the index of the
first occurrence of character c
in string s
after position i
.
String.index s c
is equivalent to String.index_from s 0 c
.
Raise Invalid_argument
if i
is not a valid position in s
.
Raise Not_found
if c
does not occur in s
after position i
.
let rindex_from: (string, int, char) => int;
String.rindex_from s i c
returns the index of the
last occurrence of character c
in string s
before position i+1
.
String.rindex s c
is equivalent to
String.rindex_from s (String.length s - 1) c
.
Raise Invalid_argument
if i+1
is not a valid position in s
.
Raise Not_found
if c
does not occur in s
before position i+1
.
let contains: (string, char) => bool;
String.contains s c
tests if character c
appears in the string s
.let contains_from: (string, int, char) => bool;
String.contains_from s start c
tests if character c
appears in s
after position start
.
String.contains s c
is equivalent to
String.contains_from s 0 c
.
Raise Invalid_argument
if start
is not a valid position in s
.
let rcontains_from: (string, int, char) => bool;
String.rcontains_from s stop c
tests if character c
appears in s
before position stop+1
.
Raise Invalid_argument
if stop < 0
or stop+1
is not a valid
position in s
.
let uppercase: string => string;
let lowercase: string => string;
let capitalize: string => string;
let uncapitalize: string => string;
type t = string;
let compare: (t, t) => int;
Pervasives.compare
. Along with the type t
, this function compare
allows the module String
to be passed as argument to the functors
Set.Make
and Map.Make
.


I'm a machine learning engineer 💻 and designer based in Rome. You can usually find me reading 📖, designing stuff (like this website) or programming.


(Deprecated API)
(Deprecated API)
(Deprecated API)
Includes enterprise licensing and support
Geocoding is the process of converting addresses (like "1600 Amphitheatre Parkway, Mountain View, CA") into geographic coordinates (like latitude 37.423021 and longitude -122.083739), which you can use to place markers or position the map. The Google Maps API Family provides two approaches to geocoding:
Here is a sample of client-side geocoding which takes an address, geocodes it, moves the center of the map to that location and adds a map marker there.
geocoder = new google.maps.Geocoder(); geocoder.geocode( { 'address': address}, function(results, status) { if (status == google.maps.GeocoderStatus.OK) { map.setCenter(results[0].geometry.location); var marker = new google.maps.Marker({ map: map, position: results[0].geometry.location });
Here is an example of using Python to do a server-side geocoding request.
import urllib2 address="1600+Amphitheatre+Parkway,+Mountain+View,+CA" url="http://maps.google.com/maps/api/geocode/json?address=%s&sensor=false" % address response = urllib2.urlopen(url) jsongeocode = response.read()
This produces a JSON object with the following content:
{ "status": "OK", "results": [ { "types": [ "street_address" ], "formatted_address": "1600 Amphitheatre Pkwy, Mountain View, CA 94043, USA", "address_components": [ { "long_name": "1600", "short_name": "1600", "types": [ "street_number" ] }, { "long_name": "Amphitheatre Pkwy", "short_name": "Amphitheatre Pkwy", "types": [ "route" ] }, { "long_name": "Mountain View", "short_name": "Mountain View", "types": [ "locality", "political" ] }, { "long_name": "San Jose", "short_name": "San Jose", "types": [ "administrative_area_level_3", "political" ] }, { "long_name": "Santa Clara", "short_name": "Santa Clara", "types": [ "administrative_area_level_2", "political" ] }, { "long_name": "California", "short_name": "CA", "types": [ "administrative_area_level_1", "political" ] }, { "long_name": "United States", "short_name": "US", "types": [ "country", "political" ] }, { "long_name": "94043", "short_name": "94043", "types": [ "postal_code" ] } ], "geometry": { "location": { "lat": 37.4220323, "lng": -122.0845109 }, "location_type": "ROOFTOP", "viewport": { "southwest": { "lat": 37.4188847, "lng": -122.0876585 }, "northeast": { "lat": 37.4251799, "lng": -122.0813633 } } } } ] }
The server-side geocoder also provies an XML format as an alternative to getting JSON
This article describes the use cases for each approach.
Server-side geocoding, through the Geocoding Web Service has a quota of 2,500 requests per IP per day, so all requests in one day count against the quota. In addition, the Web Service is rate-limited, so that requests that come in too quickly result in blocking. Client-side geocoding through the browser is rate limited per map session, so the geocoding is distributed across all your users and scales with your userbase. Geocoding quotas and rate limits drive the strategies outlined in this article.
In Google Maps API Premier, quotas are tied to
The Google Maps API allows you to cache geocodes, (store them on your server for a limited period). Caching can be useful if you have to repeatedly look up the same address. However, there are two important things to keep in mind.
The Google Maps API for Flash requires the use of API keys. Many people mistakenly think quotas are tied to keys. However, keys don't effect your geocoding quota at all. Registering for a new key won't help. Quota is solely tied to IP addresses. Therefore a new key won't give you any more quota at a particular IP address.
The basic answer is "almost always". As geocoding limits are per IP address, that limit counts against the consumer of your application. It's going to be very rare that someone is going to enter more than 2,500 addresses a day sitting at their computer. Therefore, running client-side geocoding, you generally don't have to worry about your quota.
Two basic architectures for client-side geocoding exist.
On a cautionary note, some mobile networks share IP addresses among many phones. That can cause problems for your client side app. If a lot of people on their smart phones are looking at your map. If you anticipate heavy mobile use, you might consider having a server-side back-up as a fail-over. Try to geocode in the browser and if that doesn't work, send the address to your server for http geocoding.
Server-Side Geocoding is best used for applications that require you to geocode addresses without input from a client. This usually happens when you get a dataset that comes separately from user input, for instance if you have a database of fixed, finite, and known set of addresses that need geocodes. Server-side geocoding can also be useful as a back-up for when client-side geocoding fails.
You should be wary of relying on server-side geocoding. The 2,500 request limit is per IP address. All people using your application are sharing your single server. If you are processing requests that come in from a large number of clients, you could easily overload your quota for the day, or even the queries per second from the same IP address. Also, many cloud computing infrastructures, such as Google App Engine or Amazon Web Services, share IP addresses between different applications. Your requests may run up against quota used by other applications wholely outside your control.
The basic archtecture for a server-side geocoding application is the following:
In general, a combination of client-side geocoding and caching will serve most of your needs, and the generous geocoding limits in place in the JavaScript API will be more than most applications need. You should be careful implementing server-side only, as you're very likely to run into quota issues if you geocode too fast or too much. If after designing your site, you're still running into problems with quota, you may consider a Maps API Premier license. Check out Get Maps for more information on the differences and how to get started.


View the source code of the containing document to see the code and comments.
More information about the code is available in the online example.


Drake
| Number | Name | Download |
|---|---|---|
| 1. | In My Feelings | |
| 2. | 0 to 100 | |
| 3. | Nonstop | |
| 4. | One Dance ft. Wizkid, Kyla | |
| 5. | Jumpman | |
| 6. | Final Fantasy | |
| 7. | Headlines | |
| 8. | Is There More ( Pusha T Diss ) | |
| 9. | Legend | |
| 10. | Nice For What |
XXXTENTACION
| Number | Name | Download |
|---|---|---|
| 1. | Again | |
| 2. | Jocelyn Flores | |
| 3. | SAD! | |
| 4. | Carry On | |
| 5. | Change | |
| 6. | Everybody Dies In Their Nightmares | |
| 7. | Headlines | |
| 8. | Look At Me! | |
| 9. | Moonlight | |
| 10. | Depression & Obsession |
Justin Bieber
| Number | Name | Download |
|---|---|---|
| 1. | 2U | |
| 2. | I'm The One | |
| 3. | Beauty And A Beat | |
| 4. | Boyfriend | |
| 5. | Despacito | |
| 6. | All That Matters | |
| 7. | No Brainer | |
| 8. | Let Me Love You | |
| 9. | As Long As You Love Me | |
| 10. | Be Alright |
Post Malone
| Number | Name | Download |
|---|---|---|
| 1. | Congratulation | |
| 2. | Go Flex | |
| 3. | Psycho | |
| 4. | Rockstar | |
| 5. | White Iverson | |
| 6. | I Fall Apart | |
| 7. | Stay | |
| 8. | Too Young | |
| 9. | Spoil My Night | |
| 10. | Rich And Sad |
Dua Lipa
| Number | Name | Download |
|---|---|---|
| 1. | One Kiss | |
| 2. | IDGAF | |
| 3. | Scared To Be Lonely | |
| 4. | New Rules | |
| 5. | Blow Your Mind | |
| 6. | Be The One | |
| 7. | Homesick | |
| 8. | Thinking 'Bout You | |
| 9. | I'm Not The Only One | |
| 10. | My Love |
Skrillex
| Number | Name | Download |
|---|---|---|
| 1. | Bangarang | |
| 2. | First Of The Year (Equinox) | |
| 3. | Scary Monsters and Nice Sprites | |
| 4. | Kill Everybody | |
| 5. | Breakn' a Sweat | |
| 6. | Purple Lamborghini | |
| 7. | Would You Ever | |
| 8. | Rock n' Roll (Will Take You to the Mountain) | |
| 9. | Full Flex | |
| 10. | Cinema |


Generics
Generic code enables you to write flexible, reusable functions and types that can work with any type, subject to requirements that you define. You can write code that avoids duplication and expresses its intent in a clear, abstracted manner.
Generics are one of the most powerful features of Swift, and much of the Swift standard library is built with generic code. In fact, you’ve been using generics throughout the Language Guide, even if you didn’t realize it. For example, Swift’s Array
and Dictionary
types are both generic collections. You can create an array that holds Int
values, or an array that holds String
values, or indeed an array for any other type that can be created in Swift. Similarly, you can create a dictionary to store values of any specified type, and there are no limitations on what that type can be.
The Problem That Generics Solve
Here’s a standard, nongeneric function called swapTwoInts(_:_:)
, which swaps two Int
values:
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
let temporaryA = a
a = b
b = temporaryA
}
This function makes use of in-out parameters to swap the values of a
and b
, as described in In-Out Parameters.
The swapTwoInts(_:_:)
function swaps the original value of b
into a
, and the original value of a
into b
. You can call this function to swap the values in two Int
variables:
var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
// Prints "someInt is now 107, and anotherInt is now 3"
The swapTwoInts(_:_:)
function is useful, but it can only be used with Int
values.  The only difference is the type of the values that they accept (Int
, String
, and Double
).
It’s more useful, and considerably more flexible, to write a single function that swaps two values of any type. Generic code enables you to write such a function. (A generic version of these functions is defined below.)
Generic Functions
Generic functions can work with any type. Here’s a generic version of the swapTwoInts(_:_:)
function from above, called swapTwoValues(_:_:)
:
func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
let temporaryA = a
a = b
b = temporaryA
}
The body of the swapTwoValues(_:_:)
function is identical to the body of the swapTwoInts(_:_:)
function. However, the first line of swapTwoValues(_:_:)
is slightly different from swapTwoInts(_:_:)
. Here’s how the first lines compare:
func swapTwoInts(_ a: inout Int, _ b: inout Int)
func swapTwoValues<T>(_ a: inout T, _ b: inout T)
The generic version of the function uses a placeholder type name (called T
, in this case) instead of an actual type name (such as Int
, String
, or Double
). The placeholder type name doesn’t say anything about what T
must be, but it does say that both a
and b
must be of the same type T
, whatever T
represents. The actual type to use in place of T
is determined each time the swapTwoValues(_:_:)
function is called.
The other difference between a generic function and a nongeneric function is that the generic function’s name (swapTwoValues(_:_:)
) is followed by the placeholder type name (T
) inside angle brackets (<T>
). The brackets tell Swift that T
is a placeholder type name within the swapTwoValues(_:_:)
function definition. Because T
is a placeholder, Swift doesn’t look for an actual type called T
.
The swapTwoValues(_:_:)
function can now be called in the same way as swapTwoInts
, except that it can be passed two values of any type, as long as both of those values are of the same type as each other. Each time swapTwoValues(_:_:)
is called, the type to use for T
is inferred from the types of values passed to the function.
In the two examples below, T
is inferred to be Int
and String
respectively:
var someInt = 3
var anotherInt = 107
swapTwoValues(&someInt, &anotherInt)
// someInt is now 107, and anotherInt is now 3
var someString = "hello"
var anotherString = "world"
swapTwoValues(&someString, &anotherString)
// someString is now "world", and anotherString is now "hello"
Type Parameters
In the swapTwoValues(_:_:)
example above, the placeholder type T
is an example of a type parameter. Type parameters specify and name a placeholder type, and are written immediately after the function’s name, between a pair of matching angle brackets (such as <T>
).
Once you specify a type parameter, you can use it to define the type of a function’s parameters (such as the a
and b
parameters of the swapTwoValues(_:_:)
function), or as the function’s return type, or as a type annotation within the body of the function. In each case, the type parameter is replaced with an actual type whenever the function is called. (In the swapTwoValues(_:_:)
example above, T
was replaced with Int
the first time the function was called, and was replaced with String
the second time it was called.)
You can provide more than one type parameter by writing multiple type parameter names within the angle brackets, separated by commas.
Naming Type Parameters
In most cases, type parameters have descriptive names, such as Key
and Value
in Dictionary<Key, Value>
and Element
in Array<Element>
, which tells the reader about the relationship between the type parameter and the generic type or function it’s used in. However, when there isn’t a meaningful relationship between them, it’s traditional to name them using single letters such as T
, U
, and V
, such as T
in the swapTwoValues(_:_:)
function above.
Generic Types
In addition to generic functions, Swift enables you to define your own generic types. These are custom classes, structures, and enumerations that can work with any type, in a similar way to Array
and Dictionary
.
This section shows you how to write a generic collection type called Stack
. A stack is an ordered set of values, similar to an array, but with a more restricted set of operations than Swift’s Array
type. An array allows new items to be inserted and removed at any location in the array. A stack, however, allows new items to be appended only to the end of the collection (known as pushing a new value on to the stack). Similarly, a stack allows items to be removed only from the end of the collection (known as popping a value off the stack).
The illustration below shows the push and pop behavior for a stack:
There are currently three values on the stack.
A fourth value is pushed onto the top of the stack.
The stack now holds four values, with the most recent one at the top.
The top item in the stack is popped.
After popping a value, the stack once again holds three values.
Here’s how to write a nongeneric version of a stack, in this case for a stack of Int
values:
struct IntStack {
var items = [Int]()
mutating func push(_ item: Int) {
items.append(item)
}
mutating func pop() -> Int {
return items.removeLast()
}
}
This structure uses an Array
property called items
to store the values in the stack. Stack
provides two methods, push
and pop
, to push and pop values on and off the stack. These methods are marked as mutating
, because they need to modify (or mutate) the structure’s items
array.
The IntStack
type shown above can only be used with Int
values, however. It would be much more useful to define a generic Stack
class, that can manage a stack of any type of value.
Here’s a generic version of the same code:
struct Stack<Element> {
var items = [Element]()
mutating func push(_ item: Element) {
items.append(item)
}
mutating func pop() -> Element {
return items.removeLast()
}
}
Note how the generic version of Stack
is essentially the same as the nongeneric version, but with a type parameter called Element
instead of an actual type of Int
. This type parameter is written within a pair of angle brackets (<Element>
) immediately after the structure’s name.
Element
defines a placeholder name for a type to be provided later. This future type can be referred to as Element
anywhere within the structure’s definition. In this case, Element
is used as a placeholder in three places:
To create a property called
items
, which is initialized with an empty array of values of typeElement
To specify that the
push(_:)
method has a single parameter calleditem
, which must be of typeElement
To specify that the value returned by the
pop()
method will be a value of typeElement
Because it’s a generic type, Stack
can be used to create a stack of any valid type in Swift, in a similar manner to Array
and Dictionary
.
You create a new Stack
instance by writing the type to be stored in the stack within angle brackets. For example, to create a new stack of strings, you write Stack<String>()
:
var stackOfStrings = Stack<String>()
stackOfStrings.push("uno")
stackOfStrings.push("dos")
stackOfStrings.push("tres")
stackOfStrings.push("cuatro")
// the stack now contains 4 strings
Here’s how stackOfStrings
looks after pushing these four values on to the stack:
Popping a value from the stack removes and returns the top value, "cuatro"
:
let fromTheTop = stackOfStrings.pop()
// fromTheTop is equal to "cuatro", and the stack now contains 3 strings
Here’s how the stack looks after popping its top value:
Extending a Generic Type
When you extend a generic type, you don’t provide a type parameter list as part of the extension’s definition. Instead, the type parameter list from the original type definition is available within the body of the extension, and the original type parameter names are used to refer to the type parameters from the original definition.
The following example extends the generic Stack
type to add a read-only computed property called topItem
, which returns the top item on the stack without popping it from the stack:
extension Stack {
var topItem: Element? {
return items.isEmpty ? nil : items[items.count - 1]
}
}
The topItem
property returns an optional value of type Element
. If the stack is empty, topItem
returns nil
; if the stack isn’t empty, topItem
returns the final item in the items
array.
Note that this extension doesn’t define a type parameter list. Instead, the Stack
type’s existing type parameter name, Element
, is used within the extension to indicate the optional type of the topItem
computed property.
The topItem
computed property can now be used with any Stack
instance to access and query its top item without removing it.
if let topItem = stackOfStrings.topItem {
print("The top item on the stack is \(topItem).")
}
// Prints "The top item on the stack is tres."
Extensions of a generic type can also include requirements that instances of the extended type must satisfy in order to gain the new functionality, as discussed in Extensions with a Generic Where Clause below.
Type Constraints
The swapTwoValues(_:_:)
function and the Stack
type can work with any type. However, it’s sometimes useful to enforce certain type constraints on the types that can be used with generic functions and generic types. Type constraints specify that a type parameter must inherit from a specific class, or conform to a particular protocol or protocol composition.
For example, Swift’s Dictionary
type places a limitation on the types that can be used as keys for a dictionary. As described in Dictionaries, the type of a dictionary’s keys must be hashable. That is, it must provide a way to make itself uniquely representable. Dictionary
needs its keys to be hashable so that it can check whether it already contains a value for a particular key. Without this requirement, Dictionary
could not tell whether it should insert or replace a value for a particular key, nor would it be able to find a value for a given key that is already in the dictionary.
This requirement is enforced by a type constraint on the key type for Dictionary
, which specifies that the key type must conform to the Hashable
protocol, a special protocol defined in the Swift standard library. All of Swift’s basic types (such as String
, Int
, Double
, and Bool
) are hashable by default.
You can define your own type constraints when creating custom generic types, and these constraints provide much of the power of generic programming. Abstract concepts like Hashable
characterize types in terms of their conceptual characteristics, rather than their concrete type.
Type Constraint Syntax
You write type constraints by placing a single class or protocol constraint after a type parameter’s name, separated by a colon, as part of the type parameter list. The basic syntax for type constraints on a generic function is shown below (although the syntax is the same for generic types):
func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {
// function body goes here
}
The hypothetical function above has two type parameters. The first type parameter, T
, has a type constraint that requires T
to be a subclass of SomeClass
. The second type parameter, U
, has a type constraint that requires U
to conform to the protocol SomeProtocol
.
Type Constraints in Action
Here’s a nongeneric function called findIndex(ofString:in:)
, which is given a String
value to find and an array of String
values within which to find it. The findIndex(ofString:in:)
function returns an optional Int
value, which will be the index of the first matching string in the array if it’s found, or nil
if the string can’t be found:
func findIndex(ofString valueToFind: String, in array: [String]) -> Int? {
for (index, value) in array.enumerated() {
if value == valueToFind {
return index
}
}
return nil
}
The findIndex(ofString:in:)
function can be used to find a string value in an array of strings:
let strings = ["cat", "dog", "llama", "parakeet", "terrapin"]
if let foundIndex = findIndex(ofString: "llama", in: strings) {
print("The index of llama is \(foundIndex)")
}
// Prints "The index of llama is 2"
The principle of finding the index of a value in an array isn’t useful only for strings, however. You can write the same functionality as a generic function by replacing any mention of strings with values of some type T
instead.
Here’s how you might expect a generic version of findIndex(ofString:in:)
, called findIndex(of:in:)
, to be written. Note that the return type of this function is still Int?
, because the function returns an optional index number, not an optional value from the array. Be warned, though—this function doesn’t compile, for reasons explained after the example:
func findIndex<T>(of valueToFind: T, in array:[T]) -> Int? {
for (index, value) in array.enumerated() {
if value == valueToFind {
return index
}
}
return nil
}
This function doesn’t compile as written above. The problem lies with the equality check, “if value == valueToFind
”. Not every type in Swift can be compared with the equal to operator (==
). If you create your own class or structure to represent a complex data model, for example, then the meaning of “equal to” for that class or structure isn’t something that Swift can guess for you. Because of this, it isn’t possible to guarantee that this code will work for every possible type T
, and an appropriate error is reported when you try to compile the code.
All is not lost, however. The Swift standard library defines a protocol called Equatable
, which requires any conforming type to implement the equal to operator (==
) and the not equal to operator (!=
) to compare any two values of that type. All of Swift’s standard types automatically support the Equatable
protocol.
Any type that is Equatable
can be used safely with the findIndex(of:in:)
function, because it’s guaranteed to support the equal to operator. To express this fact, you write a type constraint of Equatable
as part of the type parameter’s definition when you define the function:
func findIndex<T: Equatable>(of valueToFind: T, in array:[T]) -> Int? {
for (index, value) in array.enumerated() {
if value == valueToFind {
return index
}
}
return nil
}
The single type parameter for findIndex(of:in:)
is written as T: Equatable
, which means “any type T
that conforms to the Equatable
protocol.”
The findIndex(of:in:)
function now compiles successfully and can be used with any type that is Equatable
, such as Double
or String
:
let doubleIndex = findIndex(of: 9.3, in: [3.14159, 0.1, 0.25])
// doubleIndex is an optional Int with no value, because 9.3 isn't in the array
let stringIndex = findIndex(of: "Andrea", in: ["Mike", "Malcolm", "Andrea"])
// stringIndex is an optional Int containing a value of 2
Associated Types
When defining a protocol, it’s sometimes useful to declare one or more associated types as part of the protocol’s definition. An associated type gives a placeholder name to a type that is used as part of the protocol. The actual type to use for that associated type isn’t specified until the protocol is adopted. Associated types are specified with the associatedtype
keyword.
Associated Types in Action
Here’s an example of a protocol called Container
, which declares an associated type called Item
:
protocol Container {
associatedtype Item
mutating func append(_ item: Item)
var count: Int { get }
subscript(i: Int) -> Item { get }
}
The Container
protocol defines three required capabilities that any container must provide:
It must be possible to add a new item to the container with an
append(_:)
method.It must be possible to access a count of the items in the container through a
count
property that returns anInt
value.It must be possible to retrieve each item in the container with a subscript that takes an
Int
index value.
This protocol doesn’t specify how the items in the container should be stored or what type they’re allowed to be. The protocol only specifies the three bits of functionality that any type must provide in order to be considered a Container
. A conforming type can provide additional functionality, as long as it satisfies these three requirements.
Any type that conforms to the Container
protocol must be able to specify the type of values it stores. Specifically, it must ensure that only items of the right type are added to the container, and it must be clear about the type of the items returned by its subscript.
To define these requirements, the Container
protocol needs a way to refer to the type of the elements that a container will hold, without knowing what that type is for a specific container. The Container
protocol needs to specify that any value passed to the append(_:)
method must have the same type as the container’s element type, and that the value returned by the container’s subscript will be of the same type as the container’s element type.
To achieve this, the Container
protocol declares an associated type called Item
, written as associatedtype Item
. The protocol doesn’t define what Item
is—that information is left for any conforming type to provide. Nonetheless, the Item
alias provides a way to refer to the type of the items in a Container
, and to define a type for use with the append(_:)
method and subscript, to ensure that the expected behavior of any Container
is enforced.
Here’s a version of the nongeneric IntStack
type from earlier, adapted to conform to the Container
protocol:
struct IntStack: Container {
// original IntStack implementation
var items = [Int]()
mutating func push(_ item: Int) {
items.append(item)
}
mutating func pop() -> Int {
return items.removeLast()
}
// conformance to the Container protocol
typealias Item = Int
mutating func append(_ item: Int) {
self.push(item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> Int {
return items[i]
}
}
The IntStack
type implements all three of the Container
protocol’s requirements, and in each case wraps part of the IntStack
type’s existing functionality to satisfy these requirements.
Moreover, IntStack
specifies that for this implementation of Container
, the appropriate Item
to use is a type of Int
. The definition of typealias Item = Int
turns the abstract type of Item
into a concrete type of Int
for this implementation of the Container
protocol.
Thanks to Swift’s type inference, you don’t actually need to declare a concrete Item
of Int
as part of the definition of IntStack
. Because IntStack
conforms to all of the requirements of the Container
protocol, Swift can infer the appropriate Item
to use, simply by looking at the type of the append(_:)
method’s item
parameter and the return type of the subscript. Indeed, if you delete the typealias Item = Int
line from the code above, everything still works, because it’s clear what type should be used for Item
.
You can also make the generic Stack
type conform to the Container
protocol:
struct Stack<Element>: Container {
// original Stack<Element> implementation
var items = [Element]()
mutating func push(_ item: Element) {
items.append(item)
}
mutating func pop() -> Element {
return items.removeLast()
}
// conformance to the Container protocol
mutating func append(_ item: Element) {
self.push(item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> Element {
return items[i]
}
}
This time, the type parameter Element
is used as the type of the append(_:)
method’s item
parameter and the return type of the subscript. Swift can therefore infer that Element
is the appropriate type to use as the Item
for this particular container.
Extending an Existing Type to Specify an Associated Type
You can extend an existing type to add conformance to a protocol, as described in Adding Protocol Conformance with an Extension. This includes a protocol with an associated type.
Swift’s Array
type already provides an append(_:)
method, a count
property, and a subscript with an Int
index to retrieve its elements. These three capabilities match the requirements of the Container
protocol. This means that you can extend Array
to conform to the Container
protocol simply by declaring that Array
adopts the protocol. You do this with an empty extension, as described in Declaring Protocol Adoption with an Extension:
extension Array: Container {}
Array’s existing append(_:)
method and subscript enable Swift to infer the appropriate type to use for Item
, just as for the generic Stack
type above. After defining this extension, you can use any Array
as a Container
.
Using Type Annotations to Constrain an Associated Type
You can add a type annotation to an associated type in a protocol, to require that conforming types satisfy the constraints described by the type annotation. For example, the following code defines a version of Container
that requires the items in the container to be equatable.
protocol Container {
associatedtype Item: Equatable
mutating func append(_ item: Item)
var count: Int { get }
subscript(i: Int) -> Item { get }
}
To conform to this version of Container
, the container’s Item
type has to conform to the Equatable
protocol.
Generic Where Clauses
Type constraints, as described in Type Constraints, enable you to define requirements on the type parameters associated with a generic function, subscript, or type.
It can also be useful to define requirements for associated types. You do this by defining a generic where clause. A generic where
clause enables you to require that an associated type must conform to a certain protocol, or that certain type parameters and associated types must be the same. A generic where
clause starts with the where
keyword, followed by constraints for associated types or equality relationships between types and associated types. You write a generic where
clause right before the opening curly brace of a type or function’s body.
The example below defines a generic function called allItemsMatch
, which checks to see if two Container
instances contain the same items in the same order. The function returns a Boolean value of true
if all items match and a value of false
if they don’t.
The two containers to be checked don’t have to be the same type of container (although they can be), but they do have to hold the same type of items. This requirement is expressed through a combination of type constraints and a generic where
clause:
func allItemsMatch<C1: Container, C2: Container>
(_ someContainer: C1, _ anotherContainer: C2) -> Bool
where C1.Item == C2.Item, C1.Item: Equatable {
// Check that both containers contain the same number of items.
if someContainer.count != anotherContainer.count {
return false
}
// Check each pair of items to see if they're equivalent.
for i in 0..<someContainer.count {
if someContainer[i] != anotherContainer[i] {
return false
}
}
// All items match, so return true.
return true
}
This function takes two arguments called someContainer
and anotherContainer
. The someContainer
argument is of type C1
, and the anotherContainer
argument is of type C2
. Both C1
and C2
are type parameters for two container types to be determined when the function is called.
The following requirements are placed on the function’s two type parameters:
C1
must conform to theContainer
protocol (written asC1: Container
).C2
must also conform to theContainer
protocol (written asC2: Container
).The
Item
forC1
must be the same as theItem
forC2
(written asC1.Item == C2.Item
).The
Item
forC1
must conform to theEquatable
protocol (written asC1.Item: Equatable
).
The first and second requirements are defined in the function’s type parameter list, and the third and fourth requirements are defined in the function’s generic where
clause.
These requirements mean:
someContainer
is a container of typeC1
.anotherContainer
is a container of typeC2
.someContainer
andanotherContainer
contain the same type of items.The items in
someContainer
can be checked with the not equal operator (!=
) to see if they’re different from each other.
The third and fourth requirements combine to mean that the items in anotherContainer
can also be checked with the !=
operator, because they’re exactly the same type as the items in someContainer
.
These requirements enable the allItemsMatch(_:_:)
function to compare the two containers, even if they’re of a different container type.
The allItemsMatch(_:_:)
function starts by checking that both containers contain the same number of items. If they contain a different number of items, there’s no way that they can match, and the function returns false
.
After making this check, the function iterates over all of the items in someContainer
with a for
-in
loop and the half-open range operator (..<
). For each item, the function checks whether the item from someContainer
isn’t equal to the corresponding item in anotherContainer
. If the two items aren’t equal, then the two containers don’t match, and the function returns false
.
If the loop finishes without finding a mismatch, the two containers match, and the function returns true
.
Here’s how the allItemsMatch(_:_:)
function looks in action:
var stackOfStrings = Stack<String>()
stackOfStrings.push("uno")
stackOfStrings.push("dos")
stackOfStrings.push("tres")
var arrayOfStrings = ["uno", "dos", "tres"]
if allItemsMatch(stackOfStrings, arrayOfStrings) {
print("All items match.")
} else {
print("Not all items match.")
}
// Prints "All items match."
The example above creates a Stack
instance to store String
values, and pushes three strings onto the stack. The example also creates an Array
instance initialized with an array literal containing the same three strings as the stack. Even though the stack and the array are of a different type, they both conform to the Container
protocol, and both contain the same type of values. You can therefore call the allItemsMatch(_:_:)
function with these two containers as its arguments. In the example above, the allItemsMatch(_:_:)
function correctly reports that all of the items in the two containers match.
Extensions with a Generic Where Clause
You can also use a generic where
clause as part of an extension. The example below extends the generic Stack
structure from the previous examples to add an isTop(_:)
method.
extension Stack where Element: Equatable {
func isTop(_ item: Element) -> Bool {
guard let topItem = items.last else {
return false
}
return topItem == item
}
}
This new isTop(_:)
method first checks that the stack isn’t empty, and then compares the given item against the stack’s topmost item. If you tried to do this without a generic where
clause, you would have a problem: The implementation of isTop(_:)
uses the ==
operator, but the definition of Stack
doesn’t require its items to be equatable, so using the ==
operator results in a compile-time error. Using a generic where
clause lets you add a new requirement to the extension, so that the extension adds the isTop(_:)
method only when the items in the stack are equatable.
Here’s how the isTop(_:)
method looks in action:
if stackOfStrings.isTop("tres") {
print("Top element is tres.")
} else {
print("Top element is something else.")
}
// Prints "Top element is tres."
If you try to call the isTop(_:)
method on a stack whose elements aren’t equatable, you’ll get a compile-time error.
struct NotEquatable { }
var notEquatableStack = Stack<NotEquatable>()
let notEquatableValue = NotEquatable()
notEquatableStack.push(notEquatableValue)
notEquatableStack.isTop(notEquatableValue) // Error
You can use a generic where
clause with extensions to a protocol. The example below extends the Container
protocol from the previous examples to add a startsWith(_:)
method.
extension Container where Item: Equatable {
func startsWith(_ item: Item) -> Bool {
return count >= 1 && self[0] == item
}
}
The startsWith(_:)
method first makes sure that the container has at least one item, and then it checks whether the first item in the container matches the given item. This new startsWith(_:)
method can be used with any type that conforms to the Container
protocol, including the stacks and arrays used above, as long as the container’s items are equatable.
if [9, 9, 9].startsWith(42) {
print("Starts with 42.")
} else {
print("Starts with something else.")
}
// Prints "Starts with something else."
The generic where
clause in the example above requires Item
to conform to a protocol, but you can also write a generic where
clauses that require Item
to be a specific type. For example:
extension Container where Item == Double {
func average() -> Double {
var sum = 0.0
for index in 0..<count {
sum += self[index]
}
return sum / Double(count)
}
}
print([1260.0, 1200.0, 98.6, 37.0].average())
// Prints "648.9"
This example adds an average()
method to containers whose Item
type is Double
. It iterates over the items in the container to add them up, and divides by the container’s count to compute the average. It explicitly converts the count from Int
to Double
to be able to do floating-point division.
You can include multiple requirements in a generic where
clause that is part of an extension, just like you can for a generic where
clause that you write elsewhere. Separate each requirement in the list with a comma.
Associated Types with a Generic Where Clause
You can include a generic where
clause on an associated type. For example, suppose you want to make a version of Container
that includes an iterator, like what the Sequence
protocol uses in the standard library. Here’s how you write that:
protocol Container {
associatedtype Item
mutating func append(_ item: Item)
var count: Int { get }
subscript(i: Int) -> Item { get }
associatedtype Iterator: IteratorProtocol where Iterator.Element == Item
func makeIterator() -> Iterator
}
The generic where
clause on Iterator
requires that the iterator must traverse over elements of the same item type as the container’s items, regardless of the iterator’s type. The makeIterator()
function provides access to a container’s iterator.
For a protocol that inherits from another protocol, you add a constraint to an inherited associated type by including the generic where
clause in the protocol declaration. For example, the following code declares a ComparableContainer
protocol that requires Item
to conform to Comparable
:
protocol ComparableContainer: Container where Item: Comparable { }
Generic Subscripts
Subscripts can be generic, and they can include generic where
clauses. You write the placeholder type name inside angle brackets after subscript
, and you write a generic where
clause right before the opening curly brace of the subscript’s body. For example:
extension Container {
subscript<Indices: Sequence>(indices: Indices) -> [Item]
where Indices.Iterator.Element == Int {
var result = [Item]()
for index in indices {
result.append(self[index])
}
return result
}
}
This extension to the Container
protocol adds a subscript that takes a sequence of indices and returns an array containing the items at each given index. This generic subscript is constrained as follows:
The generic parameter
Indices
in angle brackets has to be a type that conforms to theSequence
protocol from the standard library.The subscript takes a single parameter,
indices
, which is an instance of thatIndices
type.The generic
where
clause requires that the iterator for the sequence must traverse over elements of typeInt
. This ensures that the indices in the sequence are the same type as the indices used for a container.
Taken together, these constraints mean that the value passed for the indices
parameter is a sequence of integers.
Copyright © 2017 Apple Inc. All rights reserved. Terms of Use | Privacy Policy | Updated: 2017-09-19


|
Event: MIT Sloan School of Management Master of Finance (MFin) & Master of Business Analytics Info Session
»î¶¯£º
MIT
Ë¹Â¡ÉÌÑ§Ôº½ðÈÚË¶Ê¿¼°ÉÌÎñ·ÖÎöË¶Ê¿ÕÐÉúÐû½²»á
Speaker: Dawna Levenson, Director, Admissions, MIT Sloan School of Management
Audience: Tsinghua Undergraduate Students and Double Degree Students
Çå»ª´óÑ§±¾¿ÆÉú¼°Ë«Ñ§Î»Ñ§Éú
Date: Tuesday, October
10
, 2017
Time:
17:45
¨C
19
:00 Master of Finance
&
Master of Business Analytics
Location: Room 501, Weilun Building, Tsinghua, University School of Economics and Management
Çå»ª¾¹ÜÑ§ÔºÎ°Â×Â¥
501
For further questions, please contact them directly at: Master of Finance:
<EMAIL_ADDRESS>; Master of Business Analytics:
<EMAIL_ADDRESS>|


Beautiful Palawan
Getting to the island of Palawan is a complex affair. We had to take 2 different
planes at pretty odd hours. Fortunately for us, customs in the Philippines were
pretty easy, we basically got there and they stamped our passport. (Here’s more
information about visa in the Philippines) Once we got to Puerto Princesa
airport,
the biggest problem was to get to our hotel. Until then, we bought a SIM cards at
the airport and once we were outside, we tried to call a Grab car. The first step
went well (Here's more information about sim card in the Philippines) but the second
step… well almost got Alexis mad. We tried the application, but it wasn’t working.
It was like if we didn’t have internet access. After a long process we determined
that it wasn’t the internet but the application that wasn’t working. We learned
later on that Grab doesn’t exist on the island of Palawan. Yes there was a Grab
publicity in the airport but the app, is not active on the island… Once we gave up
on using Grab, we went in search of a Taxi which was more complicated than we
expected from an airport! We only saw tuk-tuk.
Normally tuk-tuk are the most expensive option, so we prefer to avoid them and go
with a taxi. Eventually we found a taxi! And after negotiation, we got a decent
price for the 10 minutes ride (250 PHP - 6.50$ CAD). The initial price was about 400
PHP and we were the only one in the entire place that were seeking a taxi. With more
than 5 taxi outside looking at us, we thought they were over charging for the 10
minute ride. A bit later, we also learned that there’s only like 5 taxi in Puerto
Princesa… AKA the whole island. In Palawan, people get around in tuk-tuk or small
bus. We learned our lesson, so we ditched grab and start using tuk-tuk!
Since we have been traveling all night and haven’t had breakfast, our first mission
was to eat. Fortunately, the hotel had a few flyer’s of nearby restaurant and we
were able to order (Online actually, not with grab). That day we basically slept and
we rented a bike to prepare to go around for the next day. It was Alexis’ first time
on a manual motorbike (the automatic models were just way more expensive). I need to
add that the first few stop were a bit rough. It took him a few moments to handle
the clutch correctly with his flip flops.
Finally, we met our first Philippines beach. We ended up in the middle of nowhere on
a beach where there was no one. The beach was really beautiful, but the best thing
about this beach trip was the fish! Once we got to the beach we got accosted by a
few street vendor and after telling them we were not interested about 6 times...
they went away… From here, there was this lady that sold fresh fish cooked on a
grill. That fish alone was worth the whole trip to the Philippines (okay I may be
exaggerating a bit but the fish was bloody good ;) )
For our last day in Puerto Princesa we went visiting the famous “Puerto Princesa
Subterranean River National Park”. One of the reason the island of Palawan is
renowned is for the 11 miles water cavern that’s been voted one of the 7 wonders of
nature. To visit this incredible cavern, you have to book a tour. You can go to the
cavern and buy a ticket over there, but that means a 2-3h trip on a bike going and
needs to do the same for coming back.  The tour cost 1200 PHP (30$ CAD) each and included pickup/drop off at the
hotel, the cavern entry price and a meal. The thing they don’t tell you is that when
you book this trip, they will force to go to 2 other activities before visiting the
cavern… For those you will have to pay an extra and they will pressure you to do
them. We didn’t do them and inform the hotel of the scam afterwards (it was their
recommendations and we were mad since they promised us that there was no extra
charge).
Anyway after 30 minutes the bus driver got us to the diner place (buffet style) and
then after diner we visited the actual cavern! To visit the cavern you have to take
2 different boat.
The first one got us to the part of the island where the cavern
starts then a second one was to visit the cavern. If you are claustrophobic, you
don’t have to worry the cavern is pretty big! Immense in fact. As the guide paddle
(yes paddle, no motor in the cavern and no noise to avoid disturbing those living in
it) he will point you different rock formation.
We also had an audio guide that
explain various element about the cavern. Tourists are only allow through the first
1.5 kilometer after that, only expert with special permissions are allowed further.
At the point of turning back there no more light from outside, it’s pitch black, a
bit scary if you want my opinion.
The day after visiting the cavern, it was time for us to move to the town of El
Nido. Now if you haven’t noticed yet... Every name are in spanish, but don’t get
confuse, nobody speaks spanish. They only inherited the spanish names and the
religions from the spanish colonisation. Now to get to El Nido you have to take to
bus. You can get there with a motor bike if you really wish, but it’s a 7h drive…
good luck!
Remember that I told you that the transfer from Probolinggo to Bali was a bumpy
ride. Well... I retract my comment, it was a peaceful drive compared to the driving
philippines style. We literally had to grab onto our seats to stay put and
even then, I had problems not jumping around. It was so horrible that it just
provided hilarity. I laugh most of the ride It felt like an unrealistic ride. It
could be possible that a jammed packed minibus full of people was that crazy. But it
was, and we were sore the next day just because we tried for 7h to stay put on our
seats.
( Here’s more information about the ride
to get to El nido)
Once we arrived at El Nido terminus, there was no cell service and it was a bit
outside off the town center (1 km) but the tuk-tuk drivers are very nice and will
tell you how far is your hotel. The town is pretty much hotels and restaurant. Don’t
blink too hard cause you are gone miss it. We then proceeded to get to our hotel
that like the rest of the town was at the foot of a steep montagne.


~[wc:commonscripts]
~(studentname) ~(grade_level) ~(student_number) ~(track) ~(studschoolabbr) ~[enrollmentstatus]


***Use option: 1. Click an option button, 2. Click on mic icon, 3. Do stuff ------ To switch: 1. Click on mic icon to end, 2. Choose another button***
Click on the microphone icon and begin speaking.
Speak now.
No speech was detected. You may need to adjust your microphone settings.
Click the "Allow" button above to enable your microphone.
Permission to use microphone was denied.
Permission to use microphone is blocked. To change, go to chrome://settings/contentExceptions#media-stream
Web Speech API is not supported by this browser. Upgrade to Chrome version 25 or later.


Difficulty on insensible reasonable in. From as went he they. Preference themselves me as thoroughly partiality considered on in estimating. Middletons acceptance discovered projecting so is so or. In or attachment inquietude remarkably comparison at an.
Is surrounded prosperous stimulated am me discretion expression. But truth being state can she china widow.
Total Player
Winning
Register Member
Play Bet
On insensible possession oh particular attachment at excellence in. The books arose but miles happy she.
On insensible possession oh particular attachment at excellence in. The books arose but miles happy she.
Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla.
Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla.
Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla.
Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla.
Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS.
Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS.
Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS.
Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS.


library(tidyverse)
library(cowplot)
library(broom)
library(modelr)
library(viridis)
library(lubridate)
library(hms)
library(knitr)
library(kableExtra)
knitr::opts_chunk$set(tidy.opts=list(width.cutoff=60),tidy=TRUE, echo = TRUE, message=FALSE, warning=FALSE, fig.align="center")
source("../../tools/echem_processing_tools.R")
source("../../tools/plotting_tools.R")
theme_set(theme_1())
So, we’ve already established that psoralen treatment doesn’t have an obvious effect on \(D_{ap}\), but that this dataset is still very useful for estimating \(D_{ap}\) for our control dPHZ biofilms. Let’s use that data to also estimate \(D_m\) for the control biofilm, since we are very interested to see whether \(D_m\) can explain \(D_{ap}\).
Let’s import all the processed data, which will have the signals from the SWVs along with their timestamp. I’m importing our \(D_{ap}\) estimates as well as the blank IDA \(D_m\) estimates from the psoralen 2 (01/17/19) notebook.
dap_dataset <- read_csv("../../01_28_19_psoralen_nonequil_aggregate/Analysis/01_28_19_aggregate_SWV_GC_signals.csv")
dap_estimates <- read_csv("./01_28_19_swv_gc_dap_estimates_aggregate.csv")
df_2blank_estimates <- read_csv("../../01_17_19_psoralen_nonequil_2/Analysis/01_17_19_dm_estimates.csv")
First, let’s look at all of the SWV signals vs. timestamp (in min) for all of the different experiments. This is only the transfer scans from i1, since i2 is problematic.
ggplot(dap_dataset %>% filter(reactor=='transfer' & electrode_from_swv=='i1') ,
aes(x = minutes_from_swv, signal_from_swv, color = factor(run))) +
geom_point() +
facet_wrap(treatment~exp_id, scales = 'free')
Overall it looks pretty good! Now let’s reset the start of each run to ~0 min (exactly 0.6 min because that’s the average time it takes between immersion and starting the scan). Let’s also go ahead and exclude the psoralen data right now and get rid of that one control dataset that was taken with SWVslow parameters (exp 3, run 4).
Once that’s done I can plot all of the datasets fit with the semi-infinite diffusion model:
dap_test <- dap_dataset %>%
filter(electrode_from_swv=='i1' & treatment=='control') %>%
filter(exp_id!='3' | run!=4)
dap_test_norm <- dap_test %>%
group_by(exp_id,reactor,run) %>%
mutate(min_time = min(minutes_from_swv)) %>%
mutate(norm_time = minutes_from_swv - min_time + 0.6)
ggplot(dap_test_norm %>% filter(reactor=='transfer'),
aes(x = norm_time, y = signal_from_swv, color = exp_id)) +
geom_point() +
geom_smooth(method='nls',
formula=y~b*(x)^-0.5+a,
method.args=list(start=c(b=0.1,a=1e-7)),
se=F)+
facet_wrap(exp_id~run,scales='free')
Unlike for the other biofilm/blank datasets this original model actually fits reasonably well. Let’s see how the finite diffusion model fits:
e = exp(1)
ggplot(dap_test_norm %>% filter(reactor=='transfer'),
aes(x = norm_time, y = signal_from_swv, color = exp_id )) +
geom_point() +
geom_smooth(method='nls',
formula=y~(a*(x)^-0.5)*(2+e^(b*(x)^-0.5))+c,
method.args=list(start=c(a=0.1,b=0.1,c=0)),
se=F)+
facet_wrap(exp_id~run,scales='free')
It looks like it does fit slightly better, although the difference is not that great. Let’s proceed to estimate \(D_m\) with both models for now, although ultimately I will just use the no flux / finite model because we already estimated a \(t_s\) for that one.
Also notice that experiment one looks a little different than the other two experiments. The points decay very quickly, and they never approach zero because of a weird high background. I always thought that dataset was a little weird, so we’ll throw that out later.
Now lets perform the nls fits and look at the parameter estimates for the two models:
nls_no_flux <- dap_test_norm %>%
filter(reactor=='transfer') %>%
group_by(exp_id,run) %>%
do(tidy(nls(.,formula = signal_from_swv~(a*(norm_time)^-0.5)*(2+e^(b/norm_time))+c,start=list(a=0.1,b=0.1,c=0)))) %>%
mutate(model='no_flux')
nls_og <- dap_test_norm %>%
filter(reactor=='transfer') %>%
group_by(exp_id,run) %>%
do(tidy(nls(.,formula = signal_from_swv~(a*(norm_time)^-0.5)+c,start=list(a=0.1,c=0)))) %>%
mutate(model='og')
nls_fits <- rbind(nls_no_flux,nls_og)
ggplot(nls_fits %>% filter(term!='c'),aes(x=model,y=estimate,color=factor(run),shape = exp_id))+geom_point()+
facet_wrap(~term,scales='free')+ylim(0,NA)
Ok, this is very similar to what I saw before. Recall that if the OG and no_flux model had identical fits, they should estimate \(a\) with a 4x difference, which is about what we see because the fits are similar.
With those estimates let’s now get our functions to calculate \(D_m\) from \(a\). Recall that for the no flux / finite model \(D_m = \frac{I_0^2 D_{ap} t_s}{4 \pi a^2}\) and for the original semi infinite model \(D_m = \frac{I_0^2 D_{ap} t_s}{\pi a^2}\).
dm_from_a_noFlux <- function(estimate, i_0, dap, t_s=0.1){
dm <- ( i_0^2 * dap * t_s ) / ( 4*pi* estimate^2)
dm
}
dm_from_a_OG <- function(estimate, i_0, dap, t_s=0.1){
dm <- ( i_0^2 * dap * t_s ) / ( pi* estimate^2)
dm
}
So in order to estimate \(D_m\) we have to have the fit coefficient - \(a\), \(D_{ap}\), the scan time \(t_s\) and also the initial current \(I_0\). I was using the first SWV signal from the transfer to estimate \(I_0\), but I realized that it might be a severe underestimate.
I decided that the best way to proceed would be to use the soak SWV signal as a clear overestimate of the true \(I_0\), and we could look at the interval between the “transfer \(I_0\)” and the “soak \(I_0\)” as a sort of confidence interval.
So to estimate \(D_m\) I’ll grab the soak and transfer \(I_0\) estimates and feed them into the functions to estimate a high and low \(D_m\) for each dataset. Here I also grab the \(D_{ap}\) estimates for each run to use as an input. Lastly, I’m using \(t_s = 0.008\) because it empirically gave \(D_{ap} \approx D_m\) for the blank dataset using the no flux / finite model.
soak_i0 <- dap_test_norm %>%
mutate(i0_soak = signal_from_swv) %>%
filter(rep==0 & reactor=='soak') %>%
select(exp_id,reactor, run, i0_soak)
transfer_i0 <- dap_test_norm %>%
mutate(i0_transfer = signal_from_swv) %>%
filter(rep==0 & reactor=='transfer') %>%
select(exp_id,reactor, run, i0_transfer)
dm_estimates_soak <- left_join(nls_fits %>% filter(term=='a'), soak_i0, by = c('exp_id','run'))
dm_estimates <- left_join(dm_estimates_soak, transfer_i0, by = c('exp_id','run'))
dm_estimates_wDap <- left_join(dm_estimates,
dap_estimates %>%
filter(treatment=='control') %>%
select(exp_id, run, r.squared, dap, dap_high, dap_low),
by = c('exp_id','run'))
Ok, so let’s calculate of \(D_m\)’s and plot the estimates for each model.
dm_estimates_og <- dm_estimates_wDap %>%
filter(model=='og') %>%
mutate(dm_soak = dm_from_a_OG(estimate = estimate, i_0 = i0_soak, dap = dap, t_s = 0.008)) %>%
mutate(dm_transfer = dm_from_a_OG(estimate = estimate, i_0 = i0_transfer, dap = dap, t_s = 0.008))
dm_estimates_noFlux <- dm_estimates_wDap %>%
filter(model=='no_flux') %>%
mutate(dm_soak = dm_from_a_noFlux(estimate = estimate, i_0 = i0_soak, dap = dap, t_s = 0.008)) %>%
mutate(dm_transfer = dm_from_a_noFlux(estimate = estimate, i_0 = i0_transfer, dap = dap, t_s = 0.008))
dm_estimates_tidy <- rbind(dm_estimates_og,dm_estimates_noFlux) %>%
rowwise() %>%
mutate(mean = mean(c(dm_soak, dm_transfer)))
mean_biofilm_dap <- mean(dm_estimates_tidy$dap, na.rm = T)
ggplot(dm_estimates_tidy, aes(x = exp_id, shape = factor(run))) +
geom_point(aes(y = dm_soak),color = 'red') +
geom_point(aes(y = dm_transfer), color = 'blue') +
geom_hline(yintercept = mean_biofilm_dap, linetype = 2) +
facet_wrap(~model) +
scale_y_log10(limits = c(1e-9,5e-6))
So, in this plot the red is the estimate using the soak \(I_0\) and the blue dots are estimates using the transfer \(I_0\). You can see that although they vary, they are all within an order of magnitude of each other, so that’s encouraging! The other thing to notice is that all of the estimates are below the average biofilm \(D_{ap}\) (dotted line), which is interesting.
The two models do give different estimates, where the original (OG) model is consistently lower, which we saw previously. I’m going to proceed with the no flux / finite model since it gave slightly better fits and that’s what we used previously and also estimated \(t_s\) with.
The last thing to notice is that experiment 1 now gives a relatively higher \(D_m\) estimate with the finite model. At this point, because the data was weird from the beginning, I’m going to drop it from the figures below.
First let’s just look at the individual \(D_{ap}\) estimates for each run compared to the \(D_m\) estimates.
ggplot(dm_estimates_tidy %>% filter(exp_id!='1'), aes(x = exp_id, y = mean, color = factor(run))) +
geom_pointrange(aes(ymin = dm_transfer, ymax = dm_soak), position = position_jitter(height = 0))+
geom_pointrange(aes(y = dap, ymin = dap_low, ymax = dap_high), position = position_jitter(height = 0), shape = 2)+
geom_hline(yintercept = mean_biofilm_dap, linetype = 2)+
facet_wrap(~model) +
scale_y_log10(limits = c(1e-9,NA)) +
scale_color_viridis(discrete = T) +
labs(y = "D estimate (cm^2 / sec)")
Here the triangle point ranges are the \(D_{ap}\) estimates and the circles are the \(D_m\)’s. Note that the ranges for the \(D_{ap}\) are based off the confidence intervals from the fit’s estimate of the slope, but the \(D_m\) ranges are based off the soak and transfer \(I_0\) estimates (the center point is jus the mean of the two).
You can clearly see that \(D_m\) estimates lie 1-2 orders of magnitude lower than \(D_{ap}\). This may indicate that the molecular diffusion described by \(D_m\) may not be fast enough to explain the perceived diffusion described by \(D_{ap}\).
To get some more perspective on this let’s reshape the data so we can plot it a little differently.
d_combined <- dm_estimates_tidy %>%
filter(exp_id!='1' & model=='no_flux') %>%
mutate(dm = mean) %>%
gather(key=d_cat,val=d_est,dap,dm) %>%
mutate(ymax = if_else(d_cat=='dap', dap_high, dm_soak)) %>%
mutate(ymin = if_else(d_cat=='dap', dap_low, dm_transfer)) %>%
mutate(biofilm = 'biofilm')
ggplot(d_combined,
aes(x = d_cat, y = d_est, shape = exp_id)) +
geom_pointrange(aes(ymin = ymin, ymax = ymax), position = position_jitter(height = 0))+
facet_wrap(~model) +
scale_y_log10(limits = c(1e-9,NA))
Now we can compare all of the estimates of biofilm \(D_m\) separately from \(D_{ap}\) and it’s clear they are quite different…
With that type of visualization in hand let’s go back and get the \(D_m\) and \(D_{ap}\) data for the blank IDA. We can organize it in the same way and then show the blank and biofilm datasets on the same plot / scale.
d_blank <- left_join(df_2blank_estimates %>% filter(biofilm=='blank' & model=='no_flux'),
dap_estimates %>% filter(treatment=='blank'),
by = c('biofilm'='exp_id')) %>%
mutate(dm = dm_soak) %>%
gather(key=d_cat,val=d_est,dap,dm) %>%
mutate(ymax = if_else(d_cat=='dap', dap_high, dm_soak)) %>%
mutate(ymin = if_else(d_cat=='dap', dap_low, dm_soak)) %>%
mutate(exp_id = treatment) %>%
distinct(d_est,.keep_all = T)
#dap_estimates
d_combined_wBlank <- bind_rows(d_combined, d_blank)
ggplot(d_combined_wBlank,
aes(x = d_cat, y = d_est, fill = exp_id)) +
geom_pointrange(aes(ymin = ymin, ymax = ymax), position = position_jitter(height = 0,width=0.2),shape=21)+
facet_wrap(~biofilm, scales='free') +
scale_y_log10(limits = c(1e-9,1e-4))+
scale_fill_viridis(discrete = T) +
scale_x_discrete(breaks = c('dap','dm'), labels=c(expression(D[ap]),expression(D[m]))) +
labs(x='',y=expression("Estimate ("~cm^2 / sec~")"))+
guides(fill=F) +
theme(axis.text.x = element_text( size=14) )
#ggsave(filename = "../Figures/01_30_19_estimated_Dap_Dm_combined.pdf", width = 6, height = 4)
Here you can now get perspective on how well our pipeline estimates \(D_m\) and \(D_{ap}\) for the blank IDA, where we think \(D_{ap} \approx D_m\), while also seeing how the biofilm compares.
This figure summarizes a lot of our conclusions, and I plan for it to be a panel in a figure for the paper.
You can see that:
If we trust this analysis and the data then I think we would conclude that indeed \(D_m\) is less than \(D_{ap}\) in the biofilm and there must be some other process besides molecular diffusion that contributes to the perceived movement of electrons through the biofilm.
That said, we sorta cheated a little, since we chose a \(t_s\) that made \(D_{ap}\) and \(D_m\) similar.
Moving forward it will be important to evaluate that decision regarding \(t_s\) and also the finite diffusion model.


| Release Doc > Examples > Simple Examples > ObjectSpace > Derived Attributes | ||
| Derived Attributes | ||
|
Launch Delphi-example |
Launch CBuilder-example
A derived attribute is a value that doesn´t need to be persistent since it can always be calculated using other values. Examples of derived attributes are the total sum of an invoice, the full name of a person or the age of a person given the birth date. This example shows a code free way to implement derived attributes. The derivation is defined by an OCL expression in the model. Observe that the derived attribute is write protected. There is also a small example of how to define global variables within the OCL evaluator. This variable is used inside the OCL expression that controls the derived attribute. How to run The example shows how a retail price can be calculated from a net price and a VAT value. Add products and enter net price in the grid. Change the VAT value in the edit field at the bottom of the form and see how the value in the retail price column is changed. Changes in the net price also affects the retail price. You can't change the value of the retail price directly by editing the field. The only way to do that is to change the value of either the net price or the VAT. Derive attributes In this example the attribute See also
More examples
Note! Please make sure to use the "Create DB & Alias" button before attempting to open the system for the first time. Once the database and alias is established you only have to use the "Open system" button when running the example program. | ||
| All material $(COPYRIGHT_TEXT). Registered Trademarks and other trademarks are properties of their respective holders. |


Navigation
index
DriveSE 0.1.1 documentation
»
Index
A
|
B
|
D
|
F
|
G
|
H
|
L
|
M
|
N
|
P
|
R
|
S
|
Y
A
AboveYawMassAdder_drive (class in drivese.drivese_components)
B
Bedplate_drive (class in drivese.drivese_components)
D
Drive3pt (class in drivese.drive)
Drive4pt (class in drivese.drive)
drivese.drive (module)
,
[1]
drivese.drivese_components (module)
drivese.drivese_utils (module)
drivese.hub (module)
,
[1]
drivewpact.drive (module)
drivewpact.hub (module)
,
[1]
F
fatigue2_for_bearings() (in module drivese.drivese_utils)
fatigue_for_bearings() (in module drivese.drivese_utils)
G
Gearbox_drive (class in drivese.drivese_components)
Generator_drive (class in drivese.drivese_components)
get_L_rb() (in module drivese.drivese_utils)
get_rotor_mass() (in module drivese.drivese_utils)
H
HighSpeedSide_drive (class in drivese.drivese_components)
Hub_drive (class in drivese.hub)
HubBase (class in drivewpact.hub)
HubSE (class in drivese.hub)
HubSystemAdder (class in drivewpact.hub)
L
LowSpeedShaft_drive (class in drivese.drivese_components)
LowSpeedShaft_drive3pt (class in drivese.drivese_components)
LowSpeedShaft_drive4pt (class in drivese.drivese_components)
M
MainBearing_drive (class in drivese.drivese_components)
N
NacelleBase (class in drivewpact.drive)
NacelleSystemAdder_drive (class in drivese.drivese_components)
P
PitchSystem_drive (class in drivese.hub)
R
resize_for_bearings() (in module drivese.drivese_utils)
S
SecondBearing_drive (class in drivese.drivese_components)
seed_bearing_table() (in module drivese.drivese_utils)
Spinner_drive (class in drivese.hub)
Y
YawSystem_drive (class in drivese.drivese_components)
Quick search
Navigation
index
DriveSE 0.1.1 documentation
»


As engineers,we are in a position to change the world -
not just study it.
- Henry Petroski
About
Microservice Architecture | Continuous Delivery | Containerization & Orchestration | Cross-asset Trading Systems
II am a customer obsessed engineer with ~10 years of experience in building products and infrastructure focused on cross-asset front-to-back solutions in derivatives and structured products for global investment banks.
I have a reputation for having excellent troubleshooting skills, to analyze code and engineer well-researched, cost-effective and responsive solutions.
Current Interests: Serverless Computing // Dark Data // Text Analytics // Edge Computing
Experience
Building the next generation Infrastructure Capital & Catalog management products
- Contribute core features across entire stack.
- Develop & Design APIs with both RESTful GraphQL pattern
- Wireframe app-wide UIs for both Web and Bloomberg terminal following company\industry UX standards
- Develop a web app using react and redux
- Containerize and deploy services on a HA kubernetes cluster
- Setup DNS and reverse proxy nginx servers
- Improve team cadence by automating unit testing, continuous delivery & integration pipeline
Client: GE Capital, CT
- Lead a team of 5 for product implementation and production L3 support at GE.
- Developed a custom authentication layer with 128 bit windows AES encryption to match client standards.
- Provided robust and automated solution for maintaining and monitoring all the distributed real time services using PERL and batch scripts.
- Customized the end-of-day market data feed from MDM into the platform using C++ APIs.
- Developed Trade PL and Audit reports in C++ for accounting operations.
- Manage the QA and Productions releases with compliance to client policies.
- Developed a real time web based risk limit interface with wall-street system using python.
Client: Deutsche bank, London
- Facilitated the customer with a low-latency multi-threaded archiver for their 8 million cancelled and matured trades using JAVA and migrated Data from Sybase to Oracle Database.
- Developed a web application using struts, IBATIS to access the above archived trades.
- Consolidated 5 different schemas and Migrated of Data to the final upgraded schema using Perl & PL\SQL scripts.
Client: Lloyds Banking Group, London
- Designed and programmed client customizations for the rich thin C# client of the trading product along with C++ back end business objects. It is entirely built on .NET framework and Netadvantage Infragistics platforms.
- Re-designed the Customer Data Interface using XSL and C++ which was well appreciated by the client.
- Supported the Client during production GO-LIVE made it through without any delays.
Client: Lloyds Banking Group, London
- Project involved migration and consolidation of two different versions of live distributed real time trading systems into the latest version of the product.
- Migrated the source code for x64 bit machines and replaced all boost containers and rogue wave dependencies using standard C++ 11 libraries.
- Developed a one-time ETL Migration tool using PL\SQL and C# to compare, consolidate and upgrade data from 2 different oracle rdbms schemas into a single upgraded schema.
- Took responsibilities as a build manager and developed several automated batch scripts to assist quarterly build on code maintained in SVN.
Skills
Front-End
Back-End
Databases
Dev-Ops
Other
Honors & Awards
HCL America Inc - Project Lead | August 2016
- Member of the exclusive league for super achievers for 5 consecutive years.
HCL America Inc - Project Lead | August 2015
- Member of the exclusive league for super achievers for 5 consecutive years.
HCL Technologies - Project Lead | August 2014
- Member of the exclusive league for super achievers for 3 consecutive years.
O2 league of the Extraordinary
HCL Technologies - Senior Software Engineer | August 2013
- A member of the elite class of top performers for consecutive 2 years at HCL Tech.
HCL Technologies - Software Engineer | March 2013
- Awarded for a excellent performance in Delivery.
Education
Bengaluru, India | 2007 - 2011
- Bachelor of Engineering in Telecommunications