aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Graphics/users.png
blob: 805700c669160d6416fdf0bda344df73f5a603b0 (plain)
ofshex dumpascii
0000 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 00 00 02 55 00 00 01 47 08 06 00 00 00 88 f0 b9 .PNG........IHDR...U...G........
0020 bf 00 00 00 04 73 42 49 54 08 08 08 08 7c 08 64 88 00 00 00 09 70 48 59 73 00 00 5c 46 00 00 5c .....sBIT....|.d.....pHYs..\F..\
0040 46 01 14 94 43 41 00 00 00 19 74 45 58 74 53 6f 66 74 77 61 72 65 00 77 77 77 2e 69 6e 6b 73 63 F...CA....tEXtSoftware.www.inksc
0060 61 70 65 2e 6f 72 67 9b ee 3c 1a 00 00 20 00 49 44 41 54 78 9c ec dd 79 98 1c 55 b9 3f f0 ef 7b ape.org..<.....IDATx...y..U.?..{
0080 ba 67 c9 ca 92 84 84 99 ee 9e 99 10 44 09 a0 10 82 22 8a 22 70 59 14 81 64 a6 21 41 e0 72 51 b8 .g..........D...."."pY..d.!A.rQ.
00a0 88 8a 5e 05 dc 89 28 0a 8a 8a 0b 22 82 a0 6c c1 9e 99 60 0c 02 22 18 15 64 33 a0 22 83 4a 42 66 ..^...(...."..l...`.."..d3.".JBf
00c0 7a 99 21 2b 90 10 92 59 ba cf fb fb 23 83 bf 80 59 66 a9 ea d3 55 f5 fd 3c 0f 3e 92 4c de f3 0d z.!+...Y....#...Yf...U..<.>.L...
00e0 53 53 f5 76 d5 a9 73 04 44 44 8e 4c cb bc 30 25 86 d2 0c 63 6c a3 a8 36 aa 48 12 8a a9 00 26 41 SS.v..s.DD.L..0%...cl..6.H....&A
0100 31 09 82 49 00 6a 07 bf 7c 37 00 06 80 05 b0 61 f0 d7 7a a1 58 0f c1 7a 00 eb 01 ac 12 d5 bc 8a 1..I.j..|7.....a..z.X..z........
0120 74 59 63 ba b4 cf ac e8 99 5f b7 ae ec 7f 31 22 8a 24 71 1d 80 88 a2 a1 71 61 67 63 31 1e 3f 42 tYc......_....1".$q.....qagc1.?B
0140 a0 07 03 38 68 f0 9f a9 65 18 7a 15 80 bf 03 f8 9b 42 fe 5a 65 06 1e ee 9c 3b 3d 5b 86 71 89 28 ...8h...e.z......B.Ze....;=[.q.(
0160 62 d8 54 11 91 2f 1a 17 76 36 96 aa 62 c7 43 e5 7d 80 1e 01 a0 ce 75 a6 6d 74 03 f8 93 40 7f 17 b.T../..v6..b.C.}.....u.mt...@..
0180 33 a5 fb d8 64 11 91 17 d8 54 11 91 37 54 a5 a1 2d 7b b8 15 33 57 55 4e 14 e8 9b 5d 47 1a 32 c1 3...d....T..7T..-{..3WUN...]G.2.
01a0 3f a0 b8 c7 aa 69 ef 6e a9 7f 0c 22 ea 3a 12 11 05 0f 9b 2a 22 1a 95 54 26 3b 4b 8d cc 07 d0 02 ?....i.n...".:.....*"..T&;K.....
01c0 45 d2 75 1e 0f e4 00 b4 1a b1 b7 67 9b 1b ff e2 3a 0c 11 05 07 9b 2a 22 1a b6 19 b7 2d 9f d8 5f E.u........g....:.....*"....-.._
01e0 5d 7d ba 42 ce 87 e0 10 d7 79 7c f4 ac 40 6f b1 6a 6e 28 a4 93 2f ba 0e 43 44 95 8d 4d 15 11 0d ]}.B.....y|..@o.jn(../..CD..M...
0200 59 a2 2d bf af 40 3f 05 c5 59 00 c6 b9 ce 53 46 af 02 f8 99 aa 5c 53 48 27 57 b8 0e 43 44 95 89 Y.-..@?..Y....SF.....\SH'W..CD..
0220 4d 15 11 ed 52 7d a6 70 b8 81 bd 04 82 0f 62 eb b2 06 51 65 01 fc 52 45 be 59 68 4e 3e ee 3a 0c M...R}.p......b...Qe..RE.YhN>.:.
0240 11 55 16 36 55 44 b4 43 89 b6 fc 41 a2 f8 22 a0 2d ae b3 54 1c c5 03 30 f8 5c be 39 b5 cc 75 14 .U.6UD.C...A..".-..T...0.\.9..u.
0260 22 aa 0c 6c aa 88 e8 3f d4 df 59 78 93 31 f6 2a 08 4e 06 cf 13 3b a3 00 ee 52 95 4b f9 58 90 88 "..l...?..Yx.1.*.N...;...R.K.X..
0280 78 b2 24 a2 7f 6b bc ab 73 f7 62 31 fe 59 81 7e 12 40 8d eb 3c 01 32 a0 90 eb aa b5 ff cb 2b d3 x.$..k..s.b1.Y.~.@..<.2.......+.
02a0 fb 6c d8 f5 97 13 51 18 b1 a9 22 22 00 40 2a 93 3d 53 45 be 0d 60 8a eb 2c 01 b6 5a 21 9f 2e b4 .l....Q..."".@*.=SE..`..,..Z!...
02c0 24 6f 77 1d 84 88 ca 8f 4d 15 51 c4 35 2e ec 6c 2c c5 62 3f 86 e0 38 d7 59 42 e4 de b8 29 5e c0 $ow.....M.Q.5..l,.b?..8.YB...)^.
02e0 95 da 89 a2 25 ca 6f f1 10 45 9b aa 24 33 b9 0b 4a f1 d8 33 6c a8 3c 77 42 d1 c6 9f 49 b5 66 cf ....%.o..E..$3..J..3l.<wB...I.f.
0300 77 1d 84 88 ca 87 77 aa 88 22 68 5a e6 85 29 55 32 70 23 80 0f ba ce 12 7a 8a df c4 50 fa ef ae w.....w.."hZ..)U2p#.....z...P...
0320 74 d3 2a d7 51 88 c8 5f 6c aa 88 22 26 95 c9 1e ab 22 b7 02 98 ea 3a 4b 84 bc 60 d4 7e 28 9b 6e t.*.Q.._l.."&...."....:K..`.~(.n
0340 fc 9d eb 20 44 e4 1f 3e fe 23 8a 0a 55 49 b5 66 2f 55 91 7b c1 86 aa dc f6 b6 62 ee 4f b5 66 17 ....D..>.#..UI.f/U.{......b.O.f.
0360 40 95 1f 66 89 42 8a 3f dc 44 11 30 79 f1 da 09 63 fa b7 fc 1c c0 a9 ae b3 44 9d 42 da fa b4 e6 @..f.B.?.D.0y...c........D.B....
0380 9c b5 e9 bd 36 b9 ce 42 44 de 62 53 45 14 72 c9 85 b9 3a c4 b0 24 e4 1b 1f 07 cd d3 a5 62 ec 03 ....6..BD.bSE.r...:..$.......b..
03a0 3d f3 ea f3 ae 83 10 91 77 d8 54 11 85 58 22 93 3f 50 44 ef 06 90 72 9d 85 fe 43 8f 11 fb 81 6c =.......w.T..X".?PD...r...C....l
03c0 73 e3 5f 5c 07 21 22 6f b0 a9 22 0a a9 44 6b fe bd 06 f6 57 0a 99 e0 3a 0b ed d0 06 00 27 e5 5b s._\.!"o.."..Dk....W...:.....'.[
03e0 52 0f b9 0e 42 44 a3 c7 89 ea 44 21 94 c8 e4 8f 17 e8 3d 6c a8 2a de 6e 00 ee 4b b6 e5 b8 4e 18 R...BD....D!......=l.*.n..K...N.
0400 51 08 b0 a9 22 0a 99 44 26 7f aa 88 2e 06 30 c6 75 16 1a 92 b1 50 2c 4e b6 e6 4e 76 1d 84 88 46 Q..."..D&.....0.u....P,N..Nv...F
0420 87 8f ff 88 42 24 d9 96 3b 0e 8a c5 e0 66 c8 41 34 20 d0 39 b9 96 86 bb 5d 07 21 a2 91 61 53 45 ....B$..;....f.A4..9....].!..aSE
0440 14 12 a9 d6 ec d1 0a b9 1b 40 ad eb 2c 34 62 fd 10 7c 30 df 9c fa 8d eb 20 44 34 7c 6c aa 88 42 .........@..,4b..|0......D4|l..B
0460 a0 3e 53 38 dc 88 fd 2d 80 71 ae b3 d0 a8 6d 52 91 63 0a cd c9 c7 5d 07 21 a2 e1 61 53 45 14 70 .>S8...-.q....mR.c....].!..aSE.p
0480 a9 f6 ec 74 6b f1 a8 40 f6 72 9d 85 3c b3 4e 55 0e 2f a4 93 2b 5c 07 21 a2 a1 e3 44 75 a2 00 ab ...tk..@.r..<.NU./..+\.!...Du...
04a0 5f 54 98 04 8b 7b d8 50 85 ce 64 11 bd b7 ee 8e 9e c9 ae 83 10 d1 d0 b1 a9 22 0a a8 59 d7 2f ab _T...{.P..d.............."..Y./.
04c0 32 25 7b 97 42 f6 73 9d 85 7c 31 23 1e 1f c8 60 a9 c6 5d 07 21 a2 a1 61 53 45 14 50 6b 26 ed f5 2%{.B.s..|1#...`..].!..aSE.Pk&..
04e0 1d 00 ef 76 9d 83 fc a3 22 47 25 d7 e7 af 72 9d 83 88 86 86 73 aa 88 02 28 d1 9a 3f 43 a0 b7 b9 ...v...."G%...r.....s...(..?C...
0500 ce 41 65 a2 38 3d 9f 4e fd c2 75 0c 22 da 39 36 55 44 01 93 6a cb ce 54 95 27 00 8c 75 9d 85 ca .Ae.8=.N..u.".96UD..j..T.'..u...
0520 66 93 2d 99 59 dd a7 27 9e 73 1d 84 88 76 8c 8f ff 88 02 64 c6 3d cb 6b d4 ca ed 60 43 15 35 e3 f.-.Y..'.s...v.....d.=.k...`C.5.
0540 8d b1 0b 67 66 3a aa 5d 07 21 a2 1d 63 53 45 14 20 7d 9b 6b be 0e c1 5b 5d e7 20 07 04 87 6c 30 ...gf:.].!..cSE..}.k...[].....l0
0560 13 bf e2 3a 06 11 ed 18 1f ff 11 05 44 a2 35 ff 5e 81 3e 08 7e 18 8a 32 0b e0 bd f9 96 d4 43 ae ...:........D.5.^.>.~..2......C.
0580 83 10 d1 7f 62 53 15 20 75 4b 7a c6 c6 b7 0c 34 0a b4 49 45 12 0a 99 02 60 12 80 3d 00 d9 fa 38 ....bS..uKz....4..IE....`..=...8
05a0 48 b5 0a 22 03 00 20 b0 7d 00 5e b2 30 eb a1 58 2f 46 0b d6 9a ae aa aa 81 ae ae 53 9b 5e 76 f7 H.."....}.^.0..X/F.........S.^v.
05c0 37 a1 e1 4a 64 f2 63 44 f4 69 00 33 5c 67 21 c7 04 cf c5 5e 29 bd b5 eb 9c a6 5e d7 51 68 68 66 7..Jd.cD.i.3\g!....^).....^.Qhhf
05e0 dc b3 bc 66 cb c6 31 0d 26 66 1b 21 48 88 ea 54 15 99 0c c5 1e 80 8c 07 f0 ba 73 37 44 07 a0 78 ...f..1.&f.!H..T..........s7D..x
0600 49 44 d7 03 58 0f c5 0b 2a d2 59 ea 8f 77 f5 cc af 5b e7 f0 af 42 bb c0 a6 aa 42 4d cb bc 30 a5 ID..X...*.Y..w...[...B....BM..0.
0620 4a 06 de 09 e0 30 28 0e 54 91 83 04 da e0 55 7d 85 ae 11 95 a7 61 f0 b4 aa 3c 55 65 06 1e ee 9c J....0(.T.....U}.....a...<Ue....
0640 3b 3d eb 55 7d f2 56 aa 35 7b 95 42 2e 71 9d 83 2a c6 d7 f2 2d a9 2f b9 0e 41 ff 69 7a e6 f9 dd ;=.U}.V.5{.B.q..*...-./..A.iz...
0660 fa 51 7d 38 80 c3 0c ec 41 2a f2 56 00 d3 e1 dd 1d e6 97 a0 f8 3b 0c 9e 86 e2 a9 98 94 1e ed 6a .Q}8....A*.V.........;.........j
0680 6e fa a7 47 b5 69 94 d8 54 55 88 a9 b7 ac 1a 57 5d db 7f 34 0c 8e 07 70 34 14 6f 72 10 a3 5b a0 n..G.i..TU.....W]..4...p4.or..[.
06a0 bf b7 30 f7 16 35 7e ff aa f4 de 6b 1d 64 a0 37 a8 5f 54 78 ab 29 d9 65 00 b8 08 24 bd 66 00 31 ..0..5~....k.d.7._Tx.).e...$.f.1
06c0 1c 92 9f 93 7a c6 75 90 a8 9b 71 cf f2 9a fe 2d d5 ef 56 95 13 a0 38 16 c0 4c 94 ff 11 fd 3a 00 ....z.u...q....-..V...8..L....:.
06e0 7f 54 91 fb ec 80 b9 af 67 5e 7d be cc e3 d3 20 36 55 0e cd b8 6d f9 c4 fe ea ea 93 ad 98 b4 40 .T......g^}.....6U...m.........@
0700 8f 05 50 e3 3a d3 36 2c 80 87 20 b8 a5 a6 b7 af 6d c5 87 f6 dd e8 3a 50 54 25 5b 73 bf 07 f0 1e ..P.:.6,........m.....:PT%[s....
0720 d7 39 a8 b2 28 e4 77 85 96 e4 d1 ae 73 44 51 22 93 1f 03 e0 78 11 4d 03 f8 00 80 f1 8e 23 bd d1 .9..(.w.....sDQ"....x.M......#..
0740 32 11 bd b5 cf 0c dc b9 7a ce 8c 35 ae c3 44 09 9b aa 72 53 95 44 6b e1 48 23 f6 23 0a 99 0b a0 2.......z..5..D...rS.Dk.H#.#....
0760 d6 75 a4 21 d8 02 e0 97 0a b9 b5 a0 89 fb 91 96 92 eb 40 51 91 ca 64 9b 55 a4 d5 75 0e aa 58 a7 .u.!..............@Q..d.U..u..X.
0780 e4 5b 52 8b 5d 87 88 8a 86 f6 ae 43 ac 35 1f 01 30 1f c0 44 d7 79 86 60 00 8a fb 44 f4 56 b3 c9 .[R.]......C.5..0..D.y.`...D.V..
07a0 2e e1 3c 3c ff b1 a9 2a 93 59 d7 2f ab 5a 3b 69 ca 7c 55 b9 04 c0 fe ae f3 8c c2 0b 0a b9 a6 b7 ..<<...*.Y./.Z;i.|U.............
07c0 ba f6 ba 75 27 4f 79 c5 75 98 30 6b bc b9 b3 b6 34 3e f6 2c 80 26 d7 59 a8 62 ad 98 a8 af cc ec ...u'Oy.u.0k....4>.,.&.Y.b......
07e0 48 cf ec 77 1d 24 b4 54 25 d9 96 ff 20 80 cf 01 78 bb eb 38 a3 f0 32 80 eb 06 b4 ea bb 9c da e1 H..w.$.T%.......x..8..2.........
0800 1f 36 55 3e 9b 99 e9 a8 7e 45 c6 9f ae 90 2f 02 d8 d7 75 1e 0f 6d 54 c8 75 50 7c b3 90 4e be e8 .6U>....~E..../...u..mT.uP|..N..
0820 3a 4c 18 a5 32 d9 8b 54 e4 1a d7 39 a8 c2 29 3e 9a 4f a7 ae 73 1d 23 74 16 a8 49 1d 90 7b bf aa :L..2..T...9..)>.O..s.#t..I..{..
0840 5c 06 60 96 eb 38 1e ea 53 91 9f ab c8 57 bb e7 26 0a ae c3 84 0d 9b 2a 9f 24 32 f9 31 02 bd 00 \.`..8..S....W..&......*.$2.1...
0860 82 4f 03 a8 73 9d c7 2f 02 7d 05 c0 75 c5 81 aa 6f f1 55 5f ef 0c 2e a1 b0 02 21 3e 76 c8 33 2f .O..s../.}..u...o.U_......!>v.3/
0880 a8 ca 3e 85 74 72 8b eb 20 a1 90 d1 58 d2 e4 cf 86 e2 b3 08 d7 07 e1 37 ea 53 91 9f 57 c9 c0 d7 ..>.tr......X..........7.S..W...
08a0 f9 e6 b7 77 b8 88 a0 0f 52 ad d9 a3 21 78 0a 82 6f 23 e4 17 45 85 4c 50 c8 25 b1 aa e2 73 a9 4c ...w....R...!x..o#..E.LP.%...s.L
08c0 f6 22 64 34 e6 3a 53 28 08 3e 8e 90 1f 3b e4 99 bd 8d d8 f3 5d 87 08 83 54 26 3b 2b 29 f9 47 a0 ."d4.:S(.>...;......]...T&;+).G.
08e0 f8 29 c2 dd 50 01 40 8d a8 9e 57 b4 f1 7f a4 5a b3 0b 66 dc b3 bc 92 5e 94 0a 2c de a9 f2 50 22 .)..P.@...W....Z..f....^..,...P"
0900 93 af 87 c1 37 44 f5 4c d7 59 9c 51 3c a5 46 3e 5a 68 4e 3e ee 3a 4a 50 35 de dc 59 5b 1c 6f b2 ....7D.L.Y.Q<.F>ZhN>.:JP5..Y[.o.
0920 02 d9 cb 75 16 0a 8c 17 6a c6 f5 35 ad 38 71 df 3e d7 41 82 28 75 7b 76 0f 5b 6d 16 08 f4 42 00 ...u....j..5.8q.>.A.(u{v.[m...B.
0940 51 fd 60 b8 42 55 3e 5e 48 27 ef 73 1d 24 c8 78 a7 ca 03 b3 ae 5f 56 95 6a cd 5e 2a a2 ff 8a 74 Q.`.BU>^H'.s.$.x....._V.j.^*...t
0960 43 05 00 82 43 44 f5 4f c9 d6 dc b5 8d 77 75 ee ee 3a 4e 10 d9 71 e6 2c 36 54 34 4c 7b f7 6d ae C...CD.O.....wu..:N..q.,6T4L{.m.
0980 39 c3 75 88 c0 51 95 44 26 7f ae 56 cb 73 02 fd 04 a2 db 50 01 c0 0c 11 bd 37 d9 96 bb 33 b9 30 9.u..Q.D&..V.s.....P.....7...3.0
09a0 c7 bb e4 23 c4 3b 55 a3 54 b7 b0 3b 19 8b 95 16 42 70 84 eb 2c 15 28 67 60 e7 65 5b 1a 1f 71 1d ...#.;U.T..;....Bp..,.(g`.e[..q.
09c0 24 30 54 25 d9 9e ef 80 e2 2d ae a3 50 b0 28 e4 9f 85 8e c4 4c 2c 10 eb 3a 4b 10 4c cf 3c bf 5b $0T%.....-..P.(.....L,..:K.L.<.[
09e0 bf 54 df 28 d0 66 d7 59 2a d0 7a a3 f6 ec 6c ba f1 d7 ae 83 04 0d 9b aa 51 48 b5 65 4f 52 95 9f .T.(.f.Y*.z...l.........QH.eOR..
0a00 01 d8 d3 75 96 0a 56 14 e8 15 b9 8e d4 e5 3c d9 ef 5a 43 a6 eb fd 56 cc dd ae 73 50 30 a9 ca 09 ...u..V.......<..ZC...V...sP0...
0a20 7c 7c b3 6b c9 f6 dc 6c 58 fc 02 5c ae 64 67 54 21 3f d8 4d 37 5e cc 25 3b 86 8e 8f ff 46 62 a9 ||.k...lX..\.dgT!?.M7^.%;....Fb.
0a40 c6 53 ad d9 05 aa f2 4b b0 a1 da 95 b8 42 2e 4b ee 9f ff 65 22 93 e7 7f ab 5d b0 30 9c 70 4c 23 .S.....K.....B.K...e"....].0.pL#
0a60 26 50 1e 3f 3b a3 2a a9 4c f6 22 58 3c 0c 36 54 bb 22 02 fd c4 46 4c 78 b8 21 d3 c5 ff 56 43 c4 &P.?;.*.L."X<.6T."...FLx.!...VC.
0a80 3b 55 c3 d4 98 e9 9c 56 92 d8 62 00 87 b9 ce 12 40 39 1b 33 1f ec 9e 93 f8 9b eb 20 95 28 91 c9 ;U.....V..b.....@9.3.........(..
0aa0 d7 8b 68 16 d1 9e d7 41 a3 53 44 11 0d f9 79 a9 1e d7 41 2a cd 94 cc 9a f1 35 d2 b7 50 a0 1f 70 ..h....A.SD...y...A*.....5..P..p
0ac0 9d 25 80 5e 14 a3 a7 e5 e6 36 3c e0 3a 48 a5 e3 9d aa 61 68 c8 74 35 95 24 f6 47 b0 a1 1a a9 94 .%.^.....6<.:H....ah.t5.$.G.....
0ae0 29 d9 87 53 99 ec b1 ae 83 54 a8 73 c1 86 8a 46 27 2e 71 3d db 75 88 4a 93 c8 e4 f7 1c 23 5b ee )..S.....T.s...F'.q=.u.J.....#[.
0b00 67 43 35 62 7b aa 95 5f 27 5b 73 a7 bb 0e 52 e9 d8 54 0d 51 72 51 ee 00 2b e6 21 84 7f ed 12 bf gC5b{.._'[s...R..T.QrQ..+.!.....
0b20 8d 57 91 25 a9 d6 6c 8b eb 20 95 46 8c 9e e5 3a 03 85 02 9b aa 6d 34 b5 af 6c 30 62 1f 51 c8 e1 .W.%..l....F...:.....m4..l0b.Q..
0b40 ae b3 04 5c 35 80 3b 92 ad b9 4f bb 0e 52 c9 d8 54 0d 41 22 93 7f 0f 4a 78 18 40 bd eb 2c 21 51 ...\5.;...O..R..T.A"...Jx.@..,!Q
0b60 a3 90 85 a9 d6 2c e7 7f 0c 4a b6 e5 0e 85 62 1f d7 39 28 f8 14 b2 5f fd a2 c2 5b 5d e7 a8 04 a9 .....,...J....b..9(..._...[]....
0b80 4c 76 ff a2 c6 1f 52 c8 7e ae b3 84 84 00 b8 3a d1 9a bf 12 aa 9c 3e b4 1d 6c aa 76 21 d1 96 3f Lv....R.~......:......>..l.v!..?
0ba0 51 44 ef 03 b0 9b eb 2c 21 13 53 c8 8f 13 99 fc c5 ae 83 54 04 c5 69 ae 23 50 78 98 92 8d fc f1 QD.....,!.S........T..i.#Px.....
0bc0 94 ca 64 67 a9 c8 c3 50 24 5d 67 09 1b 81 5e 9a 6c cb ff d0 75 8e 4a c4 a6 6a 27 12 6d f9 b7 8b ..dg...P$]g...^.l...u.J..j'.m...
0be0 6a 06 40 ad eb 2c 61 25 a2 57 25 32 f9 73 5d e7 70 4e c0 b5 72 c8 3b 82 b4 eb 08 2e 25 ef cc ed j.@..,a%.W%2.s].pN..r.;.....%...
0c00 a3 22 bf 06 b0 87 eb 2c 21 f6 d1 64 6b ee 72 d7 21 2a 0d 6f df ed 40 aa 2d 3b 53 55 fe 08 2e 99 .".....,!..dk.r.!*.o..@.-;SU....
0c20 50 0e 25 85 a4 0b 2d c9 45 ae 83 b8 90 c8 e4 0f 14 d1 a7 5d e7 a0 70 89 49 e9 2d 5d cd 4d ff 74 P.%...-.E..........]..p.I.-].M.t
0c40 9d a3 dc 92 0b 73 75 88 73 c9 84 72 11 e8 a7 72 2d 0d d7 b8 ce 51 29 78 a7 6a 3b ea db 0b 09 55 .....su.s..r...r-....Q)x.j;....U
0c60 b9 07 6c a8 ca 25 26 d0 db 92 ad b9 77 bb 0e e2 84 e0 04 d7 11 28 7c 4a 88 45 ee b8 9a 9e 79 7e ..l..%&.....w........(|J.E....y~
0c80 37 89 eb af c1 86 aa 6c 14 f2 ed 54 5b 36 d2 77 46 b7 c5 a6 ea 0d ea ee e8 99 2c 56 7f 0b 20 e5 7......l...T[6.wF.........,V....
0ca0 3a 4b c4 8c 01 b0 38 b9 28 77 80 eb 20 e5 26 d0 c8 5d fc a8 0c 34 5a cd 7a e3 cd 9d b5 03 52 b5 :K....8.(w....&..]...4Z.z.....R.
0cc0 44 21 6f 73 9d 25 62 8c aa dc d2 90 e9 7a 9f eb 20 95 80 4d d5 b6 54 25 16 2f de 24 d0 37 bb 8e D!os.%b......z.....M..T%./.$.7..
0ce0 12 51 7b a0 84 bb 66 dc b6 7c a2 eb 20 e5 32 f5 96 55 e3 00 bc d3 75 0e 0a a5 23 13 99 fc 18 d7 .Q{...f..|....2..U....u...#.....
0d00 21 ca a5 34 3e 76 0d 80 68 de ed 76 af c6 8a 69 6b 6a 5f d9 e0 3a 88 6b 6c aa b6 91 6a cb 7d 16 !..4>v..h..v...ikj_..:.kl...j.}.
0d20 82 93 5c e7 88 b8 19 7d 35 35 37 b8 0e 51 2e b5 b5 bd 6f c7 d6 f5 5f 88 bc 56 23 31 9d ed 3a 44 ..\....}557..Q....o..._..V#1..:D
0d40 39 0c 3e 7e e2 12 2d 6e ed 51 b4 f1 5f cc ba 7e 59 95 eb 20 2e b1 a9 1a 54 df 5e 78 87 42 be e2 9.>~..-n.Q.._..~Y.......T.^x.B..
0d60 3a 07 01 00 d2 51 59 c3 ca 8a 39 c2 75 06 0a 2f b1 1a fa e3 2b 91 c9 cf 50 95 c8 7c 10 ab 70 6f :....QY...9.u../....+...P..|..po
0d80 5f bd e7 d4 af ba 0e e1 12 9b 2a 6c dd c2 40 ac de 09 20 d2 1d 76 25 51 c8 35 0d 6d 5d 07 bb ce _.........*l..@......v%Q.5.m]...
0da0 e1 3b 45 e8 2f 7a e4 8e 45 b8 9b f6 19 f7 2c af 11 e8 2f 00 44 66 ca 40 a5 13 e8 25 c9 4c ee 83 .;E./z..E.....,.../.Df.@...%.L..
0dc0 ae 73 b8 c2 a6 0a 00 04 3f 17 68 e4 9f 05 57 98 5a 0b 73 67 dd 92 9e b1 ae 83 f8 4a 10 89 c7 33 .s......?.h...W.Z.sg.......J...3
0de0 e4 86 40 df ee 3a 83 9f fa 36 d7 5c 0d c1 21 ae 73 d0 eb 08 04 3f 6d 68 ef da db 75 10 17 22 df ..@..:...6.\..!.s....?mh...u..".
0e00 54 25 33 b9 d3 b8 c9 66 85 52 bc 29 d6 5b fc 82 eb 18 7e a9 5b d8 9d 04 97 ed 20 7f 4d 0e eb c5 T%3....f.R.).[....~.[.......M...
0e20 2d d9 9e 9b 0d c5 47 5d e7 a0 ed 9a 6c ad f9 b6 eb 10 2e 44 ba a9 9a bc 78 ed 04 08 22 f9 8d 0f -.....G]....l......D....x..."...
0e40 90 cf 34 dc d9 f5 16 d7 21 fc 50 15 1b 38 c8 75 06 0a 3f ab 26 7c c7 d9 02 35 b0 f8 21 22 7e 0d ..4.....!.P..8.u..?.&|...5..!"~.
0e60 ab 70 f3 52 ad d9 a3 5d 87 28 b7 48 1f 90 63 fa b7 7c 05 dc 24 b9 d2 55 db 98 b9 2e 8c 9b 77 aa .p.R...].(.H..c..|..$..U......w.
0e80 48 f8 2e 76 54 79 14 07 ba 8e e0 b5 c4 cc c2 85 00 0e 73 9d 83 76 4e 21 d7 cd b8 67 79 8d eb 1c H..vTy............s..vN!...gy...
0ea0 e5 14 d9 a6 6a 70 91 c9 8f b9 ce 41 43 f2 9e 64 5b 3e 74 1b c4 aa c8 9b 5c 67 a0 f0 13 e8 7e ae ....jp.....AC..d[>t.....\g....~.
0ec0 33 78 a9 e9 8e 95 53 05 ca 3d e7 82 61 df fe 57 ab ff cf 75 88 72 8a 66 53 a5 2a 28 e1 3a f0 6d 3x....S..=..a..W...u.r.fS.*(.:.m
0ee0 bf 20 f9 ce e4 c5 6b 27 b8 0e e1 29 e5 56 1a e4 3f 0b 13 aa e3 ac 54 15 bb 1a c0 ee ae 73 d0 d0 ......k'...).V..?.....T......s..
0f00 28 e4 8b 75 99 9e c8 ec 50 12 c9 a6 2a d9 9a 3f 09 c0 bb 5c e7 a0 61 d9 7b 4c ff 96 8b 5c 87 f0 (..u....P...*..?...\..a.{L...\..
0f20 92 42 1a 1d 47 a0 08 10 d1 46 d7 19 bc 92 5c 94 3b 40 21 f3 5d e7 a0 61 19 1b 93 e2 65 ae 43 94 .B..G....F....\.;@!.]..a....e.C.
0f40 4b f4 9a 2a 55 11 51 2e f2 19 4c 9f 49 64 f2 e1 78 5b 6e a9 c6 05 ca f9 7c e4 3f 45 0a 19 8d b9 K..*U.Q...L.Id..x[n.....|.?E....
0f60 8e e1 89 12 be 86 28 5e b7 82 ef ec ba 4c 77 a8 1e 43 ef 48 e4 0e ce 44 6b e1 14 6e b8 19 58 bb ......(^.....Lw..C.H...Dk..n..X.
0f80 19 b1 9f 70 1d c2 0b c9 55 f9 bd 00 c4 5d e7 a0 48 a8 6a 2a 76 4e 76 1d 62 b4 06 17 03 8e ec a2 ...p....U....]..H.j*vNv.b.......
0fa0 92 01 17 8b 49 e9 f3 ae 43 94 43 e4 9a 2a 23 f6 62 d7 19 68 e4 14 f2 f1 c1 4d 88 03 4d ab 24 f0 ....I...C.C..*#.b..h.....M..M.$.
0fc0 17 39 0a 8e 52 75 2c f0 c7 9b 85 f9 0c 80 d0 bd 05 1c 21 f3 a2 30 b7 2a 52 4d 55 b2 3d 37 5b 21 .9..Ru,...........!..0.*RMU.=7[!
0fe0 87 bb ce 41 a3 b2 67 f5 98 fe b3 5d 87 18 2d 15 99 e4 3a 03 45 47 d0 8f b7 44 26 5f 0f 45 8b eb ...A..g....]..-...:.EG...D&_.E..
1000 1c 34 2a 55 71 33 10 fa 37 ee 23 d5 54 89 d5 50 3c 3a a2 e0 af a2 1c 2b 95 02 7d 91 a3 60 51 1b .4*Uq3..7.#.T..P<:.....+..}..`Q.
1020 ec 3b a3 22 7a 3e f8 b6 76 e0 a9 ca 87 c3 be 6e 55 64 9a aa a9 b7 ac 1a a7 90 53 5c e7 20 4f cc .;."z>..v......nUd........S\..O.
1040 6c 68 ef 0a f4 7e 5f 0a 19 ef 3a 03 45 87 51 1b dc 47 e6 5b 17 fe 3d c3 75 0c f2 c4 1e bd 9b 6b lh...~_...:.E.Q..G.[..=.u......k
1060 43 bd 2d 5c 64 9a aa ea da fe 16 00 bc 90 85 84 b5 e6 4c d7 19 46 43 a0 d5 ae 33 50 74 58 31 81 C.-\d.............L..FC...3PtX1.
1080 bd 3b 90 68 2d 1c 09 60 ba eb 1c e4 0d 51 0d f4 b9 7b 57 22 d3 54 a9 48 a8 bf 91 51 a3 d0 f9 b3 .;.h-..`.....Q...{W".T.H...Q....
10a0 ae 5f 16 d8 c7 01 41 be c8 51 f0 88 68 60 8f 37 31 e1 be 08 47 d0 89 75 77 f4 04 fa 71 f4 ce 44 ._....A..Q..h`.71...G..uw...q..D
10c0 a2 a9 4a 64 f2 f5 02 7d 8f eb 1c e4 1d 81 ec b5 6e 8f c9 ff e5 3a c7 48 89 6a 60 1b 42 0a 20 8b ..Jd...}........n....:.H.j`.B...
10e0 40 36 55 8d 37 77 d6 42 31 d7 75 0e f2 54 95 89 97 4e 77 1d c2 2f 91 68 aa 0c ec 99 00 c2 b1 f8 @6U.7w.B1.u..T...Nw../.h........
1100 1d fd 9b 35 c1 7e 04 48 54 2e 22 6a 5d 67 18 89 d2 b8 d8 c9 e0 96 34 a1 23 12 de bb 8f 91 68 aa ...5.~.HT."j]g........4.#.....h.
1120 54 38 41 3d 8c 44 f5 c4 99 99 8e 40 ce 4d 52 48 bf eb 0c 14 1d aa d2 e7 3a c3 88 08 78 ee 0e a7 T8A=.D.....@.MRH........:...x...
1140 d9 c9 85 b9 3a d7 21 fc 10 fa a6 6a f0 d9 ed a1 ae 73 90 f7 14 32 61 83 4c 7c a7 eb 1c 23 62 10 ....:.!....j.....s...2a.L|...#b.
1160 cc 8b 1c 05 52 20 9b f8 ad 5b eb 1c eb 3a 06 f9 42 10 c7 71 ae 43 f8 21 f4 4d 55 ac ba 78 2c f8 ....R....[...:..B..q.C.!.MU..x,.
1180 e8 2f cc 8e 77 1d 60 24 8c 5a 36 55 54 36 06 36 70 4d 55 7d ac 7b 36 00 ae e7 16 5e 81 3c 77 ef ./..w.`$.Z6UT6.6pMU}.{6....^.<w.
11a0 4a e8 9b 2a 85 bc d7 75 06 f2 8f 68 30 5f 40 b0 6a 5e 71 9d 81 a2 43 21 1b 5c 67 18 ae 58 a9 f4 J..*...u...h0_@.j^q...C!.\g..X..
11c0 5e d7 19 c8 57 81 3c 77 ef 4a e8 9b 2a b1 1a cc c7 43 34 34 82 59 75 4b 7a c6 ba 8e 31 5c 22 ba ^...W.<w.J..*....C44.YuKz...1\".
11e0 ce 75 06 8a 0e 23 36 70 c7 9b 42 78 ee 0e b7 a9 89 4c 7e 86 eb 10 5e 0b 75 53 35 3d f3 fc 6e 10 .u...#6p..Bx.....L~...^.uS5=..n.
1200 ec ef 3a 07 f9 aa 2a d6 5f 0c dc 9c 39 51 5d ef 3a 03 45 c7 80 56 05 ef 78 13 70 9f d6 90 33 c6 ..:...*._...9Q].:.E..V..x.p...3.
1220 1e e1 3a 83 d7 42 dd 54 f5 4b f5 c1 08 f9 df 91 00 b1 1a b8 2d 6b fa e2 03 81 bb 73 40 01 56 94 ..:..B.T.K..........-k.....s@.V.
1240 40 35 55 4d ed 2b 1b 00 84 76 81 48 da ca aa 09 dc b9 7b 57 42 dd 70 18 b1 07 b9 ce 40 fe 53 c8 @5UM.+...v.H......{WB.p.....@.S.
1260 81 ae 33 0c d7 ea a7 f7 59 07 f0 0d 40 2a 8b de 9e 79 7b 07 aa a9 2a 69 8c e7 ee 08 30 6a 03 77 ..3.....Y...@*...y{...*i....0j.w
1280 ee de 95 50 37 55 50 1c e0 3a 02 95 45 f0 4e c0 0b c4 02 c8 b9 8e 41 e1 a7 90 2e 88 a8 eb 1c c3 ...P7UP..:..E.N.......A.........
12a0 c2 73 77 24 a8 04 ef 03 f1 ae 84 bd a9 0a dd 24 38 da ae 7d 5d 07 18 a1 2e d7 01 28 fc 04 da e9 .sw$...........$8..}]......(....
12c0 3a c3 70 29 84 e7 ee 68 98 dc 78 57 67 a8 56 cc 0f 75 53 a5 46 9a 5c 67 a0 b2 d8 2d 88 3f 98 2a :.p)...h..xWg.V..uS.F.\g...-.?.*
12e0 12 b8 8b 1d 05 52 e0 8e 33 51 e5 b9 3b 22 b4 14 ae eb 74 78 9b aa a5 1a 87 22 e1 3a 06 95 47 10 .....R..3Q..;"....tx.....".:..G.
1300 7f 30 8d da 7f b8 ce 40 11 20 78 d6 75 84 e1 52 91 06 d7 19 a8 3c 4a 1a 0b dc b9 7b 67 42 db 54 .0.....@..x.u..R.....<J....{gB.T
1320 35 bc 98 9d 02 20 ee 3a 07 95 47 09 b1 bd 5d 67 18 2e 51 7d da 75 06 8a 00 c1 df 5d 47 18 81 c0 5......:..G...]g..Q}.u.....]G...
1340 fd 3c d3 c8 88 68 a8 be d7 a1 6d aa 4a a5 18 5f c7 8d 10 a3 36 70 df ef 81 62 35 9b 2a f2 9d 96 pre { line-height: 125%; } td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } .highlight .hll { background-color: #ffffcc } .highlight .c { color: #888888 } /* Comment */ .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ .highlight .k { color: #008800; font-weight: bold } /* Keyword */ .highlight .ch { color: #888888 } /* Comment.Hashbang */ .highlight .cm { color: #888888 } /* Comment.Multiline */ .highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */ .highlight .cpf { color: #888888 } /* Comment.PreprocFile */ .highlight .c1 { color: #888888 } /* Comment.Single */ .highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */ .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */ .highlight .gr { color: #aa0000 } /* Generic.Error */ .highlight .gh { color: #333333 } /* Generic.Heading */ .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ .highlight .go { color: #888888 } /* Generic.Output */ .highlight .gp { color: #555555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666666 } /* Generic.Subheading */ .highlight .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Authentication;
using System.Threading.Tasks;
using System.Web.Http;
using Tango.BL;
using Tango.BL.Builders;
using Tango.BL.Entities;
using Tango.BL.Enumerations;
using Tango.Core;
using Tango.Core.DB;
using Tango.Logging;
using Tango.MachineService.Models;
using Tango.PPC.Common.Web;
using Tango.Web.Controllers;
using Tango.Web.Helpers;
using Tango.Web.SMO;
using Tango.Web.Storage;
using System.Data.Entity;
using Tango.Web.Security;
using Tango.Web.ActiveDirectory;
using Tango.Core.Cryptography;
using Tango.MachineService.Filters;
using Tango.BL.DTO;

namespace Tango.MachineService.Controllers
{
    public class PPCController : TangoController<PPCController.TokenObject>
    {
        private static List<PPCPendingUpload> _pendingUploads;
        private static List<PPCPendingUpdate> _pendingUpdates;
        private ActiveDirectoryManager _ad_manager;
        public const int SQL_TEMP_CREDENTIALS_EXP_MINUTS = 20;

        public class TokenObject
        {
            public LoginMode Mode { get; set; }
            public String UserGuid { get; set; }
            public String MachineGuid { get; set; }
        }

        #region Constructors

        static PPCController()
        {
            _pendingUploads = new List<PPCPendingUpload>();
            _pendingUpdates = new List<PPCPendingUpdate>();
        }

        public PPCController()
        {
            _ad_manager = new ActiveDirectoryManager();
        }

        #endregion

        #region Setup & Update

        [HttpPost]
        [JwtTokenFilter]
        public MachineSetupResponse MachineSetup(MachineSetupRequest request)
        {
            MachineSetupResponse response = new MachineSetupResponse();
            response.NotifyCompletedToken = Guid.NewGuid().ToString();

            LogManager.Log("Setup request received: " + request.ToString());

            using (ObservablesContext db = ObservablesContextHelper.CreateContext())
            {
                String machine_guid = RequestToken.Object.MachineGuid;

                var machine = db.Machines.Include(x => x.Organization).SingleOrDefault(x => x.Guid == machine_guid);

                if (machine == null)
                {
                    throw new AuthenticationException("The specified serial number could not be found.");
                }

                if (machine.SetupActivation && String.IsNullOrWhiteSpace(machine.OsKey))
                {
                    throw new InvalidDataException("The specified machine is configured to perform an OS activation but is not associated with an OS activation key.");
                }

                if (String.IsNullOrWhiteSpace(request.DeviceID))
                {
                    throw new InvalidDataException("Device id not set.");
                }

                if (String.IsNullOrWhiteSpace(request.DeviceName))
                {
                    throw new InvalidDataException("Device name not set.");
                }

                if (machine.IsDeviceRegistered && machine.DeviceId != request.DeviceID)
                {
                    throw new InvalidDataException("The specified machine is already registered and device id is invalid.");
                }

                machine.DeviceName = request.DeviceName;
                machine.DeviceId = request.DeviceID;
                machine.IsDeviceRegistered = true;

                var machine_version = db.MachineVersions.SingleOrDefault(x => x.Guid == machine.MachineVersionGuid);

                var latest_machine_version = db.TangoVersions.Where(x => x.MachineVersionGuid == machine_version.Guid).ToList().OrderByDescending(x => Version.Parse(x.Version)).FirstOrDefault();

                response.Version = latest_machine_version.Version;
                response.FirmwareVersion = latest_machine_version.FirmwareVersion;

                var manager = new BlobStorageManager();
                var container = manager.GetContainer(MachineServiceConfig.TANGO_VERSIONS_CONTAINER);
                var blob = container.GetBlockBlobReference(latest_machine_version.BlobName);

                response.BlobAddress = blob.GenerateReadSignature(TimeSpan.FromMinutes(60));

                if (!String.IsNullOrWhiteSpace(MachineServiceConfig.CDN_ENDPOINT))
                {
                    response.CdnAddress = MachineServiceConfig.CDN_ENDPOINT + blob.Uri.AbsolutePath;
                }

                DbCredentials credentials = new DbCredentials();

                using (SmoManager smo = new SmoManager())
                {
                    credentials = smo.CreateRandomLoginAndUser();

                    Task.Delay(TimeSpan.FromMinutes(SQL_TEMP_CREDENTIALS_EXP_MINUTS)).ContinueWith((x) =>
                    {
                        using (SmoManager m = new SmoManager())
                        {
                            m.DeleteLoginAndUser(credentials.UserName);
                        }
                    });
                }

                response.DataSource = new DataSource()
                {
                    Address = MachineServiceConfig.DB_ADDRESS,
                    Catalog = MachineServiceConfig.DB_CATALOG,
                    UserName = credentials.UserName,
                    Password = credentials.Password,
                    IntegratedSecurity = false,
                    Type = DataSourceType.SQLServer,
                };

                response.OSKey = machine.OsKey;
                response.SetupActivation = machine.SetupActivation;
                response.SetupRemoteAssistance = machine.SetupRemoteAssistance;
                response.SetupUWF = machine.SetupUwf;
                response.SetupFirmware = machine.SetupFirmware;
                response.IsDemo = machine.IsDemo;
                response.Organization = machine.Organization.Name;

                TangoUpdate tangoUpdate = new TangoUpdate();
                tangoUpdate.ApplicationVersion = latest_machine_version.Version;
                tangoUpdate.FirmwareVersion = latest_machine_version.FirmwareVersion;
                tangoUpdate.MachineGuid = machine.Guid;
                tangoUpdate.StartDate = DateTime.UtcNow;
                tangoUpdate.UpdateStatus = TangoUpdateStatuses.SetupStarted;
                db.TangoUpdates.Add(tangoUpdate);

                machine.ProductionDate = DateTime.UtcNow;

                db.SaveChanges();

                _pendingUpdates.Add(new PPCPendingUpdate()
                {
                    Token = response.NotifyCompletedToken,
                    TangoUpdateGuid = tangoUpdate.Guid,
                });
            }

            return response;
        }

        [HttpPost]
        [JwtTokenFilter]
        public DownloadUpdateResponse MachineUpdate(DownloadUpdateRequest request)
        {
            DownloadUpdateResponse response = new DownloadUpdateResponse();
            response.NotifyCompletedToken = Guid.NewGuid().ToString();

            using (ObservablesContext db = ObservablesContextHelper.CreateContext())
            {
                db.Configuration.LazyLoadingEnabled = false;
                String machine_guid = RequestToken.Object.MachineGuid;

                var machine = db.Machines.SingleOrDefault(x => x.Guid == machine_guid);

                if (machine == null)
                {
                    throw new AuthenticationException("The specified serial number could not be found.");
                }

                var machine_version = db.MachineVersions.SingleOrDefault(x => x.Guid == machine.MachineVersionGuid);

                var latest_machine_version = db.TangoVersions.Where(x => x.MachineVersionGuid == machine_version.Guid).ToList().OrderByDescending(x => Version.Parse(x.Version)).FirstOrDefault();

                response.Version = latest_machine_version.Version;
                response.FirmwareVersion = latest_machine_version.FirmwareVersion;

                var manager = new BlobStorageManager();
                var container = manager.GetContainer(MachineServiceConfig.TANGO_VERSIONS_CONTAINER);
                var blob = container.GetBlockBlobReference(latest_machine_version.BlobName);

                response.BlobAddress = blob.GenerateReadSignature(TimeSpan.FromMinutes(60));

                if (!String.IsNullOrWhiteSpace(MachineServiceConfig.CDN_ENDPOINT))
                {
                    response.CdnAddress = MachineServiceConfig.CDN_ENDPOINT + blob.Uri.AbsolutePath;
                }

                DbCredentials credentials = new DbCredentials();

                using (SmoManager smo = new SmoManager())
                {
                    credentials = smo.CreateRandomLoginAndUser();

                    Task.Delay(TimeSpan.FromMinutes(SQL_TEMP_CREDENTIALS_EXP_MINUTS)).ContinueWith((x) =>
                    {
                        using (SmoManager m = new SmoManager())
                        {
                            m.DeleteLoginAndUser(credentials.UserName);
                        }
                    });
                }

                response.DataSource = new DataSource()
                {
                    Address = MachineServiceConfig.DB_ADDRESS,
                    Catalog = MachineServiceConfig.DB_CATALOG,
                    UserName = credentials.UserName,
                    Password = credentials.Password,
                    IntegratedSecurity = false,
                    Type = DataSourceType.SQLServer,
                };

                TangoUpdate tangoUpdate = new TangoUpdate();
                tangoUpdate.ApplicationVersion = latest_machine_version.Version;
                tangoUpdate.FirmwareVersion = latest_machine_version.FirmwareVersion;
                tangoUpdate.MachineGuid = machine.Guid;
                tangoUpdate.StartDate = DateTime.UtcNow;
                tangoUpdate.UpdateStatus = TangoUpdateStatuses.UpdateStarted;
                db.TangoUpdates.Add(tangoUpdate);

                db.SaveChanges();

                _pendingUpdates.Add(new PPCPendingUpdate()
                {
                    Token = response.NotifyCompletedToken,
                    TangoUpdateGuid = tangoUpdate.Guid,
                });
            }

            return response;
        }

        [HttpPost]
        [JwtTokenFilter]
        public MachineUpdateCompletedResponse NotifyUpdateCompleted(MachineUpdateCompletedRequest request)
        {
            var pendingUpdate = _pendingUpdates.SingleOrDefault(x => x.Token == request.Token);
            if (pendingUpdate != null)
            {
                _pendingUpdates.Remove(pendingUpdate);

                using (ObservablesContext db = ObservablesContextHelper.CreateContext())
                {
                    var tangoUpdate = db.TangoUpdates.SingleOrDefault(x => x.Guid == pendingUpdate.TangoUpdateGuid);

                    if (tangoUpdate != null)
                    {
                        tangoUpdate.LastUpdated = DateTime.UtcNow;
                        tangoUpdate.UpdateStatus = request.Status;
                        tangoUpdate.EndDate = DateTime.UtcNow;
                        tangoUpdate.FailedReason = request.FailedReason;
                        tangoUpdate.FailedLog = request.FailedLog;

                        if (request.ReportsAboutDbCheckNoDifferences)
                        {
                            db.TangoUpdates.Remove(tangoUpdate);
                        }

                        db.SaveChanges();
                    }
                }
            }

            return new MachineUpdateCompletedResponse();
        }

        [HttpPost]
        [JwtTokenFilter]
        public CheckForUpdateResponse CheckForUpdates(CheckForUpdateRequest request)
        {
            CheckForUpdateResponse response = new CheckForUpdateResponse();

            using (ObservablesContext db = ObservablesContextHelper.CreateContext())
            {
                String machine_guid = RequestToken.Object.MachineGuid;

                var machine = db.Machines.SingleOrDefault(x => x.Guid == machine_guid);

                if (machine == null)
                {
                    throw new AuthenticationException("The specified serial number could not be found.");
                }

                response.SetupFirmware = machine.SetupFirmware;
                response.SetupFPGA = machine.SetupFpga;

                if (!machine.SuspendVersionUpdate)
                {
                    var machine_version = db.MachineVersions.SingleOrDefault(x => x.Guid == machine.MachineVersionGuid);

                    var latest_machine_version = db.TangoVersions.Where(x => x.MachineVersionGuid == machine_version.Guid).ToList().OrderByDescending(x => Version.Parse(x.Version)).FirstOrDefault();

                    if (Version.Parse(latest_machine_version.Version) != Version.Parse(request.Version))
                    {
                        response.IsUpdateAvailable = true;
                    }

                    response.Version = latest_machine_version.Version;
                    response.FirmwareVersion = latest_machine_version.FirmwareVersion;

                    //Compare database

                    var rmls = db.Rmls.Select(x => new { x.Guid, x.LastUpdated }).ToList();
                    var hardwareVersions = db.HardwareVersions.Select(x => new { x.Guid, x.LastUpdated }).ToList();
                    var catalogs = db.ColorCatalogs.Select(x => new { x.Guid, x.LastUpdated }).ToList();

                    var arr = request.UsedRmlsGuids.ToArray();
                    var existingRml = db.Rmls.Where(x => arr.Contains(x.Guid)).Select(x => x.Guid).Distinct().ToList();
                    response.UsedNotExistingRmlsGuids = arr.Where(x => !existingRml.Exists(y => y == x)).ToList();

                    bool hasDatabaseUpdates = false;

                    hasDatabaseUpdates = machine.LastUpdated > request.MachineLastUpdated;

                    if (!hasDatabaseUpdates)
                    {
                        hasDatabaseUpdates = rmls.Exists(x => request.Rmls.Exists(y => x.Guid == y.Guid && x.LastUpdated > y.LastUpdated) || !request.Rmls.Exists(y => x.Guid == y.Guid));
                    }

                    if (!hasDatabaseUpdates)
                    {
                        hasDatabaseUpdates = hardwareVersions.Exists(x => request.HardwareVersions.Exists(y => x.Guid == y.Guid && x.LastUpdated > y.LastUpdated) || !request.HardwareVersions.Exists(y => x.Guid == y.Guid));
                    }

                    if (!hasDatabaseUpdates)
                    {
                        hasDatabaseUpdates = catalogs.Exists(x => request.Catalogs.Exists(y => x.Guid == y.Guid && x.LastUpdated > y.LastUpdated) || !request.Catalogs.Exists(y => x.Guid == y.Guid));
                    }

                    if (hasDatabaseUpdates)
                    {
                        response.IsDatabaseUpdateAvailable = true;
                        response.UpdateDBResponse = UpdateDB(new UpdateDBRequest() { SerialNumber = request.SerialNumber });
                    }

                    //Compare database

                    if (machine.ForceVersionUpdate)
                    {
                        response.IsUpdateAvailable = true;
                    }
                }
            }

            return response;
        }

        [HttpPost]
        [JwtTokenFilter]
        public UpdateDBResponse UpdateDB(UpdateDBRequest request)
        {
            UpdateDBResponse response = new UpdateDBResponse();
            response.NotifyCompletedToken = Guid.NewGuid().ToString();

            using (ObservablesContext db = ObservablesContextHelper.CreateContext())
            {

                String machine_guid = RequestToken.Object.MachineGuid;

                var machine = db.Machines.SingleOrDefault(x => x.Guid == machine_guid);

                if (machine == null)
                {
                    throw new AuthenticationException("The specified serial number could not be found.");
                }

                response.PerformSchemaUpdate = machine.PerformSchemaUpdateOnDataUpdate;

                DbCredentials credentials = new DbCredentials();

                using (SmoManager manager = new SmoManager())
                {
                    credentials = manager.CreateRandomLoginAndUser();

                    Task.Delay(TimeSpan.FromMinutes(SQL_TEMP_CREDENTIALS_EXP_MINUTS)).ContinueWith((x) =>
                    {
                        using (SmoManager m = new SmoManager())
                        {
                            m.DeleteLoginAndUser(credentials.UserName);
                        }
                    });
                }

                response.DataSource = new DataSource()
                {
                    Address = MachineServiceConfig.DB_ADDRESS,
                    Catalog = MachineServiceConfig.DB_CATALOG,
                    UserName = credentials.UserName,
                    Password = credentials.Password,
                    IntegratedSecurity = false,
                    Type = DataSourceType.SQLServer,
                };

                TangoUpdate tangoUpdate = new TangoUpdate();
                tangoUpdate.ApplicationVersion = request.ApplicationVersion;
                tangoUpdate.FirmwareVersion = request.FirmwareVersion;
                tangoUpdate.MachineGuid = machine.Guid;
                tangoUpdate.StartDate = DateTime.UtcNow;
                tangoUpdate.UpdateStatus = TangoUpdateStatuses.DatabaseStarted;
                db.TangoUpdates.Add(tangoUpdate);

                db.SaveChanges();

                _pendingUpdates.Add(new PPCPendingUpdate()
                {
                    Token = response.NotifyCompletedToken,
                    TangoUpdateGuid = tangoUpdate.Guid,
                });
            }

            return response;
        }

        #endregion

        #region Synchronization

        [HttpPost]
        [JwtTokenFilter]
        public UploadMachineDataResponse UploadMachineData(UploadMachineDataRequest request)
        {
            UploadMachineDataResponse response = new UploadMachineDataResponse();
            response.NotifyCompletedToken = Guid.NewGuid().ToString();

            using (ObservablesContext db = ObservablesContextHelper.CreateContext())
            {
                var machine = db.Machines.SingleOrDefault(x => x.Guid == RequestToken.Object.MachineGuid);

                if (machine == null)
                {
                    throw new AuthenticationException("The specified machine could not be found.");
                }

                TangoUpdate tangoUpdate = new TangoUpdate();
                tangoUpdate.ApplicationVersion = request.ApplicationVersion;
                tangoUpdate.FirmwareVersion = request.FirmwareVersion;
                tangoUpdate.MachineGuid = machine.Guid;
                tangoUpdate.StartDate = DateTime.UtcNow;
                tangoUpdate.UpdateStatus = TangoUpdateStatuses.SynchronizationStarted;
                db.TangoUpdates.Add(tangoUpdate);
                db.SaveChanges();

                _pendingUpdates.Add(new PPCPendingUpdate()
                {
                    Token = response.NotifyCompletedToken,
                    TangoUpdateGuid = tangoUpdate.Guid,
                });
            }

            User machineUser = null;

            try
            {
                using (ObservablesContext db = ObservablesContextHelper.CreateContext())
                {
                    var machine = db.Machines.SingleOrDefault(x => x.Guid == RequestToken.Object.MachineGuid);

                    if (machine == null)
                    {
                        throw new AuthenticationException("The specified machine could not be found.");
                    }

                    machineUser = db.Users.Include(x => x.Contact).SingleOrDefault(x => x.Contact.FirstName == machine.Name);

                    if (machineUser == null)
                    {
                        //No machine user then create one.
                        machineUser = new User();
                        machineUser.Email = machine.SerialNumber + "@twine-s.com";
                        machineUser.Password = machine.SerialNumber;
                        machineUser.OrganizationGuid = machine.OrganizationGuid;
                        machineUser.Contact = new Contact();
                        machineUser.Contact.Email = machineUser.Email;
                        machineUser.Contact.FirstName = machine.Name;
                        machineUser.Contact.LastName = machine.Name;
                        machineUser.Contact.FullName = machine.Name;
                        machineUser.Address = new Address();

                        db.Users.Add(machineUser);
                        db.SaveChanges();
                    }
                }

                //Insert/Replace Jobs.
                foreach (var dto in request.Jobs)
                {
                    using (ObservablesContext db = ObservablesContextHelper.CreateContext())
                    {
                        try
                        {
                            var job = dto.ToObservable();

                            job.ID = 0;
                            job.UserGuid = machineUser.Guid;
                            job.CustomerGuid = null;
                            job.IsSynchronized = true;

                            var existingJob = db.Jobs.SingleOrDefault(x => x.Guid == job.Guid);

                            if (existingJob == null)
                            {
                                db.Jobs.Add(job);
                                db.SaveChanges();
                            }
                            else if (job.LastUpdated > existingJob.LastUpdated)
                            {
                                existingJob.Delete(db);
                                db.Jobs.Add(job);
                                db.SaveChanges();
                            }
                        }
                        catch (Exception ex)
                        {
                            response.FailedJobs.Add(new SynchronizationFailedEntity()
                            {
                                Guid = dto.Guid,
                                Reason = ex.FlattenMessage(),
                            });
                        }
                    }
                }

                //Insert JobRuns.
                foreach (var dto in request.JobRuns)
                {
                    using (ObservablesContext db = ObservablesContextHelper.CreateContext())
                    {
                        try
                        {
                            var run = dto.ToObservable();
                            run.ID = 0;
                            run.IsSynchronized = true;

                            if (db.JobRuns.SingleOrDefault(x => x.Guid == run.Guid) == null)
                            {
                                db.JobRuns.Add(run);
                                db.SaveChanges();
                            }
                        }
                        catch (Exception ex)
                        {
                            response.FailedJobRuns.Add(new SynchronizationFailedEntity()
                            {
                                Guid = dto.Guid,
                                Reason = ex.FlattenMessage(),
                            });
                        }
                    }
                }

                //Insert MachineEvents.
                foreach (var dto in request.MachineEvents)
                {
                    using (ObservablesContext db = ObservablesContextHelper.CreateContext())
                    {
                        try
                        {
                            var ev = dto.ToObservable();
                            ev.ID = 0;
                            ev.UserGuid = machineUser.Guid;
                            ev.IsSynchronized = true;

                            if (db.MachinesEvents.SingleOrDefault(x => x.Guid == ev.Guid) == null)
                            {
                                db.MachinesEvents.Add(ev);
                                db.SaveChanges();
                            }
                        }
                        catch (Exception ex)
                        {
                            response.FailedMachineEvents.Add(new SynchronizationFailedEntity()
                            {
                                Guid = dto.Guid,
                                Reason = ex.FlattenMessage(),
                            });
                        }
                    }
                }

                //Insert TangoUpdates.
                foreach (var dto in request.OfflineUpdates)
                {
                    using (ObservablesContext db = ObservablesContextHelper.CreateContext())
                    {
                        try
                        {
                            var update = dto.ToObservable();
                            update.ID = 0;
                            update.IsSynchronized = true;

                            if (db.TangoUpdates.SingleOrDefault(x => x.Guid == update.Guid) == null)
                            {
                                db.TangoUpdates.Add(update);
                                db.SaveChanges();
                            }
                        }
                        catch (Exception ex)
                        {
                            response.FailedOfflineUpdates.Add(new SynchronizationFailedEntity()
                            {
                                Guid = dto.Guid,
                                Reason = ex.FlattenMessage(),
                            });
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                NotifyUpdateCompleted(new MachineUpdateCompletedRequest()
                {
                    Status = TangoUpdateStatuses.SynchronizationFailed,
                    FailedReason = ex.FlattenMessage(),
                    FailedLog = ex.FlattenException(),
                    Token = response.NotifyCompletedToken,
                });
                throw ex;
            }

            return response;
        }

        [HttpPost]
        [JwtTokenFilter]
        public DownloadMachineDataResponse DownloadMachineData(DownloadMachineDataRequest request)
        {
            DownloadMachineDataResponse response = new DownloadMachineDataResponse();

            using (ObservablesContext db = ObservablesContextHelper.CreateContext())
            {
                var machine = db.Machines.SingleOrDefault(x => x.Guid == RequestToken.Object.MachineGuid);

                if (machine == null)
                {
                    throw new AuthenticationException("The specified machine could not be found.");
                }

                //Send Jobs
                if (request.RequestJobs)
                {
                    var jobs = new JobsCollectionBuilder(db).Set(x => x.MachineGuid == machine.Guid && !x.IsSynchronized).WithSegments().WithBrushStops().Query(x => x.Take(request.MaxJobs).OrderByDescending(z => z.LastUpdated)).BuildList();

                    foreach (var job in jobs)
                    {
                        JobDTO dto = JobDTO.FromObservable(job);
                        response.Jobs.Add(dto);
                    }
                }

                //Send Job Runs
                if (request.RequestJobRuns)
                {
                    var jobRuns = db.JobRuns.Where(x => x.MachineGuid == machine.Guid && !x.IsSynchronized).Take(request.MaxJobRuns).OrderByDescending(x => x.LastUpdated).ToList();

                    foreach (var jobRun in jobRuns)
                    {
                        JobRunDTO dto = JobRunDTO.FromObservable(jobRun);
                        response.JobRuns.Add(dto);
                    }
                }

                //Send Machine Events
                if (request.RequestMachineEvents)
                {
                    var machineEvents = db.MachinesEvents.Where(x => x.MachineGuid == machine.Guid && !x.IsSynchronized).Take(request.MaxMachinesEvents).OrderByDescending(x => x.LastUpdated).ToList();

                    foreach (var machineEvent in machineEvents)
                    {
                        MachinesEventDTO dto = MachinesEventDTO.FromObservable(machineEvent);
                        response.MachineEvents.Add(dto);
                    }
                }
            }

            return response;
        }

        [HttpPost]
        [JwtTokenFilter]
        public NotifyMachineDataDownloadCompletedResponse NotifyMachineDataDownloadCompleted(NotifyMachineDataDownloadCompletedRequest request)
        {
            var response = new NotifyMachineDataDownloadCompletedResponse();

            using (ObservablesContext db = ObservablesContextHelper.CreateContext())
            {
                var machine = db.Machines.SingleOrDefault(x => x.Guid == RequestToken.Object.MachineGuid);

                if (machine == null)
                {
                    throw new AuthenticationException("The specified machine could not be found.");
                }

                if (request.SynchronizedJobs.Count > 0)
                {
                    db.Database.ExecuteSqlCommand($"UPDATE JOBS SET IS_SYNCHRONIZED = 1 WHERE GUID IN ({String.Join(",", request.SynchronizedJobs.Select(x => "'" + x + "'"))});");
                }

                if (request.SynchronizedJobRuns.Count > 0)
                {
                    db.Database.ExecuteSqlCommand($"UPDATE JOB_RUNS SET IS_SYNCHRONIZED = 1 WHERE GUID IN ({String.Join(",", request.SynchronizedJobRuns.Select(x => "'" + x + "'"))});");
                }

                if (request.SynchronizedMachineEvents.Count > 0)
                {
                    db.Database.ExecuteSqlCommand($"UPDATE MACHINES_EVENTS SET IS_SYNCHRONIZED = 1 WHERE GUID IN ({String.Join(",", request.SynchronizedMachineEvents.Select(x => "'" + x + "'"))});");
                }
            }

            return response;
        }

        #endregion

        #region Version Upload

        [HttpPost]
        public LatestVersionResponse GetLatestVersion(LatestVersionRequest request)
        {
            LatestVersionResponse response = new LatestVersionResponse();

            using (ObservablesContext db = ObservablesContextHelper.CreateContext())
            {
                var versions = db.TangoVersions.Where(x => x.MachineVersionGuid == request.MachineVersionGuid).ToList();

                if (versions.Count == 0)
                {
                    return new LatestVersionResponse()
                    {
                        Version = "0.0.0.0",
                    };
                }

                response.Version = versions.OrderByDescending(x => Version.Parse(x.Version)).FirstOrDefault().Version;
            }

            return response;
        }

        [HttpPost]
        [JwtTokenFilter]
        public UploadVersionResponse UploadVersion(UploadVersionRequest request)
        {
            UploadVersionResponse response = new UploadVersionResponse();

            using (ObservablesContext db = ObservablesContextHelper.CreateContext())
            {
                //Load relations first...
                db.Roles.ToList();
                db.Permissions.ToList();
                db.UsersRoles.ToList();
                db.RolesPermissions.ToList();

                var user_guid = RequestToken.Object.UserGuid;

                var user = new UserBuilder(db).Set(user_guid).WithRolesAndPermissions().Build();

                if (user != null && user.HasPermission(Permissions.PublishPPCVersions))
                {
                    var versions = db.TangoVersions.ToList().Where(x => x.MachineVersionGuid == request.MachineVersionGuid).OrderByDescending(x => Version.Parse(x.Version)).ToList();
                    var machine_version = db.MachineVersions.SingleOrDefault(x => x.Guid == request.MachineVersionGuid);

                    TangoVersion latestVersion = new TangoVersion();
                    latestVersion.Version = "0.0.0.0";

                    if (versions.Count > 0)
                    {
                        latestVersion = versions.FirstOrDefault();
                    }

                    Version local_version = Version.Parse(request.Version);

                    if (local_version > Version.Parse(latestVersion.Version))
                    {
                        String newVersionFileName = $"{machine_version.Name} - Tango Version {local_version.ToString()}.tup";

                        var manager = new BlobStorageManager();
                        var container = manager.GetContainer(MachineServiceConfig.TANGO_VERSIONS_CONTAINER);
                        var blob = container.CreateEmptyBlob(newVersionFileName);

                        response.Token = Guid.NewGuid().ToString();
                        response.BlobAddress = blob.GenerateWriteSignature(TimeSpan.FromMinutes(30));

                        PPCPendingUpload pending_upload = new PPCPendingUpload()
                        {
                            UserGuid = user.Guid,
                            Comments = request.Comments,
                            Token = response.Token,
                            Version = request.Version,
                            BlobName = blob.Name,
                            MachineVersionGuid = request.MachineVersionGuid,
                            FirmwareVersion = request.FirmwareVersion,
                        };

                        if (request.WithInstaller)
                        {
                            String installerVersionFileName = Path.ChangeExtension(newVersionFileName, ".exe");
                            var installerBlob = container.CreateEmptyBlob(installerVersionFileName);
                            response.InstallerBlobAddress = installerBlob.GenerateWriteSignature(TimeSpan.FromMinutes(30));
                            pending_upload.InstallerBlobName = installerBlob.Name;
                        }

                        _pendingUploads.Add(pending_upload);
                    }
                    else
                    {
                        throw new ArgumentException("New version must be greater than latest version.");
                    }
                }
                else
                {
                    throw new AuthenticationException("Invalid user credentials.");
                }
            }

            return response;
        }

        [HttpPost]
        [JwtTokenFilter]
        public UploadCompletedResponse NotifyVersionUploadCompleted(UploadCompletedRequest request)
        {
            PPCPendingUpload upload = _pendingUploads.FirstOrDefault(x => x.Token == request.Token);

            if (upload != null)
            {
                _pendingUploads.RemoveAll(x => x.Token == upload.Token);

                using (ObservablesContext db = ObservablesContextHelper.CreateContext())
                {
                    db.TangoVersions.Add(new TangoVersion()
                    {
                        Comments = upload.Comments,
                        BlobName = upload.BlobName,
                        InstallerBlobName = upload.InstallerBlobName,
                        UserGuid = upload.UserGuid,
                        Version = upload.Version,
                        MachineVersionGuid = upload.MachineVersionGuid,
                        FirmwareVersion = upload.FirmwareVersion,
                    });

                    db.SaveChanges();
                }

                return new UploadCompletedResponse();
            }
            else
            {
                throw new AuthenticationException("Invalid upload token.");
            }
        }

        [HttpPost]
        public MachineVersionsResponse GetMachineVersions(MachineVersionsRequest request)
        {
            using (var db = ObservablesContextHelper.CreateContext())
            {
                return new MachineVersionsResponse()
                {
                    MachineVersions = db.MachineVersions.ToList().Select(x => MachineVersionDTO.FromObservable(x)).ToList(),
                };
            }
        }

        [HttpPost]
        public LoginResponse Login(LoginRequest request)
        {
            LoginResponse response = new LoginResponse();

            using (ObservablesContext db = ObservablesContextHelper.CreateContext())
            {
                if (request.Mode == LoginMode.User)
                {
                    var authResult = _ad_manager.ValidateUserCredentials(request.Email, request.Password);

                    if (!_ad_manager.CanUserAccessCurrentEnvironment(request.Email))
                    {
                        throw new AuthenticationException($"You do not have permissions to access the {MachineServiceConfig.DEPLOYMENT_SLOT.ToDescription()} environment.");
                    }

                    BasicHashGenerator hash = new BasicHashGenerator();
                    String pass = hash.Encrypt(request.Password);

                    var user = new UserBuilder(db).Set(x => x.Email.ToLower() == request.Email.ToLower() && x.Password == pass).Build();

                    if (user == null)
                    {
                        throw new AuthenticationException("Domain user found but the database entry validation failed.");
                    }

                    response.AccessToken = WebToken<TokenObject>.CreateNew(MachineServiceConfig.JWT_TOKEN_SECRET, new TokenObject()
                    {
                        Mode = LoginMode.User,
                        UserGuid = user.Guid,
                    }).AccessToken;
                }
                else if (request.Mode == LoginMode.Machine)
                {
                    var machine = db.Machines.SingleOrDefault(x => x.SerialNumber == request.SerialNumber);

                    if (machine == null)
                    {
                        throw new AuthenticationException("Invalid serial number.");
                    }

                    response.AccessToken = WebToken<TokenObject>.CreateNew(MachineServiceConfig.JWT_TOKEN_SECRET, new TokenObject()
                    {
                        Mode = LoginMode.Machine,
                        MachineGuid = machine.Guid,
                    }).AccessToken;
                }
            }

            return response;
        }

        #endregion
    }
}