cordova-ubuntu-2.8.0+14.04.20140130.3/0000755000015000001560000000000012272510676017172 5ustar pbuserpbgroup00000000000000cordova-ubuntu-2.8.0+14.04.20140130.3/www/0000755000015000001560000000000012272510676020016 5ustar pbuserpbgroup00000000000000cordova-ubuntu-2.8.0+14.04.20140130.3/www/basic.js0000644000015000001560000002431312272510553021432 0ustar pbuserpbgroup00000000000000/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ var vibration_length = 1000; function get(id) { return document.getElementById(id); } function init() { navigator.accelerometer.watchAcceleration(function (v) { get("accel_val").innerHTML = v.x + ' ' + v.y + ' ' + v.z; }, null, {frequency:100}); } function getCurrentConnectionType() { var networkState = navigator.network.connection.type; var states = {}; states[Connection.UNKNOWN] = 'Unknown connection'; states[Connection.ETHERNET] = 'Ethernet connection'; states[Connection.WIFI] = 'WiFi connection'; states[Connection.CELL_2G] = 'Cell 2G connection'; states[Connection.CELL_3G] = 'Cell 3G connection'; states[Connection.CELL_4G] = 'Cell 4G connection'; states[Connection.NONE] = 'No network connection'; get("debug_output").innerHTML = states[networkState] console.log("network state = " + states[networkState]) } function test_vibra() { navigator.notification.vibrate(vibration_length); navigator.notification.beep(5); } function test_alert_confirm() { navigator.notification.alert("This is an alert.", function alertDismissed() {}, "title", "buttonName"); navigator.notification.confirm("This is a confirm.", function onConfirm(button) { if (button === 1) { alert('User input: YES'); } else if (button === 2) {alert('User input: No');} }, "title", "buttonName"); } function getCurrentPosition() { navigator.geolocation.getCurrentPosition(function(position) { // get("position_val").innerHTML = position.coords.latitude + " / " + position.coords.longitude; get("position_val").innerHTML = " success "; }, function(error) { get("position_val").innerHTML = "error"; }, { maximumAge: 3000, timeout: 5000, enableHighAccuracy: true }); } function getCurrentHeading() { navigator.compass.getCurrentHeading(function(heading) { get("heading_val").innerHTML = heading.magneticHeading; }, function(error) { get("heading_val").innerHTML = error.code + ": " + error.message; }, {timestamp: (new Date()).getTime()}); } function getCurrentAcceleration() { navigator.accelerometer.getCurrentAcceleration(function (acceleration) { get("accel_val").innerHTML = acceleration.x + ' ' + acceleration.y + ' ' + acceleration.z; }, function() { get("accel_val").innerHTML = "accelerometer is not avaliable"; }); } function getPicture(){ navigator.camera.getPicture(function(picture_file){ console.log("getPicture succeed callback: "+picture_file) get("picture_val").innerHTML = ''; }, function(){ console.log("getPicture error callback") get("picture_val").innerHTML = 'Capture cancelled or error occured' }, { quality : 75, destinationType : Camera.DestinationType.FILE_URI, sourceType : Camera.PictureSourceType.CAMERA, allowEdit : true, encodingType: Camera.EncodingType.JPEG, targetWidth: 100, targetHeight: 100}); } function test_requestFileSystem() { window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function(p_fileSystem) { get("debug_output").innerHTML = p_fileSystem.name + " / " + p_fileSystem.root.fullPath; p_fileSystem.root.getFile("test.txt", { create: true, exclusive: false }, function(p_fileEntry) { p_fileEntry.file(function(p_file) { var fileReader = new FileReader(); fileReader.readAsText(p_file); }, fileError); }, fileError); }, function() {}); } function fileError(p_fileError) { get("debug_output").innerHTML = p_filerError.code; } function createTestContact() { var created = navigator.contacts.create({"name": {familyName: "Family", givenName: "Given"}, phoneNumbers: [{"value": "+123456789", pref: false, type: "work"}], emails: [{"value": "given.family@gmail.com", pref: false, type: "email"}, {"value": "given@family.com", pref: false, type: "email"}], birthday: new Date(1985, 4, 3, 0, 0, 0)}) created.save(function() { get("create_contact_result").innerHTML = "Contact created" }, function(error) { get("create_contact_result").innerHTML = "Error occured: " + error; }) } function searchForTestContact() { navigator.contacts.find(["name", "phoneNumbers", "nickname", "displayName", "emails", "ims", "addresses", "organizations", "birthday", "photos"], function(contacts) { var result = "" for (var contact in contacts) { result += contacts[contact].name.formatted + ": " + contacts[contact].phoneNumbers[0].value + ", " + contacts[contact].emails[0].value + "
" } get("search_contact_result").innerHTML = result }, function(error) { get("search_contact_result").innerHTML = "Error occured: " + error }, {filter:"Given", multiple: true}); } function removeTestContact() { get("remove_contact_result").innerHTML = "" navigator.contacts.find(["name"], function(contacts){ for (var contact in contacts) { contacts[contact].remove(function() { get("remove_contact_result").innerHTML += "Contact removed; " }, function(error) { get("remove_contact_result").innerHTML += "Error occured: " + error + "; " }) } }, 0, {filter:"Given", multiple: true}) } var media = null; function mediaOpen(){ console.log("opened media file..."); media = new Media("testFile.mp3"); console.log("finished media file"); var position=0; var duration=0; var mediaTimer = setInterval(function() { duration = media.getDuration(); media.getCurrentPosition(function (pos) { position = pos; }); get("media_position_duration_val").innerHTML = position + " / " + duration; }, 1000); } function mediaPlay(){ media.play(); } function mediaPause(){ media.pause(); } function mediaStop(){ media.stop(); } function mediaStartRecording() { media.startRecord(); } function mediaStopRecording() { media.stopRecord(); } function mediaFF5sec(){ media.getCurrentPosition(function (position) { var jumpPosition = position * 1000 + 5000; if (jumpPosition < media.getDuration() * 1000) media.seekTo(jumpPosition); }); } function captureImage() { navigator.device.capture.captureImage(function (mediaFiles) { var res = ""; for (var i = 0; i < mediaFiles.length; i++) { res += ''; } get("pics").innerHTML = res; }, function() { get("pics").innerHTML = "error"; }, { limit: 2 }); } function captureAudio() { navigator.device.capture.captureAudio(function (mediaFiles) { var res = ""; for (var i = 0; i < mediaFiles.length; i++) { res += ""; } get("audio").innerHTML = res; }, function() { get("audio").innerHTML = "error"; }, { limit: 2, mode: "audio/wav" }); } function recordVideo() { navigator.device.capture.captureVideo(function (mediaFiles) { var res = ""; for (var i = 0; i < mediaFiles.length; i++) { res += ''; } get("videos").innerHTML = res; }, function () { get("videos").innerHTML = "error"; }, { limit: 2, duration: 10 }); } document.addEventListener("deviceready", function() { console.log("basicjs.deviceReady") get("debug_output").innerHTML = "Device Ready!
"; }, false); document.addEventListener("resume", function() { console.log("basicjs.resume") }, false); document.addEventListener("pause", function() { console.log("basicjs.pause") }, false); document.addEventListener("offline", function() { console.log("basicjs.offline") get("debug_output").innerHTML += "We are offline :(
"; }, false); document.addEventListener("online", function() { console.log("basicjs.online") get("debug_output").innerHTML += "We are online :)
"; }, false); document.addEventListener("batterycritical", function (info) { console.log("basicjs.batteryCritical") get("debug_output").innerHTML = "Battery Level Critical " + info.level + "%
"; }, false) document.addEventListener("batterylow", function (info) { console.log("basicjs.batteryLow") get("debug_output").innerHTML = "Battery Level Low " + info.level + "%
"; }, false) document.addEventListener("batterystatus", function (info) { console.log("basicjs.batteryStatus") get("debug_output").innerHTML = "Battery Level Changed " + info.level + "%
"; }, false) document.addEventListener("volumedownbutton", function () { console.log("basicjs.volumeDownKeyPressed") get("debug_output").innerHTML = "Volume Down Button
"; }, false) document.addEventListener("volumeupbutton", function () { console.log("basicjs.volumeUpKeyPressed") get("debug_output").innerHTML = "Volume Up Button
"; }, false) cordova-ubuntu-2.8.0+14.04.20140130.3/www/index.html.in0000644000015000001560000000763712272510553022427 0ustar pbuserpbgroup00000000000000 Cordova-Qt Test Page









Location

Acceleration

Heading

Picture




Position/Duration
cordova-ubuntu-2.8.0+14.04.20140130.3/www/plugins.xml0000644000015000001560000000362012272510553022214 0ustar pbuserpbgroup00000000000000 cordova-ubuntu-2.8.0+14.04.20140130.3/www/splashscreen/0000755000015000001560000000000012272510676022510 5ustar pbuserpbgroup00000000000000cordova-ubuntu-2.8.0+14.04.20140130.3/www/splashscreen/500px-Qt-logo.svg.png0000644000015000001560000010202612272510553026203 0ustar pbuserpbgroup00000000000000PNG  IHDRT"bKGDtIME3'O IDATxwt]y&gsný{)QU) fʶŎS8u,3p&LILLLb3v"Y(K* ;@[O(bp6io-/J+-@XuМ:I)uB Ҡ2)) @ RKA8#>b 8.{h\ "":7z(Q_i !WZ& H&lmh:KOpΑ !;~Pů>U@h"?sxW)^FaK!7 )7b.MBAPȗl`ΥcjcXٜ(bY.HqJhӵܹAqйE;ImϘMB.H [00w0]JRyk* D~Ų$!'$p\m]?:9?Gv. .|haپ"qBJp?ChW~s5kbKŒ@!)sCIm߬ 1@||xvlqe[1۞| BȸS9tap3&pJܹ __؜ t Rt1=O:0""/:#}{iK?Փk<5sXjN;jQ_uHyBtȧ ߷UwߴcY[jkCƧ1[ .!QG:S/7upDD*=|V*ԑ3yã6#4TG);za#" _$϶XCF'w^ނaagqPyDݎ-G nN_yпG/wMPʰ4 wW-n)vÖ) xKBt );!EWތuzEg "!?6 þ ۀ5-ICz@StFGֻ͎œ~๽@: |adU}hm`7R, t,dAVք~cqsgॎ <؂=Y*i׀jQY\d5hRnyl !qeI<0:N㯩&ס 蔐]KhZ}Ϝ:0"$AGpSm |9: Gvl?tOq<x!P=2a?ݨ4Pő9WݐdtΘW/L!Y҄ρ:T<5ltJǧjB]u(DKaj/Dj!t?=ckig!7Qqq|w?o%b>PjYGc8>N 9D$ KDE`_yjEeJs{w0 :f71txQ(I_|nH)Ҵs?ŲBŦ9D:޽;oH?08ᯂ۶Ub 4B}$~PԬzē:*.% 0nN"sr4cbPtkUH"Sm͎ 'h~sbදh-:|}%dN>Lh{ޜr'.x[{2fv;^{*Nm{jg}rrڌꌁ|pj'{;]x(ޏM>ݗGrׄ\{FlXv"Z)!OiBt]hXݿM[pB?90q6jN6yzTA^4t [6 >;BY}!ܢFDKD$bS .m[+u]/kڂF_|*}Ooi˪io: "^BN~T4BK/8_e2~3GD+-SݰqP~N9o8^ y?S;?~15CWf$5" !@vH!:ujBv`yu[e27 ;wTy[[H 8tJ);f:^L1>T500~/Weܴl~6!>o n8萎}Ϝ:0*yBhܗ\n9ER5$n tO@tS߾=<.;Bw/ޞ>'w6ص1o蜈hO]#;~8xszo2kpJ " 4$vr=];?p݀HXɃ{p#O-fnڐwptNDD9v׽t8k&/>wy~pW$ nAm傛+KJ)RtśZ\3^-#i&s""O8$ 50`8~LtJR[-G ?zu,g]u~w_zx9!~ͨy ]- OCBt gҫu! |Y%sضɜ(8t F@BJА.ŝO3 sD'ltLŹT`C| 5LDD!%%pZRtNvńgn{ۯtM;ڲ:GjDD$v-WrB~* `EX `%nXC%ЩjGvچ3ߝ% >10-VTe}""Vڤ}a8pr;He9a<]S_x}ȸʟ_'y-LDD ٩ABt;:z]E,״-dNDD4hYCC:!1^.G;_:yWBR~`26g¯]k:@s3!CJ)4S=?u3$=6n<6ۉB- B48>}&BtAtl?tGI Љ|hLzqLz 'p3SuczYj$t]{J%"" J{Ml xPsݐB#;;O}ѯ*``P47B܉(ϤǮ375 jD7Rv.L9 ]Hl9BLDDZI;r;ݶa Y:pnH%v&^V@:Q8!  4Yi8~T@t:pKs[D)w"""$`& g% 3)w"""K ]gP(H.%t9+-&t"" yg.zɔ(oo"""rK8""W@[ֈgvB+܉GLiLDDDA@f.qDDD#K_at""@/ Qh ȿ4B\;QLm[j ,r'"" .3_(;QL%t!*f %܉fS\f ~mAj޽Y(tNDDtuU4^ikDDD3RQ܉g(nV;3:QL!:QLO :Q̬ڇ΄NDD4;#tLcK#tLB7f`rNDD83 =}Wim72"""3-osFESDDDAҺuDDD\eDDDgLKUDDDٚS9 ̈́NDD4_BDDD~n|KIE*k2t&t""!+2"""Lݲ w""@4).u&t"" l∈nΔ(nY+s]ikDDD 1_ln[+,d6 %Œ%-ڜnq B7lbpਉɼ}ŗ߻/"ZT&2*42H??3Ѕ{;F#oM [ACDiYs9sc.8."%u 2-gK8_D` K:`Y}{oU_hάECjj-K6r) ,9YsCʟPrqa8F QR:iܐoBJ '{8[⼗4 ش26d%X*Vr3ڪ6cyf4BՎc5Hjjۜ,.fOxΌȚEID^3:/ZL_E3-doֈci}vK#J-6݅F$izVWVL}m0g;3xq l8NfZGՓs'5ͫRicJjwaSPw 2%RѐZsq|eyF_=!82'9u7eql"5cع!H%4Jlo74cUvO˩b*Vplt >#C/`Mz)d@ʊ5DU!ۑxd/wMk5ı*oKA:6߁Ć[hOHZ[Ė;aK LJs> Vȥ9w8fF=Wz7%*kM*р-îe*Ѡ8pЅMaSmx߆_E8/8=$g)0CDL(P,K⇝aĢXVýk%T+^ |G i?nlڏ|/^{/<ҰסBx-ldQ){ku8jz`uU!]. &[Plݗ^82w=2gۚsT*/ AxT$5|&_^ хog'xIUnR$4nlڏ- {<24gsCZqxxgG% b:ϝ/a(uto0%- Xr7U5}7dE;-. {2nυhmLn+2&t]h 9wSqCj"'EFte[yk-q~M51 L^QuT~gxuS5n[uکl޻WPj: W.ۚXsEq^38Gz}U{];oh N!qHA!_ Vs}6Ʊ,IcLQ0,K+īݓswܻ|+-{LJ_ƹ#8yE{nbMXQ[ }ZW 76߇:E9n7Ʊg[<:b EϿ1:%pƵ}GD-'J7f(XkvЇB:Ǔ'- 0v.{Wк_Ʊᗑ5GeιbT IDATJ訯aUvEٓ cBG讁w`OC| #x_Ks.DށmKHG8kmUb@*!pa{=X1ܱM*0=˾zy*@K] ˛s ܿ3to$GE76A؛^2o*hH-G&^ " @$x,z7ϼ7tok> d_xONjcԼ6EEztjdU[9|`]xt"Y_ŸSDvXRX&"z.qT;7{8ڍ9t|_?\'Bw[k/p&JJE|&6i܄:y;s!;e6C{B$1G/3t;nk? =?/k}޳9zuU4m|<;_#e5?Z``jۂ80!Dz\,⌂};7qv4**^|W0R]Vç߷ /xo}wb0;MU{Va\׹SN46٢(* YG{ATQ8z[/d}xLc5p|X/>>}u.ہs;A9}*Fصf6(*|~pG:齻;o$$=1AB+>utv@Mg$ r3n-&QDFn^Uuus 8 &zkp U/"S?tDrFwq S!܍̎'c~w >2ULp kt5L!/:x[^OCM 7jf|䱲U ܺ9a+ "};0s짾2Jp ]zq< e 0U彁U.C/'<7WSJމpᣣ}Uz46]!Hp$n\W˵H |{ r FKůbyj<Ғـ557ytL!}:I7V`[- {DCQ)>h}MۧN'G~u JX|d…^{RAT沍vm#]ݒDk};=tG`95 q,Ć[D|'G^Un[V)f>ܒ|iB[ܴ$&r6F&3_Hn*qk{65^5(z,f@>Wr+RnaCXdCc&F&,tʄ6¸t}e?:\ahd¿vL`xģ6^u[W$z.,Gn\xgqߚC6-!Sd@K]F 1ZunEuBtp%4VVoǩGJ;[@` oXC' #pw/bh4ɼ q ZW]- z@USݾaE +"iD|F_:Wֵ&_vm@PK }2S9 ѭڹ/ڵ-H#y5E[VV% ZH+~ lw`')HJnO%tlJ̹EݙCpE-]MKw&ƊUJLu8&[sspCc;VVmCU!t7~)2/?*u][z4g^31?u-oN୓X閷 !!T45;zSH%dE_-|ic4B?Ɗ+`؏b?Ƌ+`4A@'Ϊn_< uf&A "vhX~f'bɁHA„0ټauZcH' ݭ p8?q8swC+Y&z'ƦDSy1Ci-nܙuR+%X 5ry' .XT]mmkuHQ^_4&z'* &vi`|F5SpTX*hkZX]Cɵ h0V: eV4YG(1H3iPWJDJ";)iXޘt3#?{jCS,h0;b>j|Lb}#tMp>K2t&lGvڽ& x]Љ =@.`V$ј^X¡/d#thu 8y\ADj]YG~1'oԬlN`u5gxr͵j GM (-ڊآTMœno>FK袂j nIj1+fEVdR:2 zyS28>/oC7((rx(M6שʟ#V 0T+LA!a% =t暭&l3R U : s%%Д^f&t 8&JX,o%^AD1;uK}aYpn]4.怍e/bh\@[c 2# ^dl]Rbh`iYfkTtn$R = ܟTGhܤ  T2*j20Z`> 5 1FƄC kn8B#kÀ X ]ׄBB"/0zCM q=T##jE[Ƨ**W.զP"/0XC} VQ Ț^d*q󱬍 l}W-hm`BbBI{cS?%#^CXruUG`8 "jNA[Sꈼټ e[ޘ&sy}F}蹢rBu*V&+ٻO&ϩBp2a.Qh},X t &&ϺO7u&k2jFcY c%򣆊Є˒^B(<8Ƴ S7dkIܫ3j>vG0Pl5[ F UA6`IiIT%DQZZ+)_5VDUZDzzVS#SF☂5ʴDheު Ƴ6C<qeH. =T+S*  \PY`/OS  =SȖFH0ʢ:~},k!gt "m 516ڝ =yIGLlf"ِRL]?Xa$D DŽs#Q4%tR Třg˚#^P6**%r昂2CyÚ42)6`B\p:9\Q(Q=_1ߛ0XqDDDŽsټ9>Gz&棞-8YJWey x` Gqc:s}g*4ZG4C+ ZJL>U0LhЅtFAD4[ERG=Wt-{_]jn7Ś~Va1~9k C 9藙PQ\P3k}Fem@6op$^xkRëSyg«oYM 4V;@ńs>񸆊{.W!`Y.vկ!qjMtM83L]2MiQ8s*1tVA4mkP`/OWΣUx$%S1 JфTpWk_"ad5;Bx4ÑWaIXٔ@vs뙞xr-MC(&t+ܟL T 2PFAv gAB&C2ZU-Ie qwKG^ '|m8`YVU&TT ٍlh)yNDŽsS ͖7BO'ݏ'h>=k%t"}NEBr\ҕt tô$lG"|N&TQdHMSqBVz"fͻh?e} e {TĻY|s=Vk@b., JTЁeyI0̈́bt!ad\+,ž$P|+b*[>mHQbڌla_U#%Cd1%*UR"&t?STڇ0Javu%r<|d'^H_)(؃ {BdLҕi=T07f? P].q+E4LE;n$3-FM'Y.QM*-(Z9|q JMĴ넉iBp/L R'*|7ۄŕ\'LLG9ASFd:03BWVGڶSJ+WPP^d$U$p0DŽc:O%VTe˰?U-Eu6&tS%`h1фGFWc(XM}}> w)i+8۾ w@tB:|#)Uc:g+Y^K"+#LSd8>WU웖rmk'|7XIikܶ6?]2`c;&tr T}YNK! J]^@4oL9Qn,W0L{@])@}ʴmLsEajTlxPuohS05vi*g =Lˁ_Q(gDa }>S*~'x,Cζ9~(O=9dE6&t"Z($t> S0SD!#mCXr-VKK' ]e ʝ ݧx>2-V ~$LDDcWR cL:-LCD~„R^DABwXCD~H蚊%(W8lJ "qv-(ScV sޭ%v"%BD~4'j5Jv';%0"_;- % =%(@ЉhQ,:%7ۨ*wR DקĻ:̈́N1#X̘m$ǑlL>I&"Ezp\Yљl/YC 7&`ll/I x;L>ehF]+ zlSŴNLgΙ- &tjz8WLw1׵8 b!r/ѩE~%}PݮJ^>iSGa߶)w &tmD,ut%kaK %jde.=Wc+8k$fDc^ٿ Tйݢn*^k3k..{,)@}PtL%u- ']`>=s+ڎNq%eKL藋G[\Qaޚ(ϳ%&tK&Ln[\dSSB^7ǽhA}L>tFfْFbڽTr2Vێ򸵙cBۍpw]4#LKYM@"6eu niŢ8r *F覃<QrWQ>3 yrp={BĄs)#tXm;Δ{*EP1\E_QtxLʨ@KF!/*d ϥ+n %N_IԦEgþDL>LKL '˩Iјr+ghcB 'm>m||}˜um$tđ[L>Wp?^,90"L J4zBYSjҠ!-ϥ Sya tʪ(nz=^gg? R KӛUE֦C.!1Q C!JVD8N 85EHŔ;0ei4TTrEqXCϖF`KkޯﬢE[ cBv(r]pt,ZS9U!rH@$(5]FuDFUQ M)KSTLI-_&5tGrO4^΄Nń ڿNmnŹLz6oCJwk!i@eAQTvXaB ӛټqЅ3&A$އasS-&R1w0Q䖘92ً>s-*zw,$c" b=kr' zf}XA^Q¨:[1'Ss#^ 'Yq3[(ܐǑ6 }^ LJŔm(¤&ue1ɤ?>R27FMazT)(NygMxBYL܏Szx`삿GQ88zT$5],ɼaNQj:+O?X5Ws^@hLQ[~}x2e^PY5U07-"'XN>>s DUOc&>Gu)mLPtPPǽ22r3NȔ֨2r渂A:^T Qw ]CE[ :r7'\_+L>>2~\Ӏ"’_TÓT;1 M.N2$k%[DNk̽d< = TLp$G {BP%n*y6c0wӟoS ݑlNÄ)1 ,5qq򸢨!I F'Ogz-vZ"64< 4ոџYp70 sԬϴϐu)C&YVw}&liaE? sd^ח;S5Bar  =@$ޡԟG\_+,*H^$FM%-EjS5=^]]dNm[NĄ -ul7D5^$GW@uZLF_䢋 ]M p5H<>ܘ&ö%GJ8=¡) }hLMDu@}jkQEoLєL{Xv+; Bj܏N( )*:BP0BuLJ CN]r9>tj.Hp!IoFKus}S7 d"VB9VADt]uQY&ZLKzBb4shr{. aB$#t˒QTҀ@SjA--eO1G W/zGH-zsE#%0_2*Qh: GM%JjbM"s՟=m'". LJGC3=}EeOhD!\PO3"Z{󚡹MaB  8ٱòM_P몌P.IpS7CղH2kLDŽ@Zqb RJ9 p[a5 :ꂸI =h.õNe~nUsBWEgg,K:e %C MQBi+9NXUsñmG8BTBCSgEeObد [Y~zK>%M1$ ԥ_̇.LS;Ww+ Ia-) `B,'LJ_q}0ЄzPBUAܲVTo Qz1$bjF.ÒWr=/qzSk[XzLd6ayVCPliۦ8VUmWr-?RНt,s^~LzYu*)%N/B3^HWЛcXǗ~=F3 I#uÄPms{|+ 0$%XTBGSU ˫(rg5G\KUWscr/@$t\HO/qcvT%Qj: Wz.\!֪)\ʮW4BQJN_ .La-¢@G^RU𭩾\UXSŵ}Uٵ:z"ӕ:V*80? []s!,Zt;6ݦZ~#!qr5eKwx\՝74\d66.M B!Yvn6dww@x7lꦐd qec.ifT,ɒH^=Hsޙ}Kck~; t%:ClT\Geff_j *r y1_Tn?VlB#sN&87L֐+0l{Hҍq}]e&/&aStS4'DO>$-Ō쫔Lc881\fx?Vd=\+(. ]&ۜ)fM<~AMEeDYL]HvɻN@WLvEAǹ3,T`q\]!1k?-yyQ:MT/b36EҢXޝܡBm !%@|,%v4ף#`H±͸V/ X_Ef?jG9āu.Ew&lm iŅ#D'̶5Y) E=Ɛ;H0F<"F"BP#xN`09(laXȟC8'L=pZ"pDц_;5zw:]+nP;YV/4H_;=XZtj8^#Ӣ۩?(gt*2Lf<75/@@At=?(z^:Єyg, tl^\9˂ݛpKŗJ6Qs|TiawZKOkm5,Ёi@ă^N,_#8E_pqы6\OJ30<WMG3& z;=jgCaoņ/ff/Ì+:9ѲR%f|aE!1྘_GgH3GWƌލ !+HppǬ!$Q׿օvs(7bS `A`:L͘YR@/uR9TN`XXa6ywp(1Xf\[iŷ[*8PcQ07ivџ{9r2to`=ᑄ*޹O"\=#"rl98gŜ1! , +݀423(6 S>f,Ǭ嘙}RsJѧas'㏪* j4{&'Y[}XwUtkJNLQh)Ǫ?a ($7w7EҪ#UZV]ѿ[wpH- i wȁ?Upk88:9&]*g-FyTd/Ce%N8’2M zIi)gEF8QEʼ.4 ~y+LL,1C>+134\qۆvg]/3M[?,V-j`^*Td/þp/pg130d8S2Nw=xN#,lXYI)FQZL:+֋*TomFkO`'9I(ϺW݌c"X-]fG<țVjO5 F=ac(Iksb~ 5/HԮ/!ܡ3>|[X֊A~I֠3GۛȺkquӢDi;^E9 3tOhHX\\#ĄĸIAh1VfȾkh w((,uf??aL1(qǁpDK*2/*2VqpPPArwD>~cX>W]:X]/+,AZfY_5vA߰2g ~4c"iUGr?@ހsh$:@ĹEHX͇!w5}1V(Yb,.!&cmp2if^xﱸh"iف.*0pFBpbۮ$*I@'0\$nH\Di`k՝@Y\Elcl]ʴЕ_Ud<-r7 ծ¸Ah@CX >S$dV5^x"ݥ_A0 BK"u !Yd>7}ZB99z,XboJn`LYcD"mt~1C^}de3 ͝,3Ռ{X3ǃI4:!7CI[9ZZ@$`6xޥ;T蔦u|:rB7.G9YŋO30X޳aw^OB=qj,M7 []zmg}.>Ҳ%=3ƃa m?4:ܵ:˧/K1io`_~w>fZWAC $"ɀ zaaݲ,YcHs|k斟kMTkrex|/P쒯$Ewyv7.Ɨ.T,+ .!,ye(NR;YY-B;]D$'%)(5=z<'qwBYg#…gFvA[z30Vq4ZwHռjr;G`pٔC"^#T|דsܰ< Drvn*S0VMysrÖs'9}|cp433͂)ʿЇ\LMvt{No̙ )__!2|TT$EAg,a2&'Cspڧb `W &L<݀Cڿ !"r#:!5E@jKQc< I+nuD}]9,)FPt;""GsgF} |agRl;5[pUqRЍ=&V.@]wqbV;ҢLDY(s>5poFAwsFYK0+g9l@>mk׮ipat37E?[f:$$*suF/'Ć(ri&6F_ľZ6,n%E鸮\Wz$.sxCGD0&X0"\) 0yEvKZ0"7wpRAW@XĴ> z[83Ǜ<4v7WXў6& (M9jG _2-z8mG G8:H5FP% %%=1p\%l98 p`k/5;JwpiU;1`\yEZ]AR(TN^^ w/ n"l:B['v1m4 ˏ=L|ՎA)3[!\rEP?!l{JF_qpZd40,]o1չnBVTɩ{J1!M! :9C`+s!Hش?77|ar ahw֩c®vo@4:mbW**8L s n =N(݀^R;FT ze\~d'eBN*g0(k=ǜ q:P2/޴?Gx旧b)>?w~dƷ8* :9N`{M 2G{lk-'5Ávu9ȰD?6vӪckW;F|@\@n7_-k 3>#xB_t$xցjc("5E=k`G{у>-<!\FmRA'‚35p 4 }~v EqYgTq˯~m#5 &K<#^ tڈks!o+ΣNt po%2[OCneq\tѿ?<i܅48>/=g_(FǨgk.rN 1ZG+$*ox;݌l^xL߆]xij}2YΆ~NUcm+!*O[;0R. I8a)WN')m(΍~gI`y _z:/QuNϣW2m=N\ւ\ U`74WN;/=G$:]jG4Yi:|B23ٰp[?ҧWaskIS̜~|8cxָ(nW}ƥb V,7(# :×E8\J C4aQY HbN c Vh™9QAgo\0iXܷ<.+NZp'+:>>#| IDATz78AFXp4!I럁m`QTm+sp ;D}O|؂ _gVMMn (IԱ5;h>֑q3ܻ.A\ϡ} ^4qB#q 4'iNL~Ik _&Jgbq }5 fhrEzZEˆ.+\AcigTɄdp|l_ Dzho3r#J$q""VӰS;&jQ_ |8/8=I>u݇[Wm6iYYWcFRX G+eCˆ6g- qu6A +6 ظupE}g>=:3VݧXF}AчWOVq`afi fs}!4u8ֵ :#xyK3 xO)0=sd.@L?#݀Nw܍J| :JqlëD 9V? F\SrA&yBCxmtՎwcVd´"nzt[h[OA bsy9>pqs1kDZ! esQ6 Ei(N@vJ3J\߉.wiCeb :ZY ÛGdܩF 1PQOp=xjGI:,i/(B`a|"<~ gހ4x#ht8gǁYY6!ݔ4Ct ; ǠC>*D)gm.X-Ww!: \C ;sJ5 Y%)돸:|L1vx/zYoǛ;FX.?rO@`ѷ$!q;N;^gĈ;eM&OYߜ4y?#6w-{x]B Z\Aב<Q :yY<g;KV| 󣏡YvBWTЉSuxL/~cc85rBd2"^}bNcj:?)&ސ'\΅hgY%>U ޯ+Sr<|6ߤ:}Nb15Wf ?Vǯ7uc/=W|f߈!67Z2Sը(5㋷=tFTbض#cFRhI\?aW\-ADɍx8!q!g $.I5Wfb4{pqC5m`%wbRpcsᲫr TЉ&V_qу'p^9+[{Q}X=|pu혒1_ԉr`K/P׿ZQ3tA)&/ʅh ~ʇ@TAW`YɭXRxR 1H8h!q%~VZlc(3 Qh ͏B)v֮ .♿ƼXRx#*ri[`RvZmU; !d4nFǧ&70{dzkR?{܉qend3 KnFi1w/nuB:ő3,`q{‰ gDasab/<P{+>y'e±j Lz6ЄT}rej -#M`♩C#{NoLr KP;!dgO[Nւ}!v4 ~P2m[Z)ufcBA;t 2Ru^d=!/EEՎA^NÂ2x"Nv41Riߵw'e \BI`_k9-i9Eۮ@*+ԎA`{~i>"0aTσ[{%&IA Owh)+IPb]֮ ='1Q Zʱ`1!PloTI+/I'5w l#{x~c܋mYt/?< zk}N 5 :I fg_TaԇP~1!t|r ϒ Z: U U| =0ɏ5_ }X(,FM`L@ V1!~tN[# ?C~+nG^ Cd[~j AS$i) s88I4>fNcB s>V+!jPbOz}5ɦZ:7 3MH$%Z Hh'4P!0\-Pu#DUth9GCot}pBQ :I:JLL9']_^]vB9 14_ z#Rl{_FN$je";X8$ .si 2r>EZr KIs\_qלo2]8$<FS,i=Fmsݢ@Ġ ˲KKe2CX$$IΙrcHR*18׈G(1\>-]vtyJg$}6q݈~i]~E*$i-eUHefJt^.4$N#D.VwiCS$i/OQ˖G¨߉V(YI7޹O"\vBsTsbxg8T?Fc2q]ՎAH:/r'ln[~uP5;Z#'x|A4ijt=fOI5F8"ݍ+,9eOS;!q@hϨ-~q&$?\?$@ʄJR ԎAqm :IzE9̙"L0,p5} ;Jҍ9jG D >>sT zIgn>z.S!Sh]oUeuNllI_¡ BɒO!ChBNWe>+H}8N`foKH"/ym3|%dSuna1DcnI^:Bvݚ 6|dv^uDoS(!`=CtB&A/k m#O`IĨ1oRA'<3JRpf10v?**yLvB4}*\aIWX>u]pJEIb r&_#\Dx{O7;r^0 ⛞^RNE,Ms ]awT ӗ{ Ѡ$* 9 ̇5N|sD "$g+\U \$ ͅI6h[6z'Lu/脨-'];W{F_o=[ FIxav_2XXޡ!|7g*Bȅ% _2Ne` y}B! UV7T /ܶ"Ӌet2է[NdGWo6?5/Nt EI^+E' {p~6Մ$UnvMk4_MFG$IdCSDB AzQ tB1ܺ"eEC8OQ|#^SƇm[#?YQzBk秣(׈9܂Ƶ5 :a5R;!۟]rC1Q""TF_O?o}|6B_ ()c295{+5tBb,5E+|^91s'?uXFXzC~4,) o@ 'WG3kT $Yܻ.aipՇHdbwA}3Ռ2c`ǩ0-k1cwIL}Z :! ۀ[Yh=qw9}h823V,@im#5hdaVr^K5J^TՎBH IwW-ۤL*脨$$`Q*,EnGAtD0|S8GSӊLX03JFˍzq}~ӡ2isP>%sPd2}pD<~b!1Q #GNgē$}pSkd :m[#@cR`”`.ጠg(zF /|D{eE9H\D @`:)Ø;nsr<"Wē:ŝZ zf  }!8Wȑ X|/DP~Z $>E{jݱ :!Ɉ1, X8#]^WCx"~Af//˺`H?gqGuː"$Yqg~?NHɰaѡxR/=?:˘h0]YI8C'B4.FŔ8CFtB!66UU|/zZG!d 08K4u)/BH1&a?c̺ݍjg(*BM ' C~I>|nCɥNBd c8,^믖 Li. B;Ər&6RmUeu@`AB0.1&&#U6N*B. qT.|.i :}%x-N0&˴.t0 !$^'  XvxN!$!p8;NTUVKwNvAB`qkؙis]Jj ==MtzN!jI V/ 'VG4]i:!h 5ZydZuH`4] !LvrZ&Z.q0Y*j絒 $zDd$:.FvBIƞus 5^WK :=B' C-$X!C3L 0aFB1zIUUVw :!hXC:`XXU5KD !c :I'D^UYQ;.FtqTkagH|N!!he "2XWJ{I,h3ZN s0+g&I _`$yh )ఁqT^1~mu=X#8P98 䟢S.Uצa wSELXv B1XGIH9eGj#L9*۽@v_0,mTw'tB%*08gv`[6;!D<{us /^6n ˳|nj'$p~Ǻ `s I\uduSn0,a8)7_椩rmBmPq$؂!#5a!$]tw+_ %qzU(T Ag3 V&0Ę5,_~[`m侰|s{P4l6]'C$.$-6ة{!d.=Ko<խ;W`QeҮG$ 668M-l۟_!m\[g ƥ?Rm;;W` *$. 3* ] 3=%ʸ[}{6_@*~ek?Fb_ԩ8gu R}Xϭ7v0BHrPoժkb+0Nh03 Iafކ}j#`c}xW]Qw]fO1l|B. 0+[o0BEuIOeD=>q+[pŦ߿!TIL`+BG5{;F!ш8kS"IwCޘ%I K:wB$|{߼W7`7n[1V?L)0):&IXgcvIdVA'ڟY \pk`ݻW+[1`QB$zp L!luOU*IpTW~~TQ"dX=z0.PcWJgrBR{~qۀnH_9T\@#\FW3RUY BIPtxrڻ~Mr}bdJFTl$Aosղ{H!$ :|wWW 2d}XRt &# [Xz 캼ƪos/I9IDAT!$t׶E&dNF"rIR~r!$Ĭwv Gm`V4Cec\8+c 6c7h!y֎Hh;uL)1JE.s]`sĘ]64m^BI-oqͧ71gb,YycuWUV{NF!$:6}ftӾOv^~dK'!YBVpVt)UnvB&XwkTǩ 6&0f5HzD`B&Ǥo=[V7G<c @8s&7uUBTܺwWu&:Wƅ^KzV@$j~B&ڰ=noX?;$>62K:X$P+8l:Dh3 !L꛼U쭝G]w=scz Tb2%c^YqmtB!%^5qdaw)fܻ.OXpY96H4A#BbI3>UNx6w-+,meڑ.K;5ڞ _9!5hMho6\2ˢv5aXtiU6NF!\Awd.Lk(lI>!5t: 1{3Qxg.pV9 ; O!L:M1޽vp;6ln09G UmUoiXB!DqQ|wW|.83l`&jdVUYݦfVB!d2ɊڞIENDB`cordova-ubuntu-2.8.0+14.04.20140130.3/www/splashscreen/2000px-Qt-logo.svg.png0000644000015000001560000050561712272510553026275 0ustar pbuserpbgroup00000000000000PNG  IHDR PԷbKGDtIMEf IDATxyt*Ie˫  l$gLH陾gzN,=4$ssr2NOtd0qHAUHd,YW|,۲HU9:~`}N9=./Sݲ{}g|[%ؗX/q̖┹5Y$ $5ȵv+Y`R۾|EcɆ1~k\ҔI#c"IC 4ⱦc'f>X, 4v^FP,P5\;5K|q|q$- ,XkIn,|z2 f4Ҩu,0]| v@&m == l`{7f: &MIK"iiʂe._&ib7,{Vob^c J/Yt̏xdGKGu5}O $9 tUS/ߐY9pemtՒVRJr*VJ2oLYџ}fz,OEGLo~W&O8/9*ʧҐ)Gqg& Vg|dK΋VWRnf~{=^Wސʇ<~+P (}.˶7.R[<6tksń8*K:"&;vpRv&@/M.p Bs_#H()tN`0!z$;h\zz>PN:߹mɺ5Avָs/BIuIĘf,knvPR88miL:$I@e_T,W.%]"%I:ὒ\hGHݩu>y, t[SkWYDzJȏDJ$fML&uK/n,Llp(ԟ}qYHٕ&\u.XR&|kkoKoƚ,ƚ**yd)V9rűT,kK.wWJMc8v/|fZ1jOiV.MZSܢjH/Yn3u{RW̮^L8'DTϼaUR) wR咭I:.MLE5>k͏?O/F*RɒkKtjҦ߻Hw޼T)tT5%{]~mI.u3}ח(ETw]M_]dWHRҊ2Oo'cMNErOƚ(/ǧbMNIE=~uΊcsYL~RwYw&?{3o[c;6^Q6ߥKH<tl<ұ㓑F#O4:il2R\9}iE˓woM[Z`b ,\'{?'0QL6U52]eҙccG# ul,XY#oT }'A vb ̰ÒIǥ=iO'>t8GaYQێ+e tXIe EG~v\xN6\۠ ϩM: ic|E'v'0{(Ёd_,V֜?1w7\RPISUz 33]vAnz[YtgϤ,ʹҞ|O?=J: @fI.)OnHFmtQ*gz*itNg6Sk.YkjMlH8ҞN8= ~ t7~Iw9' tdxbg@7\X7]E Տ@e$W.1iԢy<_F%ٗj,MfI,z׏_TOF*OnYX^PxͺHfݶ֛G$#/{q([8/ׅ&97ֳ-=I'3Yv|DdOn]^nmSf/W ʤyTAI &r+0׷j?C,Œʶ5E'Z7>9ɩxbkOCM˵f5S2%y) L)|l3"Z}?#{NXv}??F4Y8/|B2ռNT!%; S;M t-'(qV}2ǖ{M5'ZEw~rLN_Irc_[t擣 ./uzZ d:Ίl[sr3 ]ukǏ58Rń/V-wЪP)&$R\p)tĂ_ɩs :ޕgelmOQޠg+kMKN,\ot)T\)SztI™qYk{)+iɖNDc=crgP)ݿ~֮Ytp\y72 L+3mێM*麓c1MYJfZ}iIG6"))yޥEc{RwӖݹeM=*:;zA {T33SՋKdK\ɤ . ]q!©t9|K#I mk/K*J:ۓS~{Lbv@m&Ї7.K: y$uJV,ՙ|'`Q\ -J:kq=ʐ&ɇyiECF[7Њ%d 985TAMMYrAwV3=&S=6 h듳 e,Ї&H: &$2yd<`6Pdwrs.~{LϽ2"CB8 6\DmU=f{‰R&O%* ǹu#%-=ᱲΠ1uS IG]:`R( £v& :|ZmvW:)Xy w#yޥ0Ps0lK{O07QWO|CfOiSĮAutwA>ܴ\4(yeywqɤ jjZwT1 *-x!ڄKf8*z;΄PP9,T]4_)%3zdۚ#]r4TzkTHtϭKueIG8J)B7h>~3T *Һc]/$[3GJ fV6}IG%:ݕ7) £v& .]8.MgQ=!#qj Rz`J&(sEy@At-=IQWoYAw]3SX5B7;QbzV.Wji}:(*V.-2MHzrY Ϳ'4=/vk`Aג7k^G `z]PlZT *Ic <R]lp|U-%R9֓ԫ{g8*^AK݁Y#RٖW_"\W i? #$ɤo^/O: NG=R#_K:\G^;)_ttsxBxa@x>xr]}¤Kʻr= o~p yuǦM%.cz_ɝ1=M+tE oXs& =mn? iU}rٶ?2#ӹTv}swKLe.=ʌUoҹr/^N:L@me/et-k{dҦVs뒎cJR(Wfy).[qUWvb yuɃKZ7kN56`2TLoY k,i:Olkkn5tf.=a86Pq+wҪAI%+IJ((ݰs0d:QqzLOߜ5;U8.8= i}ΕZPj3>y*&(,d]&+{sVi\Օ]bsCmͿ%ٴzCrqW_Eyl}\{>JD&fѺr=L\aɱ I敺ڤ.ufw˛)T\1J}x?zwc3 *2mݴR.(@B3KVDžr9dsI'=am͏/GqTMd,TT;V $t}.uH^,K-I:81 wWӽXrmo;7(qLٸ\W^0(@5뗔wyA r8(f0*円c8}#B:A&*d/'JC>~ukjmcW{hYtG3 .҇l*˘L\w,|:|ol|E6K5ޯH^30\җӱ1~3sѹuzpJR<*1%)/Y(Gƙr/;8ZY[SkW}YOᒾtF)qfe66$@(YyW₻.|W8/ 7Q4mq7٧{ѡ9̒)WkTQm%I{̔T ph.}ON%F>Zۚ];Pԗda47>¶xWZnh$3KVeQP,,t4Tܾ\^(0WH ]ʙ<A&*;k8p]&tNbGѩ wuKјL\ =[ۣE.h\Ngm+ա^s;[_sxY4% YA9,4#m7^N:`v-?JJjm9r},$C%[8߸IG*EɺLV).[qUWvvg C~ڱ:w)S"lDCˤMqj5.$ $1Sc ph.}OS)|~ٴK\7vcCXJ]qႤcN.ri Q*O' Ż`@? ֚r_NI7Mg}+NDZNjpeI1]6Y^*[!>t:qa[~o:k_շ;8ӑPYQ߸Q+T wI\9 ,Hb ?wIjC#7Mn:kMkmr W[_KIG̾$ϛY^"JR ;y> i L%-:GS}*YHJ+I-= gy´ԑmi?t0(O!\_6}_Z;0R֗8Is{ׯ׽r9`$!t-=IZۛ"S'h`< P7mT:S JpyAny.R7?8`0ΝCmM_<պR9֗و W6VkEC&(6,SW*V.-ٖ@R(O` n8zQsw}_]&f+*܇6s@bF$re _Iԝ,h ּldkN+ UK/O:eV y 1V(tp6PKȩ1,$B5Xِo}`2 ()Idy<06J{-@Ϳ-_j]qQg#*]Hyj'0xQ.wqΎѿoߤ 林[an2]IP޴LN&\_~Ozy34Ύt8G+IG`إ \lSrFNPKz\};YJjpKuRI\9*Xd(~g`~kтک첓AaDOhb \tN>yW#BξÒ,/Y!=˹G7L:-Sߘ3?8{j24-<`f'yKrI(nb\ T{d}I07Tu}{)|&YLJwez꓎듔sSyq϶$ O_lZ9IhT)|WGJ }MNmPRyR(JᤃU{*J^')]cg@ݶ<`zIj2YLeTaI:*V.IML:0w*'[ۚez^'~8zlS|t ]y¤c1")C qks2yZٶ_\vىtڏl:=Bc2r,/YAe˥7mܟlt8?Suzk{˟K=>4GE'cBR(yARKwtYoۣը Ͼ ^yǣ'{FqmA]$`~*ЫYh(ٖrJV5֯nMm%y{z9TkV$o^d7Ϲ{ 53USokkfzD U6U5IG$iw\Y84Y~''UQo{nӅ;$տ%se7=.K:Ne,R]ItfC|\#[O:p2;^.?N$=!s̈ire}1v&J>:$/ rP G6ؗt`@ zv4TchA1~sn7 i#ޓt0T+з~ukjmc˒F#7hb*J *ݚյ+YA .uȭ`Aro~pP*n s;(1#L[nZJypv-lIexcTIK98dRlӳe` ]ϒRy~d ' U&mj!Kɤ$SQY;ǴC2IVHǞWseC` ϴ5_2) ]G7TJ(*5%I雐JJ.q*-G-`Uz~|3>[\t :>aRQi9+tCnKEEc{~P*b} n8+KOʝ03>q]0^dwϻy 5Nw"&-r͗(1coպ(HW$L*[ۛw)BjY84Y~'N ;6%z|H/$ ߼QYYt]JsYh)*fJcwM$l~OL;G~#SA8D"T,<\v$2-*ĭ%ɭ`)7Qʄ_鱄3Ty=P[nW.=)' ;\eKSR\0c*]?m̂y[2 .yHr$fκ#W$UJ+gRKr;N:@%[7V_9I]t T[#iLOFe2e7v)r)Wʔn9p`yi^NSw--Xo@)dt^H}y1SqS林[ly?`sټ@+GsIq3*25]ېt `:19ovdTOR@At:ݑޤnOv޾cJoQ9ݰ^ܺ,L藔?>~|b=NE?IMn=S{~aow3*6~ gb\$L Zۛ%/HAyW/J:0LWٶioױoLxq T\Y-71}iXP:Xf[ڻn̫ d1s/' U 6vinK2,yDR(W^85TAMMY g8y3} ˣ#$~뾧7S~5_אt `>)ஜOǞڿQ2o&ˣ~WoJXPjkzc"nt$wMZ7J!Ņ8Ֆ}ٖrҡ@,*t$zh1dt_X/M:Pe(YA򊕳T]4_)%Ty1X;z<<njIn^Itɥ@j]\jmo2Y^ nU]u1x?qom‰ΓbO=X̬-֦>恲I{dyФ&/T1'd?9FyNny"r].\հp"޼?^uY@q~4S [k"`֚r_nHRpIGqt2TX;ofL֤*uL2~z,t 9sz=:zsIzCq鶫>*{[U}n6<`b4 0C6aV̎(Q2Zͨ>l$)fFd5_fҮN%1PLVlz |vvw^᩷ZU{-cUܐϔԦfAkqORҖrtج.o:5zM9rIIGXǡ.:ԇj)˥ђԥp;繮gw|m$I5|"Ǟv+^{{]G#IKѤ,ot ܶ]>(SsďmuI5w&5Ix&GVگxܻ w~xׁۖ?R&)Q? c5M?sm.ݿm~ǒ,%e$Gk)+,Ow~鉮t6?IJIT%s`]d>5IjM3Y?_SKr4,G;M m7_ȵM8h\O_/: zL~-_,s em5r;*ri|{^yΖx[*b[SrkIMix;S]ݻ?w]l όJvR8MgdgΕ*j~RVRRfvYcqu8jf}ܔϦ$<{-{]MR_j哻??u8f&˸R2 s6ݕ]ou Z$7֚ӵ$)5s]?Д\MZZXJhmM^S{/Ԕ-})pn) 憔|*QIkq$Rqz{w//|w`mIx׽hO=;̿?ߊ"v%Z>d%iJif3]'([2^c->WOr}R?YKRjL,?dSvy4/:16eӝM-{{,ϝm[rL~gM?=~MVZʸ7^Gv`ss_kM*`{&)הc߻ﵽY*ZҴYMӟi:z"w].$f$ͨ$Go:)K5uO6˿/?u`ⱩG[So') 7ć.-u `c=ԥ/%+IsLYY8|C]vM@oAr١Mupo/?}]6%I$&IѨ͑)ZJ&GjY^_|0&Cַ>xz.?RSJ IDATȁ|| I*{Oe1˩YJZk7ÇX( mǙmnǻ/mIɓyz+.r럽633 tN'YI~jYI.wqa&kd<`>sI򾳿JRQw:zdq~%)Te$GgJ3[lSZ_[f|5nI'RZ{//_:r>>Z=s~y^kݻZz%1)7&3$)5Ϸw-@Srj]jK7WgF+{' _^_Ϟg8j7-wϮ9wӪ4%ܐOԔ̍f]d%5K)4V~ngR3ß{lٙ>X+̗$ͨ$GITSe$Gk,ǿHyal O=wJƹw6eI?c]zm,?_RҌfp aCV_2{cI^ܭ=823S럽6Y'JҶMԥSRdžL_sr$yx#$޾_yHrkI5IfȽroVh,'ey,paR|'^kJ>wL}%%CGɽ,ίRjRJ='ݟt.†ӯpac^SnO}I9;[Ky$)9Ze-uiWrvRȗ>_X:{E+՟&ې`jARURh.Z:pviL{g^9~i[X{zsRK\RRJrKIү.5һw=:5md; t`&ܔԤ65cF_;IYJrmJ]99;\tס+kJt` Ԕw$yGR~$d`~jY.Բ|z8/>_{jʡs} t{ܘS$fhJY~q|ՙƉCӍu赖}:]$7ԚR.J4Y.rt0'ylu襔Z+S$yKJ~"߿c}/kZzKf3]gfc{s}:t{cRXk>ff<#%YJrRF3]HS/;X\<=YKf98,dIT.>c<^w^JOM1zM u*)+jjjJzm/G珧hMKmMK w,>u.k}̪3uhWܞMM3)ZRri~e>G|xwzkrr,5.)NIR۔^rdq$59ZJVfifvpӼ}/=Op $`I>$(GO$YIѤ]nۦ_} %JuS_.3+6ف$&g7MMj#ΟʽYI->݅̽׷½m<ۓ$Vte_jnI-gkҫݻxJRJۛY˿}Vu wmhO%}Ʒ7睇Y_IJMgoXuyk /3Į$?)O9 ~TJr-uگ,[ {upE_?뒽O$=3O'W e\u %$~69ڌʳgvO}q'9}S.P' tj6Mvmj.{zۿRהrrv{n#z)\ӫ)H򎤦֒}~uMOgWŧTסzh}gΘ@ IRܘS򙒒5G(%ZK?iKrtuf򻇿qm?jFתȕ$o5oM꧓dn4#&YNRIVR}qow>qshX7'ysJ~&ImF98HRJ),g3 _t\sgNq]R5Lj$3Y<Ѥ,ZmaY_:>^^ 7zg-Imz3ɑc59&R-ee\}_;vC޲oGΘ@`{$w_*R=yWs=k.K<7ZY o^SÑ tzYS>@`@_ MRߴgW t&пk2GM0T㷬ѸV:gMzӶׯ9L5m<7 ]YS^JyZ[@`:@k*CL5k;Vk+ГkPZ tL,_dZs:5 Y$Y(Xs3E5 f[$Y+El,k׮XtzMּ}8T0^@/y wk`}uЮ# tg zj F tZ&ЯXaC+Rk@zi@`ǻ`Za#:S޺IL pw0.\'WZkjU0.XR L e+ug\@oJj G@G.XuwM0.Ҡ0.X pa+/kJ&Znu~$Y@i v0Е$ñLLTF]9o>p};G>kDkD胡t߹VO4^-q`8 =[us:0{YkU0^Vϝ79/+̌&@ Myf{e`x]}fjyY=9'@ez'@ ۍKyZvOz/+Zvu胡tߺ'Ы+=; '##LO<^]v t =>Z{zxl\ w.J//_ x@Gֿ½׼'`'xe>݈ЩuO׺AIxEN|:l^ W0^QIQ0^V=].YyE&3>`'x }].{݈ЩWuB^Qn{`T7"tjz t+@ЭuMU(^Qnr}U+!ַ½U3@I + I^<@gs[ג5[ w9 2t}ԾI_\ca]+C:;Ëͮ.@^@s@ֵ½}N4Б 23eҺVNb>nޤ/nmp`xi{tv+ ?T7.@~􃓾Ñ*KNv 4eƆWMuYc :k@Ƌz.@~x}бupw:;K+a4Б&k0tj]+`x@/MvMZRÑ wlAK/Mw Z>oT Lqz: mNq6fuxvT5mJvϖkr\}lv? l ZtZkN<(Ϟ/~<mK33%Ҽ]7</襖LؠFjq|fc 3{venLI~!Q9:up6*\ <0Ǿgya//䦷͞7{IffWooflowfloWf9^3fWve\oOJ)=?0ۓz~[O֚3I i8v5v3gF/d0>ӣ93:ӣ93:ǃ/ `s:l< }OlJ}uك?{Y^__K_7:vd6\XǧS9z<ϭ`-lk]*}ۚ'ѧyA=>SύRkTKl>x]rkrpU9\\2wϗ>fW1^˲5Orrpd?ztYrt{ߘKw]Kv%K]WiE:쟻<yMM\Mrs7ʽ=o{ߘ]=wOf6WycW}<{扳Grs\l+5mA~YcyLuu=֛>]pOS\7{ߘKv:)\ |rcn}~P?uGWՌv]M>==ޞ\\\\z[3umw\?q~$ON<)\\?jl= Nm>hwAm&'}Hzeԙ IDATqב6uWڟ޲7fkK+Ţ˷4웽4ogᆪs?{zfAH,(IQ-rI\7qr9;q{rs{rR]'-[bIV$^N:LP b@ 0Ľ7Gkq{]yū;6ױ]:ֿ뽯 [@On00"фɨw07 [Z8ǧ-U33as*0_T\ 2{sj~cFwFx.إtrpv 7S=1?сc)ʍ= ZyfxLRmBT\|9l=TQFKʷHɘN:X`]U=wds] Fr:ښjȲL%Kek [3M6j p'InW{:nAg`]U=dT*]181ye~NMKsZ5%5TS 5(mJ}u*iEmhF};t-: rՅtS:p"}#<T೫ɯ&wZ╚[RAwٴ\T.Q[fm$E:os`;5FI=Q^AP ':;0zsdX{#:17ϙ.GsQsxVU4 )LUV%ZKTRvioNc:Y0*MCspH:FM8RsW}j\L5j ՜Ŕ,el-\E vk_Fw:\X@KLJGa;Q"]9WEd*)!L bUlU2P{;O ; rJva;&dר?wkx$ϖKr:lZՊ_݈ ^E׫W?M deWCM 6mQG;E|A{T"7uU#S?ЎCzbQT怖zyEI{1!lV.Ѫ.|A{_h"b:9vTJOF?U*/^ZJV. jmRk&:l6+Ձ7|QC^(#r(ȬhRo=nMK%©nj+ֲ۬M.hrRsxëjۡkGdzvt=;oL`?g'Fƞ!84xzz9 qaKk2g9@^K$Szа=㝣Srj-m5se[d<̄W.,:3:xF;;Xxd5F`R# k@i84ǘRִj~Wdy+jYV{f& HY65-Wcr>7ćL P@w!u%5UyPuI}Ͳi~jMW3@-ҼU'cRSjEm*pg(!L zO7҉}`ԤfO&wZ'@^8trD/#cI Z4ҐsfhVW߭Yw~_j3Ok`t425Vt\J}D/ݯ]5ګ Udݧe[umT⫝t03njloN?+ w(Ji^xO­ ˂-%ZWKʷm`: ek5ZE~ v'>b:3:@>KI#^uwἺԥ5sSWHjԂ gyZ[sܧ#}oiɟ蝎J$ yj{OcU^ 5{E[^jT}m@v>ئ~t@NrH?sgFw䈞{_DMG1*eZ2/˺|Ԓ-ZWJ}H+}W',琤Hv:'WBQBMuWt(F9V/,КB/{]SyܫW8 `v9ו~KcvvGv0 ǝ}w,b:Y˃ .q~_n/`v;CQ{H;;~?;M`R(hRmCJ{zPuK[)Ru׺^GjQt[CeZIkǙgHMvyG $)m=ht6.jQO̴vͭkߧj/3 u_˗vzď48m:rHgscjiz=]~vkhB9.as;av CP~s)x:3|t,9ہJz&X~w3d3=1=jb\][[W4uvˡe[uC 2rhy-ZVU{^R{;cFbѤOoT2לiӊ_v\’*Vg&` KZk^#}o녣ўR0GYnoT2%{@ϿɞsYR[_Ws.yie`nizLsBK3p9V[uf^h:K%R`td5evNvg/dר(ƅNݲHK^s#NYkOQ=-_9}_bIV2l=w Szn{T*#nKZ fQ%'-VWߣ`BTe=ۿm'ĈX<ᐤ-U./6hDOң(UtǺbK^Ǟsΐ6}J GWOB:`My{JfpBOң=Q,mXZ5 dYwuǼe93?jԋGWNF\ vdT*v7Mc\eإ;+Vihsͭ uk}ò[@;CZW^<=rӎ'YL~RNtbn麶Bm-ms5~WaoM8[H}P^9CŒQӱ9tᴥl0)^z_ϿկDu9Nq]ʋ\^sn?2 |ΠnnVWߣg~BTt,,$+=b3 ?uts%k 꺶Bl鯱diy孺: 2U2?im֮/f#I:ZJzmϠ~O8WEoCXU%wuϩ>ؖdlWC;ԡԡ7MGB@0([OErҷ,ӑt>8'^Q4F׹akdk.`2l6x_<'gLGgwSHȈHB?W ʋ{CX`rK[75~\N;%Kme:xUKFMd1$%Sf& &e~bFgI״iEH\w7C2k6nUlՓAoyZ)M9 ?L<&H&gK;ijzuŚ_ꖹ#ݗd\tY4 e0߿QQB][wmgO{]@N' e~t8fȞ~bFF}#Ihl[kuw,l0@^p?Gx 9$fq#L闯jAFKr:lmmI?n9tSǵ>YJⴹZZE?HdI>M&y p~\Nv&IEwCXeŮ=zpWU]МdUևJ;:# X:vԣ(#%Iskk}<3ޠ<0ť7h~W/H b:9TH"ғ=d˲~Ik+etKcZUut\-MiYVxU{ӑB* 'tLtqtbͫ=_ '`*ҿS?^ñ~ӑ3l=i|s.xǨSÌvҐSm*QqAw4ݨ;N.{:Ȓ9F?MG $T&YAO7 /*LUUևo-K[<9P_R<䥺EӍؔ;Уt*dJ?yG;5{uua9&=OTH@vp=k%N?1 0I:=FSdH4o=A,_.9Z^?d(IIR*eM=q:~:j:Jָ~YP7*e/],3>^~gH-nKNgc^5_lS*2%+]6ݷD A=OU\l %KQCpꋞ1 Ɣ;S`6IRz^=j/wv=zsYy[/[\b=d(4؁R"ҿ?ߥ]G"dRu?4 sE_KSAdt$VɔtkT1u5Ih8T<1eÒNM-Mr:YJ< tde9Cll~iCX:tFF/;uLtQv-oYRE4l zl?{J;:5ȩ֣Y6Q#% '40:Fǜ*+rj~W *+eapCl6's4o"9WLTNeCJ\zhK<ֹ%~&0v\U5\F5ɔzW&|ٴ3=1酷TAUPHWy~fxX>}q}Nu@2DnjSG  ];_U_8pIhBKgtGtDTY< Z cc_OtP<@][￱t\ܒ[~9S+愖ƒ':rx~N*үW{MGS1} $LG n=D΋֥,y-+P2 I~gHn+=ycl %)}._=Z|Wts?#ͭxch8ޯHl@ñ>E'G/Y:YGD_vjd34VytưS,3 \fٵS.lFӑ@t3}Z~Q^GVW-KKFk8>pk_sEsJ̛r=gR,NjX"E\vYgjdT,Yt}sw1q乃'Fm3o(}#jtz}䴹t]:,dl{l݂}c c 'ssB0z .6 \NA\z|7צS#InVS+(xͭLAw٤o41Ȼcup?_?wwr <<^šүڿe:<75I1':/?:}NhILr}hXb}5{׽pOdt/0!I̛W@:tݺo#sr%K[|L%:hK@t~ȥ?W>Ug(ML~nPOãj`[]QhG{40ڥ `zЁrSQ/T]Ktx춬f{wX8Sz̳Z# .Ͳ]|11GPh9}%R $ = `;|*ʊ]zr;)ꃭ%:l:v3GL8ͺ`ofK!OB I)n[L?zFNgz"'D@fM3w4zdKooݯ G,T^2xlgR+WX*hI{H|P{FNꎜP)%S 䒩w(OG_Pj(I6˦[~F%:t(BR~ L6HvGn9TW~ܹn:ujpNWW(?;cS:;G)_둛 soP< KR}oKFM0 FݞCd IDATT\ZWb5|X,:>GGh``Jir'o?IBnMT±vvˡ~|䑖Z}dѿc7D"?w'<@=8mn.PM][>IRQnޮM N ȤsOYFS\EcV;ntưʊvG,ik %.ǖϫw8fdJھ7wEWw\)\4ȴ_J|ZYybɨvv>:/ɉ_ } 'LGt"5Tz.:l鶹U[fCi%Z}bߩ20tоg/R8~xkMAu&ͭ%e7N!O8 M2kd4CqQM?s>UUwHIU^h(f`TE%˲ҞcEV8A10:0l7':t'f:JVYP״³!m{@"vmo1,1<1*ÜmIٍrܦcftd-:D"?ӥ㝣dō~m\w|e1@6[EtCJ&M0"}n9T\4&G@s10(JuĈ(YңIgZQw=Yd֦Ǵæroe,}c)t OJz^<4l:IV)+r꾍acս $ŭ֦O:zc:՝ʋsHZf:`dg{M*=Tn۷џn9 %ͺtqvTW\}-I 9ǯUs&+@*({cdӦ7(൏9^.CA0i++o׽-_Ͳ_byc.IemM A 30ldY֤Fc:xbDOk:FV,KVI9[Bwd`k+۬/9l_ u7,k< B 50™~lR)^һMBjn9Тh( J\.1 `\I);# q(/:%MG*+Zs̒[PeR\TBlK:+<6( : Q@FEG/:?0%̩kC8ZRvD [ֿ䩞8%NP@dc{dcft`L*ҏ^֙(Y%\Խò,khCÆR\W\G[)k: ,b:BV^hQ4fvˡt y^=ʃ 6=pcαies l'7ى䙽|.+*pHWk:`LL33ѯ UvKw_VqcrZu- 0}mz/M @ƒj?5ø% HKrMҤn3oun^Uʱ^~gHX y~C@>jсpxTɤMT@d!Ԗ4 3&IVJ<q3=#.hdvˡ/c9sBߠT*GL0oWQA! N٢Sa:`P@H]NU |v}}Xv5tMRX\.c٭IoNt43Z]gs AƷ#tU@F1NcG׵9氹Т?7 -X.0$>A$U'\#v\w@L~BR):.ubY'3* N[X {MGpjJ'\$N@.R=8+J釿P$a:JV,Kw/cs|YZQyT C([`&u$Ք^.Q*i0¦#f yv{ObZ 4rr{̌bo>rdӣJxWelt8l.>1ӌ;ѯwuڰtsݧ/c,TS@,llu$%$ۙ惘t\WiƧpU = cx6ݵ!K &l秀9&I)'H?ۥHcX7v{zC2gU]P.2I7f:FV)M_@;C*g8 ft4I%9L/_Q1ε 4;X]"IC29’cUO|Nhi` Ё9`JvhۮA1NUK8exgK[G4]OFMG ]?1pLGL) Ϻݦcd˦/>v]_!OT8mn=姸dCtKKwKRChI ¦#ٔ tE<T4 n^UP`hq fdBw>L (a:FV-K,TN`8##Bd Z1Jt%%=}yChi x)@yI~f $أ]les@Mc̛Vj]d/e} HFQr+ht0vï S Ё\Eu6 @xmϠuNmZs 龖/7`nOXg9h?sjJ'n؊ɣgJwqfb9&Ȭޘ~zYfIw]W,%Kw7^W%!Oo#U@,K.s=UsLͲmFSJQ@ $).yynum*^c(2m@KR:z$ ?oe8 r ][xL}:3#Ttݒ#G|N@-ᵦc9tO\#?.GN\⥀9:HsttXb.4b캻 r?@z,%{MGrVF f3t-8hB?~[br8Tt9!J0y~=kr\7QzC: P@KNujZsߨ 2 7Td:{RRi s.p=Cr˹:i$}dt[}],vн-_rL6ku=c9LoL(%%Y;mnU3Q W['{t.r`$^5#+mXZ±Ue`DgkӧT\l:3>?f5 䰥L[6=͛z`=D~V/*{`{P"dz`u\bu{jߎ@r ;GL:v9uoe؂0݂2YtpW) uU%(Q@B0ֵh8M QL <^>t*u44„1I*/raRrpD5 P@n@YSZc.Ժ %77}RUycՔ>)\ -hw`2s:y,uŲ]p䰹tOdivˡ~Ent`V:zft1`[ W^hJOSL`tV/.TexCRP"31!kLԁd9/{@nR=:F:~Ic&}P"VY+*n5Uz泞$ ,ꂋ $B.rݞ%ݲH!e.yJ}cU>*mL-3D<4IWLJm~՗}s|u=.h1N[.6(p4ϩ.MvL'o:`Q@ = ڼ24XS e()793OGMGuS@tr=#t:tnX^(g~~Ybm}Zf:vKteS=1loC(#kzMJ5.-7vZ[f/P"\̒{Pra|9avkr [L6a?ߡ䰹tKLus'ts4ϩdJZj ;T@٣ @6wMJn-h9v]Jt70Ք^lpV@`;9W{}q,Җk y*aC0ҲcJt ϩ)K \$'.f`zi1~;wW F{4UCF⃒H|@ٮ--ͩHwXAw)Ș[ӾW58m: 1gzcx4!OBrilCOm=cd%˦ ˂c+^%Ji41{1tXUQEO+y@AwJ}*4?G9 y*diR*@w]}dt 83M: 䐗P`tai|k6n ;:ڿSva%S$P$>SCv38>D VU4nQYX^}c?Osy\< G 'cdҐS+Z [[ChbX@:#'iO$e.تujQ]f4yՁ5i TN<4Io6/ LW4On&$Ӂ \a]_@añ~zQ;;=+ަ}Ǹ c=?;(`wp(Q±^H`!3?4f:#ݷ8Ɗ{ZP"XzeuM%FM1b4ڧ]=w3V[U6ajdOd|;VX"Smj0v0(ELwf,֯.~F2'o\ۓkeՄ[MG`Sm#O͘,~ 7]֖l_$pt@x%]Ouy@[ 3T/\Ӊ1=szJRKjr&锦)m)K˖h<-;m)HfV IDAT˖|}HڶOd*v,˒g) QA* )ʳWO3CjGczc* V /_w:t%Sz~M}UPu|F|cKϾ9j:c=|W,kRjо2/e'j*\{0g&3-RQG%a*K|*/ԯRJ‹8kh>="˔hul: pGzJJv|kJceuC[M@Q[+*+**\xdNG]#?c-O^˧'~C9LGHۯ<).-a9Va X5x @Im11ɒ]qd6Wo(,Luw]J8xx֥. j-PK}Pr'Czޯm"ƻnVG+ѩMGn[k*}a9VX"U@'o,7NNjt2i:#mm "m( ܺԋ?/9ua~bRUn|:cS:1%I..B5U2V|\9~B|Wuw{xf&"\k:7ivH#RW?ɮ>yj(h wOU@FR4G'Lp$҃3mGkJ1}쟨oŠ>kЊ+$^;1pȫkBڰ6ڂ.5[^N 6T75Ɵ t`цpw*umMfOM sݖB}F_>oX9|K{j4zt; yGez;۶u´>+Λw;>2 z*Js5o S/2 iwO ,jp1w{QFAQB`"鸾rO(^%/-i~jUfGud W_ocX"l@Nq%in*{ڒmՄpT紮 'LpBv&x#{_J o[-QEuy@ݽ1"ь.IJ ꏟ~V;yt$Kd_Ot `^L)4_ҝՄ %c۶^84n:cݻX>l$XuOL&No'N|^K+Tk:c'pThsX^˧Z?n:0/*,ȗq͒f:0QSjg{fMX^G-MćLGY1m!}=5ZP`:ci}Gzߟ>wOdѺ@Z6d餀~]}E&Wy-j@Iҋo};K8XE9#lz?_N?J";T=?|OT'_ESQqKcǓMpBesIY>OZ@UrܔǓc8RYO[[l0V\NSg/;-i"'kTg5xZğKS}kKwhC1:whf;זl76pTKtt`kOqWf\{Cy-`Lćÿ#o8A>Xo)2Qz~L|MGp Q1IR@tǨ,) ++SqP"x$-M tBA2itkΟ`vײOuN3ű,#{J=eEA<֯7d|4001>g9X"Z#C?K)MLLppW3w?a+ÿ(o>hUVWٶӟTltTjЮwK`FÒ)[<}["v?{55%OV}aW1|PG|cź~-; $2Y%X iaNirޘO5ϓ=Z!#f䥪R~]*/tWz?K'{Y҂{pξY.,+UVPg(0+-4(`P:-zL.wo(pCyQB}`~M=}'J#>}]ժ)Ӎu?^(柗ߓ=6Xn!_S_eY֖, tcJcSI1)Msϛ> J"!~*sO?zsEQܢ@ֿt PH\dt h~`9XJ0ĶmLyN{6U}T K>9]^K чReiR7&?MGpo y:y.QCe$R:ҡ!'.hx!,\q@O32:7),CU}d*oRDD_ 3.5QvKTUd( X(`-|tt Ǻk}X)oH`"]!}eVTՇVI">I@wϩ1.5ogEvKVX*۶9p3]3q>^[3ֿMI}I|U*.(4Et _|ESc%F'I US2,*Ǔ/My.ZÊf*^˧{`"YTxѨ+ȧ=^Avq_=}Q,@O+ ]MGp6qR5>zs6y,^q˲x`>:rٷ%sUj4jMNF@ҖBݿx]f2գb: "rUXI[ 1" 7}a32ضUb:n#sj &54jQpvhkkt }>Ͱfp|@^g:Vl61+V+ uDMpewh4V#[|1zteIO(UCeq<دJLG0`vվt R?P_U_PQ@`~\ʋ|Tq,_gTqtyQrxCXgהlaXXcI6ñn)ek]6o_/^'1pW?H|sB쏾ݿ0< 괭a1ض DB^F2-%; tV&fuݼ XJ`5?l8Ԕݥc8~O#5<lyYHBDt ǘ}.I? <p2ñl}X &㿯d|{CDCc8NڶO. ^6UM\3,N}7JV;:XfN)||>K7e\>vHXtL={=YZ!MFzן_dts~tLGp`Es pg(R)[o0ñvU} xCSDV [>G2ytܦG?`Crg@/`5ś\t ?層 5ƷDetƧRc8eYڳ9w1jrulc5T1^՟࿚`б&gRH5}[JvJ܀:tXѼ,hxDV ݎO%r`s5H?g:lGkL@<ˣ5%[ n@er'+'eϦN<`( b<6/OJiQT,'-W85qb>htt?fҽ?g:3^iW[h( p ,7}Ke_-݄~PEN'@SQQ!Wf:#uL848Ȏ 3  s;2,3 ,FMp$kHZJw `U^ǧ5~t ,M!mll>|t ?L@JlR@KKJ܂:㓒m:3<ښYswЫz닦c`=T m[/oֿGo7s\+5s-YZ[J,/ǫ·ey ə_6ñvͶ*a؀>9EB^=rw4:Կot %I1:ߞ2uuxB"Ci[x,iaoT*Eg>eiHƵֿ57+dǺ59Cb)Np屘(s;ЛJJ܄,TSc8V{cJ"r'1@{?1޵L?'蟏cT׆c tR@β,Weve9XX>/f492ñnQ tM/0$;*5Ñ&|Eo~tڅܪቤi1ԯt@en( |L_ipt dIO+e1j.۶՗xjt7tA>Oި2\L9XX"OMXAf\:3p+\FOo7(yL!_7:@0`P@` L:~at ubmz\ yk&9l٦!qW>畣z7u|yQW{]pX"{TY˸\P6e` uzR4ŜX]vռS~O0w@nϜ+MćLǀDB^ݻt GJ$#ؠ8oxcI;3Ƿ{<7w@ qK*K|YFzȸz&e:Z۫U/l:oo,,3tnS4i1k}S g^˧uOL N5yEziC['54/}FSM\)-GMǀP@T`eQ@6fMZY>* cOg:gt/SQ?RmUk7Nit2i:c|K׿X^)b0p#(pK ]ò񹕅kR`"::SW{6ЅsoJ6p=u6Ey`gɺHސD݃q*kgtU?_duFkj2'ltI,։ sRap`|YD[Wɳc =ڻt zdKGԑΚMǀЁ*sysvCIqX"9.N+Mp6dvl8HP&/|t D zMp+ ꜖$}_(4pƸ#Lo5et`X$ƷVQWӜ{w1"<56D IDATHCm[}ߘNMEM%[MǀAC Rξܯovyelg|]T{݆7c~%1ܵ>MIқ=_W É'LGA]?QVy1 "yp>cIf\U<sܚ.~F4 ݵ>.]l}ܟ$3T=t OFsA[O:zz.m! f,{`"=c:V[Z BC $L[2p'5l7ZC:p ܢOЕˎ9זTYA4.|Zi;m:VHȫm R* }0`h">הF**=]Py`"fEߞSPƵuOJ t׉M*K,.s }*1^Éw6j:VXgo}^B90:8A^pm]<7m۷U?,'nuy:F2.q϶bҕ~\II=s/ 'egcZ>19}55@Q@`ɔcMpJ=e( |eFEc4TT\n܅~f5y`]Rg:VL,Qd3e/(33Ҧc8uuvE OOceo-2vE5<1[nǧd6p]52+{0.~j JM[xm I=Oy.~G[Z 3}PK1.RE]ȶmyr=guYwY_OaX]?QSmA͌o-nT41kcS G &/z'kc,i)E㳓wJٌVigcc`(0#o뵴ym(GdqjeMz-lgz.G;O׿&'r׿L,|#Jonbg3v1^8u 3vrLĨ]yP=O[2K{ &j;s[fc:MGpוQ$Pn( |qr%ELsyUY ZzVzzMps:ƷXN,כ=yNu(>}3pSlj^@poɲ,mje\PqDűLGnۦs:=u/H˖MGmdB5|dQ@Djɔӝ/qUsM@  o$ Ʒ#Y':Mu{━4{ETsIRyO偌k6* %ȍ:u(g|{.猰 z |4řWK1˲,olWt秃2pmیpmY6T7`a6_,KdXy|@>jimh\*uj >Gx*j dJ=-aiFZ񄭳ݼemmP9kUP"e'uz1;XPq!csb,5HG}]z1pF#8BZnUux@ Xt=#+%^eӜ6@8I1;vu;]\i:6oH˖JEtIڹ~js-d`8yitx MEMk %/Nt`lZWٶ3Ǹ_;N`{]Zn P@NGoT$cEsԒ}|H ot `Ylh =窣)mr,3S{>1pϜ6G e@k-Kw tꔂH2 tg^5X6mA%u+j2> oHǦ Ƹ;7cy_5`q|rU- 3mzP#˦:G99-]Gպ=^O^˧=3fR59R,V*-%iٲOcI`ߣRqO,re'#{J;zJ8rJT8/sYߜagFƷX@NțcB:1e:#*zEi;-B |a9ÿmdJc %5*͒}OjfO;DnG$>t܆=u5V^vXTbT}c+bߩQ={pt UMX>\{6^=$h/>p:۷:g()Ʒ2d:}t`ŔTU: K\{~OIw(PqGƩK7VݾNL?f4gV<`4R*뗞By,}~kg`ӇYSi /1f6~ub4ItK;]9u 5>=~JSQwdi}33za%L m{o^\/>Y7EG)]Z=ξ6;>>X FB*/۰Dc n#^D{MVT|lt Gm[zcڼ6`-[Ў %Vuʷ}i[#y?fz:3|^K-Ez]БS=wm{^W-;x VpDRCc 1kÚIH ߜ9h: yUXIѬ$~:)e'}D5]?<9i~Miħѽeue$)miZ6#К* V(Vs]t̆9ZvJ 0ndYZ:qqtG^le^?;v2)TMF-Gqи'񩔊^QXڠ^ɤF&Ji|*餢q[31[dZi[%f >GG__`PŪ+PcYV6km:в_A34 Ulgt**2qlD-[|Ik (01RhBeaf8-_{݋.Lsꊉ]3ڽ!r[߿x>폖8қ(z(" c(-,eY7Xb.Q@eCS(CneM%FMh͜*K҅Ёe|E}ύ̫݅m=W!_'Zz 0; utǔv;Ekg7F60$SEqvWutxNKMus{]!n t8V?Ow\7s -5fvK7tqQ tW?a:(M5A0m:# '5>Rq؛qsd귮l`.@y#_'1E5X|@>4hOc~R淦z.#IMLTTY8r_+R/p}?Hj +(WCцyd|z|ab-"P@*݌oɒ \l@M)GjatŴ0Z<5 3 XZJwcyom8p$Sb~nˣ`9I#G}W;ݧ+ɶ=bl+``yn偬d5VEe7t.+h&6ő: C9Ёx.ycL:kTVP:5O2x|MNlpXb>["-b$pdlBj}.1KIN3p&j38{;OhwS+puoZ@Hz,xb]>O@FUsO\X|@cدw_Q";<ε{t?d!S@g|;[;yN);i:XsMj&R(9 sXU IDATrk+ۣ.}DB^ &V(3D:0+- YՅ9IN̻ڎ؀iw~@yiw';ٝ?s7c󔙬,V)Q"V4J=CzAZi) Vl4Ǫ̪;}v-nefxYL~>soŴyHX;ܵF^laeph6_=]}0fSd'Yox:A uI7?s<|}e8]2: :+~cSB̯al!5"U,/&v PivnB_( 2t6 _Mb"U߾ Yf#Fs/l4“,w{?ߜM8 1ANk?;'zo |yױKJK$< Kq|jp>ťFVb5jHB6a_38 noCJt7# ^?nl|ޞ} E~3 ,/}eܹw~yoc`mԓ4ŸO{~8 qU X N֚a4wprq{e0|>* 3?6,(!|(o|`YpzN|r ЏoÇ˰ݺ*X}WAXtnY~Ewma2a2z= gI2*ƷqJeX z7×/u _{tKo0@C&a<^? @yFhN}<߼?Oꀛ._^ը'q_QjeXO.tX^w!s?Wk"5v'?] p :K~ˏx u_^s<|ocK={ЋNi6ʚsz p6NWG˨ϟt2t7.uuot&̂";kOtp :KW0_WO]&2B%.V5 &>A7›_G;up :K^n#l^D'X:ЋAش kwgo?fǷ?}J7gz4'ںsO.ك^3#Yze?n9p(:eс^lU`\FRa˨nf?~}a֓z4oލ2s/ ƸmO> (&@`)^$kIsF0v7my.=^@9o<@x`)kۋ|d'UFXVdB/uW i3toO:\FNe]h۷"?je܌QʰGƸm6(&?DV fѩG|C#jt $MbQI{ic:,qE^$`9xQ0}]g3:ja6s$ۜ|yZR ϶~?B52^L!0\(ŋ1;@-$N"&vfgO`YeLCowg:wϷ@с/IA6@^07'i2`%n>4^|3!(ӭ$$v#@"X*:=kf#sa0&v:2g,XCt3wfXst9]J"g|{!<ׁ/t6]c܋|7\3$g]:M8<=A6@亂~k|rb߼vއaj`av|{!,HQ%ގ1::gK$<@i? NegT2ܽ4Mf*Bh#}Ǹ@:=`; 47g_.]z=oP?\{/@`nu^(ŧ%Z+*6ݽ x3ہ`w֏JBxdEyCЁ,».ln:gu?^3$Iv2:xUT$$0bk@^$s](ӣ1Fv7둪8TZ(uLp'}0PT7g0_{{0 NSBYVB=45#@g;ݣ1zGXoξ]z- ;9Lg!0}4Hy̵{&g^T;?}Qr%x{d{75((e=ׁzPioQݓ{lЁ۱cu.fO雒ei?ܵ^Tڻ.u`tځz!]ezxὢש:5X~^Qݛ4BE*NAp/&g}P?\{d;kD@e?,v`/PKt7a2`Ћu92B%.vPF Vэ,: mNҺ+?h|;p[oҵ[k;?dt(W^{@7Ї]'WКW+V!}{ ]BLN}j`Mz5=5 #ܩZ ;v?@nKg'qBgF}1wƒüjTV#ú{{݁Β$ w:6v tz{ СT7~/s @ JCsnAUс^͇:aG:4X~ރx7b8ҁ^Iк (ףd='@`='0ŮZ&q8]^W<DWފFry[>>xߩ}Vr%x:LgezJBՅk4}_eh$OTR^Ѻ{PЁ~c0ĵ)@/rYh:LfXB?>hE%@uja?.t) Q@/h4 (Ü=OA` ':{?*ajU/@7.!o1PFIbDt*9;~I%>#.,uJ`}= ;zt` u[#uJU~ @~݁B/#T<ԒçƸTtѩvt\ J>QVҺYy@Z#ud?<T8Lg1g%WtNFc-х^$yP,sM:N@>^OFP |Y'τN@u_d=kV'EV]*Én!IǻځATBњBx4a)2}$IxvU~1PZ$Eytuk\ *tC ;@h&R5>ϽU !x[RpwSyɕwrO%2ʵyjIvԋpr>+ڍzе:Сp/('@X_i:3Bf 1}^чvCujC.>}߽ vYZ- =cXMt*e6\gzN'uՐ$IȎG&G٩D:С|A`Щ$c`}Mth7k~Xr5**cwJ:Oḫ!XP谮oUA}JUr<|Q2ٵ1tC>˽M9?Nt7+`U>j^w/(Ay%T$GX=P)Gg:wos E.v'p2zXO$ c{X=t*dr+VP-b&"T,:XAt*T~^QXeB}#TnS`Y {! nBl6wt(e?nz-7t*l0 \[}m#܁OGx.v:Mg! С|t3;Lau]! ͺ1>j ЋO(8duJ8:^Ckdkz=v6E/t8:O`uSmt\ J>jnYwG,0"U4mX :qq<+ځ~Xr%*9]hu !euC/s] :qbۭ%W%9:Zh6eTR!K4|p!T -:qt^~%@p8:AUBϕG<>hv7X~t*i_m:p{G7K lo؃'н VKaҟgX~t*lw;7[JX5GFCeLYwy#@8;O/T :0əw5I7KX%GױK lk],h&v qwxqhD۹:@G%TTyvֽ+V@&TV/]B%f kA!?WwC@%؁>h|NAɕD:TfWzd>B%5jT±;V=}VhZ*VšnMM#s0:Q\gz!$秺X>t*$h]u[?u<| E.A?T p! ,э'0@FsρEއl|Qmځ^Ģ# PK7-&?qEi n~ɕh`1,-; MՀ8IzXPeWT@U L~F'ùXđ]@/t|:߁~22b>nvX*t;>3NQ'@P%W,ό("UmF?? .tNtwp:v 5m4;d>B%^ɍ~~?{G%@ c#t[vtX;d] nځBۡ @yj NA:(`.&{<3tC 7lvOy%@ q,/@OBzP&,u.8gt az!?'>-:ف>z5wB-1ч%״a{Ӝ?'w*i/tқw7Z`MN%% JM]pi|;#ay0mY'yWJj6DN@^F܋P *FAN99?xps=?۵k IDATl6 gCj75oЁЄ^c#!EnOw i[yCae;p{'Kn۪$*9h&R%mGG:OG@T}sڭ:ЁEL$ <'gǓ0sX4@!:tŏ뮨}_r%*91fn<;ЧI8}T EF' ?³^l @?O܅,\vmJOсB<_no䳩X>S;rvZ#B5.@s3x>B%@!}/ 0$CPtBۣ(so^c'B%*9ՁKg=iT~f_I/ۣ4V"X_vk ЁeӁl0 aB8wd(@X><[Ovۣq}Yz `@?~,hFX%%X>=tfaĊ`mLޏ7?F8OotVZ :Q@ׁmlGXq̌U#D3ׁ>Ё|ZƷ:OV/^_k|G@4gC/j4:@nxd1,W<Wtb5'p+vKm0|8fO*%!k@nhcX^={s] Cqlq֟|+o7Aqk{͝+Vm[hcPIaw&oՒ9| Dcv @oޙtXZE뮟sxh]R=~vtoTR#͎0VYߎ9MfIHB=谼:stTawُ7bWSID@v%~]g:,^G'wؽbRz!ƌ[p/D7~s}6"Tc谴:F@?1Znct:M?:kto4#Tӱư6tulwbKck5u(v -ur ~2z Znhջa09]w~j^9^l ȴ82:Fĝ}`U 'g>k!I0yf:o2x6dd:Ĵ~9e|ըZW bo7' d;\gcmN+CG&,$IB =.3:DպAvD3iԳ흍c,Ӳ=؁!jU=/bTFcync;B%8.XFk{dOuCT%d< )5-;b6@~^#NQu:Gϑ0 'H[%d$i.%t}:sug4N`UȄӁ묟6q2z 6{KhЍGc:>pׁީmyICCVz!@9@:гZM;ЁOwX~O0"UtۡT3pBCЁ,.`XyL+ $$܉]FMѫxGM&0@?/ =;Ё>.Dv&kW@\ͽ% Я2on0f~Q3nDXg%H=0g%tk\Fp}(`d4E_CމS pn&W;yjP:YtWs`Qgc]*:- sM߀zj@ yzt:г~#^B!@n@39qm49½ ҕ|G@C/u.D?eځq*j![>^f4-O=~ỸX1ư:@79hT3@!k@9*:D:FZ i]~Q~aJom4bP#@nho-.(.@c;vSsQSUUwBm  v]tw`sX=vf F̵6C-+@D JӁځ|BƷ걻7kӁn:ĕ$t۱eFBt"u_Tف|:qO8LUuz>zWumt2V=k2d>qzjA&On=#Mw^JU @j&W^>MpҏT B@ &OTC#{ծb;;a^=WB\@ځ5yrDl0ҁ~Q}nFXvibz[V @ PE #u0V=_^{ U^[~:@t"u_-@`|1GFV'݊]Bf#1k@ƓYLSKYDX~/aB]pGtg=FC|݆h: @dq ^>@oف,@%.zp3A"wٍ߾F̳XVWKd$r2tP~1w6KjcD~~#xKo8=]pG@?RquKlp5($\wp0aU5p(z4܁J藱#oT X-#F NKHCzl6 ӜGblUMANE +K/}At`#谲tN,BׁqӍݳ|o:<6PZ:ZF LNcܑVJۃ.@vv˧PR@Zމ]c:*#': ckn\RuZRZ+v `e5TS͡u]'^H} j(hl{o;!?5aU5?9_zBˌM!(YNc|;(]yF'Y@l @O֑ ϯN{K@h+ g<>cM K'FJ3:~s`AtX]MC;С%ҁU>5t`1.au%IҺIw:֩tQ.'@4_e: 6]Y}^U6@w +(8&aYFX#Қ  Gu[z B|}i؁,tXm͆q6?7*Өfr+;@A@#oWds1_'݈]Bz=vT7oJ3 ЯJpnO`aN !Wϡ\#OɼF`=#oMtҌ&+F]P+Oz8J BwϪժWSULrN֌X F?7Ѡ{"J{KhQh`yb4y)h+V_ތI#k- V(W#,Jh4rF` Oz֨=}+8@=]"t[k؁Q4rx @ިp9)%1j:ЁE tXu'hPtZG@i&SLҪ&`y vê3=f|Rn!@F^;ЋGFJ32ynkS:DaUF!͑]Ql|$|@1.(IU,iTCj|r*drG޺2aL*X.8v @IMEE5GAɕUmz&yLbWP bJJ16J`鴄?=kN+.b> ebbܕZ3v  `m4REY Vڋ]܈R%Wj+X*0v @I7BtہBh6G(&@v]c,,v @I> *p :tv`Mf%%с5?k'%W\T @$SWҁ,B:4]A)ЁU1@o"PL@)FY*Q݀%ƣgtTr%E RLkɀ95)v45`(5j%Kl`; YYQE[.@`(EQWKw\t6]P5;Л&yR{` uЁ~}[}4XBPiXM>l$ͦtC|U 2B=vQXMBh>ga Xpҏ]Pk_ƓglTr%E K- ZLpfC~Qa_^UUvp#(+f%6ֆS[ފ]B\FQOK,8*]:!zZ=$^[7ͼ_^=!YP zcɚzm!Щ/BrCoWiԪ7X1Ű. С6mpJj # EMgݗ"֌]œZbj45.(IUFAB;.[7܍Y֜ f'i%!:TBމ]%%i^/CѤ_r%@F9 y~A`x$~% Yk&KB 7RZ@)&F]Qk.Xr0v @ZM1@*0e*.@4zq6Z&S;С ցPWԓz%7Z{t3Ms@jt#(&@&_j3.(Q#:S;СҤ9vz #oJNtCnD c5b,,v @E:TCbpb ;Tu֍>o0,~ԅf4PYܕl.tC|Z:kp b8_Qk.Xb v @R3ܯ͊ Qt7nZR]Ru#?Yb<~Powj09]@T>]މ]d&F7H/Ygf:D$>A<<@ЁE '%%%ҁ5k@o5|Exl]ƱK4$-q%"@Z /VJUjI=v O kie++%pMXtf`pS ϛ^d> k8r+L^9,>fp&9#֪nO8'KDK~_b8v ~X"tX2?{ IDAT%IIMz|>ː\LFJ/"3{dx߇ QثWg]>矪jnbW'KOSݺ Fہ0j`JV#;,34M +`?dHjuWR%:v dNxuv*KS>uin+JVi|qdI`BV+riMT`Ú c :nt&}v6U&:,O%YeK'/.A७*v : сc%`b.᧲ơH%U01ČgSӶKNwS_.`u0eHݼ-:v v)a wA#1~9Ud>h %ULd/,JȦ},v %E( G0vMW.W&$"v P%@.t,՞sQ X6:1}?$v tg;ۦ]iM`}]0qJ%,A3Cev6P%@:S6߻Tuf `t2;)(U%w3:=0[:wk.4qt`.[eqX#K*v6&m0-tca7e K#܁eyۥj]`b ƄQpс~)yb:Ĵbwj N`T~1D<~fJ_`' L&@ߩ86ב+,]eKeP oF`R#wjtMBI+%0YC? gLǮ`6e ˒"v M8} :IC&v eJC#W= o&Ɨ$)r3wi< ߶+S#a *;пJV/dJ]@N0+w\}^]1,!vǰ%uI9P%.c 4v$dFt{K4m+@U؁bwS_.WbD;L:eg'1QŰUX8հsIIBc0@!TM ˌ*Eh6v qhEPE>=vKН.e(rO8\PfKPձ+ebO4d06?:.u"4v/"7S#@`0yWFWKԍVz=qљ`0U&v tX7ف ev6L!N2v ]$ 0_FV7p4W+̨bX#ܿɲcwƗ$s.nuZ"Ե֡K9 ݄kcw2X::)\9j@c:̟\t T irQ X::9td_;[:p:_U漕x̒rB^tH`pv&XtF~U?ȒbJ>o":ɍp?hS_.2=]ʶF~x̒|B^o":*r!zs.tnq&M:[ۆu[VzJ>:":2ƽNDu2Fʆ)OI'}W<pJti)pY.2=϶m3E&K])Fzy8ԗK&t]~סEZT `H \Mm릹X 0uvüUs=KӦmH1TƮ`;L#aHUq9)0n#܁üMq <Z Xvr)*@UyNQ a֪=t#!.tU 0]|A=s;dXgK^Ѷx+d<CLtH2jst0ibW0FKɷ)軵N Ё#a޶F~ïvnj%@AC]nwԗ+LVF:gI1P%.#^S/y0\:{ct*.A|c@g?y,v )*fGс<m[ 4nB'@.%3:i+ !F(S0g@㫃#S;!ms]|7I%2}oVfK^Q o._b}TI1oj:| E]Jp&?^.Eu -mGtX|Uu88]:Dub0t8Ej;U#?*Wq>mO0?'u[-`t( =t:|B$w.t%Yl=w]I ťpl@e4 IDAT:u9i=UtK^o0^W&h0 9?RL:̅2? 沚4`.. S#A8I.D0;ag`U]r@4F?V=@8Ɖt e|T[rI.pt'lb⹨>.s@4e=Ϫ8*t uFq<Ё~b:DseQ궊]Ɂ%:/Hs`:Lߵ{L: R% ќځȶgϜ.:a7PbNg{s*Zȶz|@e{J8/.8#uC!0>:antSX5v % <܁t8'$MQ7½LOC 14].cGU @4'G:@q@+wC\n?.`$D.Z;J|%GrO~"@hl]:Qv_l?D:Lߵunmy3ݗ~ K&@gtV¢iFt#܁c؁w#@*IBݱt=v ߥ3͂baEz^7EF'sɞz܁>(`\΋cI7u*@XL5$+ 5 S< /uG83&o@5v "Du(zw1Nw!]e @f]w<@`D̓C݄DS]0iF.9 :Q@tyc:LVu:8ԁ~V0P%C7Fɦ~] R :-=T\كA:LVq:xh6\Uc]|D<KV]WQP_l?D7OK{ʃ;]^01t2ˉus{bivJo`ND%@lsPtoJ0U:;9x?P%]tCj@Tgu]Ё#@麼nb0*FgI{V,l讛t]L:Y O7Ve[xaX0ѝxwPe@ x>0]W7V527 ~ ;1t#;/tT]mpK:E5U~t;-=>>18Y>v 3~z{i v. F'YŮڙTu~^p]T0u*ә ui={;VekxahK!`t̿4:~a;p]0MW7FJV!g9 ]~]/3X0ѝ؁Mϸ/"Gu`:reC@t'kA^LTT©TǷPyS n6;8A:LU@wQwJTtv X.DwK,\/:8]:Dq1Z;XɁqKԻ]twj??Ǜ.^Opfb!B%\b|u8>m~]l% :e*u߳u`.t\@g~_LWYXggVс>Wu"WyN$`A禧nAv\tY=$3`%]nفBBә߫HOc V0 oN%uOM}v`u؁~ߺv|hzЁ ~[^tF{nzBeJ(ғ'e2`}F? X pb!m x2Y]](x$uy-@^/KuJ%[OwVܚj9Osh:\I+7:w}GxS;\\@k]>°88>M|yYVt`@!Oiwzq)t\xXIEG%̔0ͮ{SڃSpcR@t3t` <s=;Ѝpt]\j'@?+~;гwI^8?XrWNoK:L==bwIT։$`4ޜdK¶to #aUw%ۻ]:D1tEh93Fxc;Uѱƥ ]<]Q ':qZ&!<y<2o\Kj90t'{:Ѝp]n?bqQvW-Qх~u75p%\a.@?+X KZ',Qyw*@!?|}4<[,=gwާ.twԫ3F0> ]:<* gè]\@|,)BX Bf2k毻Y~K*oXFyG1ޖ]Ǘ tKug|+nBo91:r.@t؃f}݀~{@>PtFYQm.#8tl¸}XugoWa^m? `]\5ZCy2ƥis2^DYctFͩ }݄*Kvڴntu[Ixv.0_tFe]$tܵkX}rw0߮g2$\NJ$v :v<.n: Ì.f4ihwm*HV"9k5]{P?Ёgz[%c]gw߮3v /&My{]hs4z@/0g@:]h>p%+%=vMY:Q:;|44]P0:oόpkw_ a>_ֱKjN 0.t]-2GIByK`tpoW'/tk_@tCMa/nW%@`tޝ@u輦ç*t%}'o!]eI^yet_mvtz \ 0@]ٶ+ߔF~%,ݹOEn`te"<K&#_zW̅t 9):apsB3X&vB߸{ׇ; \ 0:a|>K@~=t%`I(?@7X3byʖ%;[c2(7e^Qzwtvuvm:|a\>0dg{:[z;`殪%#۵ϡnW̅=0..@R*tOa\.m@f?M{>\TB71ptø|??@?߅t}.e*v dI^Qzg=۪ ׻ t;;-2p%7]‹KWteeI^Qzs4qqׇ{Qsk?]/u߳ |+@6!ZQctFiZٵW3ׁ瞳uo ahs\UFl%D-zh>|߃n;\@c̒>!wF>\=v s X(:] ЁySҕZOƷ?r~_aYjm o:w}ߙvY} 7s V'§w&h/&}X&:e}}n:\8a>(d':0_.W`[7@t$+gYs @`ޟK˛&lrKB@' /W \qtCEz^zC|B߇-N[`{]ooK $@gt_" k~XsJqcu]t)@ht'`xs@w߶$`t OoqOFb|لKˢYy3(zw-ծOM}9p5x.cߗtRn§.V:LtFw:eGB+,4vh:]'!1ZY: ׫.3H-sGTOByK`{>_6a:׽Ӆq}Rw`: 헫.%@`~|t~Ttp09_M;iyNTgKxZm/}B.͞V9@vU?@WU0,$|ێ^ρ+ǵbEiqyCȓrj`ٌpg.P&m88:ӻ,v =pY}`@xn6mI0koWWS:i]tFw:ڵ=]כX߮34݌{Uu(ޏou۪t9ޖ YR.~:aH||{j:=t!i.UX-vH~g';t#aP\%<47@4%Oop {!}ޜtà~yaE]g>0?tFtu{?/-]3p5؃q@LBc0p/tC$~?~vi; :!cC: ]ej%@?u#@gt/@yg]?w3p5ցCV]69桷'LO旰mcvM}UAg=^]U݆>w=p5}YO&e~\4quMs-A$? jd.@U0kgcJ;ת[*[j-mY%ٖ,@^c#Ld0`O0$$`XK-WBd6־v7Uܪ" jt}y*U G -1Tǖj3ք㝦c232\5*(ޚl 3½&F T"l\:բƗz@#`<2y:Н4;x+(@m@qTIri]m N[st;irف([y)7hMt[9Q@_Pjfѹs{܇D@LсeYjJс6WJyt OJvP^( w(|=M9w,^8 FБa:+U1N6R"*zK#x&dQ@,:7Z@_kl닗U+wܑvo/]13(ZJeF[ :7ڛIA66\@/WBۧ%ѫH/LβISy|;oZ6t`+ߧPF(tg/߇x@#Y!%B0=GIsʹ:˦#x&{Q@JW ՖV*Yp{}]hAwgYtF)VZe:g,vTPY&(|]Rk v~t:):2t/]펳JZm~M82 .-=k.8--g<V*p6+C_t֞0e8„u!ኴ܋U4 cGWtseԹT-hxq6'M1 _c?wIw;ܛg eXӁC3tM+1R.tWŲ{$+3֯ 'C@bzW\ߜ?ͥMa:I t꧀x؃Z~A<2(ΞuH\- ,F'(Ӷ鰁$@0#ݕJg*K%#L:t@â}BgA} Y|ܔ˶g(zr.ѭLP X͝4n1ݝtDCIq24L2]0{ܿX8N152UTBM&V&xc0„u+M\sTq~Ixg Qw|ae#+>tMI,.͍q>Ʒ`|{m#lԀ^K|oT*QwB|_v&LG;3%-,W]~4nQݍ1 8?lz@ x^[,ʅ:+K btQ@4qew/[2<Gt*[÷^KW۽XP\ݙ݆rb nՍF;,t5*  IҲ=oTs@mm~%#Y132UT\5uہޗݯvJyAKLǨk@wW,m0:Ptdhx{тlEvjAWf6X8Z^&SE(#]9}w\-_^( pthx,.CV[)T\G^`;Mں[~mGIa|brtEBnq24t2޶AwWoދ%#YCi(U ptGUQ?aٖ\q2ބugle狎SqP["Vwf@`:-=f( ,ϩbMǨ{/l~|@\P@BO[TdtbKn8>b:`w1pk$jJ{l~P X3}3bpwUl0½w`D$m:P@eYGZn:_tܜ?iPQ>di( N פn*LG<NV.Nn ?ic9`Bծi1|!F;Ћt$"! 0v岭+##gOq~5k:`ܵQ a9`*˦cBjU֘k%Œp?dx4q1a=_Wզ@mqte4aYz-ƕwLGhkMYe0c! Pv3}K-+ݜg#؃?@[sD޹2BZ{%g;BԕH2@۟0,,W42Ur|vaU#讍9Q˺1wt _\c{ծxFq*D] (xښjmQw.t~~:ڒZMrwo ϟQϨTv/+' KD(q*Ƹu|f7rs躷}g$@|(+^X+NbPlUq*ξuglŲ3?8 I7)jr;Rڲw$ܣqeM|'Xr/Wl`@%؃u͖: pڣ$æcԝK.]g&_8 WFYθV7_h>Xi@V4pt ߡ]Fza?qT˲ok]v.ߜ;iIKGD{myP Xn̝RJWV)5½b3p3S! (wu$by-[g~b ?NcLb872$@\}t_Tv]RCI[ 4W #%ƸN2V5Ң3N@K%B3^VbϚLG`)z¡N 2nx .]E]}4d_۳3Eo(vm]U.tgvKtN2!J4?ʚvO{K'Xz2{Lr֕vndGg\݂ cx IR< #KռGIHсʼnxLDq_Kݹeѵk{tࡸ2Wiwy,Ԯ1ims]RT3`H(D$c:>p"@u nΝ8 ?a:śtm`ZQ$5K3?I 6^K%%C:'B$L՜)jfyݻq~t@i.`lao$n@Tխsc4t"l:B]*jO`)Y8IZMG HjD7y1n1\Y1h0÷ZZQv%eYwJ [&R0mtgr %6xuǭXw?l0 U3o0R7^R@d8l*ΘuNK; dH']h 7&ZXf|FZJ'd`/ܜ? #g:Ћt2t@ݲ,:JPw]s[.G;t`[Jf;7OMi0플1MFzg%$M:37)$c׸Y1jo:Db|&ZU@?$@gJŹ.uS,wK&#c'BVI'o׳?VZ8d(]ky-k}qgΝ_4&PRIFwQst}q_mtm ӯy9{mt_ݗ`O_v?'\zUj$@wUkzJp+ds0,jn1jL ;t T*1}S΋3wγ|ۅCz9)N:,lE";o [:{ݹ+*VcSWF ߾PH;tg|#3RKoѐ Lj ^84'~iub:qp'c:{BT-'G;JqýG\/=lp" ̼R`:FCJكP?ŻLGltԕX$ԇ; )62Y cԒKti(U]I1`3>#/L٩а؃Pk:SWtN8HB7_Wq~TMGk]":Qi`eTt'>@\$zLGlt\<+m:Bqۃ^:3#CQ:3شS>ߌ3IҞ'd '9-LhX)v;Dp՞0- A\H~wM5=_v|v1j[-uu›~$$@~tI\u}t]kt۶ݞQE$lPr0g9_\}KI'{>'K\H,f|foy4 OLGhh8#ܝKt":)ޮX% px7cr^:1dv3͖N^Z2ښlI?x8e8 3Q/]11Yc܁ZB_4@ q5#cԕ&gKiS=7xA3 JpC;̏uʹ)Ʒ?lN bekR{j-@-td7Tk Fba^N9 afĢ ޟ53?2!pP<]MGlt`Gg\M1+NL|GlD$)qٿYSF,I=)q(WK:71'$_t~G'LGlt’KjmU1ۺ<ljͳ}_T[\ 0Ǻ>DӯPgrt&p`N+dNQ_N_Yr}cl9ީ#7%UX%h+&K8@{#R 5 +Ё ecmJ4 lQ&֞~6>]r{z%ƖuszZt@Of>e:܍e-TL%=7#޹01+ }Z]VZ0 O_0 ܇}IeS\v򲪶7ǾmWMG@.Q6kOsOsS>d:(IquVT{ ]z2{Ւ1P@CȒNQW]vXsz 4ҾgL@\klh:o+d!b%ShiS(5sEz1@ތdNQ_N\t.IB W>ߴ\&]q8@zq؆e\1]ج'z>+K%0ʒ+S řd#ꊛQW.Zђ>w'e gЅjl+#y1|㱽iY#/*͙ʻ`:BeQt`{$z4{t jtGumUһWgjA''{@2~kcArjtYw:/NKgahpOJ:]Y]}t/T\jXJ|EBUJŖ-JeRBs.tYD4pXFBF,,)))VS: k@_8#og!HN\Zr,K#KYzt4酲]_67 IIdʙ/\u]dS\RʶmY.c$)wjKkjet_XW4wrEse-T/!K͙::'AX)X:37qI۳%L۾ /Sd_Յd~.@^P6Cw^/N;6RtcK+[s}:i,0K tQ.ۚZ(ijʚ+ijb_J'.-+oP@=7C} t|俨?teks:7(hK+d:ouSOfv $'OB:s*gi>Ȏ_1泯NXTDeQr&gyo>"Ԯ֟MGy˺9Q`>6]Jb:'v&*w~@}6xto*BUn,]uϊd7Wڟ:δM$?TKG_054Xλ/f=L4C/hWq]m#mkr Ouc<`Wkm꣏5`JrzQ@`ٝϪHgN]v.Kқ_`S>t~U]`vfA"w7ÖB//]%1J=]b;p_~n?*VܗŲ. uedE.wҔG޴Bߢ6E,ݓm-՜Yܸp^#՛k ?iO ɞ1>\ cF$bRfq99__ܗd>7]wlJՖntyxEo59[2ɸlDOiǕOծj8MP@_Ŷm:/;>wٽq*~Wub*TMG%&lc{JCzb։q &C:+iپ/[:7(lֵ޽7VT(1IzzpV, 瀟м۳Ahdh^ą%ٶs/9Mǀ-+ܶ!KzpVpR8@\=„X9M}jAj4@dZcfޞ[uRe`JNg;up(Ih0QW"a>d۱RYGw++zg['Wcg^>R9ؗ{[qxgJLD}Qh8@p6OMtncƸ/WK%"i9l+oNjT?:9ŲL9G;_/|M4: A2I.XV{{߫J `cP\cG+5?%=wIpJEi)VzLǀ40Z~9m8Q1uwKEBQڥ՘I]+(6шGv+}[{YY>Fǿlp{I)sy8FN qi}@2~X'4xtONΫ\ mO#s_R253/PY6R"aϔU ejWqW?d-rEo[[72xXӟށb4Cm~rj^UW$IU[:qiI/<Ց`S,YԮ}:7X;LiV"_6ƾa:jhJ5=mT\[,N{hl{ZWkTŊzRONKEǵ?ض4Y!uԙTWfќBVXkYkb9 lTXvt:${¢?ڤw SizZ};[֧uquQP~tb>[1WGLYHt pfc6{t ДP@_eP3ٙ{\z֟mT/VzJ-RGKT;:ckGW\dlMioSrLrox^(N/{e`(۟rEWo -[>w $G;<6TQ./<֬d$d: HoKvֹfuTAf۶ U!Ё5|TџCOfKo_K):FXni3:Gݏ`>}Ϫ=5?>kӗ3uw;W#lxvv'] {’c]^5`N=<5QPƬl ٓ`W\E)qe7eB]kyZ@_,zh|M[Xr42r_J_|JW9]}In-֨Zcjk oHecmmϩ;G(/I/}U_msԓ٣\?U_hY5.,52YRY -V4TVXUdRUzH шd<J%BJ߉a5$z 5v4֧֞ f?.=^.^  6 ۳%ui/[螴:rQ}fI @Y c` Z)cq4/FIGsգFk}Pl:R] [ 4֮1SA_ '5+C(O54{Yﰥgɧ[1wW 5+X8=?g(-}UΊƆǚt 61g:(uړ_ YLt}3?2Kz2{vi(o=KxB3N~CSc= [UlZ^bKwMG/9':VkO?txgRŴ&5'_17KLmZWI:}Y0.lED豮OQ+Lڲ\[׎#W Fi+lEԙީŋ2ԁeU*,j鹒.浻7[_`˞Cݜ?m: c캪 ښ:?Æi eZ8g:CS:p*+t:Ё":=iݜ?^oP+ԗݯ~f?{@hXFdP@ G2ɰ_3 hx+4ϝfID2L #=Ԑ:CJT6i?J4$ xCY \)hzO'7_q*~בڡ~Mߺ򿛎w45_2WHjwoR Y L)VVLeWY\>/0 :$i8s'usVni&?}jw(R{-٧Ԑ$zMG:nj;cQm:~vA|i&?D@o1 fzOΛ+HH?TNO|V;Tb:@KSXfaF8a*kᎏpGҬ RmW,jW>o(_^0Fѕޥ~t l,8/mE.sR*d:hfOhbx@9 -~Iq=@P@ceɃY1ʛ%beE+oh+1lI?xkt [(@6By#hoEktKA4 ޴1>75_ѼGK؊ @a oTl폦T2}+H>eI_I )dXxt1AH:lt1׸Xұ_Z Szg[Hz2{Я.+XHzE;MUծ]hЅ~WXUTu}wQ@fˣyMκH^dy 㗵+آ[E VpǛ}H(@U첎~t lߣ┇Iqeb#CC2ɰݕ6~+5'H,YT(oE\xZS[S?P47?EĆF=j@푊6t z摬B4e-_{@i1IsNsnߊPHZ_@aqHzy?mN= =L+Mx8JyG0%uREfOܻ&h?zt lqΞIš_3gtsfP}&?ah\Ht!##(`؇Jt*gᆪlҪދ\  %@@BKBh1BB %ْ%٪V_j{3gYFvFmu?39Ҿ8Gn_F?.a:R $/ʔqyee>r;L ϳUiK^GۘSn|<͝\`:FG_밶mL x^}d_,$ܫp4i:ʘs[ה4֑ޭc _|iFK@æ$Q@GF$trF1iבi:4Ҿ09kL;l3c=וkugLGmO)iHׁ.Q@ѐJd9rӴjU{MC6S^?ڻM] 6&LW^g:r1={~.Ԋ9e¯#DH{:^0WPUӆ YV{rQ@G AvfҖmL 9Ї?O4%z1ƜBw&5[vS8+b IDAT Al<oK$, B.t~s'2tSSg$=j1lT)Ǘ`:X)1p+cǙS@G21O85 d tb)2CГVR[B0 &{9kuLS>J'M|U9LGco?f:b֟wl^W@VwKٽ'=2YE(a.ڠpd53#l?æc9w_WSE7+`L`IL{ې/]z,ޑ04 ؋:鐮[A,ia +-@6{ϼ?Ecږ6M=i#faZPg}^J MC16XEt +._4n;Q@ ì[Bppڝz{;1lr"O(Y{ g˲Hk5:4cxmؙS&VyLG$i t|tv@q~i#iI;jRwǓQmkyDYw>ottI=WXt1eZWeC G ttoDFmH{?t\Aũh|t~X`C=i86hc"lV*9닦cdDғ{۩McSAW_*<ʞSY7UIœitOy(.] Յ. K;B&z v7NVTa:Fyi瀚"c)y[w7ϩ3M-]d:wEzukCTҽ.Wt XiQ@GFq)iх~u Rw5h{.t!>Qta 1L''ǩVLt$#5r*Ƹ>1 pt2]g-:Hy=ik#6&\>TY0t1o62cLPyxx]_8]Yr:x|2юIMǀ!@[P,Ps\&k:Sx х~H4]GRO׉%# S%ߐ6eidYT/Ԃ[|w>.2 =a: ,u+uk Oڔϣ(B?۞cÊSbxA0ʦ-~UqH~bzbS *]9N}l߲B`ڟQ039(D2`i.t2]g EzX.צۘ@XQ}1Ƅ~\Q$z֮*Up!>k[qdR%#zWc L.IIKL=ƽ{Ѿ0:c]gYP +m- 1k:BMW@6༬tW)0FЅ~7v~U]t9\>]t%^u>hc"SYJbWQƄkSwW7Uk_COJhk#c L@$@`MI D%_IHgռ"p>EcЏnSDrէ}S癎bT"aM}jx~>nCﻩJw]W!>SKcV.\8dz ;L@wI` X)aAKvzLGr Jd#lr9tr12F0Ԯ-Yz6&kEoh(FXD{t7̭;A)% eߔIt +M0h:tI>Bn/ etvƗi;%S^ߩf_"O>;,b:,su9d:JfsHW/,;A*=d>*p b|s-cVIJS@g;#dp8vu#Ij]蒴OlJ WUwWÒ^9C AI2ZqKmBwVDY廋 p1>G:CSM+I=є AhxhNu,P$u:޷DrQy}~*VrŽL/oN-8oQ<Ɛ=k(m:2{OK݁IdG-*v&&}?VJ]dPY0E_X+f:ey˼}C>|8=l> G2Q,і_ 7$/*˲R^ۘ #(0F͘-W>p8zpu1\uTM/]b:ʨ90oʋ]wSIk{_,\6p9>Dž򸝚XIqC{SAo1 dU(0MӒYt6 0u?ڧ[1\.gW|Ws+6ն)D֜tH7,+SROqGá0l{Z#~JGz,>P G1r]OXz`¯Z=^Q.ZPLңX-wM6_W;ڞ2c qO$,u ~=p=>N.].ӎ5Iy=i%ۘ$Z;Ȣ]ؑXRm/08ۡ5KJN5 :Ogyij"^m|Pdϓ@*'3]Ao1 d$d(E d0f@:ڔ~cYm܊UtI=jtˡ{OW+??cn" \)=&zt QP@4@/);Yqecd7҉ԻJVDg\eY~5vnץ O{nTY޿3~x(ᒍ/\ώlלf"X,Qpi.Srp@XX=cdM{LSoͶ3z+'tmSmKԵJGE$}qzW8!;jtwfOb?@PocVt X N,4ܣUL;5NI6&y^oSKI%yU|u4ØnXzjLViċqzuVHMGi"FZWC}fmNgFr([`^o}\^x^S7,>Y*yܣMhx<0ꢙzOi[t\<̵)M@X40 =Q *'جp'HcG$`' [WxsHht1K+SS?GG{iѸlLf\4?OuюYo^^ٓX@' \G)UZRiK.UW䩺£2Rlո"&EnC6~c#צƟwɲ,h kܢ 59-dL@(.pڰ{tpİZP)YwGWy<+Ϋ[J^jIyqyrөC N(I*M*?՝LZTO$Nrțyj4%z*-rЭsjӣn5ӌ΁NJ$c W0]Tך^߿:G,1.#8> 䐫hݰz?7Y]2жGvƧ)ϕk'߯k'߯`w]5N{ \**pi93th{T.1@hhz1c2] m!%\#iܫQ59p8tY@q:{T,皶6!a ;lJo|t9wkgG+'ܥ6'r2ɱ+Oj">O8Wl;3 gP,ѳu3˾es2]94*ͩJKNWmNRtR?Anª5|H2О7!-U7mtzǛ3%kМlNcC$`7 (uUek )Mb?}uuY{wPZV}8_yW^'ImWAœQ s9ܚ\2_*ª5xH2plPOaQ@?׍}p`3ӫiK4t_%#ש-PPÝtk(ң`lhTVyDULRedULVE$M)Y2o|apvm49E9]@ #%X`a 賬`QNtuݦdr^=kĻ5ӫeK5l9b[E!%"OSEsw\*ɫRZNk\<s*K(,ІN⹻J-`8sf~PЁQp*mWtr̉^-U#'Ӿp3^}sH;rǒjUwcH gh| Q[[Vot @sj6ŘdR95}q{Q] P4@2\t z?9˕N1<DŽ"Iz z RZa1^zU8t" _1 A (J ]iea5wK! ;lJK\'cg<.OL0/ޡR@s 7{}[\12%1ddD}߾L(֫a`V/(2u>Pi #YDziwS@r:wP)Q;{jwpf{ bMRZ:Hy},nXѸ56P@FeYtsxۤ<]}|~Ч@"=/Px}suS(eH$ۡUs+M@R6*L979БQn:[Vm:FFœZs =h6o|nUMkcub\}_unz(Ѿm@d)39БQrs;tϚr12F]kH5'Ng8xDH%\,4è~\u\gsLHS9(̝Z%r Lv*InSǿh"dc*Ӻ?-!,.1]GF^p"6j7I9\^a88(p7ئDx=EXcQg,0 IDATx@",}Vt8|iE.vUdP-;w?(w",Kt7./57 ]2@Σ2,%>h,F㹺3kW`ܦ7Gޅ6'8a:#:t)wc|j$ zMFtguj:0jfLjΔ|1jD۹/"PpD`V@r:i/ە{v MӍ8mom@M]<ӎ4tȦD#susllAY,YD`N+S(#xr!2MK5Q$Kz~E~[%p,YuLGFJ*4è>{6?f 4fQ@wS\.^v\N?ʽ/(wQYa:pŬ]U*;l_?$0qגVB~n(دss_(`4.JuG7-/5#c }gڔ {u7a:pEfIFEIy6kD`]#Y-)+:tpQnXVL/ѯp[,=ymL]ɨ~uAN~iʊݦcu9Y_d1 @8ֻt Y G u 8{oQpB/1_W~צDg}st S_Un:q/T,nc}oWc(S@N.rnY(j[BW~/UMk۹ΦD٣v=m:`E3 4gJF ǵy9__wGd; ;(KfIgiwO{ PMƾ@_O&Iǝۓv[|GtkDp|t Q@p+ӢqKne>܍&BձTJ3Xo*M.Vnݲt ,7 +M0vud UyvNkjA_{Z}G6%6?]cF]Dr{p(g/ҫך`*2t`:.?u \H3'zMM{k_MƞCzLs:T)+'5vϹ_oy\  ߵt 7$t)#ECTtg+O==i%H"hc2!G^I+3ƕ{U9>]Cj鎼ǿɊ,YYOd (.'tJ\z r?(v9u߷)`IH(@FnqfL_IKzrs|zWSB r^a<1]ugM2{Jxs8w8c{fBū'd0\m-*O> PetҎ \ wٔ s5 +?5XenwSbzzs,ڬx2_G%dpiBzq1\Nw:5CR.W%k}S zqrZ :Ǐ~y̛Z5KL0D{X/|:o/=W}œ0.3I{ݮ 7L-+JM1m=VQ|?mJYV\[h2M}v ODptmЉ=cx `]D3'rsڀjN޳)jS"TA11rCkTZ2Ÿ{Tݒ"݆S빺`s8zU*rsںnǿp:нQ۞4s \mq%}PN Kcz_)~*+z+HpBsC#M-}J$z9#Pgt `̚Tw__.9L'1˲,7*Lw ^7䮄+2tp,^UL}Q{0=:;6%0#둚KLKgecgY6#:9tmЖ mi~X۟5i Lwl)}6wd+icgYگGdcT>ӱ@k:ϲzI6ƕ{tϚr12F4nMRډ$z2d}/i[ccYpk4kR(YCJ$z3 @:/JZi.-)b}q~{sA/PWPF~t k}*M dis/\<2H,LNk*4}շ/=ov}]/۔t7jSc3%#:ch(CL#!DH;SQC< Nvk#i[ -jP֦D+ؠ(@Nzĝ՚>NtIjhg߯Vljjz^3%تĭX)9L'KݍKFp_s K8n0)y~q=Ճ/t`S~z+:9t$Yʒ=?MD(еJLXROlU4zP[|`Lx':@Npz(!I豍ڴS?;UB:_W8z$HOugg z1MjѴ#Kv9tòR169ѫai?`8_Lft)iA{\]h6iNCf(5'#4vD3Q$ <^t$c\Jjwdzzߪk8.ߺKwt`nR#m þjFovhS"Ks P1Hr8r~u9r1>ߡ_=u'c#?Bq8F 'bC3lSmK(=>_M.Np?JZIQa͒}qs&I=1=B~I=x+ DMG0:ueБ1\. &̙Y6˲-O=^1aHژ |_*`(!O޳;?}#p.ݟWd2 ;NQ 7 WݲL1b{W4>=ro6&H-|Q1ܣyOfO7%cm O?lzA&h8@C}O)yo2W|7n̿tA"Ѥv= \<]\b:4wjj[ 9HR[wDKfyĢ/+_Whs:%~ytvjB9tE蟔%uİ(=Y+TucZw\j%έ,P㿤:2tmnCP}P$7&Kh”{;*jj"{%i%C3&x5cbNfIjMNnPUq&,#:һE~G6>`#ځBct@ש y92%cŔHHҌWlثeT?d<_}zt حs%=3'#B yܧ̲e*𔚎 wh[cz?k_Kb-  TY(;&TzFn)c}۴zU؜MM?ӶLpnL/ԤqyjЍ.ɲƎ54+Q^ij"nx2#[Gzj:h ly{nApڴj}q pZ}[X&xU^˵x@j99޽;<ߥ뗔er~9X:BOn LlO|Eh(XiKkW:ҡa5vFdY3V,OGNu5)bɈlskNUZPyWQI^ͩs 4tyG^I+a: `lsH。BPB|Z /_o;AŮx'wۜdF=t(вمZ6PC6u~Xh-]ۯ.WQmMuu}]94xT]Ukrs65q}l1 .y?pP@Gp:4.CJ|G}Qq2//_o;AXBT)ղHLk1V0حejPjNƈC Ah 5Z4;-Yjԩ=PMM?Wq^W^k4jy]6F'cjԪWj(7 FeYeJ㢀t^Suxl]}ӵp>:V I+' %SqơC_S$4$4u|ӝהXsPGC:V"#ރzW u z{~\t4dfW՚VDn &GDVW@ɘX`6Tv!7W8rմj>}o1Lg/td֙Ɨ{U?AVr?}dB>~W~Rw!zczdC>yw-ǒWӄ٤'S{d>o}hRu!k:ՙpBzWΫ˕KFT?G{$I*_5lfRP_C5ƱLDt,0 +s룷#zRD??_'aBq<܊T]4{E=[;Ϊ]&K1xB0C&mhi6ܴ7moiom{&! a @RH6`x_$}i"#Yό8s|sth^yy x=U-UՒ\#δt9֠5șշ+VŜIw>W%-z՚\N jylM9d%}zl{bTDu ح%NȀ8U},g`ϛE9Z(Gm+N5;4=nczl[6-1 D}:ѻ['zwK<,˿Z WkQj+X)sr{LpZ|'.|'MGE_+ ώsDW5V)%:i/nǵ,K ˽ZXh tQ IDAT->_T:PSgHtuЖT]7TaԽU7pPu%I˩9˵R *Jޒ)qixDç?[48U][H mAշt(ح-tͲ<#C]:ҵ]GK_ZPX+.2-D;VI5}$2`:LKes:$]_UH֫LGI)1=|>R^?x5VI| D½zߨctH).]em[5vVsWHptKl=zBa[+MQ$R5~(kWp-Ǚm6h m|'C]cA2Mʲ,L?{[TE5}&%:)T=^ b~Q X3==ӣ+d۶j ;֞RحeDOD܎sN#u:бUj^ _Y*]z̎ߢ.:G>|Jm{MG\O#LK(qBْ^D?Hl%[h}(ԣ>*Ξk !=O귵WNӒ,R fNzBqvQ[R=hz<.rpP%"񐚇i: L{^yomK}CEQgX]>m̎cVõ}pkfHm ݲH7(Kի`L*/ZGǫIHzߩst-ųz8jQ[HLP\`\PL-0&eܩ^CNKqjFKsãQL ܁Lpp'qtov*x-߫A;_L~02ԞБLySomC.iQƹ_h_`\DnGvL:hJG̙gMGi"r]E!ն].>n3M/7@2?_W*9\˶.{::*fȲh/Cvwpיs?-;jjQ 9,@GpH!.o,I~~_TmR}{p]-O詓=ʥ`\>}ECQ #PY"ex|;RK}=3v3BP\m#تW±@0=c=~̙*fGMtnD^/.Kݧdl??½с?Ѯ܁p{*KѼ^/_U8zq6|Z?>%uH@9ҵ]?:7ӎwp:d5ӣOQ()Ts@oԐ?v`K?9eg !+P t,twm:JJg;h-둣_g $ u7~m: LkwTҧi,()guIH1;N}K/'[{ ~rv<wɖu[K"tzjgW||gӣz?):"N"8PLiW),iRӞa.֎vCG!0wBv02qS=H^7 Xҍk tsl4!Lz.>Y8xT?>%u $ vL4=~Yvq 8h{`:[4Wwo.QV:tz䢵@~|Uݽ@2/Ъ}EW̎LE-e*sbq[7bp,_mOqq3[?{ACզ@F:ʼ:$)-rwiNtu~\|y_e땦Gȱ+J{ѯ7±8u_(&Q^SLsLGIYat.~zMc@2&ϱ}ש=Ɓ`]>tLm^W$˲LII#֣ꂉ 'RG_2+0c5CGMrpKT?D^^rƶm>6mpp,'jQ/{iHv}wU(Qq@G`:Z<;KY*/vZúNl u[^m~L[#Cpyp=wz?3 :Rŷ#`z*swp/Cq_ f|QMCՆ0:[tlw~F'zw wTv9fuEr0ueL{O g;79N+zQٲx G'O~S8|έpH%+um^1uEt3:Z?q;m-_P:@Q70x _9%QRV8j7꩝ b =S}{ d#g絽AE=H-D6QPҧ(צ|c_wF"z\Gx ɓM&&& tCi"}kr㤬@Lms-[Z}@ʖ[o{?[e˾CF`XŜ,}Z2'teKN 'Ps#s[}'Ý/ jt/ɓߔ?2h:D򲝺B~&^B/=׭ *`(/O~u+LHw#=yT8Ic'tkcr, UZ8+KOңH)ɶm>:3-}bv `J@1^jaqp - sLGIi]=l^;2xzȱ?NNR?pPCyӖ5.N ۡn%s"?b1[XsK9~y4:`L}V=_cj: `E t"WYZ:/tOۥ(}ntNF~}o(:@q꣛KtvD(4hl֛5>l h˦>tit$ٲuEPw|^qɕН]ibMEu%`:N{T$W+TnS;ڢ;+BYp,h0!`2[<H8ON%Z:/[; i LU,fkQ"\svT;~Ýtҿʒ 'LTQ[|_gHS@ǡn(5Ksj Fbzrg֖3TR$ _Vq\I F~mZq;f: ٶ5> tiأO^c#ھoPJ4vth݊|xM4uuZ$Wh<֡%_Tee2pCct4B0Myܖ6+ҚznO;>@Lϼ֧'u[$+u?k ' ;yt@-F@RI[L'zz#کdTrP8U]5s޻OUlP@X@;~-O(CalH/.'cQJ+h93׎ ip"}Tt1S-A]{Q0#8.y9@8޳KP}VQӐmC@ۊ\ڲin\S}'X)=*d馵SrH Z/q]~.0RWQ@4 t\,7۩w-U:xjXoih"}4mAնl^n@f=Ƈ m0i8-`tX;ҞbOd:q[Xu+t731+%n tk@WMk TV|HzzI]7NݸU-3̉qkZ?2h: CXGv9LGcp:-՚%:Оj:Cc[:ЩV,Mk UR$Eai{JڟқihAA\j>m: @Gp:M'eIgkluu䈎Վ(M'K)mxC@'Z([Wl:ڵCGvhvRm{Vm5`K[kQuNQʲFkR`Bgxt&nPGj:xrX݌w?m۪9YaUSS'UH;S|P3fL +iW/ę\0aF+u;~E֯SKwXGόޯP$n:Z갥֠j[W UZ6/K.> j~\gnҦ9wxm4twޣ@(Hq;7,)0iz4ԣD_Gkoɶ;-]!=[Enݰ*_+VOnuu̞ s>nW+lh@==c: oٖ/}t.%Z@L',ѥK"}z6V蚥r9qh{bjZS^-QNRS8ΦGZcQq}vjZuc:שFZ{"L40{ڑ!_kUz4QuNUwTHko5+`j8_u+Z LG`TNG|(}H8]Gvy6Sa/G"v;Ջrt}Uʋ7j{Ъͪ*YdP̯~7ZqpGG.LOY^VUhUE"Ѹj[:怢w/MUZ2'kԽ-js?UZUv*K߭\wQS5HH)nC+h#N4-C{gz}{PA2_sdYЖ#jzhHVh9qSm>=}Z>s֖ߡer\<c^j"8LIZ tl*j Щah (ϼS}~O|]+1]:޳Kٮ|.UזoќIL  ׯO}K#upEP$}H/hWfyu3,1w@~E]'{"]Q>=O4gڢ[癑s?'d+>~b!?}H[9^n*Ц:כ5>MJ@L/|Zu6SyMz^m@+Ko҆9ԢIH ukWc0i@<}H{T8Gs#>i (M"qvdH{O k|:OYKHΎx?ڵCGv,w6֔&3' PLok/}H^e:y[hב!l ȶ3IyhPo2_Vɛ@.I]# zwBݽZ7}a[2ʼn>@TH:<33ѫGTϸp\;joOnE< ~h1kW֖oэ X3fOqb{(ѝCTI[w4S_*dcD KuϯڴfXX$#'n&* r9#Sqˡ9yL` 'e,>sg~4Lj>_TOC[;׳q;7~o jy\1;:E)pL;N tdKZ4W~lm̗әؽMkwX?{K|GCq={?3(!4IbIq[ڼHr/cɦ}C; (\wI}V=|oS$>RۂJ,D7R#eXy n}rKn8Cwf(>vhY[=NLQBɖ)ycp, t!+3߬,[?lU2ǘ~R֭>77ރdo0+gD8uRw 2ntIm 'Ы'\܎i{Ãz`/]#p,J\Ȓ_Ͼ\e3ܦyhH>ۡȸ=8W LQ:ɰp\cpE,i8ѽfeytjl;C/4L%M i(Kp9-c 9;=}߀}[ OR]STZ>s\۶K$ګ-eqbTcgH=ݡόDБ?>Lx HмR>}gJ2^tI zrgvLxP[|)N`庋10;Б<\>L ʽeKҿأ@(#}V(Mq8mu-#0a IHqSuo+٦Wt/Α:NH W(2 ${&%ک`BOΦOq*)]יXV8ѭ9)ŶjNü;P)N`2Ut&ƶ)d]hv(~R/7np/ L%7pm@-ыUq[ͮ^;1|ٽ>=u_ d:sxeٱDR Go+Uزױn=u<Lko7i0I]zŒe:I gv=x٭=}/|F庋L`P#e8-iolmXo:FJl^/ն pZ.]S~e9KrQ UZ6#%"q=[%k OR*Wb-#0e(ItZڲi*cֳKb*UDs򗛎@vܗ^ t` ,(jq)7.=)eNNR"WYw@,ۊ$"7-Wo{Oܳ~:԰l\[Nt/oS0)s358<}#u:ڵ#LD+_+f$a[>qީ d+LGH)PL}{v4<KR"~MG 1X8ѭ*+h^tRTu@uD&b*ɞg:KrZ#LUq} cjw)Βus>`:e#@Gzq:(rQw.1׻:f%Bޱ!^bY^Zm:F{|X]}cǒD TUz\R~ t Zc:Bʉˇ>^?pHçD~u#n@`ɜlf9MH9[j_&1 _PYyc0l@aIUB-<80GvMb aLG`,c:$(Gu5Шk1;mO'9ZS~\yc0 ;0@|taߘk:ʖ4ֺ3XxS#%]Iji)Lk@=QC]:f s>(KnH-t:Rɛ, 3T-ɖ>'0gDȚ%7}8 t rm:FJ:rfDOp~t.f t VU0}4ᨭgFF]QؚDkq5t fY g?:dd)K89,~];~+{E)yBf;ҜK sLHI=5v@$9ZUv=3M-vx<)2},F.I%1 pZ.mA1xc7F=U1m^GŅn1R҉ƀGWwMr"~vxM@mxS#%]Ij cG u%8Z דx庋t;M@C@GJpП jI,B#]ۓD8n9- kp<)C \Z8ǣ9T ud Fuu eZ;kLgYl@ ZUbN4>=$'07-t @g?:`Њ9>M1׎tnKb5#kVm6,1QA 9>Bk &9ie  یp cG۪m}-[ǺҜ*t @ٖo<)0e:FJ:4U@ڸi'80a١qퟪ xx|+eYp }4gZQך2HrhMmc2->p @ XM>P$?$lVM$'0Q- `;~ ݚW1#%n{Ƹ[w u9"O#ֱl5p/i\wͿ[yb1밆dzH stXc~_TklU0Hgn]y1$GƳHY^/2#%)c/'/+|f.1!NjUcGSr1ILJ8,T|t @f|έ<@`1@T17[N1RNcgP=-['zw%9+Q1:yo\% toEIrXRl1RN$js 4&'y9c57'h-S1=u$1 +U-{|t f t ̞QItS6v:F |@ WLk|1K>kr9<' t`:XU#YSKq?"IJr慟20=QAaKKckX@dyjvR1:0]TU0B aٶ=גdqZ.}h䰜7'(Б|'\r:~@('zw)nǓd\}t 4b)NqplSKfrƾR$0n\1U̸t 4a3^~ֱAWdd#+NybQ:0,,/Q sxϫ5=R[g>a>@ MH)mLc܇B=j:D&[ŌtHspʊ\Rf%׏3H{,2chP)nAGy.1RJ]kH5=%/ )rEҔ|}HqerQ)%#8zoE#uIL`*xKǕߐCD-F#M9N i@ƸUkʒe: ؖEvFU^6#i \r>֔ݪ|t @Z t`Zk:BJEscV}$&06/Vm6F{dPirq,=:)t SXyWHr۶>C򚎑RN7QUrQo% t TV䘎RZ{"cc /ܛDZH^Hmtw]۶umٜB\w(eSӟmi,1Rʥ t1tUHY-eMG LGHUK~Ǝ  %1dWϬ\Ro"Q#%//Ƕmjz܎D$&LsS)eO)uҌ!U.(:׉F%׫_IR&/XO?8ۢ@2%+>WCGHck+.iba*}vͷ.2,(L1ԣ|)#u98ג WkYMG:Y*9~M~kG08{ͿtA@&si ^r{A#IL< }nͷx(C,N8ߥ%1RF,nDاvL=;Ig>QZ[~(b;(Б\\ 0!q?%׏u$Rr͋>'[ I8tZ# UC\o쫜FoR^8MHu\o:`gHU,}yZVt:қŷ",K+sz\GjG\c; zU?o7p, t;e:@Zk:BJ+\?ڽ#iͲ/)L7ح")-8zIL ]{f{iv2qd:N_șǸKґ@:_P?V2qr0%b;δ\?ܵM,E_\u4R2)#U]s} ةƁ#IL ]9-aƟgΣ:3Q9F6cX͐@hȰ S'4;s;}{;t`C:7 I!H4$`3l U<-K,Y3laٖNU=Zt>gWk%]g߼4u$^De tshOl|ꥧqxi܁\lK55:?&)=={{+/Q10 __:cq7l-MnL֖BuJk '_txu869i٤eo_oǸ䟉ҼԱ洦cf R<ߣGR_t#LΈ>\s{(dnLJ dÙ'F{K!F'ꩣ4r=6==ȃOhoZ8ɀ٨x{\1\]h׺xv`2k׬?O{ fb1NoO4Mc`h^oTe_#qβEsRS#w<6fϚm~xU}XwS\z90t4/O|O\|{Z/dzb[9xZ3_<}{f6DzEM_Ia9/:he Ρc[ NbR@^Egw(ПgOO9vuG)Ё9ia7-6|WcþgGwpLBx>_ @c:X^Lc(`ylܻG93B[={P\ _c-ۼc4Gܷ3͉ OE"csɛ^7? |N=g{B8 '#ugۏ tB7`,YP3OlM/vRh(wm<(^ o4iySG8L'8J,u9ů3 ]GwnӸDDwZi*@ߛ΍Gܾw1‚f IDATa4xQf^,[Ԕ:FC>^ސ(@F)e1#K(dW^l T#/~k$Hԑ:0Y8,Kp)mqc4;7 D~ض}Dh.Ğ/{*@']yB>>D=~l?G~ONBK\5k+@^ 3Sh(lçl;-=Q"פ@ȋc+ J`{/-%W+z;Uw 8*ۋqSh(Ʈa ow&J0J9'?Syt:p.;o~,(8pnBSӭ)ϧl: -1J,~1ήr8&o`Ao/0z}yJ:0)NYozݼ1r%?ΝP'a"# t3J `X}ѢXQLa ֢r'0]LI$RRͥ,%~;-#sġ1<.$j)YYvMtWLOl7Tyځy=nSLS+SXL+ߴ(JOJe_Z;řki*ʝC0C組R^+*8xk:Rhz߻'TF]8@cɲ߼)y%bQG)uw=:tIf#hHy=<$k0[57e޷-,RGi><]ĉD\3e%0^}BK\zިص.=6@C>:r/Z+70㎍^w_G-&Lpl Y1u`xKBLb!mIr? T]^8+\lK%,"OCLKc0nZugO LO !F(isǙ'0UbQ[6q"eٟ])I`"%f܃y|8MݷŦ'Vۋ˖}>u4ZmI#7FqݓġGGמwm9u;ָc4Z|ވ:0s|cW'u$9+\J5ˢ%KDD7h-{w;u$a"q4܍҂yˢXeDX-vKwTy3Euժ[q4@z -K0{Z/W7}4&j#}q@C쎸uc4 [GMC33<ԑ^Bkr`GK4wyQur[ =hWg̗Sx1lٿRx%$dMK^ZeUKbQB=ں)5u$ {J(I.-(4W,V?@FDLTqM12^oxz"u$C,}ժ[nIr 1vW.Kޡj\{KWWˏQ NtQɣC we˗DY ("bgW9{g_ wſn'RG,O]'S8 t`y].Ja::JCX<bӯ+NPH\ڵ;S8V t~%jE cpnI%_5LHy_Jb(I,d~)~ˣEsD\sKO7|$<~+S, t+d+7/}i4䉈xzx|c}o|wglgH,EXӹ9un0+%~ˢeOD֝czolo|߉}#SGf:TrS^%~]ˣPDĦG{RƷq<Ա3‡fk멃L%w9ĥ+\Z4;F{VgE6:0k#%~Օ<:TSsҊ%~ryoWGD'4^Z^MJY+SRbYy4Z|}yѹ roh@SGHT >Wn?H#b{ےx9SGicҍcшP|߈%N4X#ù4uA t"EKGe$WqcC1\oHtb'NVWRGB^nNM~.y]G|\Ry7߿/b咦QS7ZDD Nt??qSJ}"q:`UMJqUm))^bO֞:JC[޾xf߁<<$NLrm4u`U~N~(4˗ƚFEid_m]?<3z^H#>߼/uG+x W.fSzčwF~z^|9>}m%NLP$"U]:G#p:^RGi=9_+j?{-+F+ SeLDgOBNr/y,l8紶QOO}n;qWD 2Z<dYu[3s4:$8qis{Wٯ6{DĶ3&۞G}Lf@S-~=28:$im.ϯ^?Tr54Z/߸?8tؔDܱ使w&J*}ۺRiDL,;Y',iJ&z`|Ʈ`he grܳ뛊tA,3T:FR\n٢9!r2?>o">}趑#n使wFTiNR tK+aLNrNBWiQ;ŽR8MTz[DmT=wFTG|f_{޵Z t)v=!.:#u{c}P'=w"Ly NX.f^Unݞ:H+DD1uٮ?\:\ _o#F8Pԧ/ŸٯxSk:pǯX1fBDt0W%~}'%X=򈇟xٱ|p/nw 5M!#?#uݴk1S/ikza.z T7S,<5N?5cdG`JFP-^}BK4^WbqϮo'yI,n=qw[Kxy;k;oPRP,(NYqCq#1Sn{7-OocsϝX9씟 V\B9lS#/+/Y񃟸+ut[ƅ#@2Yqy14ZJHIUylyf,;'.ky/^p/6nLbE\l0w.< {u_KcQoP@sS!9=N]1<ǧuCO G)+ZjJ}<x$=D֓5Wㆭ!:ZHǶ/Y~Txx߼4޸]qĒ81 <:/E!f*#It8\eris\tvGJY.Gm,Wؼc,7+4GGO~賵11`b,m?%Xݷ11u Ȇ#㣫NdRXZ̋z=}ԩODp5V.i+|ľxg7o|Oo^ ZMQZnxbҗ:pyzsd t*xۅ RT3On ^3/j<"}_o%|r$j~Us hpy_sVu>+j׭?YQS9gpOόǎ}QSGVb{`T qbkE. -SzN8^yqk![UJӛ;nHeRҫTcDl}f<ށJH'8뤶㴕SjRjqE) Ήbf8S}Cz"up<޴vMAf3Ws\SggCرw<;;NDP5q)Gl5[wIZ-͏םY69I- qK|>qs ΋SZpnkZ4eWspSl;6GN xZ+)ϧo/Z7=t;L3&b蛥X<o>w~X"rmzEͩ t*N(8-h/ggGā;cU=Q?_P5n/8`ڊ=c;}?bkCO8+,\TDաXu8+ա xm$ƫQWRru4y5&#QRHWA^fgS+$U*3bsZ[sځ)+*H/1RroV+TOFSGf3WYS% tKS)SWĩ+[l#*{zʱzQԟ_qkMGk6;6ƎeŒceǙrޙX~Z,j=`#J_ MpGJ Nt+)gWsɕE,[5gXG^{P]FϜR}p߿/~b8u8eEKH/G~hǺ^Jue,k?%KN'ǒcQ(dG{=\SG,)[׮vO6(rBI˚egV汿{{+{{*_jKDžg̋5/ym?W?.Bm^%} -hY>ѼdxiۉKZOY>ﴡjmpe X?{Drr±jjڔ:#x䩑xrXeM_?Q/ 썧^m};"y'"vf{`BiVm ̿yM'M,]\.W"Vf+Y"8%~jDvzD2Y'A*:I G!X)/j8ztWk=F@%Fכޱ<^}-яGqyDDGdydQעE4W:W_@Dvh>,b("{<EH`6ˑc:7N2)Z[ /z Uw#H-Fj1DZz!X)^{Jk`,իn%uRm-hkiydx12^r=rOs 5y|u:STsk])x!:Ie@`/Z)Et~$u ^\)u.իN4#IlVE: /tjnҠ0lZfk멓S 澎_vZ,&Yٵ@%uK/е5|QTo JҪUɚ3 Y:LSWZ;S'XejY(g0#]GWA8~ t*g^ 09$T3Xd/\jwRa(^cW[:Kpgzbc0G%^Wߓ: S$U3B~})V}۔糘,uxIyevMp,L-G{WZ70=/W]A> tSR+U?q0NR-;4W><#U?q{_4a w`tuקBcQ_sM<.jRsxdҪZso04&S[Oљ: tjm`ʌG}'tnNg:0V+'.yS  t`6Bdbl`gk>s$UȲ٪5Ygb#0)I@X# _Vݺ=uf:0S G_/Vem:hd"Qn|'z؁͝IC1;)F1{Q˾U\>#͙. tjn:yoBb=5;۷.],:Ie@*]qS5eN#PSm"":#o/7s' ϧ@&XD~Wd٭Y-nok,u(x9 t*R'` GwQX_ [{޵ԡRTg^ 9G84f26#lBM2Sb!$3v鴡`t0Pf̢35!) FB/FX:*_Me˖d]y^8ٖy_g^Xj t>UJz}^GKrsMmz7\a(8tS=Iԟ/ڼQp2N)Oʤ|w?M]Ԛ bQMvSͽ;ٻKND]JniCGrxq: $ZrsM.ήGr"`&mn9-]}]L@S',O$rk5S}GJ#ө5S:L滥)Ln7ܝ0XtbQMn-ܺ&.v= V#Nzk֦[{g~[?(:[6-MsbsO_t]^Ng'/{kR-5ӵڟ}Q+#әtU[K6nMi{RR6:'lMҔŲ\wOףC@$I}lmJ~o7]Np'[fkj^v'sý]%әk'cGY޶KڟQ#γ,nͤO^r]e*)[sS[6?*`XJm7's,:J%%&j-4.qwˀO@3SM -$ԭ%VmZnz: :WmM-Mz֜}#]8J@8Rn+|펝޹ < 66=5n]x5t:vG`mIɶZmR.4.qw[H2Nl;<뾽a'O\Md[9a Gp Cd[m4eni]wot+]Oj1IՔA/m/kO6%K@3S]}*)k$j-M'졮,7:Q( jmImn{ۑ2@@Xz)Lʶ5/xV2Sϼ=)JɶI)֜}#]/Xmt:vol+ɶ66ݛ_^`Xt:Sdm5VfnjzzW,m:k7ɶR-)`XtcRے]Sl,e'/p|ti^/>:הf{&~paste8::Iv$u{M=imRR%$̕d[4s ÃϮ4Jto)Kk-mS~]`e>d4SRܑϼo?xE@3S+QH\j-6Ͷ9 ot A@3MxA k\l/-N-nE7=0V6C%K^vT՟]zHajM-Ͷ.vO(4M 8AA)eu2XrXt:3=܁f{RXt$;J2Ae>u{~88^t&g_^j27qp" :-&++ا u= "әo$k\e.imz3KNgF@8ꑤ'τ, >ut J2WkJS`in[˕KZ}:)lKʠvЬ9e{w Vx;s$%ٞAjL~{6\a6Xt:vJAVTJL];5Ou V3N$wfL(pA  K\ k-5y?ÑF@Wf_QMkjA5ztf䮤R\to_ޔԮǟNgt`x$R\RR}zp&:N5殺=]'MܝdԹ ˤ77ދ~8`iXvdIAjJgfN:` RN(5s5j,L-]u񍻻^ :KLmrO)ɠNpY?I@CuW-ePjKfg|<;{p0%2Wauڝ]8J@3=@h$ Ko2wswl|äq/E@3S :,s$R\RRk&?3{ey2%ôɠLʰwʚAw= xxV=qjFi2Hʠ.'/ :SۤܛdPJI,fv2?3:tftzuW-eP K2l{3)2F@39W:)sdLʰY;=̦]]X.te!ɝRf4=m7%q˙tݟQjMJ3\sYpa+Ngz=/qgS mi2(2<2 ?Ov `5s0%Z3Hͨ4T7]@@8&IN2HɰNʰ&sw0^4'yɰMѧ/鉮p|tfzz}I)s%uZSɰ?3h8t`:d>5 K2Lӎ>q v=O@V$ׯ'NbXBt:1=w&dQm2hҎ8m^sq,}:hk3ɠ fZvݷu= K@y44殺=]`DxO'e\ZM]/`Ěi`ZHr{jƵR8m3zKz);dQ I<;xօ<ɟ#kɸ2WK52/`Ĕo,Gg(/ɰLʰwv= Nz]/է2N >Q6O]zή$u(|R)uT[ztA@o1]%e&ôGκg&]B@k'D5}%d5y?ÑR'HMׯ '?3a\ =A-e\j+m3fпp]F@S@qM$ͨ2uzaZtjU$=)Υ47|oJj`5Ę$ّ?}< n]_`B$kwII4I)ÃS?;N]rTw%dҌRg޷ɮN'J%ɤhRW]|'jv0I5ͨm~a'ӉɵPR0G_pIA@S :p"Զ&5 j-Rܤ9o8:`iXJ( R$Ã׎?M,O:K\ݕd4:mFѧ/鉮+N'x{R2L- kɤ7kt= Xt:V)ZGI3-S^a&pKɸ 2_JŌ>yuu= t4]/IS3J6e?3{_^ N wXP>0{ӣ[w_ۮV:S$=̧ɠ:.y o'}! ^ I.)Zh(j3 IDAT]8t:1x;DzOMq ޛν#]X*t: pն&d4ZI;{>x,u:2L( Rͤ {g1߿Ow `:N-4,4?tbWiF)uNʰMƟRR#$'e2? ~~]Ě)@YHrgRG5()/=X"z$)k;~-& S(e3l]zKTM'u/wi_9;{,q)Z%jzǟu],ٔ/^Xl=WF@XGCyڌd85m~ePc/9\',,kN@X$Zʸ$Rx7~zI\ּgIꨖ2njM-c]Wz?e+-,|enc",;O&uTaҌJd؟}aph@O˾zY<;LD.&,Y:Zi24gfzh/Г$5g>t,?6_<(>vz*VN)iNyp}]/|@֕GI̱ m~w<ؑ4K@8i'fRG)h n}oK1$3mIz/wB/oڝEt^G弬]#?HRH͸&Ҕq2ܱ.0z,('biWrg/ydΟuů B;KʸMqv46wgf+IrS&̗;{p/}kwye-&+ɨdشxO .t=VWГc7hI}OMq'II5Y%uGJ$oav{ӹw_IzX3l,ɏ٧?vk|u=dޒ DC^sqk Iҿ}?1ɻ^ӇyEL@V侒 K)iGn7z^s@O#(O٧zu)ke&kai8zg>߿Ow=xK@OnN]{dCM>rgM󘈾*|Coz1}M2_SqJPK/>Qޖ2\hvݷu 8k@O~7 7/#/wvIyJD_MpT{CI%ͨ:ng޷ɮ9+fg~;I޸+?xĜ/HQjF)6e8ݶޮK IٙW~!)K{I]y| )uTj/&O_t]Г[Z5/u'򄈾{t &ä7 Rb =]Г$9=1Woܕ''cy9kk8Ҷ'%Ú7 J^u񍻻\'%'ǯڴHY/uw'W*x' S3Nި](O]zήI I7\zdS^z<)H?r`ٛqMqڌdo|aGԀ$W\izM5^yS}yy/}S3$5qJoT3%=0sz W{פ/u}"J"/5uZ{ 5t= $'?gΘ^Ò̼ԹǟzI}"co;5W@e@ԌFy3j븿~ԮO$ox߭Rr!Wo-ziŋzgL8S(mFSSS ji@O˾zYoԹ=O.ꍻ ЩCy'ʳXFS~]R=IRS>~O՚R{o8$/g?_' v8Idӵ F|7C XYW^R/v]wCXs?Ʈg Q$<koɎb%ГzL}yUYHrgIɰ:Nӎ.Xr=I~RWbgv=~$_ڴ;Oї7t=$w%q <;xօdK2'ǯyOmOu Ҧ]9(/+̼]-)edMMqM?ÑFK6'ǶM5Ibg}|!_޴;ON2^ UfR{dO=t_5oI$oYŒMI;Ȟ#9tēE?~f. I7RGMqm3^[=I>vEom$ًydϑ|i^їw>̮gUk%egByیrh o>8^eГ޸SS3/v˛ї8e:>DyڌY3o:8eГݟ֚bg}$_'їK/xC~3Q̗6Ҕq[p9ut= oE$bj1^=ʆkˤѻ"HO&ɰSz'/Zq=I7]&k^==$d"wWѷ ^}I?Dy3)fMon]jE$oYŒo$+/tgI5q 2ߟap؀$9cz2Rs ݿ׋'o|ܜ5] IRN)uR do/%GUeE$.[{ ݿぃ "g6'՚Qix n}oKIrW/9w^<]'6<)tpۓ20ikv ot=UГ$5<%W_XZpMu=`GrGj ̷`dGfvu+Jɿ kUO|y:1ZHrgIɰ:Nӎ.UГ%IwtOu4]XjܕdTRm2lf̧[ Ir=^R^{nzBD?A>vZ@VŒ# ̷ɰI;;o88XVm@O+_WJ Ͽ7wρѷEgzjUVIMmAR>Q)zV} xN6&ym@XD?u=8mRM(iFQvk졮n$x& *)omwD7:L՚zoIP6›v=xgb7Ͽяk|WzK5>Q6Gt=8qoYŒޝswFyuZם2kzt/ebwR~n}6"Z?}*[\&qJ3$^ޮKbjʕIϿux_ݽ"3fk2,5 ۦ etեz|Mu=`*Ȗxc%y?6錤$ߺUD 'R%6vx7zfR$^e~ /ҳ7 ~|*gfzzf>T$k{_6st>Rk )a]蓗\PWwmג&OVII&|jԶ%0#B}_)Ͻ.)S8f}KF" e_|3ɏ<'DN/_g$I'ֶO:;v=x_+m6^tbN/t#I#5 KSƓYl|äu'KMO85?"{O/^tV3d!%eXKZǥ .t= k߲?({Fp-)edMh9o#]XJ?l]6)?s?Ʈg Tۚ$ä״Zzr '};y IϽ.Y:f[RƩRGN7zr&g}?)k[؟oG=I~3roz,d\SqJ>;jw;/|יy뻞K̓IdXKI^sdu0D@?AܲRruGE?~f. U$ԌJSmpH36?0ͼ6'wvׁ\suuVw>̮g;2_aJ֜2_c7\M;f6t~2 0{R2|Sˠojgfz~Œo&yk޸'mO1~]Wꉔk 73v= G@?I~{%g' y otM@ׯRIʚ$y#ͻsʌssv=oޕ46ZiT՟]z+u3MZ3v㯝޴,I)%Z˸ 'm?vƾ;xօKǯ'jm-I{BqwZYo_xKyt38&5$Ò:na6㽇N p З}a$H=O.Kvg+'ݿ֜uT38aj[Qd^|uR%c/9Q }yG>ּt`%}%u4Z(mF7z߲R]R~6I:0ɗ;{\_9/i+ΧA ]}]I@_,$9pplޝG_g͔vK#IFdXk-iFy''Ք+gV:},:W_[HݕdXKdXj/&O_t]/. 3Iik6\X}P׳^^?[? dOJτZx2 =]H@_&ܲRo:ik`vOg"k|u=`%z"ɨK2Lڅ2ԥz,'2tMI7=]:fgzrdqMFJ5SkFuzaLw,|#ɟfwfuL^T>wAV?swA@!q|hi|RP33mI$QN@mLfN3i?ai&Vcs((vq8MRAw߯>s3`<8&%3KQK\hN08ThS\7ʥm?ӋY5oV Cg@2++SfgJZ̓B[mPyty3`deIebwOJ{h/.dߓ+yB<"[/Y8Yw:jaDn+S'=|:n[('$M۽@;{T׈~٢sBg'Q1iLYGw?v+#@m17umLHZА6np\)mp*UFR]Iʹsʅ%á`@o0V*#OKБa=[qNZ/`B̥}&f'?)KsYT.䋃@X n8oJǷtH_/ _u4}Y3L.틤Tf AIDATb7O#]߽@}b@oT.[=kT:+4@ͽ'y"Er+ <: / n]Oz[{B_?_f;x$n{TIi@c`@hk5jxNh `<#%nJL#4r+e1O뷮rٿfW:+5=n[O}tL_},}icz&p\RRb:yGySsSZhN0_ƀ>ٸ&wt+ٟۖ֒YT+u)yҜkN [46ha{.wHe/]Q?hav˕[dT-~p[wWC- löue~=pyF 5Ub'gQS3Ǯ~e$t@1OpV#zU{ba&/^yGΖg.{+2%REinraIp:€:&W|ɎsphT 4cjӨ<q6yjR,UOL]@8ooZH.{ϿEN=b7KݢH4T~ua@qWfP:Zgk$R)VUI<)䋽Lo]q5eOid,A0aHY=Vs: Q0 mGw޼GÕsѧO/,Q$2O)iB~0Fǀa{O?2'W9sf4n[P2`;rwOsnj>s0cb3i:e0(,))VDQ|kY>~ :Λz%zbx% 'UsG >,rTr٭j::ؚkrW;>zZ=g^~(cbb7O|"KYiHc:W8>1\9_h@W^:u0tS'(dqe8J^/t:jy?)>7 &(C)[*e%ˢEwVn o}qчv6Ux] f48'yR,EI.S'|ah 訹 K~;TG/r97\\N_R%3K䪔\޹?t&FmS@}*or9>j@%2O-IL~?j|&d݂|XRdJ6Iqrx;ګ_ƀQWhY1Gɿ" n(S(KBX  tu#y}\7JJ=R-Wn}AWaIp8\0cL~C3OR"WbR(KG]@6`T0`"Xy.LKbsO\k$*?ҺX0`,1#{^i#p{%k X)+渰#zo_AC4cVyIq%o/{@01nhMoe[Ɖ!I\O[:un8oȤ{Z+ij:Q1id%7O)[BX 4 tԥXdQA2Gwdb3Ū*͟S.,i4:tԵۗ],kPR.tO 'ybR,yV~率&*t k;ڮI, H*HrRYL)T_ղej~NS24ՙZ}Z| 3 $7祵fn3ޜ^5N7w_g?04\ f}?ʈuΜOu3 "?GfUK*tZͭ9&~/s̼xlg{ z {#+g{lIwJ:u񎜎gvGNow;0yF#U鶵5Y ;Jklӛι}^;=T= ;04חp2G9¹2~#Ց9 f'rK2iJmN,eGI.o>9{3ʆWz>Qɗh}Jrj\dz֠55!e˩OIv睽B~tHGڲ}uED[nK݇_r{%oq^too_|/`,HEу_ٯO<0utŒ8wœdJ;hN+ދhԴ:ݾZfV@Vқ&K;g)17/p(.Z{4rJ6_~f^Kw`z.wTC-Ss`|#Nd2, {^<v2 =c" 'g$H$իW0=gE#uu90Q^ y{%?Vտ_χWuۛ==idqIznto%IuQ}dSfsuP &wPfi(c 򣅽_޸+p2ۛpJ*BG^ӣ4ny>p ŢL'3I2Q)hj>̝ᡠ_Db{ӌ%ے*$IN}_/ѣuMŔ==tgV-; oPRFN)[|h5v8~o'{>{td6tenC\55hFu4(W2-r{ [755I7}8iWKvV\RQhB4%̔QdT$4 `]IJ|wOW;uLuUMQ^ /OSZt4pdC>mzC pӻ;SMu/K;8pKotkמNgG67jܲ.gsϞ/f[.paM+#?a}kđؽ5:vSpe̹Wa&´+ /5r=.esAXJUsFq t؆IyJo-9?<v84 ;6-ܤ-# N.ϐ|#o1ix9rRƏINմi][7Lߔ4smPg7iqJRɥ,mFLbGp)Sz%7M_77۾,i?IvS'6 zbW·tग~ޭwH.fou˫ŽedyYJηET[UoU`Lق/n'Jj| DLnnEL%%)cΥ,/{^<v0P:DAOlo[0}W}}N9̆ZB9t˔q%M"imКW0LuǦ^4iɻ7p83w8JРOp<Ǥ.O|?/i9}if_HJI^Uj0%헔4T`rI35raϤ-OtH i灓SJ)Yrs\[v )AɒKR W0LʂM7zJ5;}S{E.zaL8AtYJX?t&]Aߺc*9o+Bo>džBJV//ni٤e/&ٻܳ\+^ ;դjj^U(^p\uD6doAc\t,Ţ^Q%9 s͝*KټN:5@I\ڝY.of-шIlxH[I;w9}u3眾S{R/eՒ =8wŤKFJ45ɅPm-ȹoK|u}!̌<ĉ)_Kʆt0a p,OloZ1_m׻CJ59c_{xjcaG%e$8E A$,+[ a(x*8[wvEnZ*$e,RR6s-mU|+[7/~iC:KYJQv JQ^~IIKf)ϷLdNc:f[.pH%VП[G#u϶)g٥̚ӯ~p6,)t x2}|kw.W*ԎMvI*;t?I !&+}ƺhQ"\dM.%gi,%_|,v:Tw^:m\ϿRm]lnWT9ɥ$/i|%\+^ ;`r+䎦o{o5whV]βJW9 ,c L&\r.I饜_st298NN69I&$mԫferf)(Eڰ5a @ S/nyIIj=_]ˉx|dbaGWL9S2WHWi$K)qjNSɄ>I$iYD}I|QE1Kge^\*>{־Ěmd4a~OY};wLԇWN9&&i[#< 텭MeLjz6vh(e2Ag:N"J  7kIw!Ods.%/Hݹk0pP &de?׻)cnyLq53ISU.<ټՓ%SyJ{ cCD*wo2쐤C%nT"e1Ot*˽L4&2YK˦ް@1}n.$ }Ny] LWfɖH!$sN ͛H2 9/xLjEoa#Iթcҕ* U,JAB$2|5\G/ov0E+?xdNh[V6cp߭3t˪cL'$rf)/PIԒv0hKW%l;}W| j+#Z:S\x iksSdiZY&[}daL_E'7E}sI'[swv@c3u :@HNIJ9{]ॿtϋ`j+=clygw^)ƇfTGt㵔s5Hh$,hksSN2,FLbG ` z%<GsI+_z";bJ3)KL\Rnx|T$ ʍ{Aj{ǝo2GOfTGG+}rJS:%aCkAq ;n uOy1S7q8T7(SJNiɥd^2T}֡m@xƵ?aWW/vzѸ5§^r܏~Kw;-TFG)JA˛ܛt`rٳ%l˅؍y8]ޤkk(jdN2 텧7(%t`E=K@ Vxޥ^:Mw9mTGۏS4JA@QN:dRdis.G`t0;w 8M ; T+_mkk(t>L@UxdVtҞslY?tab{Suܱ| Ee/<6_q :JsaOJ;Y2slx7pT'ٯײ}n[SC9@28itN' 1mm|DRƤ9KA*a_^9F*"Z&{`WII$s &mmn:&)mr) ґxy2qt v ci]6^_v `"\J&8)Gӛ^n;PJQy-+ÎL͕!D]Rٙ' =OП|[۷ގe4mVՅ(U$\Z\^Kx,`@1 EO;@9xtj%4HhLHM%rdi3kFLbG VНp^nW+jTQ ;0͐N @[zeJ9&elOT$Ć\Li6oz2_mLir/(t/)%<(FSڰ5a 伧 zw,S+)ĩtLI2̓[7%KI./3L:Cc?a;V1NW*5cTUvDe%%K\ bޞ0v8L}c'MVSV&F('}67Sҙ xo~sCcsAwrN#˔n_[v %iY+ |omno)Hf)OA*8gobͶ\ة1iۛV:ߥ1x֯ ;Q0Nj3eNWгٰáti>| "kkÎ`Dl2drTW9?tR4Rr+J}]aF;vSaYj{@=L9U͛[= <=RgĖ澰Cc\^ܲyI`;ŕLܣ5`̜1SdiJF*Ӊ۟ ;O}$wsHᕺnY{e&-9= 9ɓ Cڼ٥|/Ɲ]!gpEhɞzؙϤ~xk|P>Wt.w3B!zN wE10QBLkVRL{$S$kksI%qRƏɧ7r^peهdR߀_8.K/{uf|$kk6I-Nʘ"gi?'rTVH|6c;͖n}^oȴ=Dڞ޴+F-_}3P<t[ul :2jAwV,_`:2 L( g9$'\“4L( zH|V𝜣_hŽ.(`y{ݙg9Np.<$ q(.(@qv({Y@1]Xн z.bew3AF[>Y&(՟{(wīKvAibzW/ /X.I,bzWAv :,2=׻'A0@A?qs%nCrĤ`zw3 uS(&86_1,IPЯTPt# zh/(pHE7iΓQ`bx4X^tz>e:IREvB4,q D$E'腀S(6O"WI5kw?9ǔ,Iȓ\^|l :`솗{E'<׬PlttP|^b/؅@G/AX@ $( sf@0\.:A7=E ĥ`wΈ.{:(>Oʹ@Y@4X4T`w|XA&% PkdwvGN;:~*~f[WWeW"+esT[6KeTSeNUժ̏4=S{ՓPoԈo՝mW_S{$&PҺz :z2ڲ:ږUGOA=m;gjq}yQ>WXy+|fQ]lE*㍧H"9}mOCtj|' -*tW'YIj?W!mɜ}VkV{x橡bU_9UKX9\*L; e-kpz:P'Dۯ뒟9Y>>YZZ{1yeSTѼk5ͩ^7lys ANm:@G{R:ړT[+ :׬Z[C:NMWBӚ%yU5\evծUk4i1/_\7}P4Tױތ$u?CgYPdm]yx{H /]缆JkPEOkXe3oUkz(l*-yͼYߪ=Inў: 9%(Kt}1/B8!;2}G30j*#Z{u.왱K*6CKg;SSK4jͩZ=,IujkzM!LAޘ+pXys`Z*#z'ʈgZ~U_Ve e6riQjlKf׼kd:)Tutto~{׽0+'ijT67_Լ%Q/3nҪ ZpdW}U_>|աoDGŽ :QgOA-&~j^]WTiE|yeZxV7nԵxb^ߦI+پCVO$.}Z@@{tP?dVaݴZ7^[ xi~=ZݸQHćDIY>O}\}\=v%;^R%CY]暵w7;5!;ʫF[fnsu3CHRV[6Kw,xLw,xL}N:^V}Z=lA 5yjQ:uu5z^o+Vkݜu_Ь!dT׭?[Hn:^O>L( g :G'ңo]]X7j(ԬԭuV+ !X{X=g7w*hL[N֠^ݣcb\=\iwWgߣ[?5+BJr[{oӾS?6&% s,w0x{H/[oX.k伥앱:6C}ՅӉgV4ܡ w?Zo|Ngm`\ tSӑY5[G۲e3w>|Ǵn,cGhb3tuu'jiT"&~`mah00!:NONCe({ZݲZ;G,|ZϾGEBoQ-]~V{v5X ;SNt7oX1^~[?ۧ A&xMժ^W6[MY>q4JWMA-~zu<v, >0O2}zewr<{fL>Sfd2V-E_)Qc^}[:ܽ;XLztSV!=·!5mVwf5{Ģ}jZ*V xLՍqշ)ެ0&KSLB@/v.sIZ\>S3vuFݿX^0֬GW=şVԞ(Q"Zyyj08ONk ^1({:tmtfj^_1_\;Z6s}hXHjZ+q/;BTMvҩ]&IKfjxj6,6/eLôXP|B^8gJ sI {Lzoٯ_;lE{n+ޙ/NphNաXP[X^=wOt#P(̳˿W[5#lnЬ'Ǽ2}`gt $-YO_Uz]ruͰ#Pr(,ŽL #zծPKM˫u-u_XJϚUyURl?g͝ ;%#]S(-NL_9^WHkeɧqY$l@3njKGZ A.X.ɍ] /pp=3ǚU_;b>w5PsMxs 50jܠe3׫_շw\ ^(JVo8½ۼ,ǚx= 5Ӏ"Gu9;{@o ;ƓC?w2r^_է}h](@ͭZϮ[ż0!25 w'7u3h2=AeLJw/U6&gm\ jؠt |ȇ1^szn8vxmm"SՍÎLK77ATH\O=7JPԋe7{|wؑt9~*}] 4y×Z4A=?(b  7ZwS`כGt-@b&;sr?텰`k=O2}1Ovu#ͯY5+~A\?[ܣ|~ ߭B AnJ(jW)2SS_󲘧O~`r+u5STSc ӳ:o].KnyeRm٬1{#}K}.N?Z}N燿ߛ=|7zbQ((r>q,90Mlj\rPq08٫Ξp]žu?ץζk脺NtNd*%sHؔJp%29E=}F-hS΁iduFͼ⺵eH**XP5}N>S;V[! V@ A~2׬MT Sў(瑈- Z<ܞs90}̫Vu/'ePߠǯ|9UT-x׫:^ZޝGvݺPww&)n"EHlɲ$GILgI$c'xb)Zb-Dsߺ}ؗ@7Bsl?I{{{5S?:7/P`K8җ?n8wGU;{ ?@85#?yVk3F#4K\j 8A=㩋zsGz51n`S<θ.eMGQ,#w( 5֧z DnԵч2Ez=y>m4Co[X1 1@= 8Ny{Y|UAE }?S"l:Q:vf8\5[ Gkt9Ϳ nzwݬ\'jgn|TKu-ëҵxմF)Q_ؐ7ϧMǐ$ݵAw.ݿwNnz\?PO;QkCZb=#U"CT^_<53*tw 'wGޥvuxV3v6 -?|Ysf+k~ :\Q/8!&hCO#wO7/Z޵zQS`NPI@u[8}|:o:nScUkW?yW:AӱԐ|Lmb'-t_4LG- SzIzfm(~?{z?`:H*SХ ΀42u-9vv^ut IҾ(Izj/aDj{wo:y*MCXAGΡP񙼾 ɂ AIҝO' 'PN@?yWԟo: *ŌלTKkTͪz.o~OU+¹{Mp@= _4 @"~]>QPA_6 +cd/8ԞhBWϓhR_{X`B= DnBf5bj6om )~PO*zI!jRrj^/3f9 IDATC/d >}?Ԉph$V TMsUvZmn}$T{lt IRk24I޽g5vGcM۱l@+4*~4i:F#=@AG;Zݽ7nɓ;zv8w%k:HLp_ t t3Je̯&H]{K7G~r R,J* ':EQ`ŧ\([Ss:~Ύ憠9,IzbϪ)i8O{|;7lüB=/ҿ`;PfS}GSc,yoўr]:.1w^[I u̦U0mVvF>1ps#%qr)Q(Ё:u\ʚH8.cjNvc}ãM[py8訳9$Iq2XD܄@UpP6?0cw4!;C|t=2-XAqJ]bMp\Ét t})M]{r{\'h:T;?ƽc@\+緌=\9Tɕ=6k:$q=qoݽWrHPQԇ]1ԅQ ?׾\h2 1b!@i:l1 1 z(Q_r4AzA{|<`<>cv D=|IO+ZG |D݉cԵ Ơwۺ!D zT|`ϙI* q/gJbF31̟Յ7ti愮̝LvL}fX' {S 勺23CML?ANz~R%ښB:Q=3yŜ.μ˳oix.Ͼ3W_msu%+]Ƀl:h7ϙRw.]ͩP0bl9矯-ԉ(ҁwy,ߚ7cɻiV~RCdtbF''SZן/xyM/k"}Yƞ$9r4<СtlEt?7~OSQm]'i%tԉ` %lO g QݘӦ㠎Y6m={K:7j=y:7M 4ԡwH׻ 6Vݘ޷3Wtr= T50+bqEK 8;=jNz0]^U3U;=y:7M?; =an{ӡwoR<Ӆ޶@a׏)@ =s cwښBjt7:N:_+fK_гh yXύ~A''Kz6:S&g~K -ฦ#UA԰g^|t IR8#iZeΟ׷G<[.yOyͦ = R6_TBn@(vEV~WRg|pC {MQjyKK`aibݒ6h6U_gems߸Ou>j:jP:?oCTnKo{/Mkr6_ƠZK@gD7~O~zңC⡦;{ޣg/YgRlhou'v* P j:PټV ݗ!C'vǪo^չꭲ 8gSE\/OiRG޽gt|i9Qj΅*\ܑÀ ⚈zAԘs82cɃ'H;ߩf'\'XWݩxnR?|}F4Ne zĬsNuqcD{FD{to߇tcC{ޙR<4Ԙo=oϱjmM!'MA 81CdŊEGzf}vE#fn/]ѿ7 {HT;f1jy P0R9 72~pbڊEݞ8IzMǁysI\nr1}}6x '8~~t V"n\)1jJ6ix󞶐 Cͷ zO*=睭a)0>-^GoU dաwmR`y3kBisaPw<Đ5hFu,c@p<-@8~>cv*I)󔒑vqSa^VU^qtߡ~=]jn0;ezt?}Tod4 VqĎ5fvy[_6iqGZ=j kOi3>uy-~NWfO'Ү>f+5[hw=z5q3 VP53)Ns<'%G:^Vϱ!g&_fMGQ,GmCGJk&gszl9Rjtq|TC̕$mo>b8 ?X@/Fyhm*롁zG_JLGYHoIOߺ4ɔ|ӯ?ǔb׸W{f: g۰|y3+nŪz._fѐ{lJc<[zu{W_^v ͯn~gx)Q)|sIm/MND{ Tdq uǓ~yt%-A^:mt _/w: >)Oj&mQ*qk:oٲT32t`޼=+J*Hw=9o ߜ+xM~wIgP$*U0jtu,^7a:(=omg\=8Qq#o\>ƯYr~Q}6"zۯGS){:jyol^3)uEO֥vI6uoPm'뿪7eCvۚMǐ$ueX28ư~/K/eIQ!-Z=:vƹUs|]/:AJ!Izi|L班9Vj' #CXYb $ݱ'h8Gԟo:|`:3/)S7"3=11$I_E7M@=2MGV9^ zЏ^g:@$q9nI/i:3j:J8<ԦdtIK_cB~yOrqWɸ+Ijb@[GL^ڳxp(Ƹve:,Wo#];e:JŅ~a;&Kү|t Tpq4cXQ] ; '<ƌ=JCB(L`o{t-cw14PE]`: *` y@cXϞ˪zқsc,U{sHPnztXsb:Ɩk_nc?LF?;W^ ֳg@sW>k,zy{~6k$~̛&&O|~ғ(I~M@h"cX<]1_R>D`xzpS͚1QNP~tX__Jn1Wb:ƒڟKW1Iս}4ZW䊦c%(۸t>Ckg5M9ÝTctXk'OfQuwĵ{ j:$)/yQIwWa׎-9?l@k8 @|yVAGLH* Vsjy=sscĽ՞N?3(b1`~t +ٲl@O tq4Wxw' ԟܯކݦR¼>7fJqWܖ4c~K?3t_ {&3 $'n:=ܞs9{}ݳAɠt7~tlBkO7*sgc( 1r, 8BCX\̛d+dHPR:a:,ubzWLǰp=v.Io~W54p_ۋ]}qqZ˽ {ZSZ= >La^_8u~]}1c`$} i:6a{hE['`c(+( U,joOD]#GtXgHәcXGe˶n: 6󖭠FQW 5)Msڑq-G3?WSҁA{ƾ|i}oi:3j: 6p;v0Pte|8z;"rh8|j=507LGX8i$ͪ Vo AMzHRcܙe}e: 6(uY |5[ZC Ƿ)j2OZ{ PϦf:y1m:ƒ57J>q`7~OoMVkk N{Vџ~uF/]zZ~`: 6h{LG0Ζq:9XV([nGF/1|ےeGT:S^z뷕/Q`}#t l9|kq9:@,y^ӯӦ`9u7,.+jd2g:\%bFu&(\id܎I;S$PSSCGLǁe^ o E܊yuZ3 OYr_\Zqu?aS],(>k:niϑkFI:MqN-%Q5,io* d@ X@d̿I(vƞXҪwNۜzYg4&ܹA6zYI7㫰>;1j.1 n{Bd9cɋiYp1]L Ҷ#lʩyRu:H]tp4'} 94s)_DXo١eW?W4j :`9\*kotqkN̈5v%qTg )&L,ب]w%.LGоmѥ4@-@ /܈E]!7:Ah8̱7hϪgy[_4X9Gdx} mM7@-Y@_!:68z7|DP4͉gLG YE/K3/A3ɽW'F:K~hg=hjstkЮ댧.itua=ХҋD4#%5tʚwFIR؍ @2^^@Gi#tcWKemΦ:}^5i^{3RsHmɐ, S}'vz(CKY޾oaծ?_6i`c?0d6Uйı~p"{+=.]N_N.euy,QR(zFmRZ=zp#r]̉K=P*3Itn1ʮ~K޺`wik yp"ܪX:C;?[,JY]jd"ƧKzy,@gDb:=pbfSos?3b 9-AuJt%-ZzoMo3E}M!}%nR,HJo}N}/kܻ'E;PUSioom K޴_ltfT㩋cԥ19c0ɷΧuto$龾N[pvߪ}i]U-i]ͪ#ﱭ+`^==gS0|z/ݻcK =ƽrT{3ivpZb*xyz>nNpŁ4>u1-yjÝmV5`!q=+|@7/س<t4S级gn֎^{C_0卯D mk:4b6Ud/V-?^yWƳkgTnnq`̈&җMǨk}aErl~) tfל*{ԁ7/$mk:^R܀vP=WK^2^}KDX^ĺ3ۛFYAPU9{k'b%g^1Xtܚ',әɗ zt&q0[8d@@Ƿyd P T|Aǫ?)w5ۺ"EJgi}4х7LGd $сRÉ;#߸"!356m?mB+f4̨2ʌh*=쨦#̌([gQX &pZKVT{|p&WhdԚ 1ZS̜^*f%I;Z@754'#>Q|2Lk:;_OeF ,()+(pDVweK{ '.W+ۺ"zѩR%bN)[H)L-| )Ey''lhA`WR~Ê|fD3&:P%;2ΖZK?;[N]9f: XT/C?0W+qmo>b:nQs[nM,^CyJg="0#jV"Ԭކ+{OfU}lv\M-= t .ʷxr PcE_7e,'> 3(}fgzʟ.sCtXŰ#G65VLfli}~Xәʌj6;^; t lko߾P6a*Vtaq6io ) h>mǶW;.2wv\_Ʋv|r]jv5bNӋkO-J,@EuVv|&.lv\S1PΑuFumWdv|5L+3@H^zW&cѪz.L?(,r4yVϭ@*hz,]~ 6M1d$G-p t` H?q556nv~ji}&;ܤ4X9$I3 6 i P[{Wsgi}cu`+o5۳.IN?M~`ŝElsٛQ~_w.Ve%1{^]ZoNhI8Bȱp- t` )[A[^ɕ6+s XfIp:E'rV-SOni`W\:걨=41[:;w~r9n` t`\jy$PGi@5G+WX@՞tI(T1:N=VZ+)"tlXktmKz+h,up׶_XA\"6oZ>5[$Y֝u]G G25[4a_qZY-{)9q}۰Ge|G@erEMLǐ$uNog8 l6m߱}lI~ӰKT00[V%sUq$+iQ+|TbrQ:[Yڇɠ80Ƣ[;P&fx0i[nQJ0O]2pW$O>XPQӗMG>6|z/}gaz<P2Nol-/зL۱_mI{V's*KOS$wImBTи%UtebʷZ,ZA/z `#:C J{>[PO(Ё d{8訥Ԟp\u 'SUeU/^YA' 3>$I`L@*hҒ -!9#Ij/䱂cK5p-c8 ! t 7*(f0 l7UhG֯!*V>9[*'W8ϧ'u2͞:P&g(; &혶669S9e' F4Yuo;:T:PAvD71 tn2}tlR[=[X&疷LS?z:((+(aV=勚OMǐtZ+XdftlRkҞ[%iϖ/EܸIR?:T:P!Ssvp@c SaI{MYAF[2=/P25kxI`4+f$Ʌy_E9n I[ uf2Q~jtl{t.z'j0  tB-9bݵ%c0 `* ߅5ZL[n[j {]Qcّ8-ni`;VkGE-™UICw`@2 J]iuJF:XAM { 3EItݯ:V1W@5Z{bTtI>7En۳.I3 g] %jSjƒqɆ cm31P!M KB4-ՙ@F@;PsvT69n7~07  sK_,Wnni 6wjŽ|{2BQ<ՖEgKD4ˑx5wUtj@[rZ"#̀8%Q5d$yZkA{lG[9[ Zc`؎g}q\nRbplL:C茬J@*`H!XAǭ|cYe3J_-~$P?(Ё 嘵tc- =M {neln`lFK;0W4lg j WXRi-p@Atyqn56copI&YAOg-:v j޸ ::3n  -G/EOϚ_AOĮ#VGT{l.I3 9sS` 87~mp@^A7z$t !a@6e_pIƃVMҋK^Wgm;XE@lҜ%U&&f2A5> zMh]a$\&칓>5gsIEaam MM/^9Zc}+~S"j:I+ptVqצ=XA ן^Iţ8ɴƒy؍)N&MGI,ZA/{y9ǩr6wI#=tG>NW0HaϸW,YAKz"l8 lG^Q{ TB:NJk/b-]}떾-=Ҧ\ӗ3z98P;(ЁMfHB5N^,ڃ.VfYAl 3Ӟ^99/}\uϟgoW]9~rϊ#V- FlBXZ%Ad@ON۱vAG sRN׆m;InE_tnQ+|1[4{ЁM8w ff8f5XtZz9@dxs$0p@m[.͙ n.eI(H;n& zMGiKeK+ͮK鞃 >PV-=1}my -(SfXAm 1VBONͨѝv$:ildkv2l踉RM[ʖZgc`3*UiGoDq(i+̯9y0 t`Җl YAǭsc` 5ZBx|B~ D 6*@Z2Xk7IMeFL=XrzU:h}q:7{R;bb%Ξx TNa$).(⎵^b4ǥe )i') 9aO؆B<Jl9 &|*f z(J7R+qk{-ZXp(L 1M5Z4=UvdU,E.--@i{E,TckEiNW[SEWC^/x6!ㆾxZ-LV.X!qԔ@[q|*cI8=n1KYbLV-spS2&ز -A71k!bQQׂXQ@冻5qȞ;8C/7$`K$efuP_"\E;̞;83ټ%3eҏr40@ѐ=lD]+Y=wpglZ=_KYKƸkҊEz< tv-ϥ!qVqILV4Z+QVi=V"c /\1c:!q PrߋVdVkLG@شͳV$•[Aq#A6⎵)F4lLNJTpz²=蒬 wu|"Nΐ8%]@=Ë+BJE`8 6Ǭ-,sy{^_])@iw%Cqݰq>tK[*lz6Y^(S|6Z4$kŽ~Xe&U=H=[1sy t`-…Nt XaAqP!q " lؠE]&Ps+îtZkE(Q( [9[pe a-uu#rV?ŴlZR}Z`* r`3"1` -uŖUzM$pȮ'/wo pHtb>\Y;{l+ٴ=p87)̛*e=_`T=Qkp=;ހ>2-r7@+QKΙ.߃LJ+" (Ё mL!qt?KV/Ö PdS 5D2U Nl͝mW=`I29{:A6!qcmbtTQ8h-~qKP1UtZܽك.I@tX. z] Iw,݀=QWF`Og]7A^_B]lq3,Ѓv1P舵EAǢ R!quŦ'qt8Cz\ djo` b:,--eS{vaVUrH=QIR5y]q=5.ǀcc{5UH؞Ϩ$,?,\Zܱ: hzXJ>WUt<,I؍s#"a{n^%RzХ@s|ĦEAAUB?t>WAqn(؂ąQ`3UfSpl }8oS(Ё XNձ>\(Ag*^oS1g߽@ojՏeoN@ǢP[՟hĞ[|>k{`shG PןE/˯AJ:Acoq]G`M>q>-P:6C@t XPPsBAn_B3O"! thWɾ;76 fvE((_Aϲ"5*=@]@6XB(QВtO/ XA?ֱ `S\ tDŽ,˗A3='1Ǖ؀læ AZܱt~tdo`MVu(Ё <;zUj5豷v8x) [K0kcH\} x+ff )IP @b˖Ϩ$jP(Ё *C|XBm2$.9="AJslvoPV-sFVɞx% IDAT㦊 Kk:AIaEhq-j^>VS,jK!KY+(w|q-g)Z9Z뒭3aZ\u[ l^ \҆R*uZ: U蜃R\B-k;¦1:8r6œ$3pujXI$m[#VfHM Ps5VC\˦ ؃ ̣@ɳo :\b^ ^ MGDS&g_9Vt, tu5v>69Z}ϩН'(\"Ըl!e:АpGQ(UTU:1kO&ǐ8Q@<:땭{!7j:$ tzLatbwN?qMGD-p!7b:  [+<^*9I \j\:O;+fLGnP(oE(.@mY`EQQV>O[( *T>l yX:t~tD\. 6+_Cy=)Lר؀?,`;|MqS=r!uה7jwK`9|< t`<λK2:Nx׫\1c:,aևL)q̳D8d/E˛(:@`K9xzq,@TjǨ0TU+(@Ue izl!e:M@}uw3}`TYŲَN'ěͽInMqzSM+X-j( DϜ/@b Iԙ?3$P39OLI lCDDDDtLЉ\GD1A'ZN ]_&+&uݤ˺pD$tv tAwۮ?ck_ ;Q""kh^i`|xDUADK7C "!eR϶ '& v~ &Dt"""""""FH1/eC "r%&DD.U@uN&ǯ(wUt""")SHLЉ[gFy^0!"-'k2g0-ҍNIn݈i1A'"-̼Y@1đb+'/9]UDDUq]R|:I',A7N Dj|`x :Q50|yow]PjL1Tyq;Q23n`; j(W_=Z)I :Q0A'Z$#&3gXlq9rY_L9(r<&DDB$E忦*VHz} > s|nNMSuDTVVOL2U2Y^_ |e3xnN 'Q}b9_C֐1^_T}e:|&NuqND a\b"eIWstY>&"&D$5Vi.VWt_ŝ9_:Wk0SA7,Ҝ^_+Tym!kTADZLЉIR4mӜ$tWq!9!~0mSi#k`C 9e}a&;[pw{-mCDu :"^!̰TY٠1Ai0'Aw!gfTQU}CDkyW-'p8y]tZް2TA…| CUtwI'TPu[DT|z/-Eq$sy 1!P H?}8Gg Q.HT=o!k`چPH0VC.'#A/s٪ѥy+JDTWE%Ca^:&3AY1-1C܁h\y|h ~9 ؂HT@5RAtX8YKyED :Cr_MYAل|Lꁄ#րT9bhubxQbN!At0N Ž.HϠ<꘠-A( ~bV}C$ [-`"jcN᠜.Ziтz^MWUYVh{9h`xQ]9ݘX9pYSus٪^Y z^x/9vȍ)22Z܋+'0Z*BDT}LЉ !sW I5Kge$tΟ;[󅈨-ie 3lqمYAw=)-0tGgGT@DTddD hs:wKTн^dϝ-^'-t"R :~94EuTe$#^LZ=¶\GD1A'Z Ma3ӊ!8na#o<Mriq NDt% d.s+ΩO Xvm q|6dd.P~+) z&WhK'FBE|#XAwxvTuDDuAFfA`᠌Q&W<V I lp9&jq&t"RLFfA`LfCU@U -Gݶe~1A'Z")-zt}h2,Qr2*/lUqDDțyIiqm{樵)Vi4YEw-)3 :t2r gЉj :QB2ZSEsfgMdʎXX?ʚ)0"* :QDϠZZ7QUHȑ v%q$G[Tdd.󟲞5DdgNs:5j (&ycU{ܧK2sQbVY)'R$#[i.Zs)3 :G*ܥ,:LЉ*ض=3̏ôeܬLL'.^\<*FfHT!RW[\-]Bw%q/vk8D *>/oGB̡O/*4%q`zFCK1Q 86[܉H&D"e{1Kt\>RY%1vj8xRտWY4A EQ=Qd},ݯ0-[0 P59ħv*^*$QL3Ak v*( (mqgݹUHLH{<w^MF-]\k@wVНk,]v8/&BTi}įD Ed$:3cK!Ѡ1ء: zphW -E^ǔ3引TQU|F̕ :QĄOUVs5 z0)9ך-5V]X3t"R :QBxT .9j^oh~9R*@[ܝV3^N"")Uihhs*i\Ci -̠'<ϹjhTZ;JLЉ*9"͝ :WSpB2@KT8?g2mS!a&DQA*Nk31QA a_t_a4XAXvm&UyQ=c^!R1*(AgN7Ƴ!ʘA@g{cղJ irfFQ$DTWp!5b>!&!$gjt@_N7Ѣ-yĚcjey1A'f!@ڈ+$=>Dͪà%*;Zq5ɘ#" :Q5 *kwNFIwͨV< N{ynGrwQz Hpd}(u^] $^sKuDq9-`QKk 4mn%$&5($ɳ #!ZBU@K$eDtV)c$ύdLZ$裓yuxLO z4EAΠ;S-#l{`aNTa1 9t-n!ضɔhë[FCU{H&D$^O P IbdSI)# NP5t?'Y3:"#LЉ*A&xD6_*:H7: Z9p Ο;Wt&+AxxFD :Q5|2NwyPEHQ IM5.舵HkΟ;PiYsdLЉ*d_RHH:nrwIAh9ć>N {|BjxMƞjbNTB6U/%N+&w.<7+ÑFSa׸#n4o3FRQ$DTE.D"c}pPAM]f.s)9-Et>qπOős|@+ uE$rf #yWsac H )kHqBa4XC5Җđ\^Ejb^!~OQf M͝f2D k6N yfZCz A=6 ZdOͿOFٌ\[H&5Gbu-ns?0!42iaFq{{[xHh)*tYv]]3bx5aOs@%4MC*B~aHH2 ëTA 4+[ψUij?iZ 2"?;1+Xs 61:{{ݍxnaD"wnmp;6p)H"5A'̟GC^W:#;pOQQQHTEeTsyENU IM1"舵ֆB۝IWI[-A'aNTERt8?PhscN79XX!GLK>Y zy;A'ZbNTEѐ-2 ɣ$P IDATU̓mۢfЛ*ri+N2q;&DUSFo(ӜNF!ٖE7a2i!/h{[cq;$ƆKSJc=ޢRS)'U2 #9GFCRV3K764.$+ _hhS}^"/LЉlUgPu3df~}nHH*n{49:=ßg::x49 z._6s{܏ zyD@Cċ昌{O:]WWm]75,^m0( [?h2YeX!Vux?CްLϡ_NUIe%qE .OAԒDTlWLЉj`2 iٸ0T|Ca4$UM%M$Ӧ0f42Aw26D, $3rw*,St@@q #!]Art@30mCurtnۖHqt-Q51A'.hxQxAezMeà5M0wDP%q:LЉjd]mF sRnH.ΡuIwhoNʻGB!aAnIEVfWR-qIYWC"[\Fm,R Iݤ:۶?,'Aox xp4©. 8b 5v&w˖2DFtŴ/js?3~Pa$$f!uL30t66qA8FR} {=gFB|jbNT#]2Sǹa:.ɩ@gG-7&lȘeݒsW^.: jHrke<c<>״ 6w*ch -WRAR -T!U:UXE! ꘠n9Sg.n6N׳2UuT梠sh^ش2Ǝ '::[VYvD./fB{t [T@EY0ftm tD8apIwgstI혠ՐףaU*z`vf H&C#"iXPڲBMŗ++b$ Ki3({^ eV7:v5$r +e$eܥB !E3g52fch P -T卵v@b4!IEP9KnLЉjlr :͡3Arϳ7OlHIZȫvyŜt)|9QD j`>aO~IƨfSg[;;5V8.A:kbhBN;2tM_4ݤ8Z(˶paMa媬 T<1܎ zx/I axMa3~HqD$]C Lϟ_[Sǧ{eȵLr򬸄3v#uMŝ\NՐ>HC3Emc/)$Z۸[uy]>x00pְ83ѩHgdè ˲*譍>4Dz4ȩt}Ius IJ*9Πj\ Χo9OGR I>!ԅSҰduW۷ݭ8Z(6N:9%蹲-93uW _FΕ<,&4tt is/C?T~Ra4$ͮ}C 'KvաOt\g yzc\L֕mRE<6=kgLt*ۄJaZ*k܀vZX;{ErjL~{;r@(]1A'b0u-T NXE)q:=vա"8eHȯAӄ|M&4j ձ\H9s#U I$Rl^BPsa0ѣ:y4 !=]`*.y,Hk#CN1<1nƱgDV`UvaR"mwPy˚a:ZS/aAA9m٢MYǎJVQh/ : ׆ĴnsZa$$ўP+9m:zy:P -i̟_ZA8YNnHhȋuaNms8uc~ѐ4;߆S9#/ ؼ:knR -Paa,HXP8Aa#ong!= r-&DXV`x($yAaš,FøƖa <ogʰFF.'[ɹ `0>-~G{ ռ/6dޒZͽțq]CSԋSu(N<&3SAJ?󲦼zݤ:`N$Oװe*y؉ z'($iZ=WDްp\al؎jա#8^XHT^ZA Etǘ;1A'HJ{7pa8W<J\?y C4mAmn)HñUdcWdrW*\'SPbO{p7|ô1$G0WH$10TqkøsqDng""r>S?wlHݝxw})I@s 9ѩ]Ĺ@l$ixC^tWDѠ'|a~$D6gaQ]0sϮ&ܿàELuyC؋) z6[@-GV*#sxHx$Mռ=`E{+:X@WY*_64۰q']%K`<3PЩʘW9[tG${5ذo}a0cw;\U[H ܾ~ykn9ܲXS̋ѩ/x!9CPv9y8>u_30]F]MQGG->t= Ӡ;[ZƖmuAwl~vן/}Rܙ0LЉd"^L%䧳Nc]Гxpݧx4]"N@Hx帼깦iط Ph,COZb:zT *]9|~js_}zM7W$;dD"e\ΚwO x xx {)oKM1y_ol kZ-nܵav?g{e&GDv(a]bx"eq/_6\<~q[C84oEYn?g[깓z黪COuxƇ!`s[??o~=>]O V ƛ&j܁7\ oEWt.g0A'rp8|::z"wKlm[qT$G'6蛦^W~ܼ1Tovҗ3~HuUqZ*clx(s#jo}Og==]MX4nYkڦ;t"ڻ5o%=4": &t]+ċRJMf#]ctWu(uChP9񔅦dvXq4T[Ħ;prq2F/?:hRAOVй(!Ц:Z$&DwBoSL^M,ݽ+?5MUQ1}xu[/wh uՁ͵5"(|Qxf@Q$DT@GDK5ܶ5: X6i#*:ʣyAHWTɴo?7 ۖ zPhL:joT_EO$KȮ"ސhJ.2LЉ\-Qum@&W;p[2}I@_vm6*i>tJ-cvt)sè&s9.is *h~t_u4OdLЉ\ ঍7 O8 ˆ 6܎|BukS2Tۛ[|.`_WFu4H2xt  :Kܾ#W} EU1˟ ޶gva,رI8&sQO:ߕ3va\W=gfȍ+hnAw.&D. a 6BTvW9 Zb?˼I߱._w/X C !(ѬC?|*}*:Iec1A'rv6t,UtSPcMsJƏF`Zm[،ߥ]vbX'[ }m ?TC†Aզ8VVAI)܎ zT-9UKzaX9Skia\Wް c,.#do+nTUXGRRZ62G3ye1AG}BDȩM8~>=Tv|OaD$u?c(a6G=hҀi;nkƒ?oSU3} ˖׭QK,6&C!G-Z&D.tLTџgLQ<~,{0Lup~@o IDAToǝcUý+?:$޸Ca(6[I!Q=Ou_=ݫ8nmx=c&Љ2l5 :Kݽ>][#q/~+Țˣyͭw iG{d޼)}O'ZtlРH3: 1V HK+ls'jPNDU yw[Tu¹i#.|MaD4^MOm 7ѡ :5zmx-vu<.<?^Ξ[ѩ]X .#j':ݹ#P: dɹ/| ܨqtYlmf7&қ}l]|2l^5}}-܅X=ʎT7LDhȭNbw UB,~tFDN{mݝ:t*^?І V|?ɹ[=/\@V&AWm-T/O(܊D.w(baUG`U>=Z0Onm}i >!|dgp*g7~}$[uHȭWB v(ښ|#qac/k #"'kŇ;?^1<(LSMri {nAc^_o^%Qmx'GCUAx=jo..* zuf$GiRy (}†j%9ۆ=-%=鬅o<5lޚ;ׅ񩇖8okW<66gWѬ L& FCDn`kZ1t:~yշ:xpss)~ۊiIB+-n~mwDKAՀ_nV5. 1|po~~oQznϱ˅6I$ђx٥_Qx&h1LƳ'K~gY3("r'nU!o]П}h=*EVJ4 }?x%| 7wxM" +0Aƒ澁B3ls'bNTGڛ|ycDux| Å9Dn Oˆ-6܆_%~m 5c]~< ~ {;ׅ;K.~fhn\$+̀0هǭW!EXL :Q+~/l~ En5'6/bcY_{|U~ Cxwۉ;nx}>_@!R)Ó翈4c0Uo ZOG8uy+ G;b#:'D,&Du1ITTxIl^?#nqj܁Y.@7qtG37.;ׅEϥ,ILֆQvԚՠ{5|"DC^":Zhk/$vw, ">',8xQa8βV?czZ;ݗۧx4!0A';E~yPu' -x/FDDx~Cp6?tzBՁGFB阠Qw cMö ^|D8lm{v5(=^>R4&)pWuLЉDSTomR.dD՝dslmؤx&quAS_V շSU@ `ޒLЉ{6G ObtR=uKlmomGaš,^9g D"7D0htd$t"f}j[ wiZ ~'G(hng _SF]ikq<8tv(VI3aÞ$ +%ou#[ݿ}Oȍ)hvuyMe,glK]0z̀0Ѽf4taK^L #"zgƷN lYƝplϽ1CxBȍ羠: &D4/~~U7l<( 082#QQ={?p1PҀJcxIrx_Zw^91o,Jc!wy=_3A'{g kW# I|3 oegSDDs9y(\8GюW]6+xh/?UuTaLЉhA4m=Rxsc/cp0~9yyQH'/~93:kG~Q}_à*`^grj-B zzlatxm1QYCnLvf>vj0f3iF_y$¹ g3nR&(lbS'FEDnx_aa",oٮ s)WxSFB;yy8>PrdfIDvlXR^C3_}Q=x[à%hoP8np4~gB%xKo&CáʺfN :-4F՟8-MeG7m(䍡'VMQ?N*#qT*gfl?/^^X:$&D$ߦ~w` BģA[8;9nlwPk=+Ulcxן}8NH|O"& t"Ze->f78`6ⅪS9Y|cG innGކHP\Xo_z/z')HO)o;@L^`D!:jaImَ['S]nng&7DI؉mɶ"Xn T}+mX>} h˙y>319虣V,EA0*ƅ~KęO{v:L`u/r$Vtf>Z>idu?D,l0և}}{>='P;gn2/o_t 8)꥚sVp_LNQ[wB=nWQO] -/Pv-*^IN8"A=PyDZ\G8|Z<'OS'W,7՞jVyf/ϸ]&T9==V5ޮXXpm{^{> ()-'ܽNJi,~0+.^_;ӦX״yDZk~ gF fjI/: %V_Kuwz'opשryr|Fsj|Eb: `wԳ4`gR6*l}DO4|]=/;"Ϻ]@Z :pfOUW5wͪ8Ff8ѫcZ^N8j Dz j<: @nȧEsl^IބNSg{U#4 Xܩڇ9m==V5n{L'jNez=ﯽ(yތ)!u$=B\ڼ_vE_2GHTD?\GA\{1Y7]^92dXpRxKK'U* iҊu*)L٬3|Bh>뫤z (x 4Ni/XVz^FK|R9nH /ko7QZ׻uW~X{ wphhKLk*Ջ#G%˵-,ej׉:։: {\BSk`(=p\Yk{aѥ3$I/4\y"<fV<яkW "7uˊtBmHXOUX;zU{dXZ=IS'tFkD5hݠ&_i -W$uNMu:>PqAA0T7EH~[w2E u Ā~T5t1F .ՂKrDꎅUw4k;Vƕ$zj8U.=vJr*tYZPzORyq6FN4PF& :1gהu-4K2iЦn})=5GVVMy"-/_45qQr>]uYPÑ5EtDDm1-z'=_կwSKg=ЮGM/ZWi5xrc/ݰ]ÞzEA0.~+ORk-bzSwkfO͑g=򛀖Li6+ܤkE]GA*.뱸#-QjHKTor'?ڮuW躥Ez9VV:xX7\>״]\sJVhvrL. ƻ4_7d$ckQ01Oi_\?~Cã<5MeEpV}TXvgEZtY}tեJ)_W䰮}nh6>|u`^-\gXpFfx&wVhRQz|frݠy[wjk#_ն?q E8_os9`BH *T1):$HX?ةhy_OdʎUp[Hꜩti0ϯYSBHEs X*z?0sH+y9~8.u'jI:uL՟g fZ=TmQx(N(`ۦh|Q$Iᘧ<ݩaIRc_3ꍶ9N@:Ϫ': w΄d :}2^^:$)Y=b+ϓ:']\Gk'sn @2ҺK&˗&:8?ݡHJÉ>sju, 4U電?v@F_4 C]yY\`zkWsGL /_h<w $o~P9n3Ll!qc"Od3rirV`8=ݡ$+mo}DzycL`A]S`FzLxs@&VLx~ѭJ5wzy[96]2i>7EuIuo}AS 湎hrH}_;[>s@0֜ (pէ~g.:imQ}ڱH?a5YO;[Ww~L;ZK9d9gX+ ׯ߽ej뙝}ܯ'Vwjau$mׁE_TE\'U#mu@FZ>@.Փ{u97hźqAݷ瓺iUЗ:0.cz(8eQd\>nh^ VY kK?Rejqj1OEORCJx1qpKD :dNՋUq`P\.Ϳ$Ww\OEe7K?I]FUM&=su@Z ѺKtzfgȉQ}v]Pѕ/h^0úiG(t֡z=V55 wy &9qJY\7atEbɟhwcyGuo`[}_N>dv{cx +]:#O .UݱUw0:1OOծeUD}zWm'Vqb[&r˯?K] }QGA(țf`"2h-ʆaT3zOݟ>ܧ0^I+/-oj{퀚:u-cmQ-'/n{r;(pY(_˳w0=QpVUGO\ê>V,9u%#-1 ľǾ+ޡf|@sCv=v‰~qs\RMTLBR;cr9բ>"G7(RyWТ16TG꿪0Ž9T.@ `t]@)8сatŝ4+ۧc},ъ[tymUM8dhrH5P;[+ϺI@Hr9꺥J4w%=ںo@-+zhSoSoפUuF=u@ƣtݲ"]HIh6-/_`1ܨGƾ*QHG{' -k$b,+? uez \Fz{hHU aEbn&\FW]Vk(`Z96-){B<'⩈6PۛM@ڰv9u>8L* UZsEj kauzq7f/w,`otFW3LS^vy@S[0^:xot> un>7':^%^=Xׇ2gx{X2]xlMY\?zwJ o1`CѓjeG0VV6wƔ9w(~-ӊNshOu(sӫ;-v c(TW@&{sl)ƌ1z;&V%;`8u|KCRa,]>vXhS c5584GW_B?ةXJz&C"Ϧ;1-rB~wsFtr>) ܞћC|=mCViIٍcot> ~B0uŮcɘ6;N;J6wƆ Ϭ]ȵKTsxHçza,,t C] x}U \ǐ$=r3ha_:Ku :L0+Dc6>=RCa,]d1LqLPRМi9cH3~m+8LVS%Sh2Ŋ#b+ &a,\w]G X@X<'_!GHkTg>4 JԂyc1|y&Ph4YEr Wi0A>#|鱊 6wIM%Oii0VVܪ@d VNJOA0LQIau Ig}gؤ *U:Nեe鳊^sdXZIR$9/:Nv%##>`;w7 jeNyw)i0&в5c0}yA2&5<:iGlsoݭx4 kfUtFMV؊K \G89zzgSj8F۴ZTvLlT.S`[6'_49Mb8Rkp[܅Y;#0d(7ǧf纎qڑ3CI[?0 ŒZ:&1l   h{K?[Yunscߤ1L4xC0BXd3Trk :. z&7CLHyLtT>#-:)V68 v*?X:_[ X>f64}` :@:9Ҡ3Ա=c]1]:1H( /wALZJDDK-=s7Et ˘8HmM`K`,N՝?:+ J ]rC|pҺέ`<\{p6:RVnDzq&z`R_ݣhG_*͝:iH{f f<}ͽ5S6/:L(K^~pt :dܐO g-ѳ4L7x޳@3{(]h)zw) ;Lj{tӬ@zv|Q ]:3Wy9~1򬎵YEOz g}RV@aHdhɜ~+Ls>K^sK/wtCAll~zls?U;ͽg'ܳDЗ/f,wᣠ- 5"G%i➎v{\{v8L˿YK]G -X|QGA(HA"Mhu]7ADn@_`ծϚ>6Akټ(%Sgޡx*&߁LW|YOuJ(5,:9^L{^v.M@Z7is{ kl*]V4=n6GI?,D( GIt幎 mgfũYwa%^c0C s]G`Tw3TwC 5uл[É>Jsݗ~Fm'T;u$Fvt>#-~$U՟ٔ;69Lt(Қg+]WOK|k)E.4=J́ư9mFFsKV}^_\[gT Dފ="A͘RKWixjXx Pyl0qM@JԼ+uO(RPZm^ꋶ+tRk{)eV.,p^%i]*۟>0&@^Wu==pb@I/X*M*4JnGY-QHB-HzNsI#Y9u?ϸd<[>Pv=u[4C2@6 7{{G~` dNzug4fFFVϯf,wRuo :dǰJz'`=* Mryԛ=YhMtCv<~{=RAT% :dk I>}gSDtմwq:`٦zԲ*s?-TU?|mOʾwc/ iٔ5c29QwotB1$I{NiֱJI &rIPGA1&*2v%t)r-q8enJIJx39bU/?6^QLɮc2|ܪ%E2*z[w\ V='9#2o!q77(\ǐ$P9pw=Mɳ7%`כ[=Ѝ~]-]qiJ=8][J.yQO0Zyi݋[~0 'F y}pL%M1k;4_'k'B6+Q#g<pJ <]VѫάsI #&~5.tiXQ,܌~=SvHDVFmq~]u Is{YŦrYty^ :,7]^/]} UIڟpq"d@z|`ŏ_ݿ| 0!nu I'^L/5?:TЗ:`2_hBM?BE*/ HJ;%I/F[|0_\ist5q ER"z{1B<=y1AAYI"iuߩ-ev 6Xc~w?p^*McתW,KS @ ȗ2߾ 08+\ǐVOlV/Wv pvs檋6^qF)2;VkJ ;׮CzG ]GL4~|rBAd6&[ݷVk0GiqYg#&@aۚlK9zp gv)ez K#&#Ŝ}ZtYwUݯ$<V}sDu[4uJf :F~gv)oʺ 4裂.YZy}CImӧluIH>BG&ITpC hkTO!q@F}M{G3(# RdP}7n^QP7sFϠ.n\Y:)=rv=֡zq@ڷaͦwGA-7^^!11#Czп(e [:zFPoHﻩ,-nyfGԶ?u(qvݻn#(mRQ@wvZ4A M.ˌιr=$ [:7_--tC'cڴG>eu[FAnY5Ib̀զ\GYxϣFg)Sqm+=|}P =fJs正3)QQNvgQ,[ w;2tYז֨_G\_yQ uCj/h﹎2P=?80?nTC)n8~PS ;͂+ H'F_^vɱѬPN?Bx=cd͘rZn7^GMuN`"mxӿ]D0ݷkrZ=wR_/:&v,a~ݖX| :`tmS6 G==Q}g_i84 {_寠TYqPmǯu&'}hri0ظDA9) ܾ4EwQ‹9&#}eÚmPb\}hm~+Ƿ꧵OI☿E } ɂe9谾S/pޒLqfg֯zt\0PG :\EʜY}dX||~XW$fAzC^Wl~b~0n$W#i06 H7}^?RN,_-Wt!]֞YbLd>wﭛZwR,Zۗa=!}{gu%Y~gݖRN͙Q/Iz᾿ M%K-+NS.~1}BAHM/ O'P7W494҃qdu[]n Q`tL) =ULq/|]6=R!y^<q0N\mm6;˵l^)=T*ugB届wx)']&Joʴ۔1O?}C/:3Tu8'{jQH7,և֖)6ϓ٧nOiɳ)g0a}@V0߻w߸NAAų'wMUyiica=x:+ IDATzz?S}N0>"cH\(#r٠4?BW]V4Gg_B?xCND>kkq0"AcS>Gr3îH3c-]7LLQnKW,[>%V=;G꿪X\;ncZ_y^9^EALK;M3CBXiA}ѓj˳)j}D_Q=RUEeèhOݻv˿ZtRZB_S6|C+YlRZv~L7FۜeuSIdd]y\,c]ZE>7G꥚7E4mrTQo{T{N>e 3?%+uOu6n])\Y9wIrC>-)A5wO<T0xjfE>#+ ;u?Gs3l^H66ޯHDI5ٰn#s ͟Ss\V^ 3ɞ"4wŶ?Q113`uw<ǭ.&˴护RUðbqo|CXK t"қbܢ-kqj-XK'R8,P]V1}_uBAd~M\Qa>4ĸfHReV/Ś\|Kp,VUFUulTȟK'eekU<ݳGu0ʌ\e 5K jquxXND4N[ϓUsdXkM)yx*]k22hݠ̢6;Z~cF5:ŅPo\G\cNi9Rt%txX"SJ5Gê=ѢyZHοʪeZ*ǟ+5*/R ȈףNiS(ѱPǔϹq1(#&*cf4<[Vj(҉15wt=ξ)Z<aͿ$WWkδ<Kue~Y(eQDjF ,DOE Sy6hrHC^uOR =bcFG]"Cw?4~[FWt^;uY4橩#Nt7Fs掶Fu5!^QfB# QE\(Z5p^@؄cVV^ %4T$9hbP"ɡS_'IOE$d;7ܾuEA49o`EpN 碚桃+bSS"дx22-eSI5[j\'y(@ `4<gyVJ?zO? XX'}hmhG?ˉ|IRM>$+E_`db2 *de Ld$?f8k6mrd$(#`;u|F\䢀v dgo1 5[ucpWY1( =k-#Y|5[c>B7sn}yÚ!,blq=k7ncHg|fú2(#3uTI+n あ>B@{lzuBAc3Mu'@0t=lΪr.Qi,`uw<: lq`8`b A\q0/ݼi p<[E9?tx_ݳv]I'[Ɇ[) 4t-3(1cY}3}+w>3:O:F|F_lXu<0RQn<[nK@}A6֓LyMgׯz4:DGA!?@KIgdYۚ%M/i(KHmdƷ5p*Q V#h>0~2:UP2+kvZyۃoxu(PG,HkFeeP|WWosQ ck.Lrחn~u*\ :LLÒIf+hͮrFATkewcvzƿ+J_nKu0 `ԽRƵgS^u[alQGo(F$!ɷXW WsYv8]eiOz⮃!=P`Eu>ۣNPG^9lTiʔT2 >9!1#Uz2ƨ2Wq ס(p*eTKJ{֯:2@lթ-֚}Ac0(IIƨR2>_e΍757= LҔtT>Rݻ~ݖ>! Tu#Us_dŠHuO= HGVR*#[I ks 3t IU2ڟ[ud  VQ#U[jLj-ȺFA0쀌52Wj]'X5R1VUmy[#šPlRߨn-C>q )#{DUyVR5LP}> :&>Uɚjɫ1RnGîنdlX[߸`NX*cU-jpNG\'p~t`JVZUxzͮx q:M53TZ)U7\~2:AAc(mv@2uze{IZnf{\'0( I%IZ6: :0ږԤ6T6e]>(#g;+W'cLS}c`}:@vqLjclk5N`⢠g115NW4ڜTu[,tn+UdO[S<5mu0فl~kUcj}V'}^n~u0ٍ>uQQT+V\ף#F^9Lj55W=v .ɰdL1Lm"7?:(!鰬jTkZy-7[o{X@(&wdI1=c} =sixaFh~cLv?(mݒjdUgZOMu_^ QG g;j'jHm9:LD( +$~T#Ouv-ed]LAAHQ<ɚG֯ےt2}|t0!Y+7RO5>y O\lEA z Tk^" /8 3JFFx*ۻ(ޙADP)Ih[8 `Ětk6=9d(s64=m8mXEq@ŘXFQadadID;~suF<;oz8;:@mT+4 ]g= 0:(Li WYR\bҠ_tw ic@Ȕ.<9=J0H,<0W\wLD &k"ɊnSo-20@QJAdP$~Y/T/}s&^BJ<@x}2EIAKQ뭬> |@9&STf3D!GAf ԭṬT J֮=YL^:gCbbB ,P{x8`pKMX]mڒw}'>QhSL& =v|l/vUh%vI^[qnμmkچx @MMw\=GCg8W 8GSO,jh~Xf&Ik:[nISOo=:1'gr7{$ "%rQ/aԢk}OEa3=*?˟Pz%]Zĕ4_7aԓ{7.Hg$]z7 X:") qY.ad W^QNϚӯ3oK<0Ir}+:g g:[.?#u_ޣO̺*t]: H% $A{]rQ=IKN!=l+;қ}g ɏˬ$HfqXK7ir @ yξS 7="ӯ;0\ T+:9bQ~+L?{y%_1+?sI:`d%I%Vz.ݶ-zg0/ykHl>cZN_YԶmrE2< b¼BkW%q`bCWwkub3J֮mԁ.I7.]`<#Gm7G7o/ۤn /ydR(܊ ]vdL]i_qq._yJ\w\nUZO`#j))+T6i\hz@BgLqZixHv5370q U$K¯-yH˜$;+=dF{M^?~9BT$E$Wެ1tI;rWȵhq=~"@ÒEnTA f #nlcwp׀ܑtZ䱟,4DtY&蒴ߛ|WvH]__zq32+=B(oEԂqtIZ7ג$wkO, Bˋr+q}_jل$ HIzy{rDF'L2u+=yrͣBK^YzMXK(i$}@On9\YY0([R䧞%rf=`@{$^׺kWO%Ԕ!Iݒ#/KasUmI& tIZq܃&])I[V_ -_83p>,6bB҆TIvZ*YetoyA>yZ/IډP+ [eo#w<<8m`ǃsYK~v̆r-cz}5-8)!I(R% Wnz @K=W\K>Zܳns taI|RbK7d x/5t%id=Bvnb{Bk[YG$:[.zLeŝ3v"Ё pTRɥq I[ѱ?aX@Bg˔$߸hq=9Huf]X=1I./Y$R}_Ps.Iwhk9qdSW.IΖ8xx~HcmSC$Q3I$/ʭ䁊nRų ״ g=IuGpaSệUnyhAmO|L=O]+0E)R[7:` >IDAT.]:/o'3/Α|b"74x` k}ipؿ '/ދK{T K߼i@tIZJu~t[S h~XLI蒴ua9Mx|˺{͟Ө1ZpY"d ~4e5i] ϭpɧ_L@kg;^<Ґ$g_]9Mvq\ H*<[ӠtߊYP&uKҽ}=wP9=Oׯ~d8/8Nrpv".IlZr['}}u3gN2mrE#!A;V%Y)Ζ[G}p=_|L] ZTLܣT ^зE[(T|%{?߶x^sGgW>cJLŮAwbJ?n(up3rG/i!n?YoGȵy|Ncj#)*9}rѤߒxnIˊJ54䊅@go =]dzwfEG+m-g0@8UheIENDB`cordova-ubuntu-2.8.0+14.04.20140130.3/www/splashscreen/200px-Qt-logo.svg.png0000644000015000001560000002743612272510553026213 0ustar pbuserpbgroup00000000000000PNG  IHDR|HbKGDtIME ;/2 IDATxwx\ՙΝQŲda{M!$O!nvv7.mBB&$$d y6Zlc w\U[Œeuizrif3W@9h(HŁ\(PL<Ȧ r EAFA$ xGA93m ÷q!G[>Rߥ1y!r ^oL3R/hsy},.?`u׭H™IR%@+m%͔BP@KŦʐTiLn$ßZ:w ,8w 1K&cey2,&F*SƁY JHQQ @8D6tG}6U-C₸YEfl[$6f '6:]e՗>8 J {7Ag?j(&^=`ۊ4)S @yRz6zbs PC"ȣV9>8?+jz2f!;M鴉uuzJm=ͯğ Ʉ=O4l!Dn_ݒ Y*u;2]snEN)@-@@RjuNH+{鯽ξ@T]UbƭcB}$zZӝnRk򛥻>96%ڑ19I ӘT4P;O]!3 qQ GOQ]y)6M!z 6JaOİ^V )1e`)lAp I#pƋa7%ޠgv4 Z?;dVwlV ١Z/8@jN}o@[YOT|\digxB(!G @-uwqRd3:\EC# ńۆo(؁@OAZdXqDF>P”0ڍFBS[(xr\v 5354TN@@pҠuxrc/JPP/U& Y6<%L,<k(4c44aCC|_QԶW0x0 4=8%"54"`y퀮!C$j!1xs Ck,贂0s!vHZ* %(C54&; ^sjhBS<ݠ54T-XQCCCC# ,pw|(02Z !p !' >uq7`"#%i&:I3n.@)),X+L\:ۅ!ӆO ; _ye Cm݋!]l²9x A)` Ҭ+[赫/AyY,"r& ɆL=i<[l]ѹ{Gf~2fޠސސ/>v!W&n{+$?U+`{!ZwQ싷qO0w+g? F9l8AB:o'a]^˻a6n=y2,ێg=:]R3J)׏ ONq0#|y |"iӆ#"$74VdaR MR,?'(^X;=dI5VG5f1;dc Ljdܝ@qr7ח,cSJ%*6,}QT&2b1K6*ߣFa^Y8(V.L}7νWV{QݳZeP0uLbzs]*a!~>֡*ķq;)%Xyu2>{hjF9Ѝ~46=s-꺫eǨ`yn[Ld ;QT/v'"^KpTԞO{ \]E)pvvuZm r0yNLcw\؉z>dڼ.!QFxGੰ'lY(7yps,m}-1Ή fJ46$fPonE(0)fKÆ~~e= H,8,6^,˴sqm珴?n(p^x.FLS?/{lQ1[<͒i5DC@ZJ"j+P|z,J)fKEq}Q;2gQ&pF }a*ŹF$(fK,椉' I503Uq' ȀHi.(*[|d73]\ =C~8=̻jYƝ F .qfn)2 $;VeTUP|*NP^0W1;pXIOȐ'<[i(ʨF .XL +fj%RlaE|~Y4btM B^ fISH+ $IvK^ s![gՕ8Qъ~IfF'$Cݲ̙bBтU[J6T!NA-YoLs!V'c K7fUU}1Eù^A,Ϭ^<H3Մ/ĂYV?s5c~wZwo+V-:-1 D@/~Ag$}F|[0qQpRX%yF[u=@ސS4:|xn#1 D6YF^ wxSB:e8/ Pl3H]VK+8 0E0 oH8$>VWnSJB V^٢^. G0$ /%[,;JMF!Pʖ͗ :!̖5 t bDD 0ʅ7$@pe%鯌ի¿)?HhxF)W/iDZ`bm"^,"v/V@"#&@% 4ar` Ť{D CtW W1S-Up@ ׅ%J D. 9C! _HBy.VoC% WQ}+"P!?e=۵ 0E+xuH<œDCzP[Ax 'ފ V :-ij4p DlqTC:p< k&E6(yd^b0Gn@ c4)WTg)i_Rbn^A8b!'D)6SR!U|\S;r>Qs*rmwi^csހ' ߽0\x $@HvS!Hv0b-Mkq§&r$(eW8/odԘ^ r&i6P@|?L|v'BY ;M)9YφjE WFBnŢ 2lKq^De0JNHn=5r/VS U$\%,Wd˷`u[HqFW@ +QirDY$yCC_X+A8 Dv|يjEaõ*++H ٶxޠS3Q@…x^A0eVYXrV+H3ǯ -%Z#kCƭH8/?T`\ mD?G@dt?qqWt|#s&L&T#I81 2 fJg{b)M bX⦶U̎dc;2gu C"'HY<ۢz(A-"AYqy;ӱ++s5yt`4|YxxEܼI2y?W8?Q)P0C5#~G=VlI7#~x ͔'˼6knWW@2{ Ye;ēf2df n5Uj F )hb{Og%\$˸zE@y͂?'qcD,O(qF f^?Z*fKNR,bejދyٞI«F P-9\ L{䊆R7$.BYJtEӖÅ9&Xu 0fm]t8à3I~`xA͒t:]MQ穤Ů 1 DTkj IlɷΔtޠh KP@.}-'mDӮ-#(!T6V̖yw[|{i@I|IekFC-w x*z.qe[Pr;8b I|Kx, D|n8E}aE(Β5SG˶x,{V21YAA*y]DXxCfiV/>?|,cli71"͒3A0@,>$U<,/ÀUӯd1 )"2r'E*,I4ՍھQ> ?j[c 2=9t5aw![A|^r U $#Ŵl/fs{μ}*toh"c1/Fms$ J[l y \,)\'{^;VVDvpZ w.Vcc"%L5# R$l'a]At5g;ρK 0ĂG+~p݌e#7 s\-mk$q{iV^Ү>?~πɺu g3V [gbF1qpW bQJa"3΍շy$Y"oGv@P͸pyTfA ])<lXt >藯tBe)GX@r(;fg"v0D;ztڹGξ>ͯdI 8p';]܎So)D|HAe'xߊ5I5O{(v oғYdYklBOdpլ#ԯzHxh jz*8j9BP$ 欰[w$em߹?E,hu~GHْbRdZe"A]x׊Z+B'؜8Z;ހ&{tẙߐͦމFcd sb5M!L ei* Q{_WԞi)xpKXS,c,Slixboٛ^üuo~i ]%!gMPIDAT4ރ&;M%sqlSngǂͲՖ&a{asqWt5t ;i:f/jΨui*O:@G~/闽w8Lũo\q {.`uӸgK1;cfgP|O*[)I:̞fB}Xw:'Nw5E;b#|r 4[,`xUO~g/UV䅏*~p47랒) }v=㍦Y+˸ û'@ЄųGlpSتpJS%'À5󅷃oodHhKtҐ6S=5Yľ%sݢT){)xcg[7 zyx1 $ Yn,|6 @TvG-R'!-3q͜n!j{7*:t)8Y;LgpZ&!^XL:d]!w5|z J7/-xq3 "3  ]$QUWQ^Ұh8#? -sjB1 dtsB .`2=D} ,*pljV}O),#x 8/{^pG>Fu0}HҧETę8p!K[N L*7ˮJ/Hs/؜xG(8X'CSÒ片&(0@{g; w0+ϡmpTNR JR":YHҧZ `w]fw֣YӽTc -HH8p+~!+/?>x M\#k2\8RX/,݂nwKIb\*]З_uƍU KT|!ި}72!Gc2001_H @V|lXvq~`D޻x^=g/Ljnr6 oBfʨ E Ƕw>[ e T D !(/Ԃ!wUgsއ>śu?m~3,YH! d\f/ O*&c%76FX\& 1_auN8?ZPY"%HZ^GapIJ#NB=6|S5$ݼL8}h?* r6cm5ƃm5aK-}(<꒧80>!X*j\ ! h0##Z氷aodA"$\ˈՐJWf[Q'oԌŸwq-6U &=$ك]daZJ9߲EgMUn`UVC0\c^pq6wh!bbq\-BP >xCt5ŵdkkXq%XPxl,&El1X s]Y ϟx`Җ4R JH7݃DLV%[vZ]Iu&,jäG=Ab"-U1/KBn.}n58.Y2ͅIEA21nnz_PѼFÌmًn?AB8Y1Vy28u>&9~8/A'?z(G[> a,FGX!(7]ryq?+n? h8>0Ig4z]ҀIgv@ 7ǹ37#2(ZnA\gJZ”˜:PV(˹[+%=!7}w" Dc*߸퉾! P? f*',@Id:( {Enm1!;6/}v0M *iIJI\c%&h.^  JN\GɩѷR@:M!r@@ sJU>K#/PM>xz7e{a`-4h( 5*Bi Tl=ޖ#&G65**К$w] @XQP@l"Tybӧ&^biL(h!:Z@&w`M CF0M3* %mzIuŽB5aQR+ڈI :¥h5%NƱ!ۏaj@bMpֈ2#ajfX ZȺpl(!vBH =6l2R\{M_K8>2.+>l 6G64ԂA5N=k%=nn:y>DE $"`lBtzk\HLDP[_;ᡁb1-MZ ` 5R;yFHCGEkqWDpQR JEkjLMӡU:nCW^4ˊVf\PC@ bS ֐ -;^ۡ [_H̱bʄHj5< =哾xn"#gv}6O#W̳b2%BbPl0ZD|%r>p̺)X8Ujiv /W^c2 1:eonϛ%%-Nf$>#$t"!j7Ԏ6ZsLgS`y7ZP@j 9-ί1i}y,Rz@8u"RjT 5}yg]8~IENDB`cordova-ubuntu-2.8.0+14.04.20140130.3/echoplugin/0000755000015000001560000000000012272510676021327 5ustar pbuserpbgroup00000000000000cordova-ubuntu-2.8.0+14.04.20140130.3/echoplugin/echoplugin.h0000644000015000001560000000125012272510553023625 0ustar pbuserpbgroup00000000000000#ifndef ECHO_PLUGIN_SDASFVJH7865 #define ECHO_PLUGIN_SDASFVJH7865 #include #include "../src/cplugin.h" class EchoPlugin: public CPlugin { Q_OBJECT public: EchoPlugin(Cordova *cordova); virtual const QString fullName() override { return EchoPlugin::fullID(); } virtual const QString shortName() override { return "echo"; } static const QString fullID() { return "com.example.echo"; } public slots: void echo(int scId, int ecId, const QString &str); }; extern "C" { Q_DECL_EXPORT QList> cordovaGetPluginInstances(const QList &pluginNames, Cordova *cordova); } #endif cordova-ubuntu-2.8.0+14.04.20140130.3/echoplugin/echoplugin.cpp0000644000015000001560000000103112272510553024155 0ustar pbuserpbgroup00000000000000#include "echoplugin.h" EchoPlugin::EchoPlugin(Cordova *cordova): CPlugin(cordova) { } void EchoPlugin::echo(int scId, int ecId, const QString &str) { Q_UNUSED(ecId) this->callback(scId, QString("'%1'").arg(str)); } Q_DECL_EXPORT QList> cordovaGetPluginInstances(const QList &pluginNames, Cordova *cordova) { QList> res; if (pluginNames.contains(EchoPlugin::fullID())) res.prepend(QSharedPointer(new EchoPlugin(cordova))); return res; } cordova-ubuntu-2.8.0+14.04.20140130.3/.gitignore0000644000015000001560000000006612272510553021156 0ustar pbuserpbgroup00000000000000cordovaqt.pro.user* /qtc_packaging/debian_harmattan/* cordova-ubuntu-2.8.0+14.04.20140130.3/README.md0000644000015000001560000000203612272510553020444 0ustar pbuserpbgroup00000000000000Cordova/Qt ========== Cordova/Ubuntu is the Ubuntu port of the Apache Cordova project. It is based on the Ubuntu/Qt port. Requirements ------------ - Ubuntu 12.04 LTS or newer - Qt SDK To Create a Project ------------------- Download the source code and open the project file with Qt Creator. Add your HTML and JavaScript files to the www folder. Edit xml/plugins.xml to enable or disable any required plugins. Compiling, deployment, and packaging works as described in the Qt Creator documentation. Supported APIs -------------- - Connection - Contacts (on x86/desktop only) - Device - Events - File - Geolocation (on x86/desktop only) - Notification - Storage (Uses the W3C WebSQL Database and Web Storage API specifications) - Camera (on x86/desktop only) - Capture (on x86/desktop only) - Media (on x86/desktop only) - Accelerometer (on x86/desktop only, with supported HW) - Compass (on x86/desktop only, with supported HW) - InAppBrowser - Splashscreen License ------- Licensed under the APACHE-2.0 license. See LICENSE file for details. cordova-ubuntu-2.8.0+14.04.20140130.3/cordovaqt80.png0000644000015000001560000001471512272510553022054 0ustar pbuserpbgroup00000000000000PNG  IHDRPPsRGBbKGD pHYs B(xtIME  ;1EDMIDATx}k$uwUUt o +-!+`kr7aH eڒ-Y 2F0IxM7ՠʼ~#3kk#FdTWUf=|{n4faB3 N"Y cx;UMКQWHIBI- av@8To<Ṳ80b7^`0GZI:i Fج7~'H?,"r#JT];2=i)"@j("k|^ EQiRx_YUX#N f( E |͸뮻[n;[Fa#gDw46ojgL{FZ=v;?rxx#!@/'YԂC#c+rHk^=`>íe@BcjZ;MD3jYZh,SޢfP9]`ޯɽuv!yzVsrW7q@8664:{`sN dw)I..q%K{Xk$RJ5hIC<ÇɃ {!311/.U*+pISGw>K/{v>|1`>aW.lr̜VMHLnEo/ȴVoj>_d~SKS-ITJ @64/Mxڌi)1Nۮ׷'ZCD\6 ZKTBT8 +\`I'mOŔeƓJ""0;XkUƪ{ϋ.(Mukidtq\=x 9iВq0\bH'$cǎu|g{f' w>O^Ȃ $ }ǵG,ncLT.UG޵$~&m=d+$N9R&R^1RA7lV \xM.u׽clHaQw:# pMR)Zf3:,:ل+p 7oymv#G8kmt>sNaja9t͌ްq@Z*̯#y<7@z{ 8bXkY 9κq S Ka8'`?r;""晍.KF3C۷ٵ쌎s.) J?djRhRA!W(Zat:ݮg6=pwXL DG}bӦͳeLKtUZr'j(aG)UK= 3rvG4'NGKJr$VzA@@d||߯,3`ޞGU\R-"@"ϦƘj7c}t}*p`` Ie Z_B`*֖s$)IĕJsLf@@t&y p+OXԁW*|ژ"ʉ"gs&yPt@z'¢Tw;߯y\WLґTEw[.WJ ZNwӁAֆy̛K vZay1*HVC<1qvz(@Så*5!S.bZMjRU*jUJTTBuX**J4BLۉj:Hb~wegaHR6~qceRL`z,JUXDО,HVeG#[6% 5\L,^P`JsFydxxojnLpڵ]YcOW}$\դgfp܍P'Qyw<@=j !X R*ۛc#"[ # D,wb2* O/[ׯغb dhs 9.3ªBzl76m#DNrlaBjJ d} ;\@39\ oٺ:@KUJ0O8ȅ2>G:\m MbƍAz$Lp!y0#,ruύ)H$lI%0K1@*z =m;4S#}  F)3tkE-uo YXaNvNJZv&\W=1p& /H\AԒ,K4>/m񁉉>|]XTS~ &ղ&z L?0"T0$@2,D)T*te.,@|d/"rzrf/j饢\(O"^M{Wg]Z+D(Y%ƴ,K[_p\M/͕.H$-f{c*ڒYJ \V8'J\.,ɈfjE88)ٷoϋR4DDb. KRY+a&R_8糜$>.1꽏Rm`-vm3du%[i%PޚLZ5,}QD n?5W}{߭Gkփ Pbt۝8<=+ZCR|+ ā1#o8p&"lEz!Rb[ ޵hD-(& R)LxXkgIlf||?8Ft{n#Cm@vCOD@%7{Xk{mg'~h[3@J#."PA*.0ghKQv$Iſ~ǟ&a?\6ƨR47,k9[}P渻NXO&"r k KA9O+$9rh+Q*EwvԻWOkm읃'g\%q<8ѵ6yݫ~$!]0 IYsR$PSNfE^}fɴ:?H g޽K' Lxz$+w:Hk'5M!ʅK?xqtjا|BG?ix6$)_ 暫+$Qt{:$zddxxyOn4q &SyHx'EDZVoiֹt"i /HAlh'>Cq m}yst΋w_߽x`YpΗ>G#6XK}zt wmy_kF"ǺfZ[*&iZoWVƖk^}jFìН?6j )\{{ka98xOt"JIz!a\ٿsZ XeɛT!炰t^+"JkU6It✶I-]? "R% BY /J{rXz<%{3 WeYD#xƬǶMbe 3XZ}<jZYJsD,ِ5!yKYrPj5'@xtN\ze _ ={,,YF8379%I?LNLA%(Y)" cJ6*"ɯZo?)*7?IL%9}d \kAмm-o+Kj B99,s.SY,wnaTf0ʀ=؟i5F"3LJ'sňt/"QI7Y1`  :q$ *֥,XXgaVlذim_~UWBʡzt4myuwk'" {ks&6}uZZ={ .wv$??=} __75#:G=}H0Ir&YxֺC&J[$6.Hl$։n6In5sg:~sMpם_{$ x) nUR[[D~?6Ko= =$spY Xjmg2VrMM\=!'?u%B0`M&;EȒY$R6uG D)(!HPzzhB̛F0. 084֭[?xȡ8zt GNazzN6> +a@;PyѢ(%J)8P+ҐDAI>;$}Jkl?k;m ZZjVZF#y^ /g}':̼c җވ+Z2I0+stJ$"Ib$I$M`8N'I:!cE*۶mù睋s;Fr0D\Bh t 0A`dc`cBa f\lܐIogS'#ld Z{ow qR腆956bӦAlڼ7b4M6)(he`P0& wZkhV9z"4Ɂ|//0h~asWw=Z{yA:  /x5A(eyGNMR hhifjc2:>q HF_pD(vE"Rqe qL@T"ȳs]Y:<C)b-ZghRzgRBgDbcE+ jRGI d`觉6lZ =z SsȞsU-U>%79Вys&,DD\De0$y+, (84g$,IfY/G+nCRQyYomҬ7P=M {/[όp_ق/o呱VҌe5'zQt!BrB=j:^ZrZ> 0'\&?F|+;eǬ>1.m?F#qBD@,";zK;ҏPFp5 5f=zP=*:Hk3zc#5?nA޸`xlfq SP;5b|hxtxl#%{>pg ) $92(QHw,"75}p(0G)w+Dpl2^22JhHuucV~ ͨqK3jD oMMb3RG ݙTO L<E3j ֌x Fή Od4#cV3j!ɛEd dzBpXk2AwE*GVسgoQCL [hFu=lfPճ!_ `^W BYkެGwE >/h+eo[y[_-~"SP֎^c X?\p5zLW1 uFk=f^L7@:!~jxfuW=EoH $E^lnV΃N&Z`|]`!_%ϦDtBH`f}flٮYdИ/bz5]WӆwƊw2m#ZIENDB`cordova-ubuntu-2.8.0+14.04.20140130.3/LICENSE0000644000015000001560000002613612272510553020201 0ustar pbuserpbgroup00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. cordova-ubuntu-2.8.0+14.04.20140130.3/src/0000755000015000001560000000000012272510676017761 5ustar pbuserpbgroup00000000000000cordova-ubuntu-2.8.0+14.04.20140130.3/src/cplugin.cpp0000644000015000001560000001003412272510553022116 0ustar pbuserpbgroup00000000000000/* * Copyright 2011 Wolfgang Koller - http://www.gofg.at/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "cplugin.h" #include "cordova.h" CPlugin::CPlugin(Cordova *cordova): QObject(0), m_cordova(cordova) { } void CPlugin::callback(int p_callbackId, const QString &p_jsParameters) { QString javascript; if (p_jsParameters.length() > 0) { javascript = QString("Cordova.callback(%1, %2);").arg(p_callbackId).arg(p_jsParameters); } else { javascript = QString("Cordova.callback(%1);").arg(p_callbackId); } if (javascript.size() > 1000) { QString t = javascript; t.resize(1000); qDebug() << "Running: " << t; } else { qDebug() << "Running: " << javascript; } m_cordova->execJS(javascript); } void CPlugin::callbackWithoutRemove(int p_callbackId, const QString &p_jsParameters) { QString javascript; if (p_jsParameters.length() > 0) { javascript = QString("Cordova.callbackWithoutRemove(%1, %2);").arg(p_callbackId).arg(p_jsParameters); } else { javascript = QString("Cordova.callbackWithoutRemove(%1);").arg(p_callbackId); } if (javascript.size() > 1000) { QString t = javascript; t.resize(1000); qDebug() << "Running: " << t; } else { qDebug() << "Running: " << javascript; } m_cordova->execJS(javascript); } static QString escapeCharacters(QString str) { QString res; str = str.replace('\\', QString("\\\\")).replace('"', "\\\"").replace('\'', "\\\'").replace('\n', "\\n"); res.reserve(str.size() * 2); for (QString::const_iterator it = str.begin(); it != str.end(); ++it) { QChar ch = *it; ushort code = ch.unicode(); if (code < 0x80 && code >= 0x20) { res += ch; } else { res += "\\u"; res += QString::number(code, 16).rightJustified(4, '0').toUpper(); } } return res; } namespace CordovaInternal { QString format(const QString &t) { return QString("\"%1\"").arg(escapeCharacters(t)); } QString format(const QByteArray &t) { return format(QString(t)); } QString format(const char* const t) { return format(QString(t)); } QString format(const double &t) { if (std::isnan(t)) return "Number.NaN"; return QString::number(t); } QString format(const float &t) { return format(static_cast(t)); } QString format(const QVariant &t) { switch (t.userType()) { case QVariant::LongLong: case QVariant::ULongLong: case QVariant::Int: case QVariant::UInt: return format(t.toLongLong()); break; case QVariant::String: return format(t.toString()); break; case QVariant::Double: return format(t.toDouble()); break; case QMetaType::Float: return format(t.toFloat()); default: throw std::exception(); } } QString format(const QVariantMap &t) { // QString(QJsonDocument(QJsonObject::fromVariantMap(t)).toJson()) is not good enough // e.g. QVariant(qlonglong, 1374944677139) ) -> 1.37494e+12 auto map = t.toStdMap(); QString res; for (const std::pair &p: map) { if (res.size()) res += ", "; res += QString("%1: %2").arg(format(p.first)).arg(format(p.second)); } res = QString("JSON.parse('{%1}')").arg(res); return res; } }; cordova-ubuntu-2.8.0+14.04.20140130.3/src/qmlplugin.cpp0000644000015000001560000000041012272510553022462 0ustar pbuserpbgroup00000000000000#include "qmlplugin.h" #include "cordova.h" #include #include void CordovaUbuntuPlugin::registerTypes(const char *) { qmlRegisterType("CordovaUbuntu", CORDOVA_UBUNTU_MAJOR_VERSION, CORDOVA_UBUNTU_MINOR_VERSION, "Cordova"); } cordova-ubuntu-2.8.0+14.04.20140130.3/src/plugins/0000755000015000001560000000000012272510676021442 5ustar pbuserpbgroup00000000000000cordova-ubuntu-2.8.0+14.04.20140130.3/src/plugins/connection.cpp0000644000015000001560000000512312272510553024300 0ustar pbuserpbgroup00000000000000/* * Copyright 2011 Wolfgang Koller - http://www.gofg.at/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "connection.h" Connection::Connection(Cordova *cordova) : CPlugin(cordova) { m_scId = 0; m_systemNetworkInfo = QSharedPointer(new QNetworkInfo()); QObject::connect(m_systemNetworkInfo.data(), &QNetworkInfo::currentNetworkModeChanged, [&](QNetworkInfo::NetworkMode) { updateStatus(); }); } void Connection::updateStatus() { QString result; QNetworkInfo::NetworkMode networkMode = m_systemNetworkInfo->currentNetworkMode(); QNetworkInfo::NetworkStatus networkStatus = m_systemNetworkInfo->networkStatus(networkMode, 0); QNetworkInfo::CellDataTechnology cellDataTechnology = m_systemNetworkInfo->currentCellDataTechnology(0); if (networkStatus == QNetworkInfo::NoNetworkAvailable) result = "Connection.NONE"; switch (networkMode) { case QNetworkInfo::WimaxMode: case QNetworkInfo::WlanMode: result = "Connection.WIFI"; break; case QNetworkInfo::EthernetMode: result = "Connection.ETHERNET"; break; case QNetworkInfo::LteMode: result = "Connection.CELL_4G"; break; case QNetworkInfo::GsmMode: case QNetworkInfo::CdmaMode: case QNetworkInfo::TdscdmaMode: case QNetworkInfo::WcdmaMode: switch (cellDataTechnology) { case QNetworkInfo::UmtsDataTechnology: case QNetworkInfo::HspaDataTechnology: result = "Connection.CELL_3G"; break; case QNetworkInfo::EdgeDataTechnology: case QNetworkInfo::GprsDataTechnology: result = "Connection.CELL_2G"; break; case QNetworkInfo::UnknownDataTechnology: result = "Connection.UNKNOWN"; break; } case QNetworkInfo::BluetoothMode: case QNetworkInfo::UnknownMode: result = "Connection.UNKNOWN"; break; } this->callbackWithoutRemove(m_scId, result); } void Connection::getType(int scId, int ecId) { Q_UNUSED(ecId); m_scId = scId; updateStatus(); } cordova-ubuntu-2.8.0+14.04.20140130.3/src/plugins/app.cpp0000644000015000001560000000042412272510553022720 0ustar pbuserpbgroup00000000000000#include #include #include "app.h" App::App(Cordova *cordova): CPlugin(cordova) { } void App::loadUrl(int, int, QString url) { QDesktopServices::openUrl(QUrl(url)); } void App::exitApp(int, int) { QCoreApplication::quit(); } cordova-ubuntu-2.8.0+14.04.20140130.3/src/plugins/inappbrowser.cpp0000644000015000001560000000140712272510553024655 0ustar pbuserpbgroup00000000000000#include #include #include "inappbrowser.h" #include "../cordova.h" #define INAPPBROWSER_STATE_NAME "InAppBrowser" InAppBrowser::InAppBrowser(Cordova *cordova): CPlugin(cordova) { } void InAppBrowser::loadUrl(int loadEndCb, int closeCb, QString url) { if (open) return; open = true; m_closeCb = closeCb; m_loadFinishedCb = loadEndCb; m_cordova->rootObject()->setProperty("inappbrowserUrl", url); m_cordova->pushViewState(INAPPBROWSER_STATE_NAME); } void InAppBrowser::close(int, int) { if (!open) return; open = false; m_cordova->popViewState(INAPPBROWSER_STATE_NAME); this->cb(m_closeCb); } void InAppBrowser::loadFinished() { this->callbackWithoutRemove(m_loadFinishedCb, ""); } cordova-ubuntu-2.8.0+14.04.20140130.3/src/plugins/splashscreen.h0000644000015000001560000000105212272510553024275 0ustar pbuserpbgroup00000000000000#ifndef SPLASHSCREEN_H #define SPLASHSCREEN_H #include #include "../cplugin.h" class Splashscreen: public CPlugin { Q_OBJECT public: explicit Splashscreen(Cordova *cordova); virtual const QString fullName() override { return Splashscreen::fullID(); } virtual const QString shortName() override { return "Splashscreen"; } static const QString fullID() { return "com.cordova.Splashscreen"; } public slots: void show(int, int); void hide(int, int); }; #endif // SPLASHSCREEN_H cordova-ubuntu-2.8.0+14.04.20140130.3/src/plugins/notification.cpp0000644000015000001560000000514212272510553024630 0ustar pbuserpbgroup00000000000000/* * Copyright 2011 Wolfgang Koller - http://www.gofg.at/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "notification.h" #include "../cordova.h" #include #include #include #include Notification::Notification(Cordova *cordova) : CPlugin(cordova) { } void Notification::beep(int scId, int ecId, int p_times) { Q_UNUSED(scId) Q_UNUSED(ecId) Q_UNUSED(p_times) QMediaPlayer* player = new QMediaPlayer; player->setVolume(100); player->setMedia(QUrl::fromLocalFile("/usr/share/sounds/ui-tones/snd_default_beep.wav")); player->play(); } void Notification::vibrate(int scId, int ecId, int p_milliseconds) { Q_UNUSED(scId) Q_UNUSED(ecId) QFeedbackHapticsEffect *vibrate = new QFeedbackHapticsEffect; vibrate->setIntensity(1.0); vibrate->setDuration(p_milliseconds); connect(vibrate, SIGNAL(stateChanged()), this, SLOT(deleteEffectAtStateStopped())); vibrate->start(); } void Notification::deleteEffectAtStateStopped() { QFeedbackEffect *effect = qobject_cast(sender()); if (!effect) return; if (effect->state() == QFeedbackEffect::Stopped) effect->deleteLater(); } void Notification::confirm(int scId, int ecId, const QString &message, const QString &title, const QStringList &buttonLabels) { Q_UNUSED(ecId) QString s1, s2, s3; if (buttonLabels.size() > 0) s1 = buttonLabels[0]; if (buttonLabels.size() > 1) s2 = buttonLabels[1]; if (buttonLabels.size() > 2) s3 = buttonLabels[2]; m_cordova->confirmBox(scId, message, title, s1, s2, s3); } void Notification::prompt(int scId, int ecId, const QString &message, const QString &title, const QStringList &buttonLabels, const QString &defaultText) { Q_UNUSED(ecId) QString s1, s2, s3; if (buttonLabels.size() > 0) s1 = buttonLabels[0]; if (buttonLabels.size() > 1) s2 = buttonLabels[1]; if (buttonLabels.size() > 2) s3 = buttonLabels[2]; m_cordova->promptBox(scId, message, title, s1, s2, s3, defaultText); } cordova-ubuntu-2.8.0+14.04.20140130.3/src/plugins/geolocation.cpp0000644000015000001560000000524612272510553024452 0ustar pbuserpbgroup00000000000000/* * Copyright 2011 Wolfgang Koller - http://www.gofg.at/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include "geolocation.h" Geolocation::Geolocation(Cordova *cordova) : CPlugin(cordova) { m_geoPositionInfoSource = QSharedPointer(QGeoPositionInfoSource::createDefaultSource(this)); if (m_geoPositionInfoSource.data() != 0) { QObject::connect(m_geoPositionInfoSource.data(), SIGNAL(positionUpdated(QGeoPositionInfo)), this, SLOT(positionUpdated(QGeoPositionInfo))); QObject::connect(m_geoPositionInfoSource.data(), SIGNAL(updateTimeout()), this, SLOT(updateTimeout())); } } void Geolocation::getCurrentPosition(int scId, int ecId, QVariantMap p_options) { Q_UNUSED(p_options) m_successCallbacks << scId; m_errorCallbacks << ecId; // Check if we have a valid source if (m_geoPositionInfoSource != 0) { m_geoPositionInfoSource->requestUpdate(); } else { // TODO: Replace with correct error code this->updateTimeout(); } } void Geolocation::positionUpdated(const QGeoPositionInfo &update) { QGeoCoordinate coordinate = update.coordinate(); auto t = std::make_tuple(coordinate.longitude(), coordinate.altitude(), update.attribute(QGeoPositionInfo::HorizontalAccuracy), update.attribute(QGeoPositionInfo::VerticalAccuracy), update.attribute(QGeoPositionInfo::Direction), update.attribute(QGeoPositionInfo::GroundSpeed), update.timestamp().toMSecsSinceEpoch()); QString callbackArguments = QString("Position.cast(Coordinates.cast(%1))").arg(CordovaInternal::tuple2str(t)); for (int i = 0; i < m_successCallbacks.size(); i++) { this->callback(m_successCallbacks.at(i), callbackArguments); } m_errorCallbacks.clear(); m_successCallbacks.clear(); } void Geolocation::updateTimeout() { for (int i = 0; i < m_errorCallbacks.size(); i++) { this->callback(m_errorCallbacks.at(i), "PositionError.cast(PositionError.TIMEOUT, 'Position request timed out.')"); } m_errorCallbacks.clear(); m_successCallbacks.clear(); } cordova-ubuntu-2.8.0+14.04.20140130.3/src/plugins/events.cpp0000644000015000001560000001133612272510553023450 0ustar pbuserpbgroup00000000000000/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #include #include #include #include "events.h" #include "../cordova.h" Events::Events(Cordova *cordova) : CPlugin(cordova) { m_previousPercent = 100; m_batteryInfo = new QBatteryInfo(this); connect(m_batteryInfo, SIGNAL(remainingCapacityChanged(int,int)), this, SLOT(remainingCapacityChanged(int,int))); connect(m_batteryInfo, SIGNAL(chargerTypeChanged(QBatteryInfo::ChargerType)), this, SLOT(chargerTypeChanged(QBatteryInfo::ChargerType))); if (m_cordova->topLevelEventsReceiver()) m_cordova->topLevelEventsReceiver()->installEventFilter(this); m_networkConfigurationManager = new QNetworkConfigurationManager(this); connect(m_networkConfigurationManager, SIGNAL(onlineStateChanged(bool)), this, SLOT(onlineStatusChanged(bool))); } bool Events::eventFilter(QObject *obj, QEvent *ev) { if (obj == m_cordova->topLevelEventsReceiver()) { if (ev->type() == QEvent::KeyRelease) { QKeyEvent *keyEvent = dynamic_cast(ev); if (!keyEvent) return false; switch (keyEvent->key()) { case Qt::Key_Menu: m_cordova->execJS(QString("Cordova.menuKeyPressed();")); break; case Qt::Key_Back: m_cordova->execJS(QString("Cordova.backKeyPressed();")); break; case Qt::Key_Search: m_cordova->execJS(QString("Cordova.searchKeyPressed();")); break; case Qt::Key_Call: m_cordova->execJS(QString("Cordova.callKeyPressed();")); break; case Qt::Key_Hangup: m_cordova->execJS(QString("Cordova.hangupKeyPressed();")); break; default: break; } } else if (ev->type() == QEvent::KeyPress) { QKeyEvent *keyEvent = dynamic_cast(ev); if (!keyEvent) return false; switch (keyEvent->key()) { case Qt::Key_VolumeUp: m_cordova->execJS(QString("Cordova.volumeUpKeyPressed();")); break; case Qt::Key_VolumeDown: m_cordova->execJS(QString("Cordova.volumeDownKeyPressed();")); break; default: break; } } else if (ev->type() == QEvent::WindowActivate) { m_cordova->execJS(QString("Cordova.resumeOccured();")); } else if (ev->type() == QEvent::WindowDeactivate) { m_cordova->execJS(QString("Cordova.pauseOccured();")); } } return false; } void Events::remainingCapacityChanged(int battery, int capacity) { int newPercent; if (m_batteryInfo->maximumCapacity(battery) < 1) newPercent = 0; newPercent = capacity/((double)m_batteryInfo->maximumCapacity(battery)/100); if (m_previousPercent == newPercent) return; m_previousPercent = newPercent; bool onBattery = m_batteryInfo->chargerType() == QBatteryInfo::UnknownCharger || m_batteryInfo->chargerType() == QBatteryInfo::VariableCurrentCharger; m_cordova->execJS(QString("Cordova.batteryStatusChanged(%1, %2, false);") .arg(m_previousPercent) .arg(!onBattery)); } void Events::chargerTypeChanged(QBatteryInfo::ChargerType type) { Q_UNUSED(type); qDebug() << Q_FUNC_INFO; bool isPlugged = m_batteryInfo->chargerType() == QBatteryInfo::UnknownCharger || m_batteryInfo->chargerType() == QBatteryInfo::VariableCurrentCharger; m_cordova->execJS(QString("Cordova.batteryStatusChanged(%1, %2, true);") .arg(m_previousPercent) .arg(isPlugged)); } void Events::onlineStatusChanged(bool isOnline) { if (isOnline) m_cordova->execJS(QString("Cordova.onlineOccured();")); else m_cordova->execJS(QString("Cordova.offlineOccured();")); } cordova-ubuntu-2.8.0+14.04.20140130.3/src/plugins/events.h0000644000015000001560000000325012272510553023111 0ustar pbuserpbgroup00000000000000/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #ifndef EVENTS_H #define EVENTS_H #include #include #include "../cplugin.h" class QNetworkConfigurationManager; class Events: public CPlugin { Q_OBJECT public: explicit Events(Cordova *cordova); virtual const QString fullName() override { return Events::fullID(); } virtual const QString shortName() override { return "Events"; } static const QString fullID() { return "com.cordova.Events"; } protected: bool eventFilter(QObject *obj, QEvent *ev); private slots: void remainingCapacityChanged(int battery, int capacity); void chargerTypeChanged(QBatteryInfo::ChargerType type); void onlineStatusChanged(bool isOnline); private: QBatteryInfo *m_batteryInfo; int m_previousPercent; QNetworkConfigurationManager *m_networkConfigurationManager; }; #endif // EVENTS_H cordova-ubuntu-2.8.0+14.04.20140130.3/src/plugins/device.h0000644000015000001560000000216512272510553023050 0ustar pbuserpbgroup00000000000000/* * Copyright 2011 Wolfgang Koller - http://www.gofg.at/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef DEVICE_H_FDSAFAS #define DEVICE_H_FDSAFAS #include #include "../cplugin.h" class Device: public CPlugin { Q_OBJECT public: explicit Device(Cordova *cordova); virtual const QString fullName() override { return Device::fullID(); } virtual const QString shortName() override { return "Device"; } static const QString fullID() { return "com.cordova.Device"; } signals: public slots: void getInfo(int scId, int ecId); }; #endif cordova-ubuntu-2.8.0+14.04.20140130.3/src/plugins/globalization.cpp0000644000015000001560000002370112272510553025001 0ustar pbuserpbgroup00000000000000 #include //TODO: switch to QTimeZone (QT 5.1) #include #include #include "globalization.h" Globalization::Globalization(Cordova *cordova): CPlugin(cordova) { } void Globalization::getPreferredLanguage(int scId, int ecId, QVariantMap p_options) { Q_UNUSED(ecId) Q_UNUSED(p_options) QLocale locale; QString lang = QLocale::languageToString(locale.language()); this->callback(scId, "{ value: '" + lang + "' }"); } void Globalization::isDayLightSavingsTime(int scId, int ecId, QVariantMap p_options) { time_t time = p_options.find("time_t")->toLongLong() / 1000; const tm *desc = std::localtime(&time); if (desc->tm_isdst < 0) { this->callback(ecId, QString("new GlobalizationError(%1, 'information is not available');").arg(Globalization::UNKNOWN_ERROR)); return; } this->callback(scId, QString("{dst:%1}").arg(desc->tm_isdst > 0 ? "true" : "false")); } void Globalization::getFirstDayOfWeek(int scId, int ecId, QVariantMap p_options) { Q_UNUSED(ecId) Q_UNUSED(p_options) QLocale locale; int res; if (locale.firstDayOfWeek() == Qt::Sunday) { res = 1; } else { res = (2 - Qt::Monday) + locale.firstDayOfWeek(); } QVariantMap obj; obj.insert("value", res); this->cb(scId, obj); } QLocale::FormatType translateFormat(Globalization::Format formatLength) { QLocale::FormatType format = QLocale::ShortFormat; switch (formatLength) { case Globalization::FORMAT_FULL: case Globalization::FORMAT_LONG: format = QLocale::ShortFormat; // TODO: Qt cant parse string produced with QLocale::LongFormat; break; case Globalization::FORMAT_MEDIUM: format = QLocale::ShortFormat; break; case Globalization::FORMAT_SHORT: format = QLocale::NarrowFormat; break; } return format; } void Globalization::dateToString(int scId, int ecId, QVariantMap p_options) { time_t time = p_options.find("time_t")->toLongLong() / 1000; Globalization::Format formatLength = static_cast(p_options.find("formatLength")->toInt()); Globalization::Selector selector = static_cast(p_options.find("selector")->toInt()); QLocale::FormatType format = translateFormat(formatLength); if (time < 0) { this->callback(ecId, QString("new GlobalizationError(%1, 'unsupported operation');").arg(Globalization::FORMATTING_ERROR)); return; } QLocale locale; QString res; QDateTime dateTime = QDateTime::fromTime_t((uint)time); switch (selector) { case SELECTOR_ALL: res = locale.toString(dateTime,format); break; case SELECTOR_TIME: res = locale.toString(dateTime.time(), format); break; case SELECTOR_DATE: res = locale.toString(dateTime.date(), format); break; } QVariantMap obj; obj.insert("value", res); this->cb(scId, obj); } void Globalization::stringToDate(int scId, int ecId, QVariantMap p_options) { QString dateString = p_options.find("dateString")->toString(); Globalization::Format formatLength = static_cast(p_options.find("formatLength")->toInt()); Globalization::Selector selector = static_cast(p_options.find("selector")->toInt()); QLocale::FormatType format = translateFormat(formatLength); QLocale locale; bool valid(true); int year(0), month(0), day(0), hour(0), minute(0), second(0), millisecond(0); switch (selector) { case SELECTOR_ALL: { QDateTime dateTime = locale.toDateTime(dateString, format); valid = dateTime.isValid(); QTime time = dateTime.time(); hour = time.hour(); minute = time.minute(); second = time.second(); millisecond = time.msec(); QDate date = dateTime.date(); year = date.year(); month = date.month(); day = date.day(); } break; case SELECTOR_TIME: { QTime time = locale.toTime(dateString, format); valid = time.isValid(); hour = time.hour(); minute = time.minute(); second = time.second(); millisecond = time.msec(); } break; case SELECTOR_DATE: { QDate date = locale.toDate(dateString, format); valid = date.isValid(); year = date.year(); month = date.month(); day = date.day(); } break; } if ((format == QLocale::NarrowFormat || format == QLocale::ShortFormat) && year < 2000 && year > 1900) { year += 100; } if (!valid) { this->callback(ecId, QString("new GlobalizationError(%1, 'parsing error')").arg(Globalization::PARSING_ERROR)); } else { QVariantMap obj; obj.insert("year", year); obj.insert("month", month - 1); obj.insert("day", day); obj.insert("hour", hour); obj.insert("minute", minute); obj.insert("second", second); obj.insert("millisecond", millisecond); this->cb(scId, obj); } } void Globalization::getDateNames(int scId, int ecId, QVariantMap p_options) { Q_UNUSED(ecId) int type = p_options.find("type")->toInt(); int item = p_options.find("item")->toInt(); QLocale::FormatType format; if (type == FORMAT_SHORT) format = QLocale::ShortFormat; else format = QLocale::LongFormat; QLocale locale; QList res; if (item == REQUEST_DAY_NAMES) { for (int i = 1; i <= 7; i++) { res.append(locale.dayName(i, format)); } } else { //REQUEST_MONTH_NAMES for (int i = 1; i <= 12; i++) { res.append(locale.monthName(i, format)); } } QString result; for (QList::iterator it = res.begin(); it != res.end(); it++) { result += QString("'%1',").arg(*it); } this->callback(scId, QString("{ value: [ %1 ]}").arg(result)); } template static QString format(T number, Globalization::NumberType type) { QString res; QLocale locale; switch (type) { case Globalization::DECIMAL: res = locale.toString(number); break; case Globalization::PERCENT: res = locale.toString(number) + locale.percent(); break; case Globalization::CURRENCY: res = locale.toCurrencyString(number); break; }; return res; } void Globalization::numberToString(int scId, int ecId, QVariantMap p_options) { Q_UNUSED(ecId) bool isInt = p_options.find("isInt")->toBool(); NumberType type = static_cast(p_options.find("type")->toBool()); QString res; if (isInt) { long long number = p_options.find("number")->toLongLong(); res = format(number, type); } else { double number = p_options.find("number")->toDouble(); res = format(number, type); } this->callback(scId, QString("{ value: '%1' }").arg(res)); } void Globalization::stringToNumber(int scId, int ecId, int type, QString string) { switch ((NumberType)type) { case Globalization::DECIMAL: string = string.remove(QLocale().groupSeparator()); break; case Globalization::PERCENT: string = string.remove(QLocale().percent()).remove(QLocale().groupSeparator()); break; case Globalization::CURRENCY: string = string.remove(QLocale().currencySymbol()).remove(QLocale().groupSeparator()); break; }; bool ok; double res = QLocale().toDouble(string, &ok); if (ok) this->callback(scId, QString("{ value: %1 }").arg(res)); else this->callback(ecId, QString("new GlobalizationError(%1, 'parsing error')").arg(Globalization::PARSING_ERROR)); } static QString ustr2qstr(UnicodeString &ustr) { std::string res; ustr.toUTF8String(res); return QString(res.c_str()); } void Globalization::getNumberPattern(int scId, int ecId, int type) { Q_UNUSED(ecId); UErrorCode status = U_ZERO_ERROR; icu::DecimalFormat icu(status); icu::UnicodeString pattern; icu.toPattern(pattern); QLocale locale; QVariantMap obj; obj.insert("pattern", ustr2qstr(pattern)); switch ((NumberType)type) { case Globalization::DECIMAL: obj.insert("symbol", ""); break; case Globalization::PERCENT: obj.insert("symbol", QString(locale.percent())); break; case Globalization::CURRENCY: obj.insert("symbol", QString(locale.currencySymbol())); break; }; obj.insert("fraction", icu.getMaximumFractionDigits()); obj.insert("rounding", icu.getRoundingIncrement()); obj.insert("positive", QString(locale.positiveSign())); obj.insert("negative", QString(locale.negativeSign())); obj.insert("decimal", QString(locale.decimalPoint())); obj.insert("grouping", QString(locale.groupSeparator())); this->cb(scId, obj); } static bool inDayLightSavingsTime() { time_t now; time(&now); const tm *desc = std::localtime(&now); return desc->tm_isdst > 0; } void Globalization::getDatePattern(int scId, int ecId, int formatLength, int selector) { Q_UNUSED(ecId); QLocale locale; QVariantMap res; QLocale::FormatType format = translateFormat((Format)formatLength); switch ((Selector)selector) { case Selector::SELECTOR_TIME: res.insert("pattern", locale.timeFormat(format)); break; case Selector::SELECTOR_DATE: res.insert("pattern", locale.dateFormat(format)); break; case Selector::SELECTOR_ALL: res.insert("pattern", locale.dateTimeFormat(format)); break; }; UnicodeString result; QSharedPointer timezone = QSharedPointer(TimeZone::createDefault()); timezone->getDisplayName(inDayLightSavingsTime(), TimeZone::SHORT, result); res.insert("timezone", ustr2qstr(result)); res.insert("utc_offset", timezone->getRawOffset() / 1000 + timezone->getDSTSavings() / 1000); res.insert("dst_offset", timezone->getDSTSavings() / 1000); this->cb(scId, res); } cordova-ubuntu-2.8.0+14.04.20140130.3/src/plugins/compass.h0000644000015000001560000000262412272510553023256 0ustar pbuserpbgroup00000000000000/* * Copyright 2011 Integrated Computer Solutions - http://www.ics.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef COMPASS_H #define COMPASS_H #include "../cplugin.h" #include #include class Compass : public CPlugin { Q_OBJECT public: explicit Compass(Cordova *cordova); virtual const QString fullName() override { return Compass::fullID(); } virtual const QString shortName() override { return "Compass"; } static const QString fullID() { return "com.cordova.Compass"; } public slots: void getCurrentHeading(int scId, int ecId, QVariantMap p_options); protected slots: void updateSensor(); private: QCompass* m_compassSource; QList m_successCallbacks; QList m_errorCallbacks; double m_azymuth; double m_accuracy; qtimestamp m_timestamp; }; #endif // COMPASS_H cordova-ubuntu-2.8.0+14.04.20140130.3/src/plugins/notification.h0000644000015000001560000000276212272510553024302 0ustar pbuserpbgroup00000000000000/* * Copyright 2011 Wolfgang Koller - http://www.gofg.at/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef NOTIFICATION_H #define NOTIFICATION_H #include "../cplugin.h" class Notification : public CPlugin { Q_OBJECT public: explicit Notification(Cordova *cordova); virtual const QString fullName() override { return Notification::fullID(); } virtual const QString shortName() override { return "Notification"; } static const QString fullID() { return "com.cordova.Notification"; } public slots: void beep(int scId, int ecId, int p_times); void vibrate(int scId, int ecId, int p_milliseconds); void confirm(int scId, int ecId, const QString &message, const QString &title, const QStringList &buttonLabels); void prompt(int scId, int ecId, const QString &message, const QString &title, const QStringList &buttonLabels, const QString &defaultText); private slots: void deleteEffectAtStateStopped(); }; #endif cordova-ubuntu-2.8.0+14.04.20140130.3/src/plugins/geolocation.h0000644000015000001560000000272712272510553024120 0ustar pbuserpbgroup00000000000000/* * Copyright 2011 Wolfgang Koller - http://www.gofg.at/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef GEOLOCATION_H #define GEOLOCATION_H #include #include #include #include "../cplugin.h" class Geolocation: public CPlugin { Q_OBJECT public: explicit Geolocation(Cordova *cordova); virtual const QString fullName() override { return Geolocation::fullID(); } virtual const QString shortName() override { return "Geolocation"; } static const QString fullID() { return "com.cordova.Geolocation"; } public slots: void getCurrentPosition(int scId, int ecId, QVariantMap p_options); protected slots: void positionUpdated(const QGeoPositionInfo &update); void updateTimeout(); private: QSharedPointer m_geoPositionInfoSource; QList m_successCallbacks; QList m_errorCallbacks; }; #endif cordova-ubuntu-2.8.0+14.04.20140130.3/src/plugins/capture.h0000644000015000001560000000151312272510553023250 0ustar pbuserpbgroup00000000000000#ifndef CAPTURE_H #define CAPTURE_H #include "../cplugin.h" #include #include class Capture: public CPlugin { Q_OBJECT public: explicit Capture(Cordova *cordova); virtual const QString fullName() override { return Capture::fullID(); } virtual const QString shortName() override { return "Capture"; } static const QString fullID() { return "com.cordova.Capture"; } public slots: void getSupportedFormats(int scId, int ecId); void startAudioRecordApp(int scId, int ecId, QVariantMap p_options); void record(); void cancel(); private slots: void onError(QMediaRecorder::Error); private: QSharedPointer m_recorder; int m_scId, m_ecId; QList m_files; QVariantMap m_options; }; #endif // CAPTURE_H cordova-ubuntu-2.8.0+14.04.20140130.3/src/plugins/cameraresolution.h0000644000015000001560000000237112272510553025164 0ustar pbuserpbgroup00000000000000/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #ifndef CAMERARESOLUTION_H #define CAMERARESOLUTION_H #include class CameraResolution : public QObject { Q_OBJECT Q_PROPERTY(int width READ width CONSTANT) Q_PROPERTY(int height READ height CONSTANT) public: CameraResolution(int width, int height) : m_width(width), m_height(height) {} int width() { return m_width; } int height() { return m_height; } int m_width; int m_height; }; #endif // CAMERARESOLUTION_H cordova-ubuntu-2.8.0+14.04.20140130.3/src/plugins/camera.h0000644000015000001560000000401412272510553023034 0ustar pbuserpbgroup00000000000000/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #ifndef CAMERA_H #define CAMERA_H #include "../cplugin.h" #include #include #include #include #include class Camera : public CPlugin { Q_OBJECT public: explicit Camera(Cordova *cordova); virtual const QString fullName() override { return Camera::fullID(); } virtual const QString shortName() override { return "Camera"; } static const QString fullID() { return "com.cordova.Camera"; } public slots: void getPicture(int scId, int ecId, QVariantMap p_options); void recordVideo(int scId, int ecId, QVariantMap p_options); void onRecordEnd(); void cancel(); private slots: void onImageSaved(int, QString path); private: void setState(const QString &state); void leaveState(const QString &state); bool preprocessImage(QString &path); int m_lastScId; int m_lastEcId; QVariantMap m_options; QSharedPointer m_camera; QString m_result; QString m_state; protected: enum DestinationType { DATA_URL = 0, FILE_URI = 1 }; enum EncodingType { JPEG = 0, PNG = 1 }; }; #endif // CAMERA_H cordova-ubuntu-2.8.0+14.04.20140130.3/src/plugins/inappbrowser.h0000644000015000001560000000123312272510553024317 0ustar pbuserpbgroup00000000000000#ifndef INAPPBROWSER_H #define INAPPBROWSER_H #include #include "../cplugin.h" class InAppBrowser: public CPlugin { Q_OBJECT public: InAppBrowser(Cordova *cordova); virtual const QString fullName() override { return InAppBrowser::fullID(); } virtual const QString shortName() override { return "InAppBrowser"; } static const QString fullID() { return "com.cordova.InAppBrowser"; } public slots: void loadUrl(int loadEndCb, int closeCb, QString url); void close(int, int); void loadFinished(); private: bool open; int m_closeCb, m_loadFinishedCb; }; #endif // INAPPBROWSER_H cordova-ubuntu-2.8.0+14.04.20140130.3/src/plugins/contacts.h0000644000015000001560000000441512272510553023427 0ustar pbuserpbgroup00000000000000/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #ifndef CONTACTS_H #define CONTACTS_H #include "../cplugin.h" #include #include QTCONTACTS_USE_NAMESPACE class Contacts : public CPlugin { Q_OBJECT public: explicit Contacts(Cordova *cordova); virtual const QString fullName() override { return Contacts::fullID(); } virtual const QString shortName() override { return "Contacts"; } static const QString fullID() { return "com.cordova.Contacts"; } public slots: void saveContact(int scId, int ecId, const QVariantMap ¶ms); void removeContact(int scId, int ecId, const QString &localId); void findContacts(int scId, int ecId, const QStringList &fields, const QString &filter, bool multiple); private: QContactDetail::DetailType cordovaFieldNameToQtDefinition(const QString &cordovaFieldName) const; int subTypePhoneFromString(const QString &cordovaSubType) const; int subTypeOnlineAccountFromString(const QString &cordovaSubType) const; int subTypeUrlFromString(const QString &cordovaSubType) const; QString subTypePhoneToString(int qtSubType) const; QString subTypeOnlineAccountToString(int qtSubType) const; QString subTypeUrlToString(int qtSubType) const; QString jsonedContact(const QContact &contact, const QStringList &fields = QStringList()) const; QHash m_fieldNamePairs; QSet m_notSupportedFields; QSharedPointer m_manager; }; #endif cordova-ubuntu-2.8.0+14.04.20140130.3/src/plugins/console.cpp0000644000015000001560000000157112272510553023606 0ustar pbuserpbgroup00000000000000/* * Copyright 2011 Wolfgang Koller - http://www.gofg.at/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "console.h" #include Console::Console(Cordova *cordova) : CPlugin(cordova) { } void Console::log(int scId, int ecId, QString p_message) { Q_UNUSED(scId) Q_UNUSED(ecId) std::cout << p_message.toStdString() << std::endl; } cordova-ubuntu-2.8.0+14.04.20140130.3/src/plugins/console.h0000644000015000001560000000221012272510553023242 0ustar pbuserpbgroup00000000000000/* * Copyright 2011 Wolfgang Koller - http://www.gofg.at/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef CONSOLE_H_FDSVCXGFRS #define CONSOLE_H_FDSVCXGFRS #include "../cplugin.h" #include class Console : public CPlugin { Q_OBJECT public: explicit Console(Cordova *cordova); virtual const QString fullName() override { return Console::fullID(); } virtual const QString shortName() override { return "Console"; } static const QString fullID() { return "com.cordova.Console"; } public slots: void log(int scId, int ecId, QString p_message); }; #endif cordova-ubuntu-2.8.0+14.04.20140130.3/src/plugins/app.h0000644000015000001560000000075512272510553022374 0ustar pbuserpbgroup00000000000000#ifndef APP_H #define APP_H #include #include "../cplugin.h" class App: public CPlugin { Q_OBJECT public: explicit App(Cordova *cordova); virtual const QString fullName() override { return App::fullID(); } virtual const QString shortName() override { return "App"; } static const QString fullID() { return "com.cordova.App"; } public slots: void exitApp(int, int); void loadUrl(int, int, QString url); }; #endif cordova-ubuntu-2.8.0+14.04.20140130.3/src/plugins/contacts.cpp0000644000015000001560000006255612272510553023774 0ustar pbuserpbgroup00000000000000/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #include "contacts.h" #if defined QTCONTACTS_USE_NAMESPACE QTCONTACTS_USE_NAMESPACE #endif Contacts::Contacts(Cordova *cordova): CPlugin(cordova) { m_fieldNamePairs.clear(); m_fieldNamePairs["displayName"] = QContactDetail::TypeDisplayLabel; m_fieldNamePairs["name"] = QContactDetail::TypeName; m_fieldNamePairs["nickname"] = QContactDetail::TypeNickname; m_fieldNamePairs["phoneNumbers"] = QContactDetail::TypePhoneNumber; m_fieldNamePairs["emails"] = QContactDetail::TypeEmailAddress; m_fieldNamePairs["addresses"] = QContactDetail::TypeAddress; m_fieldNamePairs["ims"] = QContactDetail::TypeOnlineAccount; m_fieldNamePairs["organizations"] = QContactDetail::TypeOrganization; m_fieldNamePairs["birthday"] = QContactDetail::TypeBirthday; m_fieldNamePairs["note"] = QContactDetail::TypeNote; m_fieldNamePairs["photos"] = QContactDetail::TypeAvatar; m_fieldNamePairs["urls"] = QContactDetail::TypeUrl; m_notSupportedFields.clear(); m_notSupportedFields << "categories"; m_manager.clear(); m_manager = QSharedPointer(new QContactManager()); } void Contacts::saveContact(int scId, int ecId, const QVariantMap ¶ms) { QContact result; QList detailsToDelete; if (params.find("id") != params.end()) { QString id = params.find("id")->toString(); if (!id.isEmpty()) { result = m_manager->contact(QContactId::fromString(id)); result.clearDetails(); } } foreach (QString field, params.keys()) { QContactDetail::DetailType qtDefinition = cordovaFieldNameToQtDefinition(field); if (qtDefinition == QContactDetail::TypeUndefined) continue; if (field == "nickname") { QContactNickname *detail = new QContactNickname; detail->setNickname(params[field].toString()); detailsToDelete << detail; result.saveDetail(detail); } else if (field == "note") { QContactNote *detail = new QContactNote; detail->setNote(params[field].toString()); detailsToDelete << detail; result.saveDetail(detail); } else if (field == "phoneNumbers") { if (params[field].type() != QVariant::List) continue; QVariantList phonesList = params[field].toList(); foreach (const QVariant &phoneDesc, phonesList) { if (phoneDesc.type() != QVariant::Map) continue; QContactPhoneNumber *detail = new QContactPhoneNumber; detail->setNumber(phoneDesc.toMap()["value"].toString()); if (!phoneDesc.toMap()["type"].toString().isEmpty() && phoneDesc.toMap()["type"].toString() != "phone") detail->setSubTypes(QList() << subTypePhoneFromString(phoneDesc.toMap()["type"].toString())); detailsToDelete << detail; result.saveDetail(detail); } } else if (field == "emails") { if (params[field].type() != QVariant::List) continue; QVariantList emailsList = params[field].toList(); foreach (const QVariant &emailDesc, emailsList) { if (emailDesc.type() != QVariant::Map) continue; if (emailDesc.toMap()["value"].toString().isEmpty()) continue; QContactEmailAddress *detail = new QContactEmailAddress; detail->setEmailAddress(emailDesc.toMap()["value"].toString()); detailsToDelete << detail; result.saveDetail(detail); } } else if (field == "ims") { if (params[field].type() != QVariant::List) continue; QVariantList imsList = params[field].toList(); foreach (const QVariant &imDesc, imsList) { if (imDesc.type() != QVariant::Map) continue; QContactOnlineAccount *detail = new QContactOnlineAccount; detail->setAccountUri(imDesc.toMap()["value"].toString()); if (!imDesc.toMap()["type"].toString().isEmpty()) detail->setSubTypes(QList() << subTypeOnlineAccountFromString(imDesc.toMap()["type"].toString())); detailsToDelete << detail; result.saveDetail(detail); } } else if (field == "photos") { if (params[field].type() != QVariant::List) continue; QVariantList photosList = params[field].toList(); foreach (const QVariant &photoDesc, photosList) { if (photoDesc.type() != QVariant::Map) continue; //TODO: we need to decide should we support base64 images or not if (photoDesc.toMap()["type"].toString() != "url") continue; QContactAvatar *detail = new QContactAvatar; detail->setImageUrl(QUrl(photoDesc.toMap()["value"].toString())); detailsToDelete << detail; result.saveDetail(detail); } } else if (field == "urls") { if (params[field].type() != QVariant::List) continue; QVariantList urlsList = params[field].toList(); foreach (const QVariant &urlDesc, urlsList) { if (urlDesc.type() != QVariant::Map) continue; QContactUrl *detail = new QContactUrl; detail->setUrl(urlDesc.toMap()["value"].toString()); if (!urlDesc.toMap()["type"].toString().isEmpty()) detail->setSubType((QContactUrl::SubType) subTypeUrlFromString(urlDesc.toMap()["type"].toString())); detailsToDelete << detail; result.saveDetail(detail); } } else if (field == "birthday") { QDateTime birthday; birthday.setTime_t(params[field].toLongLong() / 1000); QContactBirthday *detail = new QContactBirthday; detail->setDateTime(birthday); detailsToDelete << detail; result.saveDetail(detail); } else if (field == "organizations") { if (params[field].type() != QVariant::List) continue; QVariantList organizationsList = params[field].toList(); foreach (const QVariant &organizationDesc, organizationsList) { if (organizationDesc.type() != QVariant::Map) continue; QContactOrganization *detail = new QContactOrganization; detail->setName(organizationDesc.toMap()["name"].toString()); detail->setDepartment(QStringList() << organizationDesc.toMap()["department"].toString()); detail->setRole(organizationDesc.toMap()["title"].toString()); detailsToDelete << detail; result.saveDetail(detail); } } else if (field == "name") { QContactName *detail = new QContactName; QVariantMap nameMap = params[field].toMap(); detail->setLastName(nameMap["familyName"].toString()); detail->setFirstName(nameMap["givenName"].toString()); detail->setMiddleName(nameMap["middleName"].toString()); detail->setPrefix(nameMap["honorificPrefix"].toString()); detail->setSuffix(nameMap["honorificSuffix"].toString()); detailsToDelete << detail; result.saveDetail(detail); } } if (!m_manager->saveContact(&result)) { switch (m_manager->error()) { case QContactManager::DoesNotExistError: case QContactManager::AlreadyExistsError: case QContactManager::InvalidDetailError: case QContactManager::InvalidRelationshipError: case QContactManager::BadArgumentError: case QContactManager::InvalidContactTypeError: callback(ecId, "new ContactError(ContactError.INVALID_ARGUMENT_ERROR)"); break; case QContactManager::DetailAccessError: case QContactManager::PermissionsError: callback(ecId, "new ContactError(ContactError.PERMISSION_DENIED_ERROR)"); break; case QContactManager::NotSupportedError: callback(ecId, "new ContactError(ContactError.NOT_SUPPORTED_ERROR)"); break; case QContactManager::TimeoutError: callback(ecId, "new ContactError(ContactError.TIMEOUT_ERROR)"); break; case QContactManager::UnspecifiedError: case QContactManager::LockedError: case QContactManager::OutOfMemoryError: case QContactManager::VersionMismatchError: case QContactManager::LimitReachedError: case QContactManager::NoError: default: callback(ecId, "new ContactError(ContactError.UNKNOWN_ERROR)"); break; } } else { callback(scId, jsonedContact(result)); } qDeleteAll(detailsToDelete); } void Contacts::removeContact(int scId, int ecId, const QString &localId) { QContactId id = QContactId::fromString(localId); if (!m_manager->removeContact(id)) { switch (m_manager->error()) { case QContactManager::AlreadyExistsError: case QContactManager::InvalidDetailError: case QContactManager::InvalidRelationshipError: case QContactManager::BadArgumentError: case QContactManager::InvalidContactTypeError: callback(ecId, "new ContactError(ContactError.INVALID_ARGUMENT_ERROR)"); break; case QContactManager::DetailAccessError: case QContactManager::PermissionsError: callback(ecId, "new ContactError(ContactError.PERMISSION_DENIED_ERROR)"); break; case QContactManager::NotSupportedError: callback(ecId, "new ContactError(ContactError.NOT_SUPPORTED_ERROR)"); break; case QContactManager::TimeoutError: callback(ecId, "new ContactError(ContactError.TIMEOUT_ERROR)"); break; case QContactManager::UnspecifiedError: case QContactManager::LockedError: case QContactManager::OutOfMemoryError: case QContactManager::VersionMismatchError: case QContactManager::LimitReachedError: case QContactManager::NoError: case QContactManager::DoesNotExistError: default: callback(ecId, "new ContactError(ContactError.UNKNOWN_ERROR)"); break; } } else { cb(scId); } } void Contacts::findContacts(int scId, int ecId, const QStringList &fields, const QString &filter, bool multiple) { if (fields.length() <= 0){ callback(ecId, "new ContactError(ContactError.INVALID_ARGUMENT_ERROR)"); } QContactUnionFilter unionFilter; QMap > fieldNames; fieldNames[QContactDetail::TypeDisplayLabel] << QContactDisplayLabel::FieldLabel; fieldNames[QContactDetail::TypeName] << QContactName::FieldFirstName << QContactName::FieldLastName << QContactName::FieldMiddleName << QContactName::FieldPrefix << QContactName::FieldSuffix; fieldNames[QContactDetail::TypeNickname] << QContactNickname::FieldNickname; fieldNames[QContactDetail::TypePhoneNumber] << QContactPhoneNumber::FieldNumber; fieldNames[QContactDetail::TypeEmailAddress] << QContactEmailAddress::FieldEmailAddress; fieldNames[QContactDetail::TypeAddress] << QContactAddress::FieldCountry << QContactAddress::FieldLocality << QContactAddress::FieldPostcode << QContactAddress::FieldPostOfficeBox << QContactAddress::FieldRegion << QContactAddress::FieldStreet; fieldNames[QContactDetail::TypeOnlineAccount] << QContactOnlineAccount::FieldAccountUri; fieldNames[QContactDetail::TypeOrganization] << QContactOrganization::FieldAssistantName << QContactOrganization::FieldDepartment << QContactOrganization::FieldLocation << QContactOrganization::FieldName << QContactOrganization::FieldRole << QContactOrganization::FieldTitle; fieldNames[QContactDetail::TypeBirthday] << QContactBirthday::FieldBirthday; fieldNames[QContactDetail::TypeNote] << QContactNote::FieldNote; fieldNames[QContactDetail::TypeUrl] << QContactUrl::FieldUrl; foreach (const QContactDetail::DetailType &defName, fieldNames.keys()) { foreach(int fieldName, fieldNames[defName]) { QContactDetailFilter subFilter; subFilter.setDetailType(defName, fieldName); subFilter.setValue(filter); subFilter.setMatchFlags(QContactFilter::MatchContains); unionFilter.append(subFilter); } } QList contacts = m_manager->contacts(unionFilter); if (contacts.empty()) { callback(scId, "[]"); } else { QStringList stringifiedContacts; qDebug() << "stringifiedContacts:\n"; foreach (const QContact &contact, contacts) { stringifiedContacts << jsonedContact(contact, fields); qDebug() << jsonedContact(contact, fields) << "\n"; if (!multiple) break; } callback(scId, QString("[%1]").arg(stringifiedContacts.join(", "))); } } QContactDetail::DetailType Contacts::cordovaFieldNameToQtDefinition(const QString &cordovaFieldName) const { if (m_fieldNamePairs.contains(cordovaFieldName)) return m_fieldNamePairs[cordovaFieldName]; return QContactDetail::TypeUndefined; } int Contacts::subTypePhoneFromString(const QString &cordovaSubType) const { QString preparedSubType = cordovaSubType.toLower(); if (preparedSubType == "mobile") return QContactPhoneNumber::SubTypeMobile; else if (preparedSubType == "fax") return QContactPhoneNumber::SubTypeFax; else if (preparedSubType == "pager") return QContactPhoneNumber::SubTypePager; else if (preparedSubType == "voice") return QContactPhoneNumber::SubTypeVoice; else if (preparedSubType == "modem") return QContactPhoneNumber::SubTypeModem; else if (preparedSubType == "video") return QContactPhoneNumber::SubTypeVideo; else if (preparedSubType == "car") return QContactPhoneNumber::SubTypeCar; else if (preparedSubType == "assistant") return QContactPhoneNumber::SubTypeAssistant; return QContactPhoneNumber::SubTypeLandline; } int Contacts::subTypeOnlineAccountFromString(const QString &cordovaSubType) const { QString preparedSubType = cordovaSubType.toLower(); if (preparedSubType == "aim") return QContactOnlineAccount::ProtocolAim; else if (preparedSubType == "icq") return QContactOnlineAccount::ProtocolIcq; else if (preparedSubType == "irc") return QContactOnlineAccount::ProtocolIrc; else if (preparedSubType == "jabber") return QContactOnlineAccount::ProtocolJabber; else if (preparedSubType == "msn") return QContactOnlineAccount::ProtocolMsn; else if (preparedSubType == "qq") return QContactOnlineAccount::ProtocolQq; else if (preparedSubType == "skype") return QContactOnlineAccount::ProtocolSkype; else if (preparedSubType == "yahoo") return QContactOnlineAccount::ProtocolYahoo; return QContactOnlineAccount::ProtocolUnknown; } int Contacts::subTypeUrlFromString(const QString &cordovaSubType) const { QString preparedSubType = cordovaSubType.toLower(); if (preparedSubType == "blog") return QContactUrl::SubTypeBlog; else if (preparedSubType == "favourite") return QContactUrl::SubTypeFavourite; return QContactUrl::SubTypeHomePage; } QString Contacts::subTypePhoneToString(int qtSubType) const { if (qtSubType == QContactPhoneNumber::SubTypeMobile) return "mobile"; else if (qtSubType == QContactPhoneNumber::SubTypeFax) return "fax"; else if (qtSubType == QContactPhoneNumber::SubTypePager) return "pager"; else if (qtSubType == QContactPhoneNumber::SubTypeVoice) return "voice"; else if (qtSubType == QContactPhoneNumber::SubTypeModem) return "modem"; else if (qtSubType == QContactPhoneNumber::SubTypeVideo) return "video"; else if (qtSubType == QContactPhoneNumber::SubTypeCar) return "car"; else if (qtSubType == QContactPhoneNumber::SubTypeAssistant) return "assistant"; return "home"; } QString Contacts::subTypeOnlineAccountToString(int qtSubType) const { if (qtSubType == QContactOnlineAccount::ProtocolAim) return "aim"; else if (qtSubType == QContactOnlineAccount::ProtocolIcq) return "icq"; else if (qtSubType == QContactOnlineAccount::ProtocolIrc) return "irc"; else if (qtSubType == QContactOnlineAccount::ProtocolJabber) return "jabber"; else if (qtSubType == QContactOnlineAccount::ProtocolMsn) return "msn"; else if (qtSubType == QContactOnlineAccount::ProtocolQq) return "qq"; else if (qtSubType == QContactOnlineAccount::ProtocolSkype) return "skype"; else if (qtSubType == QContactOnlineAccount::ProtocolYahoo) return "yahoo"; return "unknown"; } QString Contacts::subTypeUrlToString(int qtSubType) const { if (qtSubType == QContactUrl::SubTypeBlog) return "blog"; else if (qtSubType == QContactUrl::SubTypeFavourite) return "favourite"; return "homepage"; } QString Contacts::jsonedContact(const QContact &contact, const QStringList &fields) const { QStringList resultingFields = fields; if (resultingFields.empty()) resultingFields.append(m_fieldNamePairs.keys()); if (!resultingFields.contains("id")) resultingFields << "id"; QStringList fieldValuesList; foreach (const QString &field, resultingFields) { QContactDetail::DetailType qtDefinitionName = cordovaFieldNameToQtDefinition(field); if (field == "id") { fieldValuesList << QString("%1: \"%2\"") .arg(field) .arg(contact.id().toString()); } else if (field == "displayName") { QContactDisplayLabel detail = contact.detail(qtDefinitionName); fieldValuesList << QString("%1: \"%2\"") .arg(field) .arg(detail.label()); } else if (field == "nickname") { QContactNickname detail = contact.detail(qtDefinitionName); fieldValuesList << QString("%1: \"%2\"") .arg(field) .arg(detail.nickname()); } else if (field == "note") { QContactNote detail = contact.detail(qtDefinitionName); fieldValuesList << QString("%1: \"%2\"") .arg(field) .arg(detail.note()); } else if (field == "phoneNumbers") { QStringList fieldValues; QList details = contact.details(qtDefinitionName); foreach (const QContactDetail &detail, details) { QContactPhoneNumber castedDetail = detail; QStringList subTypes; foreach (int subType, castedDetail.subTypes()) subTypes << subTypePhoneToString(subType); if (subTypes.isEmpty()) subTypes << "phone"; foreach(const QString &subType, subTypes) { fieldValues << QString("{type: \"%1\", value: \"%2\", pref: %3}") .arg(subType) .arg(castedDetail.number()) .arg("false"); } } fieldValuesList << QString("%1: [%2]") .arg(field) .arg(fieldValues.join(", ")); } else if (field == "emails") { QStringList fieldValues; QList details = contact.details(qtDefinitionName); foreach (const QContactDetail &detail, details) { QContactEmailAddress castedDetail = detail; fieldValues << QString("{type: \"%1\", value: \"%2\", pref: %3}") .arg("email") .arg(castedDetail.emailAddress()) .arg("false"); } fieldValuesList << QString("%1: [%2]") .arg(field) .arg(fieldValues.join(", ")); } else if (field == "ims") { QStringList fieldValues; QList details = contact.details(qtDefinitionName); foreach (const QContactDetail &detail, details) { QContactOnlineAccount castedDetail = detail; QStringList subTypes; foreach (int subType, castedDetail.subTypes()) subTypes << subTypeOnlineAccountToString(subType); if (subTypes.isEmpty()) subTypes << "IM"; foreach(const QString &subType, subTypes) { fieldValues << QString("{type: \"%1\", value: \"%2\", pref: %3}") .arg(subType) .arg(castedDetail.accountUri()) .arg("false"); } } fieldValuesList << QString("%1: [%2]") .arg(field) .arg(fieldValues.join(", ")); } else if (field == "photos") { QStringList fieldValues; QList details = contact.details(qtDefinitionName); foreach (const QContactDetail &detail, details) { QContactAvatar castedDetail = detail; fieldValues << QString("{type: \"%1\", value: \"%2\", pref: %3}") .arg("url") .arg(castedDetail.imageUrl().toString()) .arg("false"); } fieldValuesList << QString("%1: [%2]") .arg(field) .arg(fieldValues.join(", ")); } else if (field == "urls") { QStringList fieldValues; QList details = contact.details(qtDefinitionName); foreach (const QContactDetail &detail, details) { QContactUrl castedDetail = detail; QString subType = subTypeUrlToString(castedDetail.subType()); fieldValues << QString("{type: \"%1\", value: \"%2\", pref: %3}") .arg(subType) .arg(castedDetail.url()) .arg("false"); } fieldValuesList << QString("%1: [%2]") .arg(field) .arg(fieldValues.join(", ")); } else if (field == "birthday") { QContactBirthday detail = contact.detail(qtDefinitionName); fieldValuesList << QString("%1: new Date(%2)") .arg(field) .arg(detail.dateTime().toMSecsSinceEpoch()); } else if (field == "organizations") { QStringList fieldValues; QList details = contact.details(qtDefinitionName); foreach (const QContactDetail &detail, details) { QContactOrganization castedDetail = detail; fieldValues << QString("{type: \"%1\", name: \"%2\", department: \"%3\", title: \"%4\", pref: %5}") .arg("organization") .arg(castedDetail.name()) .arg(castedDetail.department().join(" ")) .arg(castedDetail.role()) .arg("false"); } fieldValuesList << QString("%1: [%2]") .arg(field) .arg(fieldValues.join(", ")); } else if (field == "name") { QContactName detail = contact.detail(qtDefinitionName); fieldValuesList << QString("%1: {familyName: \"%2\", givenName: \"%3\", middleName: \"%4\", honorificPrefix: \"%5\", honorificSuffix: \"%6\"}") .arg(field) .arg(detail.lastName()) .arg(detail.firstName()) .arg(detail.middleName()) .arg(detail.prefix()) .arg(detail.suffix()); } } QString result = QString("Contact.create({%1})").arg(fieldValuesList.join(", ")); return result; } cordova-ubuntu-2.8.0+14.04.20140130.3/src/plugins/accelerometer.cpp0000644000015000001560000000360212272510553024753 0ustar pbuserpbgroup00000000000000/* * Copyright 2012 Integrated Computer Solutions - http://www.ics.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "accelerometer.h" Accelerometer::Accelerometer(Cordova *cordova): CPlugin(cordova) { m_accelerometerSource = QSharedPointer(new QAccelerometer()); m_sensorAvaliable = m_accelerometerSource->start(); connect(m_accelerometerSource.data(),SIGNAL(readingChanged()), SLOT(updateSensor())); } void Accelerometer::getCurrentAcceleration(int scId, int ecId, QVariantMap p_options) { Q_UNUSED(ecId); Q_UNUSED(p_options); if (!m_sensorAvaliable) { this->cb(ecId); return; } m_successCallbacks << scId; } void Accelerometer::updateSensor() { QAccelerometerReading *accelerometer = m_accelerometerSource->reading(); QVariantMap obj; obj.insert("x", accelerometer->x()); obj.insert("y", accelerometer->y()); obj.insert("z", accelerometer->z()); obj.insert("timestamp", QDateTime::currentDateTime().toMSecsSinceEpoch()); // accelerometer->timestamp() is not sutiable. // Timestamps values are microseconds since _a_ fixed point(depend on backend). QString callbackArguments = QString("Acceleration.cast(%1)").arg(CordovaInternal::format(obj)); for (int scId: m_successCallbacks) { this->callback(scId, callbackArguments); } m_successCallbacks.clear(); } cordova-ubuntu-2.8.0+14.04.20140130.3/src/plugins/accelerometer.h0000644000015000001560000000261112272510553024417 0ustar pbuserpbgroup00000000000000/* * Copyright 2012 Integrated Computer Solutions - http://www.ics.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ACCELEROMETER_H #define ACCELEROMETER_H #include "../cplugin.h" #include #include class Accelerometer : public CPlugin { Q_OBJECT public: explicit Accelerometer(Cordova *cordova); virtual const QString fullName() override { return Accelerometer::fullID(); } virtual const QString shortName() override { return "Accelerometer"; } static const QString fullID() { return "com.cordova.Accelerometer"; } public slots: void getCurrentAcceleration(int scId, int ecId, QVariantMap p_options); protected slots: void updateSensor(); private: QSharedPointer m_accelerometerSource; bool m_sensorAvaliable; QList m_successCallbacks; }; #endif cordova-ubuntu-2.8.0+14.04.20140130.3/src/plugins/camera.cpp0000644000015000001560000001352312272510553023374 0ustar pbuserpbgroup00000000000000/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #include "cameraresolution.h" #include "camera.h" #include "../cordova.h" #include #include #include #include #include #include #include #include #define CAMERA_STATE_NAME "camera" #define RECORDVIDEO_STATE_NAME "recordVideo" Camera::Camera(Cordova *cordova): CPlugin(cordova), m_lastScId(0), m_lastEcId(0) { } bool Camera::preprocessImage(QString &path) { bool convertToPNG = (*m_options.find("encodingType")).toInt() == Camera::PNG; int quality = (*m_options.find("quality")).toInt(); int width = (*m_options.find("targetWidth")).toInt(); int height = (*m_options.find("targetHeight")).toInt(); QImage image(path); if (width && height) image = image.scaled(width, height, Qt::KeepAspectRatio, Qt::SmoothTransformation); QFile oldImage(path); QTemporaryFile newImage; const char *type; if (convertToPNG) { newImage.setFileTemplate("imgXXXXXX.png"); type = "png"; } else { newImage.setFileTemplate("imgXXXXXX.jpg"); type = "jpg"; } newImage.open(); newImage.setAutoRemove(false); image.save(newImage.fileName(), type, quality); path = newImage.fileName(); oldImage.remove(); return true; } void Camera::cancel() { bool captureAPI = m_options.find("captureAPI")->toBool(); leaveState(m_state); if (captureAPI && !m_result.isEmpty()) { this->callback(m_lastScId, QString("[%1]").arg(m_result)); } else { this->cb(m_lastEcId, "canceled"); } m_result = ""; m_lastEcId = m_lastScId = 0; } void Camera::onImageSaved(int, QString path) { bool captureAPI = m_options.find("captureAPI")->toBool(); bool dataURL = m_options.find("destinationType")->toInt() == Camera::DATA_URL; int limit = m_options.find("limit")->toInt(); QString cbParams; if (preprocessImage(path)) { QString absolutePath = QFileInfo(path).absoluteFilePath(); if (dataURL) { QFile image(absolutePath); image.open(QIODevice::ReadOnly); QByteArray content = image.readAll().toBase64(); cbParams = QString("\"%1\"").arg(content.data()); image.remove(); } else { cbParams = QString("\"%1\"").arg(QUrl::fromLocalFile(absolutePath).toString()); } } if (!captureAPI) { leaveState(CAMERA_STATE_NAME); this->callback(m_lastScId, cbParams); } else { if (!m_result.isEmpty()) m_result += ", "; m_result += cbParams; if (limit <= 1) { leaveState(CAMERA_STATE_NAME); this->callback(m_lastScId, QString("[%1]").arg(m_result)); m_result = ""; } } QObject *object = m_cordova->rootObject()->findChild(CAMERA_STATE_NAME); QObject *imageCapture = object->property("imageCapture").value(); QObject::disconnect(imageCapture, SIGNAL(imageSaved(int, const QString)), this, SLOT(onImageSaved(int, const QString))); if (--limit > 0) { m_options.insert("limit", limit); getPicture(m_lastScId, m_lastEcId, m_options); } else { m_lastEcId = m_lastScId = 0; } } void Camera::getPicture(int scId, int ecId, QVariantMap p_options) { if (m_camera.isNull()) { m_camera = QSharedPointer(new QCamera()); } if (((m_lastScId || m_lastEcId) && (m_lastScId != scId && m_lastEcId != ecId)) || !m_camera->isAvailable() || m_camera->lockStatus() != QCamera::Unlocked) { this->cb(m_lastEcId, "Device is busy"); return; } m_options = p_options; m_lastScId = scId; m_lastEcId = ecId; if (m_state != CAMERA_STATE_NAME) setState(CAMERA_STATE_NAME); QObject *object = m_cordova->rootObject()->findChild("camera"); QObject *imageCapture = object->property("imageCapture").value(); QObject::connect(imageCapture, SIGNAL(imageSaved(int, const QString)), this, SLOT(onImageSaved(int, QString))); } void Camera::recordVideo(int scId, int ecId, QVariantMap p_options) { if (m_camera.isNull()) { m_camera = QSharedPointer(new QCamera()); } if (((m_lastScId || m_lastEcId) && (m_lastScId != scId && m_lastEcId != ecId)) || !m_camera->isAvailable() || m_camera->lockStatus() != QCamera::Unlocked) { this->cb(m_lastEcId, "Device is busy"); return; } m_options = p_options; m_lastScId = scId; m_lastEcId = ecId; setState(RECORDVIDEO_STATE_NAME); } void Camera::onRecordEnd() { leaveState(RECORDVIDEO_STATE_NAME); // QObject *object = view->rootObject()->findChild("camera"); // QObject *videoRecording = object->property("videoRecording").value(); } void Camera::setState(const QString &state) { Q_ASSERT(m_state==""); m_state = state; m_cordova->pushViewState(m_state); } void Camera::leaveState(const QString &state) { Q_ASSERT(state == m_state); m_cordova->popViewState(m_state); m_state = ""; } cordova-ubuntu-2.8.0+14.04.20140130.3/src/plugins/device.cpp0000644000015000001560000000357612272510553023412 0ustar pbuserpbgroup00000000000000/* * Copyright 2011 Wolfgang Koller - http://www.gofg.at/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include"device.h" #define CORDOVA "2.3.0" Device::Device(Cordova *cordova) : CPlugin(cordova) { } static QString getOSName() { #ifdef Q_OS_SYMBIAN QString platform = "Symbian"; #endif #ifdef Q_OS_WIN QString platform = "Windows"; #endif #ifdef Q_OS_WINCE QString platform = "Windows CE"; #endif #ifdef Q_OS_LINUX QString platform = "Linux"; #endif return platform; } void Device::getInfo(int scId, int ecId) { Q_UNUSED(ecId) QDeviceInfo systemDeviceInfo; QDeviceInfo systemInfo; QString platform = getOSName(); QString uuid = systemDeviceInfo.uniqueDeviceID(); if (uuid.isEmpty()) { QString deviceDescription = systemInfo.imei(0) + ";" + systemInfo.manufacturer() + ";" + systemInfo.model() + ";" + systemInfo.productName() + ";" + platform; QString user = qgetenv("USER"); if (user.isEmpty()) { user = qgetenv("USERNAME"); if (user.isEmpty()) user = QDir::homePath(); } uuid = QString(QCryptographicHash::hash((deviceDescription + ";" + user).toUtf8(), QCryptographicHash::Md5).toHex()); } this->cb(scId, systemDeviceInfo.model(), CORDOVA, platform, uuid, systemInfo.version(QDeviceInfo::Os)); } cordova-ubuntu-2.8.0+14.04.20140130.3/src/plugins/fileapi.cpp0000644000015000001560000007251712272510553023565 0ustar pbuserpbgroup00000000000000/* * Copyright 2011 Wolfgang Koller - http://www.gofg.at/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "fileapi.h" #include #include #include #include //use static method create initialized map for hardcoded mimetype FileAPI::MimeTypeMap FileAPI::mimeMap_(FileAPI::createMimeTypeMap()); FileAPI::FileAPI(Cordova *cordova) : CPlugin(cordova), m_persistentDir(QDir::homePath() + "/.local/share/cordova-ubuntu/persistent/" + QString(cordova->get_app_dir().toUtf8().toBase64())), lastRequestId(1) { } FileAPI::MimeTypeMap FileAPI::createMimeTypeMap() { MimeTypeMap map; map.insert(QString("txt"),QString("text/plain")); map.insert(QString("css"),QString("text/css")); map.insert(QString("js"),QString("text/javascript")); map.insert(QString("xml"),QString("text/xml")); map.insert(QString("html"),QString("text/html")); return map; } void FileAPI::requestFileSystem(int scId, int ecId, unsigned short p_type, unsigned long long p_size) { QDir dir; //FIXEME,what is quota value if (p_size >= 10000){ this->callback(ecId, "FileException.cast(FileException.QUOTA_EXCEEDED_ERR)"); } // Get correct system path if (p_type == 0) { dir = QDir::temp(); } else { dir = QDir(m_persistentDir); QDir::root().mkpath(dir.absolutePath()); } if (p_type == 0) { this->callback(scId, "FileSystem.cast('temporary', '" + dir.dirName() + "', '" + dir.absolutePath() + "')"); } else if (p_type == 1){ this->callback(scId, "FileSystem.cast('persistent', '" + dir.dirName() + "', '" + dir.absolutePath() + "')"); } else { this->callback(ecId, "FileException.cast(FileException.SYNTAX_ERR)"); } } void FileAPI::resolveLocalFileSystemURL(int scId, int ecId, QString p_url) { QUrl url = QUrl::fromUserInput(p_url); // Check if we have a valid URL if (!url.isValid() || p_url[0] == '/' || p_url[0] == '.') { this->callback(ecId, "FileException.cast(FileException.ENCODING_ERR)"); return; }//FIXEME: invalid pass // Check for the correct scheme if (url.scheme() != "file") { this->callback(ecId, "FileException.cast(FileException.TYPE_MISMATCH_ERR)"); return; } // Now get info about the path QFileInfo fileInfo(url.path()); // Check if entry exists if (!fileInfo.exists()) { this->callback(ecId, "FileException.cast(FileException.NOT_FOUND_ERR)"); return; } if (fileInfo.isDir()) { this->callback(scId, "DirectoryEntry.cast('" + fileInfo.fileName() + "', '" + QDir::cleanPath(fileInfo.absoluteFilePath()) + "')"); return; } else { this->callback(scId, "FileEntry.cast('" + fileInfo.fileName() + "', '" + fileInfo.absoluteFilePath() + "')"); return; } } void FileAPI::getFile(int scId, int ecId, QString p_path, QVariantMap p_options) { // qDebug() << Q_FUNC_INFO << QString(p_path); //NOTE: colon is not safe in url, it is not a valid path in Win and Mac, simple disable it here. if (p_path.contains(":")){ this->callback(ecId, "FileException.cast(FileException.ENCODING_ERR)"); return; } // Check if we have a valid URL QUrl url = QUrl::fromUserInput(p_path); if (!url.isValid()) { this->callback(ecId, "FileException.cast(FileException.ENCODING_ERR)"); return; } // Check for the correct scheme if (url.scheme() != "file") { this->callback(ecId, "FileException.cast(FileException.TYPE_MISMATCH_ERR)"); return; } bool create = p_options.value("create").toBool(); bool exclusive = p_options.value("exclusive").toBool(); QFile file(p_path); QFileInfo pathInfo(p_path); QString fileName(pathInfo.fileName()); // if create is false and the path represents a directory, return error // if file does exist, and create is true and exclusive is true, return error // if file does not exist and create is false, return error // if file does not exist and create is true, create file and return File entry QFileInfo fileInfo(url.path()); if ((!create) && fileInfo.isDir()) { this->callback(ecId, "FileException.cast(FileException.TYPE_MISMATCH_ERR)"); return; } if (file.exists()) { if (create && exclusive) { this->callback(ecId, "FileException.cast(FileException.PATH_EXISTS_ERR)"); return; } } else { if (!create) { this->callback(ecId, "FileException.cast(FileException.NOT_FOUND_ERR)"); return; } // Create the file file.open(QIODevice::WriteOnly); file.close(); // Check if creation was successfull if (!file.exists()) { this->callback(ecId, "FileException.cast(FileException.NO_MODIFICATION_ALLOWED_ERR)"); return; } } // If we reach here, everything went well this->callback(scId, "FileEntry.cast('" + fileName + "', '" + QFileInfo(file).absoluteFilePath() + "')"); } void FileAPI::getDirectory(int scId, int ecId, QString p_path, QVariantMap p_options) { //NOTE: colon is not safe in url, it is not a valid path in Win and Mac, simple disable it here. if (p_path.contains(":")){ this->callback(ecId, "FileException.cast(FileException.ENCODING_ERR)"); } // Check if we have a valid URL QUrl url = QUrl::fromUserInput(p_path); if (!url.isValid()) { this->callback(ecId, "FileException.cast(FileException.ENCODING_ERR)"); return; } // Check for the correct scheme if (url.scheme() != "file") { this->callback(ecId, "FileException.cast(File:Exception.TYPE_MISMATCH_ERR)"); return; } bool create = p_options.value("create").toBool(); bool exclusive = p_options.value("exclusive").toBool(); QDir dir(p_path); // if create is false and the path represents a file, return error // if directory does exist and create is true and exclusive is true, return error // if directory does not exist and create is false and directory does not exist, return error // if directory does not exist and create is true, create dir and return directory entry QFileInfo fileInfo(url.path()); if ((!create) && fileInfo.isFile()) { this->callback(ecId, "FileException.cast(FileException.TYPE_MISMATCH_ERR)"); return; } if (dir.exists()) { if (create && exclusive) { this->callback(ecId, "FileException.cast(FileException.PATH_EXISTS_ERR)"); return; } } else { if (!create) { this->callback(ecId, "FileException.cast(FileException.NOT_FOUND_ERR)"); return; } // Create the folder QString folderName = dir.dirName(); dir.cdUp(); dir.mkdir(folderName); dir.cd(folderName); // Check if creation was successfull if (!dir.exists()) { this->callback(ecId, "FileException.cast(FileException.NO_MODIFICATION_ALLOWED_ERR)"); return; } } // If we reach here, everything went well this->callback(scId, "DirectoryEntry.cast('" + dir.dirName() + "', '" + dir.absolutePath() + "')"); } void FileAPI::removeRecursively(int scId, int ecId, QString p_path) { QDir dir(p_path); if (FileAPI::rmDir(dir)) { this->cb(scId); return; } this->callback(ecId, "FileException.cast(FileException.NO_MODIFICATION_ALLOWED_ERR)"); } void FileAPI::file(int scId, int ecId, QString p_path) { QFileInfo fileInfo(p_path); if (!fileInfo.exists()) { this->callback(ecId, "FileException.cast(FileException.NOT_FOUND_ERR)"); } else { this->callback(scId, "File.cast('" + fileInfo.fileName() + "', '" + fileInfo.absoluteFilePath() + "', 'unknown/unknown', new Date(" + QString::number(fileInfo.lastModified().toMSecsSinceEpoch()) + "), " + QString::number(fileInfo.size()) + ")"); } } void FileAPI::write(int scId, int ecId, QString p_path, unsigned long long p_position, QString _data, bool binary) { QFile file(p_path); // if (!file.exists()) { // FIXME: always overwrite?? file.open(QIODevice::WriteOnly); file.close(); // } if (!file.exists()) { this->callback(ecId, "FileException.cast(FileException.NOT_FOUND_ERR), 0, 0"); return; } QFileInfo fileInfo(file); if (!file.open(QIODevice::ReadWrite)) { this->callback(ecId, "FileException.cast(FileException.NO_MODIFICATION_ALLOWED_ERR), 0, " + QString::number(fileInfo.size())); return; } if (!binary) { QTextStream textStream(&file); textStream.setCodec("UTF-8"); textStream.setAutoDetectUnicode(true); if (!textStream.seek(p_position)) { file.close(); fileInfo.refresh(); this->callback(ecId, "FileException.cast(FileException.INVALID_MODIFICATION_ERR), 0, " + QString::number(fileInfo.size())); return; } textStream << _data; textStream.flush(); } else { QByteArray p_data(_data.toUtf8()); if (!file.seek(p_position)) { file.close(); fileInfo.refresh(); this->callback(ecId, "FileException.cast(FileException.INVALID_MODIFICATION_ERR), 0, " + QString::number(fileInfo.size())); return; } file.write(p_data.data(), p_data.length()); } file.flush(); file.close(); fileInfo.refresh(); if (p_position > 0) { if (!file.resize(p_position + _data.size())) { this->callback(ecId, "FileException.cast(FileException.NO_MODIFICATION_ALLOWED_ERR), " + QString::number(file.size()) + ", " + QString::number(file.size())); return; } } this->cb(scId, fileInfo.size(), fileInfo.size()); } void FileAPI::truncate(int scId, int ecId, QString p_path, unsigned long long p_size) { QFile file(p_path); if (!file.exists()) { this->callback(ecId, "FileException.cast(FileException.NOT_FOUND_ERR), 0, 0"); return; } // Try to resize (truncate) the file if (!file.resize(p_size)) { this->callback(ecId, "FileException.cast(FileException.NO_MODIFICATION_ALLOWED_ERR), " + QString::number(file.size()) + ", " + QString::number(file.size())); return; } this->cb(scId, p_size, p_size); } void FileAPI::getParent(int scId, int ecId, QString p_path) { QDir dir(p_path); //can't cdup more than app's root // Try to change into upper directory if (p_path != m_persistentDir){ if (!dir.cdUp()) { this->callback(ecId, "FileException.cast(FileException.NOT_FOUND_ERR)"); return; } } this->callback(scId, "DirectoryEntry.cast('" + dir.dirName() + "', '" + dir.absolutePath() + "')"); } void FileAPI::remove(int scId, int ecId, QString p_path) { QFileInfo fileInfo(p_path); if (!fileInfo.exists() || (p_path == m_persistentDir)) { this->callback(ecId, "FileException.cast(FileException.NO_MODIFICATION_ALLOWED_ERR)"); return; } // Check if we have a dir if (fileInfo.isDir()) { QDir dir(p_path); if (dir.rmdir(dir.absolutePath())) { this->cb(scId); return; } } else { QFile file(p_path); if (file.remove()) { this->cb(scId); return; } } this->callback(ecId, "FileException.cast(FileException.INVALID_MODIFICATION_ERR)"); } void FileAPI::getMetadata(int scId, int ecId, QString p_path) { QFileInfo fileInfo(p_path); if (!fileInfo.exists()) { this->callback(ecId, "FileException.cast(FileException.NOT_FOUND_ERR)"); return; } this->callback(scId, "Metadata.cast(new Date(" + QString::number(fileInfo.lastModified().toMSecsSinceEpoch()) + "))"); } void FileAPI::readEntries(int scId, int ecId, QString p_path) { QDir dir(p_path); QString entriesList = ""; if (dir.exists()) { // Iterate over entries and add them to response Q_FOREACH(const QFileInfo &fileInfo, dir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)) { if (fileInfo.isDir()) { entriesList += "DirectoryEntry.cast('" + fileInfo.fileName() + "','" + fileInfo.absoluteFilePath() + "/'),"; } else { entriesList += "FileEntry.cast('" + fileInfo.fileName() + "','" + fileInfo.absoluteFilePath() + "'),"; } } // Remove trailing comma if (entriesList.size() > 0) entriesList.remove(entriesList.size()-1, 1); entriesList = "new Array(" + entriesList + ")"; this->callback(scId, entriesList); return; } this->callback(ecId, "FileException.cast(FileException.NOT_FOUND_ERR)"); } void FileAPI::readAsText(int scId, int ecId, QString p_path, bool sliced, int sliceStart, int sliceEnd) { QFile file(p_path); if (!file.exists()) { this->callback(ecId, "FileException.cast(FileException.NOT_FOUND_ERR)"); return; } if (!file.open(QIODevice::ReadOnly)) { this->callback(ecId, "FileException.cast(FileException.NOT_READABLE_ERR)"); return; } QByteArray content = file.readAll(); if (sliceEnd == -1) sliceEnd = content.size(); if (sliceEnd < 0) { sliceEnd++; sliceEnd = std::max(0, content.size() + sliceEnd); } if (sliceEnd > content.size()) sliceEnd = content.size(); if (sliceStart < 0) sliceStart = std::max(0, content.size() + sliceStart); if (sliceStart > content.size()) sliceStart = content.size(); if (sliceStart > sliceEnd) sliceEnd = sliceStart; if (sliced) content = content.mid(sliceStart, sliceEnd - sliceStart); this->cb(scId, content); } void FileAPI::readAsBinaryString(int scId, int ecId, QString p_path, bool sliced, int sliceStart, int sliceEnd) { QFile file(p_path); if (!file.exists()) { this->callback(ecId, "FileException.cast(FileException.NOT_FOUND_ERR)"); return; } if (!file.open(QIODevice::ReadOnly)) { this->callback(ecId, "FileException.cast(FileException.NOT_READABLE_ERR)"); return; } QString res; QByteArray content = file.readAll(); if (sliceEnd == -1) sliceEnd = content.size(); if (sliceEnd < 0) { sliceEnd++; sliceEnd = std::max(0, content.size() + sliceEnd); } if (sliceEnd > content.size()) sliceEnd = content.size(); if (sliceStart < 0) sliceStart = std::max(0, content.size() + sliceStart); if (sliceStart > content.size()) sliceStart = content.size(); if (sliceStart > sliceEnd) sliceEnd = sliceStart; if (sliced) content = content.mid(sliceStart, sliceEnd - sliceStart); res.reserve(content.length() * 6); for (uchar c:content) { res += "\\x"; res += QString::number(c, 16).rightJustified(2, '0').toUpper(); } this->callback(scId, "\"" + res + "\""); } void FileAPI::readAsDataURL(int scId, int ecId, QString p_path, bool sliced, int sliceStart, int sliceEnd) { QFile file(p_path); QFileInfo fileInfo(p_path); if (p_path.startsWith("content:")){ this->callback(ecId, "FileException.cast(FileException.NOT_READABLE_ERR)"); return; } if (!file.exists()) { this->callback(ecId, "FileException.cast(FileException.NOT_FOUND_ERR)"); return; } // Try to open file for reading if (!file.open(QIODevice::ReadOnly)) { this->callback(ecId, "FileException.cast(FileException.NOT_READABLE_ERR)"); return; } // Read the file content QByteArray content = file.readAll(); QString contentType(mimeMap_[fileInfo.completeSuffix()]); if (sliceEnd == -1) sliceEnd = content.size(); if (sliceEnd < 0) { sliceEnd++; sliceEnd = std::max(0, content.size() + sliceEnd); } if (sliceEnd > content.size()) sliceEnd = content.size(); if (sliceStart < 0) sliceStart = std::max(0, content.size() + sliceStart); if (sliceStart > content.size()) sliceStart = content.size(); if (sliceStart > sliceEnd) sliceEnd = sliceStart; if (sliced) content = content.mid(sliceStart, sliceEnd - sliceStart); this->cb(scId, QString("data:%1;base64,").arg(contentType) + content.toBase64()); } /* * Helper function for recursively removing a directory */ bool FileAPI::rmDir(QDir p_dir) { if (p_dir == m_persistentDir) {//can't remove root dir return false; } bool result = true; if (p_dir.exists()) { // Iterate over entries and remove them Q_FOREACH(const QFileInfo &fileInfo, p_dir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)) { if (fileInfo.isDir()) { result = rmDir(fileInfo.absoluteFilePath()); } else { result = QFile::remove(fileInfo.absoluteFilePath()); } if (!result) { return result; } } // Finally remove the current dir return p_dir.rmdir(p_dir.absolutePath()); } return result; } bool FileAPI::copyFile(int scId, int ecId,const QString& sourceFile, const QString& destinationParentDir, const QString& newName) { if (!QDir(destinationParentDir).exists()){ this->callback(ecId, "FileException.cast(FileException.NOT_FOUND_ERR)"); return false; } QFileInfo fileInfo(sourceFile); QString fileName = ((newName.isEmpty()) ? fileInfo.fileName() : newName); QString destinationFile(destinationParentDir + "/" + fileName); //NOTE: colon is not safe in url, it is not a valid path in Win and Mac, simple disable it here. if (!QUrl::fromUserInput(destinationFile).isValid() || destinationFile.contains(":")){ this->callback(ecId, "FileException.cast(FileException.ENCODING_ERR)"); return false; } if (QFile::copy(sourceFile, destinationFile)){ this->callback(scId, "FileEntry.cast('" + fileName + "', '" + destinationFile + "')"); return true; } else { this->callback(ecId, "FileException.cast(FileException.INVALID_MODIFICATION_ERR)"); return false; } } void FileAPI::moveFile(int scId, int ecId,const QString& sourceFile, const QString& destinationParentDir, const QString& newName){ QString fileName = ((newName.isEmpty()) ? QFileInfo(sourceFile).fileName() : newName); //if existing a file have the newName, remove it and rename sourceFile QString destinationFile(destinationParentDir + "/" + fileName); if (QFileInfo(destinationFile).exists() && (sourceFile != destinationFile)){ if (!QFile::remove(destinationFile)){ this->callback(ecId, "FileException.cast(FileException.INVALID_MODIFICATION_ERR)"); return; } QFile::rename(sourceFile,destinationFile); this->callback(scId, "FileEntry.cast('" + fileName + "', '" + destinationFile + "')"); return; } //try copy source file to dest file and remove it if success. if (copyFile(scId,ecId,sourceFile, destinationParentDir, newName)){ remove(scId,ecId, sourceFile); this->cb(scId); return; } else { qDebug() << "unable to copy the file, ecID is callbacked by copyFile"; return; } } void FileAPI::copyDir(int scId, int ecId,const QString& sourceFolder, const QString& destinationParentDir, const QString& newName) { QDir sourceDir(sourceFolder); QString dirName = ((newName.isEmpty()) ? sourceDir.dirName() : newName); QString destFolder(destinationParentDir + "/" + dirName); //can't copy a dir on a file if (QFileInfo(destFolder).isFile()){ this->callback(ecId, "FileException.cast(FileException.INVALID_MODIFICATION_ERR)"); return; } QDir destDir(destFolder); //can't copy on or in itself if ((sourceFolder == destFolder) || (sourceFolder == destinationParentDir)){ this->callback(ecId, "FileException.cast(FileException.INVALID_MODIFICATION_ERR)"); return; } //create the dir if (!destDir.exists()){ qDebug() << "mkdir" << destDir.mkdir(destFolder);; } else{ this->callback(ecId, "FileException.cast(FileException.INVALID_MODIFICATION_ERR)"); return; } //recursively copying begin if (copyFolder(sourceFolder, destFolder)){ this->callback(scId, "DirectoryEntry.cast('" + dirName + "', '" + destFolder + "')"); return; } else { this->callback(ecId, "FileException.cast(FileException.INVALID_MODIFICATION_ERR)"); return; } } void FileAPI::moveDir(int scId, int ecId,const QString& sourceDir, const QString& destinationParentDir, const QString& newName){ QString dirName = ((newName.isEmpty()) ? QDir(sourceDir).dirName() : newName); QString destFolder(destinationParentDir + "/" + dirName); QDir destDir(destFolder); //can't copy a dir on a file if (QFileInfo(destFolder).isFile()){ this->callback(ecId, "FileException.cast(FileException.INVALID_MODIFICATION_ERR)"); return; } //can't copy on or in itself if ((sourceDir == destFolder) || (sourceDir == destinationParentDir)){ this->callback(ecId, "FileException.cast(FileException.INVALID_MODIFICATION_ERR)"); return; } if (destDir.exists() && (destFolder != sourceDir)){ if (QDir(destinationParentDir).rmdir(dirName)){ qDebug() << "empty folder rmed"; } else { this->callback(ecId, "FileException.cast(FileException.INVALID_MODIFICATION_ERR)"); return; } } if (copyFolder(sourceDir, destFolder)){ qDebug() << "rming src dir if src-> dest copy success"; rmDir(sourceDir); this->callback(scId, "DirectoryEntry.cast('" + dirName + "', '" + destFolder + "')"); return; } else { qDebug()<< "unable to copy dirs" <cb(scId, ++lastRequestId); } void FileAPI::downloadFile(int scId, int ecId, int id, const QString& url) { QSharedPointer request(new FileTransferRequest(m_manager, scId, ecId, m_id2progress[id], id, this)); m_id2request.insert(id, request); request->connect(request.data(), &FileTransferRequest::done, [&]() { auto it = m_id2request.find(id); while (it != m_id2request.end() && it.key() == id) { if (it.value().data() == request.data()) { m_id2request.erase(it); break; } it++; } }); request->download(url); } void FileAPI::uploadFile(int scId, int ecId, int id, const QString& url, const QString& content, QString fileKey, QString fileName, QString mimeType, const QVariantMap ¶ms, const QVariantMap &headers) { QSharedPointer request(new FileTransferRequest(m_manager, scId, ecId, m_id2progress[id], id, this)); m_id2request.insert(id, request); request->connect(request.data(), &FileTransferRequest::done, [&]() { auto it = m_id2request.find(id); while (it != m_id2request.end() && it.key() == id) { if (it.value().data() == request.data()) { m_id2request.erase(it); break; } it++; } }); request->upload(url, content, fileKey, fileName, mimeType, params, headers); } void FileAPI::transferRequestSetOnProgress(int scId, int ecId, int id) { Q_UNUSED(ecId); m_id2progress[id] = scId; } void FileAPI::abortRequests(int scId, int ecId, int id) { Q_UNUSED(scId) Q_UNUSED(ecId) auto it = m_id2request.find(id); while (it != m_id2request.end() && it.key() == id) { (*it)->abort(); it++; } } void FileTransferRequest::download(const QString& _url) { QUrl url(_url); QNetworkRequest request; if (!url.isValid()) { m_plugin->cb(m_ecId, "invalidUrl"); return; } request.setUrl(url); if (url.password().size() || url.userName().size()) { QString headerData = "Basic " + (url.userName() + ":" + url.password()).toLocal8Bit().toBase64(); request.setRawHeader("Authorization", headerData.toLocal8Bit()); } m_reply = QSharedPointer(m_manager.get(request)); m_reply->connect(m_reply.data(), &QNetworkReply::finished, [&]() { if (m_reply->error() != QNetworkReply::NoError) return; m_plugin->cb(m_scId, m_reply->readAll().toBase64()); emit done(); }); m_reply->connect(m_reply.data(), SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(error(QNetworkReply::NetworkError))); m_reply->connect(m_reply.data(), SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(progress(qint64, qint64))); } void FileTransferRequest::upload(const QString& _url, const QString& content, QString fileKey, QString fileName, QString mimeType, const QVariantMap ¶ms, const QVariantMap &headers) { QUrl url(_url); QNetworkRequest request; if (!url.isValid()) { m_plugin->cb(m_ecId, "invalidUrl"); return; } request.setUrl(url); if (url.password().size() || url.userName().size()) { QString headerData = "Basic " + (url.userName() + ":" + url.password()).toLocal8Bit().toBase64(); request.setRawHeader("Authorization", headerData.toLocal8Bit()); } for (const QString &key: headers.keys()) { const QString &value = headers.find(key)->toString(); request.setRawHeader(key.toUtf8(), value.toUtf8()); } QString boundary = QString("CORDOVA-QT-%1A").arg(qrand()); while (content.contains(boundary)) { boundary += QString("B%1A").arg(qrand()); } request.setHeader(QNetworkRequest::ContentTypeHeader, QString("multipart/form-data; boundary=") + boundary); fileKey.replace("\"", ""); fileName.replace("\"", ""); mimeType.replace("\"", ""); QString part = "--" + boundary + "\r\n"; part += "Content-Disposition: form-data; name=\"" + fileKey +"\"; filename=\"" + fileName + "\"\r\n"; part += "Content-Type: " + mimeType + "\r\n\r\n"; part += content + "\r\n"; for (QString key: params.keys()) { part += "--" + boundary + "\r\n"; part += "Content-Disposition: form-data; name=\"" + key + "\";\r\n\r\n"; part += params.find(key)->toString(); part += "\r\n"; } part += QString("--") + boundary + "--" + "\r\n"; m_reply = QSharedPointer(m_manager.post(request, QByteArray(part.toUtf8()))); m_reply->connect(m_reply.data(), &QNetworkReply::finished, [&]() { if (m_reply->error() != QNetworkReply::NoError) return; int status = 200; QVariant statusCode = m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); if (statusCode.isValid()) { status = statusCode.toInt(); } m_plugin->callback(m_scId, QString("%1, atob('%2')").arg(status).arg(QString(m_reply->readAll().toBase64()))); emit done(); }); m_reply->connect(m_reply.data(), SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(error(QNetworkReply::NetworkError))); m_reply->connect(m_reply.data(), SIGNAL(uploadProgress(qint64, qint64)), this, SLOT(progress(qint64, qint64))); } void FileTransferRequest::abort() { m_plugin->cb(m_ecId, "abort"); emit done(); } void FileTransferRequest::error(QNetworkReply::NetworkError code) { Q_UNUSED(code); int status = 404; QVariant statusCode = m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); if (statusCode.isValid()) { status = statusCode.toInt(); } m_plugin->cb(m_ecId, status, m_reply->readAll().toBase64()); emit done(); } void FileTransferRequest::progress(qint64 bytesReceived, qint64 bytesTotal) { if (bytesReceived && bytesTotal) m_plugin->callbackWithoutRemove(m_progressId, QString("%1, %2").arg(bytesReceived).arg(bytesTotal)); } cordova-ubuntu-2.8.0+14.04.20140130.3/src/plugins/capture.cpp0000644000015000001560000000620512272510553023606 0ustar pbuserpbgroup00000000000000#include "capture.h" #include "../cordova.h" #include #include #include #include #define AUDIO_STATE_NAME "audio" Capture::Capture(Cordova *cordova): CPlugin(cordova), m_scId(0), m_ecId(0) { } void Capture::onError(QMediaRecorder::Error) { if (!m_ecId) return; this->cb(m_ecId); m_ecId = m_scId = 0; m_cordova->popViewState(AUDIO_STATE_NAME); m_recorder.clear(); m_files.clear(); } void Capture::getSupportedFormats(int scId, int ecId) { Q_UNUSED(ecId) QAudioRecorder recorder; QString audioCodecs, videoCodecs, imageFormats; audioCodecs = QString("'audio/amr', 'audio/wav'"); for (const QString &format: recorder.supportedVideoCodecs()) { if (videoCodecs.size()) videoCodecs += ","; videoCodecs += QString("\'%1\'").arg(format); } for (const QByteArray &format: QImageReader::supportedImageFormats()) { if (imageFormats.size()) imageFormats += ","; imageFormats += QString("'image/%1'").arg(QString(format).toLower()); } this->callback(scId, QString("[%1], [%2], [%3]").arg(audioCodecs).arg(videoCodecs).arg(imageFormats)); } void Capture::startAudioRecordApp(int scId, int ecId, QVariantMap p_options) { if (m_scId || m_ecId) { this->callbackWithoutRemove(ecId, "\"Device is busy\""); return; } m_scId = scId; m_ecId = ecId; m_cordova->pushViewState(AUDIO_STATE_NAME); m_options = p_options; } static QString join(const QList &in) { QString res; for (const QString &str: in) res += QString("'%1',").arg(str); return res; } void Capture::record() { if (m_recorder.data()) { QUrl url = m_recorder->outputLocation(); QString path = url.toString(); m_recorder->stop(); m_recorder.clear(); m_files.append(path); qDebug() << m_options.find("limit")->toInt(); if (m_options.find("limit")->toInt() > 0) { m_options["limit"] = m_options.find("limit")->toInt() - 1; } else { //FIXME this->callback(m_scId, QString("[%1]").arg(join(m_files))); m_files.clear(); m_ecId = m_scId = 0; m_cordova->popViewState(AUDIO_STATE_NAME); } } else { m_recorder = QSharedPointer(new QAudioRecorder); QObject::connect(m_recorder.data(), SIGNAL(error(QMediaRecorder::Error)), this, SLOT(onError(QMediaRecorder::Error))); if (m_options.find("mode")->toString() == "audio/amr") m_recorder->setContainerFormat("amr"); else m_recorder->setContainerFormat("wav"); m_recorder->record(); } } void Capture::cancel() { if (!m_ecId) return; if (m_files.size()) { this->callback(m_scId, QString("[%1]").arg(join(m_files))); m_ecId = m_scId = 0; m_files.clear(); m_cordova->popViewState(AUDIO_STATE_NAME); m_recorder.clear(); return; } this->cb(m_ecId, "canceled"); m_ecId = m_scId = 0; m_cordova->popViewState(AUDIO_STATE_NAME); m_recorder.clear(); } cordova-ubuntu-2.8.0+14.04.20140130.3/src/plugins/splashscreen.cpp0000644000015000001560000000073112272510553024633 0ustar pbuserpbgroup00000000000000#include #include "splashscreen.h" #include "../cordova.h" #define SPLASHSCREEN_STATE_NAME "splashscreen" Splashscreen::Splashscreen(Cordova *cordova): CPlugin(cordova) { } void Splashscreen::show(int, int) { m_cordova->rootObject()->setProperty("splashscreenPath", m_cordova->getSplashscreenPath()); m_cordova->pushViewState(SPLASHSCREEN_STATE_NAME); } void Splashscreen::hide(int, int) { m_cordova->popViewState(SPLASHSCREEN_STATE_NAME); } cordova-ubuntu-2.8.0+14.04.20140130.3/src/plugins/fileapi.h0000644000015000001560000001121112272510553023212 0ustar pbuserpbgroup00000000000000/* * Copyright 2011 Wolfgang Koller - http://www.gofg.at/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef FILEAPI_H_SDASDASDAS #define FILEAPI_H_SDASDASDAS #include #include #include "../cplugin.h" #include "../cordova.h" class QNetworkReply; class FileTransferRequest: public QObject { Q_OBJECT QNetworkAccessManager &m_manager; int m_scId, m_ecId, m_progressId; int m_id; QSharedPointer m_reply; FileTransferRequest* operator=(const FileTransferRequest&) = delete; FileTransferRequest(FileTransferRequest&) = delete; public: FileTransferRequest(QNetworkAccessManager &manager, int scId, int ecId, int progressId, int id, CPlugin *plugin): m_manager(manager), m_scId(scId), m_ecId(ecId), m_progressId(progressId), m_id(id), m_plugin(plugin) { } void download(const QString& url); void upload(const QString& _url, const QString& content, QString fileKey, QString fileName, QString mimeType, const QVariantMap ¶ms, const QVariantMap &headers); void abort(); signals: void done(); private slots: void progress(qint64 bytesReceived, qint64 bytesTotal); void error(QNetworkReply::NetworkError code); private: CPlugin *m_plugin; }; class FileAPI : public CPlugin { Q_OBJECT public: explicit FileAPI(Cordova *cordova); virtual const QString fullName() override { return FileAPI::fullID(); } virtual const QString shortName() override { return "File"; } static const QString fullID() { return "com.cordova.File"; } public slots: void requestFileSystem(int scId, int ecId, unsigned short p_type, unsigned long long p_size); void resolveLocalFileSystemURL(int scId, int ecId, QString p_url); void getDirectory(int scId, int ecId, QString p_path, QVariantMap p_options); void getFile(int scId, int ecId, QString p_path, QVariantMap p_options); void getParent(int scId, int ecId, QString p_path); void getMetadata(int scId, int ecId, QString p_path); void remove(int scId, int ecId, QString p_path); void removeRecursively(int scId, int ecId, QString p_path); void file(int scId, int ecId, QString p_path); void write(int scId, int ecId, QString p_path, unsigned long long p_position, QString p_data, bool binary); void truncate(int scId, int ecId, QString p_path, unsigned long long p_size); void readEntries(int scId, int ecId, QString p_path); void readAsDataURL(int scId, int ecId, QString p_path, bool sliced, int sliceStart, int sliceEnd); void readAsText(int scId, int ecId, QString p_path, bool sliced, int sliceStart, int sliceEnd); void readAsBinaryString(int scId, int ecId, QString p_path, bool sliced, int sliceStart, int sliceEnd); bool copyFile(int scId, int ecId,const QString& sourceFile, const QString& destinationParentDir, const QString& newName); void moveFile(int scId, int ecId,const QString& sourceFile, const QString& destinationParentDir, const QString& newName); void copyDir(int scId, int ecId,const QString& sourceFolder, const QString& destFolder, const QString& newName); void moveDir(int scId, int ecId,const QString& sourceFolder, const QString& destFolder, const QString& newName); void newTransferRequest(int scId, int ecId); void transferRequestSetOnProgress(int scId, int ecId, int id); void abortRequests(int scId, int ecId, int id); void downloadFile(int scId, int ecId, int id, const QString& url); void uploadFile(int scId, int ecId, int id, const QString& url, const QString& content, QString fileKey, QString fileName, QString mimeType, const QVariantMap ¶ms, const QVariantMap &headers); protected: bool rmDir(QDir p_dir); bool copyFolder(const QString& sourceFolder, const QString& destFolder); private: typedef QMap MimeTypeMap; static MimeTypeMap createMimeTypeMap(); static MimeTypeMap mimeMap_; const QString m_persistentDir; QNetworkAccessManager m_manager; QMultiMap > m_id2request; QMap m_id2progress; int lastRequestId; }; #endif cordova-ubuntu-2.8.0+14.04.20140130.3/src/plugins/compass.cpp0000644000015000001560000000335712272510553023615 0ustar pbuserpbgroup00000000000000/* * Copyright 2011 Integrated Computer Solutions - http://www.ics.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "compass.h" Compass::Compass(Cordova *cordova) :CPlugin(cordova) { m_azymuth = 0; m_accuracy = 0; m_compassSource = new QCompass(this); m_compassSource->connectToBackend(); m_compassSource->start(); connect(m_compassSource,SIGNAL(readingChanged()), SLOT(updateSensor())); } void Compass::getCurrentHeading(int scId, int ecId, QVariantMap p_options) { Q_UNUSED(p_options) m_successCallbacks << scId; m_errorCallbacks << ecId; //TODO azymuth to true north conversion QString callbackArguments = "CompassHeading.cast(" + QString::number(m_azymuth) + ", "+ QString::number(m_azymuth) + "," + QString::number(m_accuracy) + ", " + " 0 "+")"; for (int i = 0; i < m_successCallbacks.size(); i++) { this->callback(m_successCallbacks.at(i), callbackArguments); } m_errorCallbacks.clear(); m_successCallbacks.clear(); } void Compass::updateSensor(){ QCompassReading *heading = m_compassSource->reading(); m_azymuth = heading->azimuth(); m_accuracy = heading->calibrationLevel(); m_timestamp = heading->timestamp(); } cordova-ubuntu-2.8.0+14.04.20140130.3/src/plugins/media.cpp0000644000015000001560000001047612272510553023227 0ustar pbuserpbgroup00000000000000/* * Copyright 2011 Integrated Computer Solutions - http://www.ics.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "media.h" void Media::newPlayer(int scId, int ecId, const QString &src, int id) { Q_UNUSED(scId); if (m_id2Player.find(id) != m_id2Player.end()) { m_id2Player[id]->stop(); m_id2Player.remove(id); } m_id2Player[id] = QSharedPointer(new Player(ecId, src, this)); } void Media::playerSetCallbacks(int successCb, int statusCb, QVariantMap p_options) { int id = p_options.find("id")->toInt(); if (m_id2Player.find(id) == m_id2Player.end()) return; QSharedPointer player = m_id2Player[id]; player->setSuccessCb(successCb); player->setStatusCb(statusCb); } void Media::relasePlayer(int scId, int ecId, QVariantMap p_options) { Q_UNUSED(scId); Q_UNUSED(ecId); int id = p_options.find("id")->toInt(); if (m_id2Player.find(id) == m_id2Player.end()) return; m_id2Player.remove(id); } void Media::play(int scId, int ecId, QVariantMap p_options) { Q_UNUSED(scId) Q_UNUSED(ecId) int id = p_options.find("id")->toInt(); if (m_id2Player.find(id) == m_id2Player.end()) return; QSharedPointer player = m_id2Player[id]; player->play(); } void Media::pause(int scId, int ecId, QVariantMap p_options) { Q_UNUSED(scId) Q_UNUSED(ecId) int id = p_options.find("id")->toInt(); if (m_id2Player.find(id) == m_id2Player.end()) return; QSharedPointer player = m_id2Player[id]; player->pause(); } void Media::stop(int scId, int ecId, QVariantMap p_options){ Q_UNUSED(scId) Q_UNUSED(ecId) int id = p_options.find("id")->toInt(); if (m_id2Player.find(id) == m_id2Player.end()) return; QSharedPointer player = m_id2Player[id]; player->stop(); } void Media::startRecording(int scId, int ecId, QVariantMap p_options) { Q_UNUSED(scId) Q_UNUSED(ecId) int id = p_options.find("id")->toInt(); if (m_id2Player.find(id) == m_id2Player.end()) return; QSharedPointer player = m_id2Player[id]; player->startRecording(); } void Media::stopRecording(int scId, int ecId, QVariantMap p_options) { Q_UNUSED(scId) Q_UNUSED(ecId) int id = p_options.find("id")->toInt(); if (m_id2Player.find(id) == m_id2Player.end()) return; QSharedPointer player = m_id2Player[id]; player->stopRecording(); } void Media::getDuration(int scId, int ecId, QVariantMap p_options) { Q_UNUSED(ecId) int id = p_options.find("id")->toInt(); if (m_id2Player.find(id) == m_id2Player.end()) return; QSharedPointer player = m_id2Player[id]; qint64 duration = player->getDuration(); this->cb(scId, duration); } void Media::getCurrentPosition(int scId, int ecId, QVariantMap p_options) { Q_UNUSED(ecId) int id = p_options.find("id")->toInt(); if (m_id2Player.find(id) == m_id2Player.end()) return; QSharedPointer player = m_id2Player[id]; qint64 position = player->getPosition(); this->cb(scId, position); } void Media::seekTo(int scId, int ecId, QVariantMap p_options) { Q_UNUSED(scId) Q_UNUSED(ecId) int id = p_options.find("id")->toInt(); qint64 position = p_options.find("position")->toLongLong(); if (m_id2Player.find(id) == m_id2Player.end()) return; QSharedPointer player = m_id2Player[id]; player->seekTo(position); } void Media::setVolume(int scId, int ecId, QVariantMap p_options) { Q_UNUSED(scId) Q_UNUSED(ecId) int id = p_options.find("id")->toInt(); int volume = p_options.find("volume")->toInt(); if (m_id2Player.find(id) == m_id2Player.end()) return; QSharedPointer player = m_id2Player[id]; player->setVolume(volume); } cordova-ubuntu-2.8.0+14.04.20140130.3/src/plugins/media.h0000644000015000001560000001645712272510553022701 0ustar pbuserpbgroup00000000000000/* * Copyright 2011 Integrated Computer Solutions - http://www.ics.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MEDIA_H #define MEDIA_H #include #include #include #include #include "../cplugin.h" class Player; class Media: public CPlugin { Q_OBJECT public: explicit Media(Cordova *cordova): CPlugin(cordova) { } virtual const QString fullName() override { return Media::fullID(); } virtual const QString shortName() override { return "Media"; } static const QString fullID() { return "com.cordova.Media"; } enum State { MEDIA_NONE = 0, MEDIA_STARTING = 1, MEDIA_RUNNING = 2, MEDIA_PAUSED = 3, MEDIA_STOPPED = 4 }; enum ErrorCode { MEDIA_ERR_NONE_ACTIVE = 0, MEDIA_ERR_ABORTED = 1, MEDIA_ERR_NETWORK = 2, MEDIA_ERR_DECODE = 3, MEDIA_ERR_NONE_SUPPORTED = 4 }; public slots: void newPlayer(int scId, int ecId, const QString &src, int id); void relasePlayer(int scId, int ecId, QVariantMap p_options); void playerSetCallbacks(int successCb, int statusCb, QVariantMap p_options); void startRecording(int scId, int ecId, QVariantMap p_options); void stopRecording(int scId, int ecId, QVariantMap p_options); void play(int scId, int ecId, QVariantMap p_options); void pause(int scId, int ecId, QVariantMap p_options); void stop(int scId, int ecId, QVariantMap p_options); void getDuration(int scId, int ecId, QVariantMap p_options); void getCurrentPosition(int scId, int ecId, QVariantMap p_options); void seekTo(int scId, int ecId, QVariantMap p_options); void setVolume(int scId, int ecId, QVariantMap p_options); private: QMap > m_id2Player; }; class Player: public QObject { Q_OBJECT public: Player(int ecId, QString src, CPlugin *plugin): m_state(Media::MEDIA_NONE), m_src(src), m_successCb(0), m_statusCb(0), m_errorCb(ecId), m_mode(MODE_NONE), m_plugin(plugin) { QUrl url(src, QUrl::TolerantMode); if (url.scheme().isEmpty()) { QAudioEncoderSettings audioSettings; m_recorder.setEncodingSettings(audioSettings); m_recorder.setOutputLocation(QFileInfo(src).absoluteFilePath()); m_player.setMedia(QUrl::fromLocalFile(QFileInfo(src).absoluteFilePath())); } else { m_player.setMedia(url); } QObject::connect(&m_player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)), this, SLOT(onMediaStatusChanged(QMediaPlayer::MediaStatus))); QObject::connect(&m_recorder, SIGNAL(error(QMediaRecorder::Error)), this, SLOT(onError(QMediaRecorder::Error))); } void setSuccessCb(int successCb) { m_successCb = successCb; } void setStatusCb(int statusCb) { m_statusCb = statusCb; } void startRecording() { if (recordMode() && m_state != Media::MEDIA_RUNNING) { m_recorder.record(); setState(Media::MEDIA_RUNNING); } } void stopRecording() { if (recordMode() && m_state == Media::MEDIA_RUNNING) { m_recorder.stop(); setState(Media::MEDIA_STOPPED); } } void setVolume(int volume) { m_player.setVolume(volume); } void play() { if (playMode() && m_state != Media::MEDIA_RUNNING) { m_player.play(); setState(Media::MEDIA_RUNNING); } } void pause() { if (playMode() && m_state == Media::MEDIA_RUNNING) { m_player.pause(); setState(Media::MEDIA_PAUSED); } } void stop() { if (playMode() && (m_state == Media::MEDIA_RUNNING || m_state == Media::MEDIA_PAUSED)) { m_player.stop(); setState(Media::MEDIA_STOPPED); } } qint64 getDuration() { if (m_mode == MODE_NONE) return -1; if (m_mode != MODE_PLAY) return -2; return m_player.duration() / 1000; } qint64 getPosition() { if (m_mode != MODE_PLAY) return -1; return m_player.position() / 1000; } bool seekTo(qint64 position) { if (!m_player.isSeekable()) return false; m_player.setPosition(position); return true; } private slots: void onMediaStatusChanged(QMediaPlayer::MediaStatus status) { if (status == QMediaPlayer::InvalidMedia) { m_plugin->callbackWithoutRemove(m_errorCb, QString("new MediaError(%1, 'AudioPlayer Error: The current media cannot be played.')").arg(Media::MEDIA_ERR_ABORTED)); setState(Media::MEDIA_STOPPED); } if (status == QMediaPlayer::EndOfMedia) { setState(Media::MEDIA_STOPPED); seekTo(0); } } void onError(QMediaRecorder::Error) { m_plugin->callbackWithoutRemove(m_errorCb, QString("new MediaError(%1, 'AudioPlayer Error: Device is not ready or not available.')").arg(Media::MEDIA_ERR_NONE_SUPPORTED)); setState(Media::MEDIA_STOPPED); } private: bool playMode() { switch (m_mode) { case Player::MODE_NONE: m_mode = MODE_PLAY; break; case Player::MODE_PLAY: break; case Player::MODE_RECORD: m_plugin->callbackWithoutRemove(m_errorCb, QString("new MediaError(%1, 'AudioPlayer Error: Can't play in record mode.')").arg(Media::MEDIA_ERR_NONE_SUPPORTED)); return false; break; } return true; } bool recordMode() { switch (m_mode) { case Player::MODE_NONE: if (m_recorder.outputLocation().isEmpty()) { m_plugin->callbackWithoutRemove(m_errorCb, QString("new MediaError(%1, 'AudioPlayer Error: unsupported output location.')").arg(Media::MEDIA_ERR_NONE_SUPPORTED)); return false; } m_mode = MODE_RECORD; break; case Player::MODE_PLAY: m_plugin->callbackWithoutRemove(m_errorCb, QString("new MediaError(%1, 'AudioPlayer Error: Can't play in play mode.')").arg(Media::MEDIA_ERR_NONE_SUPPORTED)); return false; break; case Player::MODE_RECORD: break; } return true; } void setState(Media::State state) { m_state = state; m_plugin->callbackWithoutRemove(m_statusCb, QString("%1").arg(state)); } QMediaPlayer m_player; QAudioRecorder m_recorder; Media::State m_state; QString m_src; int m_successCb, m_statusCb, m_errorCb; enum Mode { MODE_NONE, MODE_PLAY, MODE_RECORD }; Mode m_mode; CPlugin *m_plugin; }; #endif // MEDIA_H cordova-ubuntu-2.8.0+14.04.20140130.3/src/plugins/globalization.h0000644000015000001560000000363612272510553024453 0ustar pbuserpbgroup00000000000000#ifndef GLOBALIZATION_H #define GLOBALIZATION_H #include #include #include "../cplugin.h" class Globalization: public CPlugin { Q_OBJECT enum GlobalizationError { UNKNOWN_ERROR = 0, FORMATTING_ERROR = 1, PARSING_ERROR = 2, PATTERN_ERROR = 3 }; enum Selector { SELECTOR_DATE = 0, SELECTOR_TIME = 1, SELECTOR_ALL = 2 }; enum Format { FORMAT_SHORT = 0, FORMAT_MEDIUM = 1, FORMAT_LONG = 2, FORMAT_FULL = 3 }; enum { REQUEST_DAY_NAMES = 0, REQUEST_MONTH_NAMES = 1 }; enum NumberType { DECIMAL, PERCENT, CURRENCY }; public: explicit Globalization(Cordova *cordova); virtual const QString fullName() override { return Globalization::fullID(); } virtual const QString shortName() override { return "Globalization"; } static const QString fullID() { return "com.cordova.Globalization"; } public slots: void getPreferredLanguage(int scId, int ecId, QVariantMap p_options); void isDayLightSavingsTime(int scId, int ecId, QVariantMap p_options); void getFirstDayOfWeek(int scId, int ecId, QVariantMap p_options); void dateToString(int scId, int ecId, QVariantMap p_options); void stringToDate(int scId, int ecId, QVariantMap p_options); void getDateNames(int scId, int ecId, QVariantMap p_options); void numberToString(int scId, int ecId, QVariantMap p_options); void stringToNumber(int scId, int ecId, int type, QString string); void getNumberPattern(int scId, int ecId, int type); void getDatePattern(int scId, int ecId, int formatLength, int selector); private: friend QLocale::FormatType translateFormat(Globalization::Format formatLength); template friend QString format(T number, Globalization::NumberType type); }; #endif // GLOBALIZATION_H cordova-ubuntu-2.8.0+14.04.20140130.3/src/plugins/connection.h0000644000015000001560000000237112272510553023747 0ustar pbuserpbgroup00000000000000/* * Copyright 2011 Wolfgang Koller - http://www.gofg.at/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef CONNECTION_H #define CONNECTION_H #include "../cplugin.h" #include #include class Connection : public CPlugin { Q_OBJECT public: explicit Connection(Cordova *cordova); virtual const QString fullName() override { return Connection::fullID(); } virtual const QString shortName() override { return "Connection"; } static const QString fullID() { return "com.cordova.Connection"; } public slots: void getType(int scId, int ecId); private: void updateStatus(); QSharedPointer m_systemNetworkInfo; int m_scId; }; #endif cordova-ubuntu-2.8.0+14.04.20140130.3/src/coreplugins.cpp0000644000015000001560000000257012272510553023015 0ustar pbuserpbgroup00000000000000#include "plugins/accelerometer.h" #include "plugins/app.h" #include "plugins/camera.h" #include "plugins/cameraresolution.h" #include "plugins/capture.h" #include "plugins/compass.h" #include "plugins/connection.h" #include "plugins/console.h" #include "plugins/contacts.h" #include "plugins/device.h" #include "plugins/events.h" #include "plugins/fileapi.h" #include "plugins/geolocation.h" #include "plugins/globalization.h" #include "plugins/inappbrowser.h" #include "plugins/media.h" #include "plugins/notification.h" #include "plugins/splashscreen.h" #define CHECK_PLUGIN(class) \ if (pluginNames.contains(class::fullID())) { \ res.prepend(QSharedPointer(new class(cordova))); \ } extern "C" { Q_DECL_EXPORT QList> cordovaGetPluginInstances(const QList &pluginNames, Cordova *cordova) { QList> res; CHECK_PLUGIN(Accelerometer); CHECK_PLUGIN(App); CHECK_PLUGIN(Camera); CHECK_PLUGIN(Capture); CHECK_PLUGIN(Compass); CHECK_PLUGIN(Connection); CHECK_PLUGIN(Console); CHECK_PLUGIN(Contacts); CHECK_PLUGIN(Device); CHECK_PLUGIN(Events); CHECK_PLUGIN(FileAPI); CHECK_PLUGIN(Geolocation); CHECK_PLUGIN(Globalization); CHECK_PLUGIN(InAppBrowser); CHECK_PLUGIN(Media); CHECK_PLUGIN(Notification); CHECK_PLUGIN(Splashscreen); return res; } } cordova-ubuntu-2.8.0+14.04.20140130.3/src/js/0000755000015000001560000000000012272510676020375 5ustar pbuserpbgroup00000000000000cordova-ubuntu-2.8.0+14.04.20140130.3/src/js/compass.js0000644000015000001560000000667612272510553022411 0ustar pbuserpbgroup00000000000000/* * Copyright 2011 Integrated Computer Solutions - http://www.ics.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function CompassHeading(p_heading, p_trueHeading, p_accuracy, timestamp) { if (p_heading !== undefined) this.magneticHeading = p_heading; if (p_trueHeading !== undefined) this.trueHeading = p_trueHeading || 0; if (p_accuracy !== undefined) this.headingAccuracy = p_accuracy || 0; this.timestamp = timestamp || 0; }; CompassHeading.cast = function(heading, trueHeading, accuracy, timestamp){ var that = new CompassHeading(heading, trueHeading, accuracy, timestamp); return that; }; function CompassError() { }; CompassError.cast = function (p_code, p_message) { var CompassError = new CompassError(); CompassError.code = p_code; CompassError.message = p_message; return CompassError; }; CompassError.COMPASS_INTERNAL_ERR = 0; CompassError.COMPASS_NOT_SUPPORTED = 20; CompassError.prototype.code = 0; CompassError.prototype.message = ""; function HeadingOptions() { }; function Compass() { }; Compass.prototype.watchIds = []; Compass.prototype.cachedHeading = null; Compass.prototype.getCurrentHeading = function(successCallback, errorCallback, options) { if (typeof successCallback !== "function") return; if (typeof errorCallback !== "function") errorCallback = function() {}; var headingOptions = new HeadingOptions(); var me = this; Cordova.exec(function(p_heading) { received = true; me.cachedHeading = p_heading; successCallback(p_heading); }, errorCallback, "com.cordova.Compass", "getCurrentHeading", [ headingOptions ]); return me.cachedHeading; }; Compass.prototype.watchHeading = function(successCallback, errorCallback, options) { if (typeof successCallback !== "function") return; if (typeof errorCallback !== "function") errorCallback = function() {}; var watchId = this.watchIds.length + 1; // +1 in order to avoid 0 as watchId this.watchIds[watchId] = true; var me = this; function doWatch() { me.getCurrentHeading(function(p_heading) { if (!me.watchIds[watchId]) return; successCallback(p_heading); // Wait some time before starting again setTimeout(doWatch, 100); }, function(p_headingError) { if (!me.watchIds[watchId]) return; errorCallback(p_headingError); // Wait some time before starting again setTimeout(doWatch, 100); }, options); } // Start watching for heading changes (slight delay, in order to simulate asynchronous behaviour) setTimeout(doWatch, 100); return watchId; }; Compass.prototype.clearWatch = function(watchId) { this.watchIds[watchId] = false; }; Cordova.addConstructor("com.cordova.Compass", function () { navigator.compass = new Compass(); window.CompassError = CompassError; window.CompassHeading = CompassHeading; }); cordova-ubuntu-2.8.0+14.04.20140130.3/src/js/splashscreen.js0000644000015000001560000000053112272510553023416 0ustar pbuserpbgroup00000000000000var Splashscreen = { show: function() { Cordova.exec(null, null, "com.cordova.Splashscreen", "show", []); }, hide: function() { Cordova.exec(null, null, "com.cordova.Splashscreen", "hide", []); } }; Cordova.addConstructor("com.cordova.Splashscreen", function () { navigator.splashscreen = Splashscreen; }); cordova-ubuntu-2.8.0+14.04.20140130.3/src/js/device.js0000644000015000001560000000271512272510553022171 0ustar pbuserpbgroup00000000000000/* * Copyright 2011 Wolfgang Koller - http://www.gofg.at/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function Device() { var self = this; Cordova.deviceready.freeze(); Cordova.exec(function (p_name, p_cordova, p_platform, p_uuid, p_version) { self.name = p_name; self.model = p_name; self.cordova = p_cordova; self.platform = p_platform; self.uuid = p_uuid; self.version = p_version; Cordova.deviceready.unfreeze(); }, null, "com.cordova.Device", "getInfo", []); }; Device.prototype.name = ""; Device.prototype.cordova = ""; Device.prototype.platform = ""; Device.prototype.uuid = ""; Device.prototype.version = ""; Cordova.addConstructor("com.cordova.Device", function() { window.device = new Device(); window.cordova = window.Cordova; /* var PhoneGap = window.Cordova; PhoneGap.addPlugin = window.Cordova.enablePlugin; var plugins = window.Cordova; */ }); cordova-ubuntu-2.8.0+14.04.20140130.3/src/js/capture.js0000644000015000001560000001573612272510553022404 0ustar pbuserpbgroup00000000000000function CaptureAudioOptions(override) { this.limit = 1; this.duration = -1; this.mode = "audio/amr"; if (typeof(override) === 'object') { //TODO: throw exception if (typeof(override.limit) == typeof(this.limit) && override.limit >= 1) this.limit = override.limit; if (typeof(override.mode) == typeof(this.mode) && navigator.device.capture.supportedAudioModes.indexOf(override.mode) !== -1) this.mode = override.mode; } } function CaptureImageOptions(override) { this.limit = 1; this.mode = "image/jpeg"; if (typeof(override) === 'object') { //TODO: throw exception if (typeof(override.limit) == typeof(this.limit) && override.limit >= 1) this.limit = override.limit; if (typeof(override.mode) == typeof(this.mode) && navigator.device.capture.supportedImageModes.indexOf(override.mode) !== -1) this.mode = override.mode; } } function CaptureVideoOptions(override) { this.limit = 1; this.duration = -1; this.mode = "video/3gpp"; if (typeof(override) === 'object') { //TODO: throw exception if (typeof(override.limit) == typeof(this.limit) && override.limit != 0) this.limit = override.limit; if (typeof(override.mode) == typeof(this.mode) && override.mode in navigator.device.capture.supportedVideoModes) this.mode = override.mode; } } function CaptureError(code) { if (code) { this.code = code; } else { this.code = CaptureError.CAPTURE_INTERNAL_ERR; } } CaptureError.CAPTURE_INTERNAL_ERR = 0; CaptureError.CAPTURE_APPLICATION_BUSY = 1; CaptureError.CAPTURE_INVALID_ARGUMENT = 2; CaptureError.CAPTURE_NO_MEDIA_FILES = 3; CaptureError.CAPTURE_NOT_SUPPORTED = 4; function MediaFile(name, fullPath, type, lastModifiedDate, size) { if (name) this.name = name; else this.name = ""; if (fullPath) this.fullPath = fullPath; else this.fullPath = ""; if (type) this.type = type; else this.type = ""; if (lastModifiedDate) this.lastModifiedDate = lastModifiedDate; else this.lastModifiedDate = 0; if (size) this.size = size; else this.size = 0; this.getFormatData = function() {} } function MediaFileData(codecs, bitrate, height, width, duration) { if (codecs) this.codecs = codecs; else this.codecs = ""; if (bitrate) this.bitrate = bitrate; else this.bitrate = 0; if (this.height) this.height = height; else this.height = 0; if (this.width) this.width = width; else this.width = 0; if (this.duration) this.duration = duration; else this.duration = 0; } function Capture() { Cordova.deviceready.freeze(); this.supportedAudioModes = []; this.supportedImageModes = []; this.supportedVideoModes = []; var self = this; Cordova.exec(function (audioCodecs, videoCodecs, imageFormats) { self.supportedAudioModes = audioCodecs; self.supportedVideoModes = videoCodecs; self.supportedImageModes = imageFormats; Cordova.deviceready.unfreeze(); }, null, "com.cordova.Capture", "getSupportedFormats", []); } function makeCallback(captureSuccess, captureError) { return function (files) { var i = 0; var result = []; function getFileInfo() { var fileEntry = new FileEntry(); if (files[i].match(/^file:\/\//)) files[i] = files[i].substr('file://'.length); fileEntry.fullPath = files[i]; fileEntry.file(handleFile, function() { captureError(new CaptureError()); }); } function handleFile(file) { result.push(new MediaFile(file.name, file.fullPath, file.type, file.lastModifiedDate, file.size)); if (files.length <= ++i) { captureSuccess(result); } else { getFileInfo(); } } getFileInfo(); }; } Capture.prototype = { captureAudio: function(captureSuccess, captureError, options) { if (typeof(captureError) != 'function') captureError = new Function(); options = new CaptureAudioOptions(options); Cordova.exec(makeCallback(captureSuccess, captureError), function (msg) { if (msg === 'canceled') { captureError(new CaptureError(CaptureError.CAPTURE_NO_MEDIA_FILES)); } else { captureError(new CaptureError(CaptureError.CAPTURE_APPLICATION_BUSY)); } }, "com.cordova.Capture", "startAudioRecordApp", [ options ]); }, captureImage: function(captureSuccess, captureError, options) { if (typeof(captureSuccess) != 'function') return; if (typeof(captureError) != 'function') captureError = new Function(); options = new CaptureImageOptions(options); var cameraOptions = { quality: 75, sourceType: Camera.PictureSourceType.CAMERA, destinationType: Camera.DestinationType.FILE_URI, allowEdit: true, captureAPI: true, encodingType: Camera.EncodingType.JPEG,//FIXME should be options.mode limit: options.limit }; Cordova.exec(makeCallback(captureSuccess, captureError), function (msg) { if (msg === 'canceled') { captureError(new CaptureError(CaptureError.CAPTURE_NO_MEDIA_FILES)); } else { captureError(new CaptureError(CaptureError.CAPTURE_APPLICATION_BUSY)); } }, "com.cordova.Camera", "getPicture", [ cameraOptions ]); }, captureVideo: function(captureSuccess, captureError, options) { if (typeof(captureSuccess) != 'function') return; if (typeof(captureError) != 'function') captureError = new Function(); options = new CaptureImageOptions(options); Cordova.exec(function(files) { console.log(String(files)); }, function (msg) { if (msg === 'canceled') { captureError(new CaptureError(CaptureError.CAPTURE_NO_MEDIA_FILES)); } else { captureError(new CaptureError(CaptureError.CAPTURE_APPLICATION_BUSY)); } }, "com.cordova.Camera", "recordVideo", [ options ]); } }; Cordova.addConstructor("com.cordova.Capture", function () { if (!window.navigator.device) { window.navigator.device = {}; } window.navigator.device.capture = new Capture(); window.MediaFile = MediaFile; window.CaptureError = CaptureError; window.MediaFileData = MediaFileData; window.MediaFile = MediaFile; window.CaptureAudioOptions = CaptureAudioOptions; window.CaptureImageOptions = CaptureImageOptions; window.CaptureVideoOptions = CaptureVideoOptions; }); cordova-ubuntu-2.8.0+14.04.20140130.3/src/js/accelerometer.js0000644000015000001560000000546312272510553023547 0ustar pbuserpbgroup00000000000000/* * Copyright 2011 Integrated Computer Solutions - http://www.ics.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function Acceleration(p_x,p_y,p_z,p_ts) { this.x = p_x || 0; this.y = p_y || 0; this.z = p_z || 0; this.timestamp = p_ts || 0; return this; }; Acceleration.prototype.x = null; Acceleration.prototype.y = null; Acceleration.prototype.z = null; Acceleration.prototype.timestamp = null; Acceleration.cast = function (p_acceleration) { var acceleration = new Acceleration(p_acceleration.x, p_acceleration.y, p_acceleration.z, p_acceleration.timestamp); return acceleration; }; function Accelerometer() { }; Accelerometer.prototype.watchIds = []; Accelerometer.prototype.getCurrentAcceleration = function (successCallback, errorCallback) { if (typeof successCallback !== "function") return; if (typeof errorCallback !== "function") errorCallback = function() {}; Cordova.exec(successCallback, errorCallback, "com.cordova.Accelerometer", "getCurrentAcceleration", [ {} ]); }; Accelerometer.prototype.watchAcceleration = function (successCallback, errorCallback, options) { if (typeof successCallback !== "function") return; if (typeof errorCallback !== "function") errorCallback = function() {}; var watchId = this.watchIds.length + 1; // +1 in order to avoid 0 as watchId this.watchIds[watchId] = true; var frequency=10000; if (options && typeof(options.frequency) === "number") { frequency=options.frequency; } var self = this; function doWatch() { self.getCurrentAcceleration(function (p_acceleration) { if (!self.watchIds[watchId]) return; successCallback(p_acceleration); setTimeout(doWatch, frequency); }, function () { if (!self.watchIds[watchId]) return; errorCallback(p_accelerationError); }); } setTimeout(doWatch, frequency); return watchId; }; Accelerometer.prototype.clearWatch = function(watchId) { this.watchIds[watchId] = false; }; Cordova.addConstructor("com.cordova.Accelerometer", function () { window.Acceleration = Acceleration; navigator.accelerometer = new Accelerometer(); }); cordova-ubuntu-2.8.0+14.04.20140130.3/src/js/notification.js0000644000015000001560000000517712272510553023425 0ustar pbuserpbgroup00000000000000/* * Copyright 2011 Wolfgang Koller - http://www.gofg.at/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ var _notificationBusy = false; function Notification() { } function _showNotificationDialog(method, args, cb) { (function f1() { if (_notificationBusy) { setTimeout(f1, 150); return; } _notificationBusy = true; Cordova.exec(function(id, text) { _notificationBusy = false; cb(id, text); }, null, "com.cordova.Notification", method, args); })(); } Notification.prototype.alert = function(message, alertCallback, title, buttonName) { if (!title) title = "Alert"; if (!buttonName) buttonName = "OK"; this.confirm(message, alertCallback, title, buttonName); } Notification.prototype.confirm = function(message, confirmCallback, title, buttonLabels) { if (!title) title = "Confirm"; if (typeof(buttonLabels) === "string" ) { buttonLabels = buttonLabels.split(',').filter(function(str) {return str.length}); } else { throw new Error("argument error"); } if (!buttonLabels) buttonLabels = ["OK", "Cancel"]; if (buttonLabels.length > 3) throw new Error("unsupported more then 3 buttons"); _showNotificationDialog("confirm", [message, title, buttonLabels], confirmCallback); } Notification.prototype.prompt = function(message, confirmCallback, title, buttonLabels, defaultText) { if (!title) title = "Prompt"; if (!buttonLabels) buttonLabels = ["OK", "Cancel"]; if (buttonLabels.length > 3) throw new Error("unsupported more then 3 buttons"); _showNotificationDialog("prompt", [message, title, buttonLabels, defaultText], confirmCallback); } Notification.prototype.beep = function(times) { Cordova.exec(null, null, "com.cordova.Notification", "beep", [times]); } Notification.prototype.vibrate = function(milliseconds) { Cordova.exec(null, null, "com.cordova.Notification", "vibrate", [milliseconds]); } Cordova.addConstructor("com.cordova.Notification", function () { navigator.notification = new Notification(); }); cordova-ubuntu-2.8.0+14.04.20140130.3/src/js/camera.js0000644000015000001560000000517612272510553022166 0ustar pbuserpbgroup00000000000000/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ function Camera(){ this.DestinationType = Camera.DestinationType; this.PictureSourceType = Camera.PictureSourceType; this.EncodingType = Camera.EncodingType; this.MediaType = Camera.MediaType; return this; } Camera.DestinationType = { DATA_URL : 0, FILE_URI : 1, NATIVE_URI: 2 }; Camera.PictureSourceType = { PHOTOLIBRARY : 0, CAMERA : 1, SAVEDPHOTOALBUM : 2 }; Camera.EncodingType = { JPEG : 0, // Return JPEG encoded image PNG : 1 // Return PNG encoded image }; Camera.MediaType = { PICTURE : 0, VIDEO : 1, ALLMEDIA: 2 }; function CameraOptions(override) { var options = { quality : 75, destinationType : Camera.DestinationType.DATA_URL, sourceType : Camera.PictureSourceType.CAMERA, allowEdit : true, encodingType: Camera.EncodingType.JPEG, targetWidth: 100, targetHeight: 100 }; for (var key in options) { if (!(options.hasOwnProperty(key) && override.hasOwnProperty(key))) continue; if (typeof(options[key]) !== typeof(override[key])) continue; //TODO: check value limits options[key] = override[key]; } options['limit'] = 1; return options; }; Camera.prototype.getPicture = function(successCallback, errorCallback, options) { if (typeof(successCallback) !== "function") return; if (typeof(errorCallback) !== "function") errorCallback = function() {}; if (typeof(options) !== "object") object = {}; Cordova.exec(successCallback, errorCallback, "com.cordova.Camera", "getPicture", [ new CameraOptions(options) ]); }; Cordova.addConstructor("com.cordova.Camera", function () { window.navigator.camera = new Camera(); window.Camera = Camera; }); cordova-ubuntu-2.8.0+14.04.20140130.3/src/js/connection.js0000644000015000001560000000274412272510553023073 0ustar pbuserpbgroup00000000000000/* * Copyright 2011 Wolfgang Koller - http://www.gofg.at/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function Connection() { var self = this; self.type = Connection.UNKNOWN; var first = true; Cordova.deviceready.freeze(); Cordova.exec(function (res) { self.type = res; if (first) { Cordova.deviceready.unfreeze(); first = false; } }, null, "com.cordova.Connection", "getType", []); } Connection.UNKNOWN = "unknown"; Connection.ETHERNET = "ethernet"; Connection.WIFI = "wifi"; Connection.CELL_2G = "2g"; Connection.CELL_3G = "3g"; Connection.CELL_4G = "4g"; Connection.NONE = "none"; Connection.CELL = "cellular"; Cordova.addConstructor("com.cordova.Connection", function() { if (typeof(navigator.network) === "undefined") navigator.network = {}; navigator.network.connection = new Connection(); navigator.connection = navigator.network.connection; window.Connection = Connection; }); cordova-ubuntu-2.8.0+14.04.20140130.3/src/js/app.js0000644000015000001560000000121312272510553021502 0ustar pbuserpbgroup00000000000000 function unsupported() { throw new Error("unsupported"); } App = { loadUrl:function(url, props) { if (typeof(props) !== 'object' || !props.openExternal) throw new Error("unsupported"); Cordova.exec(null, null, "com.cordova.App", "loadUrl", [ url ]); }, closeApp: function() { Cordova.exec(null, null, "com.cordova.App", "exitApp", []); }, cancelLoadUrl: unsupported, clearCache: unsupported, clearHistory: unsupported, backHistory: unsupported, overrideBackbutton: unsupported }; Cordova.addConstructor("com.cordova.App", function() { window.navigator.app = App; }); cordova-ubuntu-2.8.0+14.04.20140130.3/src/js/console.js0000644000015000001560000000155512272510553022375 0ustar pbuserpbgroup00000000000000/* * Copyright 2011 Wolfgang Koller - http://www.gofg.at/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function Console() { } Console.prototype.log = function(p_message) { Cordova.exec(null, null, "com.cordova.Console", "log", [p_message]); } Cordova.addConstructor("com.cordova.Console", function() { window.console = new Console(); }); cordova-ubuntu-2.8.0+14.04.20140130.3/src/js/media.js0000644000015000001560000000622212272510553022006 0ustar pbuserpbgroup00000000000000 var _mediaPlayerLastId = 1; function Media(src, mediaSuccess, mediaError, mediaStatus) { if (typeof(mediaError) !== "function") { mediaError = new Function(); } if (typeof(mediaStatus) !== "function") { mediaStatus = new Function(); } this.src = src; this.id = _mediaPlayerLastId++; this._duration = -1; this._position = -1; this._timeoutId = 0; Cordova.exec(null, mediaError, "com.cordova.Media", "newPlayer", [src, this.id]); Cordova.exec(mediaSuccess, mediaStatus, "com.cordova.Media", "playerSetCallbacks", [ { id: this.id } ]); } Media.prototype = { seekTo: function (position) { if (typeof(position) !== "number") return; Cordova.exec(null, null, "com.cordova.Media", "seekTo", [ { id: this.id, position: position } ]); }, setVolume: function (level) { if (typeof mediaSuccess !== "number") return; Cordova.exec(null, null, "com.cordova.Media", "setVolume", [ { id: this.id, volume: level } ]); }, getCurrentPosition: function (mediaSuccess, mediaError) { if (typeof mediaSuccess !== "function") return; var self = this; Cordova.exec(function (position) { self._position = position; mediaSuccess(position); }, null, "com.cordova.Media", "getCurrentPosition", [ { id: this.id } ]); }, getDuration: function () { var self = this; Cordova.exec(function (duration) { if (duration <= 0 && !self._timeoutId) self._timeoutId = setTimeout(self.getDuration.bind(self), 500); self._duration = duration; }, null, "com.cordova.Media", "getDuration", [ { id: this.id } ]); return this._duration; }, play: function () { this.getDuration(); Cordova.exec(null, null, "com.cordova.Media", "play", [ { id: this.id } ]); }, pause: function () { this.getDuration(); Cordova.exec(null, null, "com.cordova.Media", "pause", [ { id: this.id } ]); }, stop: function () { this.getDuration(); Cordova.exec(null, null, "com.cordova.Media", "stop", [ { id: this.id } ]); }, release: function () { if (this._timeoutId) { this._timeoutId = 0; clearTimeout(this._timeoutId); } Cordova.exec(null, null, "com.cordova.Media", "releasePlayer", [ { id: this.id } ]); }, startRecord: function () { Cordova.exec(null, null, "com.cordova.Media", "startRecording", [ { id: this.id } ]); }, stopRecord: function () { Cordova.exec(null, null, "com.cordova.Media", "stopRecording", [ { id: this.id } ]); } }; Media.MEDIA_NONE = 0; Media.MEDIA_STARTING = 1; Media.MEDIA_RUNNING = 2; Media.MEDIA_PAUSED = 3; Media.MEDIA_STOPPED = 4; function MediaError(code, message) { this.code = code; this.message = message; } MediaError.MEDIA_ERR_NONE_ACTIVE = 0; MediaError.MEDIA_ERR_ABORTED = 1; MediaError.MEDIA_ERR_NETWORK = 2; MediaError.MEDIA_ERR_DECODE = 3; MediaError.MEDIA_ERR_NONE_SUPPORTED = 4; Cordova.addConstructor("com.cordova.Media", function() { window.Media = Media; window.MediaError = MediaError; }); cordova-ubuntu-2.8.0+14.04.20140130.3/src/js/globalization.js0000644000015000001560000001521212272510553023564 0ustar pbuserpbgroup00000000000000 function GlobalizationError(code, message) { this.code = code; this.message = message; } GlobalizationError.UNKNOWN_ERROR = 0; GlobalizationError.FORMATTING_ERROR = 1; GlobalizationError.PARSING_ERROR = 2; GlobalizationError.PATTERN_ERROR = 3; function convertStringToDateOptions(override) { var options = { formatLength: 'short', selector: 'date and time' }; if (override) { for (var key in options) { if (!options.hasOwnProperty(key)) continue; if (typeof(options[key]) !== typeof(override[key])) continue; options[key] = override[key]; } } var formats = ["short", "medium", "long", "full"]; var selectors = ["date", "time", "date and time"]; options.formatLength = formats.indexOf(options.formatLength); options.selector = selectors.indexOf(options.selector); //TODO: throw error if (options.formatLength === -1) options.formatLength = 0; if (options.selector === -1) options.selector = 0; return options; } function convertStringToNumberOptions(override) { var options = { type: 'decimal' }; //TODO: make function if (override) { for (var key in options) { if (!options.hasOwnProperty(key)) continue; if (typeof(options[key]) !== typeof(override[key])) continue; options[key] = override[key]; } } var types = [ 'decimal', 'percent', 'currency' ]; options.type = types.indexOf(options.type); if (options.type === -1) options.type = 0; return options; } function isInt(n) { return n % 1 === 0; } var Globalization = { getPreferredLanguage: function (successCB, errorCB) { Cordova.exec(successCB, null, "com.cordova.Globalization", "getPreferredLanguage", [ { } ]); }, getLocaleName: function (successCB, errorCB) { if (typeof(successCB) != "function") return; successCB({ value: navigator.language.replace('-', '_') }); }, dateToString: function (date, successCB, errorCB, override) { if (!(date instanceof Date)) return; if (typeof(successCB) != "function") return; if (typeof(errorCB) != "function") errorCB = new Function(); var options = convertStringToDateOptions(override); Cordova.exec(successCB, errorCB, "com.cordova.Globalization", "dateToString", [ { time_t: date.getTime(), formatLength: options.formatLength, selector: options.selector } ]); }, stringToDate: function (dateString, successCB, errorCB, override) { if (typeof(dateString) !== 'string') return; if (typeof(successCB) != "function") return; if (typeof(errorCB) != "function") errorCB = new Function(); var options = convertStringToDateOptions(override); Cordova.exec(successCB, errorCB, "com.cordova.Globalization", "stringToDate", [ { dateString: dateString, formatLength: options.formatLength, selector: options.selector } ]); }, getDateNames: function (successCB, errorCB, override) { if (typeof(successCB) != "function") return; if (typeof(errorCB) != "function") errorCB = new Function(); var options = { type: 'wide', item: 'months' }; if (override) { for (var key in options) { if (!options.hasOwnProperty(key)) continue; if (typeof(options[key]) !== typeof(override[key])) continue; options[key] = override[key]; } } var requests = ["days", "months"]; var formats = ["narrow", "wide"]; options.item = requests.indexOf(options.item); options.type = formats.indexOf(options.type); //TODO: throw error if (options.item === -1) options.item = 0; if (options.type === -1) options.type = 0; Cordova.exec(successCB, errorCB, "com.cordova.Globalization", "getDateNames", [ options ]); }, isDayLightSavingsTime: function (date, successCB, errorCB) { if (!(date instanceof Date)) return; Cordova.exec(successCB, errorCB, "com.cordova.Globalization", "isDayLightSavingsTime", [ { time_t: date.getTime() } ]); }, getFirstDayOfWeek: function (successCB, errorCB) { if (typeof(successCB) != "function") return; Cordova.exec(successCB, errorCB, "com.cordova.Globalization", "getFirstDayOfWeek", [ { } ]); }, numberToString: function (number, successCB, errorCB, override) { if (typeof(number) !== "number") return; if (typeof(successCB) !== "function") return; if (typeof(errorCB) !== "function") errorCB = new Function(); var options = convertStringToNumberOptions(override); Cordova.exec(successCB, errorCB, "com.cordova.Globalization", "numberToString", [ { type: options.type, isInt: isInt(number), number: number } ]); }, stringToNumber: function (string, successCB, errorCB, override) { if (typeof(string) !== "string") return; if (typeof(successCB) !== "function") return; if (typeof(errorCB) !== "function") errorCB = new Function(); var options = convertStringToNumberOptions(override); Cordova.exec(successCB, errorCB, "com.cordova.Globalization", "stringToNumber", [ options.type, string ]); }, getNumberPattern: function (successCB, errorCB, override) { if (typeof(successCB) !== "function") return; if (typeof(errorCB) !== "function") errorCB = new Function(); var options = convertStringToNumberOptions(override); Cordova.exec(successCB, errorCB, "com.cordova.Globalization", "getNumberPattern", [ options.type ]); }, getCurrencyPattern: function (currencyCode, successCB, errorCB) { if (typeof(errorCB) !== "function") errorCB = new Function(); //TODO: implement errorCB(new GlobalizationError(GlobalizationError.PATTERN_ERROR, "unimplemented")) }, getDatePattern: function (successCB, errorCB, override) { if (typeof(successCB) !== "function") return; if (typeof(errorCB) !== "function") errorCB = new Function(); var options = convertStringToDateOptions(override); Cordova.exec(successCB, errorCB, "com.cordova.Globalization", "getDatePattern", [ options.formatLength, options.selector ]); } }; Cordova.addConstructor("com.cordova.Globalization", function() { window.GlobalizationError = GlobalizationError; navigator.globalization = Globalization; }); cordova-ubuntu-2.8.0+14.04.20140130.3/src/js/file.js0000644000015000001560000006040612272510553021652 0ustar pbuserpbgroup00000000000000/* * Copyright 2011 Wolfgang Koller - http://www.gofg.at/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function FileError() { } FileError.cast = function(p_code) { var fe = new FileError(); fe.code = p_code; return fe; } FileError.prototype.code = 0; FileError.NOT_FOUND_ERR = 1; FileError.SECURITY_ERR = 2; FileError.ABORT_ERR = 3; FileError.NOT_READABLE_ERR = 4; FileError.ENCODING_ERR = 5; FileError.NO_MODIFICATION_ALLOWED_ERR = 6; FileError.INVALID_STATE_ERR = 7; FileError.SYNTAX_ERR = 8; FileError.INVALID_MODIFICATION_ERR = 9; FileError.QUOTA_EXCEEDED_ERR = 10; FileError.TYPE_MISMATCH_ERR = 11; FileError.PATH_EXISTS_ERR = 12; function FileException() { } FileException.cast = function(p_code) { var fe = new FileException(); fe.code = p_code; return fe; } FileException.prototype.code = 0; FileException.NOT_FOUND_ERR = 1; FileException.SECURITY_ERR = 2; FileException.ABORT_ERR = 3; FileException.NOT_READABLE_ERR = 4; FileException.ENCODING_ERR = 5; FileException.NO_MODIFICATION_ALLOWED_ERR = 6; FileException.INVALID_STATE_ERR = 7; FileException.SYNTAX_ERR = 8; FileException.INVALID_MODIFICATION_ERR = 9; FileException.QUOTA_EXCEEDED_ERR = 10; FileException.TYPE_MISMATCH_ERR = 11; FileException.PATH_EXISTS_ERR = 12; function Metadata(p_modificationDate) { this.modificationTime = p_modificationDate || null; return this; } Metadata.cast = function(p_modificationDate) { var md = new Metadata(p_modificationDate); return md; } function Flags(create, exclusive) { this.create = create || false; this.exclusive = exclusive || false; }; Flags.cast = function(p_modificationDate) { var md = new Metadata(p_modificationDate); return md; } Flags.cast = function(create, exclusive) { var that = new Flags(create, exclusive); return that; }; function Entry() { } Entry.prototype.isFile = false; Entry.prototype.isDirectory = false; Entry.prototype.name = ""; Entry.prototype.fullPath = "";//fullpath for cordova-test = realFullPath - "/" Entry.prototype.filesystem = null; Entry.prototype.getMetadata = function(successCallback, errorCallback) { Cordova.exec(successCallback, errorCallback, "com.cordova.File", "getMetadata", [this.fullPath]); } Entry.prototype.setMetadata = function(successCallback, errorCallback) { //TODO: implement //Cordova.exec(successCallback, errorCallback, "com.cordova.File", "setMetadata", [this.fullPath]); } Entry.prototype.toURL = function(mimeType) { return "file://" + this.fullPath; } Entry.prototype.remove = function(successCallback, errorCallback) { Cordova.exec(successCallback, errorCallback, "com.cordova.File", "remove", [this.fullPath]); } Entry.prototype.getParent = function(successCallback, errorCallback) { Cordova.exec(successCallback, errorCallback, "com.cordova.File", "getParent", [this.fullPath]); } function File(name, fullPath, type, lastModifiedDate, size) { this.name = name || null; this.fullPath = fullPath || null; this.type = type || null; this.lastModifiedDate = lastModifiedDate || null; this.size = size || 0; } File.cast = function(p_name, p_fullPath, p_type, p_lastModifiedDate, p_size) { var f = new File(p_name, p_fullPath, p_type, p_lastModifiedDate, p_size); return f; } File.prototype.slice = function(start, end) { var res = new File(this.name, this.fullPath, this.type, this.lastModifiedDate, this.size); res._sliceStart = start; res._sliceEnd = end; return res; } function FileSaver() { } FileSaver.createEvent = function(p_type, p_target) { var evt = { "type": p_type, "target": p_target }; return evt; } FileSaver.prototype.abort = function() { if (this.readyState == FileSaver.INIT || this.readyState == FileSaver.DONE) throw FileException.cast(FileException.INVALID_STATE_ERR); this.error = FileError.cast(FileError.ABORT_ERR); this.readyState = FileSaver.DONE; if (typeof this.onerror === "function") this.onerror(FileSaver.createEvent("error", this)); if (typeof this.onabort === "function") this.onabort(FileSaver.createEvent("abort", this)); if (typeof this.onwriteend === "function") this.onwriteend(FileSaver.createEvent("writeend", this)); } FileSaver.INIT = 0; FileSaver.WRITING = 1; FileSaver.DONE = 2; FileSaver.prototype.readyState = FileSaver.INIT; FileSaver.prototype.error = new FileError(); FileSaver.prototype.onwritestart = null; FileSaver.prototype.onprogress = null; FileSaver.prototype.onwrite = null; FileSaver.prototype.onabort = null; FileSaver.prototype.onerror = null; FileSaver.prototype.onwriteend = null; function FileWriter(p_file) { this.fullPath = p_file.fullPath || ""; return this; } FileWriter.cast = function(p_fullPath, p_length) { var tmpFile = new File(null,p_fullPath,null, null,null); var fw = new FileWriter(tmpFile); return fw; } FileWriter.prototype = new FileSaver(); FileWriter.prototype.fullPath = ""; FileWriter.prototype.position = 0; FileWriter.prototype.length = 0; FileWriter.prototype._write = function(data, isBinary) { // Check if we are able to write if (this.readyState === FileSaver.WRITING) throw FileException.cast(FileException.INVALID_STATE_ERR); this.readyState = FileSaver.WRITING; if (typeof this.onwritestart === "function") this.onwritestart(FileSaver.createEvent("writestart", this)); var me = this; Cordova.exec(function(p_position, p_length) { me.position = p_position; me.length = p_length; me.readyState = FileSaver.DONE; if (typeof me.onwrite === "function") me.onwrite(FileSaver.createEvent("write", me)); if (typeof me.onwriteend === "function") me.onwriteend(FileSaver.createEvent("writeend", me)); }, function(p_fileError, p_position, p_length) { me.position = p_position; me.length = p_length; me.error = p_fileError; me.readyState = FileSaver.DONE; if (typeof me.onerror === "function") me.onerror(FileWriter.createEvent("error", me)); if (typeof me.onwriteend === "function") me.onwriteend(FileWriter.createEvent("writeend", me)); }, "com.cordova.File", "write", [this.fullPath, this.position, data, isBinary]); } FileWriter.prototype.write = function(data) { if (data instanceof ArrayBuffer) { var binary = ""; for (var i = 0; i < data.byteLength; i++) { binary += String.fromCharCode(data[i]); } this._write(binary, true); } else if ((data instanceof Blob) || (data instanceof File)) { var self = this; var reader = new FileReader(); reader.onloadend = function(evt) { //FIXME: check for error; self._write(evt.target.result, true); } reader.readAsBinaryString(data); } else { this._write(data, false); } } FileWriter.prototype.seek = function(offset) { if (this.readyState === FileSaver.WRITING) throw FileException.cast(FileException.INVALID_STATE_ERR); if (offset < 0) { this.position = Math.max(offset + this.length, 0); } else if (offset > this.length) { this.position = this.length; } else { this.position = offset; } } FileWriter.prototype.truncate = function(size) { // Check if we are able to write if (this.readyState == FileSaver.WRITING) throw FileException.cast(FileException.INVALID_STATE_ERR); this.readyState = FileSaver.WRITING; if (typeof this.onwritestart === "function") this.onwritestart(FileSaver.createEvent("writestart", this)); var me = this; Cordova.exec(function(p_position, p_length) { me.position = p_position; me.length = p_length; me.readyState = FileSaver.DONE; if (typeof me.onwrite === "function") me.onwrite(FileSaver.createEvent("write", me)); if (typeof me.onwriteend === "function") me.onwriteend(FileSaver.createEvent("writeend", me)); }, function(p_fileError, p_position, p_length) { me.position = p_position; me.length = p_length; me.error = p_fileError; me.readyState = FileSaver.DONE; if (typeof me.onerror === "function") me.onerror(FileSaver.createEvent("error", me)); if (typeof me.onwriteend === "function") me.onwriteend(FileSaver.createEvent("writeend", me)); }, "com.cordova.File", "truncate", [this.fullPath, size]); } var originFileReader = window.FileReader; function forwardRequestToOriginalFileReader(source, methodName, file) { var of = new originFileReader(); for (var i in source) { if (source.hasOwnProperty(i)) of[i] = source[i]; } of[methodName](file); } function FileReader() { } FileReader.EMPTY = 0; FileReader.LOADING = 1; FileReader.DONE = 2; FileReader.prototype.readyState = FileReader.EMPTY; FileReader.prototype.result = ""; FileReader.prototype.error = new FileError(); FileReader.prototype.onloadstart = null; FileReader.prototype.onprogress = null; FileReader.prototype.onload = null; FileReader.prototype.onabort = null; FileReader.prototype.onerror = null; FileReader.prototype.onloadend = null; FileReader.prototype.readAsArrayBuffer = function(file) { if (file instanceof Blob) { forwardRequestToOriginalFileReader(this, 'readAsArrayBuffer', file); return; } function strToArray(str) { var res = new Uint8Array(str.length); for (var i = 0; i < str.length; i++) { res[i] = str.charCodeAt(i); } return res; } var origLoadEnd = this.onloadend; var origError = this.onerror; var self = this; function restore() { self.onerror = origError; self.onloadend = origLoadEnd; } this.onloadend = function() { restore(); self.result = strToArray(self.result); origLoadEnd.apply(this, arguments); } this.onerror = function() { restore(); origError.apply(this, arguments); } this.readAsText(file); }; function createReaderFunc(name) { return function(file) { if (file instanceof Blob) { forwardRequestToOriginalFileReader(this, name, file); return; } this.readyState = FileReader.EMPTY; this.result = null; this.readyState = FileReader.LOADING; if (typeof this.onloadstart === "function") this.onloadstart(FileSaver.createEvent("loadstart", this)); var me = this; var sliceStart = 0, sliceEnd = -1/*-1 is undefined*/, sliced = false; if (file._sliceStart !== undefined) { sliceStart = file._sliceStart; if (file._sliceEnd !== undefined) { sliceEnd = file._sliceEnd; if (sliceEnd < 0) sliceEnd--; } sliced = true; } Cordova.exec(function(p_data) { me.readyState = FileReader.DONE; me.result = p_data; if (typeof me.onload === "function") me.onload(FileSaver.createEvent("load", me)); if (typeof me.onloadend === "function") me.onloadend(FileSaver.createEvent("loadend", me)); }, function(p_fileError) { me.readyState = FileReader.DONE; me.result = null; me.error = p_fileError; if (typeof me.onloadend === "function") me.onloadend(FileSaver.createEvent("loadend", me)); if (typeof me.onerror === "function") me.onerror(FileSaver.createEvent("error", me)); }, "com.cordova.File", name, [file.fullPath, sliced, sliceStart, sliceEnd]); }; } FileReader.prototype.readAsBinaryString = createReaderFunc('readAsBinaryString'); FileReader.prototype.readAsText = createReaderFunc('readAsText'); FileReader.prototype.readAsDataURL = createReaderFunc('readAsDataURL'); FileReader.prototype.abort = function() { this.readyState = FileReader.DONE; this.result = null; this.error = FileError.cast(FileError.ABORT_ERR); if (typeof this.onerror === "function") this.onerror(FileSaver.createEvent("error", me)) ; if (typeof this.onabort === "function") this.onabort(FileSaver.createEvent("abort", me)) ; if (typeof this.onloadend === "function") this.onloadend(FileSaver.createEvent("loadend", me)) ; } function FileEntry() { this.isFile = true; this.isDirectory = false; } FileEntry.cast = function(filename, path) { var fe = new FileEntry(); fe.name = filename; fe.fullPath = path; return fe; } FileEntry.prototype = new Entry(); FileEntry.prototype.createWriter = function(successCallback, errorCallback) { this.file(function(p_file) { successCallback(FileWriter.cast(p_file.fullPath, p_file.size)); }, errorCallback); } FileEntry.prototype.file = function(successCallback, errorCallback) { // Lets get the fileinfo Cordova.exec(successCallback, errorCallback, "com.cordova.File", "file", [this.fullPath]); } FileEntry.prototype.copyTo = function(parent, newName, successCallback, errorCallback) { Cordova.exec(successCallback, errorCallback, "com.cordova.File", "copyFile", [this.fullPath, parent.fullPath, newName]); }; FileEntry.prototype.moveTo = function(parent, newName, successCallback, errorCallback) { Cordova.exec(successCallback, errorCallback, "com.cordova.File", "moveFile", [this.fullPath, parent.fullPath, newName]); }; function DirectoryReader() { } DirectoryReader.cast = function(p_fullPath) { var dr = new DirectoryReader(); dr.fullPath = p_fullPath; return dr; } DirectoryReader.prototype.fullPath = ""; DirectoryReader.prototype.readEntries = function(successCallback, errorCallback) { if (this._used) { try { successCallback([]); } catch (e) {} return; } this._used = true; Cordova.exec(successCallback, errorCallback, "com.cordova.File", "readEntries", [this.fullPath]); } function DirectoryEntry() { this.isFile = false; this.isDirectory = true; } DirectoryEntry.cast = function(dirname, path) { var de = new DirectoryEntry(); de.name = dirname; de.fullPath = path; return de; } DirectoryEntry.prototype = new Entry(); DirectoryEntry.prototype.createReader = function() { return DirectoryReader.cast(this.fullPath); } DirectoryEntry.prototype.getFile = function(path, options, successCallback, errorCallback) { var requestPath = path; if (requestPath.charAt(0) !== '/') requestPath = this.fullPath + "/" + requestPath; Cordova.exec(successCallback, errorCallback, "com.cordova.File", "getFile", [requestPath, options]); } DirectoryEntry.prototype.getDirectory = function(path, options, successCallback, errorCallback) { var requestPath = path; // Check for a relative path if (requestPath.charAt(0) != '/') requestPath = this.fullPath + "/" + requestPath; Cordova.exec(successCallback, errorCallback, "com.cordova.File", "getDirectory", [requestPath, options]); } DirectoryEntry.prototype.removeRecursively = function(successCallback, errorCallback) { Cordova.exec(successCallback, errorCallback, "com.cordova.File", "removeRecursively", [this.fullPath]); } DirectoryEntry.prototype.copyTo = function(parent, newName, successCallback, errorCallback) { Cordova.exec(successCallback, errorCallback, "com.cordova.File", "copyDir", [this.fullPath, parent.fullPath, newName]); }; DirectoryEntry.prototype.moveTo = function(parent, newName, successCallback, errorCallback) { Cordova.exec(successCallback, errorCallback, "com.cordova.File", "moveDir", [this.fullPath, parent.fullPath, newName]); }; function FileSystem() { } FileSystem.cast = function(fsname, dirname, path) { var fs = new FileSystem(); fs.name = fsname; fs.root = DirectoryEntry.cast(dirname, path); return fs; } FileSystem.prototype.name = ""; FileSystem.prototype.root = null; // Should be a DirectoryEntry function LocalFileSystem() { } LocalFileSystem.TEMPORARY = 0; LocalFileSystem.PERSISTENT = 1; LocalFileSystem.prototype.requestFileSystem = function(type, size, successCallback, errorCallback) { Cordova.exec(successCallback, errorCallback, "com.cordova.File", "requestFileSystem", [type,size]); } LocalFileSystem.prototype.resolveLocalFileSystemURL = function(url, successCallback, errorCallback) { Cordova.exec(successCallback, errorCallback, "com.cordova.File", "resolveLocalFileSystemURL", [url]); } function FileUploadOptions() { this.fileKey = "file"; this.fileName = "image.jpg"; this.mimeType = "image/jpeg"; this.params = {}; this.chunkedMode = true; this.headers = {}; } function FileUploadResult() { this.bytesSent = 0; this.responseCode = 400; this.response = ""; } function FileTransferError(code, source, target, http_status) { this.code = code; this.source = source; this.target = target; this.http_status = http_status; } FileTransferError.FILE_NOT_FOUND_ERR = 1; FileTransferError.INVALID_URL_ERR = 2; FileTransferError.CONNECTION_ERR = 3; FileTransferError.ABORT_ERR = 4; function FileTransfer() { //TODO: implement onprogress var self = this; this._id = 0; this._callQueue = []; this._aborted = 0; this._callNum = 0; Cordova.exec(function (id) { Cordova.exec(function(loaded, total) { if (typeof(self.onprogress) === 'function') { self.onprogress({ lengthComputable: total > 0, total: total, loaded: loaded }); } }, null, "com.cordova.File", "transferRequestSetOnProgress", [ id ]); self._id = id; for (var i = 0; i < self._callQueue.length; i++) { self._callQueue[i](); } delete self._callQueue; }, null, "com.cordova.File", "newTransferRequest", [ ]); } FileTransfer.prototype = { upload: function(filePath, server, successCallback, errorCallback, override, trustAllHosts) { var self = this; if (this._id === 0) { var args = arguments; this._callQueue.push(function () { self.upload.apply(self, args); }); return; } var callNum = ++this._callNum; if (typeof(successCallback) !== "function") return; if (typeof(errorCallback) !== "function") errorCallback = new Function(); if (typeof(override) !== "object") override = {}; var options = new FileUploadOptions(); for (var key in options) { if (!(options.hasOwnProperty(key) && override.hasOwnProperty(key))) continue; if (typeof(options[key]) !== typeof(override[key])) continue; //TODO: check value limits options[key] = override[key]; } for (var key in options.params) { if (!options.params.hasOwnProperty(key)) continue; options.params[key] = String(options.params[key]); } for (var key in options.headers) { if (!options.headers.hasOwnProperty(key)) continue; if (options.headers[key] instanceof Array) { var array = options.headers[key]; for (var i = 0; i < array.length; i++) { array[i] = String(array[i]); } options.headers[key] = array.join(', '); } else { options.headers[key] = String(options.headers[key]); } } var file = new File(null, filePath); var reader = new FileReader(); reader.onerror = function () { errorCallback(new FileTransferError(FileTransferError.FILE_NOT_FOUND_ERR, filePath, server, 0)); }; reader.readAsDataURL(file); reader.onloadend = function () { if (!reader.result) return; if (self._aborted > callNum) { errorCallback(new FileTransferError(FileTransferError.ABORT_ERR, filePath, server, 0)); return; } var match = reader.result.match(/^data:[^;]*;base64,(.+)$/); if (match) { //FIXME: stack overflow with large files Cordova.exec(function(status, response) { successCallback({ bytesSent: match[1].length, responseCode: status, response: response }); }, function (status) { if (status === "abort") { errorCallback(new FileTransferError(FileTransferError.ABORT_ERR, filePath, server, 0)); } else if (status === "invalidUrl") { errorCallback(new FileTransferError(FileTransferError.INVALID_URL_ERR, filePath, server, 0)); } else { errorCallback(new FileTransferError(FileTransferError.CONNECTION_ERR, filePath, server, status)); } }, "com.cordova.File", "uploadFile", [self._id, server, atob(match[1]), options["fileKey"], options["fileName"], options["mimeType"], options.params, options.headers]); } } }, download: function(source, target, successCallback, errorCallback, trustAllHosts) { var self = this; if (this._id === 0) { var args = arguments; this._callQueue.push(function () { self.download.apply(self, args); }); return; } if (typeof(successCallback) !== "function") return; if (typeof(errorCallback) !== "function") errorCallback = new Function(); ++this._callNum; Cordova.exec(function(data) { window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fileSystem) { fileSystem.root.getFile(target, {create: true, exclusive: false}, function (fileEntry) { fileEntry.createWriter(function (writer) { writer.onwriteend = function () { successCallback(fileEntry); } writer.onerror = errorCallback; writer._write(atob(data), true); }, errorCallback); }, function () { errorCallback(new FileTransferError(FileTransferError.FILE_NOT_FOUND_ERR, source, target, 0)); }); }, errorCallback); }, function (status, body) { var error; if (status === "abort") { error = new FileTransferError(FileTransferError.ABORT_ERR, source, target, 0); } else if (status === "invalidUrl") { error = new FileTransferError(FileTransferError.INVALID_URL_ERR, source, target, 0); } else { error = new FileTransferError(FileTransferError.CONNECTION_ERR, source, target, status); } if (body) { error.body = atob(body); } errorCallback(error); }, "com.cordova.File", "downloadFile", [this._id, source]); }, abort: function() { if (this._id === 0) { var args = arguments; var self = this; this._callQueue.push(function () { self.abort.apply(self, args); }); return; } this._aborted = ++this._callNum; Cordova.exec(null, null, "com.cordova.File", "abortRequests", [this._id]); } }; Cordova.addConstructor("com.cordova.File", function () { var localFileSystem = new LocalFileSystem(); window.requestFileSystem = localFileSystem.requestFileSystem; window.resolveLocalFileSystemURI = localFileSystem.resolveLocalFileSystemURL; window.FileUploadOptions = FileUploadOptions; window.FileTransfer = FileTransfer; window.FileTransferError = FileTransferError; window.FileError = FileError; window.FileReader = FileReader; window.FileWriter = FileWriter; window.File = File; window.LocalFileSystem = LocalFileSystem; window.FileEntry = FileEntry; window.DirectoryEntry = DirectoryEntry; window.DirectoryReader = DirectoryReader; window.FileSystem = FileSystem; window.FileEntry = FileEntry; window.Flags = Flags; window.Metadata = Metadata; window.FileException = FileException; }); cordova-ubuntu-2.8.0+14.04.20140130.3/src/js/cordova.qt.js0000644000015000001560000000317712272510553023015 0ustar pbuserpbgroup00000000000000/* * Copyright 2011 Wolfgang Koller - http://www.gofg.at/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ Cordova.Qt = {}; var callbackId = 1; /** * Execute a call to a plugin function * @return bool true on success, false on error (e.g. function doesn't exist) */ Cordova.Qt.exec = function(successCallback, errorCallback, pluginName, functionName, parameters) { // Check if plugin is enabled if (Cordova.plugins[pluginName] !== true) { return false; } if (callbackId % 2) { callbackId++; } // Store a reference to the callback functions var scId = callbackId++; var ecId = callbackId++; Cordova.callbacks[scId] = successCallback; Cordova.callbacks[ecId] = errorCallback; parameters.unshift(ecId); parameters.unshift(scId); navigator.qt.postMessage(JSON.stringify({messageType: "callPluginFunction", plugin: pluginName, func: functionName, params: parameters})) return true; } Cordova.Qt.objects = {}; Cordova.Qt.registerObject = function(pluginName, pluginObject) { Cordova.Qt.objects[pluginName] = pluginObject; } Cordova.exec = Cordova.Qt.exec; cordova-ubuntu-2.8.0+14.04.20140130.3/src/js/contacts.js0000644000015000001560000002411312272510553022544 0ustar pbuserpbgroup00000000000000/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ function ContactAddress(pref, type, formatted, streetAddress, locality, region, postalCode, country) { if (pref) this.pref = pref; if (type) this.type = type; if (formatted) this.formatted = formatted; if (streetAddress) this.streetAddress = streetAddress; if (locality) this.locality = locality; if (region) this.region = region; if (postalCode) this.postalCode = postalCode; if (country) this.country = country; } ContactAddress.create = function(obj) { var result = new ContactAddress() result.pref = obj.pref result.type = obj.type result.formatted = obj.formatted result.streetAddress = obj.streetAddress result.locality = obj.streetLocality result.region = obj.region result.postalCode = obj.postalCode result.country = obj.country return result } ContactAddress.prototype = { pref: false, type: "", formatted: "", streetAddress: "", locality: "", region: "", postalCode: "", country: "" }; function ContactField(type, value, pref) { this.type = String(type); this.value = String(value); this.pref = pref; } ContactField.create = function(obj) { var result = new ContactField() result.type = obj.type; result.value = obj.value; result.pref = obj.pref; return result; } ContactField.prototype = { type: "", value: "", pref: false }; function ContactFindOptions(filter, multiple) { if (filter) this.filter = filter; if (multiple) this.multiple = multiple; } ContactFindOptions.create = function(obj) { var result = new ContactFindOptions(); result.filter = obj.filter; result.multiple = obj.multiple; return result; } ContactFindOptions.prototype.filter = ""; ContactFindOptions.prototype.multiple = false; function ContactName(formatted, familyName, givenName, middleName, honorificPrefix, honorificSuffix) { if (formatted) this.formatted = formatted; if (familyName) this.familyName = familyName; if (givenName) this.givenName = givenName; if (middleName) this.middleName = middleName; if (honorificPrefix) this.honorificPrefix = honorificPrefix; if (honorificSuffix) this.honorificSuffix = honorificSuffix; } ContactName.create = function(obj) { var result = new ContactName() result.familyName = obj.familyName result.givenName = obj.givenName result.formatted = obj.formatted result.middleName = obj.middleName result.honorificPrefix = obj.honorificPrefix result.honorificSuffix = obj.honorificSuffix var formattedArr = [] if (typeof result.honorificPrefix === 'undefined') result.honorificPrefix = ""; else if (result.honorificPrefix !== "") formattedArr.push(result.honorificPrefix); if (typeof result.givenName === 'undefined') result.givenName = ""; else if (result.givenName !== "") formattedArr.push(result.givenName); if (typeof result.middleName === 'undefined') result.middleName = ""; else if (result.middleName !== "") formattedArr.push(result.middleName); if (typeof result.familyName == 'undefined') result.familyName = ""; else if (result.familyName !== "") formattedArr.push(result.familyName); if (typeof result.honorificSuffix == 'undefined') result.honorificSuffix = ""; else if (result.honorificSuffix !== "") formattedArr.push(result.honorificSuffix); return result; } ContactName.prototype = { formatted: "", familyName: "", givenName: "", middleName: "", honorificPrefix: "", honorificSuffix: "" }; function ContactOrganization(pref, type, name, department, title) { if (pref) this.pref = pref; if (type) this.type = type; if (name) this.name = name; if (department) this.department = department; if (title) this.title = title; } ContactOrganization.create = function(obj) { var result = new ContactOrganization() result.pref = obj.pref result.type = obj.type result.name = obj.name result.department = obj.department result.title = obj.title return result } ContactOrganization.prototype = { pref: false, type: "", name: "", department: "", title: "" }; function ContactError(code) { if (code) this.code = code; } ContactError.UNKNOWN_ERROR = 0; ContactError.INVALID_ARGUMENT_ERROR = 1; ContactError.TIMEOUT_ERROR = 2; ContactError.PENDING_OPERATION_ERROR = 3; ContactError.IO_ERROR = 4; ContactError.NOT_SUPPORTED_ERROR = 5; ContactError.PERMISSION_DENIED_ERROR = 20; ContactError.prototype.code = ContactError.UNKNOWN_ERROR function Contact(p_id, p_displayName, p_name, p_nickname, p_phoneNumbers, p_emails, p_addresses, p_ims, p_organizations, p_birthday, p_note, p_photos, p_categories, p_urls) { this.id = p_id || ""; this.displayName = p_displayName || ""; if (typeof(p_name) == 'object') { this.name = ContactName.create(p_name); } else { this.name = new ContactName(); } this.nickname = p_nickname || ""; this.phoneNumbers = p_phoneNumbers || null; this.emails = p_emails || null; this.addresses = p_addresses || null; this.ims = p_ims || null; this.organizations = p_organizations || null; this.birthday = p_birthday || ""; this.note = p_note || ""; this.photos = p_photos || null; this.categories = p_categories || null; this.urls = p_urls || null; } Contact.create = function(obj) { var result = new Contact(); result.id = obj.id; result.displayName = obj.displayName; result.name = ContactName.create(obj.name); result.nickname = obj.nickname || null; var subObj; if (obj.phoneNumbers) result.phoneNumbers = []; for (subObj in obj.phoneNumbers) result.phoneNumbers.push(ContactField.create(obj.phoneNumbers[subObj])); if (obj.emails) result.emails = []; for (subObj in obj.emails) result.emails.push(ContactField.create(obj.emails[subObj])); if (obj.addresses) result.addresses = []; for (subObj in obj.addresses) result.addresses.push(ContactAddress.create(obj.addresses[subObj])); if (obj.ims) result.ims = []; for (subObj in obj.ims) result.ims.push(ContactField.create(obj.ims[subObj])); if (obj.organizations) result.organizations = []; for (subObj in obj.organizations) result.organizations.push(ContactOrganization.create(obj.organizations[subObj])); result.birthday = obj.birthday; result.note = obj.note; result.gender = obj.gender; if (obj.photos) result.photos = []; for (subObj in obj.photos) result.photos.push(ContactField.create(obj.photos[subObj])); if (obj.categories) result.categories = []; for (subObj in obj.categories) result.categories.push(ContactField.create(obj.categories[subObj])); if (obj.urls) result.urls = []; for (subObj in obj.urls) result.urls.push(ContactField.create(obj.urls[subObj])); return result; } Contact.prototype = { id: null, displayName: "", nickname: "", note: "" }; Contact.prototype.clone = function() { var newContact = Contact.create(this); newContact.id = null; return newContact; } Contact.prototype.remove = function(contactSuccess, contactError) { if (typeof(contactSuccess) !== "function") contactSuccess = function() {} if (typeof(contactError) !== "function") contactError = function() {} if (!this.id) { contactError(new ContactError(ContactError.UNKNOWN_ERROR)); return; } Cordova.exec(contactSuccess, contactError, "com.cordova.Contacts", "removeContact", [ this.id ]); } Contact.prototype.save = function(contactSuccess,contactError) { if (typeof(contactSuccess) !== "function") contactSuccess = function() {} if (typeof(contactError) !== "function") contactError = function() {} var clone = this.clone(); clone.id = this.id; if (clone.birthday) clone.birthday = clone.birthday.getTime(); Cordova.exec(contactSuccess, contactError, "com.cordova.Contacts", "saveContact", [ clone ]); } function ContactsManager() { } ContactsManager.prototype.create = function(properties) { return Contact.create(properties); } ContactsManager.prototype.find = function(contactFields, contactSuccess, contactError, contactFindOptions) { if (typeof contactSuccess !== "function") {throw "no callback";} if (typeof contactError !== "function") { contactError = function() {} } Cordova.exec(contactSuccess, contactError, "com.cordova.Contacts", "findContacts", [ contactFields, contactFindOptions.filter, contactFindOptions.multiple ]) } Cordova.addConstructor("com.cordova.Contacts", function () { navigator.contacts = new ContactsManager() window.ContactFindOptions = ContactFindOptions; window.Contact = Contact; window.ContactName = ContactName; window.ContactField = ContactField; window.ContactAddress = ContactAddress; window.ContactOrganization = ContactOrganization; window.ContactError = ContactError; }); cordova-ubuntu-2.8.0+14.04.20140130.3/src/js/geolocation.js0000644000015000001560000001436612272510553023242 0ustar pbuserpbgroup00000000000000/* * Copyright 2011 Wolfgang Koller - http://www.gofg.at/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function Coordinates() { }; Coordinates.cast = function (p_latitude, p_longitude, p_altitude, p_accuracy, p_altitudeAccuracy, p_heading, p_speed) { var coordinates = new Coordinates(); coordinates.latitude = p_latitude; coordinates.longitude = p_longitude; coordinates.altitude = p_altitude; coordinates.accuracy = p_accuracy; coordinates.altitudeAccuracy = p_altitudeAccuracy; coordinates.heading = p_heading; coordinates.speed = p_speed; return coordinates; }; Coordinates.prototype.latitude = 0; Coordinates.prototype.longitude = 0; Coordinates.prototype.altitude = 0; Coordinates.prototype.accuracy = 0; Coordinates.prototype.altitudeAccuracy = 0; Coordinates.prototype.heading = 0; Coordinates.prototype.speed = 0; function Position() { }; Position.cast = function (p_coords, p_timestamp) { // The timestamp is optional and can be auto-generated on creation if (typeof p_timestamp === "undefined") p_timestamp = (new Date()).getMilliseconds(); var position = new Position(); position.coords = p_coords; position.timestamp = p_timestamp; return position; }; Position.prototype.coords = null; Position.prototype.timestamp = 0; function PositionError() { }; PositionError.cast = function(p_code, p_message) { var positionError = new PositionError(); positionError.code = p_code; positionError.message = p_message; return positionError; }; PositionError.PERMISSION_DENIED = 1; PositionError.POSITION_UNAVAILABLE = 2; PositionError.TIMEOUT = 3; PositionError.prototype.code = 0; PositionError.prototype.message = ""; function PositionOptions() { }; PositionOptions.prototype.enableHighAccuracy = false; PositionOptions.prototype.timeout = -1; // Timeout by default negative, which means no timeout PositionOptions.prototype.maximumAge = 0; function Geolocation() { }; Geolocation.prototype.watchIds = []; Geolocation.prototype.cachedPosition = null; Geolocation.prototype.getCurrentPosition = function (successCallback, errorCallback, options) { // Check the callbacks if (typeof successCallback !== "function") return; if (typeof errorCallback !== "function") errorCallback = function() {}; // This is a workaround as we allow passing any object in as options (for convenience) var positionOptions = new PositionOptions(); if (typeof options.maximumAge !== "undefined" && options.maximumAge > 0) positionOptions.maximumAge = options.maximumAge; if (typeof options.timeout !== "undefined") { if (options.timeout > 0) { positionOptions.timeout = options.timeout; } else { positionOptions.timeout = 0; } } if (typeof options.enableHighAccuracy !== "undefined") positionOptions.enableHighAccuracy = options.enableHighAccuracy; // Check if the cached object is sufficient if (this.cachedPosition !== null && this.cachedPosition.timestamp > ((new Date()).getTime() - positionOptions.maximumAge)) { successCallback(this.cachedPosition); return; } // Check if the timeout is 0, if yes invoke the ErrorCallback immediately if (positionOptions.timeout === 0) { errorCallback(PositionError.cast(PositionError.TIMEOUT, "Timeout")); return; } var timedOut = false; // Flag for indicating a timeout var timeoutId = 0; // Flag for indicating a successful location receive if (options.timeout > 0) { timeoutId = window.setTimeout(function() { // Request timed out, set status and execute errorCallback timedOut = true; timeoutId = 0; errorCallback(PositionError.cast(PositionError.TIMEOUT, "Timeout")); }, options.timeout); } // Call the native function and query for a new position var me = this; Cordova.exec(function(p_position) { received = true; if (timeoutId > 0) { window.clearTimeout(timeoutId); } // Cache the new position me.cachedPosition = p_position; // Execute the successCallback if not timed out if (!timedOut) successCallback(p_position); }, errorCallback, "com.cordova.Geolocation", "getCurrentPosition", [ positionOptions ]); }; Geolocation.prototype.watchPosition = function(successCallback, errorCallback, options) { // Check the callbacks if (typeof successCallback !== "function") return; if (typeof errorCallback !== "function") errorCallback = function() {}; var watchId = this.watchIds.length + 1; // +1 in order to avoid 0 as watchId this.watchIds[watchId] = true; var me = this; function doWatch() { me.getCurrentPosition(function(p_position) { if (!me.watchIds[watchId]) return; successCallback(p_position); // Wait some time before starting again setTimeout(doWatch, 100); }, function(p_positionError) { if (!me.watchIds[watchId]) return; errorCallback(p_positionError); // Wait some time before starting again setTimeout(doWatch, 100); }, options); } // Start watching for position changes (slight delay, in order to simulate asynchronous behaviour) setTimeout(doWatch, 100); return watchId; }; Geolocation.prototype.clearWatch = function(watchId) { this.watchIds[watchId] = false; }; Cordova.addConstructor("com.cordova.Geolocation", function () { // HACK: webkit doesn't allow replacing of navigator.geolocation function Navigator() { } Navigator.prototype = navigator; window.navigator = new Navigator(); navigator.geolocation = new Geolocation(); window.Position = Position; window.Coordinates = Coordinates; }); cordova-ubuntu-2.8.0+14.04.20140130.3/src/js/cordova.js0000644000015000001560000001741412272510553022371 0ustar pbuserpbgroup00000000000000/* * Copyright 2011 Wolfgang Koller - http://www.gofg.at/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ window.Cordova = { plugins: {}, constructors: {}, callbacks: {}, }; Cordova.callback = function() { var scId = arguments[0]; var callbackRef = null; var parameters = []; for (var i = 1; i < arguments.length; i++) { parameters[i-1] = arguments[i]; } callbackRef = Cordova.callbacks[scId]; // Even IDs are success-, odd are error-callbacks - make sure we remove both if ((scId % 2) !== 0) { scId = scId - 1; } // Remove both the success as well as the error callback from the stack delete Cordova.callbacks[scId]; delete Cordova.callbacks[scId + 1]; if (typeof callbackRef == "function") callbackRef.apply(this, parameters); }; Cordova.callbackWithoutRemove = function() { var scId = arguments[0]; var callbackRef = null; var parameters = []; for (var i = 1; i < arguments.length; i++) { parameters[i-1] = arguments[i]; } callbackRef = Cordova.callbacks[scId]; if (typeof(callbackRef) == "function") callbackRef.apply(this, parameters); }; Cordova.enablePlugin = function (pluginName) { Cordova.plugins[pluginName] = true; if (typeof Cordova.constructors[pluginName] === "function") Cordova.constructors[pluginName](); } Cordova.addConstructor = function(pluginName, constructor) { Cordova.constructors[pluginName] = constructor; } Cordova.Event = function() { }; Cordova.Event.CAPTURING_PHASE = 1; Cordova.Event.AT_TARGET = 2; Cordova.Event.BUBBLING_PHASE = 3; Cordova.Event.prototype.type = "unknown"; Cordova.Event.prototype.target = Cordova; Cordova.Event.prototype.currentTarget = Cordova; Cordova.Event.prototype.eventPhase = Cordova.Event.AT_TARGET; Cordova.Event.prototype.bubbles = false; Cordova.Event.prototype.cancelable = false; Cordova.Event.prototype.timeStamp = 0; Cordova.Event.prototype.stopPropagation = function() {}; Cordova.Event.prototype.preventDefault = function() {}; Cordova.Event.prototype.initEvent = function (eventTypeArg, canBubbleArg, cancelableArg) { this.type = eventTypeArg; this.timeStamp = (new Date()).getMilliseconds(); }; Cordova.EventHandler = function(p_type) { this.type = p_type this.listeners = [] } Cordova.EventHandler.prototype.type = "unknown"; Cordova.EventHandler.prototype.listeners = []; Cordova.EventHandler.prototype.addEventListener = function(p_listener, p_capture) { if (p_capture) { this.listeners.unshift(p_listener); } else { this.listeners.push(p_listener); } }; Cordova.EventHandler.prototype.removeEventListener = function(p_listener, p_capture) { for (var i = 0; i < this.listeners.length; i++) { if (this.listeners[i] === p_listener) { this.listeners.splice(i, 1); break; } } }; Cordova.EventHandler.prototype.dispatchEvent = function() { var event = new Cordova.Event(); event.initEvent(this.type, false, false); for (var i = 0; i < this.listeners.length; i++) { this.listeners[i].apply(Cordova, arguments); } }; Cordova.events = { deviceready: new Cordova.EventHandler("deviceready"), resume: new Cordova.EventHandler("resume"), pause: new Cordova.EventHandler("pause"), online: new Cordova.EventHandler("online"), offline: new Cordova.EventHandler("offline"), backbutton: new Cordova.EventHandler("backbutton"), batterycritical: new Cordova.EventHandler("batterycritical"), batterylow: new Cordova.EventHandler("batterylow"), batterystatus: new Cordova.EventHandler("batterystatus"), menubutton: new Cordova.EventHandler("menubutton"), searchbutton: new Cordova.EventHandler("searchbutton"), startcallbutton: new Cordova.EventHandler("startcallbutton"), endcallbutton: new Cordova.EventHandler("endcallbutton"), volumedownbutton: new Cordova.EventHandler("volumedownbutton"), volumeupbutton: new Cordova.EventHandler("volumeupbutton") }; //Keep references to the original EventTarget implementations Cordova.doc_addEventListener = document.addEventListener; Cordova.doc_removeEventListener = document.removeEventListener; Cordova.doc_dispatchEvent = document.dispatchEvent; document.addEventListener = function(type, listener, useCapture) { if (typeof Cordova.events[type] !== "undefined") { Cordova.events[type].addEventListener(listener, useCapture); } else { Cordova.doc_addEventListener.call(document, type, listener, useCapture); } }; document.removeEventListener = function(type, listener, useCapture) { if (typeof Cordova.events[type] !== "undefined") { Cordova.events[type].removeEventListener(listener, useCapture); } else { Cordova.doc_removeEventListener.call(document, type, listener, useCapture); } }; document.dispatchEvent = function (evt) { if (typeof Cordova.events[evt.type] !== "undefined") { Cordova.events[evt.type].dispatchEvent(); } else { Cordova.doc_dispatchEvent.call(document, evt); } }; var deviceReadyCounter = 0; var isDeviceReady = false; Cordova.deviceready = function() { isDeviceReady = true; if (!deviceReadyCounter) { Cordova.events.deviceready.dispatchEvent(); } } Cordova.deviceready.freeze = function() { if (isDeviceReady && !deviceReadyCounter) { console.log('WARNING: trying freeze deviceready event after it was emited'); } deviceReadyCounter++; } Cordova.deviceready.unfreeze = function() { deviceReadyCounter--; if (!deviceReadyCounter && isDeviceReady) { Cordova.deviceready(); } } Cordova.resumeOccured = function() { Cordova.events.resume.dispatchEvent(); } Cordova.pauseOccured = function() { Cordova.events.pause.dispatchEvent(); } Cordova.onlineOccured = function() { Cordova.events.online.dispatchEvent(); } Cordova.offlineOccured = function() { Cordova.events.offline.dispatchEvent(); } navigator.battery = { _level: null, _isPlugged: null }; Cordova.batteryStatusChanged = function(level, isPlugged, forceStatus) { if (navigator.battery._level === level && navigator.battery._isPlugged === isPlugged) return; console.log("Cordova.batteryStatusChanged: " + level + ", " + isPlugged + ", " + forceStatus) if (level < 3 && !forceStatus) Cordova.events.batterycritical.dispatchEvent({level: level, isPlugged: isPlugged}) else if (level < 40 && !forceStatus) Cordova.events.batterylow.dispatchEvent({level: level, isPlugged: isPlugged}) Cordova.events.batterystatus.dispatchEvent({level: level, isPlugged: isPlugged}) navigator.battery._level = level; navigator.battery._isPlugged = isPlugged; } Cordova.menuKeyPressed = function() { Cordova.events.menubutton.dispatchEvent(); } Cordova.backKeyPressed = function() { Cordova.events.backbutton.dispatchEvent(); } Cordova.searchKeyPressed = function() { Cordova.events.searchbutton.dispatchEvent(); } Cordova.callKeyPressed = function() { Cordova.events.startcallbutton.dispatchEvent(); } Cordova.hangupKeyPressed = function() { Cordova.events.endcallbutton.dispatchEvent(); } Cordova.volumeUpKeyPressed = function() { Cordova.events.volumeupbutton.dispatchEvent(); } Cordova.volumeDownKeyPressed = function() { Cordova.events.volumedownbutton.dispatchEvent(); } cordova-ubuntu-2.8.0+14.04.20140130.3/src/js/inappbrowser.js0000644000015000001560000000302412272510553023437 0ustar pbuserpbgroup00000000000000var systemWindowOpen = null; function openBrowser(url, target, options) { if (!url || typeof(url) != "string") return; if (!target || typeof(target) != "string") target = "_self"; if (!options || typeof(options) != "string") options = "location=yes"; if (target === "_self") { systemWindowOpen(url, "_self"); return; } if (target === "_system") { // TODO: don't allow relative url Cordova.exec(null, null, "com.cordova.App", "loadUrl", [ url ]); return; } var ref = { events: { loadstart: new Cordova.EventHandler("loadstart"), loadend: new Cordova.EventHandler("loadend"), close: new Cordova.EventHandler("close") }, addEventListener: function(eventname, callback) { ref.events[eventname].addEventListener(callback); }, removeEventListener: function(eventname, callback) { ref.events[eventname].removeEventListener(callback); }, close: function() { Cordova.exec(null, null, "com.cordova.InAppBrowser", "close", [ url ]); } }; Cordova.exec(function() { ref.events.loadend.dispatchEvent() }, function() { ref.events.close.dispatchEvent() }, "com.cordova.InAppBrowser", "loadUrl", [ url ]); return ref; } Cordova.addConstructor("com.cordova.InAppBrowser", function () { if (systemWindowOpen) return; systemWindowOpen = window.open; window.open = openBrowser; }); cordova-ubuntu-2.8.0+14.04.20140130.3/src/cordova.h0000644000015000001560000000603612272510553021566 0ustar pbuserpbgroup00000000000000/* * Copyright 2011 Wolfgang Koller - http://www.gofg.at/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef CORDOVA_H_DJJKASDM44 #define CORDOVA_H_DJJKASDM44 #include #include #include "cplugin.h" class QQuickView; class QQuickItem; class Cordova: public QObject { Q_OBJECT Q_PROPERTY(QString mainUrl READ mainUrl CONSTANT) public: explicit Cordova(QDir wwwDir, QQuickItem *item, QObject *parent = nullptr); QString mainUrl() const; QObject *topLevelEventsReceiver(); QQuickItem *rootObject(); QString get_app_dir(); void pushViewState(const QString &state); void popViewState(const QString &state); void confirmBox(int scId, const QString &message, const QString &title, const QString &button1Name, const QString &button2Name, const QString &button3Name) { assert(!m_alertCallback); m_alertCallback = scId; emit confirm(message, title, button1Name, button2Name, button3Name); } void promptBox(int scId, const QString &message, const QString &title, const QString &button1Name, const QString &button2Name, const QString &button3Name, const QString &defaultText) { assert(!m_alertCallback); m_alertCallback = scId; emit prompt(message, title, button1Name, button2Name, button3Name, defaultText); } void notificationDialogButtonPressed(int buttonId, const QString &text) { this->execJS(QString("Cordova.callback(%1, %2, atob('%3'));").arg(m_alertCallback).arg(buttonId).arg(QString(text.toUtf8().toBase64()))); m_alertCallback = 0; } QString getSplashscreenPath(); signals: void confirm(const QString &message, const QString &title, const QString &button1Name, const QString &button2Name, const QString &button3Name); void prompt(const QString &message, const QString &title, const QString &button1Name, const QString &button2Name, const QString &button3Name, const QString &defaultText); void javaScriptExecNeeded(const QString &js); void pluginWantsToBeAdded(const QString &pluginName, QObject *pluginObject, const QString &pluginShortName); public slots: void loadFinished(bool ok); void execJS(const QString &js); void setTitle(const QString &title); private: int m_alertCallback; void initPlugins(QList requiredPlugins); QList getRequiredPluginNames(const QDir &xmlDir); QQuickItem *m_item; QList> m_plugins; QDir m_www; QString m_mainUrl; QList m_states; Q_DISABLE_COPY(Cordova) }; #endif cordova-ubuntu-2.8.0+14.04.20140130.3/src/cordova.cpp0000644000015000001560000001316112272510553022116 0ustar pbuserpbgroup00000000000000/* * Copyright 2011 Wolfgang Koller - http://www.gofg.at/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "cordova.h" #include #include #include #include #include Cordova::Cordova(QDir wwwDir, QQuickItem *item, QObject *parent): QObject(parent), m_alertCallback(0), m_item(item), m_www(wwwDir) { qDebug() << "Using" << m_www.absolutePath() << "as working dir"; m_mainUrl = QUrl::fromUserInput(m_www.absoluteFilePath("index.html")).toString(); } QString Cordova::get_app_dir() { return m_www.absolutePath(); } struct Splash { double rating; QString path; }; QString Cordova::getSplashscreenPath() { double ratio = (double)m_item->width() / m_item->height(); QDir dir(get_app_dir()); if (!dir.cd("splashscreen")) return ""; QList images; for (QFileInfo info: dir.entryInfoList()) { QImage image(info.absoluteFilePath()); if (image.isNull()) continue; Splash t; t.path = info.absoluteFilePath(); t.rating = std::abs((image.width() / (double)m_item->width()) * ((image.width() / image.height()) / ratio) - 1); images.push_back(t); } std::min_element(images.begin(), images.end(), [](Splash &f, Splash &s) { return f.rating < s.rating; }); if (!images.empty()) return images.first().path; return ""; } QList Cordova::getRequiredPluginNames(const QDir &xmlDir) { QList res; QFile pluginsXml(xmlDir.filePath("plugins.xml")); if (!pluginsXml.open(QIODevice::ReadOnly | QIODevice::Text)) { qCritical() << "Error loading plugins config!"; return res; } QXmlStreamReader plugins; plugins.setDevice(&pluginsXml); while (!plugins.atEnd()) { if (plugins.readNext() == QXmlStreamReader::StartElement) { if (plugins.name() == "plugin") { QXmlStreamAttributes attribs = plugins.attributes(); if (attribs.hasAttribute("name") && attribs.hasAttribute("value")) { QString attribValue = attribs.value("value").toString(); if (!attribValue.size()) continue; res.prepend(attribValue); } } } } return res; } void Cordova::initPlugins(QList requiredPlugins) { QList searchPath = {QDir("/usr/lib/cordova-ubuntu-" CORDOVA_UBUNTU_VERSION), get_app_dir()}; m_plugins.clear(); for (QDir pluginsDir: searchPath) { for (const QString &fileName: pluginsDir.entryList(QDir::Files)) { QString path = pluginsDir.absoluteFilePath(fileName); qDebug() << "Testing " << path; if (!QLibrary::isLibrary(path)) continue; CordovaGetPluginInstances loader = (CordovaGetPluginInstances) QLibrary::resolve(path, "cordovaGetPluginInstances"); if (!loader) { QLibrary library(path); library.load(); if ( ! library.isLoaded()) { qCritical() << "Cannot load:" << path << ", reason:" << library.errorString(); } else { library.unload(); qCritical() << "Missing cordovaGetPluginInstances symbol in" << path; } continue; } auto plugins = (*loader)(requiredPlugins, this); for (QSharedPointer plugin: plugins) { requiredPlugins.removeAll(plugin->fullName()); emit pluginWantsToBeAdded(plugin->fullName(), plugin.data(), plugin->shortName()); execJS("Cordova.enablePlugin('" + plugin->fullName() + "')"); } m_plugins += plugins; } } if (!requiredPlugins.empty()) { qCritical() << "Unknown Plugin(s) " << requiredPlugins; } } void Cordova::loadFinished(bool ok) { Q_UNUSED(ok) QList requiredPlugins = getRequiredPluginNames(m_www); initPlugins(requiredPlugins); execJS("Cordova.deviceready();"); } void Cordova::execJS(const QString &js) { emit javaScriptExecNeeded(js); } QString Cordova::mainUrl() const { return m_mainUrl; } QObject *Cordova::topLevelEventsReceiver() { return dynamic_cast(m_item->window()); } QQuickItem *Cordova::rootObject() { return m_item->parentItem(); } void Cordova::setTitle(const QString &title) { dynamic_cast(m_item->window())->setTitle(title); } void Cordova::pushViewState(const QString &state) { if (m_states.empty()) { rootObject()->setState(state); } m_states.push_front(state); } void Cordova::popViewState(const QString &state) { if (!m_states.removeOne(state)) qDebug() << "WARNING: incorrect view states order"; if (m_states.empty()) { rootObject()->setState("main"); } else { rootObject()->setState(m_states.front()); } } cordova-ubuntu-2.8.0+14.04.20140130.3/src/cplugin.h0000644000015000001560000000655112272510553021574 0ustar pbuserpbgroup00000000000000/* * Copyright 2011 Wolfgang Koller - http://www.gofg.at/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef CPLUGIN_H #define CPLUGIN_H #include namespace CordovaInternal { template struct Assign { template static void x(Result& t, const Src& tup) { std::get(t) = std::get(tup); Assign::x(t, tup); } }; template<> struct Assign<1> { template static void x(Result& t, const Src& tup) { std::get<0>(t) = std::get<1>(tup); } }; template std::tuple tail(std::tuple &tuple) { std::tuple t; Assign>::value>::x(t, tuple); return t; } template std::tuple<> tail(std::tuple &) { return std::tuple<>(); } template std::tuple<> tail(std::tuple<> &) { return std::tuple<>(); } template QString format(const T &t) { return QString("%1").arg(t); } QString format(const QString &t); QString format(const QByteArray &t); QString format(const char* const t); QString format(const double &t); QString format(const float &t); QString format(const QVariant &t); QString format(const QVariantMap &t); template QString tuple2str(std::tuple<> &) { return QString(); } template QString tuple2str(std::tuple &tuple) { auto t = tail(tuple); QString rest = tuple2str(t); QString head(format(std::get<0>(tuple))); if (rest.size() == 0) return head; return QString("%1, %2").arg(head).arg(rest); } template QString tuple2str(std::tuple &tuple) { return format(std::get<0>(tuple)); } }; class Cordova; class CPlugin: public QObject { Q_OBJECT public: explicit CPlugin(Cordova *cordova); void callbackWithoutRemove(int p_callbackId, const QString &p_jsParameters); void callback(int p_callbackId, const QString &p_jsParameters); template void cb(int callbackId, Arguments... args) { auto tuple = std::make_tuple(args...); callback(callbackId, CordovaInternal::tuple2str(tuple)); } template void cb(int callbackId) { callback(callbackId, ""); } virtual const QString fullName() = 0; virtual const QString shortName() = 0; protected: Cordova *m_cordova; private: CPlugin(const CPlugin&) = delete; CPlugin& operator=(const CPlugin&) = delete; }; typedef QList> (*CordovaGetPluginInstances)(const QList &pluginNames, Cordova *cordova); #endif cordova-ubuntu-2.8.0+14.04.20140130.3/src/qmlplugin.h0000644000015000001560000000652412272510553022143 0ustar pbuserpbgroup00000000000000#ifndef QMLPLUGIN_H_SDASDAS #define QMLPLUGIN_H_SDASDAS #include #include #include #include "cordova.h" class CordovaWrapper: public QQuickItem { Q_OBJECT Q_PROPERTY(QString wwwDir READ wwwDir WRITE setWwwDir SCRIPTABLE true FINAL) Q_PROPERTY(QString mainUrl READ mainUrl CONSTANT) public: CordovaWrapper() = default; QString wwwDir() { if (!m_cordova.data()) { return ""; } return m_wwwDir; } void setWwwDir(const QString &www) { if (www.trimmed().isEmpty()) { return; } assert(!m_cordova.data()); m_cordova = QSharedPointer(new Cordova(QDir(www), this)); m_wwwDir = www; connect(m_cordova.data(), &Cordova::javaScriptExecNeeded, [&] (const QString &js) { emit javaScriptExecNeeded(js); }); connect(m_cordova.data(), &Cordova::pluginWantsToBeAdded, [&] (const QString &pluginName, QObject *pluginObject, const QString &pluginShortName) { emit pluginWantsToBeAdded(pluginName, pluginObject, pluginShortName); }); connect(m_cordova.data(), &Cordova::confirm, [&] (const QString &message, const QString &title, const QString &button1Name, const QString &button2Name, const QString &button3Name) { emit confirm(message, title, button1Name, button2Name, button3Name); }); connect(m_cordova.data(), &Cordova::prompt, [&] (const QString &message, const QString &title, const QString &button1Name, const QString &button2Name, const QString &button3Name, const QString &defaultText) { emit prompt(message, title, button1Name, button2Name, button3Name, defaultText); }); } Q_INVOKABLE static QString getSplashscreenPath(QQuickItem *parent, const QString &www) { return QSharedPointer(new Cordova(QDir(www), parent))->getSplashscreenPath(); } QString mainUrl() { if (!m_cordova.data()) { return ""; } return m_cordova->mainUrl(); } signals: void confirm(const QString &message, const QString &title, const QString &button1Name, const QString &button2Name, const QString &button3Name); void prompt(const QString &message, const QString &title, const QString &button1Name, const QString &button2Name, const QString &button3Name, const QString &defaultText); void javaScriptExecNeeded(const QString &js); void pluginWantsToBeAdded(const QString &pluginName, QObject *pluginObject, const QString &pluginShortName); public slots: void notificationDialogButtonPressed(int id, const QString &text) { if (!m_cordova.data() || !m_cordova->rootObject()) { return; } m_cordova->notificationDialogButtonPressed(id, text); } void setTitle(const QString &title) { if (!m_cordova.data() || !m_cordova->rootObject()) { return; } return m_cordova->setTitle(title); } void loadFinished(bool b) { if (!m_cordova.data()) { return; } return m_cordova->loadFinished(b); } private: QSharedPointer m_cordova; QString m_wwwDir; }; class CordovaUbuntuPlugin: public QQmlExtensionPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") public: void registerTypes(const char *uri); }; #endif cordova-ubuntu-2.8.0+14.04.20140130.3/qml/0000755000015000001560000000000012272510676017763 5ustar pbuserpbgroup00000000000000cordova-ubuntu-2.8.0+14.04.20140130.3/qml/main.qml.in0000644000015000001560000000016212272510553022020 0ustar pbuserpbgroup00000000000000import QtQuick 2.0 import CordovaUbuntu @VERSION@ CordovaView { width: 560 height: 896 wwwDir: www } cordova-ubuntu-2.8.0+14.04.20140130.3/qml/CordovaView.qml.in0000644000015000001560000000154712272510553023334 0ustar pbuserpbgroup00000000000000import QtQuick 2.0 import CordovaUbuntu @VERSION@ Item { id: root property string wwwDir property var mainWebview Cordova { id: cordova wwwDir: root.wwwDir } Image { id: splashscreen anchors.fill: parent } Loader { id: loader asynchronous: true visible: false anchors.fill: parent onLoaded: { root.mainWebview = loader.item.mainWebview cordova.parent = loader.item loader.item.completed.connect(function(){ loader.item.visible = true loader.visible = true splashscreen.visible = false }); } } Component.onCompleted: { splashscreen.source = cordova.getSplashscreenPath(cordova, root.wwwDir) loader.source = "CordovaViewInternal.qml" } } cordova-ubuntu-2.8.0+14.04.20140130.3/cordovaqt.svg0000644000015000001560000027561512272510553021727 0ustar pbuserpbgroup00000000000000 image/svg+xml cordova-ubuntu-2.8.0+14.04.20140130.3/package.py0000644000015000001560000001121412272510553021130 0ustar pbuserpbgroup00000000000000#!/usr/bin/env python import tempfile import shutil import os import sys import re import string from optparse import OptionParser cmake_pattern = """cmake_minimum_required(VERSION 2.8.8) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}") project({APP_NAME}) install (DIRECTORY ${PROJECT_SOURCE_DIR}/www DESTINATION share/{APP_NAME}) install (FILES ${PROJECT_SOURCE_DIR}/{APP_NAME}.desktop DESTINATION share/applications/) install (FILES ${PROJECT_SOURCE_DIR}/{ICON_NAME} DESTINATION share/{APP_NAME}) set (CPACK_DEBIAN_BUILD_DEPENDS debhelper cmake) set (CPACK_PACKAGE_NAME {APP_NAME}) set (CPACK_PACKAGE_CONTACT "{APP_MAINTAINER}") set (CPACK_PACKAGE_VERSION {APP_VERSION}) set (CPACK_DEBIAN_PACKAGE_DEPENDS "cordova-ubuntu-{CORDOVA_VERSION}") set (CPACK_DEBIAN_PACKAGE_ARCHITECTURE "all") set (DPUT_HOST "ppa:campo/1.0") set(CPACK_DEBIAN_DISTRIBUTION_NAME ubuntu) set(CPACK_DEBIAN_DISTRIBUTION_RELEASES raring saucy) INCLUDE(CPack) INCLUDE(DebSourcePPA) """ def fix_ref(path, version): source = string.join(open(path).readlines(), '') re.sub('src=["\']cordova-\d\.\d\.\d(rc\d)?.js["\']', r'src="file:///usr/share/cordova-ubuntu-' + version + '/www/cordova-' + version + '.js"', source) with open(path, 'w') as f: f.write(source) def cordova_runtime_path_for(version): return '/usr/share/cordova-ubuntu-' + version + '/www/cordova-' + version + '.js' def make_package(version, app_name, app_version, www_dir, maintainer, icon_path, dput, fix_refs): if re.match(r'.*\s.*', 'app-demo'): print 'Application name should not contain any spaces' return if not os.path.isfile(cordova_runtime_path_for(version)): print 'Invalid version number, could not find qtcordova runtime installed with version: ' + str(version) return if not os.path.isfile(icon_path): print "Missing icon file path (or file does not exist)" return if not os.path.exists(www_dir): print "Invalid path to package: '", www_dir, "'" return tmp_path = tempfile.mkdtemp() if fix_refs: shutil.copytree(www_dir, os.path.join(tmp_path, 'www'), ignore = shutil.ignore_patterns("cordova*.js", ".git", ".bzr")) else: shutil.copytree(www_dir, os.path.join(tmp_path, 'www'), ignore = shutil.ignore_patterns(".git", ".bzr")) icon = os.path.join(tmp_path, os.path.basename(icon_path)) shutil.copyfile(icon_path, icon) if fix_refs: for root, dirs, files in os.walk(www_dir): for file in files: if re.match('.+\\.html$', file): fix_ref(os.path.join(root, file), version) prefix = os.path.join('/usr/share/', app_name) with open(os.path.join(tmp_path, app_name + '.desktop'), 'w') as f: content = "[Desktop Entry]\nName={0}\nType=Application\nExec=/usr/bin/cordova-ubuntu-{3} {1}\nIcon={2}\nX-Ubuntu-Touch=true" content = content.format(app_name, os.path.join(prefix, 'www'), os.path.join(prefix, os.path.basename(icon_path)), version) f.write(content) with open(os.path.join(tmp_path, "CMakeLists.txt"), 'w') as f: cmake = cmake_pattern.format(APP_NAME = app_name, APP_VERSION = app_version, CORDOVA_VERSION = version, PROJECT_SOURCE_DIR = "{CMAKE_SOURCE_DIR}", APP_MAINTAINER = maintainer, ICON_NAME = os.path.basename(icon), CMAKE_MODULE_PATH="{CMAKE_MODULE_PATH}") f.write(cmake) shutil.copyfile(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'DebSourcePPA.cmake'), os.path.join(tmp_path, 'DebSourcePPA.cmake')) build_tmp_dir = tempfile.mkdtemp() os.system('cd {0}; cmake {1}; cpack -G DEB; cp {2}*.deb {3}'.format(build_tmp_dir, tmp_path, app_name, os.getcwd())) if dput: os.system('cd {0}; make dput'.format(build_tmp_dir, tmp_path, app_name, os.getcwd())) shutil.rmtree(tmp_path) shutil.rmtree(build_tmp_dir) if __name__ == '__main__': usage='Usage: package.py --dput_to_ppa --fix-refs cordova_version app_name app_version path_to_www maintainer icon_path' parser = OptionParser(usage=usage) parser.add_option("--dput_to_ppa", action="store_true", dest="dput") parser.add_option("--fix-refs", action="store_true", dest="fix_refs") (options, args) = parser.parse_args() if len(args) == 6: version = args[0] app_name = args[1] app_version = args[2] www_dir = args[3] maintainer = args[4] icon_path = args[5] dput = options.dput fix_refs = options.fix_refs make_package(version, app_name, app_version, www_dir, maintainer, icon_path, dput, fix_refs) else: print "Invalid argument count:" print "\t", usage cordova-ubuntu-2.8.0+14.04.20140130.3/Cordovaqt/0000755000015000001560000000000012272510676021134 5ustar pbuserpbgroup00000000000000cordova-ubuntu-2.8.0+14.04.20140130.3/Cordovaqt/CordovaViewInternal.qml0000644000015000001560000002144712272510553025576 0ustar pbuserpbgroup00000000000000import QtQuick 2.0 import QtWebKit 3.0 import QtWebKit.experimental 1.0 import "cordova_wrapper.js" as CordovaWrapper import Ubuntu.Components 0.1 import Ubuntu.Components.Popups 0.1 Item { anchors.fill: parent state: "main" id: root signal completed property string wwwDir property string splashscreenPath property string inappbrowserUrl property var mainWebview function exec(plugin, func, args) { CordovaWrapper.execMethod(plugin, func, args); } Component { id: notificationDialog Dialog { id: dialogue property string button1Text property string button2Text property string button3Text property bool promptVisible property string defaultPromptText TextInput {// FIXME: swith to TextField(TextField should support visible property) id: prompt text: defaultPromptText visible: promptVisible focus: true } Button { text: button1Text color: "orange" onClicked: { cordova.notificationDialogButtonPressed(1, prompt.text) PopupUtils.close(dialogue) } } Button { text: button2Text visible: button2Text.length > 0 color: "orange" onClicked: { cordova.notificationDialogButtonPressed(2, prompt.text) PopupUtils.close(dialogue) } } Button { text: button3Text visible: button3Text.length > 0 onClicked: { cordova.notificationDialogButtonPressed(3, prompt.text) PopupUtils.close(dialogue) } } } } Rectangle { id: webViewContainer anchors.fill: parent WebView { id: webView anchors.fill: parent objectName: "webView" property string scheme: "file" experimental.preferences.navigatorQtObjectEnabled: true experimental.preferences.localStorageEnabled: true experimental.preferences.offlineWebApplicationCacheEnabled: true experimental.preferences.universalAccessFromFileURLsAllowed: true experimental.preferences.webGLEnabled: true experimental.databaseQuotaDialog: Item { Timer { interval: 1 running: true onTriggered: { model.accept(model.expectedUsage) } } } // port in QTWEBKIT_INSPECTOR_SERVER enviroment variable experimental.preferences.developerExtrasEnabled: true function evalInPageUnsafe(expr) { experimental.evaluateJavaScript('(function() { ' + expr + ' })();'); } experimental.onMessageReceived: { if (message.data.length > 1000) { console.debug("WebView received Message: " + message.data.substr(0, 900) + "..."); } else { console.debug("WebView received Message: " + message.data); } CordovaWrapper.messageHandler(message) } Component.onCompleted: { webView.url = cordova.mainUrl root.mainWebview = webView; } onTitleChanged: { cordova.setTitle(webView.title) } onLoadingChanged: { if (loadRequest.status) { root.completed() cordova.loadFinished(true) } //TODO: check here for errors } Connections { target: cordova onJavaScriptExecNeeded: { webView.experimental.evaluateJavaScript(js); } onPluginWantsToBeAdded: { CordovaWrapper.addPlugin(pluginName, pluginObject) } onConfirm: { PopupUtils.open(notificationDialog, root, { title: title, text: message, promptVisible: false, button1Text: button1Name, button2Text: button2Name, button3Text: button3Name }) } onPrompt: { PopupUtils.open(notificationDialog, root, { title: title, text: message, promptVisible: true, defaultPromptText: defaultText, button1Text: button1Name, button2Text: button2Name, button3Text: button3Name }) } } } } CaptureWidget { id: captureWidget anchors.fill: parent rotation: 180 } Image { id: splashscreen anchors.fill: parent source: splashscreenPath visible: false smooth: true fillMode: Image.PreserveAspectFit } InAppBrowser { anchors.fill: parent id: inappbrowser url: root.inappbrowserUrl } states: [ State { name: "main" PropertyChanges { target: webViewContainer visible: true } PropertyChanges { target: splashscreen visible: false } PropertyChanges { target: inappbrowser visible: false } PropertyChanges { target: captureWidget state: "off" rotation: 180 } }, State { name: "camera" PropertyChanges { target: webViewContainer visible: false } PropertyChanges { target: splashscreen visible: false } PropertyChanges { target: inappbrowser visible: false } PropertyChanges { target: captureWidget state: "camera" rotation: 0 } }, State { name: "recordVideo" PropertyChanges { target: webViewContainer visible: false } PropertyChanges { target: splashscreen visible: false } PropertyChanges { target: inappbrowser visible: false } PropertyChanges { target: captureWidget state: "videoRecording" rotation: 0 } }, State { name: "audio" PropertyChanges { target: webViewContainer visible: false } PropertyChanges { target: splashscreen visible: false } PropertyChanges { target: inappbrowser visible: false } PropertyChanges { target: captureWidget state: "audio" rotation: 0 } }, State { name: "splashscreen" PropertyChanges { target: webViewContainer visible: false } PropertyChanges { target: inappbrowser visible: false } PropertyChanges { target: splashscreen visible: true } }, State { name: "InAppBrowser" PropertyChanges { target: webViewContainer visible: false } PropertyChanges { target: inappbrowser visible: true } PropertyChanges { target: splashscreen visible: false } } ] transitions: Transition { RotationAnimation { duration: 500; direction: RotationAnimation.Shortest } } } cordova-ubuntu-2.8.0+14.04.20140130.3/Cordovaqt/assets/0000755000015000001560000000000012272510676022436 5ustar pbuserpbgroup00000000000000cordova-ubuntu-2.8.0+14.04.20140130.3/Cordovaqt/assets/back.png0000644000015000001560000003021412272510553024036 0ustar pbuserpbgroup00000000000000PNG  IHDR>abKGD pHYsHHFk> vpAg01/IDATxy\}W{UWw $\dRvSEɒHH)#؊}8c{2=Q<'L9đm%YD$ApXn޵/owzHbyV{KKKKKKKo"n>< tP{;I h,V_=1)B~J)v])ѨMVW^7 ] o`j|Fwb)z:$J/>?u>]e`a[};㏽|? !^W<^Ҽ lΔNFs4FV_vh^7_}S|ݞ@kK~ *>> [Ey$2ki ڸ7x]`Mi@C=pp ZCċN%}o9X+\< $&V կXiDy{VP߯[ W&sH^Ut"|~Y t MБZ2w`F,v-艱Aw_}3|n=q/[ xݺжgW͝6&&[㏟෵`я [6TMiw,N$8\͝9CxӺ)?}BCuW%?LJ>4@یhYɾo_%i7ih5艱[/ w8r4a݇}_]!Z$JbV,Z ,vO oi-٬]#h] ᶍW4鮻Ӝ+޿ NxөW χ!\ǁ?>}UqFRB ^W(I$-*e;?ύm;>x)) T줴?0G?'"hkn%GB7<` 2u4wEt)ٶm%WOֹ>ﲒ)U0XH(_Kr5wu!h]wѨCOK;@*XpP|Fض)2Q i sҹ2^1/X%VtP}^⳵  cØҌޓ}Ñq2֍v٨_w6 MBoV8ZA:}V@# j/ v_IG߲rmJ{ZõZ@<;ՇmF;-2 6&;e% 1"ǥ|3'HK,ˁWWZ|T*l {A!]Waے駯5b~32~q n!v:ƎX\ x}^(S()" TP=USyLP5!FOŁ>:뺊;xC=@iP~ 6&L^ؑ㻩V ;-"nYb'P+O0^qDneϝ^{:Z+?~SBYkq6> vFvF@GIжmK#j3e㺪 Ǭ˕_fg_&ma;O_.@Xc y˂G;dB|b#}Vж.50~c;1[׋L&Z ۮ%t.g4AW+>oR/6@očx7Lt`hv6 PDS뾑GF"SJx¦?l@dZʔu]F|'uݑ]kVPHx^BŁgNױ;k+ l* V&GLT:BShG"CiɸictGiѨo񝲁DܰA"v hAo_%PP'krBD"{ܷN^$h5tm;mGҟ܀ŅZC:AX$D9;2|H:ta0]o)Ɉ$tL8@zDG 0>^`\šQ"vg0<O)oahSV#_R:Y^WI&"$f~NHlڪѨPنNr:!7"-WP^/[Gxfh8ʲtxf]lQ IU_( a !m,. &bYEE.FɄXlz[bf@lZ_";V@@ka 4Z(W.VL|Е@+CR d+j,TF-^Wx&DbX7bz+8}^M`;j`#oa+n`JupU3(Q kBZҥ.]^m)R`=.d-#6&6Ev-'sA`.DcrC#KJ,-]2u@ 6|$ DY4Fm7^ u:RV>T+?WL̘!/$$! divnכm–vRAZL,̹D#70N)@ Ti?x}r*S$6@V븮G&$Sw%ccK;n uUH~k0h(0͢58a nY/M(<-cmQ%@ZHbqA2%JI:#HzJAs+pE˯(fN:V5FԯS -ߞ >?~co$\\C_|X1]ҽ@5vWsV!ćFzmWD*(!YXTkqA&)Xq! 6UI$&Pf RD Q-cɓ/s/kƯk1FXأS(h @Q O5{ uo) 0U)I)VA ׿~|hr$(%Dp]D"M~W<8 f+ EM_Vuۿo%#@]@a; RiA")njr 4ϝW_#ȤL4FFHՐ~ ukw+hq*^rn^T~Z,s夳|@[ bUHhK+yYЛ8턀4۫BOII4֌1X+3.6Tt 5@c&5^0F6!^yxRTW^O'1$# i;j@jB,n5Hh~BE mxiryM"t3""NH$L/ 'dڍ`#@ض HY@5-k΍+&fR)M3M_]AK7vA R,|m^<I;=CA DјզZ D>)%RZJkƘHEl~ fjF>磔 Pz]Q+"hd>Cïc1Ϧ˗LrzN!  [pI 3U,6N:j}mٟ}Gg ޽Qg+5bc>̅{8_"$EbŎ#/3+8 U!؎`߾8BDE,.,Qkp#`mH&u5Պ`nQ3w`.L`mw5#h lnUlRxJ9;x>|#JEcs5JE}1z{#koG(HK(v¡P|9}-z3 +lk|18X<<3/HL!Imd$SɤM7 vǪT&8V5󋚥{6b1rBZPͨ`l\h0fQojg?73O9:r{ JlvVCK&scZ8 C׻F( Ź DJ)'ݫ螌̂I'uEOJUufY7BI=I ^-"Q5MnQ,,)n;bΘ\Z ^Na@+|A(g|ul=cكt2 td$}Qjm8:jNl[[ qښNt6r+3Wsrd*<XBXvNl0$d#}NlWɸb1@"Þ=QL2<'!0!/p!c9{gAssk%nJ- @a䗞7?_W^)X}ja0>X@%o,eԦ'Ր-wmI(V4[D:4oDǂm:ˋϼ 8xCh~+1ג=Rɓ+D,8СQ,) ! .k@Ԥ\=!5amq7shBP'󓽇ַ'cc_*0| # NV`ۚ[(,|Opbfc#&Q3> ͇"L澆 ^m| Xx`hg;1U61ɤw[<{ρDCwEf+LOUxŹX6Au*lD¨ %U F7@Sk !L&ФWHcW&HrHbXnciєN3ZIBj ݈* j5/)5aC)rM9VoX2Ws9V=fIL,1jKPĸL X1R4KVZTiۗV&de:=m91HdexkJkx"r6Yl>=5n`X\tq]EuxqkB7@(\5L494zG2iL"XB!$O\4cSf3#D"O R _5_k,$8v+^\eD_*>Vى$hOZ .3~@%亅CZi|J<*|n]DO15Y{8t8,{cj%>R1.i&ccۂ%U\G+ѷCJa`0 5!Ht6 J ~ 3Ru`?g?Gӧ~+gm[0?Woo-R*zDv%š*ܫD$oFLy!p+y& 1hI8x=H5!bRDG>.x,wݝv$j,A!P,fD+[uB:?) i ؆HZrrt:{Q[iR eK"ݍUa Pĸ-/>(/~붭R[O-_afJ$"]-kj ˬ_:O&-b1kMVLUHΞ]bamm]a߁6DTWN?wfԧ^1 k|f ԪjJ+9T}|rLӧM@0zbͲ⛦#Q}ť-_vT!hLm<s BZkn/~a"Ǒb%:T^D'CC V=Ԋh5{# jX01ELcqU+HAqC)gˍ2ºƜLdVkC%אT4%@6:koF?7FW3U|Ϋ͆% v(U@7z|JS<,C1j%rF亦ܶworH!LAX^4?*5#]WF`"z[(i4E87HaIߟjW0#^m.^cҴ5r.g&sG-I[fvmKrS_}pS?O3. ׀0UA)|,,u'H$,r|hޖA8/p"Ғc_g1L{.!]J$SZMs}T܊Knz"ishcw}%W$W9{vi o8oN装lZJ*\B.bI43¦ӘQHBz[W 04^j JB׮YY#dZ͝|O^M}y g1_*&`wNZQr+.n]oL%WLO<V8?SSfg*((m ߌ'|^Bs^C/`t|c7\ `䖯^m$>03U;ߙUkVYXTu2A)Uf3߿RS34I#>7Lsbv%I$z;KN[) !uZnbuS-LoraJR3~&nS|=;2p?qZ+ZbiZ2Ͷqaѐ9#=y|Uzstz{9O[vxczr9T+4G&Z0azhȥ H`:CA`+1c&C^0%hDFQؾ]kPj| wYۛ5;ܕ7w 0'4dy Jy$0@h2;0~viviviviviviޔX o%tEXtdate:create2010-02-10T01:18:00-06:00uh %tEXtdate:modify2004-04-25T16:07:38-05:00*IENDB`cordova-ubuntu-2.8.0+14.04.20140130.3/Cordovaqt/assets/microphone.png0000644000015000001560000002425712272510553025313 0ustar pbuserpbgroup00000000000000PNG  IHDR>a pHYsHHFk>bKGDC(OIDATx^ U՝뽛ivYUPhAAYDDG3cb&KrL$.U:e2+F1n7\Yek^ۻNխWP:vSuusmE-j 0|ǎ4l)ee3jf6{ȑӃSc(-0bO*95'0~p3;ubm xף||NN(,~RnthٹG..++wZUUk[jkۢ[/$ee{W*\lmc=6[^skk32:\^R2d3G*uӦqƍpA\QQ5knqK"Oƌ9^@XUU}]iرuW҂#YYfu԰X߾܌c\׮E\]CC;pJZ 7;7bOnnÆnr7dHoWSSzgVW{78}v$ZIuu/wWRR;inZ׿t۷uoY Q(vŅw6;Z^]Eb^Pu{{|<):u:îٹrrppThw}v;@ ܃~Y;ɓGѣJzy tұn^nift/ի"|MZ 99E (!iN׻wWm^S\߾ /^zIa[kjv}K$8a OIN&Ȍ]TR2_^4\Hd?wQ]o{)7oB>@ӽ}Uoe,EI:t| _Vv <%Ow6(o̘)ū{IhWn֭ ]`zU ۾enoCB3p Iۺ^{5k#4jk&tJv.j}z/ml!og\wǐ!CVnܸ!2/;"襲AIP l% D0,Dܹ5~!@~JgxG@4,Ŋjݷ0Z 陙YTsS YrIg曗_ӯ?E29|#ï@"r 54FK&~Zg,RG~f1@:(!UpHʆȜ R>~}Ν E Jy D`1s02c^DVlxCN<H4:i책vqΐxxlϦ `76n( ~UJwW\1sLItd"t- g "A|װY555ERxl4` Kj d"?OHj,zU;#u% B$R%ǴW2vXDVi;S]8r\V6y|,d+c 'H}r8~79@4e*͘P{4'4K}Cբ0P(JJ[ cp~+PڻH>6x -⠊XkXˍ4@n@S}c˽\CR>~e&,'ʍ7~9< Vq\SS!MS $liFd^@'aY=B8#%SH5w tR"HA?_IItd@ґ8qPT+xݘ%5D;XFpQ܃Oaa&qIK6Hz-"/@$5Y\6S #0v%U?ssUE\c@@Q bk5T?>I Zc Pa1?hAR#5nDH= E[Eg| B3xC.!D0 6d&BF$0)UYzJd6,yVN_pT yMqꩣ=h\'hLgFl묳Inذ}|e! -?^/5#U\dl^k_Hw51 "^[H7 r\BJG(cK`wUf̙37^Ze7iOҥKoSG&L3jirzL5s|Y@ 'ߡRǛpb!dC">c*d&bT&Jf I,2@ RDUk0]R5 D)pNS=]8@r Kğvwٺڵku5ҺD~}a!z$S]SMD*'yVxqǟCk̈,J,>K$?JS2)?hz˘?RrFCC i> /% P, H=j_6==1& s?bHasT8&hCiG `61!i_Ļ瘚A $ʾHBD6&Ϡ7jl> կ:׿u^^h44vP. 8&uۥK EI3D'_9}' }ʷI4I (  CyxX?Kx NEY0/yp04p:&!G)sI S=DnOAkoh]va xn{$>nYxpinbWove'"ch' c'_?x) q(X'9Ypcxw3 ҏ|oaB̩#DO0eFA2@~H$(-;,Bn/8"v \oϞ=U&𪔦0Qŗ睦|HQ+?Y51h@Zȗ$"`]%Jl.IcЀ '˹3v\=$Ah(:"v]wIj$<^2 ;Mټ<%p2K@w4$׋ld2JS% pH`I M$]P[ "sn3t? g61jԨz]իӵ%$@~F6ID삂˔:]/^{e/-T]/K^llrJc_.fHQu7 {ϑNf'ahIfȣʿ>cP`L B)Zm%볳cq(-23!&NRe՟mD32R.pȷ JbOCtW#>rG$PI=G=' $/>`y Mdh7Y; bꁀe%p,%7w o}5i99?&߱k]ϺK4iv.@@ߖ"Iuqb1E@3ԴD`{C>!{H3{F,N&2>cߓǷi0{N/K_di  dlB x #㱟`B 3ȁs ЁARxF0̜@y54m)"j PՑ~u@A5$`ߏa!ǀ0}F $2p8ga\盩csi F0H(.Cf81F3ƾξC3„AئvmsZ ]$0M3c?! 0753n-D0NZRi1Z):22VQ '}467 VK9`G_3DŇ<6EjKOZs`Uwtf`64)153k l`-"9it_IecR -l2?fTCAoI XQedXI&&# Ø@HOO^Ӽc~1ggXԠ1d&gМɲ4i߲bU1!Xm["K5d 9YhbXd~rr$|fm|f2y%oafDL @ 5H33\ȔdH@(G#4KFrKվ9ϲpDDB/.m,$H S24}uKYB$-P:ul1s&z DJ:)2S}+ P(ՁmRښ+۽FkjijTjb̈́4QfmU5FXrH[xtȡ ١U5~P6G+" <LқdVsuH&dڔ̜?Hg j6oaROJ>2 #Vu5@(Hѐ4SRn)g{.$#}JӢ`ryz3!^ &|KZu Ma!uD7%@Sz`SԱ'8Lc t5#ʵpKYT0׬1#0۞oXLDS$C }7>5#gRV =⇍~iH?_6AtdT! .,Bek/i W.YLkjFdS`K-;g jo`VcX{(Bo5"9ɓ'Y|&Mi7-ij $t:ڄs% 6Ccg?ylYX-xWIf_dI=G>Skݺux+#ܰ={5u,6AbG, <0mڴzj8Th{s-{Ɛ~rr٘1c " -k?F%aAIZ#xap0j Wj|'r!4{,VOq}C pm8 c4]YYR`JcwI{Ip(Gд\C!xnԩ7U}A$fϞ}`& @I Nϱ3 tV~|K.yg [zr no}V2B<`N W˫BD{M|g0Yq=w~/.jFy7*D dw]L! RFBeyC KQ!ӰC?TQ!>x'5r1iI٬Ak@sOd/R^4v `$Iسnenbn^Ɇov.֜ RkUQ@>OrEQHH@C,B{O{Ǚ{e9eg Iikh.a~#VC`~oAMu*$ t>Pߏ0 90 Wpdz eK$& Ɉؿ^!`BeekU#{@U`(,l~blR+%6yCz]yJipַH"O2T/d?IqU \gp_~ÿbҥ 1c '3@m R5@tP6o?XC@VFk-SB] 6( S <_<YZ'IyЙ *_"O~O6UYK4~Űڍ7ޘ'}5W^y6nJi^!!/!o?qW4ȡ֌6%yV8Kv{-.rv,vc) a>5!RSs}\;h 7)`ʘp'B1ymEH) oquԟk;-"76 zDϽxMZy[i>XDs@CmQiZ/mR-Lc4F"Ku5)VO1ьQ6t3 D&6rp՜/o-"O:ִU.{PUDvxY>$ob*Gh[񣽄@EH]6J*oSmEK{کO^@dRKZ'CZ,C wr-Sv:S-KR%ճt##:1xd0*ڟ,ouNyϠAy٠!Py9w&4NB4@U%KjPIb*wKZP>Z`Uka:>[gi;_/ӽgr/tV/ !?qSg+:@F,&mo1I? X_Q?Sǧk;UO!Ʃ342=pn &T"&Gٸ9yH$'/I!!fߟy^$Lu ƺ5ƌ!b԰D@c( R F c'gi&k[K}z4.X"rZǵ_A[@\| Tl K*;[g@dAgAz6  -d )!@e xY2PШ{5f;:ҶZUi*ֶZ"tEXtSoftwareAdobe ImageReadyqe<hiTXtXML:com.adobe.xmp #IDATx] XײVAQ6AD H( "Aݗ%.h&uIȽO1F7[p}< r%(*.𪴇sNaЩ𢡊a?UsTUUUQ^>Q!0o#F1o#F1o./=::mA4444m$k>@z61&^ zWpAAC@}y@OzH|7A5^R#!44 vܙr2B?/ݫ[nm 1I{S2ݼ+~QwPw'99sk]!gfffUgn7d/hO[3[%d ;vmݺuUrV!wZv:B8-%/AXRRRiӦhp R'.Iͭkٳ1K(zTHLw8jԨTaH9Q}ѢE!"\|WWW/V9֊A4VQ٨T9s&xCP?Î˗/NO"'; ~Chݻ, ҟQϸqF@T+**Jȸr{Νˀ,G. bVnnnm;@Dq+**۽{AR.Hڷo_NtӠ#gD5Џbܹso{1Wbt~Æ ZPr A_{qŊ|^dTx tآWlllܔ\X3fD F)N<9m۶6?7Rz'77'H={Fu242u{jS9sf)S^aD^⚨c҈ǿzxxJN wʕ:W&"uǎ-~IXN~D>!vh<,RQ[[[B*h{{{OkwZ8Ctḱvڡ>CRzKD_gY>e'XNܹsVH~ճ/%o浉'Nn[ʚ5kzEě ɿtx凋qKا{{{G]HvKz.\pD2ARơC62qV1OU34r >|L Y (/7%~n?!!ab&~̘Z;vM0!T*}k|rСCwܿ@z'=ZdNy1...uum4ܟTz9iҤs4!k7VP]VӜ-5Ldon>z ~ pHqg}6{"傿 _^Rz׋׍׏A:A@1F\E?-"]zu DpohW"%{NzxVlzMp XO?4.<ܹs=VZ5Zw\Ƒ ~f)A.Z>}zoqVcpJv}zIw/Nע/8+"Z`vDy i%Vz"pZn?\x4em۶3dH h!urVэ7N:X5˗O>I$b`T|j(E &?!KP?2lذ{=&Њ]ipį9eӳHkR!n\*] эݻ[jj+W䋻J… w!y [`Lk?681sׯi֭$ұ8<ژyYYYޢE.[,InІ%XTO 16NʻمLRզAAAy"&?,utt,wyR<'xN֭[۷EYP{!A{MfPARW_ K,57KNNcٻҹBq:ٳ}9:x%@uʐZYA?5"'~'F0()~7 _֯8qbAVQ+VarU?&Y;Ho߾kuW2Dr 5  /$G!:O|o]R9_uwC^@$~界 Fx . 7q%3|މ ďLKw\2jY`Y&rz !xn߾}0!ŗ}P٤IM VѵkՉă={:2)(( v%:~L/X\M#Tzɥt)))[4i҆{14"Qgʕ+sEj*XM\\5Մ^z tݻwd,&_Z>+܏!>"$ܑE7cqa=Mry[+t3g^p k{#E4J!0~8!^ C|gqy^2#}ׯ__®K+8e8K}Tiu >KDH&[f۶mH7h"HkC󦼼 䗩 ߿dee]`#W&ةCt}Wj\đtrwB/W{|2ݻw=!nNjt~a ZI#YE˧ǑHE/)>#|o#wMi>EDDI*=]|}"SпW13'GA1y|J DywI?G"##%Y"+'a-p B5xNs7*FP|-x)Q{mE8@$GH xc&|դq#W5@Y|d>;_JhƞmxިlyQɕuر%ϒ1)0{W,^/󠃕7^Iۉ/&D/..~?k&5l2zNx\uDyިZWNqOė_DV σ6\j*GȂXZZҞ|-ýXEC%WɽRqqeZUQj77~9Z'\Q*#gMeHIk%52q},9 H xX7WfUí7 )Mz =J|DV σx7^Ik͚5k>*#pfǑ-jKX <:"A)%OҼ1۷=#߮];O'+*x{ZJ3O>:F7W8Ѷ&ʝ3X8Ȼ|;99y2btyr)p q=j;N}/*R*|ӵkڷo-Jdڂ#/h֮ҩ8!g IyuES>ϟm6H0a/GxF3'Yt=qq"^6mڸ@3%̤ktş]֗zGq%ŧ8m捙qZZftto@:5((Ȗ^PlnRqAGyu<| z瓉xgN+W^VV9K֟oi|e"w"Fi}q'Y<Gٳ;*\&G9Oп,%#ˈ;ɀx<;F>ּU8.~p5u"& |U/gQč NA~DaEC5EiF|'~+K@^X<+?+?B2A>V_~9M;6NT_iAUzRU-A|6yI;ϗA" 6̧m۶I-xҤIgqҁlll^9s\/(N}~gb(Qōx [#D|x5ܳ~ƍA4>>t qaTami(c%MTHkpړy8CObl~=$$ĉȑ#G8vΆŇݎKjtrqlGCBh!~# _d ǰ(ָ(4[[޹s*VoE rۭ׮]ۓvC ^`y3Zބ1%F:z8t^DݤqQ]U]]֭[DDtLNNNyzzzСC}qd 01 133?TV-Ѣz-RήhJss/X:s5NzDvu֍l# &=ۻk }֕Jwzʕ}:ҏG]vBaۣG~8 ###oȌ,[rjM%@SNz S#F=kٗ(޽{^uqhR%¾B<==[C4 ] SNQJrرKǃ6c))HzBf?{,iF>̘1gDdWgܹCDsbꅂ4C@-&&!>Zv4p{$ql;WIm+q;S\ W'0\xqG7n*5СCQ#F8MZYY }]i]K\__-o.7~c &JY\[˗ 0oDGǾ\ZtQZ,*  g"q&M:G ݄MNwpp/[#Fϋx@z8jԨgΜɒټyϸqFk`]@͌)))w++$x'gVnnnm;:{/vhqr_qvG3m]HX۷?erESYY._,\mdnnn#^ N=uԓer>~a˗k_ iσxjBD<~}s΍@WOUٳgcfϞ}bZaGX|>`ZVV WWkRɄ7u̘1r}:zH@_ץ}-b!< y9' ۷op[WC$^StBJG%HY8er ;HM6|ߑq֭Ka-㢮Yw}Q>:2gܼy~mϋì'xO5D:BY;)a7c58&N8W=["Oqƌ'hkQ \ R8M/  MHQHQ 08{1FɰIENDB`cordova-ubuntu-2.8.0+14.04.20140130.3/Cordovaqt/assets/toolbar-right.png0000644000015000001560000000221112272510553025707 0ustar pbuserpbgroup00000000000000PNG  IHDR%qPLTE~~~'''...CCCNNN$$$(((...jjiAAAeeeVVV*** ''&+߫{tRNS$&+,IIJKNS\\`ftvwyOLIDATxYw@W[V @$ ڨqVܪb~z'CK..?~?PuK7۪?}QVWnhoev׎ou=AyηĘR̬3Fן. T5S)$Nܫ(YyKv\JqpT2(es5 /^TE˲Jؕjm0WQ e}z#_-<UUYe*KJuկOjYD=5-RVA_AG\rU?a(;y "~0I>JIM'ՆQ+k^ک% ͧx oES<9S9^+tEXtSoftwareAdobe ImageReadyqe<hiTXtXML:com.adobe.xmp B>D4IDATx]XTG׾,H/kL,bn,X@&j>$jL1OO&$;64 @FT4"U{3w{v;3.wwf9eYMW7C7Q¾ף}ʖ7Wpi#b ޳^_ˉ M&d&dDkYϼV@̓,#fڵk5k;oloo_KPxrL0LjYP5M:G*aNN?>p¿bbbTt 1ⵘt%n2__{ww6vvv-hY]ꂂ;yyy/]tzРA$HLL 8Mk T;P]kժ7ٳgﳯDի4iimEh#_Ap[PрV]VyHܒ(p9 %*X݂ܾ}{.[kT@|W3gάW @J bcǎPZa@cٹ/^LIIT &B I kkk@9zurrR:::ڸgp`[F˗[>:$$䑀R@")'ɚ|޼y^ƍ f]Af=zڵkO._ܹs)iضT `ձcGg___f͚{{{{ԬY*x7Px,1bj<ޫW/uMdٳ1Hv-eR,@&y׆ Q&S)& E0X]Lŋw7mt_~y^CK+MsIOAΰE`$ૌ jDԄ F6SU8zȑ|POW輛IKB@(ш :LKONǃj!QoZ 'O~HCCX++PXJ+LQ|VT|Vc pvzA#Ͳ%+?~9̞=9h9'u'O3GSNFՖ-[ Psmԩ 7o`kHv!]h!Cѽ{&uܪ::99ۻ9)xٳgϯ\Ϯ]$$$d/,&7nl?ڵk3hѽk׮֖S-Z4$!pk>'tkﲸ,6WȨ(Zuh|  UG5??L WhΝqRaccܒϔtJD#I_U/A9j۸Ic+W>^089[vr qf}ʪ5 l+n[T[dn5Mlc40LppWhH۷oO_.Ɣt2m_"%*\/YA @X8\BM41̓?#1wp>T AGG LZ \_?o ˇ"%G])H<+Mz؇ݵk?jIc)wqv֞={&d_Zw6]:wy,軳~G=}4˨]Bt{(6__fLR=m=|Dwg.)+UVYW^CDRU("xi#KӔ@{jyv͞=vXWॼR+AnygʨB㪍1"rGG 7YrMUJ޽"g'Y |sc8`chJܶvYvWsߺyG{vZʵ*)vf͚5KbRM(td VX+(r\i.>+ITј)̞5kҥKS/͛wHYLV4js΍pww-姓5H'M4w5X#H~9g`30uKpg  J0ཌ*gJ9 WZh1[*"~*R9<~Rcǎ} A #KgoaS6mBP5bhѹǏO$$1[absa\̙3ѣ]qPg:wCiU>SZi?tK'Cò}ّ$I)=_K|6MIUP'YT γzժڶmkǏ'{Ç pX5zTgJ#h1n_}-nݺ/Tё6 KniW'8:8q {zƍ> ".Bmo3&LXg?tSsI+o `^+as{.$]hѢfm}}_@v*&|Z,AVKŒoNͲ^ޮ]^~xbOhg?&e ^IhD.\믿Í˥]4qǕE;~,f8v,Y o7h@#zF!zN:R_jUoG$ ;y8Ԙ]7d CCCC^]7Vx0d?rpVU* ^+'yf4ך%z&2e8vC111ϦҮcTY߼ݍ}cO J=ae#|͚58u4O@ӧO8qO >$ϔw"|P YryMam*j,Uo`3#g`_jaWLe_+Vc€@ƣC'ϣە+W:zi*ۉH (E:Ɗܝ;vtpvvOUҢE!/$>$.cyWrquu v9֪ED'OzQƤ t(-3Q_Dl{̫J43yh5-OFjdZaY-[ՒkeSw{6eҢ WU\-F6h` E"/wn5<_zuѣ^Qw؀ =ք L9~: l UKX^GnąܹW:*#R)>H֫ L {xpP"ǟ(qN~6'Ddĉ!a D 5D< m۵߄jtgɛ&֭[o}K,X(2"")?P.jݺumeYF@Xʴ,b,TVxQ'M1QL \-R+PU( iV'?9j<1=~1c~erLC Yɓ[{ 9D:%\۷/p:uSHTy~8!!BtDfA#6h_\R=={N^HH<ϧS;iS| rSbbbv[mŁN  t[|uD6s={;2Z~|||ݶm"MO}u`h zNNO&Nʕ(}Bi e!M OL3 sr֭;v꼁2L^Trȑon.&Mۢ#[l]^Vw%y_;ׯ'scHuwLV$$rfᤤPEZpI<ݪU zFFFʐ!A :L mӬ_0B_M'j૊ fSNkݢm1e˖Mq'޴Qɚ'O<~7xgm@~m[[[S׮]{Jih$E4]fͷ+ t?xlyiiկxض+]l*66pz$Ի=Ըۻ+{{j[(MS7nxd@Ǎg-x=?}TիW@CՊ=555= pӧ44B%;x"قVZ9XhXCOK{;0$7y0777pjdEv 4!d6~/ }9]SۻN |8BQҘL2)tҨQ#ҴO-$N8.Ykk:Fؒ‡QgPX%ރU$/t`\xӰ;%vl{YW 5zd 6l Z &Kji}AssssD|m! CL=g4hr0`]bbYDP8i%'OUƀǠocu$:w5"lD~2̋>tBpQ;=:_ROLȫtSXJaFJ(|2^ɗ#8ۻ,%`cL Ձ$0\B`T*-/^'&fs9)B?Q=m\)}~G\.S9z/言V~e4\C RiX~l@'n 0jK,gKy5ymed2"`$e@@xxtRjlDwɌRi-+G!%̙3uG"zʀT*T*Z(e2FF[t>aaC|"mphbXTUai/OHHҵ6?,snҚ*,QS&Kwt`Y]LL c49.tyGӱS ٻ9@/^&it5AAnER;ۻI0 IߦR[r!xr!Gmq?WKn*^rc*_˅UҖ{'@>M}gq"*ԥYwK.]ZuQqTr= :VEtRZ |A[sf<IcE_v/۴iueǏ5/^,wN3عrM Į<'Uƍ{}3m۶uPe˖B JtݳJ KViv\x "gŁDd^^+׏eV" m灷#o] 7e9˗/s-۴iS=+V$@oݺDw b9;^%''itt/9}0} 1FJ!PtI1(SF.Wh(7/i9ä;R-hO~kݺu8ԧ_>;86W,q :E:<8xg .mV LY>W:zUԽa:EEF~ L`rk,}<<< ? Z%AtG.0 8˫{jǎ( ɘ}sUEHҷAC.'bHuP(T-Vl =֭&\)^lU|9<;|p B999gƣzQD@]ֱ-٪'Mx3Z,6۷2O9Bu˱S&hɕ#vD\U/HIN{^ёǏ߸}V +wQ+"|F3w3fx(<*[ȾiZ\kLo4 ;v SM&1+B/ԹN RYݹ@-`)VjQV5=[0A܄Ip<(!Qr$ʕ+1b- yY*Yq]X"yx!zæ$)((&:Pkv2uqsJ*o\" B|}SBC%+ԁzd{iǯK.Mf@PO&F偺7z&Ǐ/d\)>zK^- صK}n XJ&c!Bs\fJ佊TOs3[+a bJ^('8exo;iҤZ@2ESNR"+ӌWl?æĠƒ6 uaLq&E4quuuU ]gî.Xr-\keՉ ěeHY$XdBB[FIlIsW/L0`]aZ-Zs+@˫ccO ]u {4 !nh񁈈 ebb"%rgBC׭kHkhj.KF6}pYz 12`ۓT7(y]e :A=xf߬YwDu73åsMk.v̙-o|>EyP1a0aXt "9^^$I! $ddB\ll6mZ^㺖0Wx2k̙Bl~eeeml@bJ믿ޅ6` ?ԣGP^1Hajj? tI|##"Ɓz<+Wud젧7n%x9'M4ܹ"[K?G }`~A~lŊ+(xY'P @.k:vEՖv+Wl &A. X.ZIϔ1!TbŊG ?(ɘUVu];c5 ޚ^Y~yG}-@Xt t4~Æ "%`k֬"v]+N3%Ѣ\o?z[jU>SA,֡ Í741~mBey¢OV.[|_R<Ǐc0*ۿLHʔ;fIw Glu\/Uw T>aQQ3gDϝ3? pBm`?2!KHIǐocƌY$#YuڰaC{L4_ `,F휊޷o_ \,X 21c)wvʀ^C˾(I?k{*6sOV*~aaO?]y95UL8VZ ~4b,G<<<¨ReL]OQ Jvm*1KAc6q/1-lBBBΝOY0D1\iJsR0k M6g0>Rֳf;gS1" dI?"dd{ >d_}_&Ez˗O<9*% L)A7Pcǎ.Wb(J޽{ٳ@Ak?kpEna|͗0ˁ1"~WU=xKH: ɲ;PYC'l򘿲H^Ib۶mܹ\tFi||ĝiذС=b7;(J8pWjѢ3guYfݲez &s Gx(ɓf͚MuC-Z֭[9uduZʕ+ €+er+n=ztw)rl.% jF޽7>}`Ijj?_|B[nP?QR*"P$Cuǎ  Fpd.{cΜ9#<Rf//- ds ~R GWܽ@]TR=HKZkE./fni@+*6`>׺C$'Ovρ?nܸ *>~(I{yy>&[R$@ @ERsC7Qv/^\RZaRgG޵W^ ݖL:{}e ʵkA[ݻ3e8)X}7nlmӵkfhcj !|ڵg̘BߗKQJKY|abnч) L1Կ ^w)p *M㋎ɻ^i4nBXY)(QZ+i(엯R![ 8zcq13o???ٳg7֭ؾwj%h" QݒOfy0}'H`ݴiӵ_~ <E祟Q[Bx(4Sע  &x=lx#$G92uni>6… ɤ f;vopn8p9exiث}b#ދgG!LbSGfשSg7epvܡWQYzrZndPw6KSSS3ޏgϞ=$dEWM= ?<((߿6 B&;,jܹW^U/%z`޼y^LWf8J|VeA]{rΝKMɡL%(P:v 5kۣf͚UQR,qÇ}$xߔS"̟? (l\"sQmtM*8UtW5 ]ccc#Gv-ٕ+1L, ꐐGSR飅 oߞ M)((ӯfΜYҿ=KuE>>MIہѧVF!KbbbO8ۖ K3 \kժ7ٳgAUŒ}7--mիW6ią̪Y+r __{m&P((n55}`.]:=hР-6uJ<MZ_3ڵSΚ57 &\.w肢P.ɂ *;jjaa#J0''矇Xp_111*">#`_^I@Q (kS"`Mn`Rb,xOIouיoߥcK7_2s0o oߔ{?* $KIENDB`cordova-ubuntu-2.8.0+14.04.20140130.3/Cordovaqt/assets/record_on.png0000644000015000001560000001144612272510553025116 0ustar pbuserpbgroup00000000000000PNG  IHDR~>tEXtSoftwareAdobe ImageReadyqe<hiTXtXML:com.adobe.xmp TIDATx] BUhXA0BDc[ ER[($m6PFQj!BAGeQd) =susg<מ/9d~߽wιϢ'OEC@W ^+Tx P*BW (Gt(!kMւ)>?cd֒M;*9|F&nd瓝K$"{5mdɶR8gWNtRFxad+a vב]OV) vɊ]Cn!õ:d(U ތY ٔ=lLL:}VEv 5&k0g9ȦSD{&!WXk3{|#ЎG8Z# £]Lv{쥟EQd/s86tLvSI֟һ'/ QD J6k'[d" ދ} g }}AO CC4 K <_0v{ %{/$ 0 My-<% (D}:"|Kxq\L2 9 mP !>+"@tT?D/z?Ytגx]AC%gEx ޑ)R] A&kw F۴Me%=W ZD˥hWn=w{C8̃-:Y|&KnG5onUc{g+e8!5 dW*k&@\ƙ[pMQD7εn̼l;U=rB$!Y.\ յH%JQ*Ŭx4rFmTG %9;f3ccw&ڌ+ۗp 3٪GŎ.x?3^ϖzhYp JJm}E.8*<γDC3VWk g^} g7=r?2WYq>W$KdtÜ<~s0>z#3$;$pnvԲØ6>a5'j&聨K|y2a;TO'Ldjz2'p!qjFޞ|[kRn'\:F[u'T۔Ʈ?.?j }?KYDK4d˒p8[Ƽ蔸kyM2Lag&u@/u6z2h<~Hȍ/TD0ȑzW"K{OTDO{z9 p^z-aSćuz9 U8Qew-<9 ߡCᲴ@@*Qpķ3Eq 'tu俘u-Z*}p~pjVC۸·B(TDF[GZ^I+F5JmuhWxiP(TĪ]t8- غFQ*hC)p0PiO*9^Z^T=Î:|W yxp^z:j >p@\ οwuWxjuJ5~p]/\ۮZ% _>9 /-Jx =--|ɦpY IJuUm9NƻAJq U8/m,ԯ #[^!Lf+TDBpαrx פf`#nj4^`]&`&{10iä?룼HFK|hP[Q8Y _1i5KU5uY@*yȿܱץYAdGpM.Ei}%$A w1W|*©Jrr@=ivL}O Lz ᙀxh珑K$DYE 5 F\U*jvdg}&R٫ƛx$Bz1T~n[Ihy1T{FT%bq!$=xmMB܂(#iFj+q`Vr87;L҅ϷO1v@;U)6qG5焯F~<+-UP[rg xͭp4 #Q:^JrVx& 1N=VNN{07n1}y ]{Ոwv%`tbpzLJBqJzfu)=י, jfl6I˗gaPUY$,p_jB6H]S7C\,v&mJ/CVa?2'aHGWd1 3諁 dAߐ2d @2 d @2 d @2 d @2 d @2 d @2 d @2 dsT>N& V2LDgXqcY* T1T3rVj<[<#%ʮq6sČ`ՍgcA0zȞ D K 2eIh:Ԧ $d#;rvN!JjG$֬߼ut\ʰV]iIENDB`cordova-ubuntu-2.8.0+14.04.20140130.3/Cordovaqt/assets/toolbar-middle.png0000644000015000001560000001050012272510553026030 0ustar pbuserpbgroup00000000000000PNG  IHDRAXIDATxOTg08"FQI/HMhiIH7^5+t#B [Ku`ܹ҅|㼞oIs|~s#!yS PBq [nϝ;ǻ=}^WW8NUUU ݻw/TVV 7Xsq \ ĵqF̙3mMMM:tv8>^EgPK~(-I+pxYXa") K ~5$q9w\kȄ{½qgtttK7yN$-d$e(J`L OIaB~ߏ9~~p9)5xk #>S eZŽqhBq+W'N c]vҲQQ$3F1e0lZ2| B:-kmBFu/\ÇUW=Dy&Ip.HhX e°P#ӳH[Bt%BVlHKK%SDIǙ,3pU$DhhIUV187oT:uKJ%N0[ N,J  `hkHvViP(qɟ߾}[Yھ|'̬9-З%[" -h31,'q]]] _aTXȒ(>y&`-M"@BZ _m%bZ|!|={$1Pci0]$Fmň&Q Br1ElKQ˗eUe04MuA8EmvevgV(b#֥"N//CUٵCguqY"9S 1D,uXw E-΃w_W_4F?gY O@<ҳTbۻA,c*u y[|e).AGluA;;;b',Z%MYD2n € BF G SvWeMHi̼١ZetQaP F{8{U y}X52*.Lٺg^kU,!G%D#GxfIn(2&oP}\cԴrH''' BGkhhT̠ 3&֩2Əʻ rGDvTy^NcFEXO*uiy9B'Xj}{)XZ<*]u nppkT,ػ&VMW{e4#W)yݻwU.ilX Ir vS)PҒGv!%Nŋ?&蔆㙝 ~&ro8?Y\1Z 4E'EKE'pΝyuHuq4u9En%۷o"gtt+yeu,%Ҹ8rI 5rYq"o`l#LPg9Fs~]q,_ʰ"5[lXb:c< R9Fs˷oUòK#=40@k^_<)O 3)iR>|$CWB(- aȵ]'2qwv]x'Elsߩ@b}v۳ZL<^4- )L~]Y%GiJ >)Q6 ^I(%w("lC(8C!PBq!C(8Bq!PBq8C(8PBq!PB(8Cʞ8C(!PBq!C(8C!PBq!C(8_;g7AAIĨֈPشbhl1MhPۄFA* SuSЕ D?OyL'| /qf޽8;o08#c0 F`1 ZLpf;z7<υXɈxqPh$8K 1E$#LFEOX^74 %21a &zTT@CUa˶^&lT@F+G'+#þhۣ yKwaTQΐ8}<HighqFA|/ztFtFVUYF~ 1@?ĉU")>bq RuiaaTY+3 K $K:SitKr($!̨,q#pz }=q cl.++˘gI#@ 0#܀8"Jo޼ZXXHeYc/8uEoܸJ9p--yĦh4ۜ9Y.T4j?K1-r\sέTDSΣ9R偹FRAN[sMY&aމ<1}τ3I r\65}Fn96a*G,{;v[T0lוnsh UF.Mv9tYs'&c[N_~Hti{d(K2{҄#GXU`ĦG} f#zb7$J3YyV{ʌJS__?# 8CqM___ʦZ}'yk 2jAk"9V:#u;wNTUU iODzda_, 2C1b&8D!ћ7o;;;C .P@JR")"EI^0¨U!1b1]!r;^WkdDtonLz,F'F wI@H'%%! ޽{U mXX}7<CKK$%Ĥ*$I. bX3)v!򣃙,&%(O</.N$DH,^(=ª(.NE11B8fs6{#YCb_Eb$=)hEQdaTY bBü*kŋp8qc9 P4H4uJ_W0g1@,8& GFx88Z>8t?go?B,ZTP*z!$,F) 9U1s1W̙羖c1Fw2|f=t~, l۶m(77M")I*uտ EI$ 怹`NyNɈ^>(&obۺts~[r&E$B$R a3Ǝ9`.ce71cw]8MErޅyGH@M}v+WI Fs{{As'p-\,:qH9D !`+>1/q$ss[KZ|'Q8酗yD'x)W*>]MaVc95=3uM`0R_nj1IENDB`cordova-ubuntu-2.8.0+14.04.20140130.3/Cordovaqt/InAppBrowser.qml0000644000015000001560000000216212272510553024215 0ustar pbuserpbgroup00000000000000import QtQuick 2.0 import QtWebKit 3.0 Rectangle { id: inappbrowser property string url: "http://canonical.com" Rectangle { border.color: "black" width: parent.width height: url.height color: "gray" TextInput { id: url width: parent.width - closeButton.width text: inappbrowser.url activeFocusOnPress: false } Image { id: closeButton width: height x: parent.width - width height: parent.height source: "assets/close.png" MouseArea { anchors.fill: parent onClicked: { inappbrowser.parent.exec("com.cordova.InAppBrowser", "close", [0, 0]) } } } } WebView { width: parent.width y: url.height height: parent.height - y url: inappbrowser.url onLoadingChanged: { if (loadRequest.status) { inappbrowser.parent.exec("com.cordova.InAppBrowser", "loadFinished") } } } } cordova-ubuntu-2.8.0+14.04.20140130.3/Cordovaqt/qmldir0000644000015000001560000000020112272510553022332 0ustar pbuserpbgroup00000000000000module CordovaUbuntu plugin cordovaubuntuplugin CordovaView 2.0 CordovaView.qml CordovaViewInternal 2.0 CordovaViewInternal.qml cordova-ubuntu-2.8.0+14.04.20140130.3/Cordovaqt/CaptureWidget.qml0000644000015000001560000001352012272510553024411 0ustar pbuserpbgroup00000000000000import QtQuick 2.0 import QtMultimedia 5.0 Rectangle { property string recordOffImagePath: "assets/record_off.png" property string recordOnImagePath: "assets/record_on.png" property string shootImagePath: "assets/shoot.png" function isSuffix(str, suffix) { return String(str).substr(String(str).length - suffix.length) == suffix } id: ui color: "#252423" state: "off" Camera { objectName: "camera" id: camera cameraState: Camera.UnloadedState onError: { console.log(errorString); shootButton.source = recordOffImagePath } videoRecorder.audioBitRate: 128000 videoRecorder.mediaContainer: "mp4" } Image { id: microphoneImage source: "assets/microphone.png" smooth: true visible: false width: parent.width height: parent.height } VideoOutput { id: output focus : visible source: camera width: parent.width height: parent.height } Item { anchors.bottom: parent.bottom width: parent.width height: shootButton.height BorderImage { id: leftBackground anchors.left: parent.left anchors.top: parent.top anchors.bottom: parent.bottom anchors.right: middle.left anchors.topMargin: units.dp(2) anchors.bottomMargin: units.dp(2) source: "assets/toolbar-left.png" Image { anchors.verticalCenter: parent.verticalCenter anchors.left: parent.left anchors.leftMargin: parent.iconSpacing source: "assets/back.png" width: units.gu(6) height: units.gu(5) MouseArea { anchors.fill: parent onClicked: { if (ui.state === "camera") { ui.parent.exec("com.cordova.Camera", "cancel"); } else if (ui.state === "audio") { ui.parent.exec("com.cordova.Capture", "cancel"); } else if (ui.state === "videoRecording") { ui.parent.exec("com.cordova.Camera", "cancel"); } } } } } BorderImage { id: middle anchors.top: parent.top anchors.bottom: parent.bottom anchors.horizontalCenter: parent.horizontalCenter height: shootButton.height + units.gu(1) width: shootButton.width source: "assets/toolbar-middle.png" Image { id: shootButton width: units.gu(8) height: width anchors.horizontalCenter: parent.horizontalCenter source: shootImagePath MouseArea { anchors.fill: parent onClicked: { if (ui.state === "camera") { camera.imageCapture.capture(); } else if (ui.state === "audio") { ui.parent.exec("com.cordova.Capture", "record"); if (isSuffix(shootButton.source, recordOffImagePath)) { shootButton.source = recordOnImagePath } else { shootButton.source = recordOffImagePath } } else if (ui.state === "videoRecording") { if (!camera.videoRecorder.recorderState) { shootButton.source = recordOnImagePath camera.videoRecorder.record(); } else { camera.videoRecorder.stop(); shootButton.source = recordOffImagePath } } } } } } BorderImage { id: rightBackground anchors.right: parent.right anchors.top: parent.top anchors.bottom: parent.bottom anchors.left: middle.right anchors.topMargin: units.dp(2) anchors.bottomMargin: units.dp(2) source: "assets/toolbar-right.png" } } states: [ State { name: "off" StateChangeScript { script:{ ui.visible = false; camera.stop(); camera.start(); camera.stop(); camera.unlock(); } } }, State { name: "camera" StateChangeScript { script: { camera.start(); microphoneImage.visible = false output.visible = true shootButton.source = shootImagePath ui.visible = true } } }, State { name: "videoRecording" StateChangeScript { script: { shootButton.source = recordOffImagePath camera.start(); microphoneImage.visible = false output.visible = true ui.visible = true } } }, State { name: "audio" StateChangeScript { script:{ shootButton.source = recordOffImagePath camera.stop(); microphoneImage.visible = true camera.unlock(); output.visible = false ui.visible = true } } } ] } cordova-ubuntu-2.8.0+14.04.20140130.3/Cordovaqt/cordova_wrapper.js0000644000015000001560000000316512272510553024666 0ustar pbuserpbgroup00000000000000/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ var pluginObjects = {} function addPlugin(pluginName, pluginObject) { pluginObjects[pluginName] = pluginObject } function messageHandler(message) { var received = JSON.parse(message.data); if (typeof received === 'undefined') return false; if (typeof received.messageType === 'undefined') return false; if (received.messageType === "callPluginFunction") { if (typeof received.plugin === 'undefined' || typeof received.func == 'undefined') return false; execMethod(received.plugin, received.func, received.params); } return true; } function execMethod(pluginName, functionName, params) { if (typeof pluginObjects[pluginName][functionName] != "function") return false; pluginObjects[pluginName][functionName].apply(this, params); return true; } cordova-ubuntu-2.8.0+14.04.20140130.3/CMakeLists.txt0000644000015000001560000001753512272510553021737 0ustar pbuserpbgroup00000000000000cmake_minimum_required(VERSION 2.8.8) project(cordova-ubuntu) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOMOC ON) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}") file (STRINGS "VERSION" tmp) STRING(REGEX MATCH "^[0-9]+\\.[0-9]+" VERSION ${tmp}) STRING(REGEX MATCH "^[0-9]+" MAJOR_VERSION ${tmp}) STRING(REGEX MATCH "[0-9]+$" MINOR_VERSION ${VERSION}) configure_file ( "${PROJECT_SOURCE_DIR}/qml/main.qml.in" "${PROJECT_BINARY_DIR}/main.qml" ) configure_file ( "${PROJECT_SOURCE_DIR}/qml/CordovaView.qml.in" "${PROJECT_BINARY_DIR}/CordovaView.qml" ) SET(CMAKE_CXX_FLAGS "-std=c++0x -Wall -Wextra -DCORDOVA_UBUNTU_VERSION=\\\"${VERSION}\\\" -DCORDOVA_UBUNTU_MAJOR_VERSION=${MAJOR_VERSION} -DCORDOVA_UBUNTU_MINOR_VERSION=${MINOR_VERSION}") set(js_src src/js/cordova.js src/js/cordova.qt.js src/js/console.js src/js/connection.js src/js/device.js src/js/file.js src/js/geolocation.js src/js/notification.js src/js/compass.js src/js/accelerometer.js src/js/camera.js src/js/contacts.js src/js/media.js src/js/globalization.js src/js/capture.js src/js/app.js src/js/splashscreen.js src/js/inappbrowser.js ) add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/www/cordova-${VERSION}.js COMMAND echo \"\(function\(\){\" > ${PROJECT_BINARY_DIR}/www/cordova-${VERSION}.js COMMAND cat ${js_src} >> ${PROJECT_BINARY_DIR}/www/cordova-${VERSION}.js COMMAND echo \"}\)\(\)\;\" >> ${PROJECT_BINARY_DIR}/www/cordova-${VERSION}.js DEPENDS ${js_src} ${PROJECT_BINARY_DIR}/www/index.html SOURCE ${js_src} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} ) add_custom_target(concatenate_js DEPENDS ${PROJECT_BINARY_DIR}/www/cordova-${VERSION}.js) add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/qml COMMAND mkdir -p ${PROJECT_BINARY_DIR}/qml COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_BINARY_DIR}/main.qml ${PROJECT_BINARY_DIR}/qml DEPENDS ${PROJECT_BINARY_DIR}/main.qml ) file(GLOB tmp examples/*) add_custom_command( OUTPUT ${PROJECT_BINARY_DIR}/examples COMMAND mkdir -p ${PROJECT_BINARY_DIR}/examples COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/examples ${PROJECT_BINARY_DIR}/examples DEPENDS ${tmp} ${PROJECT_SOURCE_DIR}/examples ) file(GLOB tmp Cordovaqt/*) add_custom_command( OUTPUT ${PROJECT_BINARY_DIR}/CordovaUbuntu.${VERSION} COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/Cordovaqt ${PROJECT_BINARY_DIR}/CordovaUbuntu.${VERSION} COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_BINARY_DIR}/libcordovaubuntuplugin.so ${PROJECT_BINARY_DIR}/CordovaUbuntu.${VERSION} COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_BINARY_DIR}/CordovaView.qml ${PROJECT_BINARY_DIR}/CordovaUbuntu.${VERSION} DEPENDS ${tmp} cordovaubuntuplugin ${PROJECT_BINARY_DIR}/CordovaView.qml ) file(GLOB tmp xml/*) add_custom_command( OUTPUT ${PROJECT_BINARY_DIR}/xml COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/xml ${PROJECT_BINARY_DIR}/xml DEPENDS ${tmp} ${PROJECT_SOURCE_DIR}/xml ) file(GLOB tmp www/*) add_custom_command( OUTPUT ${PROJECT_BINARY_DIR}/www/index.html COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/www ${PROJECT_BINARY_DIR}/www COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_BINARY_DIR}/libechoplugin.so ${PROJECT_BINARY_DIR}/www COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_BINARY_DIR}/libcoreplugins.so ${PROJECT_BINARY_DIR}/www COMMAND sed "s/\@VERSION\@/${VERSION}/" "${PROJECT_SOURCE_DIR}/www/index.html.in" > "${PROJECT_BINARY_DIR}/www/index.html" DEPENDS ${tmp} ${PROJECT_SOURCE_DIR}/www/index.html.in echoplugin coreplugins ) add_custom_target(copy_wwwqmlxml DEPENDS ${PROJECT_BINARY_DIR}/www/index.html ${PROJECT_BINARY_DIR}/CordovaUbuntu.${VERSION} ${PROJECT_BINARY_DIR}/xml ${PROJECT_BINARY_DIR}/qml) add_custom_target(copy_examples DEPENDS ${PROJECT_BINARY_DIR}/examples) find_package(Qt5Widgets) find_package(Qt5Core) add_executable(cordova-ubuntu-${VERSION} main.cpp ) qt5_use_modules(cordova-ubuntu-${VERSION} Widgets Quick) add_dependencies(cordova-ubuntu-${VERSION} concatenate_js copy_wwwqmlxml copy_examples) ADD_LIBRARY(cordovaubuntuplugin SHARED src/cplugin.cpp src/cordova.cpp src/qmlplugin.cpp src/cordova.h src/cplugin.h src/qmlplugin.h ) qt5_use_modules(cordovaubuntuplugin Widgets Quick) ADD_LIBRARY(coreplugins SHARED src/plugins/accelerometer.h src/plugins/cameraresolution.h src/plugins/capture.h src/plugins/camera.h src/plugins/compass.h src/plugins/connection.h src/plugins/console.h src/plugins/contacts.h src/plugins/device.h src/plugins/events.h src/plugins/fileapi.h src/plugins/geolocation.h src/plugins/globalization.h src/plugins/media.h src/plugins/notification.h src/plugins/app.h src/plugins/splashscreen.h src/plugins/inappbrowser.h src/plugins/accelerometer.cpp src/plugins/capture.cpp src/plugins/camera.cpp src/plugins/compass.cpp src/plugins/connection.cpp src/plugins/console.cpp src/plugins/contacts.cpp src/plugins/device.cpp src/plugins/events.cpp src/cordova.cpp src/plugins/fileapi.cpp src/plugins/geolocation.cpp src/plugins/globalization.cpp src/plugins/media.cpp src/plugins/notification.cpp src/plugins/app.cpp src/plugins/splashscreen.cpp src/plugins/inappbrowser.cpp src/coreplugins.cpp ) qt5_use_modules(coreplugins Widgets Location Sensors Feedback SystemInfo Contacts Multimedia Quick MultimediaWidgets) ADD_LIBRARY(echoplugin SHARED echoplugin/echoplugin.cpp echoplugin/echoplugin.h ) qt5_use_modules(echoplugin Core) find_library(XCB_LIB xcb) target_link_libraries(cordova-ubuntu-${VERSION} ${XCB_LIB} cordovaubuntuplugin) target_link_libraries(coreplugins cordovaubuntuplugin) target_link_libraries(echoplugin cordovaubuntuplugin) # Qt5's cmake does not export QT_IMPORTS_DIR, lets query qmake on our own for now get_target_property(QMAKE_EXECUTABLE Qt5::qmake LOCATION) function(QUERY_QMAKE VAR RESULT) exec_program(${QMAKE_EXECUTABLE} ARGS "-query ${VAR}" RETURN_VALUE return_code OUTPUT_VARIABLE output ) if(NOT return_code) file(TO_CMAKE_PATH "${output}" output) set(${RESULT} ${output} PARENT_SCOPE) endif(NOT return_code) endfunction(QUERY_QMAKE) query_qmake(QT_INSTALL_QML QT_IMPORTS_DIR) install (TARGETS cordova-ubuntu-${VERSION} DESTINATION bin) install (TARGETS echoplugin DESTINATION share/cordova-ubuntu-${VERSION}/www) install (TARGETS coreplugins DESTINATION lib/cordova-ubuntu-${VERSION}/) install (DIRECTORY ${PROJECT_BINARY_DIR}/www ${PROJECT_BINARY_DIR}/xml DESTINATION share/cordova-ubuntu-${VERSION}) install (FILES ${PROJECT_BINARY_DIR}/www/cordova-${VERSION}.js DESTINATION share/cordova-ubuntu-${VERSION}/www) install (FILES src/cordova.h src/cplugin.h DESTINATION include/cordova-ubuntu-${VERSION}/) install (DIRECTORY ${PROJECT_BINARY_DIR}/qml DESTINATION share/cordova-ubuntu-${VERSION}) install (DIRECTORY ${PROJECT_BINARY_DIR}/CordovaUbuntu.${VERSION} DESTINATION ${QT_IMPORTS_DIR}/ PATTERN assets EXCLUDE) install (DIRECTORY ${PROJECT_BINARY_DIR}/CordovaUbuntu.${VERSION}/assets DESTINATION share/cordova-ubuntu-${VERSION}) install (DIRECTORY ${PROJECT_BINARY_DIR}/examples DESTINATION share/cordova-ubuntu-${VERSION} PATTERN *.desktop EXCLUDE) install (FILES examples/qrcode-scanner/CordovaExampleQRCodeScanner.desktop DESTINATION share/applications) install(CODE "EXECUTE_PROCESS( COMMAND ln -svf /usr/share/cordova-ubuntu-${VERSION}/assets \$ENV{DESTDIR}${QT_IMPORTS_DIR}/CordovaUbuntu.${VERSION}/assets )") set (CPACK_PACKAGE_NAME cordova-ubuntu-runtime-${VERSION}) set (CPACK_PACKAGE_VERSION ${VERSION}) set (CPACK_DEBIAN_PACKAGE_DEPENDS "libqt5webkit5-qmlwebkitplugin, qtdeclarative5-qtfeedback-plugin, qtdeclarative5-qtmultimedia-plugin, qtdeclarative5-qtquick2-plugin") set (CPACK_DEBIAN_PACKAGE_MAINTAINER "Maxim Ermilov(maxim.ermilov@canonical.com)") set (CPACK_DEBIAN_PACKAGE_DESCRIPTION "Cordova is a free and open source framework that allows you to create mobile apps using standardized web APIs for the platforms you care about.") INCLUDE(CPack) cordova-ubuntu-2.8.0+14.04.20140130.3/DebSourcePPA.cmake0000644000015000001560000004202112272510553022401 0ustar pbuserpbgroup00000000000000## Debian Source Package Generator # # Copyright (c) 2010 Daniel Pfeifer # Many modifications by Rosen Diankov # # Creates source debian files and manages library dependencies # # Features: # # - Automatically generates symbols and run-time dependencies from the build dependencies # - Custom copy of source directory via CPACK_DEBIAN_PACKAGE_SOURCE_COPY # - Simultaneous output of multiple debian source packages for each distribution # - Can specificy distribution-specific dependencies by suffixing DEPENDS with _${DISTRO_NAME}, for example: CPACK_DEBIAN_PACKAGE_DEPENDS_LUCID, CPACK_COMPONENT_MYCOMP0_DEPENDS_LUCID # # Usage: # # set(CPACK_DEBIAN_BUILD_DEPENDS debhelper cmake) # set(CPACK_DEBIAN_PACKAGE_PRIORITY optional) # set(CPACK_DEBIAN_PACKAGE_SECTION devel) # set(CPACK_DEBIAN_CMAKE_OPTIONS "-DMYOPTION=myvalue") # set(CPACK_DEBIAN_PACKAGE_DEPENDS mycomp0 mycomp1 some_ubuntu_package) # set(CPACK_DEBIAN_PACKAGE_DEPENDS_UBUNTU_LUCID mycomp0 mycomp1 lucid_specific_package) # set(CPACK_DEBIAN_PACKAGE_NAME mypackage) # set(CPACK_DEBIAN_PACKAGE_REMOVE_SOURCE_FILES unnecessary_file unnecessary_dir/file0) # set(CPACK_DEBIAN_PACKAGE_SOURCE_COPY svn export --force) # if using subversion # set(CPACK_DEBIAN_DISTRIBUTION_NAME ubuntu) # set(CPACK_DEBIAN_DISTRIBUTION_RELEASES karmic lucid maverick natty) # set(CPACK_DEBIAN_CHANGELOG " * Extra change log lines") # set(CPACK_DEBIAN_PACKAGE_SUGGESTS "ipython") # set(CPACK_COMPONENT_X_RECOMMENDS "recommended-package") ## find_program(DEBUILD_EXECUTABLE debuild) find_program(DPUT_EXECUTABLE dput) if(NOT DEBUILD_EXECUTABLE OR NOT DPUT_EXECUTABLE) return() endif(NOT DEBUILD_EXECUTABLE OR NOT DPUT_EXECUTABLE) # DEBIAN/control # debian policy enforce lower case for package name # Package: (mandatory) IF(NOT CPACK_DEBIAN_PACKAGE_NAME) STRING(TOLOWER "${CPACK_PACKAGE_NAME}" CPACK_DEBIAN_PACKAGE_NAME) ENDIF(NOT CPACK_DEBIAN_PACKAGE_NAME) # Section: (recommended) IF(NOT CPACK_DEBIAN_PACKAGE_SECTION) SET(CPACK_DEBIAN_PACKAGE_SECTION "devel") ENDIF(NOT CPACK_DEBIAN_PACKAGE_SECTION) # Priority: (recommended) IF(NOT CPACK_DEBIAN_PACKAGE_PRIORITY) SET(CPACK_DEBIAN_PACKAGE_PRIORITY "optional") ENDIF(NOT CPACK_DEBIAN_PACKAGE_PRIORITY) file(STRINGS ${CPACK_PACKAGE_DESCRIPTION_FILE} DESC_LINES) foreach(LINE ${DESC_LINES}) set(DEB_LONG_DESCRIPTION "${DEB_LONG_DESCRIPTION} ${LINE}\n") endforeach(LINE ${DESC_LINES}) file(REMOVE_RECURSE "${CMAKE_BINARY_DIR}/Debian") file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/Debian") set(DEBIAN_SOURCE_ORIG_DIR "${CMAKE_BINARY_DIR}/Debian/${CPACK_DEBIAN_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}") if( CPACK_DEBIAN_PACKAGE_SOURCE_COPY ) execute_process(COMMAND ${CPACK_DEBIAN_PACKAGE_SOURCE_COPY} "${CMAKE_SOURCE_DIR}" "${DEBIAN_SOURCE_ORIG_DIR}.orig") else() execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR} "${DEBIAN_SOURCE_ORIG_DIR}.orig") execute_process(COMMAND ${CMAKE_COMMAND} -E remove_directory "${DEBIAN_SOURCE_ORIG_DIR}.orig/.git") execute_process(COMMAND ${CMAKE_COMMAND} -E remove_directory "${DEBIAN_SOURCE_ORIG_DIR}.orig/.svn") endif() # remove unnecessary folders foreach(REMOVE_DIR ${CPACK_DEBIAN_PACKAGE_REMOVE_SOURCE_FILES}) file(REMOVE_RECURSE ${DEBIAN_SOURCE_ORIG_DIR}.orig/${REMOVE_DIR}) endforeach() # create the original source tar execute_process(COMMAND ${CMAKE_COMMAND} -E tar czf "${CPACK_DEBIAN_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}.orig.tar.gz" "${CPACK_DEBIAN_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}.orig" WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/Debian) set(DEB_SOURCE_CHANGES) foreach(RELEASE ${CPACK_DEBIAN_DISTRIBUTION_RELEASES}) set(DEBIAN_SOURCE_DIR "${DEBIAN_SOURCE_ORIG_DIR}-${CPACK_DEBIAN_DISTRIBUTION_NAME}1~${RELEASE}1") set(RELEASE_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION}-${CPACK_DEBIAN_DISTRIBUTION_NAME}1~${RELEASE}1") string(TOUPPER ${RELEASE} RELEASE_UPPER) string(TOUPPER ${CPACK_DEBIAN_DISTRIBUTION_NAME} DISTRIBUTION_NAME_UPPER) file(MAKE_DIRECTORY ${DEBIAN_SOURCE_DIR}/debian) ############################################################################## # debian/control set(DEBIAN_CONTROL ${DEBIAN_SOURCE_DIR}/debian/control) file(WRITE ${DEBIAN_CONTROL} "Source: ${CPACK_DEBIAN_PACKAGE_NAME}\n" "Section: ${CPACK_DEBIAN_PACKAGE_SECTION}\n" "Priority: ${CPACK_DEBIAN_PACKAGE_PRIORITY}\n" "DM-Upload-Allowed: yes\n" "Maintainer: ${CPACK_PACKAGE_CONTACT}\n" "Build-Depends: " ) if( CPACK_DEBIAN_BUILD_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) foreach(DEP ${CPACK_DEBIAN_BUILD_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}}) file(APPEND ${DEBIAN_CONTROL} "${DEP}, ") endforeach(DEP ${CPACK_DEBIAN_BUILD_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}}) else( CPACK_DEBIAN_BUILD_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) if( CPACK_DEBIAN_BUILD_DEPENDS_${DISTRIBUTION_NAME_UPPER} ) foreach(DEP ${CPACK_DEBIAN_BUILD_DEPENDS_${DISTRIBUTION_NAME_UPPER}}) file(APPEND ${DEBIAN_CONTROL} "${DEP}, ") endforeach(DEP ${CPACK_DEBIAN_BUILD_DEPENDS_${DISTRIBUTION_NAME_UPPER}}) else( CPACK_DEBIAN_BUILD_DEPENDS_${DISTRIBUTION_NAME_UPPER} ) foreach(DEP ${CPACK_DEBIAN_BUILD_DEPENDS}) file(APPEND ${DEBIAN_CONTROL} "${DEP}, ") endforeach(DEP ${CPACK_DEBIAN_BUILD_DEPENDS}) endif( CPACK_DEBIAN_BUILD_DEPENDS_${DISTRIBUTION_NAME_UPPER} ) endif( CPACK_DEBIAN_BUILD_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) file(APPEND ${DEBIAN_CONTROL} "\n" "Standards-Version: 3.8.4\n" "Homepage: ${CPACK_PACKAGE_VENDOR}\n" "\n" "Package: ${CPACK_DEBIAN_PACKAGE_NAME}\n" "Architecture: any\n" "Depends: " ) if( CPACK_DEBIAN_PACKAGE_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) foreach(DEP ${CPACK_DEBIAN_PACKAGE_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}}) file(APPEND ${DEBIAN_CONTROL} "${DEP}, ") endforeach(DEP ${CPACK_DEBIAN_PACKAGE_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}}) else( CPACK_DEBIAN_PACKAGE_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) if( CPACK_DEBIAN_PACKAGE_DEPENDS_${DISTRIBUTION_NAME_UPPER} ) foreach(DEP ${CPACK_DEBIAN_PACKAGE_DEPENDS_${DISTRIBUTION_NAME_UPPER}}) file(APPEND ${DEBIAN_CONTROL} "${DEP}, ") endforeach(DEP ${CPACK_DEBIAN_PACKAGE_DEPENDS_${DISTRIBUTION_NAME_UPPER}}) else( CPACK_DEBIAN_PACKAGE_DEPENDS_${DISTRIBUTION_NAME_UPPER} ) foreach(DEP ${CPACK_DEBIAN_PACKAGE_DEPENDS}) file(APPEND ${DEBIAN_CONTROL} "${DEP}, ") endforeach(DEP ${CPACK_DEBIAN_PACKAGE_DEPENDS}) endif( CPACK_DEBIAN_PACKAGE_DEPENDS_${DISTRIBUTION_NAME_UPPER} ) endif( CPACK_DEBIAN_PACKAGE_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) file(APPEND ${DEBIAN_CONTROL} "\nRecommends: ") if( CPACK_DEBIAN_PACKAGE_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) foreach(DEP ${CPACK_DEBIAN_PACKAGE_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}}) file(APPEND ${DEBIAN_CONTROL} "${DEP}, ") endforeach(DEP ${CPACK_DEBIAN_PACKAGE_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}}) else( CPACK_DEBIAN_PACKAGE_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) if( CPACK_DEBIAN_PACKAGE_RECOMMENDS_${DISTRIBUTION_NAME_UPPER} ) foreach(DEP ${CPACK_DEBIAN_PACKAGE_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}}) file(APPEND ${DEBIAN_CONTROL} "${DEP}, ") endforeach(DEP ${CPACK_DEBIAN_PACKAGE_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}}) else( CPACK_DEBIAN_PACKAGE_RECOMMENDS_${DISTRIBUTION_NAME_UPPER} ) foreach(DEP ${CPACK_DEBIAN_PACKAGE_RECOMMENDS}) file(APPEND ${DEBIAN_CONTROL} "${DEP}, ") endforeach(DEP ${CPACK_DEBIAN_PACKAGE_RECOMMENDS}) endif( CPACK_DEBIAN_PACKAGE_RECOMMENDS_${DISTRIBUTION_NAME_UPPER} ) endif( CPACK_DEBIAN_PACKAGE_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) file(APPEND ${DEBIAN_CONTROL} "\nSuggests: ") if( CPACK_DEBIAN_PACKAGE_SUGGESTS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) foreach(DEP ${CPACK_DEBIAN_PACKAGE_SUGGESTS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}}) file(APPEND ${DEBIAN_CONTROL} "${DEP}, ") endforeach(DEP ${CPACK_DEBIAN_PACKAGE_SUGGESTS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}}) else( CPACK_DEBIAN_PACKAGE_SUGGESTS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) if( CPACK_DEBIAN_PACKAGE_SUGGESTS_${DISTRIBUTION_NAME_UPPER} ) foreach(DEP ${CPACK_DEBIAN_PACKAGE_SUGGESTS_${DISTRIBUTION_NAME_UPPER}}) file(APPEND ${DEBIAN_CONTROL} "${DEP}, ") endforeach(DEP ${CPACK_DEBIAN_PACKAGE_SUGGESTS_${DISTRIBUTION_NAME_UPPER}}) else( CPACK_DEBIAN_PACKAGE_SUGGESTS_${DISTRIBUTION_NAME_UPPER} ) foreach(DEP ${CPACK_DEBIAN_PACKAGE_SUGGESTS}) file(APPEND ${DEBIAN_CONTROL} "${DEP}, ") endforeach(DEP ${CPACK_DEBIAN_PACKAGE_SUGGESTS}) endif( CPACK_DEBIAN_PACKAGE_SUGGESTS_${DISTRIBUTION_NAME_UPPER} ) endif( CPACK_DEBIAN_PACKAGE_SUGGESTS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) file(APPEND ${DEBIAN_CONTROL} "\n" "Description: ${CPACK_PACKAGE_DISPLAY_NAME} ${CPACK_PACKAGE_DESCRIPTION_SUMMARY}\n" "${DEB_LONG_DESCRIPTION}" ) foreach(COMPONENT ${CPACK_COMPONENTS_ALL}) string(TOUPPER ${COMPONENT} UPPER_COMPONENT) set(DEPENDS "\${shlibs:Depends}") if( CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) foreach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}}) set(DEPENDS "${DEPENDS}, ${DEP}") endforeach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}}) else( CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) if( CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS_${DISTRIBUTION_NAME_UPPER} ) foreach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS_${DISTRIBUTION_NAME_UPPER}}) set(DEPENDS "${DEPENDS}, ${DEP}") endforeach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS_${DISTRIBUTION_NAME_UPPER}}) else( CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS_${DISTRIBUTION_NAME_UPPER} ) foreach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS}) set(DEPENDS "${DEPENDS}, ${DEP}") endforeach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS}) endif( CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS_${DISTRIBUTION_NAME_UPPER} ) endif( CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) set(RECOMMENDS) if( CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) foreach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}}) set(RECOMMENDS "${RECOMMENDS} ${DEP}, ") endforeach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}}) else( CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) if( CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS_${DISTRIBUTION_NAME_UPPER} ) foreach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}}) set(RECOMMENDS "${RECOMMENDS} ${DEP}, ") endforeach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}}) else( CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS_${DISTRIBUTION_NAME_UPPER} ) foreach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS}) set(RECOMMENDS "${RECOMMENDS} ${DEP}, ") endforeach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS}) endif( CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS_${DISTRIBUTION_NAME_UPPER} ) endif( CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) set(SUGGESTS) if( CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) foreach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}}) set(SUGGESTS "${SUGGESTS} ${DEP}, ") endforeach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}}) else( CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) if( CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS_${DISTRIBUTION_NAME_UPPER} ) foreach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS_${DISTRIBUTION_NAME_UPPER}}) set(SUGGESTS "${SUGGESTS} ${DEP}, ") endforeach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS_${DISTRIBUTION_NAME_UPPER}}) else( CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS_${DISTRIBUTION_NAME_UPPER} ) foreach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS}) set(SUGGESTS "${SUGGESTS} ${DEP}, ") endforeach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS}) endif( CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS_${DISTRIBUTION_NAME_UPPER} ) endif( CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) file(APPEND ${DEBIAN_CONTROL} "\n" "Package: ${COMPONENT}\n" "Architecture: any\n" "Depends: ${DEPENDS}\n" "Recommends: ${RECOMMENDS}\n" "Suggests: ${SUGGESTS}\n" "Description: ${CPACK_PACKAGE_DISPLAY_NAME} ${CPACK_COMPONENT_${UPPER_COMPONENT}_DISPLAY_NAME}\n" "${DEB_LONG_DESCRIPTION}" " .\n" " ${CPACK_COMPONENT_${UPPER_COMPONENT}_DESCRIPTION}\n" ) endforeach(COMPONENT ${CPACK_COMPONENTS_ALL}) ############################################################################## # debian/copyright set(DEBIAN_COPYRIGHT ${DEBIAN_SOURCE_DIR}/debian/copyright) execute_process(COMMAND ${CMAKE_COMMAND} -E copy ${CPACK_RESOURCE_FILE_LICENSE} ${DEBIAN_COPYRIGHT} ) ############################################################################## # debian/rules set(DEBIAN_RULES ${DEBIAN_SOURCE_DIR}/debian/rules) file(WRITE ${DEBIAN_RULES} "#!/usr/bin/make -f\n" "\n" "BUILDDIR = build_dir\n" "\n" "build:\n" " mkdir $(BUILDDIR)\n" " cd $(BUILDDIR); cmake -DCMAKE_BUILD_TYPE=Release ${CPACK_DEBIAN_CMAKE_OPTIONS} -DCMAKE_INSTALL_PREFIX=/usr ..\n" " $(MAKE) -C $(BUILDDIR) preinstall\n" " touch build\n" "\n" "binary: binary-indep binary-arch\n" "\n" "binary-indep: build\n" "\n" "binary-arch: build\n" " cd $(BUILDDIR); cmake -DCOMPONENT=Unspecified -DCMAKE_INSTALL_PREFIX=../debian/tmp/usr -P cmake_install.cmake\n" " mkdir -p debian/tmp/DEBIAN\n" " dpkg-gensymbols -p${CPACK_DEBIAN_PACKAGE_NAME}\n" ) foreach(COMPONENT ${CPACK_COMPONENTS_ALL}) set(PATH debian/${COMPONENT}) file(APPEND ${DEBIAN_RULES} " cd $(BUILDDIR); cmake -DCOMPONENT=${COMPONENT} -DCMAKE_INSTALL_PREFIX=../${PATH}/usr -P cmake_install.cmake\n" " mkdir -p ${PATH}/DEBIAN\n" " dpkg-gensymbols -p${COMPONENT} -P${PATH}\n" ) endforeach(COMPONENT ${CPACK_COMPONENTS_ALL}) file(APPEND ${DEBIAN_RULES} " dh_shlibdeps\n" " dh_strip\n" # for reducing size " dpkg-gencontrol -p${CPACK_DEBIAN_PACKAGE_NAME}\n" " dpkg --build debian/tmp ..\n" ) foreach(COMPONENT ${CPACK_COMPONENTS_ALL}) set(PATH debian/${COMPONENT}) file(APPEND ${DEBIAN_RULES} " dpkg-gencontrol -p${COMPONENT} -P${PATH} -Tdebian/${COMPONENT}.substvars\n" " dpkg --build ${PATH} ..\n" ) endforeach(COMPONENT ${CPACK_COMPONENTS_ALL}) file(APPEND ${DEBIAN_RULES} "\n" "clean:\n" " rm -f build\n" " rm -rf $(BUILDDIR)\n" "\n" ".PHONY: binary binary-arch binary-indep clean\n" ) execute_process(COMMAND chmod +x ${DEBIAN_RULES}) ############################################################################## # debian/compat file(WRITE ${DEBIAN_SOURCE_DIR}/debian/compat "7") ############################################################################## # debian/source/format file(WRITE ${DEBIAN_SOURCE_DIR}/debian/source/format "3.0 (quilt)") ############################################################################## # debian/changelog set(DEBIAN_CHANGELOG ${DEBIAN_SOURCE_DIR}/debian/changelog) execute_process(COMMAND date -R OUTPUT_VARIABLE DATE_TIME) file(WRITE ${DEBIAN_CHANGELOG} "${CPACK_DEBIAN_PACKAGE_NAME} (${RELEASE_PACKAGE_VERSION}) ${RELEASE}; urgency=medium\n\n" " * Package built with CMake\n\n" "${CPACK_DEBIAN_CHANGELOG}" " -- ${CPACK_PACKAGE_CONTACT} ${DATE_TIME}" ) ############################################################################## # debuild -S if( DEB_SOURCE_CHANGES ) set(DEBUILD_OPTIONS "-sd") else() set(DEBUILD_OPTIONS "-sa") endif() set(SOURCE_CHANGES_FILE "${CPACK_DEBIAN_PACKAGE_NAME}_${RELEASE_PACKAGE_VERSION}_source.changes") set(DEB_SOURCE_CHANGES ${DEB_SOURCE_CHANGES} "${SOURCE_CHANGES_FILE}") add_custom_command(OUTPUT "${SOURCE_CHANGES_FILE}" COMMAND ${DEBUILD_EXECUTABLE} -S ${DEBUILD_OPTIONS} WORKING_DIRECTORY ${DEBIAN_SOURCE_DIR}) endforeach(RELEASE ${CPACK_DEBIAN_DISTRIBUTION_RELEASES}) ############################################################################## # dput ppa:your-lp-id/ppa add_custom_target(dput ${DPUT_EXECUTABLE} ${DPUT_HOST} ${DEB_SOURCE_CHANGES} DEPENDS ${DEB_SOURCE_CHANGES} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/Debian) cordova-ubuntu-2.8.0+14.04.20140130.3/VERSION0000644000015000001560000000000612272510553020230 0ustar pbuserpbgroup000000000000002.8.0 cordova-ubuntu-2.8.0+14.04.20140130.3/main.cpp0000644000015000001560000000612512272510553020620 0ustar pbuserpbgroup00000000000000/* * Copyright 2011 Wolfgang Koller - http://www.gofg.at/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #ifdef Q_OS_LINUX #include #include #endif static void customMessageOutput(QtMsgType type, const QMessageLogContext &, const QString &msg) { switch (type) { case QtDebugMsg: if (qgetenv("DEBUG").size()) { fprintf(stderr, "Debug: %s\n", msg.toStdString().c_str()); } break; case QtWarningMsg: fprintf(stderr, "Warning: %s\n", msg.toStdString().c_str()); break; case QtCriticalMsg: fprintf(stderr, "Critical: %s\n", msg.toStdString().c_str()); break; case QtFatalMsg: fprintf(stderr, "Fatal: %s\n", msg.toStdString().c_str()); abort(); } } int main(int argc, char *argv[]) { qInstallMessageHandler(customMessageOutput); QScopedPointer app(new QApplication(argc, argv)); //TODO: switch to options parser // temprory hack to filter --desktop_file_hint QStringList args = app->arguments().filter(QRegularExpression("^[^-]")); std::string wm_class; QDir wwwDir; qDebug() << args << args[args.size() - 1]; if (QDir(args[args.size() - 1]).exists()) { QDir app_dir(args[args.size() - 1]); QDir parent(app_dir); parent.cdUp(); wm_class = parent.dirName().toStdString(); wwwDir = app_dir; } else { wwwDir = QDir(QApplication::applicationDirPath()); wwwDir.cd("www"); } QScopedPointer view(new QQuickView());; std::string execDir = "/usr/bin"; QDir workingDir; if (QApplication::applicationDirPath().toStdString().substr(0, execDir.size()) == execDir) { workingDir = QString("/usr/share/cordova-ubuntu-") + CORDOVA_UBUNTU_VERSION; } else { workingDir = QApplication::applicationDirPath(); } view->rootContext()->setContextProperty("www", wwwDir.absolutePath()); view->setSource(QUrl(QString("%1/qml/main.qml").arg(workingDir.absolutePath()))); #if defined(Q_OS_LINUX) && defined(Q_PROCESSOR_X86) if (wm_class.size()) { xcb_connection_t *c = xcb_connect(NULL,NULL); xcb_change_property(c, XCB_PROP_MODE_REPLACE, view->winId(), XCB_ATOM_WM_CLASS, XCB_ATOM_STRING, 8, wm_class.size(), wm_class.c_str()); xcb_flush(c); xcb_disconnect(c); } #endif view->setResizeMode(QQuickView::SizeRootObjectToView); view->show(); return app->exec(); } cordova-ubuntu-2.8.0+14.04.20140130.3/xml/0000755000015000001560000000000012272510676017772 5ustar pbuserpbgroup00000000000000cordova-ubuntu-2.8.0+14.04.20140130.3/xml/plugins.xml0000644000015000001560000000352712272510553022176 0ustar pbuserpbgroup00000000000000 cordova-ubuntu-2.8.0+14.04.20140130.3/examples/0000755000015000001560000000000012272510676021010 5ustar pbuserpbgroup00000000000000cordova-ubuntu-2.8.0+14.04.20140130.3/examples/qrcode-scanner/0000755000015000001560000000000012272510676023714 5ustar pbuserpbgroup00000000000000cordova-ubuntu-2.8.0+14.04.20140130.3/examples/qrcode-scanner/plugins.xml0000644000015000001560000000352712272510553026120 0ustar pbuserpbgroup00000000000000 cordova-ubuntu-2.8.0+14.04.20140130.3/examples/qrcode-scanner/CordovaExampleQRCodeScanner.desktop0000644000015000001560000000037012272510553032562 0ustar pbuserpbgroup00000000000000[Desktop Entry] Name=Cordova Example QRCodeScanner Type=Application Exec=/usr/bin/cordova-ubuntu-2.8 /usr/share/cordova-ubuntu-2.8/examples/qrcode-scanner Icon=/usr/share/cordova-ubuntu-2.8/examples/qrcode-scanner/img/qrcode.png X-Ubuntu-Touch=truecordova-ubuntu-2.8.0+14.04.20140130.3/examples/qrcode-scanner/js/0000755000015000001560000000000012272510676024330 5ustar pbuserpbgroup00000000000000cordova-ubuntu-2.8.0+14.04.20140130.3/examples/qrcode-scanner/js/app.js0000644000015000001560000000764712272510553025456 0ustar pbuserpbgroup00000000000000var UI = new UbuntuUI(); document.addEventListener("deviceready", onDeviceReady, false); var SCAN_HISTORY_KEY='scan-code-history-key'; function appendScantoHistory(data) { if ( ! window.localStorage || ! data) { return; } if ( ! window.localStorage.getItem(SCAN_HISTORY_KEY)) { window.localStorage.setItem(SCAN_HISTORY_KEY, JSON.stringify([])); } function saveScanResultTakenAtPosition(position) { var history = JSON.parse(window.localStorage.getItem(SCAN_HISTORY_KEY)); history.push({data: data, time: new Date(), location: position.coords}); window.localStorage.setItem(SCAN_HISTORY_KEY, JSON.stringify(history)); }; function geolocationError(error) { console.log(error); }; // disabled since the geolocation backend does not seem to work // in my quick tests ... /* navigator.geolocation.getCurrentPosition( saveScanResultTakenAtPosition, geolocationError, { maximumAge: 3000, timeout: 5000, enableHighAccuracy: true }); */ // ... instead we just save the result with a dummy position (guess which one!) saveScanResultTakenAtPosition({coords: {latitude: '34.943742', longitude:'136.888269'}}); }; function displayScannedResults(data) { document.getElementById('scan-results').innerHTML = data; }; function doScanCode() { // Error strings returned by the qrcode js library, so that // we can try (even with false positives) to identify scanning // errors & user cancelled operations var ERROR_STRING = 'error decoding QR Code'; var CANCELLED_SCAN = 'canceled'; var onQrScanningComplete = function(data) { navigator.notification.vibrate(1000); displayScannedResults(data); UI.dialog('scanning').hide(); if (data != ERROR_STRING && data != CANCELLED_SCAN) appendScantoHistory(data); }; var onPictureTaken = function (data) { qrcode.callback = onQrScanningComplete; UI.dialog('scanning').show(); qrcode.decode("data:image/jpeg;base64," + data); }; var onPictureErrors = function(message) { console.log('Scan Code error: ' + message); }; navigator.camera.getPicture(onPictureTaken, onPictureErrors, { quality: 100, targetWidth: 300, targetHeight: 300, sourceType: Camera.PictureSourceType.CAMERA, encodingType: Camera.EncodingType.JPEG, destinationType: Camera.DestinationType.DATA_URL }); }; function onHistoryList() { if ( ! window.localStorage.getItem(SCAN_HISTORY_KEY)) return; var history = JSON.parse(window.localStorage.getItem(SCAN_HISTORY_KEY)); UI.list('#history-items-list').removeAllItems(); history.forEach(function (element) { UI.list('#history-items-list').append(element.data, // the label for this item element.time, // no specific 'id' null, // onclick handler function (targetNode, location) { // We use the Cordova inappbrowser 'API' window.open('https://maps.google.ca/maps?safe=off&q=' + location.latitude + '+' + location.longitude); }, element.location); }); }; function onDeviceReady() { UI.init(); // Set up the app by pushing the main view UI.pagestack.push("main-page"); // Wire up the pages logic UI.button('scan').click(function (e) { UI.pagestack.push('scan-page', {subtitle: 'Scan Code'}); displayScannedResults(''); }); UI.button('history').click(function (e) { UI.pagestack.push('history-page', {subtitle: 'Scan History'}); onHistoryList(); }); /* UI.button('clear-history-list').click(function (e) { if (window.localStorage.getItem(SCAN_HISTORY_KEY)) { window.localStorage.setItem(SCAN_HISTORY_KEY, JSON.stringify([])); UI.list('#history-items-list').removeAllItems(); } }); */ UI.button('info').click(function (e) { UI.pagestack.push('info-page', {subtitle: 'Application Info'}); }); UI.button('do-scan').click(function () { doScanCode(); }); }; cordova-ubuntu-2.8.0+14.04.20140130.3/examples/qrcode-scanner/js/lib/0000755000015000001560000000000012272510676025076 5ustar pbuserpbgroup00000000000000cordova-ubuntu-2.8.0+14.04.20140130.3/examples/qrcode-scanner/js/lib/jsqrcode/0000755000015000001560000000000012272510676026710 5ustar pbuserpbgroup00000000000000cordova-ubuntu-2.8.0+14.04.20140130.3/examples/qrcode-scanner/js/lib/jsqrcode/README0000644000015000001560000000310612272510553027562 0ustar pbuserpbgroup00000000000000JavaScript QRCode reader for HTML5 enabled browser. 2011 Lazar Laszlo http://lazarsoft.info Try it online: http://webqr.com This is a port of ZXing qrcode scanner, http://code.google.com/p/zxing. Usage: Include the scripts in the following order: Set qrcode.callback to function "func(data)", where data will get the decoded information. Decode image with: qrcode.decode(url or DataURL). Decode from canvas with "qr-canvas" ID: qrcode.decode() For webcam qrcode decoding (included in the test.html) you will need the camcanvas.swf from http://www.taboca.com/p/camcanvas/cordova-ubuntu-2.8.0+14.04.20140130.3/examples/qrcode-scanner/js/lib/jsqrcode/src/0000755000015000001560000000000012272510676027477 5ustar pbuserpbgroup00000000000000cordova-ubuntu-2.8.0+14.04.20140130.3/examples/qrcode-scanner/js/lib/jsqrcode/src/bitmat.js0000644000015000001560000000512412272510553031311 0ustar pbuserpbgroup00000000000000/* Ported to JavaScript by Lazar Laszlo 2011 lazarsoft@gmail.com, www.lazarsoft.info */ /* * * Copyright 2007 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function BitMatrix( width, height) { if(!height) height=width; if (width < 1 || height < 1) { throw "Both dimensions must be greater than 0"; } this.width = width; this.height = height; var rowSize = width >> 5; if ((width & 0x1f) != 0) { rowSize++; } this.rowSize = rowSize; this.bits = new Array(rowSize * height); for(var i=0;i> 5); return ((URShift(this.bits[offset], (x & 0x1f))) & 1) != 0; } this.set_Renamed=function( x, y) { var offset = y * this.rowSize + (x >> 5); this.bits[offset] |= 1 << (x & 0x1f); } this.flip=function( x, y) { var offset = y * this.rowSize + (x >> 5); this.bits[offset] ^= 1 << (x & 0x1f); } this.clear=function() { var max = this.bits.length; for (var i = 0; i < max; i++) { this.bits[i] = 0; } } this.setRegion=function( left, top, width, height) { if (top < 0 || left < 0) { throw "Left and top must be nonnegative"; } if (height < 1 || width < 1) { throw "Height and width must be at least 1"; } var right = left + width; var bottom = top + height; if (bottom > this.height || right > this.width) { throw "The region must fit inside the matrix"; } for (var y = top; y < bottom; y++) { var offset = y * this.rowSize; for (var x = left; x < right; x++) { this.bits[offset + (x >> 5)] |= 1 << (x & 0x1f); } } } }cordova-ubuntu-2.8.0+14.04.20140130.3/examples/qrcode-scanner/js/lib/jsqrcode/src/databr.js0000644000015000001560000002256212272510553031273 0ustar pbuserpbgroup00000000000000/* Ported to JavaScript by Lazar Laszlo 2011 lazarsoft@gmail.com, www.lazarsoft.info */ /* * * Copyright 2007 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function QRCodeDataBlockReader(blocks, version, numErrorCorrectionCode) { this.blockPointer = 0; this.bitPointer = 7; this.dataLength = 0; this.blocks = blocks; this.numErrorCorrectionCode = numErrorCorrectionCode; if (version <= 9) this.dataLengthMode = 0; else if (version >= 10 && version <= 26) this.dataLengthMode = 1; else if (version >= 27 && version <= 40) this.dataLengthMode = 2; this.getNextBits = function( numBits) { var bits = 0; if (numBits < this.bitPointer + 1) { // next word fits into current data block var mask = 0; for (var i = 0; i < numBits; i++) { mask += (1 << i); } mask <<= (this.bitPointer - numBits + 1); bits = (this.blocks[this.blockPointer] & mask) >> (this.bitPointer - numBits + 1); this.bitPointer -= numBits; return bits; } else if (numBits < this.bitPointer + 1 + 8) { // next word crosses 2 data blocks var mask1 = 0; for (var i = 0; i < this.bitPointer + 1; i++) { mask1 += (1 << i); } bits = (this.blocks[this.blockPointer] & mask1) << (numBits - (this.bitPointer + 1)); this.blockPointer++; bits += ((this.blocks[this.blockPointer]) >> (8 - (numBits - (this.bitPointer + 1)))); this.bitPointer = this.bitPointer - numBits % 8; if (this.bitPointer < 0) { this.bitPointer = 8 + this.bitPointer; } return bits; } else if (numBits < this.bitPointer + 1 + 16) { // next word crosses 3 data blocks var mask1 = 0; // mask of first block var mask3 = 0; // mask of 3rd block //bitPointer + 1 : number of bits of the 1st block //8 : number of the 2nd block (note that use already 8bits because next word uses 3 data blocks) //numBits - (bitPointer + 1 + 8) : number of bits of the 3rd block for (var i = 0; i < this.bitPointer + 1; i++) { mask1 += (1 << i); } var bitsFirstBlock = (this.blocks[this.blockPointer] & mask1) << (numBits - (this.bitPointer + 1)); this.blockPointer++; var bitsSecondBlock = this.blocks[this.blockPointer] << (numBits - (this.bitPointer + 1 + 8)); this.blockPointer++; for (var i = 0; i < numBits - (this.bitPointer + 1 + 8); i++) { mask3 += (1 << i); } mask3 <<= 8 - (numBits - (this.bitPointer + 1 + 8)); var bitsThirdBlock = (this.blocks[this.blockPointer] & mask3) >> (8 - (numBits - (this.bitPointer + 1 + 8))); bits = bitsFirstBlock + bitsSecondBlock + bitsThirdBlock; this.bitPointer = this.bitPointer - (numBits - 8) % 8; if (this.bitPointer < 0) { this.bitPointer = 8 + this.bitPointer; } return bits; } else { return 0; } } this.NextMode=function() { if ((this.blockPointer > this.blocks.length - this.numErrorCorrectionCode - 2)) return 0; else return this.getNextBits(4); } this.getDataLength=function( modeIndicator) { var index = 0; while (true) { if ((modeIndicator >> index) == 1) break; index++; } return this.getNextBits(qrcode.sizeOfDataLengthInfo[this.dataLengthMode][index]); } this.getRomanAndFigureString=function( dataLength) { var length = dataLength; var intData = 0; var strData = ""; var tableRomanAndFigure = new Array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', '$', '%', '*', '+', '-', '.', '/', ':'); do { if (length > 1) { intData = this.getNextBits(11); var firstLetter = Math.floor(intData / 45); var secondLetter = intData % 45; strData += tableRomanAndFigure[firstLetter]; strData += tableRomanAndFigure[secondLetter]; length -= 2; } else if (length == 1) { intData = this.getNextBits(6); strData += tableRomanAndFigure[intData]; length -= 1; } } while (length > 0); return strData; } this.getFigureString=function( dataLength) { var length = dataLength; var intData = 0; var strData = ""; do { if (length >= 3) { intData = this.getNextBits(10); if (intData < 100) strData += "0"; if (intData < 10) strData += "0"; length -= 3; } else if (length == 2) { intData = this.getNextBits(7); if (intData < 10) strData += "0"; length -= 2; } else if (length == 1) { intData = this.getNextBits(4); length -= 1; } strData += intData; } while (length > 0); return strData; } this.get8bitByteArray=function( dataLength) { var length = dataLength; var intData = 0; var output = new Array(); do { intData = this.getNextBits(8); output.push( intData); length--; } while (length > 0); return output; } this.getKanjiString=function( dataLength) { var length = dataLength; var intData = 0; var unicodeString = ""; do { intData = getNextBits(13); var lowerByte = intData % 0xC0; var higherByte = intData / 0xC0; var tempWord = (higherByte << 8) + lowerByte; var shiftjisWord = 0; if (tempWord + 0x8140 <= 0x9FFC) { // between 8140 - 9FFC on Shift_JIS character set shiftjisWord = tempWord + 0x8140; } else { // between E040 - EBBF on Shift_JIS character set shiftjisWord = tempWord + 0xC140; } //var tempByte = new Array(0,0); //tempByte[0] = (sbyte) (shiftjisWord >> 8); //tempByte[1] = (sbyte) (shiftjisWord & 0xFF); //unicodeString += new String(SystemUtils.ToCharArray(SystemUtils.ToByteArray(tempByte))); unicodeString += String.fromCharCode(shiftjisWord); length--; } while (length > 0); return unicodeString; } this.__defineGetter__("DataByte", function() { var output = new Array(); var MODE_NUMBER = 1; var MODE_ROMAN_AND_NUMBER = 2; var MODE_8BIT_BYTE = 4; var MODE_KANJI = 8; do { var mode = this.NextMode(); //canvas.println("mode: " + mode); if (mode == 0) { if (output.length > 0) break; else throw "Empty data block"; } //if (mode != 1 && mode != 2 && mode != 4 && mode != 8) // break; //} if (mode != MODE_NUMBER && mode != MODE_ROMAN_AND_NUMBER && mode != MODE_8BIT_BYTE && mode != MODE_KANJI) { /* canvas.println("Invalid mode: " + mode); mode = guessMode(mode); canvas.println("Guessed mode: " + mode); */ throw "Invalid mode: " + mode + " in (block:" + this.blockPointer + " bit:" + this.bitPointer + ")"; } dataLength = this.getDataLength(mode); if (dataLength < 1) throw "Invalid data length: " + dataLength; //canvas.println("length: " + dataLength); switch (mode) { case MODE_NUMBER: //canvas.println("Mode: Figure"); var temp_str = this.getFigureString(dataLength); var ta = new Array(temp_str.length); for(var j=0;j Math.abs(toX - fromX); if (steep) { var temp = fromX; fromX = fromY; fromY = temp; temp = toX; toX = toY; toY = temp; } var dx = Math.abs(toX - fromX); var dy = Math.abs(toY - fromY); var error = - dx >> 1; var ystep = fromY < toY?1:- 1; var xstep = fromX < toX?1:- 1; var state = 0; // In black pixels, looking for white, first or second time for (var x = fromX, y = fromY; x != toX; x += xstep) { var realX = steep?y:x; var realY = steep?x:y; if (state == 1) { // In white pixels, looking for black if (this.image[realX + realY*qrcode.width]) { state++; } } else { if (!this.image[realX + realY*qrcode.width]) { state++; } } if (state == 3) { // Found black, white, black, and stumbled back onto white; done var diffX = x - fromX; var diffY = y - fromY; return Math.sqrt( (diffX * diffX + diffY * diffY)); } error += dy; if (error > 0) { if (y == toY) { break; } y += ystep; error -= dx; } } var diffX2 = toX - fromX; var diffY2 = toY - fromY; return Math.sqrt( (diffX2 * diffX2 + diffY2 * diffY2)); } this.sizeOfBlackWhiteBlackRunBothWays=function( fromX, fromY, toX, toY) { var result = this.sizeOfBlackWhiteBlackRun(fromX, fromY, toX, toY); // Now count other way -- don't run off image though of course var scale = 1.0; var otherToX = fromX - (toX - fromX); if (otherToX < 0) { scale = fromX / (fromX - otherToX); otherToX = 0; } else if (otherToX >= qrcode.width) { scale = (qrcode.width - 1 - fromX) / (otherToX - fromX); otherToX = qrcode.width - 1; } var otherToY = Math.floor (fromY - (toY - fromY) * scale); scale = 1.0; if (otherToY < 0) { scale = fromY / (fromY - otherToY); otherToY = 0; } else if (otherToY >= qrcode.height) { scale = (qrcode.height - 1 - fromY) / (otherToY - fromY); otherToY = qrcode.height - 1; } otherToX = Math.floor (fromX + (otherToX - fromX) * scale); result += this.sizeOfBlackWhiteBlackRun(fromX, fromY, otherToX, otherToY); return result - 1.0; // -1 because we counted the middle pixel twice } this.calculateModuleSizeOneWay=function( pattern, otherPattern) { var moduleSizeEst1 = this.sizeOfBlackWhiteBlackRunBothWays(Math.floor( pattern.X), Math.floor( pattern.Y), Math.floor( otherPattern.X), Math.floor(otherPattern.Y)); var moduleSizeEst2 = this.sizeOfBlackWhiteBlackRunBothWays(Math.floor(otherPattern.X), Math.floor(otherPattern.Y), Math.floor( pattern.X), Math.floor(pattern.Y)); if (isNaN(moduleSizeEst1)) { return moduleSizeEst2 / 7.0; } if (isNaN(moduleSizeEst2)) { return moduleSizeEst1 / 7.0; } // Average them, and divide by 7 since we've counted the width of 3 black modules, // and 1 white and 1 black module on either side. Ergo, divide sum by 14. return (moduleSizeEst1 + moduleSizeEst2) / 14.0; } this.calculateModuleSize=function( topLeft, topRight, bottomLeft) { // Take the average return (this.calculateModuleSizeOneWay(topLeft, topRight) + this.calculateModuleSizeOneWay(topLeft, bottomLeft)) / 2.0; } this.distance=function( pattern1, pattern2) { xDiff = pattern1.X - pattern2.X; yDiff = pattern1.Y - pattern2.Y; return Math.sqrt( (xDiff * xDiff + yDiff * yDiff)); } this.computeDimension=function( topLeft, topRight, bottomLeft, moduleSize) { var tltrCentersDimension = Math.round(this.distance(topLeft, topRight) / moduleSize); var tlblCentersDimension = Math.round(this.distance(topLeft, bottomLeft) / moduleSize); var dimension = ((tltrCentersDimension + tlblCentersDimension) >> 1) + 7; switch (dimension & 0x03) { // mod 4 case 0: dimension++; break; // 1? do nothing case 2: dimension--; break; case 3: throw "Error"; } return dimension; } this.findAlignmentInRegion=function( overallEstModuleSize, estAlignmentX, estAlignmentY, allowanceFactor) { // Look for an alignment pattern (3 modules in size) around where it // should be var allowance = Math.floor (allowanceFactor * overallEstModuleSize); var alignmentAreaLeftX = Math.max(0, estAlignmentX - allowance); var alignmentAreaRightX = Math.min(qrcode.width - 1, estAlignmentX + allowance); if (alignmentAreaRightX - alignmentAreaLeftX < overallEstModuleSize * 3) { throw "Error"; } var alignmentAreaTopY = Math.max(0, estAlignmentY - allowance); var alignmentAreaBottomY = Math.min(qrcode.height - 1, estAlignmentY + allowance); var alignmentFinder = new AlignmentPatternFinder(this.image, alignmentAreaLeftX, alignmentAreaTopY, alignmentAreaRightX - alignmentAreaLeftX, alignmentAreaBottomY - alignmentAreaTopY, overallEstModuleSize, this.resultPointCallback); return alignmentFinder.find(); } this.createTransform=function( topLeft, topRight, bottomLeft, alignmentPattern, dimension) { var dimMinusThree = dimension - 3.5; var bottomRightX; var bottomRightY; var sourceBottomRightX; var sourceBottomRightY; if (alignmentPattern != null) { bottomRightX = alignmentPattern.X; bottomRightY = alignmentPattern.Y; sourceBottomRightX = sourceBottomRightY = dimMinusThree - 3.0; } else { // Don't have an alignment pattern, just make up the bottom-right point bottomRightX = (topRight.X - topLeft.X) + bottomLeft.X; bottomRightY = (topRight.Y - topLeft.Y) + bottomLeft.Y; sourceBottomRightX = sourceBottomRightY = dimMinusThree; } var transform = PerspectiveTransform.quadrilateralToQuadrilateral(3.5, 3.5, dimMinusThree, 3.5, sourceBottomRightX, sourceBottomRightY, 3.5, dimMinusThree, topLeft.X, topLeft.Y, topRight.X, topRight.Y, bottomRightX, bottomRightY, bottomLeft.X, bottomLeft.Y); return transform; } this.sampleGrid=function( image, transform, dimension) { var sampler = GridSampler; return sampler.sampleGrid3(image, dimension, transform); } this.processFinderPatternInfo = function( info) { var topLeft = info.TopLeft; var topRight = info.TopRight; var bottomLeft = info.BottomLeft; var moduleSize = this.calculateModuleSize(topLeft, topRight, bottomLeft); if (moduleSize < 1.0) { throw "Error"; } var dimension = this.computeDimension(topLeft, topRight, bottomLeft, moduleSize); var provisionalVersion = Version.getProvisionalVersionForDimension(dimension); var modulesBetweenFPCenters = provisionalVersion.DimensionForVersion - 7; var alignmentPattern = null; // Anything above version 1 has an alignment pattern if (provisionalVersion.AlignmentPatternCenters.length > 0) { // Guess where a "bottom right" finder pattern would have been var bottomRightX = topRight.X - topLeft.X + bottomLeft.X; var bottomRightY = topRight.Y - topLeft.Y + bottomLeft.Y; // Estimate that alignment pattern is closer by 3 modules // from "bottom right" to known top left location var correctionToTopLeft = 1.0 - 3.0 / modulesBetweenFPCenters; var estAlignmentX = Math.floor (topLeft.X + correctionToTopLeft * (bottomRightX - topLeft.X)); var estAlignmentY = Math.floor (topLeft.Y + correctionToTopLeft * (bottomRightY - topLeft.Y)); // Kind of arbitrary -- expand search radius before giving up for (var i = 4; i <= 16; i <<= 1) { //try //{ alignmentPattern = this.findAlignmentInRegion(moduleSize, estAlignmentX, estAlignmentY, i); break; //} //catch (re) //{ // try next round //} } // If we didn't find alignment pattern... well try anyway without it } var transform = this.createTransform(topLeft, topRight, bottomLeft, alignmentPattern, dimension); var bits = this.sampleGrid(this.image, transform, dimension); var points; if (alignmentPattern == null) { points = new Array(bottomLeft, topLeft, topRight); } else { points = new Array(bottomLeft, topLeft, topRight, alignmentPattern); } return new DetectorResult(bits, points); } this.detect=function() { var info = new FinderPatternFinder().findFinderPattern(this.image); return this.processFinderPatternInfo(info); } }cordova-ubuntu-2.8.0+14.04.20140130.3/examples/qrcode-scanner/js/lib/jsqrcode/src/bmparser.js0000644000015000001560000001322412272510553031644 0ustar pbuserpbgroup00000000000000/* Ported to JavaScript by Lazar Laszlo 2011 lazarsoft@gmail.com, www.lazarsoft.info */ /* * * Copyright 2007 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function BitMatrixParser(bitMatrix) { var dimension = bitMatrix.Dimension; if (dimension < 21 || (dimension & 0x03) != 1) { throw "Error BitMatrixParser"; } this.bitMatrix = bitMatrix; this.parsedVersion = null; this.parsedFormatInfo = null; this.copyBit=function( i, j, versionBits) { return this.bitMatrix.get_Renamed(i, j)?(versionBits << 1) | 0x1:versionBits << 1; } this.readFormatInformation=function() { if (this.parsedFormatInfo != null) { return this.parsedFormatInfo; } // Read top-left format info bits var formatInfoBits = 0; for (var i = 0; i < 6; i++) { formatInfoBits = this.copyBit(i, 8, formatInfoBits); } // .. and skip a bit in the timing pattern ... formatInfoBits = this.copyBit(7, 8, formatInfoBits); formatInfoBits = this.copyBit(8, 8, formatInfoBits); formatInfoBits = this.copyBit(8, 7, formatInfoBits); // .. and skip a bit in the timing pattern ... for (var j = 5; j >= 0; j--) { formatInfoBits = this.copyBit(8, j, formatInfoBits); } this.parsedFormatInfo = FormatInformation.decodeFormatInformation(formatInfoBits); if (this.parsedFormatInfo != null) { return this.parsedFormatInfo; } // Hmm, failed. Try the top-right/bottom-left pattern var dimension = this.bitMatrix.Dimension; formatInfoBits = 0; var iMin = dimension - 8; for (var i = dimension - 1; i >= iMin; i--) { formatInfoBits = this.copyBit(i, 8, formatInfoBits); } for (var j = dimension - 7; j < dimension; j++) { formatInfoBits = this.copyBit(8, j, formatInfoBits); } this.parsedFormatInfo = FormatInformation.decodeFormatInformation(formatInfoBits); if (this.parsedFormatInfo != null) { return this.parsedFormatInfo; } throw "Error readFormatInformation"; } this.readVersion=function() { if (this.parsedVersion != null) { return this.parsedVersion; } var dimension = this.bitMatrix.Dimension; var provisionalVersion = (dimension - 17) >> 2; if (provisionalVersion <= 6) { return Version.getVersionForNumber(provisionalVersion); } // Read top-right version info: 3 wide by 6 tall var versionBits = 0; var ijMin = dimension - 11; for (var j = 5; j >= 0; j--) { for (var i = dimension - 9; i >= ijMin; i--) { versionBits = this.copyBit(i, j, versionBits); } } this.parsedVersion = Version.decodeVersionInformation(versionBits); if (this.parsedVersion != null && this.parsedVersion.DimensionForVersion == dimension) { return this.parsedVersion; } // Hmm, failed. Try bottom left: 6 wide by 3 tall versionBits = 0; for (var i = 5; i >= 0; i--) { for (var j = dimension - 9; j >= ijMin; j--) { versionBits = this.copyBit(i, j, versionBits); } } this.parsedVersion = Version.decodeVersionInformation(versionBits); if (this.parsedVersion != null && this.parsedVersion.DimensionForVersion == dimension) { return this.parsedVersion; } throw "Error readVersion"; } this.readCodewords=function() { var formatInfo = this.readFormatInformation(); var version = this.readVersion(); // Get the data mask for the format used in this QR Code. This will exclude // some bits from reading as we wind through the bit matrix. var dataMask = DataMask.forReference( formatInfo.DataMask); var dimension = this.bitMatrix.Dimension; dataMask.unmaskBitMatrix(this.bitMatrix, dimension); var functionPattern = version.buildFunctionPattern(); var readingUp = true; var result = new Array(version.TotalCodewords); var resultOffset = 0; var currentByte = 0; var bitsRead = 0; // Read columns in pairs, from right to left for (var j = dimension - 1; j > 0; j -= 2) { if (j == 6) { // Skip whole column with vertical alignment pattern; // saves time and makes the other code proceed more cleanly j--; } // Read alternatingly from bottom to top then top to bottom for (var count = 0; count < dimension; count++) { var i = readingUp?dimension - 1 - count:count; for (var col = 0; col < 2; col++) { // Ignore bits covered by the function pattern if (!functionPattern.get_Renamed(j - col, i)) { // Read a bit bitsRead++; currentByte <<= 1; if (this.bitMatrix.get_Renamed(j - col, i)) { currentByte |= 1; } // If we've made a whole byte, save it off if (bitsRead == 8) { result[resultOffset++] = currentByte; bitsRead = 0; currentByte = 0; } } } } readingUp ^= true; // readingUp = !readingUp; // switch directions } if (resultOffset != version.TotalCodewords) { throw "Error readCodewords"; } return result; } }cordova-ubuntu-2.8.0+14.04.20140130.3/examples/qrcode-scanner/js/lib/jsqrcode/src/formatinf.js0000644000015000001560000001021512272510553032013 0ustar pbuserpbgroup00000000000000/* Ported to JavaScript by Lazar Laszlo 2011 lazarsoft@gmail.com, www.lazarsoft.info */ /* * * Copyright 2007 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ var FORMAT_INFO_MASK_QR = 0x5412; var FORMAT_INFO_DECODE_LOOKUP = new Array(new Array(0x5412, 0x00), new Array(0x5125, 0x01), new Array(0x5E7C, 0x02), new Array(0x5B4B, 0x03), new Array(0x45F9, 0x04), new Array(0x40CE, 0x05), new Array(0x4F97, 0x06), new Array(0x4AA0, 0x07), new Array(0x77C4, 0x08), new Array(0x72F3, 0x09), new Array(0x7DAA, 0x0A), new Array(0x789D, 0x0B), new Array(0x662F, 0x0C), new Array(0x6318, 0x0D), new Array(0x6C41, 0x0E), new Array(0x6976, 0x0F), new Array(0x1689, 0x10), new Array(0x13BE, 0x11), new Array(0x1CE7, 0x12), new Array(0x19D0, 0x13), new Array(0x0762, 0x14), new Array(0x0255, 0x15), new Array(0x0D0C, 0x16), new Array(0x083B, 0x17), new Array(0x355F, 0x18), new Array(0x3068, 0x19), new Array(0x3F31, 0x1A), new Array(0x3A06, 0x1B), new Array(0x24B4, 0x1C), new Array(0x2183, 0x1D), new Array(0x2EDA, 0x1E), new Array(0x2BED, 0x1F)); var BITS_SET_IN_HALF_BYTE = new Array(0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4); function FormatInformation(formatInfo) { this.errorCorrectionLevel = ErrorCorrectionLevel.forBits((formatInfo >> 3) & 0x03); this.dataMask = (formatInfo & 0x07); this.__defineGetter__("ErrorCorrectionLevel", function() { return this.errorCorrectionLevel; }); this.__defineGetter__("DataMask", function() { return this.dataMask; }); this.GetHashCode=function() { return (this.errorCorrectionLevel.ordinal() << 3) | dataMask; } this.Equals=function( o) { var other = o; return this.errorCorrectionLevel == other.errorCorrectionLevel && this.dataMask == other.dataMask; } } FormatInformation.numBitsDiffering=function( a, b) { a ^= b; // a now has a 1 bit exactly where its bit differs with b's // Count bits set quickly with a series of lookups: return BITS_SET_IN_HALF_BYTE[a & 0x0F] + BITS_SET_IN_HALF_BYTE[(URShift(a, 4) & 0x0F)] + BITS_SET_IN_HALF_BYTE[(URShift(a, 8) & 0x0F)] + BITS_SET_IN_HALF_BYTE[(URShift(a, 12) & 0x0F)] + BITS_SET_IN_HALF_BYTE[(URShift(a, 16) & 0x0F)] + BITS_SET_IN_HALF_BYTE[(URShift(a, 20) & 0x0F)] + BITS_SET_IN_HALF_BYTE[(URShift(a, 24) & 0x0F)] + BITS_SET_IN_HALF_BYTE[(URShift(a, 28) & 0x0F)]; } FormatInformation.decodeFormatInformation=function( maskedFormatInfo) { var formatInfo = FormatInformation.doDecodeFormatInformation(maskedFormatInfo); if (formatInfo != null) { return formatInfo; } // Should return null, but, some QR codes apparently // do not mask this info. Try again by actually masking the pattern // first return FormatInformation.doDecodeFormatInformation(maskedFormatInfo ^ FORMAT_INFO_MASK_QR); } FormatInformation.doDecodeFormatInformation=function( maskedFormatInfo) { // Find the int in FORMAT_INFO_DECODE_LOOKUP with fewest bits differing var bestDifference = 0xffffffff; var bestFormatInfo = 0; for (var i = 0; i < FORMAT_INFO_DECODE_LOOKUP.length; i++) { var decodeInfo = FORMAT_INFO_DECODE_LOOKUP[i]; var targetInfo = decodeInfo[0]; if (targetInfo == maskedFormatInfo) { // Found an exact match return new FormatInformation(decodeInfo[1]); } var bitsDifference = this.numBitsDiffering(maskedFormatInfo, targetInfo); if (bitsDifference < bestDifference) { bestFormatInfo = decodeInfo[1]; bestDifference = bitsDifference; } } // Hamming distance of the 32 masked codes is 7, by construction, so <= 3 bits // differing means we found a match if (bestDifference <= 3) { return new FormatInformation(bestFormatInfo); } return null; } cordova-ubuntu-2.8.0+14.04.20140130.3/examples/qrcode-scanner/js/lib/jsqrcode/src/alignpat.js0000644000015000001560000001653512272510553031640 0ustar pbuserpbgroup00000000000000/* Ported to JavaScript by Lazar Laszlo 2011 lazarsoft@gmail.com, www.lazarsoft.info */ /* * * Copyright 2007 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function AlignmentPattern(posX, posY, estimatedModuleSize) { this.x=posX; this.y=posY; this.count = 1; this.estimatedModuleSize = estimatedModuleSize; this.__defineGetter__("EstimatedModuleSize", function() { return this.estimatedModuleSize; }); this.__defineGetter__("Count", function() { return this.count; }); this.__defineGetter__("X", function() { return Math.floor(this.x); }); this.__defineGetter__("Y", function() { return Math.floor(this.y); }); this.incrementCount = function() { this.count++; } this.aboutEquals=function( moduleSize, i, j) { if (Math.abs(i - this.y) <= moduleSize && Math.abs(j - this.x) <= moduleSize) { var moduleSizeDiff = Math.abs(moduleSize - this.estimatedModuleSize); return moduleSizeDiff <= 1.0 || moduleSizeDiff / this.estimatedModuleSize <= 1.0; } return false; } } function AlignmentPatternFinder( image, startX, startY, width, height, moduleSize, resultPointCallback) { this.image = image; this.possibleCenters = new Array(); this.startX = startX; this.startY = startY; this.width = width; this.height = height; this.moduleSize = moduleSize; this.crossCheckStateCount = new Array(0,0,0); this.resultPointCallback = resultPointCallback; this.centerFromEnd=function(stateCount, end) { return (end - stateCount[2]) - stateCount[1] / 2.0; } this.foundPatternCross = function(stateCount) { var moduleSize = this.moduleSize; var maxVariance = moduleSize / 2.0; for (var i = 0; i < 3; i++) { if (Math.abs(moduleSize - stateCount[i]) >= maxVariance) { return false; } } return true; } this.crossCheckVertical=function( startI, centerJ, maxCount, originalStateCountTotal) { var image = this.image; var maxI = qrcode.height; var stateCount = this.crossCheckStateCount; stateCount[0] = 0; stateCount[1] = 0; stateCount[2] = 0; // Start counting up from center var i = startI; while (i >= 0 && image[centerJ + i*qrcode.width] && stateCount[1] <= maxCount) { stateCount[1]++; i--; } // If already too many modules in this state or ran off the edge: if (i < 0 || stateCount[1] > maxCount) { return NaN; } while (i >= 0 && !image[centerJ + i*qrcode.width] && stateCount[0] <= maxCount) { stateCount[0]++; i--; } if (stateCount[0] > maxCount) { return NaN; } // Now also count down from center i = startI + 1; while (i < maxI && image[centerJ + i*qrcode.width] && stateCount[1] <= maxCount) { stateCount[1]++; i++; } if (i == maxI || stateCount[1] > maxCount) { return NaN; } while (i < maxI && !image[centerJ + i*qrcode.width] && stateCount[2] <= maxCount) { stateCount[2]++; i++; } if (stateCount[2] > maxCount) { return NaN; } var stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2]; if (5 * Math.abs(stateCountTotal - originalStateCountTotal) >= 2 * originalStateCountTotal) { return NaN; } return this.foundPatternCross(stateCount)?this.centerFromEnd(stateCount, i):NaN; } this.handlePossibleCenter=function( stateCount, i, j) { var stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2]; var centerJ = this.centerFromEnd(stateCount, j); var centerI = this.crossCheckVertical(i, Math.floor (centerJ), 2 * stateCount[1], stateCountTotal); if (!isNaN(centerI)) { var estimatedModuleSize = (stateCount[0] + stateCount[1] + stateCount[2]) / 3.0; var max = this.possibleCenters.length; for (var index = 0; index < max; index++) { var center = this.possibleCenters[index]; // Look for about the same center and module size: if (center.aboutEquals(estimatedModuleSize, centerI, centerJ)) { return new AlignmentPattern(centerJ, centerI, estimatedModuleSize); } } // Hadn't found this before; save it var point = new AlignmentPattern(centerJ, centerI, estimatedModuleSize); this.possibleCenters.push(point); if (this.resultPointCallback != null) { this.resultPointCallback.foundPossibleResultPoint(point); } } return null; } this.find = function() { var startX = this.startX; var height = this.height; var maxJ = startX + width; var middleI = startY + (height >> 1); // We are looking for black/white/black modules in 1:1:1 ratio; // this tracks the number of black/white/black modules seen so far var stateCount = new Array(0,0,0); for (var iGen = 0; iGen < height; iGen++) { // Search from middle outwards var i = middleI + ((iGen & 0x01) == 0?((iGen + 1) >> 1):- ((iGen + 1) >> 1)); stateCount[0] = 0; stateCount[1] = 0; stateCount[2] = 0; var j = startX; // Burn off leading white pixels before anything else; if we start in the middle of // a white run, it doesn't make sense to count its length, since we don't know if the // white run continued to the left of the start point while (j < maxJ && !image[j + qrcode.width* i]) { j++; } var currentState = 0; while (j < maxJ) { if (image[j + i*qrcode.width]) { // Black pixel if (currentState == 1) { // Counting black pixels stateCount[currentState]++; } else { // Counting white pixels if (currentState == 2) { // A winner? if (this.foundPatternCross(stateCount)) { // Yes var confirmed = this.handlePossibleCenter(stateCount, i, j); if (confirmed != null) { return confirmed; } } stateCount[0] = stateCount[2]; stateCount[1] = 1; stateCount[2] = 0; currentState = 1; } else { stateCount[++currentState]++; } } } else { // White pixel if (currentState == 1) { // Counting black pixels currentState++; } stateCount[currentState]++; } j++; } if (this.foundPatternCross(stateCount)) { var confirmed = this.handlePossibleCenter(stateCount, i, maxJ); if (confirmed != null) { return confirmed; } } } // Hmm, nothing we saw was observed and confirmed twice. If we had // any guess at all, return it. if (!(this.possibleCenters.length == 0)) { return this.possibleCenters[0]; } throw "Couldn't find enough alignment patterns"; } }cordova-ubuntu-2.8.0+14.04.20140130.3/examples/qrcode-scanner/js/lib/jsqrcode/src/gf256.js0000644000015000001560000000503512272510553030663 0ustar pbuserpbgroup00000000000000/* Ported to JavaScript by Lazar Laszlo 2011 lazarsoft@gmail.com, www.lazarsoft.info */ /* * * Copyright 2007 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function GF256( primitive) { this.expTable = new Array(256); this.logTable = new Array(256); var x = 1; for (var i = 0; i < 256; i++) { this.expTable[i] = x; x <<= 1; // x = x * 2; we're assuming the generator alpha is 2 if (x >= 0x100) { x ^= primitive; } } for (var i = 0; i < 255; i++) { this.logTable[this.expTable[i]] = i; } // logTable[0] == 0 but this should never be used var at0=new Array(1);at0[0]=0; this.zero = new GF256Poly(this, new Array(at0)); var at1=new Array(1);at1[0]=1; this.one = new GF256Poly(this, new Array(at1)); this.__defineGetter__("Zero", function() { return this.zero; }); this.__defineGetter__("One", function() { return this.one; }); this.buildMonomial=function( degree, coefficient) { if (degree < 0) { throw "System.ArgumentException"; } if (coefficient == 0) { return zero; } var coefficients = new Array(degree + 1); for(var i=0;i minmax[ax][ay][1]) minmax[ax][ay][1] = target; } } //minmax[ax][ay][0] = (minmax[ax][ay][0] + minmax[ax][ay][1]) / 2; } } var middle = new Array(numSqrtArea); for (var i3 = 0; i3 < numSqrtArea; i3++) { middle[i3] = new Array(numSqrtArea); } for (var ay = 0; ay < numSqrtArea; ay++) { for (var ax = 0; ax < numSqrtArea; ax++) { middle[ax][ay] = Math.floor((minmax[ax][ay][0] + minmax[ax][ay][1]) / 2); //Console.out.print(middle[ax][ay] + ","); } //Console.out.println(""); } //Console.out.println(""); return middle; } qrcode.grayScaleToBitmap=function(grayScale) { var middle = qrcode.getMiddleBrightnessPerArea(grayScale); var sqrtNumArea = middle.length; var areaWidth = Math.floor(qrcode.width / sqrtNumArea); var areaHeight = Math.floor(qrcode.height / sqrtNumArea); var bitmap = new Array(qrcode.height*qrcode.width); for (var ay = 0; ay < sqrtNumArea; ay++) { for (var ax = 0; ax < sqrtNumArea; ax++) { for (var dy = 0; dy < areaHeight; dy++) { for (var dx = 0; dx < areaWidth; dx++) { bitmap[areaWidth * ax + dx+ (areaHeight * ay + dy)*qrcode.width] = (grayScale[areaWidth * ax + dx+ (areaHeight * ay + dy)*qrcode.width] < middle[ax][ay])?true:false; } } } } return bitmap; } qrcode.grayscale = function(){ var ret = new Array(qrcode.width*qrcode.height); for (var y = 0; y < qrcode.height; y++) { for (var x = 0; x < qrcode.width; x++) { var gray = qrcode.getPixel(x, y); ret[x+y*qrcode.width] = gray; } } return ret; } function URShift( number, bits) { if (number >= 0) return number >> bits; else return (number >> bits) + (2 << ~bits); } Array.prototype.remove = function(from, to) { var rest = this.slice((to || from) + 1 || this.length); this.length = from < 0 ? this.length + from : from; return this.push.apply(this, rest); }; cordova-ubuntu-2.8.0+14.04.20140130.3/examples/qrcode-scanner/js/lib/jsqrcode/src/gf256poly.js0000644000015000001560000001446212272510553031573 0ustar pbuserpbgroup00000000000000/* Ported to JavaScript by Lazar Laszlo 2011 lazarsoft@gmail.com, www.lazarsoft.info */ /* * * Copyright 2007 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function GF256Poly(field, coefficients) { if (coefficients == null || coefficients.length == 0) { throw "System.ArgumentException"; } this.field = field; var coefficientsLength = coefficients.length; if (coefficientsLength > 1 && coefficients[0] == 0) { // Leading term must be non-zero for anything except the constant polynomial "0" var firstNonZero = 1; while (firstNonZero < coefficientsLength && coefficients[firstNonZero] == 0) { firstNonZero++; } if (firstNonZero == coefficientsLength) { this.coefficients = field.Zero.coefficients; } else { this.coefficients = new Array(coefficientsLength - firstNonZero); for(var i=0;i largerCoefficients.length) { var temp = smallerCoefficients; smallerCoefficients = largerCoefficients; largerCoefficients = temp; } var sumDiff = new Array(largerCoefficients.length); var lengthDiff = largerCoefficients.length - smallerCoefficients.length; // Copy high-order terms only found in higher-degree polynomial's coefficients //Array.Copy(largerCoefficients, 0, sumDiff, 0, lengthDiff); for(var ci=0;ci= other.Degree && !remainder.Zero) { var degreeDifference = remainder.Degree - other.Degree; var scale = this.field.multiply(remainder.getCoefficient(remainder.Degree), inverseDenominatorLeadingTerm); var term = other.multiplyByMonomial(degreeDifference, scale); var iterationQuotient = this.field.buildMonomial(degreeDifference, scale); quotient = quotient.addOrSubtract(iterationQuotient); remainder = remainder.addOrSubtract(term); } return new Array(quotient, remainder); } }cordova-ubuntu-2.8.0+14.04.20140130.3/examples/qrcode-scanner/js/lib/jsqrcode/src/datamask.js0000644000015000001560000000741012272510553031616 0ustar pbuserpbgroup00000000000000/* Ported to JavaScript by Lazar Laszlo 2011 lazarsoft@gmail.com, www.lazarsoft.info */ /* * * Copyright 2007 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ DataMask = {}; DataMask.forReference = function(reference) { if (reference < 0 || reference > 7) { throw "System.ArgumentException"; } return DataMask.DATA_MASKS[reference]; } function DataMask000() { this.unmaskBitMatrix=function(bits, dimension) { for (var i = 0; i < dimension; i++) { for (var j = 0; j < dimension; j++) { if (this.isMasked(i, j)) { bits.flip(j, i); } } } } this.isMasked=function( i, j) { return ((i + j) & 0x01) == 0; } } function DataMask001() { this.unmaskBitMatrix=function(bits, dimension) { for (var i = 0; i < dimension; i++) { for (var j = 0; j < dimension; j++) { if (this.isMasked(i, j)) { bits.flip(j, i); } } } } this.isMasked=function( i, j) { return (i & 0x01) == 0; } } function DataMask010() { this.unmaskBitMatrix=function(bits, dimension) { for (var i = 0; i < dimension; i++) { for (var j = 0; j < dimension; j++) { if (this.isMasked(i, j)) { bits.flip(j, i); } } } } this.isMasked=function( i, j) { return j % 3 == 0; } } function DataMask011() { this.unmaskBitMatrix=function(bits, dimension) { for (var i = 0; i < dimension; i++) { for (var j = 0; j < dimension; j++) { if (this.isMasked(i, j)) { bits.flip(j, i); } } } } this.isMasked=function( i, j) { return (i + j) % 3 == 0; } } function DataMask100() { this.unmaskBitMatrix=function(bits, dimension) { for (var i = 0; i < dimension; i++) { for (var j = 0; j < dimension; j++) { if (this.isMasked(i, j)) { bits.flip(j, i); } } } } this.isMasked=function( i, j) { return (((URShift(i, 1)) + (j / 3)) & 0x01) == 0; } } function DataMask101() { this.unmaskBitMatrix=function(bits, dimension) { for (var i = 0; i < dimension; i++) { for (var j = 0; j < dimension; j++) { if (this.isMasked(i, j)) { bits.flip(j, i); } } } } this.isMasked=function( i, j) { var temp = i * j; return (temp & 0x01) + (temp % 3) == 0; } } function DataMask110() { this.unmaskBitMatrix=function(bits, dimension) { for (var i = 0; i < dimension; i++) { for (var j = 0; j < dimension; j++) { if (this.isMasked(i, j)) { bits.flip(j, i); } } } } this.isMasked=function( i, j) { var temp = i * j; return (((temp & 0x01) + (temp % 3)) & 0x01) == 0; } } function DataMask111() { this.unmaskBitMatrix=function(bits, dimension) { for (var i = 0; i < dimension; i++) { for (var j = 0; j < dimension; j++) { if (this.isMasked(i, j)) { bits.flip(j, i); } } } } this.isMasked=function( i, j) { return ((((i + j) & 0x01) + ((i * j) % 3)) & 0x01) == 0; } } DataMask.DATA_MASKS = new Array(new DataMask000(), new DataMask001(), new DataMask010(), new DataMask011(), new DataMask100(), new DataMask101(), new DataMask110(), new DataMask111()); cordova-ubuntu-2.8.0+14.04.20140130.3/examples/qrcode-scanner/js/lib/jsqrcode/src/version.js0000644000015000001560000003641712272510553031527 0ustar pbuserpbgroup00000000000000/* Ported to JavaScript by Lazar Laszlo 2011 lazarsoft@gmail.com, www.lazarsoft.info */ /* * * Copyright 2007 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function ECB(count, dataCodewords) { this.count = count; this.dataCodewords = dataCodewords; this.__defineGetter__("Count", function() { return this.count; }); this.__defineGetter__("DataCodewords", function() { return this.dataCodewords; }); } function ECBlocks( ecCodewordsPerBlock, ecBlocks1, ecBlocks2) { this.ecCodewordsPerBlock = ecCodewordsPerBlock; if(ecBlocks2) this.ecBlocks = new Array(ecBlocks1, ecBlocks2); else this.ecBlocks = new Array(ecBlocks1); this.__defineGetter__("ECCodewordsPerBlock", function() { return this.ecCodewordsPerBlock; }); this.__defineGetter__("TotalECCodewords", function() { return this.ecCodewordsPerBlock * this.NumBlocks; }); this.__defineGetter__("NumBlocks", function() { var total = 0; for (var i = 0; i < this.ecBlocks.length; i++) { total += this.ecBlocks[i].length; } return total; }); this.getECBlocks=function() { return this.ecBlocks; } } function Version( versionNumber, alignmentPatternCenters, ecBlocks1, ecBlocks2, ecBlocks3, ecBlocks4) { this.versionNumber = versionNumber; this.alignmentPatternCenters = alignmentPatternCenters; this.ecBlocks = new Array(ecBlocks1, ecBlocks2, ecBlocks3, ecBlocks4); var total = 0; var ecCodewords = ecBlocks1.ECCodewordsPerBlock; var ecbArray = ecBlocks1.getECBlocks(); for (var i = 0; i < ecbArray.length; i++) { var ecBlock = ecbArray[i]; total += ecBlock.Count * (ecBlock.DataCodewords + ecCodewords); } this.totalCodewords = total; this.__defineGetter__("VersionNumber", function() { return this.versionNumber; }); this.__defineGetter__("AlignmentPatternCenters", function() { return this.alignmentPatternCenters; }); this.__defineGetter__("TotalCodewords", function() { return this.totalCodewords; }); this.__defineGetter__("DimensionForVersion", function() { return 17 + 4 * this.versionNumber; }); this.buildFunctionPattern=function() { var dimension = this.DimensionForVersion; var bitMatrix = new BitMatrix(dimension); // Top left finder pattern + separator + format bitMatrix.setRegion(0, 0, 9, 9); // Top right finder pattern + separator + format bitMatrix.setRegion(dimension - 8, 0, 8, 9); // Bottom left finder pattern + separator + format bitMatrix.setRegion(0, dimension - 8, 9, 8); // Alignment patterns var max = this.alignmentPatternCenters.length; for (var x = 0; x < max; x++) { var i = this.alignmentPatternCenters[x] - 2; for (var y = 0; y < max; y++) { if ((x == 0 && (y == 0 || y == max - 1)) || (x == max - 1 && y == 0)) { // No alignment patterns near the three finder paterns continue; } bitMatrix.setRegion(this.alignmentPatternCenters[y] - 2, i, 5, 5); } } // Vertical timing pattern bitMatrix.setRegion(6, 9, 1, dimension - 17); // Horizontal timing pattern bitMatrix.setRegion(9, 6, dimension - 17, 1); if (this.versionNumber > 6) { // Version info, top right bitMatrix.setRegion(dimension - 11, 0, 3, 6); // Version info, bottom left bitMatrix.setRegion(0, dimension - 11, 6, 3); } return bitMatrix; } this.getECBlocksForLevel=function( ecLevel) { return this.ecBlocks[ecLevel.ordinal()]; } } Version.VERSION_DECODE_INFO = new Array(0x07C94, 0x085BC, 0x09A99, 0x0A4D3, 0x0BBF6, 0x0C762, 0x0D847, 0x0E60D, 0x0F928, 0x10B78, 0x1145D, 0x12A17, 0x13532, 0x149A6, 0x15683, 0x168C9, 0x177EC, 0x18EC4, 0x191E1, 0x1AFAB, 0x1B08E, 0x1CC1A, 0x1D33F, 0x1ED75, 0x1F250, 0x209D5, 0x216F0, 0x228BA, 0x2379F, 0x24B0B, 0x2542E, 0x26A64, 0x27541, 0x28C69); Version.VERSIONS = buildVersions(); Version.getVersionForNumber=function( versionNumber) { if (versionNumber < 1 || versionNumber > 40) { throw "ArgumentException"; } return Version.VERSIONS[versionNumber - 1]; } Version.getProvisionalVersionForDimension=function(dimension) { if (dimension % 4 != 1) { throw "Error getProvisionalVersionForDimension"; } try { return Version.getVersionForNumber((dimension - 17) >> 2); } catch ( iae) { throw "Error getVersionForNumber"; } } Version.decodeVersionInformation=function( versionBits) { var bestDifference = 0xffffffff; var bestVersion = 0; for (var i = 0; i < Version.VERSION_DECODE_INFO.length; i++) { var targetVersion = Version.VERSION_DECODE_INFO[i]; // Do the version info bits match exactly? done. if (targetVersion == versionBits) { return this.getVersionForNumber(i + 7); } // Otherwise see if this is the closest to a real version info bit string // we have seen so far var bitsDifference = FormatInformation.numBitsDiffering(versionBits, targetVersion); if (bitsDifference < bestDifference) { bestVersion = i + 7; bestDifference = bitsDifference; } } // We can tolerate up to 3 bits of error since no two version info codewords will // differ in less than 4 bits. if (bestDifference <= 3) { return this.getVersionForNumber(bestVersion); } // If we didn't find a close enough match, fail return null; } function buildVersions() { return new Array(new Version(1, new Array(), new ECBlocks(7, new ECB(1, 19)), new ECBlocks(10, new ECB(1, 16)), new ECBlocks(13, new ECB(1, 13)), new ECBlocks(17, new ECB(1, 9))), new Version(2, new Array(6, 18), new ECBlocks(10, new ECB(1, 34)), new ECBlocks(16, new ECB(1, 28)), new ECBlocks(22, new ECB(1, 22)), new ECBlocks(28, new ECB(1, 16))), new Version(3, new Array(6, 22), new ECBlocks(15, new ECB(1, 55)), new ECBlocks(26, new ECB(1, 44)), new ECBlocks(18, new ECB(2, 17)), new ECBlocks(22, new ECB(2, 13))), new Version(4, new Array(6, 26), new ECBlocks(20, new ECB(1, 80)), new ECBlocks(18, new ECB(2, 32)), new ECBlocks(26, new ECB(2, 24)), new ECBlocks(16, new ECB(4, 9))), new Version(5, new Array(6, 30), new ECBlocks(26, new ECB(1, 108)), new ECBlocks(24, new ECB(2, 43)), new ECBlocks(18, new ECB(2, 15), new ECB(2, 16)), new ECBlocks(22, new ECB(2, 11), new ECB(2, 12))), new Version(6, new Array(6, 34), new ECBlocks(18, new ECB(2, 68)), new ECBlocks(16, new ECB(4, 27)), new ECBlocks(24, new ECB(4, 19)), new ECBlocks(28, new ECB(4, 15))), new Version(7, new Array(6, 22, 38), new ECBlocks(20, new ECB(2, 78)), new ECBlocks(18, new ECB(4, 31)), new ECBlocks(18, new ECB(2, 14), new ECB(4, 15)), new ECBlocks(26, new ECB(4, 13), new ECB(1, 14))), new Version(8, new Array(6, 24, 42), new ECBlocks(24, new ECB(2, 97)), new ECBlocks(22, new ECB(2, 38), new ECB(2, 39)), new ECBlocks(22, new ECB(4, 18), new ECB(2, 19)), new ECBlocks(26, new ECB(4, 14), new ECB(2, 15))), new Version(9, new Array(6, 26, 46), new ECBlocks(30, new ECB(2, 116)), new ECBlocks(22, new ECB(3, 36), new ECB(2, 37)), new ECBlocks(20, new ECB(4, 16), new ECB(4, 17)), new ECBlocks(24, new ECB(4, 12), new ECB(4, 13))), new Version(10, new Array(6, 28, 50), new ECBlocks(18, new ECB(2, 68), new ECB(2, 69)), new ECBlocks(26, new ECB(4, 43), new ECB(1, 44)), new ECBlocks(24, new ECB(6, 19), new ECB(2, 20)), new ECBlocks(28, new ECB(6, 15), new ECB(2, 16))), new Version(11, new Array(6, 30, 54), new ECBlocks(20, new ECB(4, 81)), new ECBlocks(30, new ECB(1, 50), new ECB(4, 51)), new ECBlocks(28, new ECB(4, 22), new ECB(4, 23)), new ECBlocks(24, new ECB(3, 12), new ECB(8, 13))), new Version(12, new Array(6, 32, 58), new ECBlocks(24, new ECB(2, 92), new ECB(2, 93)), new ECBlocks(22, new ECB(6, 36), new ECB(2, 37)), new ECBlocks(26, new ECB(4, 20), new ECB(6, 21)), new ECBlocks(28, new ECB(7, 14), new ECB(4, 15))), new Version(13, new Array(6, 34, 62), new ECBlocks(26, new ECB(4, 107)), new ECBlocks(22, new ECB(8, 37), new ECB(1, 38)), new ECBlocks(24, new ECB(8, 20), new ECB(4, 21)), new ECBlocks(22, new ECB(12, 11), new ECB(4, 12))), new Version(14, new Array(6, 26, 46, 66), new ECBlocks(30, new ECB(3, 115), new ECB(1, 116)), new ECBlocks(24, new ECB(4, 40), new ECB(5, 41)), new ECBlocks(20, new ECB(11, 16), new ECB(5, 17)), new ECBlocks(24, new ECB(11, 12), new ECB(5, 13))), new Version(15, new Array(6, 26, 48, 70), new ECBlocks(22, new ECB(5, 87), new ECB(1, 88)), new ECBlocks(24, new ECB(5, 41), new ECB(5, 42)), new ECBlocks(30, new ECB(5, 24), new ECB(7, 25)), new ECBlocks(24, new ECB(11, 12), new ECB(7, 13))), new Version(16, new Array(6, 26, 50, 74), new ECBlocks(24, new ECB(5, 98), new ECB(1, 99)), new ECBlocks(28, new ECB(7, 45), new ECB(3, 46)), new ECBlocks(24, new ECB(15, 19), new ECB(2, 20)), new ECBlocks(30, new ECB(3, 15), new ECB(13, 16))), new Version(17, new Array(6, 30, 54, 78), new ECBlocks(28, new ECB(1, 107), new ECB(5, 108)), new ECBlocks(28, new ECB(10, 46), new ECB(1, 47)), new ECBlocks(28, new ECB(1, 22), new ECB(15, 23)), new ECBlocks(28, new ECB(2, 14), new ECB(17, 15))), new Version(18, new Array(6, 30, 56, 82), new ECBlocks(30, new ECB(5, 120), new ECB(1, 121)), new ECBlocks(26, new ECB(9, 43), new ECB(4, 44)), new ECBlocks(28, new ECB(17, 22), new ECB(1, 23)), new ECBlocks(28, new ECB(2, 14), new ECB(19, 15))), new Version(19, new Array(6, 30, 58, 86), new ECBlocks(28, new ECB(3, 113), new ECB(4, 114)), new ECBlocks(26, new ECB(3, 44), new ECB(11, 45)), new ECBlocks(26, new ECB(17, 21), new ECB(4, 22)), new ECBlocks(26, new ECB(9, 13), new ECB(16, 14))), new Version(20, new Array(6, 34, 62, 90), new ECBlocks(28, new ECB(3, 107), new ECB(5, 108)), new ECBlocks(26, new ECB(3, 41), new ECB(13, 42)), new ECBlocks(30, new ECB(15, 24), new ECB(5, 25)), new ECBlocks(28, new ECB(15, 15), new ECB(10, 16))), new Version(21, new Array(6, 28, 50, 72, 94), new ECBlocks(28, new ECB(4, 116), new ECB(4, 117)), new ECBlocks(26, new ECB(17, 42)), new ECBlocks(28, new ECB(17, 22), new ECB(6, 23)), new ECBlocks(30, new ECB(19, 16), new ECB(6, 17))), new Version(22, new Array(6, 26, 50, 74, 98), new ECBlocks(28, new ECB(2, 111), new ECB(7, 112)), new ECBlocks(28, new ECB(17, 46)), new ECBlocks(30, new ECB(7, 24), new ECB(16, 25)), new ECBlocks(24, new ECB(34, 13))), new Version(23, new Array(6, 30, 54, 74, 102), new ECBlocks(30, new ECB(4, 121), new ECB(5, 122)), new ECBlocks(28, new ECB(4, 47), new ECB(14, 48)), new ECBlocks(30, new ECB(11, 24), new ECB(14, 25)), new ECBlocks(30, new ECB(16, 15), new ECB(14, 16))), new Version(24, new Array(6, 28, 54, 80, 106), new ECBlocks(30, new ECB(6, 117), new ECB(4, 118)), new ECBlocks(28, new ECB(6, 45), new ECB(14, 46)), new ECBlocks(30, new ECB(11, 24), new ECB(16, 25)), new ECBlocks(30, new ECB(30, 16), new ECB(2, 17))), new Version(25, new Array(6, 32, 58, 84, 110), new ECBlocks(26, new ECB(8, 106), new ECB(4, 107)), new ECBlocks(28, new ECB(8, 47), new ECB(13, 48)), new ECBlocks(30, new ECB(7, 24), new ECB(22, 25)), new ECBlocks(30, new ECB(22, 15), new ECB(13, 16))), new Version(26, new Array(6, 30, 58, 86, 114), new ECBlocks(28, new ECB(10, 114), new ECB(2, 115)), new ECBlocks(28, new ECB(19, 46), new ECB(4, 47)), new ECBlocks(28, new ECB(28, 22), new ECB(6, 23)), new ECBlocks(30, new ECB(33, 16), new ECB(4, 17))), new Version(27, new Array(6, 34, 62, 90, 118), new ECBlocks(30, new ECB(8, 122), new ECB(4, 123)), new ECBlocks(28, new ECB(22, 45), new ECB(3, 46)), new ECBlocks(30, new ECB(8, 23), new ECB(26, 24)), new ECBlocks(30, new ECB(12, 15), new ECB(28, 16))), new Version(28, new Array(6, 26, 50, 74, 98, 122), new ECBlocks(30, new ECB(3, 117), new ECB(10, 118)), new ECBlocks(28, new ECB(3, 45), new ECB(23, 46)), new ECBlocks(30, new ECB(4, 24), new ECB(31, 25)), new ECBlocks(30, new ECB(11, 15), new ECB(31, 16))), new Version(29, new Array(6, 30, 54, 78, 102, 126), new ECBlocks(30, new ECB(7, 116), new ECB(7, 117)), new ECBlocks(28, new ECB(21, 45), new ECB(7, 46)), new ECBlocks(30, new ECB(1, 23), new ECB(37, 24)), new ECBlocks(30, new ECB(19, 15), new ECB(26, 16))), new Version(30, new Array(6, 26, 52, 78, 104, 130), new ECBlocks(30, new ECB(5, 115), new ECB(10, 116)), new ECBlocks(28, new ECB(19, 47), new ECB(10, 48)), new ECBlocks(30, new ECB(15, 24), new ECB(25, 25)), new ECBlocks(30, new ECB(23, 15), new ECB(25, 16))), new Version(31, new Array(6, 30, 56, 82, 108, 134), new ECBlocks(30, new ECB(13, 115), new ECB(3, 116)), new ECBlocks(28, new ECB(2, 46), new ECB(29, 47)), new ECBlocks(30, new ECB(42, 24), new ECB(1, 25)), new ECBlocks(30, new ECB(23, 15), new ECB(28, 16))), new Version(32, new Array(6, 34, 60, 86, 112, 138), new ECBlocks(30, new ECB(17, 115)), new ECBlocks(28, new ECB(10, 46), new ECB(23, 47)), new ECBlocks(30, new ECB(10, 24), new ECB(35, 25)), new ECBlocks(30, new ECB(19, 15), new ECB(35, 16))), new Version(33, new Array(6, 30, 58, 86, 114, 142), new ECBlocks(30, new ECB(17, 115), new ECB(1, 116)), new ECBlocks(28, new ECB(14, 46), new ECB(21, 47)), new ECBlocks(30, new ECB(29, 24), new ECB(19, 25)), new ECBlocks(30, new ECB(11, 15), new ECB(46, 16))), new Version(34, new Array(6, 34, 62, 90, 118, 146), new ECBlocks(30, new ECB(13, 115), new ECB(6, 116)), new ECBlocks(28, new ECB(14, 46), new ECB(23, 47)), new ECBlocks(30, new ECB(44, 24), new ECB(7, 25)), new ECBlocks(30, new ECB(59, 16), new ECB(1, 17))), new Version(35, new Array(6, 30, 54, 78, 102, 126, 150), new ECBlocks(30, new ECB(12, 121), new ECB(7, 122)), new ECBlocks(28, new ECB(12, 47), new ECB(26, 48)), new ECBlocks(30, new ECB(39, 24), new ECB(14, 25)),new ECBlocks(30, new ECB(22, 15), new ECB(41, 16))), new Version(36, new Array(6, 24, 50, 76, 102, 128, 154), new ECBlocks(30, new ECB(6, 121), new ECB(14, 122)), new ECBlocks(28, new ECB(6, 47), new ECB(34, 48)), new ECBlocks(30, new ECB(46, 24), new ECB(10, 25)), new ECBlocks(30, new ECB(2, 15), new ECB(64, 16))), new Version(37, new Array(6, 28, 54, 80, 106, 132, 158), new ECBlocks(30, new ECB(17, 122), new ECB(4, 123)), new ECBlocks(28, new ECB(29, 46), new ECB(14, 47)), new ECBlocks(30, new ECB(49, 24), new ECB(10, 25)), new ECBlocks(30, new ECB(24, 15), new ECB(46, 16))), new Version(38, new Array(6, 32, 58, 84, 110, 136, 162), new ECBlocks(30, new ECB(4, 122), new ECB(18, 123)), new ECBlocks(28, new ECB(13, 46), new ECB(32, 47)), new ECBlocks(30, new ECB(48, 24), new ECB(14, 25)), new ECBlocks(30, new ECB(42, 15), new ECB(32, 16))), new Version(39, new Array(6, 26, 54, 82, 110, 138, 166), new ECBlocks(30, new ECB(20, 117), new ECB(4, 118)), new ECBlocks(28, new ECB(40, 47), new ECB(7, 48)), new ECBlocks(30, new ECB(43, 24), new ECB(22, 25)), new ECBlocks(30, new ECB(10, 15), new ECB(67, 16))), new Version(40, new Array(6, 30, 58, 86, 114, 142, 170), new ECBlocks(30, new ECB(19, 118), new ECB(6, 119)), new ECBlocks(28, new ECB(18, 47), new ECB(31, 48)), new ECBlocks(30, new ECB(34, 24), new ECB(34, 25)), new ECBlocks(30, new ECB(20, 15), new ECB(61, 16)))); }cordova-ubuntu-2.8.0+14.04.20140130.3/examples/qrcode-scanner/js/lib/jsqrcode/src/findpat.js0000644000015000001560000004207012272510553031457 0ustar pbuserpbgroup00000000000000/* Ported to JavaScript by Lazar Laszlo 2011 lazarsoft@gmail.com, www.lazarsoft.info */ /* * * Copyright 2007 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ var MIN_SKIP = 3; var MAX_MODULES = 57; var INTEGER_MATH_SHIFT = 8; var CENTER_QUORUM = 2; qrcode.orderBestPatterns=function(patterns) { function distance( pattern1, pattern2) { xDiff = pattern1.X - pattern2.X; yDiff = pattern1.Y - pattern2.Y; return Math.sqrt( (xDiff * xDiff + yDiff * yDiff)); } /// Returns the z component of the cross product between vectors BC and BA. function crossProductZ( pointA, pointB, pointC) { var bX = pointB.x; var bY = pointB.y; return ((pointC.x - bX) * (pointA.y - bY)) - ((pointC.y - bY) * (pointA.x - bX)); } // Find distances between pattern centers var zeroOneDistance = distance(patterns[0], patterns[1]); var oneTwoDistance = distance(patterns[1], patterns[2]); var zeroTwoDistance = distance(patterns[0], patterns[2]); var pointA, pointB, pointC; // Assume one closest to other two is B; A and C will just be guesses at first if (oneTwoDistance >= zeroOneDistance && oneTwoDistance >= zeroTwoDistance) { pointB = patterns[0]; pointA = patterns[1]; pointC = patterns[2]; } else if (zeroTwoDistance >= oneTwoDistance && zeroTwoDistance >= zeroOneDistance) { pointB = patterns[1]; pointA = patterns[0]; pointC = patterns[2]; } else { pointB = patterns[2]; pointA = patterns[0]; pointC = patterns[1]; } // Use cross product to figure out whether A and C are correct or flipped. // This asks whether BC x BA has a positive z component, which is the arrangement // we want for A, B, C. If it's negative, then we've got it flipped around and // should swap A and C. if (crossProductZ(pointA, pointB, pointC) < 0.0) { var temp = pointA; pointA = pointC; pointC = temp; } patterns[0] = pointA; patterns[1] = pointB; patterns[2] = pointC; } function FinderPattern(posX, posY, estimatedModuleSize) { this.x=posX; this.y=posY; this.count = 1; this.estimatedModuleSize = estimatedModuleSize; this.__defineGetter__("EstimatedModuleSize", function() { return this.estimatedModuleSize; }); this.__defineGetter__("Count", function() { return this.count; }); this.__defineGetter__("X", function() { return this.x; }); this.__defineGetter__("Y", function() { return this.y; }); this.incrementCount = function() { this.count++; } this.aboutEquals=function( moduleSize, i, j) { if (Math.abs(i - this.y) <= moduleSize && Math.abs(j - this.x) <= moduleSize) { var moduleSizeDiff = Math.abs(moduleSize - this.estimatedModuleSize); return moduleSizeDiff <= 1.0 || moduleSizeDiff / this.estimatedModuleSize <= 1.0; } return false; } } function FinderPatternInfo(patternCenters) { this.bottomLeft = patternCenters[0]; this.topLeft = patternCenters[1]; this.topRight = patternCenters[2]; this.__defineGetter__("BottomLeft", function() { return this.bottomLeft; }); this.__defineGetter__("TopLeft", function() { return this.topLeft; }); this.__defineGetter__("TopRight", function() { return this.topRight; }); } function FinderPatternFinder() { this.image=null; this.possibleCenters = []; this.hasSkipped = false; this.crossCheckStateCount = new Array(0,0,0,0,0); this.resultPointCallback = null; this.__defineGetter__("CrossCheckStateCount", function() { this.crossCheckStateCount[0] = 0; this.crossCheckStateCount[1] = 0; this.crossCheckStateCount[2] = 0; this.crossCheckStateCount[3] = 0; this.crossCheckStateCount[4] = 0; return this.crossCheckStateCount; }); this.foundPatternCross=function( stateCount) { var totalModuleSize = 0; for (var i = 0; i < 5; i++) { var count = stateCount[i]; if (count == 0) { return false; } totalModuleSize += count; } if (totalModuleSize < 7) { return false; } var moduleSize = Math.floor((totalModuleSize << INTEGER_MATH_SHIFT) / 7); var maxVariance = Math.floor(moduleSize / 2); // Allow less than 50% variance from 1-1-3-1-1 proportions return Math.abs(moduleSize - (stateCount[0] << INTEGER_MATH_SHIFT)) < maxVariance && Math.abs(moduleSize - (stateCount[1] << INTEGER_MATH_SHIFT)) < maxVariance && Math.abs(3 * moduleSize - (stateCount[2] << INTEGER_MATH_SHIFT)) < 3 * maxVariance && Math.abs(moduleSize - (stateCount[3] << INTEGER_MATH_SHIFT)) < maxVariance && Math.abs(moduleSize - (stateCount[4] << INTEGER_MATH_SHIFT)) < maxVariance; } this.centerFromEnd=function( stateCount, end) { return (end - stateCount[4] - stateCount[3]) - stateCount[2] / 2.0; } this.crossCheckVertical=function( startI, centerJ, maxCount, originalStateCountTotal) { var image = this.image; var maxI = qrcode.height; var stateCount = this.CrossCheckStateCount; // Start counting up from center var i = startI; while (i >= 0 && image[centerJ + i*qrcode.width]) { stateCount[2]++; i--; } if (i < 0) { return NaN; } while (i >= 0 && !image[centerJ +i*qrcode.width] && stateCount[1] <= maxCount) { stateCount[1]++; i--; } // If already too many modules in this state or ran off the edge: if (i < 0 || stateCount[1] > maxCount) { return NaN; } while (i >= 0 && image[centerJ + i*qrcode.width] && stateCount[0] <= maxCount) { stateCount[0]++; i--; } if (stateCount[0] > maxCount) { return NaN; } // Now also count down from center i = startI + 1; while (i < maxI && image[centerJ +i*qrcode.width]) { stateCount[2]++; i++; } if (i == maxI) { return NaN; } while (i < maxI && !image[centerJ + i*qrcode.width] && stateCount[3] < maxCount) { stateCount[3]++; i++; } if (i == maxI || stateCount[3] >= maxCount) { return NaN; } while (i < maxI && image[centerJ + i*qrcode.width] && stateCount[4] < maxCount) { stateCount[4]++; i++; } if (stateCount[4] >= maxCount) { return NaN; } // If we found a finder-pattern-like section, but its size is more than 40% different than // the original, assume it's a false positive var stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4]; if (5 * Math.abs(stateCountTotal - originalStateCountTotal) >= 2 * originalStateCountTotal) { return NaN; } return this.foundPatternCross(stateCount)?this.centerFromEnd(stateCount, i):NaN; } this.crossCheckHorizontal=function( startJ, centerI, maxCount, originalStateCountTotal) { var image = this.image; var maxJ = qrcode.width; var stateCount = this.CrossCheckStateCount; var j = startJ; while (j >= 0 && image[j+ centerI*qrcode.width]) { stateCount[2]++; j--; } if (j < 0) { return NaN; } while (j >= 0 && !image[j+ centerI*qrcode.width] && stateCount[1] <= maxCount) { stateCount[1]++; j--; } if (j < 0 || stateCount[1] > maxCount) { return NaN; } while (j >= 0 && image[j+ centerI*qrcode.width] && stateCount[0] <= maxCount) { stateCount[0]++; j--; } if (stateCount[0] > maxCount) { return NaN; } j = startJ + 1; while (j < maxJ && image[j+ centerI*qrcode.width]) { stateCount[2]++; j++; } if (j == maxJ) { return NaN; } while (j < maxJ && !image[j+ centerI*qrcode.width] && stateCount[3] < maxCount) { stateCount[3]++; j++; } if (j == maxJ || stateCount[3] >= maxCount) { return NaN; } while (j < maxJ && image[j+ centerI*qrcode.width] && stateCount[4] < maxCount) { stateCount[4]++; j++; } if (stateCount[4] >= maxCount) { return NaN; } // If we found a finder-pattern-like section, but its size is significantly different than // the original, assume it's a false positive var stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4]; if (5 * Math.abs(stateCountTotal - originalStateCountTotal) >= originalStateCountTotal) { return NaN; } return this.foundPatternCross(stateCount)?this.centerFromEnd(stateCount, j):NaN; } this.handlePossibleCenter=function( stateCount, i, j) { var stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4]; var centerJ = this.centerFromEnd(stateCount, j); //float var centerI = this.crossCheckVertical(i, Math.floor( centerJ), stateCount[2], stateCountTotal); //float if (!isNaN(centerI)) { // Re-cross check centerJ = this.crossCheckHorizontal(Math.floor( centerJ), Math.floor( centerI), stateCount[2], stateCountTotal); if (!isNaN(centerJ)) { var estimatedModuleSize = stateCountTotal / 7.0; var found = false; var max = this.possibleCenters.length; for (var index = 0; index < max; index++) { var center = this.possibleCenters[index]; // Look for about the same center and module size: if (center.aboutEquals(estimatedModuleSize, centerI, centerJ)) { center.incrementCount(); found = true; break; } } if (!found) { var point = new FinderPattern(centerJ, centerI, estimatedModuleSize); this.possibleCenters.push(point); if (this.resultPointCallback != null) { this.resultPointCallback.foundPossibleResultPoint(point); } } return true; } } return false; } this.selectBestPatterns=function() { var startSize = this.possibleCenters.length; if (startSize < 3) { // Couldn't find enough finder patterns throw "Couldn't find enough finder patterns"; } // Filter outlier possibilities whose module size is too different if (startSize > 3) { // But we can only afford to do so if we have at least 4 possibilities to choose from var totalModuleSize = 0.0; for (var i = 0; i < startSize; i++) { totalModuleSize += this.possibleCenters[i].EstimatedModuleSize; } var average = totalModuleSize / startSize; for (var i = 0; i < this.possibleCenters.length && this.possibleCenters.length > 3; i++) { var pattern = this.possibleCenters[i]; if (Math.abs(pattern.EstimatedModuleSize - average) > 0.2 * average) { this.possibleCenters.remove(i); i--; } } } if (this.possibleCenters.length > 3) { // Throw away all but those first size candidate points we found. this.possibleCenters.sort(function(a, b){ if (a.count > b.count){return -1;} if (a.count < b.count){return 1;} return 0; }); } return new Array( this.possibleCenters[0], this.possibleCenters[1], this.possibleCenters[2]); } this.findRowSkip=function() { var max = this.possibleCenters.length; if (max <= 1) { return 0; } var firstConfirmedCenter = null; for (var i = 0; i < max; i++) { var center = this.possibleCenters[i]; if (center.Count >= CENTER_QUORUM) { if (firstConfirmedCenter == null) { firstConfirmedCenter = center; } else { // We have two confirmed centers // How far down can we skip before resuming looking for the next // pattern? In the worst case, only the difference between the // difference in the x / y coordinates of the two centers. // This is the case where you find top left last. this.hasSkipped = true; return Math.floor ((Math.abs(firstConfirmedCenter.X - center.X) - Math.abs(firstConfirmedCenter.Y - center.Y)) / 2); } } } return 0; } this.haveMultiplyConfirmedCenters=function() { var confirmedCount = 0; var totalModuleSize = 0.0; var max = this.possibleCenters.length; for (var i = 0; i < max; i++) { var pattern = this.possibleCenters[i]; if (pattern.Count >= CENTER_QUORUM) { confirmedCount++; totalModuleSize += pattern.EstimatedModuleSize; } } if (confirmedCount < 3) { return false; } // OK, we have at least 3 confirmed centers, but, it's possible that one is a "false positive" // and that we need to keep looking. We detect this by asking if the estimated module sizes // vary too much. We arbitrarily say that when the total deviation from average exceeds // 5% of the total module size estimates, it's too much. var average = totalModuleSize / max; var totalDeviation = 0.0; for (var i = 0; i < max; i++) { pattern = this.possibleCenters[i]; totalDeviation += Math.abs(pattern.EstimatedModuleSize - average); } return totalDeviation <= 0.05 * totalModuleSize; } this.findFinderPattern = function(image){ var tryHarder = false; this.image=image; var maxI = qrcode.height; var maxJ = qrcode.width; var iSkip = Math.floor((3 * maxI) / (4 * MAX_MODULES)); if (iSkip < MIN_SKIP || tryHarder) { iSkip = MIN_SKIP; } var done = false; var stateCount = new Array(5); for (var i = iSkip - 1; i < maxI && !done; i += iSkip) { // Get a row of black/white values stateCount[0] = 0; stateCount[1] = 0; stateCount[2] = 0; stateCount[3] = 0; stateCount[4] = 0; var currentState = 0; for (var j = 0; j < maxJ; j++) { if (image[j+i*qrcode.width] ) { // Black pixel if ((currentState & 1) == 1) { // Counting white pixels currentState++; } stateCount[currentState]++; } else { // White pixel if ((currentState & 1) == 0) { // Counting black pixels if (currentState == 4) { // A winner? if (this.foundPatternCross(stateCount)) { // Yes var confirmed = this.handlePossibleCenter(stateCount, i, j); if (confirmed) { // Start examining every other line. Checking each line turned out to be too // expensive and didn't improve performance. iSkip = 2; if (this.hasSkipped) { done = this.haveMultiplyConfirmedCenters(); } else { var rowSkip = this.findRowSkip(); if (rowSkip > stateCount[2]) { // Skip rows between row of lower confirmed center // and top of presumed third confirmed center // but back up a bit to get a full chance of detecting // it, entire width of center of finder pattern // Skip by rowSkip, but back off by stateCount[2] (size of last center // of pattern we saw) to be conservative, and also back off by iSkip which // is about to be re-added i += rowSkip - stateCount[2] - iSkip; j = maxJ - 1; } } } else { // Advance to next black pixel do { j++; } while (j < maxJ && !image[j + i*qrcode.width]); j--; // back up to that last white pixel } // Clear state to start looking again currentState = 0; stateCount[0] = 0; stateCount[1] = 0; stateCount[2] = 0; stateCount[3] = 0; stateCount[4] = 0; } else { // No, shift counts back by two stateCount[0] = stateCount[2]; stateCount[1] = stateCount[3]; stateCount[2] = stateCount[4]; stateCount[3] = 1; stateCount[4] = 0; currentState = 3; } } else { stateCount[++currentState]++; } } else { // Counting white pixels stateCount[currentState]++; } } } if (this.foundPatternCross(stateCount)) { var confirmed = this.handlePossibleCenter(stateCount, i, maxJ); if (confirmed) { iSkip = stateCount[0]; if (this.hasSkipped) { // Found a third one done = haveMultiplyConfirmedCenters(); } } } } var patternInfo = this.selectBestPatterns(); qrcode.orderBestPatterns(patternInfo); return new FinderPatternInfo(patternInfo); }; }cordova-ubuntu-2.8.0+14.04.20140130.3/examples/qrcode-scanner/js/lib/jsqrcode/src/errorlevel.js0000644000015000001560000000267412272510553032221 0ustar pbuserpbgroup00000000000000/* Ported to JavaScript by Lazar Laszlo 2011 lazarsoft@gmail.com, www.lazarsoft.info */ /* * * Copyright 2007 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function ErrorCorrectionLevel(ordinal, bits, name) { this.ordinal_Renamed_Field = ordinal; this.bits = bits; this.name = name; this.__defineGetter__("Bits", function() { return this.bits; }); this.__defineGetter__("Name", function() { return this.name; }); this.ordinal=function() { return this.ordinal_Renamed_Field; } } ErrorCorrectionLevel.forBits=function( bits) { if (bits < 0 || bits >= FOR_BITS.Length) { throw "ArgumentException"; } return FOR_BITS[bits]; } var L = new ErrorCorrectionLevel(0, 0x01, "L"); var M = new ErrorCorrectionLevel(1, 0x00, "M"); var Q = new ErrorCorrectionLevel(2, 0x03, "Q"); var H = new ErrorCorrectionLevel(3, 0x02, "H"); var FOR_BITS = new Array( M, L, H, Q);cordova-ubuntu-2.8.0+14.04.20140130.3/examples/qrcode-scanner/js/lib/jsqrcode/src/rsdecoder.js0000644000015000001560000001233012272510553032000 0ustar pbuserpbgroup00000000000000/* Ported to JavaScript by Lazar Laszlo 2011 lazarsoft@gmail.com, www.lazarsoft.info */ /* * * Copyright 2007 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function ReedSolomonDecoder(field) { this.field = field; this.decode=function(received, twoS) { var poly = new GF256Poly(this.field, received); var syndromeCoefficients = new Array(twoS); for(var i=0;i= b's if (a.Degree < b.Degree) { var temp = a; a = b; b = temp; } var rLast = a; var r = b; var sLast = this.field.One; var s = this.field.Zero; var tLast = this.field.Zero; var t = this.field.One; // Run Euclidean algorithm until r's degree is less than R/2 while (r.Degree >= Math.floor(R / 2)) { var rLastLast = rLast; var sLastLast = sLast; var tLastLast = tLast; rLast = r; sLast = s; tLast = t; // Divide rLastLast by rLast, with quotient in q and remainder in r if (rLast.Zero) { // Oops, Euclidean algorithm already terminated? throw "r_{i-1} was zero"; } r = rLastLast; var q = this.field.Zero; var denominatorLeadingTerm = rLast.getCoefficient(rLast.Degree); var dltInverse = this.field.inverse(denominatorLeadingTerm); while (r.Degree >= rLast.Degree && !r.Zero) { var degreeDiff = r.Degree - rLast.Degree; var scale = this.field.multiply(r.getCoefficient(r.Degree), dltInverse); q = q.addOrSubtract(this.field.buildMonomial(degreeDiff, scale)); r = r.addOrSubtract(rLast.multiplyByMonomial(degreeDiff, scale)); //r.EXE(); } s = q.multiply1(sLast).addOrSubtract(sLastLast); t = q.multiply1(tLast).addOrSubtract(tLastLast); } var sigmaTildeAtZero = t.getCoefficient(0); if (sigmaTildeAtZero == 0) { throw "ReedSolomonException sigmaTilde(0) was zero"; } var inverse = this.field.inverse(sigmaTildeAtZero); var sigma = t.multiply2(inverse); var omega = r.multiply2(inverse); return new Array(sigma, omega); } this.findErrorLocations=function( errorLocator) { // This is a direct application of Chien's search var numErrors = errorLocator.Degree; if (numErrors == 1) { // shortcut return new Array(errorLocator.getCoefficient(1)); } var result = new Array(numErrors); var e = 0; for (var i = 1; i < 256 && e < numErrors; i++) { if (errorLocator.evaluateAt(i) == 0) { result[e] = this.field.inverse(i); e++; } } if (e != numErrors) { throw "Error locator degree does not match number of roots"; } return result; } this.findErrorMagnitudes=function( errorEvaluator, errorLocations, dataMatrix) { // This is directly applying Forney's Formula var s = errorLocations.length; var result = new Array(s); for (var i = 0; i < s; i++) { var xiInverse = this.field.inverse(errorLocations[i]); var denominator = 1; for (var j = 0; j < s; j++) { if (i != j) { denominator = this.field.multiply(denominator, GF256.addOrSubtract(1, this.field.multiply(errorLocations[j], xiInverse))); } } result[i] = this.field.multiply(errorEvaluator.evaluateAt(xiInverse), this.field.inverse(denominator)); // Thanks to sanfordsquires for this fix: if (dataMatrix) { result[i] = this.field.multiply(result[i], xiInverse); } } return result; } }cordova-ubuntu-2.8.0+14.04.20140130.3/examples/qrcode-scanner/js/lib/jsqrcode/src/datablock.js0000644000015000001560000000676712272510553031773 0ustar pbuserpbgroup00000000000000/* Ported to JavaScript by Lazar Laszlo 2011 lazarsoft@gmail.com, www.lazarsoft.info */ /* * * Copyright 2007 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function DataBlock(numDataCodewords, codewords) { this.numDataCodewords = numDataCodewords; this.codewords = codewords; this.__defineGetter__("NumDataCodewords", function() { return this.numDataCodewords; }); this.__defineGetter__("Codewords", function() { return this.codewords; }); } DataBlock.getDataBlocks=function(rawCodewords, version, ecLevel) { if (rawCodewords.length != version.TotalCodewords) { throw "ArgumentException"; } // Figure out the number and size of data blocks used by this version and // error correction level var ecBlocks = version.getECBlocksForLevel(ecLevel); // First count the total number of data blocks var totalBlocks = 0; var ecBlockArray = ecBlocks.getECBlocks(); for (var i = 0; i < ecBlockArray.length; i++) { totalBlocks += ecBlockArray[i].Count; } // Now establish DataBlocks of the appropriate size and number of data codewords var result = new Array(totalBlocks); var numResultBlocks = 0; for (var j = 0; j < ecBlockArray.length; j++) { var ecBlock = ecBlockArray[j]; for (var i = 0; i < ecBlock.Count; i++) { var numDataCodewords = ecBlock.DataCodewords; var numBlockCodewords = ecBlocks.ECCodewordsPerBlock + numDataCodewords; result[numResultBlocks++] = new DataBlock(numDataCodewords, new Array(numBlockCodewords)); } } // All blocks have the same amount of data, except that the last n // (where n may be 0) have 1 more byte. Figure out where these start. var shorterBlocksTotalCodewords = result[0].codewords.length; var longerBlocksStartAt = result.length - 1; while (longerBlocksStartAt >= 0) { var numCodewords = result[longerBlocksStartAt].codewords.length; if (numCodewords == shorterBlocksTotalCodewords) { break; } longerBlocksStartAt--; } longerBlocksStartAt++; var shorterBlocksNumDataCodewords = shorterBlocksTotalCodewords - ecBlocks.ECCodewordsPerBlock; // The last elements of result may be 1 element longer; // first fill out as many elements as all of them have var rawCodewordsOffset = 0; for (var i = 0; i < shorterBlocksNumDataCodewords; i++) { for (var j = 0; j < numResultBlocks; j++) { result[j].codewords[i] = rawCodewords[rawCodewordsOffset++]; } } // Fill out the last data block in the longer ones for (var j = longerBlocksStartAt; j < numResultBlocks; j++) { result[j].codewords[shorterBlocksNumDataCodewords] = rawCodewords[rawCodewordsOffset++]; } // Now add in error correction blocks var max = result[0].codewords.length; for (var i = shorterBlocksNumDataCodewords; i < max; i++) { for (var j = 0; j < numResultBlocks; j++) { var iOffset = j < longerBlocksStartAt?i:i + 1; result[j].codewords[iOffset] = rawCodewords[rawCodewordsOffset++]; } } return result; } cordova-ubuntu-2.8.0+14.04.20140130.3/examples/qrcode-scanner/js/lib/jsqrcode/src/grid.js0000644000015000001560000001116012272510553030753 0ustar pbuserpbgroup00000000000000/* Ported to JavaScript by Lazar Laszlo 2011 lazarsoft@gmail.com, www.lazarsoft.info */ /* * * Copyright 2007 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ GridSampler = {}; GridSampler.checkAndNudgePoints=function( image, points) { var width = qrcode.width; var height = qrcode.height; // Check and nudge points from start until we see some that are OK: var nudged = true; for (var offset = 0; offset < points.Length && nudged; offset += 2) { var x = Math.floor (points[offset]); var y = Math.floor( points[offset + 1]); if (x < - 1 || x > width || y < - 1 || y > height) { throw "Error.checkAndNudgePoints "; } nudged = false; if (x == - 1) { points[offset] = 0.0; nudged = true; } else if (x == width) { points[offset] = width - 1; nudged = true; } if (y == - 1) { points[offset + 1] = 0.0; nudged = true; } else if (y == height) { points[offset + 1] = height - 1; nudged = true; } } // Check and nudge points from end: nudged = true; for (var offset = points.Length - 2; offset >= 0 && nudged; offset -= 2) { var x = Math.floor( points[offset]); var y = Math.floor( points[offset + 1]); if (x < - 1 || x > width || y < - 1 || y > height) { throw "Error.checkAndNudgePoints "; } nudged = false; if (x == - 1) { points[offset] = 0.0; nudged = true; } else if (x == width) { points[offset] = width - 1; nudged = true; } if (y == - 1) { points[offset + 1] = 0.0; nudged = true; } else if (y == height) { points[offset + 1] = height - 1; nudged = true; } } } GridSampler.sampleGrid3=function( image, dimension, transform) { var bits = new BitMatrix(dimension); var points = new Array(dimension << 1); for (var y = 0; y < dimension; y++) { var max = points.length; var iValue = y + 0.5; for (var x = 0; x < max; x += 2) { points[x] = (x >> 1) + 0.5; points[x + 1] = iValue; } transform.transformPoints1(points); // Quick check to see if points transformed to something inside the image; // sufficient to check the endpoints GridSampler.checkAndNudgePoints(image, points); try { for (var x = 0; x < max; x += 2) { var xpoint = (Math.floor( points[x]) * 4) + (Math.floor( points[x + 1]) * qrcode.width * 4); var bit = image[Math.floor( points[x])+ qrcode.width* Math.floor( points[x + 1])]; qrcode.imagedata.data[xpoint] = bit?255:0; qrcode.imagedata.data[xpoint+1] = bit?255:0; qrcode.imagedata.data[xpoint+2] = 0; qrcode.imagedata.data[xpoint+3] = 255; //bits[x >> 1][ y]=bit; if(bit) bits.set_Renamed(x >> 1, y); } } catch ( aioobe) { // This feels wrong, but, sometimes if the finder patterns are misidentified, the resulting // transform gets "twisted" such that it maps a straight line of points to a set of points // whose endpoints are in bounds, but others are not. There is probably some mathematical // way to detect this about the transformation that I don't know yet. // This results in an ugly runtime exception despite our clever checks above -- can't have // that. We could check each point's coordinates but that feels duplicative. We settle for // catching and wrapping ArrayIndexOutOfBoundsException. throw "Error.checkAndNudgePoints"; } } return bits; } GridSampler.sampleGridx=function( image, dimension, p1ToX, p1ToY, p2ToX, p2ToY, p3ToX, p3ToY, p4ToX, p4ToY, p1FromX, p1FromY, p2FromX, p2FromY, p3FromX, p3FromY, p4FromX, p4FromY) { var transform = PerspectiveTransform.quadrilateralToQuadrilateral(p1ToX, p1ToY, p2ToX, p2ToY, p3ToX, p3ToY, p4ToX, p4ToY, p1FromX, p1FromY, p2FromX, p2FromY, p3FromX, p3FromY, p4FromX, p4FromY); return GridSampler.sampleGrid3(image, dimension, transform); }cordova-ubuntu-2.8.0+14.04.20140130.3/examples/qrcode-scanner/js/lib/jsqrcode/src/decoder.js0000644000015000001560000000545712272510553031447 0ustar pbuserpbgroup00000000000000/* Ported to JavaScript by Lazar Laszlo 2011 lazarsoft@gmail.com, www.lazarsoft.info */ /* * * Copyright 2007 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ Decoder={}; Decoder.rsDecoder = new ReedSolomonDecoder(GF256.QR_CODE_FIELD); Decoder.correctErrors=function( codewordBytes, numDataCodewords) { var numCodewords = codewordBytes.length; // First read into an array of ints var codewordsInts = new Array(numCodewords); for (var i = 0; i < numCodewords; i++) { codewordsInts[i] = codewordBytes[i] & 0xFF; } var numECCodewords = codewordBytes.length - numDataCodewords; try { Decoder.rsDecoder.decode(codewordsInts, numECCodewords); //var corrector = new ReedSolomon(codewordsInts, numECCodewords); //corrector.correct(); } catch ( rse) { throw rse; } // Copy back into array of bytes -- only need to worry about the bytes that were data // We don't care about errors in the error-correction codewords for (var i = 0; i < numDataCodewords; i++) { codewordBytes[i] = codewordsInts[i]; } } Decoder.decode=function(bits) { var parser = new BitMatrixParser(bits); var version = parser.readVersion(); var ecLevel = parser.readFormatInformation().ErrorCorrectionLevel; // Read codewords var codewords = parser.readCodewords(); // Separate into data blocks var dataBlocks = DataBlock.getDataBlocks(codewords, version, ecLevel); // Count total number of data bytes var totalBytes = 0; for (var i = 0; i < dataBlocks.Length; i++) { totalBytes += dataBlocks[i].NumDataCodewords; } var resultBytes = new Array(totalBytes); var resultOffset = 0; // Error-correct and copy data blocks together into a stream of bytes for (var j = 0; j < dataBlocks.length; j++) { var dataBlock = dataBlocks[j]; var codewordBytes = dataBlock.Codewords; var numDataCodewords = dataBlock.NumDataCodewords; Decoder.correctErrors(codewordBytes, numDataCodewords); for (var i = 0; i < numDataCodewords; i++) { resultBytes[resultOffset++] = codewordBytes[i]; } } // Decode the contents of that stream of bytes var reader = new QRCodeDataBlockReader(resultBytes, version.VersionNumber, ecLevel.Bits); return reader; //return DecodedBitStreamParser.decode(resultBytes, version, ecLevel); } cordova-ubuntu-2.8.0+14.04.20140130.3/examples/qrcode-scanner/js/lib/jsqrcode/src/test.html0000644000015000001560000000765112272510553031347 0ustar pbuserpbgroup00000000000000 QRCODE

cordova-ubuntu-2.8.0+14.04.20140130.3/examples/qrcode-scanner/js/lib/jsqrcode/COPYING0000644000015000001560000002613512272510553027744 0ustar pbuserpbgroup00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. cordova-ubuntu-2.8.0+14.04.20140130.3/examples/qrcode-scanner/index.html0000644000015000001560000001210112272510553025676 0ustar pbuserpbgroup00000000000000 Cordova Ubuntu: QRCode scanner
cordova-ubuntu-2.8.0+14.04.20140130.3/examples/qrcode-scanner/img/0000755000015000001560000000000012272510676024470 5ustar pbuserpbgroup00000000000000cordova-ubuntu-2.8.0+14.04.20140130.3/examples/qrcode-scanner/img/icon-location@18.png0000644000015000001560000000511312272510553030177 0ustar pbuserpbgroup00000000000000PNG  IHDR2itEXtSoftwareAdobe ImageReadyqe<$iTXtXML:com.adobe.xmp IDATxڼXiLTW͛7RaSf+.q VmbbiڤҦK6b]BDAiSX@YG|o{s=v3dyNF4* .4n2RP[< Tax)L@6!]G;|&aty8I~zlZ`oNJ Tb4KT(.N'sԦFA\J TT RL$V`ZVd)X[Rfۙ^@M-ן"a+"D:EXʏ/7!UdƆG@n,7X 4 u:`22HGGW8O1P',iqI:F&6]%d#66۝ keKW(jAh 9EP wDDZn}NĖ.ADZ,zFϷm߁c}w~ܻmmQ2Kar#51ªzf0%Pzqk\|LJz1D1_zMWzzgMGF:8<. :n9uy*FhB[9ꌉ"2{j: qx8)y`B1rPxh[M'`6qxRTO,ޤ~"烂h%VbmV_b("k0hs=!b)X,n>>!񆜽1Rj:?7+K0+܃u% kr.Q]FSpÈjXt?l`3ԽBq|Jp U9<%9uѝׯ$)1JWn/ޏ q\PF*,9%6\bW_$a([Py8M <8Dm;wHq җ:iM˔}(P E5?dƩXz秒B [^|kv]TʓQ4rB@ftJ*rxXpQ,lOx&rً+/X|K >($Kjx>+)*fr|pdY}l`4C{yb<x1 xoNE[χJ$-[rRʢ[3aetK^K5R;e= Xs})Ik9j98)XՈM-J*+CmFEwz=*5Eg7JH|j8/+q;,Q^-hh>5..siU55-5#{i#5$x &S&/N縗ͤ]A׬kp' ۽)}p3ޑFF3ϰ"ngv}>eE,*.{(ԅTۤ:fnmAQ h힔}Z|7p-)9R=;A͎|G!w2Pa Ĺȑ.1_ 'A(zV FP=M @J2ڷ sPtqi`?~rFGG5uĉU o98Vɓ'Rpwcbb6ZlD"dU᧶]YYITWv'OJw,g{"1Fv YS! yyyr pث{nX܈r^/?~]5y#_܊i](s!g+c~s-0ϷёaqǏұ'2(UwUFNUx(FD~6!(33SF2nZ cM K&uEl6Qb||&Cf?g-?9zvT]]-34:::p=~wqY@KL@vȑ~,..+;Z`6''G`8<222 q,..ׅb4zJayQBww@>dK)߆?-77^쐯j/_v/9dLMMr$8gx %%oô/ܹ#iR2=VcŴ@ ~  @+ġh8tdG&/G!p9 b9̋B4?24IENDB`cordova-ubuntu-2.8.0+14.04.20140130.3/examples/qrcode-scanner/img/clock64.png0000644000015000001560000002472512272510553026447 0ustar pbuserpbgroup00000000000000PNG  IHDRvGsBITO pHYs7tEXtSoftwarewww.inkscape.org<)SIDATx]y|T°$$H "(h-XC믭T壵bZdWR6= $aG~ߙprߛ7/dOy{s9s۹snܸrɱmO|WAi4F^3:Xz*TrmyrZΓD+ b>}+y++Woe׏vm' Xi`qWF4C$fzIoy/m9gr`2X$WNZwW?`Dt96$ׯ_e-Nnߌ&C 2+_jP- ޫWjV*s2Kx/-amF0`]]4S>i De [ҋI4}x2'a<" lF危o1Z5icpg a譕Vi9MYnv^ c`g a`PzZEVk ~odl!>y -B/fo[9)[#p&xXپi`gyW7VtRNNr-;;_/_lSU @WF>$*UoUVV>yVJ+ $,JշB)ɓ'N'""1xmeXF(5AŢhrcj] ?u֭W^LL LԨq[RIKQ-[زv8KKKqф3**$$M>2`EX4t΁P-/^'N EGGwqGڵرCmv&8pq}|V7Id%ZtNKAlW|}+rرǏUr5kv!))ɪE!SoBM6YѠ?T߆ } 5PTEDod`@j\Ih 1ɍ3F:c#͛ar[h *(2 5X>ePEg]vFI`-h,~!G)Fş+: %+ .lZ ڙ+s"u->4aݻw>שSpٔl$LmcÌ-nJP$_QOHH l:#[ѣ)))FzGZPp~Pzh,0=2ӌZT9lMJDm3_;v(# v -K] 'v966֚7ClV@ATD{5!"!C!gC&DUC WC.+@SLq3 (:JqE\ƱEYP2f͚m&3B(LU;vEz%_˻˔rpe @|xБ֙du6L2na)4\As=o߾V9̓eY1Cg!Aσ0cPk,y{Eɵ%zzq30]Wn;\|9Ν;?n׮~t[8ܹB޽1jb/C[Z6 󂽸q¾ˉ80a'H7A_NN^@O%E@3U|']٢ELҰaCHزeƌL(,7)LƱ_ʃr0".q Dvwڴiۛo)A @va !a g2D;&$$Gq-v<22t7ʗK(d4ܥKBHYe7onٲ ŌkR8W[g_`QZ:wܜ9sl8y$9V&M#̞=R?zWqi5bCș%ߺ,1`VA5k_Ǐ79r?ܶm۰O!ܥKN\\{oT:u{wҥUVP⹆|e}F{gc(S8 /)aN@o#y!^493j޼;$r~֪U()@_h\HCNڷo^Vw @… \4:7 m̫DR Ң=K[oڲ噤>3}>{6CFFK0a [YYYpHeMժUC.u&sv0] %+~'y.כFEEe Xc߾?ڵRz`WRRRȿnH!.2ʍl:t,`HcL"K$k?L@1  [%d0`@͚5сB,9mREg>XZ2jr 4j5k }TE+^Ѳyy္fu4hL&KeRA~qnؤIܓ6lذ`PB Rvmp˖8x Fb|I* t@ר߿-jQ\zG}Rv_P]O<0(< ē\/,:y Ç5iѦM4mE VQ?|ҥ<'w p@<34dF!(Q.YnCsUbWxoŋ/ڒ > }X:411BFn.2R^=bL7|g'%KIII]vQo.B.Wb|B֢E ^ZQF111 gG]jZP"FŪU233awO>lE< x ? ~A'fϞ~z|e,c܀[֋[n-@#XFߌ6ǼSNsY DܴiWXhȘ%ďY_:kV >oW;qqq:!ʕ Na"NrG![%f܀9"@.^"V5ꗸCt +h0%UzA -zO~(I׽sswt;x~Er dڴiZ1iҤCv 8f̍cz=7i\O>$0 ]d$eKhrуqUX7n`8;v$&,lP111g| Hf%|2N Ҭ_|2es=2%>7n\A9xJv+VnTر^o[`?p)CвeƏ?`ucZ\1 = 9W,XMѿݶ :W"؉O=ԁJeA6oq4_K~pRf1_$>uTLV'j٣GÆ dɓo,yeff‘82嗒5| a!'r)2ჵk ȝ s{ =A+N<'߿ |L>Hu{kEGKL4#A}1sLO֭{zX kmٲ'.^Km0x:P~^|EpMwȎzRgZ`dC8 HKddƌ60=iɟڢmVzuM-[] :KIIrCCO3 !#GXq*PȺ)Z zBB{'N$%%1¬C+թX9t%S} -P'f^аybjpn݂5.7Z9˼%{5 WuImCt 9sbgO:j\, wlB F]aFvAODzy-XDx];뵋iUT9,Cۺ$iOʇ+,:Ǐ߻wo|BDm1M҇}(Xe|u:8DŒ9R3@B>3#4lJR6럝=h&dxRډaCQj lǒ*|+)|FۿMp\B(VdU PrD֞oW:>tMR;B1:İÇ:uLWG9KtOws;|..ݗzT D` #t[- 鯞\Tְa2"RF؀LHu:T᪷EGKUc~fDN4q>ZZ t+*uЊ2_kt>:>ȺL-hؤM!HCmSv b׉^);Н&Q2"## 䄬LfOlxYVeš/ȵqb"5z2ܹs 9rDNNNe_Ji<q{61-o`L /\pѢE d RW'N+(GY !he3`=zuoAKRl{f["2%ìo 6쩧*kKx2v &;QEV2E&3Jؚ5k-[EGGO:V+l۶-A <fQJ {CGAǗn m;wmMM[A*9ڵk߾}O?4<(P{饗{1g /ɗre/m~kӘBbg#{}w8WB܊mŊSLIIIٸq#D2ȮcLsk)N˲Hoڴu:vgSnJNNNtOրٳW\Ƀqƍ3*egIkz2ELQFFZbbEj^}͛7?vA%Kׯ٨Qu릥'P{m,K'@PE0P=!ŋ;:~1!ᨎ9/(JJIHH`7@ 6ԪU,Q޽gnںuk,$šf[8v\C󊕘3HcT/ʭˠ= {P:u4h cNhz g1bsY M"3`^ɫz;-_̆ hS٪U+B9y40>4e6]C*{fM|XE ̔{b@ #od;M!222TǷah ftH ˧+^]4<+VԎnR2H+}d|I,Xo*a9k܂~g*ZAH ]6K2f"U= ;F&6N W5o 7z&M$uë/_~eNSY\VotXJ$ 9z+ d_52i]ĆkӧO߶m[0M6A% 6̓޶k׮7x=ӌEl-: R3<Û9nA TyUq_ Λ7/dUN >;wɓa;w}~sHDLQ9̗͐xG x4IXI O\۩+2# cV^]pCi02aÆMױ!RkԨѥK|Ɍ$Ȋ^aqqqƍ5j$=e| c(x#o$M6/b!O8$Xh$z`[0^"VJ*%mXd?o0pH7ni򬄽Yft(JT @q,>> ,?dv0xcTd,g $&&g\aA@Ì G ![ЇţU{fl2(a"80r 3ԩӲe˺ur-+{B-GM8޽;-- IAotz}9PG]`3 gk$+``ZE90,@ӯe$5lSRR$8K,&2Td4Suu۷وs 1c֎,_gF-T ;܊ "Ze3,C[5^T\9@Aj&4%"+3^n0]S`tmeL̯Z}o MR3"P Œ6>u j if=/sG X4!FJ˄_*h]eA9Pud&3:kgs)Ӑ0 -^_FRc1)AʹT,H)LY R ueO*3/O)VTb~i.TpqNr(؍-q=jWU)ԨDl W}9 0[J;R@\΢S_ס݁!Yf3ߨx^ڣ~IENDB`cordova-ubuntu-2.8.0+14.04.20140130.3/examples/qrcode-scanner/img/camera@18.png0000644000015000001560000000172512272510553026676 0ustar pbuserpbgroup00000000000000PNG  IHDR22?bKGD pHYs  tIME  ۙbIDATh혿k`ǟ֋ 6Y;!"A\]JDHI:ԡqjvhqR( V'`DWϋ L!011111Ypkkk+,wh4eY6WlNәՕÿ;]~w<^[ʃ`PVaD" ӝllllx^/EQ9(b<zR&t4vC/py0 REa}boZUox|}ײZ}Q(j>B,%L&t$IRkvݣd2[ȺQ(\.{+$I2rjZ +$CP%I͐$IBCPĐBhcX lvpl6Ei FQT~JvL& |T*R%F 'gΟ#3M~yyy秵ANH頶vpBQ8q8qNHP( !0LR8N';NgR0 àZP( ZT*-$I~̐$I AmԴh pmri}4d { ,^\\\h DUUjZeYA0|Pp8llϊ(X僢(Jl~BB~_u~~߯3|g6w?===eenDbq\{eEQ,E0111111111W~c_aIENDB`cordova-ubuntu-2.8.0+14.04.20140130.3/examples/qrcode-scanner/img/scan.png0000644000015000001560000000245112272510553026116 0ustar pbuserpbgroup00000000000000PNG  IHDRZZ8AsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<IDATxOhe?ojc5(uAEXID=؁tQI"J;pAszPԓ!c9i˜E \f4ly,y?&}ߛgsDI@E{"D(Q'hODў=E{"D(Q'.,."ec!܌fVhG{-ahF]x>Q,7ho5D;7:*"2)"7kU\ oZkEd\8BX&&&.WS0TR)˧(q[k +(*.FBm<,"'0ਈ64+zD ٔP v%%z"wll춄k{Ak1=`Lz5uhg+ʂJRFWbh%Gn=WR.AQ=i9>`8R(.t5K9ѫV_[xN`>YTSgn D B_V=2@5tS;GB ]ϭ"aN£0==i'L NDѰ]=tS]cZM:=\| "ojlciPP+ɢ1эZ Fiiĩcm6HSbf`kT7mRoSZhC筵SI3Jd*slJR2D;0dݧQ<&]K2D Zkn%}}}}}4D<AUk.4ƼPDY"vr948ڢxnaߨ68:ӿcj3 -D;禁`. -oYįz"D(Q'hODў=E{"D(Q'hO hlԐIENDB`cordova-ubuntu-2.8.0+14.04.20140130.3/examples/qrcode-scanner/qrcode-scanner.cordovaproject0000644000015000001560000000000012272510553031546 0ustar pbuserpbgroup00000000000000cordova-ubuntu-2.8.0+14.04.20140130.3/cordovaqt64.png0000644000015000001560000001302112272510553022043 0ustar pbuserpbgroup00000000000000PNG  IHDR@@iqsRGBbKGD pHYs B(xtIME  ;5IDATx[{dW]~gtfvgvwaBleǹKD "!'A~Mg "r ӣ n Mh ~0FI,5 )(wF!"qA9-"Cԝv6~ھ ])˿(YEd/5lvͷ}܅[n%"G+`F 2煲FeSX˽$xdx~hc|%[owsy-"oD\衃?cfYz2ߐdnG63'E6 puNhDծ.L8΍^v$)% `zY=;y YЗt,`K¾G ' $xǬ RKwwKa'!hߤsJ9`)9'J)zpu8n;kt@ WW]s tLВfݞ={e k,ѣǼÇeS'|̌A&&)$a$LLZ&[I"33X_Еj}K%߷Q*7"`2vO^=Sev&r4c%J`w/r#"*LЭV I$Ij5$jZH ?|3{zz[jy_}j}[$M@T*q, h$Ν;l.a m(uEhrwUmwURnؿR4HHDsIs#]v:S+8v?jG[OO4y@ MbŲ/IR/jIdJ7zMNNj۶aF]BNK!='ozBg]C!H*|/|ySzj]0zf s0-[yy(lٺ[nÇ!A|ļdӹ%n+_YcZkuZ(摏bݓRA C&ie{"00J. PeHbM$Kpw.TsJR,|Rg68I~ժ!IBv}`2L^LNNBX&h(@EvW0 C! `Ⱦǒ(E!0BXc#?Z+ZtΆ!$`&ڋ|S U:a%J5nDS;q%k!l͔RŖq=m3A9EƕjD@Sm@_@~>^S)ՊhZN՞vAH0t)ɴW 5,\e l㐜{UXZ,%qgDz}9109?[o@_ߦ78gcGM7{IEqI97&f, :7gp@0Rڽbc-^x52' &"\<%)FaXU'ȑIYDQf8rxK^q+̼ yB1/Ȉu?.ue6o `ûXb3ֺR~nYe%w8*:YXB.ZkeV0m?;|!9XFi2y"dE%\,c SP*^XXxww{)"~ H'0Q%*^g@ŨV,>Ju΅4EJw]|ghN\ VZI%J;o%IFI[IT,( 3\ ؑl Y(驩P \xiK}IRcm`p$3-c3{>/ gs~$OvmDd̜۵kםǎUtnI "t1Ơ(:QDw3O۪H=˯ K9EdȌf} IFFO ԖޢbG?ruw/ϫ"6?}q5Yf2c-LfPJ_L>88gs.+EDH۳,i;nĭ~4lx~EQA<_uYp]B`35[=Zr O ;OyA$/XgQVvROߏfs-]ͦ4[NU/ WJ]TT.}M"K<ľA")"-l>v1MFPptjxQw2jb !Ζֺѱ圃u9 PɁbGm>fV޼]$In2S$EAEf$"f&p8FNkd5dFmZOD"3, lٺODZH}Mn pm#qǵɜ9us."ι_4&CdY,ggfY:ʌ&ckg]s;uރHS;v씏}شyr3"NxZ PJ4Z{L5MY"MSdY4~9;vܚԘTԌzQeXh6Ѫ:l]+z)(@~`$k( [)(%4 BQe9YĥB̀L & y#^^i1V 'N@޿s+qLc~~i9mۢ(=Z, 20 oLYELQ *P/%9JiqbǎW;O](0S>dPTP;lE_v_܉,3Gɋ6 H}Z{ei}k_yޗ hX4e&-. I9msE4M 7"ؿcc$BZEZELj+q۶y硷#h,0tY#B9ъg }$_E@k22eH4Os4Yl=1|/9@vN _p>.ǰmp(BRA\ ]]]О΃(Qо={>Cx c_/O̺*%ptуr*R{@\/GHE@F'p&D$cFVM (!y%kؾж۔Ro l7щ=CHU@*r8}uć]Ӡ- >61>?

Scan Code

Results:

Scan History

Application Info

This is an example app for Ubuntu Cordova
Scanning...