| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333 | <html><head>    <title>ArozOS Desktop</title>    <meta charset="UTF-8">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <link rel="stylesheet" href="./script/semantic/semantic.min.css">    <link id="fwcss" rel="stylesheet" href="./script/ao.css">    <link rel="stylesheet" href="./script/contextmenu.css">    <link rel="stylesheet" href="./SystemAO/desktop/script/jsCalendar/source/jsCalendar.css">    <script type="text/javascript" src="./script/jquery.min.js"></script>    <script type="text/javascript" src="./script/semantic/semantic.min.js"></script>    <script type="text/javascript" src="./script/ao_module.js"></script>    <script type="text/javascript" src="./SystemAO/desktop/script/jsCalendar/source/jsCalendar.js"></script>    <script type="text/javascript" src="./script/applocale.js"></script>    <!-- <script type="text/javascript" src="./script/html2canvas.min.js"></script> -->    <link rel="icon" href="img/system/favicon.png">    <style>        body {            background-repeat: no-repeat;            background-size: cover;            background-position: center;            background-image: url('img/desktop/bg/init.jpg');            width: 100%;            height: 100%;            overflow: hidden;            line-height: 1.4385em;        }        body:not(.darkTheme){            color: var(--body_text, #5a5a5a);        }        body.darkTheme{            color: var(--body_text,#f0f0f0);        }        * {            position: relative;            font-family: "SF Pro TC","SF Pro Text","SF Pro Icons","PingFang TC","Helvetica Neue","Helvetica","Arial","Microsoft JhengHei",wf_SegoeUI,"Segoe UI",Segoe,"Segoe WP",Tahoma,Verdana,Ubuntu,"Bitstream Vera Sans","DejaVu Sans",Tahoma,微軟正黑體,"LiHei Pro","WenQuanYi Micro Hei","Droid Sans Fallback","AR PL UMing TW",Roboto,"Helvetica Neue","Hiragino Maru Gothic ProN",メイリオ,"ヒラギノ丸ゴ ProN W4",Meiryo,"Droid Sans",sans-serif;            box-sizing: border-box;            letter-spacing: -.02em;        }        .ui.button{            background-color: #eeeeee;        }        .ui.progress{            background-color: #eeeeee;        }                .backgroundFrame {            height: 100%;            min-width: 100%;            background-repeat: no-repeat;            background-size: cover;            border: 0px solid transparent;            background-position: center;            position: absolute;            opacity: 0;            top: 0;            left: 0;            -webkit-transition: opacity 2s ease-in-out;            -moz-transition: opacity 2s ease-in-out;            -o-transition: opacity 2s ease-in-out;            transition: opacity 2s ease-in-out;        }                .background-wrapper {            border: 0px solid transparent;            overflow: hidden;            width: 100%;            height: 100%;            position: fixed;            left: 0px;            top: 0px;            user-select: none;            -moz-user-select: none;            -webkit-user-drag: none;            -webkit-user-select: none;            -ms-user-select: none;        }                .showBackground {            opacity: 1;        }        /*            Desktop icons        */                .icon-wrapper {            height: 100%;            width: 100%;            position: fixed;            top: 0px;            left: 0px;            padding: 5px;        }                .launchIcon {            position: fixed;            cursor: pointer;            padding: 2px;        }                .launchIconImage.small {            width: 48px;            height: 48px;        }                .launchIconImage.medium {            width: 68px;            height: 68px;        }                .launchIconImage.big {            width: 82px;            height: 82px;        }                .launchIconWrapper {            padding-bottom: 0.6em;            max-height: calc(100% - 4px);            width: calc(100% - 4px);            margin: 2px;            border-radius: 3px;            position: absolute;        }                .launchIconWrapper.selected {            background: rgba(250, 250, 250, 0.4) !important;        }                .launchIconText {            color: white;            text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black;            text-align: center;            text-overflow: ellipsis;            overflow: hidden;            word-break: break-all;            width: 100%;            font-variant-numeric: tabular-nums lining-nums;        }                .launchIconWrapper:hover {            background: rgba(250, 250, 250, 0.2);        }                .launchIconText.small {            margin-top: -3px;            font-size: 70%;            line-height: 1.55em;            /*                Fixed the issue of text being trimmed off due to lineheight setting            */            font-family: sans-serif !important;        }                .launchIconText.medium {            margin-top: -2px;            font-size: 90%;            line-height: 1.2em;        }                .launchIconText.big {            margin-top: -6px;            font-size: 110%;        }        .launchIconText.longTextSplit{            white-space: nowrap;            overflow: hidden;            text-overflow: ellipsis;        }                .navimenu {            position: fixed;            z-index: 1110;            width: 100%;            height: 36px;            left: 0px;            bottom: 0px;            padding-left: 8px;            padding-right: 8px;        }        /* Connection loss indicator */        #connectionLost{            position: fixed;            z-index: 1000;            right: 1em;            top: 1em;            display: none;        }        #connectionLost .ui.card{            box-shadow: none;            border: 0px solid transparent;            color: white;        }        /* Theme Color css settings */        .themeColor {            background-color: rgba(14,14,14,0.5);            backdrop-filter: blur(4px);        }        .themeColorSolid{            background-color: rgba(14,14,14,0.9);            backdrop-filter: blur(4px);        }                .navimenu .item {            height: 36px;            display: inline-block;            vertical-align: top;        }                .navimenu .item.padding {            display: inline-block;            width: 12px;        }                .navimenu .item.clickable:hover {            background-color: rgba(250, 250, 250, 0.2);            cursor: pointer;        }        /* Floatwindow control button related css*/                .navimenu .item.floatWindowButton {            padding: 8px;            padding-top: 10px;            vertical-align: top;            width: 200px;            overflow: hidden;            font-size: 90%;            text-overflow: ellipsis;            white-space: nowrap;            word-break: break-all;            color: white;        }                .navimenu .item.floatWindowButton .floatWindowAppIcon {            height: 20px;            margin-top: -2px;            margin-right: 8px;            display: inline-block;        }                .navimenu .item.floatWindowButton .floatWindowTitle {            display: inline;            color: white;            padding-top: 5px;            vertical-align: top;        }                .navimenu .item.floatWindowButton.hideText {            width: 36px;        }                .navimenu .item.floatWindowButton.hideText .floatWindowTitle {            display: none;        }                .navimenu .item.floatWindowButton.hideText .floatWindowAppIcon {            margin-right: 0px;        }        .navimenu .clock{            float: right;            text-align: center;            color: white;            font-size: 0.9em;            line-height: 1.3em;            padding-top: 1px;            padding-right: 0.5em;            padding-left: 0.5em;        }        .navimenu .backgroundtasks{            float: right;            border-right: 1px solid rgb(206, 206, 206, 0.4);            color: white;            padding-top: 0.5em;            padding-right: 0.5em;            padding-left: 0.7em;        }                #fwdragpanel {            position: fixed;            width: 100%;            height: 100%;            top: 0px;            left: 0px;            z-index: 100;            display: none;        }        #tfwdragpanel{            position: fixed;            width: 100%;            height: 100%;            top: 0px;            left: 0px;            z-index: 500;            display: none;        }                #stackedWindowList {            position: fixed;            z-index: 1112;            left: 0px;            bottom: 36px;            width: 300px;            padding-bottom: 4px;            display: none;        }                #stackedWindowList .item {            padding: 6px;            display: inline-block;            color: white;            width: 100%;        }                #stackedWindowList .item img {            display: inline-block;            vertical-align: bottom;            width: 20px;            height: 20px;            margin-right: 12px;            margin-top: 0px;            margin-left: 4px;        }                #stackedWindowList .item span {            overflow: hidden;            word-break: break-all;            text-overflow: ellipsis;            white-space: nowrap;            width: calc(100% - 2em);            display: inline-block;        }                #stackedWindowList .item.clickable:hover {            background-color: rgba(250, 250, 250, 0.2);            cursor: pointer;        }                #stackedWindowList .item .closebtn {            position: absolute;            right: 0px;            top: 8px;        }                #stackedWindowList .item .closebtn>img {            height: 15px;            width: 15px;        }                #listMenu {            position: fixed;            bottom: calc(36px + 1em);            left: 0.4em;            height: 500px;            width: 400px;            background-color: #ffffff;            box-shadow: 3px 3px 5px 0px rgba(207, 207, 207, 0.37);            z-index: 1113;            border-radius: 6px;            overflow: hidden;        }        body.darkTheme #listMenu{            background-color: var(--body_background, #242330);            color: var(--text_color, white);            -webkit-box-shadow: 7px -6px 7px -1px rgba(92,92,92,0.2);            -moz-box-shadow: 7px -6px 7px -1px rgba(92,92,92,0.2);            box-shadow: 7px -6px 7px -1px rgba(92,92,92,0.2);        }                #listMenu .searchBar{            width: 100%;            border-bottom: 2px solid #34b7eb;        }        body.darkTheme i{            color: var(--text_color);        }        body.darkTheme #listMenu #searchBar::selection{            background: var(--body_background);        }        body.darkTheme #listMenu .searchBar input{            background-color: var(--body_background_secondary, #17161f) !important;            color: var(--text_color_secondary, white) !important;            border: 1px solid var(--divider, #17161f);        }                #listMenu .listItemWrapper {            overflow: hidden;            height: 462px;            border-bottom-left-radius: 1em;        }                .listItemWrapper .groups{            position: relative;        }        #listMenu .listItemWrapper .groups {            background-color: #f5f5f5;            width: 120px;            height: 100%;            display: inline-block;            overflow-y: auto;            padding-top: 8px;        }        body.darkTheme #listMenu .listItemWrapper .groups {            background-color: var(--body_background, #17161f);            color: var(--text_color, white);        }                #listMenu .listItemWrapper .groups .item {            padding-left: 7px;            padding-bottom: 6px;            padding-top: 6px;            cursor: pointer;        }                #listMenu .listItemWrapper .groups .item.selected {            color: #34b7eb;        }                #listMenu .listItemWrapper .groups .item:hover {            background-color: #dedede;        }        body.darkTheme #listMenu .listItemWrapper .groups .item:hover {            background-color: var(--body_background_active, #242330);        }                #listMenu .listItemWrapper .items {            height: 100%;            width: calc(100% - 120px - 5px);            display: inline-block;            overflow-y: auto;            padding-top: 8px;                        vertical-align: top;        }        body.whiteTheme #listMenu .listItemWrapper .items {            box-shadow: -2px 0px 5px 0px rgba(194, 194, 194, 0.5);         }        body.darkTheme #listMenu .listItemWrapper .items {            box-shadow: -2px 0px 5px 0px rgba(194, 194, 194, 0.11);         }        #listMenu.darkTheme .listItemWrapper .items {            box-shadow: 0px 0px 0px 0px transparent;        }                #listMenu .listItemWrapper .items .item {            padding-left: 12px;            padding-top: 8px;            padding-bottom: 8px;            cursor: pointer;        }                #listMenu .listItemWrapper .items .item:hover {            background-color: #f5f5f5;        }        body.darkTheme #listMenu .listItemWrapper .items .item:hover {            background-color: var(--body_background_active, #17161f) !important;            margin-right: 5px;        }                #listMenu .listItemWrapper .items .item img {            width: 26px;            margin-right: 12px;            vertical-align: middle;        }                #listMenu .poweroption {            position: absolute;            bottom: 0px;            left: 0px;            padding: 6px;            padding-left: 7px;            width: 100%;            cursor: pointer;        }        #listMenu .poweroption:hover {            background-color: #dedede;        }        body.darkTheme #listMenu .poweroption{            color: var(--text_color_secondary);         }        body.darkTheme #listMenu .poweroption:hover {            background-color: var(--body_background_active);        }                .contextmenu {            position: fixed;            z-index: 3000 !important;            left: 20px;            top: 20px;        }                #contextmenu .item {            padding: 0.6em 1em !important;        }                #subcontextmenu .item {            padding: 0.6em 1em !important;        }                #selectionPanel {            background-color: rgba(39, 108, 227, 0.3);            border: 1px solid #276ce3;            position: fixed;            height: 100px;            width: 100px;            display: none;        }                .renameInput {            background-color: white;            border: 1px solid black;            width: calc(100% - 4px);            margin-left: 4px;            position: absolute;            resize: none;            outline: none;            border: 1px solid #0c0c0f;            -webkit-box-shadow: none;            -moz-box-shadow: none;            box-shadow: none;        }                .renameInput.big {            bottom: 0px;            left: 0px;            font-size: 16px;            line-height: 1;        }                .renameInput.medium {            bottom: 8px;            left: 0px;            height: 32px;            font-size: 12px;            line-height: 1;        }                .renameInput.small {            bottom: 3px;            left: 0px;            height: 24px;            font-size: 11px;            line-height: 1;        }        #statusbar{            z-index:0;            width:100%;            height:28px;            position: absolute;            background-color: rgba(0,0,0,0.9);            color:white;            backdrop-filter: blur(4px);            text-align:center;            display: flex;            justify-content: space-between;        }        .statusbarpadding{            padding-top: 0.2em;        }        .hostname{            text-align:left;             pointer-events:none;            padding-left:18px;            white-space: nowrap;            user-select: none;        }        .quicktools{            margin-top: -0.1em;            position: relative;            text-align:center;             height: 100%;        }        .qtwrapper{            cursor:pointer;            display: inline-block;            border-radius: 0.4em;        }        .qtwrapper.backgroundtask{            padding-left:8px;            padding-right: 6px;            padding-top: 7px;            padding-bottom: 5px;        }        .qtwrapper.backgroundtask i{            margin-top: -5px;            margin-right: 1px;        }        .qtwrapper.content{            padding-left:6px;            padding-right: 4px;            padding-top: 4px;            padding-bottom: 8px;        }        .qtwrapper:hover{            background-color: rgba(240,240,240,0.2);        }        .notificationbar{            position: fixed;            top:28px;            left: 0;            width:100%;            height: calc(100% - 28px);            z-index:1114;        }        .notificationbar .content{            position: fixed;            background-color:white;            margin-top:6px;            width:30%;            right: 1em;            bottom: calc(36px + 1em);            min-width:650px;            height:400px;            padding: 3px;            border-radius: 5px;            pointer-events: auto;        }        .notificationbar #notificationlist{            position: relative;            width: calc(100% - 302px);             padding:8px;             margin-top:5px;             padding-top:22px;             overflow-y:auto;             overflow-x:hidden;             height: calc(100% - 12px);        }        .notificationbar .cover{            backdrop-filter: blur(0.5px);            -webkit-backdrop-filter: blur(0.5px);            background-color: rgba(0,0,0,0.15);            position:fixed;            top:0;            left:0;            width:100%;            height: calc(100%);            pointer-events: auto;        }        body.whiteTheme .item:hover{            background-color: #ececec !important;        }        @supports not (backdrop-filter: blur(2px)) {            .notificationbar .cover{                /*                //Replaced with Javascript implementation on Firefox                background-color: rgba(24,24,24,0.3);                */            }                        #bgwrapper{                transition: all 0.5s ease;            }            #iconwrapper{                transition: all 0.5s ease;            }            #navimenu{                transition: all 0.5s ease;            }        }        .notification .title{            font-weight:bold;            font-size:120%;        }        .notification .notifycontent{            margin-top:-12px;        }        .notificationbar .clearall{            position:absolute;            top:0px;            right:4px;            cursor:pointer;        }        .nonotification{            opacity: 0.3;            pointer-events:none;            position:absolute;            margin-top:9em;            width:100%;            user-select: none;        }        .notification.object .closebtn{            position:absolute;            top:3px;            right:3px;            cursor:pointer;        }        .notification.object{            position: relative;            padding-left:7px;            border-left: 3px solid transparent;            cursor:pointer;        }        .notification.object:hover{            /*                border-left: 3px solid #83D8FF;            */        }        .blured{            filter: blur(2px);        }        #quickAccessPanel{            background-color:var(--body_background);            position:absolute;            bottom:calc(36px + 1em);            left:55px;            z-index:114;            width:300px;            border-radius: 6px;            max-height: calc(100% - 100px);            overflow-y: auto;            scrollbar-width: thin;            border: 1px solid #ebebeb;            padding-top:8px;            padding-bottom:8px;            box-shadow: 6px 8px 13px 2px rgba(191,191,191,0.13);            -webkit-box-shadow: 6px 8px 13px 2px rgba(191,191,191,0.13);            -moz-box-shadow: 6px 8px 13px 2px rgba(191,191,191,0.13);        }        #quickAccessPanel .item{            padding-left:12px;            padding-right:12px;            padding-top:4px;            padding-bottom:4px;            cursor:pointer;            border-left: 3px solid transparent;                    }        #quickAccessPanel .item{            color: var(--text_color);        }        #quickAccessPanel .item:hover{           background-color:var(--body_background_active);        }        /*            Handle dark theme for the quick access panel        */        #quickAccessPanel{            background-color: var(--body_background);            color: var(--text_color);            border: 1px solid transparent;        }        body.darkTheme #quickAccessPanel{            -webkit-box-shadow: -5px 4px 7px -1px rgba(92,92,92,0.2);            -moz-box-shadow: -5px 4px 7px -1px rgba(92,92,92,0.2);            box-shadow: -5px 4px 7px -1px rgba(92,92,92,0.2);        }        #quickAccessPanel .header{           color: var(--text_color);        }        #quickAccessPanel .meta{           color: var(--text_color_secondary);        }                #quickAccessPanel .progress{           background-color: var(--body_background_active);        }        #quickAccessPanel .progress .bar{            background-color: var(--theme_color) !important;        }        #quickAccessPanel .button{           background-color: var(--body_background_secondary);           border: 1px solid var(--divider);           color: var(--text_color);        }        body.darkTheme #quickAccessPanel .ui.basic.button{            color: var(--text_color_secondary) !important;        }        .item.module{            cursor:pointer;        }        .item.module:hover{            background-color:#f5f5f5 !important;        }        .fileShareIndicator.small{            position: absolute;            top: calc(50% - 8px);            left: 8px;            height: 10px;            width: 10px;        }        .fileShareIndicator.medium{            position: absolute;            top: calc(50% - 8px);            left: 10px;            height: 16px;            width: 16px;        }        .fileShareIndicator.big{            position: absolute;            top: calc(50% - 8px);            left: 12px;            height: 18px;            width: 18px;        }        .fileShareIndicator img{            width: 100%;        }        .disabled{            pointer-events: none;            opacity: 0.5;        }        .stackedWindowButton{            text-overflow: ellipsis !important;            white-space: nowrap;            word-break: break-all;        }        .iframewrapper iframe{            border: 0px;        }        .alternativeAccount.item{            padding-top: 0.6em !important;            padding-bottom: 0.6em !important;            margin: 0;        }        /* File operation progress tracker */        #backgroundTaskPanel{            background-color: var(--body_background) !important;            color: var(--text_color);            border: var(--divider) !important;        }         /* Offline blinking warning css */         @-moz-keyframes blink {                0% {                    opacity:1;                }                50% {                    opacity:0;                }                100% {                    opacity:1;                }            }             @-webkit-keyframes blink {                0% {                    opacity:1;                }                50% {                    opacity:0;                }                100% {                    opacity:1;                }            }            /* IE */            @-ms-keyframes blink {                0% {                    opacity:1;                }                50% {                    opacity:0;                }                100% {                    opacity:1;                }            }             /* Opera and prob css3 final iteration */            @keyframes blink {                0% {                    opacity:1;                }                50% {                    opacity:0;                }                100% {                    opacity:1;                }            }             .blink-image {                -moz-animation: blink normal 2s infinite ease-in-out; /* Firefox */                -webkit-animation: blink normal 2s infinite ease-in-out; /* Webkit */                -ms-animation: blink normal 2s infinite ease-in-out; /* IE */                animation: blink normal 2s infinite ease-in-out; /* Opera and prob css3 final iteration */            }            /*                Hover file decriptor UI            */            .fileDescription {                width:200px;                position:fixed;                z-index:10;                background:white;                padding: 10px;                border: 1px solid #2c2c2c;                -webkit-box-shadow: 6px 5px 10px -3px rgba(0,0,0,0.75);                -moz-box-shadow: 6px 5px 10px -3px rgba(0,0,0,0.75);                box-shadow: 6px 5px 10px -3px rgba(0,0,0,0.75);                padding:2px;                word-wrap: break-word;            }            body.darkTheme .fileDescription{                background-color: var(--body_background, #242330);            }            /*                Background Task UI            */            #backgroundTaskPanel{                background-color:white;                position:absolute;                bottom:36px;                right:0;                z-index:115;                width:400px;                border: 1px solid #ebebeb;                padding-top:8px;                padding-bottom:8px;                max-height: 70vh;                overflow-y: auto;                overflow-x: hidden;            }            .backgroundtaskObject{                padding: 0.4em;                padding-right: 0.8em;                padding-left: 1.2em;            }            .backgroundtaskObject .progress, .backgroundtaskObject .bar{                height: 1em !important;            }            .backgroundtaskObject .bar{                min-width: 0px !important;            }            .backgroundtaskObject .progress .bar{                background-color: #2b4871;            }            .backgroundtaskObject.paused .progress .bar{                background-color: #d6ba3e;            }            .backgroundtaskObject.stopping .progress .bar{                background-color: #d63e3e;            }            .backgroundtaskObject .circular.button i{                color: rgb(160, 160, 160) !important;                display: inline-block;                width: 10px !important;            }        /*                Z-index layering                Layer -1 : Background Images                Layer 0: Status Bar                Layer 0 - 99: Not focused tab                Layer 100: Focused tab drag drop layer                Layer 101: Focused Tab / File Descriptor Tag                Layer 114: Quick Access Panel                Layer 115: Background Task Panel                ...                Layer 400 - 499: Non-focused top most FloatWindows                Layer 500: Top Mot FloatWindow drag drop layer                Layer 501: Top Most FloatWindow                ...                Layer 1000: Connection lost indicator                ...                Layer 1110: Navigation Bar                Layer 1112: Stacked Window List                Layer 1113: List Menu                Layer 1114: Notification Bar background bluring layer                Layer 1115: Notification Bar                ...                Layer 3000: contextmenu            */    </style>    <script>        //Force redirection if it is on mobile        if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {            window.location.href = "mobile.system";        }    </script></head><body class="whiteTheme" style="background-color:black;">    <!-- Background frames-->    <div id="bgwrapper" class="background-wrapper" allowdrop="true" ondrop="drop(event)" ondragstart="return false;" onclick="event.preventDefault(); hideAllContextMenus();" ondblclick="event.preventDefault();event.stopImmediatePropagation();" ondragover="allowDrop(event);"        align="center" draggable="false">    </div>    <!-- Calendar and Notification -->    <div class="notificationbar" style="display:none;">                <div class="cover" onclick='toggleNotification("hide");' ontouchstart='toggleNotification("hide");'></div>        <div class="content">            <div id="notificationlist">                <div class="nonotification">                    <h4 class="ui center aligned icon header">                        <i class="bell icon"></i><span locale="notification/nonotification">No Notification</span>                    </h4>                </div>                <a class="clearall" onclick="clearAllNotification();" locale="notification/clear">Clear All</a>            </div>            <div style="position:absolute; right:3px; top:3px; padding-top:8px;">                <div class="ui header" style="padding-left:22px;">                    <div id="dayofweek" class="sub header"></div>                    <span id="largedate" style="font-size:120%;"></span>                </div>                <div class="auto-jsCalendar blue"></div>            </div>        </div>           </div>    <!-- Desktop icons-->    <div id="iconwrapper">            </div>    <!-- File Descriptors -->    <div id="fileDescriptor" class="fileDescription" style="font-size: 80%;display:none;z-index:101;">No Information</div>    <!-- Navigation Menu-->    <div id="navimenu" class="navimenu themeColor">        <div class="item clickable system" onclick="toggleListMenu();" ontouchstart="toggleListMenu();" style="margin-right: 0.5em;">            <img style="height:36px;" src="img/desktop/system_icon/list.png"></img>        </div>        <div class="item clickable system" onclick="showToolPanel();" ontouchend="showToolPanel();" style="border-left: 1px solid rgba(207, 207, 207, 0.37)">            <img style="height:36px;" src="img/desktop/system_icon/navi.png"></img>        </div>        <div class="item system" style="padding-top: 0.5em; padding-right: 1.3em; color: white; pointer-events: none;">            <span class="hostname">Welcome</span>        </div>             <!-- Right fixed buttons-->        <div id="backgroundtaskBtn" class="item backgroundtasks clickable system" onclick="showBackgroundTaskPanel()" ontouchstart="showBackgroundTaskPanel();">            <i class="clone icon"></i>        </div>        <div class="item clock clickable system"  onclick="toggleNotification();" ontouchstart="toggleNotification();">        </div>            </div>    <!-- floatWindow dragging panel-->    <div id="fwdragpanel"></div>    <div id="tfwdragpanel"></div>    <!-- Selection panel-->    <div id="selectionPanel"></div>    <!-- Stacked windows listing container-->    <div id="stackedWindowList" class="themeColor"></div>    <!-- List menu -->    <div id="listMenu" class="" style="display:none;">        <div class="searchBar" onkeydown="searchModule(event);">            <div class="ui icon fluid input" style="border-radius: 0px !important;">                <input id="searchBar" type="text" placeholder="Search" style="border: 0px solid transparent;">                <i class="search icon"></i>            </div>        </div>        <div class="listItemWrapper">            <div class="groups">                <div locale="listmenu/catergory/searchResults" id="searchResults" class="item" style="display:none;">Search Results</div>                <div locale="listmenu/catergory/all" class="item groupType selected" group="All">All</div>                <div locale="listmenu/catergory/media" class="item groupType" group="Media">Media</div>                <div locale="listmenu/catergory/office" class="item groupType" group="Office">Office</div>                <div locale="listmenu/catergory/download" class="item groupType" group="Download">Download</div>                <div locale="listmenu/catergory/files" class="item groupType" group="Files">Files</div>                <div locale="listmenu/catergory/internet" class="item groupType" group="Internet">Internet</div>                <div locale="listmenu/catergory/settings" class="item groupType" group="System Settings">System Settings</div>                <div locale="listmenu/catergory/tools" class="item groupType" group="System Tools">System Tools</div>                <div locale="listmenu/catergory/utils" class="item groupType" group="Utilities">Utilities</div>                <div locale="listmenu/catergory/other" class="item groupType" group="Other">Other</div>                <div class="poweroption">                    <img id="powerIcon" style="width:18px; vertical-align: top; margin-right:4px;" src="img/system/power.svg"></img> <span locale="listmenu/catergory/exit">Exit</span>                </div>            </div>            <div id="listMenuItem" class="items">            </div>        </div>    </div>    <div id="contextmenu" class="aroz contextmenu" style="display:none;">    </div>    <div id="subcontextmenu" class="aroz contextmenu" style="display:none;">    </div>    <!-- Disconnected. Reconnecting interface -->    <div id="connectionLost">        <div class="ui inverted card themeColor" style="width: 300px; background-color: rgba(14,14,14,0.5);">            <div class="content">                <div class="header"><img class="ui mini image blink-image" style="vertical-align:bottom; padding-right: 0.5em;" src="SystemAO/desktop/icons/connlost.svg"><span locale="error/connlost/title" style="color: white;">Connection Lost</span></div>                <div class="description" locale="error/connlost" style="color: white;">                    Connection to server is lost. Please wait until this warning disappear before further operations.                </div>            </div>            <div class="ui fluid bottom attached buttons">                <button locale="error/connlost/recheck" class="ui opinion button" style="background-color: rgba(14,14,14,0.2); color: white;" onclick="handleManualCheckReconnect(this);">Check Again</button>                <button locale="error/connlost/wait" class="ui secondary opinion button" style="background-color: rgba(14,14,14,0.5); color: white;">Wait</button>            </div>        </div>    </div>    <!-- Background Task Panel -->    <div id="backgroundTaskPanel" class="" style="display:none;">        <!--        <div class="backgroundtaskObject">            <small>src > dest (test.mp4)</small>            <div class="ui grid">                <div class="twelve wide column" style="padding-right: 0.4em;">                    <div class="ui mini active progress">                        <div class="bar" style="width: 50%;">                            <div class="progress">50%</div>                        </div>                    </div>                </div>                <div class="four wide column"  style="padding-top: 0.4em; padding-left: 0;" align="right">                    <button class="circular ui mini basic icon button">                        <i class="pause icon"></i>                    </button>                    <button class="circular ui mini basic red icon button">                        <i class="remove icon" style="color: red !important;"></i>                    </button>                </div>              </div>              <div class="ui divider" style="margin-top: 0;"></div>        </div>        -->    </div>    <!-- Content / Quick Access Panel-->    <div id="quickAccessPanel" class="" style="display:none;">        <div class="ui small items" style="margin-bottom: 0;">            <div class="item">                <div class="ui mini image">                    <img class="usericon" src="img/desktop/system_icon/user.svg">                </div>                <div class="content" style="padding-left: 1em;">                    <div id="username" class="header" style="font-weight: 600; font-size: 1.22em;">User</div>                    <div class="meta" style="margin-top: 0.15em;">                        <div id="usergroups">@Users</div>                    </div>                </div>                <div class="actions">                    <div class="ui small button" onclick="logout(); hideToolPanel();">                        <i class="log out icon"></i> <span locale="quickAccess/logout">Logout</span>                    </div>                </div>            </div>            <div class="ui divider"></div>            <div id="alternativeAccountList">                           </div>            <div class="ui divider" style="margin-left: 3em; margin-right: 3em;"></div>            <div class="item" style="padding-top: 6px; padding-bottom:6px; margin: 0px !important;" onclick="openSwitchAccountPanel(); hideToolPanel();">                <i class="ui user plus icon" style="margin-right: 0.6em;"></i> <span locale="account/switch/addAccount">Add another account</span>            </div>            <div id="signoutAllButton" style="padding-top: 6px; padding-bottom:6px; margin: 0px !important;" class="item" onclick="logoutAllAccounts();">                <i class="log out icon icon" style="margin-right: 0.6em;"></i> <span locale="account/switch/signoutAll">Sign-out all accounts</span>            </div>            <div class="ui divider"></div>        </div>        <div class="item" style="padding-bottom:12px;">            <i class="volume up icon"></i> <span locale="quickAccess/sysvol">System Global Volume</span>            <div class="ui fluid small progress" style="margin-top:8px; margin-bottom:8px; cursor:pointer;" onclick="updateVolume(this,event);" >                <div id="volumebar" class="bar" style="width: 0%; min-width: 0px; background-color:#52C9FF;  cursor:pointer;"></div>            </div>        </div>        <div class="item" style="padding-bottom:12px;">            <i class="lightbulb icon"></i> <span locale="quickAccess/brightness">Brightness</span>            <div class="ui fluid small progress" style="margin-top:8px; margin-bottom:8px; cursor:pointer;" onclick="updateBrightness(this,event);" >                <div id="brightnessbar" class="bar" style="width: 100%; min-width: 0px; background-color:#52C9FF;  cursor:pointer;"></div>            </div>        </div>        <div class="item" id="settingButton" onclick="showSystemSettings(); hideToolPanel();" ontouchend="showSystemSettings(); hideToolPanel();">            <i class="setting icon"></i> <span locale="quickAccess/settings">System Settings</span>            <!-- <div style="float:right;"><i class="caret right icon"></i></div> -->        </div>        <div class="item" onclick="fullscreen(); hideToolPanel();" ontouchend="fullscreen(); hideToolPanel();">            <i class="expand icon"></i> <span locale="quickAccess/fullscreen">Toggle Fullscreen</span>        </div>        <div class="ui divider" style="margin: 0.4em;"></div>        <div class="item powerman" onclick="restart(); hideToolPanel();" ontouchend="restart(); hideToolPanel();">            <i class="repeat icon"></i> <span locale="quickAccess/restart">Restart</span>        </div>        <div class="item powerman" style="color:#b51d1d;"  onclick="shutdown(); hideToolPanel();" ontouchend="shutdown(); hideToolPanel();">            <i class="power icon"></i> <span locale="quickAccess/poweroff">Power Off</span>        </div>        <div class="ui container" style="padding-left: 1em; color: rgb(199, 199, 199);">            <small id="sysinfo"></small>        </div>    </div>    <div>        <canvas id="textWidthCanvas" style="display:none;"></canvas>    </div>    <script>        /*        ArOZ Online Desktop Interface        This script maintain the usability of the desktop environment.        This is not identical to the previous Desktop environment used in ArOZ Online BETA.        */        //System environment variables        var isDesktopMode = true;        var loggingOut = false;        //Desktop background related        var desktopThemeList = []; //Storing the list of background installed        var currentBackgroundList = []; //Current list of background files        var currentUserTheme = ""; //The theme for current user.         var backgroundCrossfadeInterval = 30000; //Time between the crossfade of each background image        var nextSlideshowIndex = 0; //The next background image index to be shown        var backgroundIntervalCounter; //The interval object for background changer        var desktopThemeColor = ""; //The current desktop theme color, which renders to the status bar and suchs        //Desktop icon realted        var desktopIconSize = "medium"; //Size of desktop icons. Allow {small / medium / big}        var desktopIconPack = "default"; //Desktop icon pack to be used. Located under desktop/file_icon/{pack-name}        var desktopGrids = []; //Reference virtual grid for icons on desktop        var iconSize = []; //Defined the icon size for the desktop icons        var desktopFileList = []; //Temperature storage of desktop filenames        var startDragRelatuve = []; //Relative location of where the icon being start dragging        var iconOffsetXY = [-10,-10];  //Pixel to offset for the icon location        //Float window related        var focusedWindow;        const maxWindowCount = 100;        var movingWindow = false;        var resizingWindow = false;        var resizingEdgeID = 0; //Resizing edge. {0, 1, 2, 3, 4, 5, 6} => None, Right, Right Bottom Corner, Bottom, Left Bottom Corner, Left, TOp        var stackedFloatWindowListShown = false;        //Laucnh icon related        var multiSelecting = false;        var multiSelectionStartPoint = [-1, -1];        var clickDownOffset = [-1, -1];        var renameMode = false;        var operationTargetLaunchIcon;        var currentMousePosition = [-1, -1];        //Document key bindings        var ctrlHold = false;        var shiftHold = false;        //ListMenu Related Paramters        var moduleInstalled = [];        var listMenuShown = false;        //Context Menu variables        var menuStartLocation = [0, 0];        //Input Method Editor objects        window.ime = {            handler: null,            focus: null        };        //Upload related        let uploadFileChunkSize = 1024 * 512; //512KB per chunk in low memory upload        let largeFileCutoffSize = 8192 * 1024 * 1024; //Any file larger than this size is consider "large file", default to 8GB        let postUploadModeCutoff = 25 * 1048576; //25MB, files smaller than this will upload using POST Mode        //Others        var monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];        var daysNames = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'];        var hostInfo = {};        var userInfo = {};        var powerman = false;        var downloadMode = false;        var lowMemoryMode = true;        //Browser and device detection        var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);        var isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;        var isChrome = /Chrome/.test(navigator.userAgent) && /Google Inc/.test(navigator.vendor);        var isMacOS = (navigator.appVersion.indexOf("Mac")!=-1);        var isTouchScreen = window.matchMedia("(any-pointer: coarse)").matches;        //Check and prepare localization        if (typeof(applocale) != "undefined"){            //Applocale found. Do localization            applocale.init("./SystemAO/locale/desktop.json", function(){                applocale.translate();                initDesktop();            });        }else{            //Applocale not found. Is this a trim down version of ArozOS?            var applocale = {                getString: function(key, original){                    return original;                }            }            initDesktop();        }        function initDesktop(){            //Initiation functions            initDesktopTheme();            initDesktopHostInfo();            initDesktopUserInfo();            initBackgroundSwitchingAnimation();            //Commented for debug purpose            initUploadMode();            initModuleList();            initDesktopIconPreference()            initUserDefinedThemeColor();            hookFloatWindowEvents();            hookLaunchMenuEvents();            initTheme();            initStartupSounds();            initUploadCuttoffValues();            //Login cookie expire check            setInterval(function() {                checkConnection();            }, 15000);            //Activate all dropdowns            $(".dropdown").dropdown();        }        function initUploadCuttoffValues(){             //Get the avaible space on tmp disk and decide the cutoff file size that need to directly write to disk            $.ajax({                url: "system/disk/space/tmp",                method: "POST",                data: {},                success: function(data){                    if (data.error !== undefined){                        console.log("%c[Desktop] Unable to auto-detect huge file cutoff size: " + data.error, 'color: #e64747');                    }else{                        if (!isNaN(data.Available) && data.Available > 0){                            largeFileCutoffSize = data.Available/16 - 4096;                            console.log("%c[Desktop] Setting huge file cutoff size at: " + ao_module_utils.formatBytes(data.Available/16), 'color: #036ffc');                        }else if (isNaN(data.Available)){                            console.log("%c[Desktop] Unable to read available tmp disk size. Using default huge file cutoff size.", 'color: #e64747');                        }                                            }                },                error: function(){                    //Hardware mode disabled. Use default value.                }            });        }        function handleManualCheckReconnect(button){            $(button).addClass("loading");            checkConnection(undefined, function(status){                let oldText = $(button).text();                $(button).removeClass("loading");                if (status == false){                    //Still unable to connect. Show cross icon                    $(button).html(`<i class="remove icon"></i>`);                    setTimeout(function(){                        //Restore its original text after 5 sec                        $(button).text(oldText);                    }, 5000);                }            });        }        function centerTruncat(fullStr, strLen, separator) {            if (fullStr.length <= strLen) return fullStr;            separator = separator || '...';            var sepLen = separator.length,                charsToShow = strLen - sepLen,                frontChars = Math.ceil(charsToShow/2),                backChars = Math.floor(charsToShow/2);            return fullStr.substr(0, frontChars) +                 separator +                 fullStr.substr(fullStr.length - backChars);        };        function handleBackgroundTaskPauseToggle(oprid, btn=undefined, currentlyPaused=false){            console.log(oprid, currentlyPaused);            if (btn != undefined){                $(btn).addClass("disabled");                $(btn).html(`<i class="ui spinner loading icon"></i>`);            }            if (currentlyPaused){                //Resume                $.ajax({                    url: "system/file_system/ongoing",                    method: "POST",                    data: {"oprid": oprid, "flag": "continue"},                    success: function(data){                        if (data.error != undefined){                            console.log(data.error);                        }                        updateBackgroundgTaskList();                    }                });            }else{                //Pause                $.ajax({                    url: "system/file_system/ongoing",                    method: "POST",                    data: {"oprid": oprid, "flag": "pause"},                    success: function(data){                        if (data.error != undefined){                            console.log(data.error);                        }                        updateBackgroundgTaskList();                    }                });            }        }        function handleBackgroundTaskCancel(oprid, btn=undefined){            $.ajax({                url: "system/file_system/ongoing",                method: "POST",                data: {"oprid": oprid, "flag": "cancel"},                success: function(data){                    if (data.error != undefined){                        console.log(data.error);                    }else{                        //Disable further operation untill task cancelled                        if (btn != undefined){                            $(btn).addClass("disabled");                            $(btn).html(`<i class="ui spinner loading icon"></i>`);                        }                                          }                    updateBackgroundgTaskList();                }            });        }        //The background task checking function will ping server side at a more         //frequent interval if there is a background task running        var rapidIntervalTaskListing = undefined;        function updateBackgroundgTaskList(){            //Update background tasks            $.get("system/file_system/ongoing", function(tasks){                tasks.sort(function(a, b) {                     return a.ID > b.ID;                });                //console.log(tasks);                $("#backgroundTaskPanel").html("");                tasks.forEach(function(task){                    console.log(task);                    var pausedClass = "";                    var pauseIcon = "pause";                    var cancelBtnDisabled = "";                    if (task.FileOperationSignal == 1){                        pausedClass = "paused";                        pauseIcon = "play";                    }else if (task.FileOperationSignal == 2){                        pausedClass = "stopping";                        cancelBtnDisabled = "disabled";                    }                    $("#backgroundTaskPanel").append(`<div class="backgroundtaskObject ${pausedClass}">                        <small>${centerTruncat(task.Src, 22, "...")} <i class="angle right icon"></i> ${centerTruncat(task.Dest, 22, "...")} (${centerTruncat(task.LatestFile, 30, "...")})</small>                        <div class="ui grid">                            <div class="twelve wide column" style="padding-right: 0.4em; padding-bottom: 0.4em;">                                <div class="ui mini active progress">                                    <div class="bar" style="width: ${task.Progress}%;">                                        <div class="progress">${task.Progress}%</div>                                    </div>                                </div>                            </div>                            <div class="four wide column"  style="padding-top: 0.4em; padding-left: 0;  padding-bottom: 0.4em;" align="right">                                <button class="circular ui mini basic icon ${cancelBtnDisabled} button" oprid="${task.ID}" onclick="handleBackgroundTaskPauseToggle('${task.ID}', this, ${task.FileOperationSignal==1});">                                    <i class="${pauseIcon} icon"></i>                                </button>                                <button class="circular ui mini basic red icon ${cancelBtnDisabled} button" oprid="${task.ID}" onclick="handleBackgroundTaskCancel('${task.ID}', this);">                                    <i class="remove icon" style="color: red !important;"></i>                                </button>                            </div>                        </div>                    </div>`);                });                if (tasks.length > 0){                    if (rapidIntervalTaskListing != undefined){                        clearTimeout(rapidIntervalTaskListing);                        rapidIntervalTaskListing = undefined;                    }                    rapidIntervalTaskListing = setTimeout(function(){                        updateBackgroundgTaskList();                    }, 1000);                    $("#backgroundtaskBtn").find("i").attr("class", "loading circle notch icon");                }else{                    $("#backgroundTaskPanel").append(`<div class="ui basic segment" style="width: 100%;">                        <i class="ui checkmark icon"></i> ${applocale.getString("backgroundTasks/noTasks", "No running background tasks")}                        <a style="cursor: pointer; float: right; margin-top: 0.2em;" onclick="updateBackgroundgTaskList();">${applocale.getString("backgroundTasks/refresh", "Refresh")}</a>                    </div>`);                    $("#backgroundtaskBtn").find("i").attr("class", "circle notch icon");                }                            });        }        updateBackgroundgTaskList();              function checkConnection(timeout=15000, callback=undefined){            $.ajax({                url: 'system/auth/checkLogin',                success: function(data) {                    if (data == true) {                        //Continue session                        updateBackgroundgTaskList();                                          } else {                        //Session timeout. Redirect to system index                        loggingOut = true;                        window.location.href = "index.html";                    }                    $("#connectionLost").hide();                    document.title = hostInfo.Hostname;                    if (callback != undefined){                        callback(true);                    }                },                error: function(evt) {                    //Server closed or freezed?                    $("#connectionLost").show();                    document.title = "Reconnecting...";                    if (callback != undefined){                        callback(false);                    }                },                timeout: timeout            });        }        //Keep the clock updated        setInterval(function(){            updateClockTime();        },5000);        updateClockTime();        function updateClockTime(){            var d = new Date();            var ampm = "AM";            var currentHour = d.getHours()            if (currentHour > 12){                ampm = "PM";                currentHour -= 12;            }            var display = `${zeropad(currentHour,2)}:${zeropad(d.getMinutes(),2)} ${ampm}<br>            ${d.getDate()} ${monthNames[d.getMonth()].substr(0, 3)} ${d.getFullYear()}`;                        if ($(".notification.object").length > 0){                display += `<span style="color: #f54242; margin-left: 8px; float: center;"><i class="notice circle icon"></i></span>`;            }            $(".clock").html(display);            var largedate = monthNames[d.getMonth()] + " " + d.getDate() + " " + d.getFullYear()             $("#largedate").text(largedate);            var dow = daysNames[d.getDay()];            $("#dayofweek").text(dow);        }        function zeropad(n, width, z) {            z = z || '0';            n = n + '';            return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;        }        function showBackgroundTaskPanel(){            $("#backgroundTaskPanel").slideToggle("fast");        }        function showToolPanel(){            if (listMenuShown = true){                hideListMenu();            }            $("#quickAccessPanel").fadeIn("fast");        }        function hideToolPanel(){            $("#quickAccessPanel").fadeOut("fast");        }        function initStartupSounds(){            $.ajax({                url: "system/desktop/preference",                method: "POST",                data: {preference: "startup-audio"},                success: function(data){                    if (data == undefined || data == ""){                        return;                    }                    var currentGlobalVol = localStorage.getItem("global_volume");                    if (currentGlobalVol != null && currentGlobalVol != undefined && currentGlobalVol != ""){                                            }else{                        currentGlobalVol = 0;                    }                    var audio = new Audio("media?file=" + data);                    audio.volume = currentGlobalVol;                    audio.play();                }            });        }        function initDesktopUserInfo(callback=undefined){            $.get("system/desktop/user", function(data){                if (data.error !== undefined){                    alert(data.error);                }else{                    userInfo = data;                    listAllStoredAccounts();                    //Update the user tag                    $("#username").text(userInfo.Username);                    $("#usergroups").text("@" + userInfo.UserGroups.join("/"));                    $("#usergroups").attr("title",userInfo.UserGroups.join(" / "));                    if (data.UserIcon !== ""){                        $(".usericon").attr("src",data.UserIcon);                    }else{                        $(".usericon").attr("src", "img/desktop/system_icon/user.svg")                    }                    if (data.IsAdmin == false){                        //Hide the power buttons                        $(".hardware").hide();                    }else{                        //User is admin. Add admin icon                        $("#username").append(`<i style="margin-left: 0.4em; color: #${desktopThemeColor}" class="small shield alternate icon themed text"></i>`);                    }                    if (callback != undefined){                        callback();                    }                }            });        }        function initDesktopHostInfo(){            //Load the data into variable            $.get("system/desktop/host",function(data){                hostInfo = data;                                //Update the ui element as well                $(".hostname").text(hostInfo.Hostname);                document.title = hostInfo.Hostname;                $("#sysinfo").text(hostInfo.DeviceModel + " firmware:" + hostInfo.BuildVersion + " " + hostInfo.InternalVersion);            });            //Setup volume bar            var currentGlobalVol = localStorage.getItem("global_volume");            if (currentGlobalVol != null && currentGlobalVol != undefined && currentGlobalVol != ""){                $("#volumebar").css("width", currentGlobalVol * 100 + "%");            }else{                currentGlobalVol = 0;                localStorage.setItem("global_volume",currentGlobalVol);            }            //Setup brightness            var currentBrightness = localStorage.getItem("brightness");            if (currentBrightness != null && currentBrightness != undefined && currentBrightness != ""){                $("#brightnessbar").css("width", currentBrightness * 100 + "%");                $("body").css("filter", `brightness(${currentBrightness * 100}%)`);            }else{                currentBrightness = 1;                localStorage.setItem("brightness",currentBrightness);            }                        //Check if hardware management mode is enabled. Hide buttons if needed            $.get("system/power/accessCheck",function(data){                if (data == true){                    //Hardware management mode is on                    powerman = true;                }else{                    //Hardware management mode is off                    $(".item.powerman").remove();                    powerman = false;                }               });        }        function toggleNotification(action=undefined){            if (typeof action == "undefined"){                $(".notificationbar").stop().finish().fadeToggle("fast", function(){                                  });            }else{                if (action == "hide"){                    $(".notificationbar").stop().finish().fadeOut("fast");                }else if (action == "show"){                    $(".notificationbar").stop().finish().fadeIn("fast");                }            }        }        // ===================== LIST MENU EVENTS FUNCTIONS ===============        function toggleListMenu() {            hideToolPanel()            $("#listMenu").fadeToggle("fast", function(){                if ($("#listMenu").is(":visible")) {                    listMenuShown = true;                } else {                    listMenuShown = false;                }            });        }        function initDesktopIconPreference() {            getStorage("iconsize", function(catergory) {                if (["small", "medium", "big"].includes(catergory)) {                    desktopIconSize = catergory;                }                refresh();                hideAllContextMenus();            });        }        function hideListMenu() {            if (listMenuShown) {                $("#listMenu").fadeOut("fast");                listMenuShown = false;            }        }        function initModuleList() {            $.ajax({                url: "system/modules/list",                success: function(data) {                    moduleInstalled = data;                    listModulesType("All");                    checkFileSystemAccess();                    //Hide the system setting button if access is denied                    var allowSettingAccess = false;                    moduleInstalled.forEach(thismod => {                        if (thismod.Name == "System Setting"){                            allowSettingAccess = true;                        }                    });                    if (!allowSettingAccess){                        $("#settingButton").hide();                    }                }            });        }        function hookLaunchMenuEvents(){            $(".groupType").off("click touchstart").on("click touchstart",function(){                moduleTypeButtonClicked(this);            });            $(".poweroption").off("click touchstart").on("click touchstart",function(){                logout();            });        }        function moduleTypeButtonClicked(object) {            var groupType = $(object).attr("group");            listModulesType(groupType);            $(".groupType.selected").removeClass("selected");            $(object).addClass("selected");            $("#searchResults").slideUp('fast');            $("#searchBar").val("");        }        function listModulesType(groupType) {            var listingItems = [];            if (groupType == "All") {                //List all of the items                for (var i = 0; i < moduleInstalled.length; i++) {                    if (moduleInstalled[i]["StartDir"] != "") {                        listingItems.push(moduleInstalled[i]);                    }                }            } else if (groupType == "Other") {                var excludeList = ["Media", "Office", "Download", "Files", "Internet", "System Settings", "System Tools", "Utilities"];                //List the Other groups                for (var i = 0; i < moduleInstalled.length; i++) {                    if (excludeList.includes(moduleInstalled[i]["Group"]) == false && moduleInstalled[i]["StartDir"] != "") {                        console.log(moduleInstalled[i]["Group"]);                        listingItems.push(moduleInstalled[i]);                    }                }            } else {                //List the given group                for (var i = 0; i < moduleInstalled.length; i++) {                    if (moduleInstalled[i]["Group"] == groupType && moduleInstalled[i]["StartDir"] != "") {                        listingItems.push(moduleInstalled[i]);                    }                }            }            //List the item to the listmenu            $("#listMenuItem").html("");            for (var i = 0; i < listingItems.length; i++) {                var thisModule = listingItems[i];                generateListMenuItem(thisModule);            }            if (listingItems.length == 0) {                $("#listMenuItem").html(`<div class="item module"><span><img src="img/system/not found.png">No WebApp found</span></div>`)            }        }        //Given a module information and generate a selectable item in the list menu        function generateListMenuItem(thisModule) {            var icon = thisModule["IconPath"];            if (icon == "") {                //Use default system icon                icon = "img/system/service.png";            }            var name = thisModule["Name"];            var startdir = thisModule["StartDir"];            var fwsupport = "false";            if (thisModule["SupportFW"]) {                fwsupport = "true";            }            $("#listMenuItem").append(`<div class="item module" module="${name}" startdir="${startdir}" fw="${fwsupport}" onclick="openModuleFromMenu(this);" ontouchstart="openModuleFromMenu(this);">                        <span>                            <img src="${icon}"></img>                            ${name}                        </span>                    </div>`);        }        function searchModule(event) {            if (event.which == 13) {                var keyword = $("#searchBar").val().toLowerCase();                var results = [];                var lessAccurateResults = [];                $(".groupType.selected").removeClass("selected");                $("#searchResults").addClass("selected").slideDown('fast');                //Load all search results                for (var i = 0; i < moduleInstalled.length; i++) {                    var thisModule = moduleInstalled[i];                    if (thisModule["StartDir"] == ""){                        continue;                    }                    var pathInfo = thisModule["StartDir"].split("/");                    for (var j = 0; j < pathInfo.length; j++) {                        pathInfo[j] = pathInfo[j].toLowerCase();                    }                    if (thisModule["Name"].toLowerCase().includes(keyword)) {                        results.push(thisModule);                    } else if (pathInfo.includes(keyword.toLowerCase()) || pathInfo.includes(keyword.split(" ").join("_").toLowerCase())) {                        lessAccurateResults.push(thisModule);                    }                }                results = results.concat(lessAccurateResults);                //Append the results to list                $("#listMenuItem").html("");                for (var i = 0; i < results.length; i++) {                    generateListMenuItem(results[i]);                }                if (results.length == 0) {                    //Append a custom no results div to the content                    $("#listMenuItem").append(` <div class="item">                        <span>                            <img src="img/system/not found.png"></img>                            No Result                        </span>                    </div>`);                }            }        }        function openModuleFromMenu(object) {            var moduleName = $(object).attr("module");            openModule(moduleName);        }        function openModule(moduleName, callback=undefined) {            $.get("system/modules/getLaunchPara?module=" + moduleName, function(data) {                if (data.error !== undefined) {                    //Something went wrong.                    console.log("Unable to open module " + moduleName);                    if (data.error == "Not logged in."){                        //Session expired                        window.location.href = "login.system";                    }                } else {                    //Launch the given module                    var url = data["StartDir"];                    var size = [undefined, undefined];                    var icon = "img/system/favicon.png";                    if (data["IconPath"] != "") {                        icon = data["IconPath"];                    }                    var title = data["Name"];                    //Check if the module support fw mode. If yes, launch with fwmode url. IF not, launch to index                    if (data["SupportFW"] == true) {                        console.log(data["LaunchFWDir"]);                        if (data["LaunchFWDir"] != null && data["LaunchFWDir"] != "") {                            url = data["LaunchFWDir"];                        }                        if (data["InitFWSize"] != null) {                            size = data["InitFWSize"];                        }                    }                    //Launch the given module                    var uuid = newFloatWindow({                        url: url,                        width: size[0],                        height: size[1],                        appicon: icon,                        title: title                    });                    if (callback !== undefined){                        callback();                    }                    hideListMenu();                }            });        }        // ===================== FLOAT WINDOWS EVENTS =====================        function hookFloatWindowEvents() {            //Handle floatWindow mouse drag events            $(".fwdragger").off("mousedown").on("mousedown", function(evt) {                evt.preventDefault();                evt.stopImmediatePropagation();                fwdown($(this).parent(), evt);            });            $(".fwdragger").off("mousemove").on("mousemove", function(evt) {                evt.preventDefault();                evt.stopImmediatePropagation();                fwmove($(this).parent(), evt);                //Add cusor change on resizble position reach                let hoverOffset = [event.pageX - $(this).offset().left, event.pageY - $(this).offset().top];                if (hoverOffset[1] <= 3 && !$(this).parent().hasClass("fixedsize")){                    $(this).addClass("resizbleCursor");                }else{                    $(this).removeClass("resizbleCursor");                }            });            $(".fwdragger").off("mouseup").on("mouseup", function(evt) {                evt.preventDefault();                evt.stopImmediatePropagation();                fwup($(this).parent(), evt);            });            $(".fwdragger").off("touchstart").on("touchstart", function(evt) {                evt.preventDefault();                evt.stopImmediatePropagation();                fwdown($(this).parent(), evt);                let fwMaxiButton = $(this).parent().find(".maxToogleButton").parent()[0]                doubleTouchHandler(this, evt, function(){                    toggleMax(fwMaxiButton, evt);                });            });            $(".fwdragger").off("touchmove").on("touchmove", function(evt) {                evt.preventDefault();                evt.stopImmediatePropagation();                fwmove($(this).parent(), evt);            });                        $(".fwdragger").off("touchend").on("touchend", function(evt) {                evt.preventDefault();                evt.stopImmediatePropagation();                fwup($(this).parent(), evt);            });            $(".fwdragger").off("dblclick").on("dblclick", function(evt) {                //Activate full screen                evt.preventDefault();                evt.stopImmediatePropagation();                //Emulate keypress on maximize btn                toggleMax($(this).parent().find(".maxToogleButton").parent()[0], evt);            });            //Floatwindow operations for touch devices            $(".maxtoggle").off("touchstart").on("touchstart",function(evt){                evt.preventDefault();                evt.stopImmediatePropagation();                toggleMax(this, evt);            });            $(".mintoggle").off("touchstart").on("touchstart",function(evt){                evt.preventDefault();                evt.stopImmediatePropagation();                min(this, evt);            });            $(".closetoggle").off("touchstart").on("touchstart",function(evt){                evt.preventDefault();                evt.stopImmediatePropagation();                closeFloatWindow(this,evt);            });            $(".dockleft").off("touchstart").on("touchstart",function(evt){                evt.preventDefault();                evt.stopImmediatePropagation();                dockWindowToLeft($(this).parent().parent().parent());            });            $(".dockright").off("touchstart").on("touchstart",function(evt){                evt.preventDefault();                evt.stopImmediatePropagation();                dockWindowToRight($(this).parent().parent().parent());            });            //floatWindow events for mouse            $(".maxtoggle").off("mousedown").on("mousedown",function(evt){                evt.preventDefault();                evt.stopImmediatePropagation();                toggleMax(this, evt);            });            $(".mintoggle").off("mousedown").on("mousedown",function(evt){                evt.preventDefault();                evt.stopImmediatePropagation();                min(this, evt);            });            $(".closetoggle").off("mousedown").on("mousedown",function(evt){                evt.preventDefault();                evt.stopImmediatePropagation();                closeFloatWindow(this,evt);            });            $(".dockleft").off("mousedown").on("mousedown",function(evt){                evt.preventDefault();                evt.stopImmediatePropagation();                dockWindowToLeft($(this).parent().parent().parent());            });            $(".dockright").off("mousedown").on("mousedown",function(evt){                evt.preventDefault();                evt.stopImmediatePropagation();                dockWindowToRight($(this).parent().parent().parent());            });            //Float Window events for resizing            $(".iframewrapper").off("mousedown").on("mousedown", function(evt) {                evt.preventDefault();                evt.stopImmediatePropagation();                resizeDown($(this).parent(), evt);            });            $(".iframewrapper").off("mousemove").on("mousemove", function(evt) {                evt.preventDefault();                evt.stopImmediatePropagation();                if (resizingWindow == true) {                    //Resizeing Move                    resizeMove($(this).parent(), evt);                } else {                    //Dragdropping move                    fwmove($(this).parent(), evt);                }            });            $(".iframewrapper").off("mouseup").on("mouseup", function(evt) {                evt.preventDefault();                evt.stopImmediatePropagation();                resizeUp($(this).parent(), evt);            });            $(".iframewrapper").off("mouseover").on("mouseover", function(evt) {                var object = $(this).parent();                if ($(object).hasClass("fixedsize")) {                    return false;                }                var dx = event.pageX - $(object).find(".iframewrapper").offset().left;                var dy = event.pageY - $(object).offset().top;                if (dx < 10 && dy > $(object).height() - 10) {                    //Left Bottom Corner                    $(".iframewrapper").attr("class", "iframewrapper leftCorner");                } else if (dx > $(object).width() - 10 && dy > $(object).height() - 10) {                    //Right Bottom Corner                    $(".iframewrapper").attr("class", "iframewrapper rightCorner");                } else if (dx < 10) {                    //Dragging left edge                    $(".iframewrapper").attr("class", "iframewrapper widthHover");                } else if (dx > $(object).width() - 10) {                    //Dragging right edge                    $(".iframewrapper").attr("class", "iframewrapper widthHover");                } else if (dy > $(object).height() - 10) {                    //Bottom Edge                    $(".iframewrapper").attr("class", "iframewrapper heighHover");                } else {                    //???                    $(".iframewrapper").attr("class", "iframewrapper");                }            });            //Hook events on the floatWindow button            $(".floatWindowButton").off("click touchstart").on("click touchstart", function(event) {                event.preventDefault();                event.stopImmediatePropagation();                $("#stackedWindowList").css("left", $(this).offset().left);                //Generate the stackedWindowList                var windowIdList = JSON.parse(decodeURIComponent($(this).attr("windowidgroup")));                if (windowIdList.length == 1) {                    //There are only one window in this group.                                        //Focus that floatWindow if it is in the back                    var targetFW = getFloatWindowByID(windowIdList[0]);                    if (FloatWindowIsTopped(targetFW) && !($(targetFW).css('display') == 'none')){                        //Top Window. Hide it                        $(targetFW).fadeOut(100);                    }else{                        //Bring it to front                        $(targetFW).fadeIn(100);                        MoveFloatWindowToTop(targetFW);                        stackedFloatWindowListShown = false;                    }                    if (checkIfFloatWindowOutsideWindowArea(targetFW)){                        //This floatWindow is outside of the display area.                        resetFloatWindowPosition(targetFW);                    }                    $("#stackedWindowList").hide();                } else {                    //Get icon for each windows and build the list objects                    $("#stackedWindowList").html("");                    for (var i = 0; i < windowIdList.length; i++) {                        var iconURL = getFloatWindowIconByID(windowIdList[i]);                        var title = getFloatWindowTitleByID(windowIdList[i]);                        $("#stackedWindowList").append(`<div class="stackedWindowButton item clickable" windowId="${windowIdList[i]}" onclick="bringFloatWindowToFrontByFWB(this,event);"  ontouchstart="bringFloatWindowToFrontByFWB(this,event);"><span><img src="${iconURL}"></img>${title}</span><div class="closebtn" onclick="closeFWviaFWB(this,event);"><img src="img/system/close.png"></img></div></div>`);                    }                    $("#stackedWindowList").show();                    stackedFloatWindowListShown = true;                }            });        }        var tapedTwiceTouch = false;        var timeoutObject;        var tappingTarget = undefined;        function doubleTouchHandler(object, event, callback) {            if(!tapedTwiceTouch) {                tapedTwiceTouch = true;                tappingTarget = object;                timeoutObject = setTimeout( function() { tapedTwiceTouch = false; }, 300 );                return false;            }            if (tappingTarget == object){                //Double click on the same icon                event.preventDefault();                callback(object, event);                tappingTarget = undefined;            }else{                //Although it touch twice within 300ms, but it is on different target                //Update the tab target instead.                tappingTarget = object;                tapedTwiceTouch = true;                clearTimeout(timeoutObject);                timeoutObject = setTimeout( function() { tapedTwiceTouch = false; }, 300 );            }                   }        function openViaTouch(object, event){            iconDoubleClicked(object,event);        }        //Handle focus through floatWindow taskbar button        function bringFloatWindowToFrontByFWB(object, event) {            event.preventDefault();            event.stopImmediatePropagation();            var targetWFID = $(object).attr("windowId");            var targetFW = getFloatWindowByID(targetWFID);            if (targetFW == undefined){                //fw not found                return;            }            $(targetFW).fadeIn(100);            MoveFloatWindowToTop(targetFW);            stackedFloatWindowListShown = false;            $("#stackedWindowList").hide();        }        //Close FloatWindow via fwid        function closeFloatWindowViaID(fwid){            var thisFW = getFloatWindowByID(fwid);            closeFloatWindow(thisFW.find(".close"), null);        }        //Close FloatWindow via the floatWindowBody        function closeFWviaFWB(object, event=null) {            if (event != null){                event.preventDefault();                event.stopImmediatePropagation();            }                      var targetWFID = $(object).parent().attr("windowId");            var targetFW = getFloatWindowByID(targetWFID);            if (targetFW == undefined){                //fw not found                return;            }            closeFloatWindow(targetFW.find(".close"), event);            $(object).parent().remove();            if ($("#stackedWindowList").find(".item").length == 0) {                //There are no more things in this tab. Close this list as well.                stackedFloatWindowListShown = false;                $("#stackedWindowList").hide();            }        }        //Check if the given floatWindow DOM object is located outside the screen area.        function checkIfFloatWindowOutsideWindowArea(targetFW, checkForCompletelyOutside=true){            let fwTop = $(targetFW).offset().top;            let fwLeft = $(targetFW).offset().left;            let fwBottom = $(targetFW).offset().left + $(targetFW).width();            let fwRight = $(targetFW).offset().top + $(targetFW).height();            //Check for floatWindow complete            if (checkForCompletelyOutside){                if (fwBottom < 0 || fwTop > window.innerHeight + 1){                    return true;                }else if (fwRight < 0 || fwLeft > window.innerWidth + 1){                    return true;                }                return false;            }else{                //Check if any edge of the fw is outside of the document window                if (fwTop < 0 || fwBottom > window.innerHeight + 1){                    return true;                }else if (fwLeft < 0 || fwRight > window.innerWidth + 1){                    return true;                }                return false;            }        }        //Reset the given floatWindow object position on screen        function resetFloatWindowPosition(targetFW, center=true){            if (center == true){                //Calculate the corner position of the target                var newTop = window.innerHeight/2 - $(targetFW).height()/2;                var newLeft = window.innerWidth/2 - $(targetFW).width()/2;                $(targetFW).css({                    left: newLeft,                    top: newTop,                });            }else{                //Reset to origin + 10                $(targetFW).css({                    left: 10,                    top: 10,                });            }        }        //Handle floatWindow resize events        let resizingWindowTarget;        let resizingMinX = 0;        let minxWidth = 120;        let minHeight = 100;        function resizeDown(object, event) {            if (object.length > 1){                object = object[0];            }            if ($(object).hasClass("fixedsize")) {                return false;            }            //Mouse down, start resizing            resizingWindow = true;            resizingWindowTarget = object;            resizingMinX = $(object).offset().left + $(object).width() - minxWidth;            MoveFloatWindowToTop(object);            if ($(object).hasClass("topmost")){                //Top most windows                $("#tfwdragpanel").show();            }else{                //Normal Windows                $('.floatWindow.topmost').css("pointer-events", "none");                $('.floatWindow.topmost').css("opacity", 0.7);                $("#fwdragpanel").show();            }                                  $(object).find(".iframecover").show();            //Check which edge is the user dragging            var dx = event.pageX - $(object).find(".iframewrapper").offset().left;            var dy = event.pageY - $(object).offset().top;            if (dx < 10 && dy > $(object).height() - 10) {                //Left Bottom Corner                resizingEdgeID = 4;                $(object).find(".iframewrapper").css('cursor', 'sw-resize');            } else if (dx > $(object).width() - 10 && dy > $(object).height() - 10) {                //Right Bottom Corner                resizingEdgeID = 2;                $(object).find(".iframewrapper").css('cursor', 'se-resize');            } else if (dx < 10) {                //Dragging left edge                resizingEdgeID = 5;                $(object).find(".iframewrapper").css('cursor', 'w-resize');            } else if (dx > $(object).width() - 10) {                //Dragging right edge                resizingEdgeID = 1;                $(object).find(".iframewrapper").css('cursor', 'w-resize');            } else if (dy > $(object).height() - 10) {                //Bottom Edge                resizingEdgeID = 3;                $(object).find(".iframewrapper").css('cursor', 's-resize');            }            //For upper edge, see fwdown() handler        }        function resizeMove(object, event) {            var posX = event.pageX;            var posY = event.pageY;                        if (resizingWindow == true && resizingEdgeID != 0) {                if (resizingEdgeID == 1) {                    //Width = posX - floatWindow width + 2 (for border width)                    var newWidth = posX - $(object).offset().left + 2;                    $(object).css("width", Math.max(newWidth, minxWidth));                } else if (resizingEdgeID == 2) {                    var newWidth = posX - $(object).offset().left + 2;                    var newHeight = posY - $(object).offset().top + 2;                    $(object).css({                        width: Math.max(newWidth, minxWidth),                        height: Math.max(newHeight, minHeight)                    });                } else if (resizingEdgeID == 3) {                    var newHeight = posY - $(object).offset().top + 2;                    $(object).css("height", Math.max(newHeight,minHeight));                } else if (resizingEdgeID == 4) {                    var newWidth = $(object).offset().left - posX + $(object).width();                    var newHeight = posY - $(object).offset().top + 2;                                        if (newWidth < minxWidth){                        posX = resizingMinX;                    }                                        $(object).css({                        width: Math.max(newWidth, minxWidth),                        height: Math.max(newHeight, minHeight),                        left: posX                    });                } else if (resizingEdgeID == 5) {                    var newWidth = $(object).offset().left - posX + $(object).width();                    if (newWidth < minxWidth){                        posX = resizingMinX;                    }                                        $(object).css({                        width: Math.max(newWidth, minxWidth),                        left: posX                    });                } else if (resizingEdgeID == 6){                    var newHeight = $(object).height() - (posY - $(object).offset().top) + 2;                    $(object).css({                        "top": posY - 2,                        "height": Math.max(newHeight,minHeight),                    });                }            }        }        function resizeUp(object, event) {            resizingWindow = false;            resizingEdgeID = 0;            $("#fwdragpanel").hide();            $("#tfwdragpanel").hide();            $('.floatWindow.topmost').css("pointer-events", "auto");            $('.floatWindow.topmost').css("opacity", 1);            $(object).find(".iframecover").hide();            $(object).find(".iframewrapper").css('cursor', '');            //Force minmium width and height on any floatWindow objects            if ($(object).width() < 120) {                $(object).css("width", "120px");            }            if ($(object).height() < 120) {                $(object).css("height", "120px");            }            resizingWindowTarget = undefined;            $(".topmost").show();        }        //Hook body mousemove assistant events        $("body").on("mousemove", function(evt) {            if (focusedWindow !== undefined && movingWindow == true) {                fwmove(focusedWindow, evt);            } else if (focusedWindow !== undefined && resizingWindow == true) {                resizeMove(focusedWindow, evt);            } else if (multiSelecting == true) {                movingMultiSelectionArea(evt);            }        });        //Hook body clicke vents        $("body").on("click", function(evt) {            if (stackedFloatWindowListShown == true) {                //Hide the stacked Float Window list if it is shown                $("#stackedWindowList").hide();                stackedFloatWindowListShown = false;            }            if (renameMode == true){                //Exit rename mode if the target is not on the editing launchIcon                //console.log(evt.target);                var isBackground = false;                if ($(evt.target).attr("id") && $(evt.target).attr("id").length >= 4 &&  $(evt.target).attr("id").substr(0, 3) == "dbg"){                    isBackground = true;                }                if ($(evt.target).is("body") || isBackground){                    //End rename mode                    exitRenameMode();                }            }        });        //Convert touch events to click events        function mapEventFromTouch(event){            if (typeof event.originalEvent == "undefined"){                //Mouse click / down / up events                return event;            }            try{                //Touch events                if (typeof event.pageX == "undefined"){                    event.pageX = event.originalEvent.touches[0].pageX;                }                if (typeof event.pageY == "undefined"){                    event.pageY = event.originalEvent.touches[0].pageY;                }                return event;            }catch{                return event;            }                   }        //Please pass in the floatWindow object instead of the dragger        function fwdown(object, event) {            event = mapEventFromTouch(event);            //Hide all contenxt menus            hideAllContextMenus();            //Move the window to the top layer            MoveFloatWindowToTop(object);                        //Show the background drag panel            if ($(object).hasClass("topmost")){                $("#tfwdragpanel").show();            }else{                                $('.floatWindow.topmost').css("pointer-events", "none");                $('.floatWindow.topmost').css("opacity", 0.7);                $("#fwdragpanel").show();            }                                    //Get the relative click offset of the down event            clickDownOffset = [event.pageX - $(object).offset().left, event.pageY - $(object).offset().top];            if (clickDownOffset[1] <= 3 && !$(object).hasClass("fixedsize")){                //Resizing Top Edge                resizingWindow = true;                resizingWindowTarget = $(object);                resizingEdgeID = 6;            }else{                //Moving Window                movingWindow = true;                            }            $(object).find(".iframecover").show();                    }         function fwmove(object, event) {            event = mapEventFromTouch(event);            if (movingWindow == true) {                //Check if the object is maximized. If yes, minimized it                if ($(object).attr("max") == "true") {                    var originalSize = JSON.parse(decodeURIComponent($(object).attr("orgsize")));                    $(object).attr("max", "false");                    $(object).attr("orgsize", "");                    //Calculate new left right offsets                    var clickRatio = event.pageX / window.innerWidth;                    var newLeft = event.pageX - (clickRatio * originalSize[0]);                    originalSize                    $(object).css({                        width: originalSize[0],                        height: originalSize[1],                        left: newLeft,                        right: "auto",                        top: event.Y - 2                    });                    clickDownOffset[0] = clickRatio * originalSize[0];                    clickDownOffset[1] = 2;                    //Restore the maximize icon                    $(object).find(".maxToogleButton").attr('src', "img/system/max.svg");                    $(object).find(".dockright").removeClass("disabled");                    $(object).find(".dockleft").removeClass("disabled");                }                $(object).css("left", event.pageX - clickDownOffset[0]);                $(object).css("top", event.pageY - clickDownOffset[1]);            } else if (resizingWindow && resizingEdgeID == 6){                resizeMove($(object), event);            }        }        //Dock the window object to left        function dockWindowToLeft(object){            var originalSize = [$(object).width(), $(object).height(), $(object).offset().left, $(object).offset().top];            $(object).attr("orgsize", encodeURIComponent(JSON.stringify(originalSize)));            $(object).css({                width: "50%",                height: "calc(100% - 36px)",                left: "0px",                right: "auto",                top: "0px"            });            $(object).attr("max", "true");            $(object).find(".maxToogleButton").attr('src', "img/system/restore.svg");            $(object).find(".dockright").addClass("disabled");            $(object).find(".dockleft").addClass("disabled");        }        //Dock the window object to right        function dockWindowToRight(object){            var originalSize = [$(object).width(), $(object).height(), $(object).offset().left, $(object).offset().top];            $(object).attr("orgsize", encodeURIComponent(JSON.stringify(originalSize)));            $(object).css({                width: "50%",                height: "calc(100% - 36px)",                right: "0px",                left: "auto",                top: "0px"            });            $(object).attr("max", "true");            $(object).find(".maxToogleButton").attr('src', "img/system/restore.svg");            $(object).find(".dockright").addClass("disabled");            $(object).find(".dockleft").addClass("disabled");        }        function fwup(object, event) {            event = mapEventFromTouch(event);            if (movingWindow) {                $("#fwdragpanel").hide();                $("#tfwdragpanel").hide();                $('.floatWindow.topmost').css("pointer-events", "auto");                $('.floatWindow.topmost').css("opacity", 1);                $(object).find(".iframecover").hide();                movingWindow = false;                //Float Window Snapping Logic                //Check if the window location is drag to the edge of the screen. If yes, toggle half screen fullscreen                //Not need to check for if max because it must be minimized during drag move                var dockMode = false;                if (event.pageX < 10) {                    //Dock to left                    dockWindowToLeft(object);                } else if (event.pageX > window.innerWidth - 10) {                    //Dock to right                    dockWindowToRight(object);                }            }else if (resizingWindow && resizingEdgeID == 6){                resizeUp($(object), event);            }        }        //Handle floatWindow min, max and close        function min(object, event) {            event.preventDefault();            event.stopImmediatePropagation();            if (event.type == "mousedown" && event.which != 1) {                //Ignore right mouse down                return;            }            var fw = $(object).parent().parent().parent();            $(fw).fadeOut(100);        }        function toggleMax(object, event) {            event.preventDefault();            event.stopImmediatePropagation();            event = mapEventFromTouch(event);            if (event.type == "mousedown" && event.which != 1) {                //Ignore right mouse down                return;            }            if ($(object).css('display') == 'none'){                //This windows do not allow resizing.                 return;            }            var fw = $(object).parent().parent().parent();            var maxedAlready = $(fw).attr('max');            MoveFloatWindowToTop(fw);            //Add transition animation            $(fw).css({                "transition": "width 0.3s ease-out,  height 0.3s ease-out, top 0.3s ease-out, left 0.3s ease-out"            });            //Remove transition animation after complete wth 50ms buffer            setTimeout(function(){                $(fw).css({                "transition": ""                });            }, 350);                       if (maxedAlready == "true") {                //Resize to original                console.log($(fw));                var originalSize = JSON.parse(decodeURIComponent($(fw).attr("orgsize")));                               $(fw).attr("max", "false");                $(fw).attr("orgsize", "");                $(fw).css({                    width: originalSize[0],                    height: originalSize[1],                    left: originalSize[2],                    top: originalSize[3]                });                $(fw).find(".maxToogleButton").attr('src', "img/system/max.svg");                $(fw).find(".dockright").removeClass("disabled");                $(fw).find(".dockleft").removeClass("disabled");            } else {                //Maxmize                var originalSize = [$(fw).width(), $(fw).height(), $(fw).offset().left, $(fw).offset().top];                $(fw).attr("orgsize", encodeURIComponent(JSON.stringify(originalSize)));                $(fw).css({                    width: "100%",                    height: "calc(100% - 36px)",                    left: "0px",                    top: "0px"                });                $(fw).attr("max", "true");                $(fw).find(".maxToogleButton").attr('src', "img/system/restore.svg");                $(fw).find(".dockright").addClass("disabled");                $(fw).find(".dockleft").addClass("disabled");            }        }        function closeFloatWindow(object, event=null) {            if (event != null){                if (event.type == "mousedown" && event.which != 1) {                    //Ignore right mouse down on close buttons                    return;                }                event.preventDefault();                event.stopImmediatePropagation();            }                     if ($(object).is("img")) {                object = $(object).panret();            }            var fw = $(object).parent().parent().parent();            var contentWindow = $(fw).find("iframe")[0].contentWindow;            try {                if (contentWindow.ao_module_close === undefined) {                    //This module do not use ao_module wrapper. Close it directly.                    closeFwProcess($(fw).attr("windowId"));                } else {                    //Pass the closing events to the window itself                    contentWindow.ao_module_close();                }            } catch (ex) {                //Problems of closing floatWindow. Force closing.                closeFwProcess($(fw).attr("windowId"));            }            //Find the btn object that contains the windowID            var closingWindowID = $(fw).attr("windowId");            $("#stackedWindowList").hide();            resizeAllFloatWindowButtons();            hideAllContextMenus();        }        function findFloatWindowButtonWithID(windowID) {            var targetButtonObject;            $(".floatWindowButton").each(function() {                var originalIDlist = JSON.parse(decodeURIComponent($(this).attr('windowIDGroup')));                originalIDlist = originalIDlist.map(String);                if (originalIDlist.includes(windowID)) {                    targetButtonObject = $(this);                }            });            return targetButtonObject;        }        function closeFwProcess(windowID) {            //Close the floatwindow process            $(".floatWindow").each(function() {                if ($(this).attr("windowId") == windowID) {                    $(this).remove();                }            });            //Remove the button from menu as well            var targetTab = findFloatWindowButtonWithID(windowID);            var originalIDlist = JSON.parse(decodeURIComponent($(targetTab).attr('windowIDGroup')));            originalIDlist = originalIDlist.map(String);            if (originalIDlist.length > 1) {                //There are more than 1 floatWindow in this tab.                var newIDList = [];                for (var i = 0; i < originalIDlist.length; i++) {                    if (originalIDlist[i] != windowID) {                        newIDList.push(originalIDlist[i]);                    }                }                newIDListAttr = encodeURIComponent(JSON.stringify(newIDList));                //console.log("Newlist",newIDList);                $(targetTab).attr("windowIDGroup", newIDListAttr);            } else {                //This is the only floatWindow in this tab. Remove the tab itself.                $(targetTab).remove();            }        }        function PinFloatWindowToTopMostMode(object){            if ($(".floatwindow.topmost").length >= 100){                //Cannot add more topmost fw                console.log("Max number of top most floatWindow reached")                return            }            //Move the current fw to top, its z index is now 101            MoveFloatWindowToTop(object);            var windowID = $(object).attr("windowId");            console.log("[Desktop] Pinning window ID: " + windowID)            //Move this to fixed layer position            $(object).addClass("topmost");            $(object).css("z-index", 501);        }        function UnpinFloatWindowFromTopMostMode(object){            $(object).removeClass("topmost");            if (focusedWindow == object){                focusedWindow = undefined;                $(object).css("z-index", 1);            }                        MoveFloatWindowToTop(object);        }        function FloatWindowIsTopped(object){            if ($(object).attr("windowId") == $(focusedWindow).attr("windowId")) {                //Top Window                return true;            }            return false;        }        function MoveFloatWindowToTop(object) {            var windowID = $(object).attr("windowId");            var windowZindex = $(object).css("z-index");            //Shift down all floatWindows that has z-index higher than this window by 2            if (windowID == $(focusedWindow).attr("windowId")) {                //This window already at the top                return;            }            if ($(focusedWindow).hasClass("topmost") && $(object).hasClass("topmost")){                //The previous focused windows is topmost. Move it to layer 500                $(focusedWindow).css("z-index", 500);                $(".floatWindow.topmost").each(function(){                    var thisWindowZIndex = $(this).css("z-index");                    if (parseInt(thisWindowZIndex) > parseInt(windowZindex)) {                        if ($(this).attr("windowId") != windowID) {                            $(this).css("z-index", thisWindowZIndex - 1);                        }                    }                });            }else if ($(focusedWindow).hasClass("topmost") && !$(object).hasClass("topmost")){                //The previous focused windows is topmost but the current one is not.                //No need to move the top most windows but need to move every 101 windows to 100                $(".floatWindow:not(.topmost)").each(function(){                    if ($(this).css("z-index") == 101){                        $(this).css("z-index", 100);                    }                });                        }else if (!$(focusedWindow).hasClass("topmost") && $(object).hasClass("topmost")){                //The previous focused window is normal but now focusing on top most windows.                $(".floatWindow.topmost").each(function(){                    if ($(this).css("z-index") == 501){                        $(this).css("z-index", 500);                    }                });                            }else{                //The previous focused windows is normal windows. Move it to 100                $(focusedWindow).css("z-index", 100);                //Shift all the other windows down                $(".floatWindow").each(function() {                    if ($(this).hasClass("topmost")){                        return;                    }                    var thisWindowZIndex = $(this).css("z-index");                    if (parseInt(thisWindowZIndex) > parseInt(windowZindex)) {                        if ($(this).attr("windowId") != windowID) {                            $(this).css("z-index", thisWindowZIndex - 1);                            //console.log($(this).attr("windowId"), $(this).css("z-index"));                        }                    }                });            }            if ($(object).hasClass("topmost")){                //The new windows is a topmost window                $(object).css("z-index", 501);            }else{                $(object).css("z-index", 101);            }                                   focusedWindow = $(object);                        //Check if this div is hidden. If yes, fade it in.            if ($(object).is(":hidden")) {                $(object).fadeIn(100);            }            //Focus on the top most floatWindow            var iframe = focusedWindow.find("iframe")[0];            iframe.contentWindow.focus();        }        function newFloatWindow(config, callback=undefined) {            //Check if the number of floatWindow already reaching its maxmium            if ($(".floatWindow").length > maxWindowCount){                console.log("Max number of floatWindow reached.");                return;            }            //Generate new floatwindow startup config from object            var url = defaultOrKey(config, "about:blank", "url");            var uuid = defaultOrKey(config, (new Date()).getTime(), "uid");            var width = defaultOrKey(config, 854, "width");            var height = defaultOrKey(config, 480, "height");            var moduleIcon = defaultOrKey(config, "img/system/favicon.png", "appicon");            var title = defaultOrKey(config, "New floatWindow", "title");            var left = defaultOrKey(config, 100, "left");            var top = defaultOrKey(config, 100, "top");            var parentWindowID = defaultOrKey(config, "", "parent");            var callbackFunctionName = defaultOrKey(config, "", "callback");            var bgcolor = defaultOrKey(config, "", "background-color");            //Encode function name            callbackFunctionName = encodeURIComponent(callbackFunctionName);            //Validate paramters            if (width > window.innerWidth) {                width = window.innerWidth;            }            if (height > window.innerHeight) {                height = window.innerHeight;            }            if (left + width > window.innerWidth) {                left = 0;            }            if (top + height > window.innerHeight) {                top = 0;            }            //Check if the location already cotain any window            while (floatWindowLocationDuplicated(left, top)) {                left += 30;                top += 30;            }            //Check if the opening require a overwrite on background color            var backgroundStyle = "";            if (bgcolor !== ""){                backgroundStyle = `background-color: ${bgcolor};`;            }            //Check if the theme color is applied. If yes, generate the floatWindow with overwritten theme color            var overWriteThemeColor = "";            var overWriteIframeWrapperBorderStyle = "";            if (desktopThemeColor != ""){                var overWriteBackgroundColor = hexToRgbA(desktopThemeColor, 0.25);                overWriteThemeColor = `background-color: ${overWriteBackgroundColor}`;                overWriteIframeWrapperBorderStyle = `border-left: 3px solid ${overWriteBackgroundColor};                    border-right: 3px solid ${overWriteBackgroundColor};                    border-bottom: 3px solid ${overWriteBackgroundColor};                    backdrop-filter: blur(5px);`            }            //Updates 2022-06-24: Added touch screen docking buttons            let dockButtons = `<div class="buttons dockleft">                <img src="img/system/dleft.svg"></img>            </div>            <div class="buttons dockright">                <img src="img/system/dright.svg"></img>            </div>`;            if (!isTouchScreen){                dockButtons = "";            }            //Append the floatWindow into the body            $("body").append(`<div class="floatWindow" windowId="${uuid}" parent="${parentWindowID}" callback="${callbackFunctionName}" style="z-index:0; width:${width}px; height:${height}px; left:${left}px; top:${top}px;${backgroundStyle}">                <div class="controls fwdragger themeColorSolid" style="${overWriteThemeColor}">                    <img class="moduleicon" src="${moduleIcon}"></img>                    <div class="title">${title}</div>                    <div class="fwcontrol">                        ${dockButtons}                        <div class="buttons mintoggle" style="margin-left: 1em;">                            <img src="img/system/min.svg"></img>                        </div>                        <div class="buttons maxtoggle">                            <img class="maxToogleButton" src="img/system/max.svg"></img>                        </div>                        <div class="buttons closetoggle close">                            <img src="img/system/close.svg"></img>                        </div>                    </div>                </div>                <div class="iframewrapper" style="${overWriteIframeWrapperBorderStyle}">                    <iframe src="${url}" allowfullscreen="true"></iframe>                    <div class="iframecover"></div>                </div>            </div>`);            var newWindowObject = getFloatWindowByID(uuid);            //console.log(newWindowObject);            MoveFloatWindowToTop(newWindowObject);            //Append window to taskbar            var groupInfo = url.split("/");            var group = "";            if (groupInfo.length == 1) {                group = groupInfo[0];            } else {                groupInfo.pop();                group = groupInfo.join("/");            }            //File system windows require special grouping based on their filename            if (url.includes("SystemAO/file_system/")){                group = url.split("/").pop().split(".").join("_");            }else if (url.includes("SystemAO/utilities/")){                group = url.split("/").pop().split(".").join("_");                if (group.includes("#")){                    group = group.split("#")[0];                }            }            //Check if the group already exists.            var groupExists = false;            var targetGroupingTab;            $(".floatWindowButton").each(function() {                if ($(this).attr("group") == group) {                    groupExists = true;                    targetGroupingTab = $(this);                }            });            //Check if the group is System Explorer and held special treatment if yes            if (group.split("/").shift() == "SystemAO") {                if (url.includes("file_explorer.html") && groupExists) {                    //File Manager. Group them                    group = "file_explorer";                }else if (url.includes("utilities") && groupExists){                    //Allow grouping                } else {                    //Do not group anything from SystemAO other than file explorer                    groupExists = false;                }            }            if (groupExists == false) {                //Append the item to taskbar                var windowIDGroup = encodeURIComponent(JSON.stringify([uuid]));                var floatWindowButtonObject = ` <div class="item clickable floatWindowButton onscreen" group="${group}" windowIDGroup="${windowIDGroup}">                                                        <img class="floatWindowAppIcon" src="${moduleIcon}"></img>                                                        <p class="floatWindowTitle">${title}</p>                                                    </div>`;                $(".navimenu").append(floatWindowButtonObject);            } else {                //Group already exists. Add tab into that group.                var originalIDlist = JSON.parse(decodeURIComponent($(targetGroupingTab).attr('windowIDGroup')));                originalIDlist.push(uuid);                //Encode and put the group list back to the object                var newIDList = encodeURIComponent(JSON.stringify(originalIDlist));                $(targetGroupingTab).attr("windowIDGroup", newIDList);            }            hookFloatWindowEvents();            resizeAllFloatWindowButtons();            if (callback !== undefined){                callback(uuid);            }        }        function resizeAllFloatWindowButtons() {            var fwbTotalWidth = $(".floatWindowButton").length * 200;            if (fwbTotalWidth > window.innerWidth * 0.7) {                $(".floatWindowButton").addClass("hideText");            } else {                $(".floatWindowButton").removeClass("hideText");            }        }        function floatWindowLocationDuplicated(left, top) {            var duplicated = false;            $(".floatWindow").each(function() {                if ($(this).offset().left == left && $(this).offset().top == top) {                    duplicated = true;                }            });            return duplicated;        }        function defaultOrKey(object, defaultvalue, key) {            if (object[key] !== undefined) {                return object[key];            }            return defaultvalue;        }        function getFloatWindowByID(id) {            var targetWindow = undefined;            $(".floatWindow").each(function() {                if ($(this).attr("windowId") == id) {                    targetWindow = $(this);                }            });            return targetWindow;        }                function getFloatWindowIconByID(id) {            var targetIconURL = "img/system/favicon.png";            $(".floatWindow").each(function() {                if ($(this).attr("windowId") == id) {                    //This window ID matched the target fw                    targetIconURL = $(this).find(".moduleicon").attr('src');                }            });            return targetIconURL;        }        function getFloatWindowTitleByID(id) {            var title = "";            $(".floatWindow").each(function() {                if ($(this).attr("windowId") == id) {                    //This window ID matched the target fw                    title = $(this).find(".title").text();                }            });            return title;        }        function setFloatWindowResizePolicy(targetFWId, resizble = true) {            var targetfw = getFloatWindowByID(targetFWId);            if (resizble) {                $(targetfw).find(".maxtoggle").show();                if (isTouchScreen){                    $(targetfw).find(".dockleft").show();                    $(targetfw).find(".dockright").show();                }                $(targetfw).removeClass("fixedsize");            } else {                $(targetfw).find(".maxtoggle").hide();                if (isTouchScreen){                    $(targetfw).find(".dockleft").hide();                    $(targetfw).find(".dockright").hide();                }                $(targetfw).addClass("fixedsize");            }        }        function setFloatWindowSize(targetFWId, newWidth, newHeight) {            var targetfw = getFloatWindowByID(targetFWId);            $(targetfw).css({                height: newHeight,                width: newWidth            });        }        function setFloatWindowTitle(targetFWId, newTitle) {            var targetfw = getFloatWindowByID(targetFWId);            $(targetfw).find(".title").text(newTitle);                    }        function openFileWithModule(moduleLaunchInfo, openFileList) {            var url = moduleLaunchInfo["StartDir"];            var size = [undefined, undefined];            var title = moduleLaunchInfo["Name"];            var icon = "img/system/favicon.png";            if (moduleLaunchInfo["IconPath"] != "") {                icon = moduleLaunchInfo["IconPath"];            }            //Use floatWindow if exists            if (moduleLaunchInfo["SupportFW"] == true && moduleLaunchInfo["LaunchFWDir"] != "") {                url = moduleLaunchInfo["LaunchFWDir"];                if (moduleLaunchInfo["InitFWSize"] !== null) {                    size = moduleLaunchInfo["InitFWSize"]                }            }            //Use embedded mode if exists            if (moduleLaunchInfo["SupportEmb"] == true && moduleLaunchInfo["LaunchEmb"] != "") {                url = moduleLaunchInfo["LaunchEmb"];                if (moduleLaunchInfo["InitEmbSize"] !== null) {                    size = moduleLaunchInfo["InitEmbSize"]                }            }            var openParamter = encodeURIComponent(JSON.stringify(openFileList));            //Add launch files info and launch floatWindow            parent.newFloatWindow({                url: url + "#" + openParamter,                width: size[0],                height: size[1],                appicon: icon,                title: title            });        }        //====================== DESKTOP THEME RELATED FUNCTIONS =====================        //Initiate desktop theme list and user current theme        function initDesktopTheme() {            //Update 1 April 2021: Check if the user customize the desktop with the given path            $.get("system/desktop/theme", function(data) {                //Return a list of theme stored on the system                desktopThemeList = data;                $.get("system/desktop/theme?get=true", function(data) {                    //Get the user theme settings                    changeDesktopTheme(data);                });            });        }        function setDesktopTheme(themeName) {            $.get("system/desktop/theme?set=" + themeName, function(data) {                //Get the user theme settings                changeDesktopTheme(themeName);                if (data.includes("Error")) {                    console.log(data);                }            });        }        //Actiave background cross fade changing animation        function initBackgroundSwitchingAnimation() {            if (localStorage.getItem("ao/desktop/backgroundInterval") !== null && !isNaN(parseInt(localStorage.getItem("ao/desktop/backgroundInterval")))){                //Localstorage has interval setting that is not NaN                backgroundCrossfadeInterval = parseInt(localStorage.getItem("ao/desktop/backgroundInterval")) * 1000;            }            if (backgroundIntervalCounter != undefined){                clearInterval(backgroundIntervalCounter);            }            backgroundIntervalCounter = setInterval(function() {                $("body").css("background-image", "none").css({                    'background-color': '#000000'                });                $(".showBackground").removeClass("showBackground");                $($(".backgroundFrame")[nextSlideshowIndex]).addClass("showBackground");                nextSlideshowIndex++;                if (nextSlideshowIndex > currentBackgroundList.length - 1) {                    nextSlideshowIndex = 0;                }            }, backgroundCrossfadeInterval);        }        //Function for changing the desktop theme        function changeDesktopTheme(targetThemeName) {            currentUserTheme = targetThemeName;            if (currentUserTheme.includes(":/") == false){                //This is default theme pack name                for (var i = 0; i < desktopThemeList.length; i++) {                    var thisTheme = desktopThemeList[i];                    if (thisTheme["Theme"] == targetThemeName) {                        //Use this config as the target theme                        currentBackgroundList = thisTheme["Bglist"];                        break;                    }                }                //Initiate the background image.                $("#bgwrapper").html("");                for (var i = 0; i < currentBackgroundList.length; i++) {                    var id = "dbg" + i;                    var thisImage = "img/desktop/bg/" + currentUserTheme + "/" + currentBackgroundList[i];                    $("#bgwrapper").append('<img id="' + id + '" rel="preload" draggable="false" onclick="this.focus();" style="background-image:url(\'' + thisImage + '\');" class="backgroundFrame"></img>');                }                setTimeout(function() {                    $("#dbg0").addClass("showBackground");                }, 300);                if (currentBackgroundList.length == 1) {                    //There are only 1 background in this pack. Make the next slice be 0 as well.                    nextSlideshowIndex = 0;                }else if (currentBackgroundList.length == 0){                    //Background no longer exists. Change to default                    changeDesktopTheme("default");                } else {                    nextSlideshowIndex = 1;                }            }else{                //This is user defined photo file                $.get("system/desktop/theme?load=" + targetThemeName, function(data){                    if (data.error !== undefined){                        //The folder is gone. Use default instead                        console.log(data.error);                        changeDesktopTheme("default");                    }else{                        //OK! Load it                        currentBackgroundList = data;                             $("#bgwrapper").html("");                        for (var i = 0; i < currentBackgroundList.length; i++) {                            var id = "dbg" + i;                            var thisImage = "media/?file=" + currentBackgroundList[i];                            $("#bgwrapper").append('<img id="' + id + '" rel="preload" draggable="false" style="background-image:url(\'' + thisImage + '\');" class="backgroundFrame"></img>');                        }                        setTimeout(function() {                            $("#dbg0").addClass("showBackground");                        }, 300);                        if (currentBackgroundList.length == 1) {                            //There are only 1 background in this pack. Make the next slice be 0 as well.                            nextSlideshowIndex = 0;                        }else if (currentBackgroundList.length == 0){                            //Background no longer exists. Change to default                            changeDesktopTheme("default");                        } else {                            nextSlideshowIndex = 1;                        }                    }                });                           }        }        $("#bgwrapper").on("click", function(evt) {            evt.preventDefault();        });        //================== DESKTOP FILE LOCATION FUNCTIONS ====================        function initDesktopFiles(optionObject = {}, callback = undefined) {            $.get("system/desktop/listDesktop", function(data) {                if (data.error !== undefined){                    console.log("[Desktop] Unable to list desktop files: ", data.error);                    if (callback !== undefined) {                        callback(false);                    }                    return;                }                //Prase optionObject                var noflash = false;                if (typeof optionObject.noflash !== "undefined"){                    noflash = optionObject.noflash;                }                if (noflash){                    //Only clean out those object that not exists in the new filelist                    var existsingFilepaths = [];                    if (data != null){                        for (var i =0; i < data.length; i++){                            existsingFilepaths.push(data[i].Filepath);                        }                    }else{                        //Nothing on desktop                    }                                       //console.log(existsingFilepaths);                    //If the launchIcon path is not in the latest list, remove it from desktop                    $(".launchIcon").each(function(){                        if (existsingFilepaths.includes($(this).attr("filepath")) == false){                           $(this).remove();                        }                    });                }else{                    //Cleanup all previous icons                    $("#iconwrapper").children().each(function(){                        if ($(this).hasClass("launchIcon") && $(this).attr("type") == "dummy"){                            //Special kind of launchIcon. Skip this                            return;                        }                        $(this).remove();                    });                }                //Allocate new items location                var iheight = 106;                var iwidth = 70;                var padding = 16;                if (desktopIconSize == "small") {                    iheight = 82;                    iwidth = 50;                } else if (desktopIconSize == "medium") {                    iheight = 106;                    iwidth = 70;                } else if (desktopIconSize == "big") {                    iheight = 124;                    iwidth = 84;                }                iconSize = [iwidth, iheight];                var screenHeight = window.innerHeight;                var screenWidth = window.innerWidth;                var vc = Math.floor((screenHeight - 20 - padding) / iheight);                var hc = Math.floor((screenWidth - padding) / iwidth);                var slots = []; //A 2D array for storing relative to absolute locations                for (var j = 0; j < hc; j++) {                    var thisLocationList = [];                    for (var i = 0; i < vc; i++) {                        var thisLocation = [j * iwidth + padding, i * iheight + padding];                        thisLocationList.push(thisLocation);                    }                    slots.push(thisLocationList);                }                //Store the root position (0,0) in rootPosition                let rootPosition = JSON.parse(JSON.stringify(slots[0][0]));                desktopGrids = JSON.parse(JSON.stringify(slots));                //Assign items to desktop                var unallocatedFiles = [];                let remainingSlots = JSON.parse(JSON.stringify(slots));                desktopFileList = [];                if (data === null){                    //No files on desktop                    return;                }                for (var i = 0; i < data.length; i++) {                    var thisFile = data[i];                    desktopFileList.push(JSON.parse(JSON.stringify(thisFile.Filename)));                    //Get icon from the icon list                    var location = [thisFile.IconX, thisFile.IconY];                    if (location[0] == -1 && location[1] == -1) {                        //This file is not located. Push it into unallocatedFileList                        unallocatedFiles.push(thisFile);                    } else if (location[0] >= slots.length || location[1] >= slots[0].length) {                        //This file is outside of the screen area. Set to be be unallocatedFiles as well                        unallocatedFiles.push(thisFile);                    } else {                        //This file is already located. Push it location into occupiedSlots                        //var screenX = location[0] * iwidth + padding/2;                        //var screenY = location[1] * iheight + padding/2;                        var screenLocation = slots[location[0]][location[1]];                        //Remove this object from remaining slots                        remainingSlots[location[0]][location[1]] = undefined;                        //console.log(thisFile, screenLocation[0], screenLocation[1], iheight, iwidth);                        appendIconAtLocation(thisFile, screenLocation[0], screenLocation[1], iheight, iwidth, noflash);                    }                }                //Foreach remaining files, assign a location for it.                var walk = [slots.length, slots[0].length];                var current = [0, 0];                for (var i = 0; i < unallocatedFiles.length; i++) {                    var thisFile = unallocatedFiles[i];                    try{                        while (typeof(remainingSlots[current[0]][current[1]]) == "undefined") {                            //This slot is not usabled. Next slot.                            current[1] += 1;                            if (current[1] >= walk[1]) {                                current[1] = 0;                                current[0] += 1;                            }                            if (typeof(remainingSlots[current[0]]) == "undefined"){                                //Not enough space to fit the item. Move it to 0 0 instead                                current = [-1,-1];                                console.log(current);                                break;                            }                                                    }                    }catch{                        //Something went wrong while assigning positions. Set at root location                        current = [-1,-1];                    }                                        //Append the icon to screen                    if (current[0] == -1 && current[1] == -1){                        //Screen overflow. Stack the file at (0,0)                        screenLocation = [rootPosition[0], rootPosition[1]];                        console.log(screenLocation);                    }else{                        screenLocation = remainingSlots[current[0]][current[1]];                        remainingSlots[current[0]][current[1]] = undefined;                    }                                        appendIconAtLocation(thisFile, screenLocation[0], screenLocation[1], iheight, iwidth, noflash);                    //Save the icon location to server                    $.ajax({                        url: "system/desktop/files",                        method: "POST",                        data: {"set": thisFile.Filename, "x": current[0], "y": current[1]},                        success: function(data) {                            if (data.error !== undefined) {                                console.log(data.error);                            }                        }                    });                                    }                //Update the desktop hash to prevent the auto refresh by hash                getDesktopHash(function(hash){                    desktopFileHash = hash;                });                if (callback !== undefined) {                    //console.log(callback);                    callback(true);                }            });        }        //Handle desktop file multi selection and dragging        $("#bgwrapper").on("mousedown", function(evt) {            initMultiSelection(evt);        });        $("#bgwrapper").on("touchstart", function(evt) {            initMultiSelection(evt);        });        $("body").on("mouseup", function(evt) {            mainWindowMouseup(evt);        });        $("body").on("touchend", function(evt) {            mainWindowMouseup(evt);        });        $("#selectionPanel").on("mouseup", function(event) {        });        function mainWindowMouseup(event) {            if (event.pageX == multiSelectionStartPoint[0] && event.pageY == multiSelectionStartPoint[1]) {                //Pressdown and up at the same location                $(".launchIconWrapper.selected").removeClass("selected");                endMultiSelection(event);            } else {                //Press down and up at different location                endMultiSelection(event);            }            if (resizingWindow){                //Resizing floatWindow out of the window bound (aka someone don't know how to resize a window correctly)                resizingWindow = false;                resizingEdgeID = 0;                $("#fwdragpanel").hide();                $("#tfwdragpanel").hide();                $('.floatWindow.topmost').css("pointer-events", "auto");                $('.floatWindow.topmost').css("opacity", 1);                $(resizingWindowTarget).find(".iframecover").hide();                $(resizingWindowTarget).find(".iframewrapper").css('cursor', '');            }                    }        function initMultiSelection(event) {            event.preventDefault();            multiSelecting = true;            hideAllContextMenus();            $("#selectionPanel").css({                left: event.pageX,                top: event.pageY,                width: 0,                height: 0            });            $("#selectionPanel").show();            multiSelectionStartPoint = [event.pageX, event.pageY];        }        function movingMultiSelectionArea(event) {            event.preventDefault();            var sx = multiSelectionStartPoint[0];            var sy = multiSelectionStartPoint[1];            var ex = event.pageX;            var ey = event.pageY;            var newleft = sx;            if (ex < sx) {                newleft = ex;            }            var newtop = sy;            if (ey < sy) {                newtop = ey;            }            var newWidth = Math.abs(sx - ex);            var newHeight = Math.abs(sy - ey);            $("#selectionPanel").css({                left: newleft,                top: newtop,                width: newWidth,                height: newHeight            });            //Select all the launch icon selected            selectAllLaunchIconInRange(newleft, newleft + newWidth, newtop, newtop + newHeight);        }        function endMultiSelection(event) {            event.preventDefault();            multiSelecting = false;            multiSelectionStartPoint = [-1, -1];            $("#selectionPanel").hide();        }        function selectAllLaunchIconInRange(minX, maxX, minY, maxY) {            //Select launch icons from its center point            var xOffset = iconSize[0] / 2;            var yOffset = iconSize[1] / 2;            $(".launchIconWrapper.selected").removeClass("selected");            $(".launchIcon").each(function() {                //Calculate center point for this icon                var thisX = $(this).offset().left + xOffset;                var thisY = $(this).offset().top + yOffset;                if (thisX > minX && thisX < maxX) {                    if (thisY > minY && thisY < maxY) {                        $(this).find(".launchIconWrapper").addClass("selected");                    }                }            });        }        function redrawDesktopGrids() {            var iheight = 106;            var iwidth = 70;            var padding = 16;            if (desktopIconSize == "small") {                iheight = 82;                iwidth = 50;            } else if (desktopIconSize == "medium") {                iheight = 106;                iwidth = 70;            } else if (desktopIconSize == "big") {                iheight = 124;                iwidth = 84;            }            iconSize = [iwidth, iheight];            var screenHeight = window.innerHeight;            var screenWidth = window.innerWidth;            var vc = Math.floor((screenHeight - 20 - padding) / iheight);            var hc = Math.floor((screenWidth - padding) / iwidth);            var slots = []; //A 2D array for storing relative to absolute locations            for (var j = 0; j < hc; j++) {                var thisLocationList = [];                for (var i = 0; i < vc; i++) {                    var thisLocation = [j * iwidth + padding, i * iheight + padding];                    thisLocationList.push(thisLocation);                }                slots.push(thisLocationList);            }            desktopGrids = JSON.parse(JSON.stringify(slots));        }        function getTextPixelWidth(measureText){            let canvas = document.getElementById('textWidthCanvas');            let ctx = canvas.getContext('2d');            let text = ctx.measureText(measureText);            let estimatedFilenameSize = text.width;            if (desktopIconSize == "small"){                estimatedFilenameSize = estimatedFilenameSize * 0.8679245283018868;            }else if (desktopIconSize == "big"){                estimatedFilenameSize = estimatedFilenameSize * 1.509433962264151;            }else{                estimatedFilenameSize = estimatedFilenameSize * 1.2452830188679245;            }            return estimatedFilenameSize;        }        function appendIconAtLocation(filedata, screenX, screenY, iheight, iwidth, updateMode=false) {            //Get the icon from extension            var icon = ao_module_utils.getIconFromExt(filedata.Ext.substring(1, filedata.Ext.length));            var imagePath = "img/desktop/files_icon/" + desktopIconPack + "/" + icon + ".png";            //Handle special icon types here            var size = desktopIconSize;            var filename = JSON.parse(JSON.stringify(filedata.Filename));            var filepath = JSON.parse(JSON.stringify(filedata.Filepath));            var isDir = JSON.parse(JSON.stringify(filedata.IsDir));            var isEmptyDir = JSON.parse(JSON.stringify(filedata.IsEmptyDir));            var isShared = JSON.parse(JSON.stringify(filedata.IsShared));            var maxlength = 12;            var type = "file";            let shortenedName = filename;            screenX += iconOffsetXY[0];            screenY += iconOffsetXY[1];                        if (isDir) {                //Folder objects                icon = "folder outline";                if (isEmptyDir){                    imagePath = "img/desktop/system_icon/folder.png";                }else{                    imagePath = "img/desktop/system_icon/folder-with-content.png";                }                                type = "folder";            } else if (isDir == false && icon == "folder outline") {                icon = "file outline";                imagePath = "img/desktop/files_icon/" + desktopIconPack + "/file outline.png";                type = "file";            } else if (filedata.Ext == ".exe" || filedata.Ext == ".elf") {                //Executable objects                imagePath = "img/desktop/system_icon/script.png";                type = "executable";            } else if (filedata.Ext == ".shortcut") {                //Shortcut                var shortcutImage = filedata.ShortcutImage;                shortenedName = JSON.parse(JSON.stringify(filedata.ShortcutName));                imagePath = shortcutImage;                type = "shortcut";            }            //Check if it is under small text mode            if (size == "small"){                maxlength = 46;            }else if (size == "big"){                maxlength = 80;            }else{                maxlength = 66;            }                        var estimatedFilenameSize = 0;            if (type == "shortcut"){                estimatedFilenameSize = getTextPixelWidth(shortenedName);            }else{                estimatedFilenameSize = getTextPixelWidth(filename);                shortenedName = filename;                if (estimatedFilenameSize > (maxlength * 2 - 10)) {                    //This name is too long to fit inside two lines                    var newFilenameLength = getTextPixelWidth(shortenedName + "...");                    while (newFilenameLength >= (maxlength * 2 - 10)){                        shortenedName = shortenedName.substr(0, shortenedName.length - 1);                        newFilenameLength = getTextPixelWidth(shortenedName + "...");                    }                    shortenedName = shortenedName + "...";                }            }            if (estimatedFilenameSize < (maxlength * 2 - 10)  && estimatedFilenameSize > (maxlength - 5) && shortenedName.indexOf(" ") > 0){                //This is short enough to fit inside two lines and it contains space                //Try to see if there is a combination of splitting that fit inside two lines                var filenameSegments = shortenedName.split(" ");                var segEnd = 1;                var currentSegmentText = filenameSegments[0];                var currentSegmentWidth = getTextPixelWidth(currentSegmentText);                var spaceWidth = getTextPixelWidth(" ");                while(segEnd < filenameSegments.length && (currentSegmentWidth + spaceWidth)  < (maxlength - 5)){                    //When it is not the last segment && can still fit more segment into current line                    currentSegmentText = currentSegmentText + " " + filenameSegments[segEnd];                    currentSegmentWidth = getTextPixelWidth(currentSegmentText);                    segEnd++;                }                //Back trace one segment                segEnd--;                //Build the filename segmentation                var line1 = "";                var line2 = "";                for (var i = 0; i < segEnd; i++){                    line1 += filenameSegments[i] + " ";                }                for (var i = segEnd; i < filenameSegments.length; i++){                    line2 += filenameSegments[i] + " ";                }                line1 = line1.trim();                line2 = line2.trim();                if (line1 != "" && line1 != ""){                    shortenedName = line1 + `<br>` + line2;                }else if (line1 == ""){                    shortenedName = line2;                }else if (line2 == ""){                    shortenedName = line1;                }            }            var compressedFiledata = ao_module_utils.objectToAttr(filedata);            if (updateMode){                //Update the content that already exists for the same filepath object                var updateObject = undefined;                $(".launchIcon").each(function(){                    if ($(this).attr("filedata") == compressedFiledata){                        updateObject = $(this);                    }                });                if (updateObject !== undefined){                    //Check if content identical. If yes, skip rewrite                    if (updateObject.attr("filedata") == compressedFiledata){                        //Identical. Skipping                    }else{                        //Update its contents                        updateObject.attr("type", type);                        updateObject.attr("filename", filename);                        updateObject.attr("filepath", filepath);                        updateObject.attr("filedata", compressedFiledata);                        updateObject.css("width", iwidth + "px");                        updateObject.css("height", iheight + "px");                        updateObject.css("left", screenX + "px");                        updateObject.css("top", screenY + "px");                    }                }else{                    //No exists. Append to wrapper                    appendDesktopIcon($("#iconwrapper"),{                        type: type,                        filename: filename,                        filepath: filepath,                        compressedFiledata: compressedFiledata,                        iwidth: iwidth,                        iheight: iheight,                        screenX: screenX,                        screenY: screenY,                        size: size,                        imagePath: imagePath,                        shortenedName: shortenedName,                        isShared: isShared,                    });                }            }else{                //Append into the desktop                appendDesktopIcon($("#iconwrapper"),{                    type: type,                    filename: filename,                    filepath: filepath,                    compressedFiledata: compressedFiledata,                    iwidth: iwidth,                    iheight: iheight,                    screenX: screenX,                    screenY: screenY,                    size: size,                    imagePath: imagePath,                    shortenedName: shortenedName,                    isShared: isShared,                });            }                   }        /*            Main function to append desktop icon to desktop            Usage: Pass in the target (as jquery object, usually $("#iconwrapper")) and properties with the following object            properties = {                type: "",                filename: "",                filepath: "",                compressedFiledata: "",                iwidth: "",                iheight: "",                screenX: "",                screenY: "",                size: "",                imagePath: "",                shortenedName: "",            }            Where the enmty string is the value that require filling in        */        function appendDesktopIcon(target, properties){            var htmlType = "div";            if (properties.type == "file" && isChrome){                htmlType = "a";            }            var imageStyleOverride = "";            //Special type of override for files            if (properties.type == "shortcut"){                var fd = JSON.parse(decodeURIComponent(properties.compressedFiledata));                if (fd.ShortcutType == "url"){                    imageStyleOverride = `padding: 8px;`;                }            }                        var iconTextReadjustment = "";            if (isChrome){                iconTextReadjustment = "font-size: 92%;"            }                       var thisIcon = $(`<${htmlType} href="javascript:void(0);" class="launchIcon"                     type="${properties.type}"                     draggable="true"                     ondragover="allowDrop(event)"                     ondrop="drop(event)"                     ondragstart="drag(event)"                     onmousedown="iconClicked(this,event);"                     ondblclick="iconDoubleClicked(this,event);"                     ontouchstart="iconClicked(this,event); doubleTouchHandler(this, event,openViaTouch);"                    filename="${properties.filename}"                     filepath="${properties.filepath}"                     filedata="${properties.compressedFiledata}"                     style="width:${properties.iwidth}px; height:${properties.iheight}px;left:${properties.screenX}px; top:${properties.screenY}px;">                    <span class="launchIconWrapper">                        <img class="launchIconImage ${properties.size}" src="${properties.imagePath}" style="${imageStyleOverride}" draggable="false"></img>                        <p class="launchIconText ${properties.size}" style="${iconTextReadjustment}">${properties.shortenedName}</p>                    </span>                    </${htmlType}>`);            $(target).append(thisIcon);            //Updates 20 May 2021: Check if this file is shared. If yes, append the share icon            if (typeof(properties.isShared) != "undefined" && properties.isShared == true){                setFileShareIndicator(properties.filename);            }                        if (properties.type == "file" && isChrome){                console.log(isChrome);                let thisFilepath = properties.filepath;                $(thisIcon)[0].addEventListener("dragstart",function(evt){                //var filecontent = toDataUrl("media/?file=" + thisFilepath);                //var fileBase64 = window.btoa(filecontent);                var targetMime = "plain/text";                    $.ajax({                        url: "media/getMime/?file=" + encodeURIComponent(properties.filepath),                        success: function(data){                            if (data.error !== undefined){                                targetMime = "text/directory";                            }else{                                targetMime = data;                            }                        },                        async: false                    });                evt.dataTransfer.setData("DownloadURL",targetMime+":"+ properties.filename +":"+ location.protocol + "//" + location.hostname + ":" + location.port + "/media/?file=" + encodeURIComponent(properties.filepath));                //evt.dataTransfer.setData("DownloadURL","video/mp4"+":"+"test.mp4"+":"+"data:"+"video/mp4"+";base64,"+fileBase64);                },false);            }        }        //Folder description box        var timeoutId;        function attachDescriptionBoxEvents(){            $(".launchIcon").off("hover").hover(function(event) {                let modulePath = $(this).attr("filepath");                let filename = $(this).attr("filename");                let filedata = JSON.parse( decodeURIComponent($(this).attr("filedata")));                                if (!timeoutId) {                    if (renameMode == true){                        //Renaming. Do not show hover info tab                        return;                    }                    timeoutId = window.setTimeout(function() {                        let position = [currentMousePosition[0] + 10, currentMousePosition[1] + 10];                        timeoutId = null;                        console.log(filedata, position);                        $('#fileDescriptor').css('left',position[0] + "px");                        $('#fileDescriptor').css('top',position[1] + "px");                        if (filedata.IsShortcut){                            $('#fileDescriptor').html(`<p><i class="linkify icon"></i> ${filedata.ShortcutName}<br><i class="folder icon"></i> ${filedata.ShortcutPath}</p>`);                            $('#fileDescriptor').show();                        }else{                            $.ajax({                                url: "system/file_system/getProperties",                                data: {path: filedata.Filepath},                                success: function(data){                                    $('#fileDescriptor').html(`<p>${filedata.Filename}<br><i class="file outline icon"></i> ${formatBytes(data.Filesize)} (${data.MimeType})<br><i class="time icon"></i> ${data.LastModTime}</p>`);                                    if (!(data.MimeType == undefined)){                                        $('#fileDescriptor').show();                                    }                                                                    }                            })                                                    }                                                                    }, 1500);                }            },            function () {                if (timeoutId) {                    window.clearTimeout(timeoutId);                    timeoutId = null;                }else {                    $('#fileDescriptor').hide();                }            });        }        /*            Share indicator settings            This append or remove share from a particular file            Only require filename as all files here are on desktop        */        function getFileObjectByFilename(filename){            var result = null;            $(".launchIcon").each(function(){                var thisFilename = $(this).attr("filename");                if (thisFilename == filename){                    result = $(this);                }            });            return result;        }        function setFileShareIndicator(filename){            var targetFileObject = getFileObjectByFilename(filename);            if (targetFileObject == null){                return;            }            var sharedIcon = `<div class="fileShareIndicator ${desktopIconSize}">                <img src="img/desktop/system_icon/shared.png">            </div>`;            $(targetFileObject).find(".launchIconWrapper").append(sharedIcon);        }        function removeFileShareIndicator(filename){            var targetFileObject = getFileObjectByFilename(filename);            if (targetFileObject == null){                return;            }            var indicator = $(targetFileObject).find(".fileShareIndicator");            if (indicator.length > 0){                indicator.remove();            }        }        // ========================== LAUNCH ICON OPERATIONS ================        //This function start all the launchicon related events        function drag(ev) {            //If rename mode, disable drag drop            if (renameMode){                return false;            }            var target = ev.target;            if (!($(ev.target).is("div") || $(ev.target).is("a"))) {                target = $(target).parent();            }            //Parse the standard filename / filepath data            var filename = $(target).attr("filename");            var filepath = $(target).attr('filepath');            ev.dataTransfer.setData("filename", filename);            ev.dataTransfer.setData("filepath", filepath);            //Parse multifile selection filedata            var filelist = [];            if ($(".launchIconWrapper.selected").length > 0){                if (ctrlHold || $(".launchIconWrapper.selected").length > 1){                    //Include all objects selected                    $(".launchIconWrapper.selected").each(function(){                        var fd = $(this).parent().attr("filedata");                        fd = JSON.parse(decodeURIComponent(fd));                        filelist.push({                            filename: fd.Filename,                            filepath: fd.Filepath,                            hostUUID: hostInfo.DeviceUUID                        });                    });                }else{                    //Only push the one selected                    filelist.push({                        filename: filename,                        filepath: filepath,                        hostUUID: hostInfo.DeviceUUID                    });                }            }else{                //There is no selected item on desktop. Use the drag drop one                filelist.push({                    filename: filename,                    filepath: filepath                });            }                        //console.log(filelist);            ev.dataTransfer.setData("filedata", JSON.stringify(filelist));            console.log(filelist);            //Set a flag on the drag events that these files are from Desktop GUI            ev.dataTransfer.setData("desktopflag", "true");            //Record the start drop relative position of the icon object            var dx = ev.pageX - $(target).offset().left;            var dy = ev.pageY - $(target).offset().top;            startDragRelatuve = [dx, dy];            ev.stopPropagation();        }        function drop(ev) {            ev.preventDefault();            ev.stopImmediatePropagation();            var target = $(ev.target);            if (!(target.is("div") || target.is("a"))) {                target = $(target).parent();            }            if (target.hasClass("launchIconWrapper")) {                target = target.parent();            }            var thisFilepath = $(target).attr("filepath");            if (thisFilepath == ev.dataTransfer.getData("filepath")) {                //Drag and drop on the same item. Ignore it                return;            }            var sourceFilename = ev.dataTransfer.getData("filename");            var sourceFilepath = ev.dataTransfer.getData("filepath");            //To handle multiple file transfer from file explorer            var sourceFilelist = ev.dataTransfer.getData("filedata");             //To handle drag dropping URLs onto desktop            var linkObject = ev.dataTransfer.getData('text/html');            var remoteLink = ($(linkObject).find("a").length>0 || $(linkObject).is("a"))? ($(linkObject).find("a").attr("href")|| $(linkObject).attr("href")):($(linkObject).find("img").length>0?$(linkObject).find('img').attr("src"):($(linkObject).attr('src')!=""?$(linkObject).attr('src'):undefined));            //var remoteSrc = $(linkObject).find("img").length>0?$(linkObject).find('img').attr("src"):undefined; //If dragging in media (e.g. img / audio)            console.log(target)            console.log(sourceFilename);            console.log(sourceFilepath);            console.log(remoteLink);                        if (sourceFilelist !== ""){                sourceFilelist = JSON.parse(sourceFilelist);            }            //Drop opererations            if (target.attr("id") == "bgwrapper") {                if (sourceFilename == "" && sourceFilepath == "" && ev.dataTransfer.files.length > 0){                    //Drag drop from external source. Upload to desktop                    //Assign the locations for the objects                    var files = ev.dataTransfer.files;                    var gridMaxX = desktopGrids.length;                    var gridMaxY = desktopGrids[0].length;                    var targetLocation = findClosestGrid((ev.clientX), (ev.clientY), false);                    var targetGridLocation = targetLocation[1];                    var locations = [];                                       //Rewrite of the upload file target location, 2022-02-02                    //Back step the y location of drag point by 1                    targetGridLocation[1] = targetGridLocation[1] - 1;                    var nextLocation = JSON.parse(JSON.stringify(targetGridLocation));                    for (var k =0; k < files.length; k++){                        //Add 1 to the file y position                        nextLocation[1] += 1;                        if (nextLocation[1] >= gridMaxY){                            //If y overflow, move to next x lane                            nextLocation[0] += 1;                            nextLocation[1] = 0;                        }                        if (nextLocation[0] >= desktopGrids.length){                            //Desktop full. Force put to 0 0                             nextLocation[0] = 0;                            nextLocation[1] = 0;                            locations.push(JSON.parse(JSON.stringify(nextLocation)));                            continue;                        }                        //Check if this position is occupied, update next placement location if true                        console.log("Grid Location:", nextLocation[0], nextLocation[1]);                        while (getObjectFromGridLocation(nextLocation[0], nextLocation[1]) !== undefined){                            let gridLocation = getLocationFromGridIndex(nextLocation[0], nextLocation[1]);                            let newAssignmentLocation = findClostestEmptyGridLocation(gridLocation[0],gridLocation[1]);                            nextLocation = newAssignmentLocation[1];                            console.log("Not empty. Updating")                        }                        locations.push(JSON.parse(JSON.stringify(nextLocation)));                    }                    /*                    for (var k =0; k < files.length; k++){                        var thisLocation = JSON.parse(JSON.stringify(targetGridLocation));                        //Add k to y axis of the list.                        thisLocation[1] += k;                        if (thisLocation[1] >= gridMaxY){                                thisLocation[0]++;                                thisLocation[1] = thisLocation[1] % gridMaxY;                        }                        if (thisLocation[1] >= gridMaxY && thisLocation[0] >= gridMaxX){                            //Desktop full. Force put to 0 0                             thisLocation[0] = 0;                            thisLocation[1] = 0;                            break;                        }                        while (getObjectFromGridLocation(thisLocation[0], thisLocation[1]) !== undefined){                            thisLocation[1] += 1;                            if (thisLocation[1] >= gridMaxY){                                //Over the screen. Shift to the row on the right                                thisLocation[0]++;                                thisLocation[1] = 0;                            }                            if (thisLocation[1] >= gridMaxY && thisLocation[0] >= gridMaxX){                                //Desktop full. Force put to 0 0                                 thisLocation[0] = 0;                                thisLocation[1] = 0;                                break;                            }                        }                        locations.push(thisLocation)                    }                    */                    console.log(locations, ev.dataTransfer.files);                    //Register file locations                    for (var j =0; j < locations.length; j++){                        let thisFile = files[j];                        let thisFilename = files[j].name;                        let x = parseInt(locations[j][0]);                        let y = parseInt(locations[j][1]);                        let uploadIconUUID = generateUploadingIcon(thisFile.name, [x,y]);                        var refreshTimer;                        uploadFile(thisFile,function(){                            console.log("Uploader callback");                            $.ajax({                                url: "system/desktop/files",                                method: "POST",                                data: {"set": thisFilename, "x": x, "y": y},                                success: function(data) {                                    //Refresh the desktop                                    clearTimeout(refreshTimer);                                    refreshTimer = setTimeout(function(){                                        refresh(undefined, false);                                    }, 500)                                                                    }                            });                        }, uploadIconUUID);                                            }                }else if (sourceFilelist.length > 0 && Array.isArray(sourceFilelist)){                    //Drag drop multiple files from desktop or file explorer to desktop                    var desktopFlag = ev.dataTransfer.getData("desktopflag");                     if (desktopFlag == "" || desktopFlag === undefined || desktopFlag == null){                        //This is a file drag drop from not desktop to desktop                        var filelist = ev.dataTransfer.getData("filedata");                        if (filelist != ""){                            filelist = JSON.parse(filelist);                            if (filelist.length == 0){                                return                            }                            //Get the position for this drop events and arrange grid locations                            var gridPosition = gridPositionAllocate(ev.clientX, ev.clientY, filelist.length);                            console.log(gridPosition)                            //Check if source is also from user:/                            var srcVroot = filelist[0].filepath.split(":/").shift();                            var mode = "copy"                            var title = "Copying "                            if (srcVroot == "user"){                                //Move                                mode = "move"                                title = "Moving "                            }                            var filepathList = [];                            filelist.forEach(file => {                                filepathList.push(file.filepath)                            });                            //Start the file operation dialog                            var oprConfig = {                                opr: mode,                                src: filepathList,                                dest: "user:/Desktop/",                                overwriteMode: "ask"                            }                            var configHash = encodeURIComponent(JSON.stringify(oprConfig));                            //Genreate window title                            title = title + filepathList.length;                            if (filepathList.length > 1){                                title += " files";                            }else{                                title += " file";                            }                            newFloatWindow({                                url: "SystemAO/file_system/file_operation.html#" + configHash,                                width: 400,                                height: 220,                                appicon: "SystemAO/file_system/img/selector.png",                                title: title                            });                        }                                            }else{                        //This is a file drag event from desktop, but more than one files.                        //Pin the final location for the drag drop object                        var sourceObject = getObjectFromPath(sourceFilepath);                        var dx = startDragRelatuve[0];                        var dy = startDragRelatuve[1];                        var targetLocation = findClosestGrid((ev.clientX - dx), (ev.clientY - dy));                        var closestLocation = targetLocation[0];                        var duplicateObject = getObjectFromLocation(closestLocation[0]  + iconOffsetXY[0], closestLocation[1]  + iconOffsetXY[1]);                        if (duplicateObject !== undefined) {                            //There are already object there. Do nothing                            console.log("Drop location duplicated!")                            return;                        }                        //Get other objects that is not the one drag dropped                        var iconOffset = {};                        for (var i =0; i < sourceFilelist.length; i++){                            var thisFile = sourceFilelist[i];                            if (thisFile.filepath != sourceFilepath){                                //Calculate the x y offset of this icon to the drag drop one                                var thisIconObject = getObjectFromPath(thisFile.filepath);                                iconOffset[thisFile.filepath] = {                                    dx: $(sourceObject).offset().left - $(thisIconObject).offset().left,                                    dy: $(sourceObject).offset().top - $(thisIconObject).offset().top                                }                                //console.log(thisFile.filename, iconOffset[thisFile.filepath]);                            }                        }                        //Move the drag drop object to the desiged location                        $(sourceObject).css({                            left: closestLocation[0] + iconOffsetXY[0],                            top: closestLocation[1] + iconOffsetXY[1]                        });                        //Save the drag item location                        $.ajax({                            url: "system/desktop/files",                            method: "POST",                            data: {"set": sourceFilename, "x": targetLocation[1][0], "y": targetLocation[1][1]},                            success: function(data) {                                //console.log(data);                            }                        });                        //Move all the relative files to the main object                        var relocatePendingObjects = [];                        for (const [filepath, offset] of Object.entries(iconOffset)) {                            let thisIconObject = getObjectFromPath(filepath);                            let caluclatedLocation = [$(sourceObject).offset().left - offset.dx, $(sourceObject).offset().top - offset.dy];                            let finalIconLocation = findClosestGrid(caluclatedLocation[0], caluclatedLocation[1]);                                                    //Move this icon to designed location                            $(thisIconObject).css({                                left: finalIconLocation[0][0] + iconOffsetXY[0],                                top: finalIconLocation[0][1] + iconOffsetXY[1]                            });                            let thisIconFileData = JSON.parse(decodeURIComponent($(thisIconObject).attr("filedata")));                                                        //Record this in database                            $.ajax({                                url: "system/desktop/files",                                method: "POST",                                data: {"set": thisIconFileData.Filename, "x": finalIconLocation[1][0], "y": finalIconLocation[1][1]},                                success: function(data) {                                    //console.log(data);                                }                            });                                                    }                        //Get duplication objects                        for (const [filepath, offset] of Object.entries(iconOffset)) {                            let thisIconObject = getObjectFromPath(filepath);                            //Check for duplication                            var iconLocation = [$(thisIconObject).offset().left, $(thisIconObject).offset().top];                            $(".launchIcon").each(function(){                                if ($(this).offset().left == iconLocation[0] && $(this).offset().top == iconLocation[1]){                                    //This icon is at the target icon location                                    if ($(this).attr("filepath") != filepath){                                        relocatePendingObjects.push($(this));                                    }                                }                            });                        }                        //Relocate objects that is in the way of moving                        for (var i = 0; i < relocatePendingObjects.length; i++){                            var thisObject = relocatePendingObjects[i];                            console.log(thisObject);                            var thisX = $(thisObject).offset().left;                            var thisY = $(thisObject).offset().top;                            var nextEmptyGrid = findClostestEmptyGridLocation(thisX, thisY);                                                        //Move this file to the next empty grid location                            $(thisObject).css({                                left: nextEmptyGrid[0][0] + iconOffsetXY[0],                                top: nextEmptyGrid[0][1] + iconOffsetXY[1]                            });                            //Save move record to db                            let thisIconFileData = JSON.parse(decodeURIComponent($(thisObject).attr("filedata")));                            $.ajax({                                url: "system/desktop/files",                                method: "POST",                                data: {"set": thisIconFileData.Filename, "x": nextEmptyGrid[1][0], "y": nextEmptyGrid[1][1]},                                success: function(data) {                                    //console.log(data);                                }                            });                        }                    }                                    }else{                    //Dropping a file onto other place on desktop                    var sourceObject = getObjectFromPath(sourceFilepath);                    var dx = startDragRelatuve[0];                    var dy = startDragRelatuve[1];                    var targetLocation = findClosestGrid((ev.clientX - dx), (ev.clientY - dy));                    var closestLocation = targetLocation[0];                    //Check if there are objects already at that location                    var duplicateObject = getObjectFromLocation(closestLocation[0], closestLocation[1]);                    if (duplicateObject !== undefined) {                        //There are already object there. Do nothing                        console.log("Drop location duplicated!")                        return;                    }                    var closestGridIndex = targetLocation[1];                    $(sourceObject).css({                        left: closestLocation[0] + iconOffsetXY[0],                        top: closestLocation[1] + iconOffsetXY[1]                    });                    $.ajax({                        url: "system/desktop/files",                        method: "POST",                        data: {"set": sourceFilename, "x": closestGridIndex[0], "y": closestGridIndex[1]},                        success: function(data) {                            //console.log(data);                        }                    });                }            } else if (target.attr("type") == "folder") {                //Move this file or folder into the target folder                var moveSources = [sourceFilepath];                if ($(".launchIconWrapper.selected").length > 1){                    //Multi move operations                    moveSources = [];                    $(".launchIconWrapper.selected").each(function(){                        var thisFileData = $(this).parent().attr("filedata");                        thisFileData = JSON.parse(decodeURIComponent(thisFileData));                        moveSources.push(thisFileData.Filepath);                    });                }                //Get the move target location                var targetFd = $(target).attr("filedata");                targetFd = JSON.parse(decodeURIComponent(targetFd));                //Move it                moveSourceFilesToTarget(moveSources, targetFd.Filepath)            } else if (target.attr("type") == "shortcut") {                //Opening with the shortcut                //Check shortcut type                let shortcutData = JSON.parse(decodeURIComponent($(target).attr("filedata")));                var shortcutType = shortcutData["ShortcutType"];                if (shortcutType == "module") {                    //Open the source file with this module                    let openFileList = [];                    if ($(".launchiconwrapper.selected").length > 0 && !Array.isArray(sourceFilelist)) {                        $(".launchiconwrapper.selected").each(function() {                            let thisFileData = JSON.parse(decodeURIComponent($(this).parent().attr("filedata")));                            openFileList.push({                                filename: thisFileData["Filename"],                                filepath: thisFileData["Filepath"]                            });                        });                    }else if (sourceFilelist.length > 0 && Array.isArray(sourceFilelist)){                        //Open file that is transfered from file explorer.                        openFileList = sourceFilelist;                        console.log(openFileList);                    } else {                        //Only pass in the current selected file.                        openFileList.push({                            filename: sourceFilename,                            filepath: sourceFilepath                        });                    }                    var shortcutModule = getModuleFromShortcutInfo(shortcutData);                    //console.log(openFileList);                    if (shortcutModule === undefined){                        //This shortcut module is not found on this server                        return;                    }                    openFileWithModule(shortcutModule, openFileList);                } else if (shortcutType == "folder") {                    //Move the source file into this folder                    var moveSources = [sourceFilepath];                    if ($(".launchIconWrapper.selected").length > 1){                        //Multi move operations                        moveSources = [];                        $(".launchIconWrapper.selected").each(function(){                            var thisFileData = $(this).parent().attr("filedata");                            thisFileData = JSON.parse(decodeURIComponent(thisFileData));                            moveSources.push(thisFileData.Filepath);                        });                    }                    //Extract shortcut info from the target                    var targetPath = shortcutData.ShortcutPath;                    moveSourceFilesToTarget(moveSources, targetPath);                }            } else {                console.log("Unknown action type: ", target.attr("type"));            }        }                //Use move if it is folder on desktop, use copy if it is a shortcut        function moveSourceFilesToTarget(sourceList, target, opr="move"){            var oprConfig = {                opr: opr,                src: sourceList,                dest: target,                callbackWindowID: "desktop",                callbackFunction: `refresh(undefined, true)`            }            var configHash = encodeURIComponent(JSON.stringify(oprConfig));            var title = "Copying " + sourceList.length;            if (sourceList.length > 1){                title += " files";            }else{                title += " file";            }            //Create FloatWindow to handle the file operations            newFloatWindow({                url: "SystemAO/file_system/file_operation.html#" + configHash,                width: 400,                height: 220,                appicon: "SystemAO/file_system/img/selector.png",                title: title            });            //Delete the file location from db            sourceList.forEach(file => {                let filename = file.split("/").pop();                $.ajax({                    url: "system/desktop/files",                    data: {del: filename},                    success: function(data){                        if (data.error !== undefined){                            console.log(data.error);                        }                    }                });            });        }        function requestCSRFToken(callback){            $.ajax({                url: "system/csrf/new",                success: function(token){                    callback(token);                }            });        }                function getModuleFromShortcutInfo(shortcutInfo) {            var ShortcutPath = shortcutInfo["ShortcutPath"];            if (ShortcutPath.includes("/") == false) {                //Legacy defination. Append /index.html at the back.                ShortcutPath = ShortcutPath + "/index.html";            }            //Try to match it with the module installed            for (var i = 0; i < moduleInstalled.length; i++) {                if (moduleInstalled[i]["StartDir"] == ShortcutPath || moduleInstalled[i]["Name"] == shortcutInfo["ShortcutName"]) {                    //This is the correct module to be loaded                    return moduleInstalled[i];                }            }        }        //Allocate the given number of grids from desktop         function gridPositionAllocate(posx, posy, numberOfGridNeeded=1){            var gridMaxX = desktopGrids.length;            var gridMaxY = desktopGrids[0].length;            var targetLocation = findClosestGrid(posx, posy, false);            var targetGridLocation = targetLocation[1];            var previousEmptyGridPosition = targetGridLocation;            var locations = [];            for (var k =0; k < numberOfGridNeeded; k++){                var thisLocation = JSON.parse(JSON.stringify(previousEmptyGridPosition));                //Add k to y axis of the list.                thisLocation[1] += k;                if (thisLocation[1] >= gridMaxY){                        thisLocation[0]++;                        thisLocation[1] = 0;                }                if (thisLocation[1] >= gridMaxY && thisLocation[0] >= gridMaxX){                    //Desktop full. Force put to 0 0                     thisLocation[0] = 0;                    thisLocation[1] = 0;                    break;                }                while (getObjectFromGridLocation(thisLocation[0], thisLocation[1]) !== undefined){                    thisLocation[1] += 1;                    if (thisLocation[1] >= gridMaxY){                        //Over the screen. Shift to the row on the right                        thisLocation[0]++;                        thisLocation[1] = 0;                    }                    if (thisLocation[1] >= gridMaxY && thisLocation[0] >= gridMaxX){                        //Desktop full. Force put to 0 0                         thisLocation[0] = 0;                        thisLocation[1] = 0;                        break;                    }                }                previousEmptyGridPosition = JSON.parse(JSON.stringify(thisLocation))                locations.push(thisLocation)            }            return locations        }        function setIconDesktopLocation(sourceFilename, gridIndexX, gridIndexY, callback = undefined) {            $.ajax({                url: "system/desktop/files",                method: "POST",                data: {"set": sourceFilename, "x": gridIndexX, "y": gridIndexY},                success: function(data) {                    if (data.error !== undefined) {                        console.log(data.error);                    } else {                        if (callback !== undefined) {                            callback();                        }                    }                }            });        }        //THIS FUNCTION IS NEEDED. DO NOT DELETE ALLOWDROP FUNCTION        function allowDrop(ev) {            ev.preventDefault();        }        //Pass in the object fullpath and return the icon object onscreen        function getObjectFromPath(path) {            var object;            $(".launchIcon").each(function() {                if ($(this).attr("filepath") == path) {                    object = $(this);                }            });            return object;        }        //Pass in the coordinate and check if there is another object at the same location        function getObjectFromLocation(x, y) {            var object;            $(".launchIcon").each(function() {                if ($(this).position().left == x && $(this).position().top == y) {                    object = $(this);                }            });            return object;        }        //Similar function to getObjectFromLocation but using grid coordinate instead of pixel coordinate        function getObjectFromGridLocation(gx, gy){            if (desktopGrids[gx] == undefined){                //X overflow                return false;            }            var pos = JSON.parse(JSON.stringify(desktopGrids[gx][gy]));            pos[0] = pos[0] + iconOffsetXY[0];            pos[1] = pos[1] + iconOffsetXY[1];            return getObjectFromLocation(pos[0],pos[1]);        }        //Find the clostest empty grid, prioirty given to y first then x        function findClostestEmptyGridLocation(x, y){            //Reduce icon offset to the x y on screen coordinate            x = x - iconOffsetXY[0];            y = y - iconOffsetXY[1];            //Get the grid index from absolute coordinate            var currentGridLocation = getGridIndexFromLocation(x,y);            //console.log(currentGridLocation);            //Search for the next empty location            var targetLocation = [[-1,-1],[-1,-1]];            for (var i = currentGridLocation[0]; i < desktopGrids.length; i++){                var yStart = 0;                if (i == currentGridLocation[0]){                    yStart = currentGridLocation[1];                }                for (k = yStart; k < desktopGrids[i].length; k++){                    var thisLocation = JSON.parse(JSON.stringify(desktopGrids[i][k]));                    var offsetedLocation = [thisLocation[0], thisLocation[1]];                    var possibleDuplication = getObjectFromGridLocation(i,k);                    //console.log( [i,k], offsetedLocation, possibleDuplication)                    if (possibleDuplication === undefined){                        //This is an empty slot                        targetLocation = [offsetedLocation, [i,k]];                        return targetLocation;                    }                }            }            return targetLocation;        }        //Convert location to grid index        function getGridIndexFromLocation(x,y){            var gridIndex = [-1,-1];            for (var i = 0; i < desktopGrids.length; i++){                var thisXAxis = desktopGrids[i];                if (thisXAxis[0][0] == x){                    //This x matches. Match y                    gridIndex[0] = i;                    for (var k = 0; k < thisXAxis.length; k++){                        var thisYAxis = thisXAxis[k];                        if (thisYAxis[1] == y){                            gridIndex[1] = k;                            return gridIndex;                        }                    }                }            }            return gridIndex;        }        //Convert grid index to location        function getLocationFromGridIndex(x, y){            var location = [-1,-1];                        //Calculate the usable grid on screen            var iheight = 106;            var iwidth = 70;            var padding = 16;            if (desktopIconSize == "small") {                iheight = 82;                iwidth = 50;            } else if (desktopIconSize == "medium") {                iheight = 106;                iwidth = 70;            } else if (desktopIconSize == "big") {                iheight = 124;                iwidth = 84;            }            var screenHeight = window.innerHeight;            var screenWidth = window.innerWidth;            var vc = Math.floor((screenHeight - 20 - padding) / iheight);            var hc = Math.floor((screenWidth - padding) / iwidth);            //Calculate the position of this icon on the grid            var resultX = padding + iwidth * x + iconOffsetXY[0];            var resultY = padding + iheight * y + iconOffsetXY[1];            return [resultX, resultY];        }           //Set allow overshoot to allow drop point to get closest grid with x / y > cursor posx /y        function findClosestGrid(x, y, allowOvershoot = true) {            var minDx = window.innerWidth;            var minDy = window.innerHeight;            var finalLocation = [-1, -1];            var gridLocation = [-1, -1];            for (var i = 0; i < desktopGrids.length; i++) {                for (var j = 0; j < desktopGrids[0].length; j++) {                    var thisGridLocation = desktopGrids[i][j];                    var dx = x - thisGridLocation[0];                    var dy = y - thisGridLocation[1];                    if (allowOvershoot) {                        if (Math.abs(dx) < minDx) {                            minDx = Math.abs(x - thisGridLocation[0]);                            finalLocation[0] = thisGridLocation[0];                            gridLocation[0] = i;                        }                        if (Math.abs(dy) < minDy) {                            minDy = Math.abs(y - thisGridLocation[1]);                            finalLocation[1] = thisGridLocation[1];                            gridLocation[1] = j;                        }                    } else {                        if (dx < minDx && dx > 0) {                            minDx = Math.abs(x - thisGridLocation[0]);                            finalLocation[0] = thisGridLocation[0];                            gridLocation[0] = i;                        }                        if (dy < minDy && dy > 0) {                            minDy = Math.abs(y - thisGridLocation[1]);                            finalLocation[1] = thisGridLocation[1];                            gridLocation[1] = j;                        }                    }                }            }            return [finalLocation, gridLocation];        }        //Ask for confirmation before window close        //Update 16 Feb 2021: Disabled confirmation and use a new method of implementing this later        /*        function myConfirmation() {            if (!loggingOut){                return 'Your data might not been saved. Are you sure you want to quit?';            }        }        window.onbeforeunload = myConfirmation;        */        function iconClicked(object, evt) {            if (renameMode){                //Exit rename mode if icon is clicked during renaming                if ($(object).find(".renameInput").length == 0){                    exitRenameMode();                }                            }            hideAllContextMenus();                    //Clicked on a launch icon.            var alreadyHighlighted = $(object).find(".launchIconWrapper").hasClass("selected");            if (alreadyHighlighted){                //Already selected                if (ctrlHold) {                    //Selection                    $(object).find(".launchIconWrapper").removeClass("selected");                }            }else{                //Not selected yet                if (ctrlHold) {                    //Add this into selection                    $(object).find(".launchIconWrapper").addClass("selected");                }else{                    //Remove all others and select this                    $(".launchIconWrapper.selected").removeClass("selected");                    $(object).find(".launchIconWrapper").addClass("selected");                }            }        }        function iconDoubleClicked(object, evt=undefined) {            //Don't allow opening when renaming            if (renameMode){                return;            }            //Double click on a launch icon, tries to open it            var filedata = ao_module_utils.attrToObject($(object).attr("filedata"));            //console.log(filedata);            if (filedata.IsDir) {                //This is a directory. Open with file explorer                newFloatWindow({                    url: "SystemAO/file_system/file_explorer.html#" + encodeURIComponent(filedata.Filepath),                    appicon: "SystemAO/file_system/img/small_icon.png",                    width: 1080,                    height: 580,                    title: "File Manager"                });            } else if (filedata.IsShortcut) {                //This is a shortcut. Open the target endpoint                var stype = filedata["ShortcutType"];                if (stype == "module") {                    //Open the target module                    openModule(filedata.ShortcutPath);                } else if (stype == "folder") {                    //Open the target folder                    openFolder(filedata.ShortcutPath)                }else if (stype == "url"){                    //Open the target webpage in a new tab                    newFloatWindow({                        url: filedata.ShortcutPath,                        appicon: filedata.ShortcutImage,                        title: filedata.ShortcutName,                        parent: filedata.ShortcutPath                    })                    //window.open(filedata.ShortcutPath);                }else{                    console.log(filedata);                }            } else {                //This is a file. Open it with default opener                $.ajax({                    url: "system/modules/getDefault",                    method: "GET",                    data: {                        opr: "launch",                        ext: filedata.Ext,                        mode: "launch"                    },                    success: function(data) {                        if (data.error !== undefined) {                            //No default opener assigned                             var url = "SystemAO/file_system/defaultOpener.html";                            var icon = "SystemAO/file_system/img/opener.png";                            var title = "Select an opener WebApp: "                            var openFileList = [];                            var openFileObject = {                                filepath: filedata.Filepath,                                filename: filedata.Filename                            }                            openFileList.push(openFileObject);                            var openParamter = encodeURIComponent(JSON.stringify(openFileObject));                            newFloatWindow({                                url: url + "#" + openParamter,                                width: 320,                                height: 510,                                appicon: icon,                                title: title                            });                        } else {                            //Assigned. Launch with given paramter                            var url = data["StartDir"];                            var size = [undefined, undefined];                            var title = data["Name"];                            var icon = "img/system/favicon.png";                            if (data["IconPath"] != "") {                                icon = data["IconPath"];                            }                            //Use floatWindow if exists                            if (data["SupportFW"] == true && data["LaunchFWDir"] != "") {                                url = data["LaunchFWDir"];                                if (data["InitFWSize"] !== null) {                                    size = data["InitFWSize"]                                }                            }                            //Use embedded mode if exists                            if (data["SupportEmb"] == true && data["LaunchEmb"] != "") {                                url = data["LaunchEmb"];                                if (data["InitEmbSize"] !== null) {                                    size = data["InitEmbSize"]                                }                            }                            //Build open File Hash Data Format                            var openFileList = [];                            var openFileObject = {                                filepath: filedata.Filepath,                                filename: filedata.Filename                            }                            openFileList.push(openFileObject);                            var openParamter = encodeURIComponent(JSON.stringify(openFileList));                            //Add launch files info and launch floatWindow                            newFloatWindow({                                url: url + "#" + openParamter,                                width: size[0],                                height: size[1],                                appicon: icon,                                title: title                            });                        }                    }                })            }        }        $(window).on("resize", function(event) {            redrawDesktopGrids();            resizeAllFloatWindowButtons();        })        // ======================= DOCUMENT KEY BINDING =====================        document.addEventListener('keydown', function(event) {            let keycode = event.which || event.keyCode;            if (keycode == "17") {                //Pressdown of Ctrl key                ctrlHold = true;            } else if (keycode == "16") {                //Pressdown of Shift key                shiftHold = true;            }else if (keycode == "27"){                //Cancel all floatwindow events and key events                $("#fwdragpanel").hide();                $("#tfwdragpanel").hide();                $(".floatWindow").find(".iframecover").hide();                movingWindow = false;                resizingWindow = false;                resizingEdgeID = 0;                multiSelecting = false;                ctrlHold = false;                shiftHold = false;            }else if (keycode == "46"){                //Delete key                if (renameMode){                    //Deleting content in textarea. Ignore delte action                    return true                }                var deleteFilelist = [];                var deleteFilenameList = [];                $(".launchIconWrapper.selected").each(function(){                    var fileObject = $(this).parent();                    var fd = JSON.parse(decodeURIComponent((fileObject).attr("filedata")));                    deleteFilelist.push(fd.Filepath);                    deleteFilenameList.push(fd.Filename)                });                //Prase the filelist and pass to trash module                console.log(deleteFilelist);                generateCSRFToken(function(csrftoken){                    $.ajax({                        url: "system/file_system/fileOpr",                        method:"POST",                        data: {opr: "recycle", src: JSON.stringify(deleteFilelist), csrft: csrftoken},                        success: function(data){                            if (data.error !== undefined){                                alert(data.error);                            }else{                                //Delete the file's desktop location                                deleteFilenameList.forEach(file => {                                    $.ajax({                                        url: "system/desktop/files",                                        data: {del: file},                                        success: function(data){                                            if (data.error !== undefined){                                                console.log(data.error);                                            }                                            refresh(undefined, true);                                        }                                    });                                });                            }                        }                    });                });                                                           }else if (keycode == "112" ){                //Enter key                if (!renameMode){                    //Open selected object by emulating double click                    $(".launchIconWrapper.selected").each(function(){                        var object = $(this).parent();                        iconDoubleClicked(object);                    });                                    }else if (renameMode){                    event.preventDefault();                    event.stopImmediatePropagation();                    exitRenameMode();                }                        }else if (keycode == "67" && ctrlHold){                //Ctrl + C, copy                handleCopyOperation();             }else if (keycode == "88" && ctrlHold){                //Ctrl + X, cut                handleCutOperation();            }else if (keycode == "86" && ctrlHold){                //Ctrl + V, Paste                handlePasteOperation();            }else{                //console.log(event.which);            }        });                $(document).on("mousemove", function(event){            currentMousePosition = [event.clientX, event.clientY];        });        $(document).keyup(function(event) {            let keycode = event.which || event.keyCode;            if (keycode == "17") {                ctrlHold = false;            }else if (keycode == "16") {                shiftHold = false;            }else if (keycode == "27"){                //ESC key, stop all floatWindow operations                console.log("%c[Desktop] Dragging function killed. Restarting all dragging elements.", 'color: #e64747');                movingWindow = false;                resizingWindow = false;                event.preventDefault();            }else if (keycode == "13"){                //Enter key. open the selected object if exists                $(".launchIconWrapper.selected").each(function(){                    console.log($(this).parent());                    iconDoubleClicked($(this).parent(), event);                })            }        });        $("#bgwrapper").on("mouseup", function(event) {            //Deselect all selected icons            event.preventDefault();            event.stopImmediatePropagation();            mainWindowMouseup(event);        });        function openFolder(virtualPath){            newFloatWindow({                url: "SystemAO/file_system/file_explorer.html#" + encodeURIComponent(virtualPath),                appicon: "SystemAO/file_system/img/small_icon.png",                width:1080,                height:580,                title: "File Manager"            });        }        function logout() {            loggingOut = true;            if (confirm("Exiting Session. Confirm?")){                $.get("system/auth/logout", function() {                    window.location.href = "./";                });            }            hideAllContextMenus();        }        function openSwitchAccountPanel(){            var uuid = newFloatWindow({                url: 'SystemAO/advance/switchAccount.html',                width: 470,                height: 680,                appicon: "SystemAO/desktop/img/account-switch.png",                title: "Switch Account"            });        }        // ======================= CONTEXT MENU =============================        window.addEventListener("contextmenu",            function(e) {                e.preventDefault();                e.stopPropagation();                var clickTarget = $(e.target);                hideAllContextMenus();                showMenu = false;                $("#contextmenu").html("");                if (clickTarget.hasClass("launchIcon") || clickTarget.hasClass("launchIconImage") || clickTarget.hasClass("launchIconText")) {                    //Click on an object on destkop                    if (clickTarget.hasClass("launchIcon") == false) {                        clickTarget = $(clickTarget).parent().parent();                    }                    if (!ctrlHold && !$(clickTarget).find(".launchIconWrapper").hasClass("selected")){                        $(".launchIconWrapper.selected").removeClass("selected");                    }                    //Select this object                    $(clickTarget).find(".launchIconWrapper").addClass("selected");                    var objectType = $(clickTarget).attr("type");                    operationTargetLaunchIcon = $(clickTarget);                    //Check if selected more than one object                    if ($(".launchIconWrapper.selected").length > 1){                            //When the user selected more than one item on desktop                            addContextMenuItem($("#contextmenu"), lcontex('Open'), undefined, "openIconViaMenu", false);                            addContextMenuItem($("#contextmenu"), lcontex('Open With'), "<i class='caret right icon'></i>", "handleOpenWith", true);                            //addContextMenuItem($("#contextmenu"), 'Share', "<i class='caret right icon'></i>", "handleFileShare", true);                            addContextMenuSeperator($("#contextmenu"));                            addContextMenuItem($("#contextmenu"), lcontex('Download in Zip'), "<i class='download icon'></i>", "downloadFile", false);                            addContextMenuItem($("#contextmenu"), lcontex('Copy'), "<i class='copy icon'></i>", "handleCopyOperation", false);                            addContextMenuItem($("#contextmenu"), lcontex('Cut'), "<i class='cut icon'></i>", "handleCutOperation", false);                            addContextMenuItem($("#contextmenu"), lcontex('Delete'), "<i class='trash icon'></i>", "handleFileDelete", false);                            addContextMenuSeperator($("#contextmenu"));                            addContextMenuItem($("#contextmenu"), lcontex('Properties'), undefined, "openObjectProperty", false);                    }else{                        //When the user only selected one item                        if (objectType == "file") {                            addContextMenuItem($("#contextmenu"), lcontex('Open'), undefined, "openIconViaMenu", false);                            addContextMenuItem($("#contextmenu"), lcontex('Open With'), "<i class='caret right icon'></i>", "handleOpenWith", true);                            addContextMenuItem($("#contextmenu"), lcontex('Share'), "<i class='caret right icon'></i>", "handleFileShare", true);                            addContextMenuSeperator($("#contextmenu"));                            addContextMenuItem($("#contextmenu"), lcontex('Download'), "<i class='download icon'></i>", "downloadFile", false);                            addContextMenuItem($("#contextmenu"), lcontex('Copy'), "<i class='copy icon'></i>", "handleCopyOperation", false);                            addContextMenuItem($("#contextmenu"), lcontex('Cut'), "<i class='cut icon'></i>", "handleCutOperation", false);                            addContextMenuItem($("#contextmenu"), lcontex('Rename'), undefined, "handleRename", false);                            addContextMenuItem($("#contextmenu"), lcontex('Delete'), "<i class='trash icon'></i>", "handleFileDelete", false);                            addContextMenuSeperator($("#contextmenu"));                            addContextMenuItem($("#contextmenu"), lcontex('Properties'), undefined, "openObjectProperty", false);                        } else if (objectType == "folder") {                            addContextMenuItem($("#contextmenu"), lcontex('Open'), undefined, "openIconViaMenu", false);                            addContextMenuItem($("#contextmenu"), lcontex('Zip here'), "<i class='zip icon'></i>", "handleZipFolder", false);                            addContextMenuItem($("#contextmenu"), lcontex('Share'), "<i class='caret right icon'></i>", "handleFileShare", true);                            addContextMenuSeperator($("#contextmenu"));                            addContextMenuItem($("#contextmenu"), lcontex('Download as Zip'), "<i class='download icon'></i>", "downloadFile", false);                            addContextMenuItem($("#contextmenu"), lcontex('Copy'), "<i class='copy icon'></i>", "handleCopyOperation", false);                            addContextMenuItem($("#contextmenu"), lcontex('Cut'), "<i class='cut icon'></i>", "handleCutOperation", false);                            addContextMenuItem($("#contextmenu"), lcontex('Rename'), undefined, "handleRename", false);                            addContextMenuItem($("#contextmenu"), lcontex('Delete'), "<i class='trash icon'></i>", "handleFileDelete", false);                            addContextMenuSeperator($("#contextmenu"));                            addContextMenuItem($("#contextmenu"), lcontex('Properties'), undefined, "openObjectProperty", false);                        } else if (objectType == "shortcut") {                            var fd = JSON.parse(decodeURIComponent($(clickTarget).attr("filedata")));                            console.log(fd);                            if (fd.ShortcutType == "module"){                                //Public WebApp                                addContextMenuItem($("#contextmenu"), lcontex('Open'), undefined, "openIconViaMenu", false);                                addContextMenuItem($("#contextmenu"), lcontex('Open in New Tab'), "<i class='external icon'></i>", "openWebAppInNewTab", false);                                addContextMenuItem($("#contextmenu"), lcontex('Rename'), undefined, "handleRename", false);                                addContextMenuItem($("#contextmenu"), lcontex('Delete'), "<i class='trash icon'></i>", "handleFileDelete", false);                            }else if (fd.ShortcutType == "folder"){                                //Folder                                addContextMenuItem($("#contextmenu"), lcontex('Open'), undefined, "openIconViaMenu", false);                                addContextMenuItem($("#contextmenu"), lcontex('Open File Location'), "<i class='folder open icon'></i>", "handleShortcutFolderOpen", false);                                addContextMenuItem($("#contextmenu"), lcontex('Rename'), undefined, "handleRename", false);                                addContextMenuItem($("#contextmenu"), lcontex('Delete'), "<i class='trash icon'></i>", "handleFileDelete", false);                                addContextMenuSeperator($("#contextmenu"));                                addContextMenuItem($("#contextmenu"), lcontex('Properties'), undefined, "openObjectProperty", false);                                                      }else{                                addContextMenuItem($("#contextmenu"), lcontex('Open'), undefined, "openIconViaMenu", false);                                addContextMenuItem($("#contextmenu"), lcontex('Delete'), "<i class='trash icon'></i>", "handleFileDelete", false);                            }                                                                              }else{                            console.log("Opening context menu on unknown type: ", objectType);                        }                    }                    showMenu = true;                } else if (clickTarget.hasClass("backgroundFrame") || ((isSafari || (isMacOS && isChrome)) && $(clickTarget).attr("id") == "selectionPanel")) {                    //Click on the background. Load background context menu.                    addContextMenuItem($("#contextmenu"), lcontex('New'), "<i class='caret right icon'></i>", "newitemmenu", true);                    addContextMenuItem($("#contextmenu"), lcontex('Refresh'), "<i class='refresh icon'></i>", "handleMenuRefresh", false);                    addContextMenuItem($("#contextmenu"), lcontex('Open File Manager'), undefined, "openfm", false);                    if (checkFileInClipboard()){                        addContextMenuItem($("#contextmenu"), lcontex('Paste Here'), "<i class='paste icon'></i>", "handlePasteOperation", false);                    }                    addContextMenuItem($("#contextmenu"), lcontex('Personalization'), "<i class='paint brush icon'></i>", "personalization", false);                    addContextMenuItem($("#contextmenu"), lcontex('Background'), "<i class='caret right icon'></i>", "background", true);                    addContextMenuItem($("#contextmenu"), lcontex('Icon Size'), "<i class='caret right icon'></i>", "listIconsize", true);                    addContextMenuItem($("#contextmenu"), lcontex('Toggle FullScreen'), "<i class='expand  icon'></i>", "fullscreen", false);                    addContextMenuItem($("#contextmenu"), lcontex('Exit'), undefined, "logout", false);                    showMenu = true;                }else if (clickTarget.hasClass("fwdragger") || (clickTarget.hasClass("title") && clickTarget.parent().hasClass("fwdragger"))){                    //Click on the floatWindow object                     addContextMenuItem($("#contextmenu"), lcontex('Open in New Tab'), "<i class='external icon'></i>", "openSelectedFloatWindowInNewTab", false);                    addContextMenuItem($("#contextmenu"), lcontex('Refresh'), "<i class='refresh icon'></i>", "refreshSelectedFloatWindow", false);                    addContextMenuSeperator($("#contextmenu"));                    addContextMenuItem($("#contextmenu"), lcontex('Minimize'), "<i class='window minimize icon'></i>", "minimizeSelectedFloatWindow", false);                    if ($(clickTarget).parent().hasClass("fixedsize") == false && $(clickTarget).parent().parent().hasClass("fixedsize") == false){                        //This FloatWindow is resizable                        console.log($(clickTarget).parent());                        if ($(clickTarget).parent().attr("max") !== undefined && $(clickTarget).parent().attr("max") == "true"){                            addContextMenuItem($("#contextmenu"), lcontex('Restore'), "<i class='window window restore icon'></i>", "maximizeSelectedFloatWindow", false);                        }else{                            addContextMenuItem($("#contextmenu"), lcontex('Maximize'), "<i class='window maximize icon'></i>", "maximizeSelectedFloatWindow", false);                        }                                            }                    addContextMenuItem($("#contextmenu"), lcontex('Close'), "<i class='remove icon'></i>", "closeSelectedFloatWindow", false);                    showMenu = true;                } else if ($(clickTarget).hasClass("floatWindowButton") || $(clickTarget).parent().hasClass("floatWindowButton")){                    if ($(clickTarget).parent().hasClass("floatWindowButton")){                        clickTarget = $(clickTarget).parent();                    }                    //Get the ID list of this button group                    var originalIDlist = JSON.parse(decodeURIComponent($(clickTarget).attr('windowIDGroup')));                    var buttonGroupName = $(clickTarget).attr('group');                    var displayText = lcontex('Close');                    if (originalIDlist.length > 1){                        //More than 1 window                        displayText = lcontex('Close All');                    }                    addContextMenuItem($("#contextmenu"), displayText, "<i class='remove icon'></i>", `closeWindowGroup('${buttonGroupName}');`, false);                    showMenu = true;                }                                if (showMenu){                    //Toggle context menu                    $("#contextmenu").show();                    var startX = e.pageX;                    var startY = e.pageY;                    if (e.pageX > window.innerWidth / 2){                        startX = e.pageX - $("#contextmenu").width();                    }                    if (e.pageY > window.innerHeight / 2){                        startY = e.pageY -  $("#contextmenu").height();                    }                    $("#contextmenu").css({                        left: startX,                        top: startY                    });                    menuStartLocation = [e.pageX, e.pageY];                }            }        , true);                //Localize context menu items using applocale        function lcontex(key){            if (applocale){                return applocale.getString("contextmenu/" + key, key);            }else{                return key;            }        }        function handleMenuRefresh() {            //This function is here to remove the object and event passed in from menu pressed object            refresh();        }        function newshortcut(){            //Show the new shortcut creation tool            newFloatWindow({                url: "SystemAO/desktop/shortcutCreator.html",                appicon: "img/desktop/system_icon/shortcut.png",                width:815,                height:485,                title: "New Shortcut"            });            hideAllContextMenus();        }        function openIconViaMenu(target, event){            $(".launchIconWrapper.selected").each(function(){                iconObject = $(this).parent();                //Emulate a doubleclick on icon                iconDoubleClicked(iconObject, event);            });            hideAllContextMenus();        }        //Opening a shortcut module from desktop to new tab        function openWebAppInNewTab(target, event){            $(".launchIconWrapper.selected").each(function(){                var fd = JSON.parse(decodeURIComponent($(this).parent().attr("filedata")));                $.get("system/modules/getLaunchPara?module=" + fd.ShortcutPath, function(data) {                    if (data.error !== undefined) {                        console.log(data.error);                    }else{                        //Open in new tab                        window.open(data.StartDir)                    }                });            });            hideAllContextMenus();        }        function downloadFile(target, event){            if ( $(".launchIconWrapper.selected").length == 1){                //Download this file directly                var rawfiledata = $(".launchIconWrapper.selected").parent().attr("filedata");                var filedata = JSON.parse(decodeURIComponent(rawfiledata));                var filepath = filedata.Filepath;                //Resolve the link to media download link                var downloadLink = "media/download?file=" + filepath;                window.open(downloadLink)            }else if ($(".launchIconWrapper.selected").length > 1){                //Create a zip file using the fs api                var filelist = [];                $(".launchIconWrapper.selected").each(function(){                    var filedata = JSON.parse(decodeURIComponent($(this).parent().attr("filedata")));                    var filepath = filedata.Filepath;                    filelist.push(filepath);                });                $.ajax({                    url: "system/file_system/zipHandler",                    data: {opr: "tmpzip", src: JSON.stringify(filelist), dest: ""},                    method: "POST",                    success: function(data){                        if (data.error !== undefined){                            alert(data.error);                        }else{                            //Zip completed.                            window.open("media/download?file=" + data);                        }                    }                });            }                        hideAllContextMenus();        }        function handleZipFolder(){            var filelist = [];            var filename = "desktop_" + new Date().getTime() + ".zip"            if ($(".launchIconWrapper.selected").length == 1){                filename = $(".launchIconWrapper.selected").parent().attr('filename') + ".zip";            }            $(".launchIconWrapper.selected").each(function(){                var filedata = JSON.parse(decodeURIComponent($(this).parent().attr("filedata")));                var filepath = filedata.Filepath;                if (filedata.IsDir == true){                    filelist.push(filepath);                }            });            $.ajax({                    url: "system/file_system/zipHandler",                    data: {opr: "zip", src: JSON.stringify(filelist), dest: "user:/Desktop/" + filename},                    method: "POST",                    success: function(data){                        if (data.error !== undefined){                            alert(data.error);                        }else{                            //Zip completed.                            console.log(data);                        }                    }                });            //console.log(filelist);            hideAllContextMenus();        }        function handleOpenWith(target, event){            $("#subcontextmenu").html("");            //Updates 19 May 2021: Added support for better parsing Open With List            var exts = [];            //Get all exts from the selected files            $(".launchIconWrapper.selected").each(function(){                var filename = $(this).parent().attr("filename");                var ext = "." + filename.split(".").pop();                exts.push(ext);            });            $.get("system/modules/list",function(data){                if (data.error !== undefined){                    alert(data.error);                }else{                    var supportedModuleCount = 0;                    var openWithTargets = [];                    for (var i =0; i < data.length; i++){                        var thisModule = data[i];                        //If this module support this ext, add it to list                        var thisModuleSupportExt = thisModule.SupportedExt;                        if (thisModule.Name == "File Manager"){                            //Exceptional case                            addContextMenuItem($("#subcontextmenu"), thisModule.Name, "", "openSelectedWith", false);                        }                        if (thisModuleSupportExt == null || thisModuleSupportExt.length == 0){                            //Not supporting anything                            continue;                        }                        thisModuleSupportExt.forEach(supportedExt => {                            if (exts.includes(supportedExt)){                                //Add this to the menu                                addContextMenuItem($("#subcontextmenu"), thisModule.Name, "", "openSelectedWith", false);                            }                        })                                                //if (thisModule.SupportEmb == true){                        //    addContextMenuItem($("#subcontextmenu"), thisModule.Name, "", "openSelectedWith", false);                        //}                    }                    //Add select more opener option                    addContextMenuSeperator($("#subcontextmenu"));                    addContextMenuItem($("#subcontextmenu"), lcontex("Select Other WebApps"), ``, "openOpenSelector", false);                }                showSubContextMenu(target);            });        }        function handleFileShare(target, object){            $("#subcontextmenu").html("");            //Get the selected file            var targetFile = $(".launchIconWrapper.selected")[0];            var fileData = $(targetFile).parent().attr("filedata");            if (fileData != undefined){                fileData = JSON.parse(decodeURIComponent(fileData));                 //Check if the target file is shared                 $.ajax({                     url: "system/file_system/share/checkShared",                     data: {path: fileData.Filepath},                     success: function(data){                        if (data.IsShared == true){                            addContextMenuItem($("#subcontextmenu"), lcontex("Open Shared Link"), `<i class="external icon"></i>`, "openSharedLink", false, {                                payload: {                                    uuid: data.ShareUUID.UUID                                }                            });                            addContextMenuItem($("#subcontextmenu"),  lcontex("Copy Link"), `<i class="copy icon"></i>`, "copySharedLink", false, {                                payload: {                                    uuid: data.ShareUUID.UUID                                }                            });                            addContextMenuSeperator($("#subcontextmenu"));                            addContextMenuTitle($("#subcontextmenu"), lcontex(`<i class="share alternate icon"></i> ${applocale.getString("contextmenu/Change Share Settings", "Change Share Settings")}]`));                        }else{                            addContextMenuTitle($("#subcontextmenu"), lcontex(`<i class="share alternate icon"></i> ${applocale.getString("contextmenu/Share this File", "Share this File")}`));                        }                        var checkmarkStyle = `style="color: #71ba68;"`;                        var anyoneClass = "";                        if (data.ShareUUID.Permission == "anyone"){                            anyoneClass = `<i ${checkmarkStyle} class="checkmark icon"></i>`;                        }                        var signedinClass = "";                        if (data.ShareUUID.Permission == "signedin"){                            signedinClass = `<i ${checkmarkStyle} class="checkmark icon"></i>`;                        }                        var sameGroupClass = "";                        if (data.ShareUUID.Permission == "samegroup"){                            samegroup = `<i ${checkmarkStyle} class="checkmark icon"></i>`;                        }                        addContextMenuItem($("#subcontextmenu"), `<i class="globe icon"></i> ${applocale.getString("contextmenu/share/link","Anyone with Link")}`, anyoneClass, "shareWithThisPermission", false, {                            payload: {                                type: "anyone"                            }                        });                        addContextMenuItem($("#subcontextmenu"), `<i class="user circle outline icon"></i> ${applocale.getString( "contextmenu/share/signedin","Anyone Signed In")}`, signedinClass, "shareWithThisPermission", false, {                            payload: {                                type: "signedin"                            }                        });                        addContextMenuItem($("#subcontextmenu"), `<i class="users icon"></i> ${applocale.getString("contextmenu/share/samegroup","Same Group Users")}`, sameGroupClass, "shareWithThisPermission", false,{                            payload: {                                type: "samegroup"                            }                        });                        if (data.IsShared == true){                            //This file is shared.                            addContextMenuSeperator($("#subcontextmenu"));                            addContextMenuItem($("#subcontextmenu"), lcontex("Remove Share"), `<i style="color: #d97762;" class="trash icon"></i>`, "shareWithThisPermission", false,{                                payload: {                                    type: "remove"                                }                            });                        }                     }                 });            }                        showSubContextMenu(target);        }        //Copy the shared link        function copySharedLink(target, event){            var payload = getContextMenuPayload(target);            if (payload == null){                //Something wrong                return;            }            //Generate the share link            let protocol = "https://";            if (location.protocol !== 'https:') {                protocol = "http://";            }            var shareURL = protocol + window.location.hostname + ":" + window.location.port + "/share/" + payload.uuid;            //Copy the text to clipboard            const area = document.createElement('textarea');            document.body.appendChild(area);            area.value = shareURL;            area.select();            document.execCommand('copy');            document.body.removeChild(area);            //Update status so it show the user it has been coped            $(target).html(`<i style="color: #71ba68;" class="checkmark icon"></i> ${lcontex("Copied")}`);            setTimeout(function(){                if ($(target).length > 0){                    $(target).html(`${lcontex("Copy Link")}                        <span class="description">                            <i class="copy icon"></i>                        </span>`);                }            }, 3000);        }        //Open the shared file link        function openSharedLink(target, event){            var payload = getContextMenuPayload(target);            if (payload == null){                //Something wrong                return;            }            var targetURL = "share/" + payload.uuid;            window.open(targetURL);            hideAllContextMenus();        }        function shareWithThisPermission(target, event){            var payload = getContextMenuPayload(target);            if (payload == null){                //Something wrong                return;            }            //Get the selected file            var selectedFileObjects = $(".launchIconWrapper.selected");            if (selectedFileObjects.length == 0){                //Not found                return            }else if (selectedFileObjects.length > 1){                //This should not happens. If it did happens, use the first one                selectedFileObjects = selectedFileObjects[0];            }            //Extract file information            var fileData = $(selectedFileObjects).parent().attr("filedata");            fileData = JSON.parse(decodeURIComponent(fileData));                        //Convert the desktop file data to ArozOS generic filedata            var afd = {                "filename": fileData.Filename,                "filepath": fileData.Filepath,                "shareMode": payload.type            };            //Create a new share for this            var targetURL = "SystemAO/file_system/file_share.html#" + encodeURIComponent(JSON.stringify([afd]));            //Calculate the window spawn position            var basePosition = $(selectedFileObjects).offset();            var left = basePosition.left + 100;            if (left + 320 > window.innerWidth){                left = basePosition.left - 350;            }            var top = basePosition.top;            if (top + 480 > window.innerHeight){                top = window.innerHeight - 480;            }            newFloatWindow({                url: targetURL,                width: 330,                height: 480,                left: left,                top: top,                appicon: "SystemAO/file_system/img/share.svg",                title: "Share File"            }, function(windowUUID){                //Set the window to fixed window                setFloatWindowResizePolicy(windowUUID, false);            });            hideAllContextMenus();        }        function openObjectProperty(target, object){           var filelist = [];           $(".launchIconWrapper.selected").each(function(){               var filepath = $(this).parent().attr("filepath");               filelist.push(filepath);           });                      var hashPassthrough = encodeURIComponent(JSON.stringify(filelist));            newFloatWindow({                url: "SystemAO/file_system/file_properties.html#" + hashPassthrough,                width: 340,                height: 480,                appicon: "SystemAO/file_system/img/properties.png",                title: "File Properties",            });            hideAllContextMenus();        }        //Open the file extension selector        function openOpenSelector(target, event){            var filedata = $($(".launchIconWrapper.selected")[0]).parent().attr("filedata")            filedata = JSON.parse(decodeURIComponent(filedata));                        var fileDescriptor = {                filepath: filedata.Filepath,                filename: filedata.Filename            }                        newFloatWindow({                url: "SystemAO/file_system/defaultOpener.html#" + encodeURIComponent(JSON.stringify(fileDescriptor)),                width: 320,                height: 510,                appicon: "SystemAO/file_system/img/opener.png",                title: "Select WebApp to Open File",            });            hideAllContextMenus();        }        function openSelectedWith(target, event){            var targetModulename = $(target).text().trim();            var openFileList = [];            $(".selected.launchIconWrapper").each(function(){                var thisFiledata = JSON.parse(decodeURIComponent($(this).parent().attr("filedata")));               openFileList.push({                   filename: thisFiledata.Filename,                   filepath: thisFiledata.Filepath               });            });            //Find the launch info of the module            var targetModuleInfo = undefined;            for (var i =0; i < moduleInstalled.length; i++){                if (moduleInstalled[i].Name == targetModulename){                    targetModuleInfo = JSON.parse(JSON.stringify(moduleInstalled[i]));                }            }           //Open the files with the given module            openFileWithModule(targetModuleInfo, openFileList);            hideAllContextMenus();        }        function getModuleInfoFromName(moduleName){            for (var i = 0; i < moduleInstalled.length; i++){                if (moduleInstalled[i].Name == moduleName){                    return moduleInstalled[i];                }            }            return false        }        /*            This function is used to generate menu items for context menu.            Options example            {                payload: {                    //Some JSON based payload here                }            }        */        function addContextMenuItem(target, keyword, hotkey = undefined, functionName, containSubMenu = false, options=undefined) {            var itemClass = "item";            if (containSubMenu) {                itemClass = "item submenu";            }            var payload = "";            if (options != undefined && options.payload != undefined){                 payload = encodeURIComponent(JSON.stringify(options.payload));            }            if (hotkey !== undefined) {                target.append(`<div class="${itemClass}" onclick="${functionName}(this,event);" payload="${payload}">                        ${keyword}                        <span class="description">${hotkey}</span>                    </div>`);            } else {                target.append(`<div class="${itemClass}"  onclick="${functionName}(this,event);" payload="${payload}">                        ${keyword}                    </div>`);            }        }        function getContextMenuPayload(object){            var encodedPayload = $(object).attr("payload");            if (encodedPayload != ""){                return JSON.parse(decodeURIComponent(encodedPayload));            }else{                return null;            }        }        function listIconsize(target, event) {            $("#subcontextmenu").html("");            var smallCheckmark = undefined;            var mediumCheckmark = undefined;            var bigCheckmark = undefined;            if (desktopIconSize == "small") {                smallCheckmark = "<i class='checkmark icon'></i>";            }            if (desktopIconSize == "medium") {                mediumCheckmark = "<i class='checkmark icon'></i>";            }            if (desktopIconSize == "big") {                bigCheckmark = "<i class='checkmark icon'></i>";            }            addContextMenuItem($("#subcontextmenu"), lcontex("Small"), smallCheckmark, "setDesktopIconSize", false, {payload: "small"});            addContextMenuItem($("#subcontextmenu"), lcontex("Medium"), mediumCheckmark, "setDesktopIconSize", false, {payload: "medium"});            addContextMenuItem($("#subcontextmenu"), lcontex("Big"), bigCheckmark, "setDesktopIconSize", false, {payload: "big"});            showSubContextMenu(target);        }        function setDesktopIconSize(target, evt) {            var targetSize = $(target).attr("payload");            targetSize = JSON.parse(decodeURIComponent(targetSize));            if (["small", "medium", "big"].includes(targetSize)) {                desktopIconSize = targetSize;            }            refresh();            setStorage("iconsize", desktopIconSize);            hideAllContextMenus();        }        function addContextMenuSeperator(target) {            $(target).append(`<div class="ui divider"></div>`);        }        function addContextMenuTitle(target, title){            $(target).append(`<div class="header">                ${title}            </div>`);        }        function background(target, evt) {            $("#subcontextmenu").html('<div class="item"><i class="loading spinning icon"></i> Loading</div>');            $.get("system/desktop/theme", function(data) {                $("#subcontextmenu").html("");                for (var i = 0; i < data.length; i++) {                    if (currentUserTheme == data[i].Theme) {                        addContextMenuItem($("#subcontextmenu"), data[i].Theme, "<i class='checkmark icon'></i>", "setTheme", false);                    } else {                        addContextMenuItem($("#subcontextmenu"), data[i].Theme, undefined, "setTheme", false);                    }                }            });            showSubContextMenu(target);        }        //Set theme from button click        function setTheme(target, evt) {            var theme = $(target).text().trim();            setDesktopTheme(theme);            hideAllContextMenus();        }        function personalization() {            //Show the personalization window            newFloatWindow({                url: "SystemAO/desktop/personalization.html",                appicon: "SystemAO/desktop/img/personalization.png",                width:640,                height:480,                title: "Personalization"            });            hideAllContextMenus();        }        //New folder on the menu start location        function newfolder(object, event) {            var closestLocation = findClosestGrid(menuStartLocation[0], menuStartLocation[1], false);            let closestPixelLocation = closestLocation[0];            let closestGridIndexLocation = closestLocation[1];            //Generate new foldername            var newFolderName = "New Folder";            var counter = 1;            while (desktopFileList.includes(newFolderName)) {                newFolderName = `New Folder(${counter})`;                counter++;            }            //Check if there are already another object at that locaton            var duplicateObject = getObjectFromLocation(closestPixelLocation[0], closestPixelLocation[1]);            var createObjectLocation = true;            if (duplicateObject !== undefined) {                //Ignore create position. Let it settle on next new slot.                createObjectLocation = false;            }            //Create the folder            requestCSRFToken(function(token){                $.post("system/file_system/newItem", {                    type: "folder",                    src: "user:/Desktop/",                    filename: newFolderName,                    csrft: token                }).done(function(data) {                    if (data.error !== undefined) {                        alert(data.error);                    } else {                        if (createObjectLocation) {                            setIconDesktopLocation(newFolderName, closestGridIndexLocation[0], closestGridIndexLocation[1], function() {                                //After set Desktop icon, refresh the page                                 refresh(function() {                                    //After refresh the page, highlight the new folder and set it to rename mode                                    var targetFolderObject = getObjectFromGridLocation(closestGridIndexLocation[0], closestGridIndexLocation[1]);                                    console.log(targetFolderObject);                                    enableRenameOnLaunchIconObject(targetFolderObject);                                });                            });                        }                    }                });            });            hideAllContextMenus();        }        function enableRenameOnLaunchIconObject(object) {            renameMode = true;            $(".launchIcon").attr("draggable", "false");            var filedata = JSON.parse(decodeURIComponent($(object).attr("filedata")));            var originalName = filedata.Filename;            if (filedata.IsShortcut){                //Shortcut. Use its display name instead                originalName = filedata.ShortcutName;            }            $(object).find(".launchIconText").hide();            $(object).append(`<textarea class="renameInput ${desktopIconSize}" type="text" onkeydown="handleRenameKeydown(event);" ondragstart="return false;" dblclick="event.stopImmediatePropagation(); event.stopImmediatePropagation();"maxlength="32">${originalName}</textarea>`);            $(object).find(".renameInput")[0].select();            var index = originalName.lastIndexOf(".");            console.log(index);            if( index >= 0){                $(object).find(".renameInput")[0].setSelectionRange(0, index);            }            //Updates 4-5-2021: Added IME support on rename input            $(object).find(".renameInput")[0].addEventListener("keydown", function(event){                if (window.ime && window.ime.handler != null){                    window.ime.handler(event);                }else{                    //No IME handler. Just continue the input                }            });            window.ime.focus = $(object).find(".renameInput")[0];        }        //Handle enter keypress on the rename textarea        function handleRenameKeydown(e){            if (e.keyCode == 13){                //Enter pressed                e.preventDefault();                exitRenameMode();            }        }        function exitRenameMode() {            if (renameMode) {                $(".launchIcon").attr("draggable", "true");                $(".launchIcon").find(".launchIconText").show();                //Update the folder to textarea content                $(".renameInput").each(function() {                    if ($(this).val() == "") {                        //Ignore this update                        refresh(function() {                            //Refresh the desktop                        });                                           return;                    } else {                        var filedata = JSON.parse(decodeURIComponent($(this).parent().attr("filedata")));                        var filepath = filedata.Filepath;                        var newFilename = $(this).val();                                                if (filedata.IsShortcut == true){                            //Shortcut. Edit the shortcut content name                            let currentInputTextArea = $(this);                            $.ajax({                                url: "/system/desktop/opr/renameShortcut",                                data: {src: filepath, new: newFilename},                                success: function(data){                                    if (data.error !== undefined){                                        //Cancel the operation                                        console.log("*ERROR* " + data.error);                                        currentInputTextArea.remove();                                    }else{                                        //No need to update the shortcut position (as its name not changed)                                        refresh(function() {                                            //Refresh the desktop                                        });                                    }                                }                            })                        }else{                            //Normal typed files / folder. Rename the object                            let currentInputTextArea = $(this);                            //Check if new filename is identaical to the old filename                            var originalFilename = $(this).parent().attr("filename");                            console.log("Launch Icon object", $(this).parent());                            if (newFilename == originalFilename){                                //Filename has no changes                                currentInputTextArea.remove();                                return;                            }                            generateCSRFToken(function(csrftoken){                                $.ajax({                                    url: "./system/file_system/fileOpr",                                    method: "POST",                                    data: {opr: "rename", src: JSON.stringify([filepath]), new: JSON.stringify([newFilename]), csrft: csrftoken},                                    success: function(data){                                        if (data.error !== undefined){                                            //Cancel the operation                                            alert(data.error);                                            console.log("*ERROR* " + data.error);                                            currentInputTextArea.remove();                                        }else{                                            //Update the new file position                                            let closestLocation = findClosestGrid($(currentInputTextArea).parent().offset().left, $(currentInputTextArea).parent().offset().top);                                            let closestGridIndexLocation = closestLocation[1];                                            setIconDesktopLocation(newFilename, closestGridIndexLocation[0], closestGridIndexLocation[1], function(){                                                //Callback after setting location                                                refresh(function() {                                                    //Refresh the desktop                                                });                                            });                                        }                                    }                                });                            });                        }                    }                });                renameMode = false;            }        }        //Handle opening shortcut folder location        function handleShortcutFolderOpen(object, event){            var openPendingFolders = [];            $(".launchIconWrapper.selected").each(function(){                var filedata = JSON.parse(decodeURIComponent($(this).parent().attr("filedata")));                console.log(filedata);                if (filedata.IsShortcut == true){                    if (filedata.ShortcutType == "folder"){                        openPendingFolders.push(filedata.ShortcutPath);                    }else if (filedata.ShortcutType == "module"){                        openPendingFolders.push("web:/" + filedata.ShortcutPath);                    }                                    }            });            //Open all folders            openPendingFolders.forEach(folder => {                newFloatWindow({                    url: "SystemAO/file_system/file_explorer.html#" + encodeURIComponent(folder),                    appicon: "SystemAO/file_system/img/small_icon.png",                    width:1080,                    height:580,                    title: "File Manager"                });            })            hideAllContextMenus();        }        //Handle basic desktop file operations        function handleFileDelete(object, event){            var deleteFileList = [];            $(".launchIconWrapper.selected").each(function(){                var filedata = JSON.parse(decodeURIComponent($(this).parent().attr("filedata")));                deleteFileList.push(filedata.Filepath);            });            console.log(deleteFileList);            generateCSRFToken(function(csrftoken){                $.ajax({                    url: "system/file_system/fileOpr",                    method:"POST",                    data: {opr: "recycle", src: JSON.stringify(deleteFileList), csrft: csrftoken},                    success: function(data){                        if (data.error !== undefined){                            alert(data.error);                        }else{                        refresh(undefined, true);                        }                    }                });                hideAllContextMenus();            });                    }        //File Rename        let renamingItems = [];        function handleRename(object, event){            if ($('.launchIconWrapper.selected').length > 0){                //Enter rename mode                renamingItems = $('.launchIconWrapper.selected');                let renameTarget = $('.launchIconWrapper.selected')[0]                let fileObject = $(renameTarget).parent();                enableRenameOnLaunchIconObject(fileObject);            }            hideAllContextMenus();        }        function handleCopyOperation(){            var clipboard = [];            $(".launchIconWrapper.selected").each(function(){                var object = $(this).parent();                var fd = JSON.parse(decodeURIComponent($(object).attr("filedata")));                clipboard.push(fd.Filepath);            });            localStorage.setItem("ao/file_system/clipboard",JSON.stringify(clipboard));            localStorage.setItem("ao/file_system/cutmode","false");            copyStringToClipboard(JSON.stringify(clipboard));            hideAllContextMenus();        }        function handleCutOperation(){            var clipboard = [];            $(".launchIconWrapper.selected").each(function(){                var object = $(this).parent();                var fd = JSON.parse(decodeURIComponent($(object).attr("filedata")));                clipboard.push(fd.Filepath);            });            localStorage.setItem("ao/file_system/clipboard",JSON.stringify(clipboard));            localStorage.setItem("ao/file_system/cutmode","true");            copyStringToClipboard(JSON.stringify(clipboard));            hideAllContextMenus();        }        function checkFileInClipboard(){            //Check if there are files in clipboard            var crossFrameClipboard = localStorage.getItem("ao/file_system/clipboard");            var useCutMode = localStorage.getItem("ao/file_system/cutmode");            var fileList = [];            if (crossFrameClipboard !== "" && crossFrameClipboard !== undefined && crossFrameClipboard !== null){                fileList = JSON.parse(crossFrameClipboard);            }                        return fileList.length > 0;        }        function handlePasteOperation(){            //Check if there are files in clipboard            var crossFrameClipboard = localStorage.getItem("ao/file_system/clipboard");            var useCutMode = localStorage.getItem("ao/file_system/cutmode");            var fileList = [];            if (crossFrameClipboard !== "" && crossFrameClipboard !== undefined && crossFrameClipboard !== null){                fileList = JSON.parse(crossFrameClipboard);            }            if (useCutMode !== "" && useCutMode !== undefined && useCutMode !== null){                thisOprCutMode = (useCutMode == "true");            }            var mode = "copy";            var title = "Copying "            if (thisOprCutMode){                mode = "move";                title = "Moving "            }            if (fileList.length > 0){                //There are something to move. Start the file operation dialog                var oprConfig = {                    opr: mode,                    src: fileList,                    dest: "user:/Desktop/",                    overwriteMode: "ask"                }                var configHash = encodeURIComponent(JSON.stringify(oprConfig));                //Genreate window title                var title = title + fileList.length;                if (fileList.length > 1){                    title += " files";                }else{                    title += " file";                }                newFloatWindow({                    url: "SystemAO/file_system/file_operation.html#" + configHash,                    width: 400,                    height: 220,                    appicon: "SystemAO/file_system/img/selector.png",                    title: title                });            }            hideAllContextMenus();        }        //New item menus.        function newitemmenu(target, event) {            $("#subcontextmenu").html("");            //Append the new folder option first            addContextMenuItem($("#subcontextmenu"), lcontex('Folder'), "<i class='folder icon'></i>", "newfolder", true);            addContextMenuItem($("#subcontextmenu"), lcontex('Shortcut'), "<i class='external icon'></i>", "newshortcut", true);            addContextMenuItem($("#subcontextmenu"), lcontex('Upload'), "<i class='cloud upload icon'></i>", "upload", true);            addContextMenuSeperator($("#subcontextmenu"));            requestCSRFToken(function(token){                $.ajax({                    url: "system/file_system/newItem",                    data: {csrft: token},                    success: function(data){                        for (var i = 0; i < data.length; i++) {                            var thisNewFile = data[i];                            var icon = ao_module_utils.getIconFromExt(thisNewFile.Ext);                            addContextMenuItem($("#subcontextmenu"), `<i class="${icon} icon" ext="${thisNewFile.Ext}"></i> ${thisNewFile.Desc}`, undefined, "newitem");                        }                        //Show sub-context menu                        showSubContextMenu(target);                    }                })            });        }        function showSubContextMenu(target) {            $("#subcontextmenu").show();            var targetLeft = $("#contextmenu").offset().left + $("#contextmenu").width() + 2;            var targetTop = $(target).offset().top - 1;            if (targetLeft +  $("#subcontextmenu").width() > window.innerWidth){                //Overflow. Swtich to the left side of the menu                targetLeft = $("#contextmenu").offset().left - $("#subcontextmenu").width() - 2;            }            $("#subcontextmenu").css({                left: targetLeft,                top: targetTop            });                    }        //Create new file item with that filename        function newitem(object, event) {            var extension = $(object).find("i").attr("ext");            //Generate a newfile name            var newfn = "NewFile" + "." + extension;            var counter = 1;            while (desktopFileList.includes(newfn)){                newfn = "NewFile (" + counter + ")." + extension;                counter++;            }            //Get the location position            let closestLocation = findClosestGrid(menuStartLocation[0], menuStartLocation[1], false);            let closestGridIndexLocation = closestLocation[1];            //Request backend to generate the new file            generateCSRFToken(function(token){                $.ajax({                    url: "system/file_system/newItem",                    data: {type: "file",src: "user:/Desktop/",filename: newfn, csrft: token},                    success: function(data){                        if (data.error !== undefined){                            alert(data.error);                        }else{                            //Set the icon location                            setIconDesktopLocation(newfn, closestGridIndexLocation[0], closestGridIndexLocation[1], function(){                                //Refresh the desktop                                refresh(function(){                                    var targetNewFile = getObjectFromGridLocation(closestGridIndexLocation[0], closestGridIndexLocation[1]);                                    console.log("Renaming ", targetNewFile);                                    enableRenameOnLaunchIconObject(targetNewFile);                                });                            });                        }                    }                });            });            hideAllContextMenus();        }        document.getElementById("volumebar").parentNode.addEventListener("touchstart", function(e){            updateVolume( document.getElementById("volumebar").parentNode, e);        });        document.getElementById("brightnessbar").parentNode.addEventListener("touchstart", function(e){            updateBrightness( document.getElementById("brightnessbar").parentNode, e);        });                function getCoordinateFromEvent(e){            var x = -1;            var y = -1;            if (e.originalEvent == undefined){                e.originalEvent = e;            }            if(e.type == 'touchstart' || e.type == 'touchmove' || e.type == 'touchend' || e.type == 'touchcancel'){                var touch = e.originalEvent.touches[0] || e.originalEvent.changedTouches[0];                x = touch.pageX;                y = touch.pageY;            } else if (e.type == 'mousedown' || e.type == 'mouseup' || e.type == 'mousemove' || e.type == 'mouseover'|| e.type=='mouseout' || e.type=='mouseenter' || e.type=='mouseleave') {                x = e.clientX;                y = e.clientY;            }else{                x = e.clientX;                y = e.clientY;            }            return [x,y];        }        function updateVolume(object, event){            var width = $(object).width();            var left = $(object).offset().left;            var clickPosition = getCoordinateFromEvent(event)[0];            var clickRel = clickPosition - left;            var percentage = clickRel / width * 100;            if (percentage < 0){                percentage = 0;            }else if (percentage > 100){                percentage = 100;            }            //Update the global volume            $(object).find(".bar").css("width",percentage + "%");            localStorage.setItem("global_volume", clickRel / width);        }        //Update screen brightness, for those who use ArozOS on their TV        function updateBrightness(object, event){            var width = $(object).width();            var left = $(object).offset().left;            var clickPosition = getCoordinateFromEvent(event)[0];            var clickRel = clickPosition - left;            var percentage = clickRel / width * 100;            if (percentage < 0){                percentage = 0;            }else if (percentage > 100){                percentage = 100;            }            //Min is 3%            if (percentage < 3){                percentage = 3;            }            //Set body brightness filter            $("body").css("filter", `brightness(${percentage}%)`);            //Save changes to localStorage            currentBrightness = percentage;            $(object).find(".bar").css("width",percentage + "%");            localStorage.setItem("brightness", clickRel / width);        }        function refresh(callback = undefined, noflash=false) {            //Refresh desktop contents            let launchOption = {};            if (noflash){                launchOption = {                    noflash: true                };            }            if (callback == undefined) {                initDesktopFiles(launchOption, function(){                    startThumbnailLoader();                    attachDescriptionBoxEvents();                });            } else {                initDesktopFiles(launchOption, function(){                    startThumbnailLoader();                    attachDescriptionBoxEvents();                    callback()                });            }            hideAllContextMenus();        }        function startThumbnailLoader(){            let path = "user:/Desktop";            let protocol = "wss://";            if (location.protocol !== 'https:') {                protocol = "ws://";            }            var port = window.location.port;            if (window.location.port == ""){                if (location.protocol !== 'https:') {                    port = "80";                }else{                    port = "443";                }            }            thumbRenderWebSocket = new WebSocket(protocol + window.location.hostname + ":" + port + "/system/file_system/handleCacheRender?folder=" + path);            thumbRenderWebSocket.onopen = function(e) {            };            thumbRenderWebSocket.onmessage = function(event) {                //Find the correct file in the current directory and place its image                let thumbData = JSON.parse(event.data);                $(".launchIcon").each(function(){                    if (thumbData[1].length > 0){                        if ($(this).attr("filename") == thumbData[0]){                            let imageContainer = $(this).find(".launchIconImage");                            imageContainer.attr("src","data:image/jpg;base64," + thumbData[1]);                            imageContainer.css("padding", "0.6em");                            //Load the application icon on this file                            let filedata = $(this).attr("filedata");                            if (filedata == undefined){                                return;                            }                            filedata = JSON.parse(decodeURIComponent(filedata));                            $.ajax({                                url: "system/modules/getDefault",                                data: {opr: "launch", ext: filedata.Ext},                                method: "GET",                                success: function(data){                                    if (data.error == undefined){                                        let iconSize = 20;                                        let topOffset = $(imageContainer).height() - iconSize/2 + 2;                                        $(imageContainer).parent().append(`<img src="${data.IconPath}" style="position: absolute; right: 0px; top: ${topOffset}px; width: ${iconSize}px; height: ${iconSize}px; pointer-events:none;"></img>`);                                    }                                }                            });                        }                    }                });            };            thumbRenderWebSocket.onclose = function(event) {                //Transfer ended            };            thumbRenderWebSocket.onerror = function(error) {                console.log("Cannot connect to WebSocket cache renderer. Falling back to AJAX request");                startFallbackThumbnailLoader();            };        }        function startFallbackThumbnailLoader(){                $(".launchIcon").each(function(){                    let fd = JSON.parse(decodeURIComponent($(this).attr("filedata")))                     let filepath = fd.Filepath;                    let targetDOM = $(this);                    $.ajax({                        url: "system/file_system/loadThumbnail",                        data: {vpath: filepath},                        success: function(data){                            if (data.error == undefined && data != undefined && data != ""){                                let imageContainer = $(targetDOM).find(".launchIconImage");                                imageContainer.attr("src","data:image/jpg;base64," + data);                                imageContainer.css("padding", "0.6em");                                                                 $.ajax({                                    url: "system/modules/getDefault",                                    data: {opr: "launch", ext: fd.Ext},                                    method: "GET",                                    success: function(data){                                        if (data.error == undefined){                                            let iconSize = 20;                                            let topOffset = $(imageContainer).height() - iconSize/2 + 2;                                            $(imageContainer).parent().append(`<img src="${data.IconPath}" style="position: absolute; right: 0px; top: ${topOffset}px; width: ${iconSize}px; height: ${iconSize}px; pointer-events:none;"></img>`);                                        }                                    }                                });                            }                              }                    })                });            }        function openfm() {            //Open file explorer on desktop            newFloatWindow({                url: "SystemAO/file_system/file_explorer.html#" + encodeURIComponent("user:/Desktop"),                appicon: "SystemAO/file_system/img/small_icon.png",                width: 1080,                height: 580,                title: "File Manager"            });            hideAllContextMenus();        }        /*            Notification and Notification bar related functions            Usage:            title -> The title of the notification            content -> The content of the notification            icon (optional) -> The icon of the notification            windowOpenOption (optional) -> The window opening option for user onclick redirection        */        function sendNotification(title, content, icon="info circle", windowOpenOption=null){            if (content.length > 100){                shortenContent = content.substring(0,100) + "...";            }else{                shortenContent = content;            }            onClickOpenWindowOption = encodeURIComponent(JSON.parse(windowOpenOption));            $("#notificationlist").append(` <div class="notification object" originalcontent="${content}" redirect="${onClickOpenWindowOption}" onclick="openNotification(this);">                    <p class="title"><i class="${icon} icon"></i> ${title}</p>                    <p class="notifycontent">${shortenContent}</p>                    <div class="closebtn" onclick="event.stopImmediatePropagation(); closeThisNotification(this);"><i class="remove icon"></i></div>                    <div class="ui divider"></div>                </div>`);            $(".nonotification").hide();                    }        function openNotification(obj){            newWindowOpeningOption = JSON.parse(decodeURIComponent($(obj).attr("redirect")));            if (newWindowOpeningOption == null){                //Ignore            }else{                //Start a floatWindow to the given target                newFloatWindow(newWindowOpeningOption);            }            //Clear the notiication            closeThisNotification($(obj).find(".closebtn"));        }        function closeThisNotification(obj){            $(obj).parent().slideUp("fast",function(data){                $(this).remove();                if ($(".notification.object").length == 0){                    $(".nonotification").show();                }            });        }        function clearAllNotification(){            $(".notification.object").slideUp('fast',function(data){                $(this).remove();                $(".nonotification").show();            });        }        function hideAllContextMenus() {            $("#subcontextmenu").hide();            $("#contextmenu").hide()            $("#quickAccessPanel").fadeOut("fast");            $("#backgroundTaskPanel").slideUp("fast");        }        function restart(){            if (!powerman){                return            }            var apiObject = {                api: "/system/power/restart",                data: {},                title: applocale.getString("power/restart/text", "Password Required"),                desc: applocale.getString("power/restart/instruction", "for restarting the ArozOS Host"),                thisuser: true, //This username as default, set to false for entering other user                method: "GET"            }            apiObject = encodeURIComponent(JSON.stringify(apiObject));            newFloatWindow({                url: "SystemAO/security/authreq.html#" + apiObject,                width: 480,                height: 300,                appicon: "SystemAO/security/img/lock.svg",                title: applocale.getString("power/restart/title", "Restart - Authentication Required"),                parent: ao_module_windowID,                callback: "handleRestartCallback"            });        }        function shutdown(){            if (!powerman){                return            }            var apiObject = {                api: "system/power/shutdown",                data: {},                title: `<i class='red exclamation triangle icon'></i> ${applocale.getString("power/shutdown/text", "Shutdown Host")} <i class='red exclamation triangle icon'></i>`,                desc: applocale.getString("power/shutdown/instruction", "Please enter your password to confirm operation."),                thisuser: true, //This username as default, set to false for entering other user                method: "GET",                success: "SystemAO/boot/shutdown.html" //Success redirection            }            apiObject = encodeURIComponent(JSON.stringify(apiObject));            newFloatWindow({                url: "SystemAO/security/authreq.html#" + apiObject,                width: 480,                height: 300,                appicon: "SystemAO/security/img/lock.svg",                title: applocale.getString("power/shutdown/title", "Shutdown - Authentication Required"),                parent: ao_module_windowID,                callback: "handleShutdownCallback"            });                   }        //Check if this server is a low memory one        function initUploadMode(){            $.ajax({                url: "system/info/getRAMinfo",                success: function(data){                    if (data.error !== undefined){                        //Permission denied or other reasons that cannot access harwdare info. Use default mode                        lowMemoryMode = true;                    }else{                        //Check if ramsize > 3.8 GB (4GB). If yes, switch to large memory upload mode                        var memsize = JSON.parse(data);                        if (parseFloat(memsize)/ 1024 / 1024 / 1024 >= 3.8){                            console.log("%c[Desktop] Setting upload mode to large memory mode", 'color: #036ffc');                            lowMemoryMode = false;                        }                    }                },                error: function(){                    //Hardware mode disabled. Always use low memory upload mode instead                    lowMemoryMode = true;                }            });        }        //Generate a loading icon for this upload task        function generateUploadingIcon(filename, position){            //Get position for appending            var onScreenLocation = getLocationFromGridIndex(position[0], position[1]);            //Append to UI            var uploadIconUUID = Date.now();            $("#iconwrapper").append(`<div href="javascript:void(0);" class="${uploadIconUUID} launchIcon" type="dummy" filename="${filename}" filepath="user:/Desktop/${filename}"  style="width:70px; height:106px;left:${onScreenLocation[0]}px; top:${onScreenLocation[1]}px;">                <span class="launchIconWrapper">                    <img class="launchIconImage medium" src="img/desktop/files_icon/${desktopIconPack}/file upload.png" draggable="false">                    <p class="launchIconText ${desktopIconSize}" >${applocale.getString( "upload/message/uploading", "Uploading")}</p>                    <div class="ui tiny primary progress" style="margin-top: -4px;">                        <div class="bar" style="min-width: 0px !important; width: 0%;"></div>                    </div>                </span>            </div>`);            return uploadIconUUID;        }        function upload(){            var input = document.createElement('input');            input.type = 'file';            input.multiple = true;            input.onchange = e => {                 var files = e.target.files;                 for (var i = 0; i < files.length; i++){                    uploadFile(files[i], function(){                        refresh(undefined, true);                    });                }            }            input.click();            hideAllContextMenus();        }        function uploadFile(file, callback=undefined, uploadingIconUUID = undefined) {            if (file.size > postUploadModeCutoff && lowMemoryMode){                /*                    Low Memory Upload Mode                */                var filename = encodeURIComponent(file.name);                var filesize = file.size;                //Open the websocket                let path = "user:/Desktop";                let protocol = "wss://";                if (location.protocol !== 'https:') {                    protocol = "ws://";                }                var port = window.location.port;                if (window.location.port == ""){                    if (location.protocol !== 'https:') {                        port = "80";                    }else{                        port = "443";                    }                }                let uploadDir = "user:/Desktop";                    //Fixing Firefox path issues on or above FF48.0                if (isFirefox && file.webkitRelativePath != ""){                    //Use the webkitRelativePath instead of the name, this is a folder upload                    let pathinfo = file.webkitRelativePath.split("/");                    pathinfo.pop();                    let subpath = pathinfo.join("/");                    uploadDir = uploadDir + subpath;                }                let hugeFileMode = "";                if (file.size > largeFileCutoffSize){                    //Filesize over cutoff line. Use huge file mode                    hugeFileMode = "&hugefile=true";                }                                let socket = new WebSocket(protocol + window.location.hostname + ":" + port + "/system/file_system/lowmemUpload?filename=" + filename + "&path=" + uploadDir + hugeFileMode);                let currentSendingIndex = 0;                let chunks = Math.ceil(file.size/uploadFileChunkSize,uploadFileChunkSize);                                //Define a function for sending a particular chunk                function sendChunk(id, uploadingIconUUID){                    let offsetStart = id*uploadFileChunkSize;                    let offsetEnd = id*uploadFileChunkSize + uploadFileChunkSize;                    let thisblob = file.slice(offsetStart,offsetEnd);                    socket.send(thisblob);                    //console.log(id + "/" + chunks);                    //Update progress to first percentage                    let progress = id / (chunks-1) * 100.0;                    if (progress > 100){                        progress = 100;                    }                    if (uploadingIconUUID != undefined){                        //Update the progress on the object                        $("." + uploadingIconUUID + ".launchIcon").find(".bar").css("width", progress + "%");                        if (progress == 100){                            $("." + uploadingIconUUID + ".launchIcon").find(".progress").addClass("indeterminate");                        }                    }                                 }                //Start sending                socket.onopen = function(e) {                    if (filesize < uploadFileChunkSize){                        //This file is smaller than chunk size, set it to somwhere within 10% - 20% so it doesn't look like it is stuck                        $("." + uploadingIconUUID + ".launchIcon").find(".bar").css("width", "15%");                    }                                        //Send the first chunk                    sendChunk(0, uploadingIconUUID);                    currentSendingIndex++;                };                socket.onmessage = function(event) {                    //Append to the send index                    var incomingValue = event.data;                    if (incomingValue == "next"){                        if (currentSendingIndex == chunks + 1){                            //Already finished                            socket.send("done");                        }else{                            //Send next chunk                            sendChunk(currentSendingIndex, uploadingIconUUID);                            currentSendingIndex++;                        }                                          }else if (incomingValue == "OK"){                        //Merge completed                                            }else{                        //Try to parse it as JSON                        try{                            var resp = JSON.parse(incomingValue.split('\\' + '"').join("\""));                            console.log(resp);                            if (resp.error !== undefined){                                //This is an error message                                sendNotification("Upload Failed", resp.error, "remove")                                //Update the progress bar to error                                $("." + uploadingIconUUID + ".launchIcon").find(".progress").removeClass("primary").addClass("error");                                $("." + uploadingIconUUID + ".launchIcon").find(".launchIconText").text(applocale.getString("upload/message/failed", "Failed!"));                                setTimeout(function(){                                    $("." + uploadingIconUUID + ".launchIcon").fadeOut(3000,function() { $(this).remove(); });                                }, 2000);                            }                        }catch(ex){                            //Something else                            console.log(incomingValue);                            console.log(ex);                        }                    }                };                socket.onclose = function(event) {                    $("." + uploadingIconUUID).remove();                    if (callback != undefined){                        callback();                    }                };                socket.onerror = function(error) {                    console.log(error.message);                    console.log("[Desktop] Unable to open WebSocket connection. Fall back to FORM POST upload mode. (Check your nginx / reverse proxy settings!!!)")                    //Try to fallback to FORM POST upload mode                    lowMemoryMode = false;                    uploadFile(thisFile, callback)                    return                };            }else{                let url = 'system/file_system/upload'                let uploadCurrentPath = "user:/Desktop/";                let formData = new FormData();                let xhr = new XMLHttpRequest();                formData.append('file', file);                formData.append('path', uploadCurrentPath);                xhr.open('POST', url, true)                xhr.upload.addEventListener("progress", function(e) {                    console.log((e.loaded * 100.0 / e.total) || 100)                    var progress = (e.loaded * 100.0 / e.total) || 100;                    if (uploadingIconUUID != undefined){                        //Update the progress on the object                        $("." + uploadingIconUUID + ".launchIcon").find(".bar").css("width", progress + "%");                        if (progress == 100){                            $("." + uploadingIconUUID + ".launchIcon").find(".progress").addClass("indeterminate");                        }                    }                })                xhr.addEventListener('readystatechange', function(e) {                    if (xhr.readyState == 4 && xhr.status == 200) {                        //Upload Succ                        $("." + uploadingIconUUID).remove();                        if (callback !== undefined){                            callback(e.target.response);                        }                    }                    else if (xhr.readyState == 4 && xhr.status != 200) {                        console.log("Upload failed :" + xhr.status);                        //Set upload progress bar to error                        $("." + uploadingIconUUID + ".launchIcon").find(".progress").removeClass("primary").addClass("error");                        $("." + uploadingIconUUID + ".launchIcon").find(".launchIconText").text(applocale.getString("upload/message/failed", "Failed!"));                        setTimeout(function(){                            $("." + uploadingIconUUID + ".launchIcon").fadeOut(3000,function() { $(this).remove(); });                        }, 2000);                    }                })                xhr.send(formData);            }        }        function setStorage(key, value, callback = undefined) {            $.ajax({                url: "system/desktop/preference",                 data: {preference: key, value: value},                method: "POST",                success: function(data) {                    if (data.error !== undefined) {                        console.log(data.error);                    } else {                        if (callback !== undefined) {                            callback();                        }                    }                }            });        }        function getStorage(key, callback) {            $.ajax({                url: "system/desktop/preference",                data: {preference: key},                success: callback            });        }        function showSystemSettings(){            var hasAccessToSetting = false;            moduleInstalled.forEach(thismod => {                if (thismod.Name == "System Setting"){                    openModule("System Setting");                }            })        }        function initTheme(targetTheme=undefined){            if (targetTheme == undefined){                $.get("system/file_system/preference?key=file_explorer/theme", function(data){                    if (data == "darkTheme"){                        setDarkTheme();                    }else{                        setWhiteTheme();                    }                });            }else{                //Manual override mode                if (targetTheme == "darkTheme"){                    setDarkTheme();                }else if (targetTheme == "whiteTheme"){                    setWhiteTheme();                }            }                  }        function setFloatWindowTheme(fwid, theme="dark"){            var targetFW = getFloatWindowByID(fwid);            if (theme == "dark"){                $(targetFW).removeClass("white");            }else if (theme == "white"){                $(targetFW).addClass("white");            }        }        function checkFileSystemAccess(){            var allowReadWrite = false;            moduleInstalled.forEach(thisModule => {                if (thisModule.Name == "File Manager"){                    //This user has read write access to file system                    allowReadWrite = true;                }            });            if (!allowReadWrite){                sendNotification(applocale.getString("error/connlost/readonly", "READ ONLY Account"), applocale.getString("error/connlost/readonl/infoy", "This account is read only. You cannot perform any file operations on this desktop."));            }        }        function setDarkTheme(){            $("body").removeClass("whiteTheme").addClass("darkTheme");            $("#powerIcon").attr("src","img/system/power-white.svg");        }        function setWhiteTheme(){            $("body").removeClass("darkTheme").addClass("whiteTheme");            $("#powerIcon").attr("src","img/system/power.svg");        }        function hexToRgbA(hex, transparent=1){            var c;            if(/^#([A-Fa-f0-9]{3}){1,2}$/.test(hex)){                c= hex.substring(1).split('');                if(c.length== 3){                    c= [c[0], c[0], c[1], c[1], c[2], c[2]];                }                c= '0x'+c.join('');                return 'rgba('+[(c>>16)&255, (c>>8)&255, c&255].join(',')+',' + transparent + ')';            }            throw new Error('Bad Hex');        }        function setThemeColor(newThemeColor){            //Update the global theme color            desktopThemeColor = newThemeColor;            //Update the related elements            $("#statusbar").css("background-color",hexToRgbA(newThemeColor, 0.8));            $("#navimenu").css("background-color",hexToRgbA(newThemeColor, 0.5));            var themeColorForBoarders = hexToRgbA(newThemeColor, 0.25);            $(".floatWindow .controls").css("background-color",themeColorForBoarders);            $(".floatWindow .iframewrapper").css({                "border-left":"3px solid " + themeColorForBoarders,                "border-right":"3px solid " + themeColorForBoarders,                "border-bottom":"3px solid " + themeColorForBoarders,            })            //List menu theme color bar            $("#listMenu").find(".searchBar").css("border-bottom", "2px solid " + newThemeColor);            $("#volumebar").css("background-color", newThemeColor);            $("#brightnessbar").css("background-color", newThemeColor);            $(".themed.text").css("color", newThemeColor);            //Connection lost notification css            $("#connectionLost").find(".ui.card").css("background-color", hexToRgbA(newThemeColor, 0.5));        }        //Load the user define theme color to overwrite the default color if exists        function initUserDefinedThemeColor(){            $.ajax({                url: "system/desktop/preference",                data: {preference: "themecolor"},                method: "POST",                success: function(data){                    if (data.error == undefined && data != ""){                        setThemeColor(data);                    }                }            });        }        //Float Window context menu        function getFocusedFloatWindowID(){            var targetFloatWindowId = "";            $(".floatWindow").each(function() {                var thisWindowZIndex = $(this).css("z-index");                if (parseInt(thisWindowZIndex) == 101){                    targetFloatWindowId =  $(this).attr("windowid");                }            });             return targetFloatWindowId;        }        function closeWindowGroup(groupName){            $(".floatWindowButton").each(function(){                if ($(this).attr("group") == groupName){                    var originalIDlist = JSON.parse(decodeURIComponent($(this).attr('windowIDGroup')));                    originalIDlist.forEach(fwid => {                        closeFloatWindowViaID(fwid);                    });                                    }            })        }        function getFocusedFloatWindow(){            var focusedFwId = getFocusedFloatWindowID();            if (focusedFwId != ""){                var fw = getFloatWindowByID(focusedFwId);                return fw;            }else{                return undefined;            }        }        function refreshSelectedFloatWindow(target, event){           var fw = getFocusedFloatWindow();           if (fw != undefined){               $(fw).find("iframe")[0].contentWindow.location.reload();           }           hideAllContextMenus();        }        function maximizeSelectedFloatWindow(target, event){            var fw = getFocusedFloatWindow();            if (fw != undefined){                toggleMax($(fw).find(".buttons.maxtoggle"),event);            }            hideAllContextMenus();        }        function minimizeSelectedFloatWindow(target, event){            var fw = getFocusedFloatWindow();            if (fw != undefined){                min($(fw).find(".buttons.mintoggle"),event);            }            hideAllContextMenus();        }        function openSelectedFloatWindowInNewTab(){            var fw = getFocusedFloatWindow();            if (fw != undefined){                try{                    var currentURL = $(fw).find("iframe")[0].contentWindow.location;                    window.open(currentURL);                }catch(ex){                    //Maybe CORS. Try to get it from window's parent properties                    let parentURL = $(fw).attr("parent");                    if (parentURL != undefined){                        window.open(parentURL);                    }else{                        console.log("Unable to access iframe object")                    }                }                           }            hideAllContextMenus();        }        function closeSelectedFloatWindow(target, event){            var fw = getFocusedFloatWindow();            if (fw != undefined){                closeFloatWindow($(fw).find(".buttons.closetoggle"),event);            }            hideAllContextMenus();        }        function fullscreen() {            //Opening full screen will lead to hidden of all iframe for unknown reasons            var isInFullScreen = (document.fullscreenElement && document.fullscreenElement !== null) ||                (document.webkitFullscreenElement && document.webkitFullscreenElement !== null) ||                (document.mozFullScreenElement && document.mozFullScreenElement !== null) ||                (document.msFullscreenElement && document.msFullscreenElement !== null);            var elem = document.documentElement;            if (!isInFullScreen) {                if (elem.requestFullscreen) {                    elem.requestFullscreen();                } else if (elem.mozRequestFullScreen) { /* Firefox */                    elem.mozRequestFullScreen();                } else if (elem.webkitRequestFullscreen) { /* Chrome, Safari and Opera */                    elem.webkitRequestFullscreen();                } else if (elem.msRequestFullscreen) { /* IE/Edge */                    elem.msRequestFullscreen();                }            } else {                if (document.exitFullscreen) {                    document.exitFullscreen();                } else if (document.webkitExitFullscreen) {                    document.webkitExitFullscreen();                } else if (document.mozCancelFullScreen) {                    document.mozCancelFullScreen();                } else if (document.msExitFullscreen) {                    document.msExitFullscreen();                }            }            hideAllContextMenus();        }        function copyStringToClipboard(content){            var el = document.createElement('textarea');            el.value = content;            el.setAttribute('readonly', '');            el.style = {position: 'absolute', left: '-9999px'};            document.body.appendChild(el);            el.select();            document.execCommand('copy');            document.body.removeChild(el);        }        /*        var screenshotBuf = [];        var totalFloatWindowsLeft = 0;        function screenshot(){            totalFloatWindowsLeft = $(".floatWindow").length;            screenshotBuf = [];            //Get a screenshot from each floatWindow            $(".floatWindow").each(function(){                let contentWindow = $(this).find("iframe")[0].contentWindow;                let offsets = [$(this).find("iframe").offset().left, $(this).find("iframe").offset().top];                let thisWindowId = $(this).attr("windowid");                if (contentWindow.ao_module_screenshot){                    contentWindow.ao_module_screenshot(function(capture){                        screenshotBuf.push([thisWindowId,offsets,capture]);                        totalFloatWindowsLeft--;                        if (totalFloatWindowsLeft == 0){                            //Merge the canvas                            mergeScreenshotCanvas();                        }                    })                }else{                    //Float window do not allow screenshot                }            });            if (totalFloatWindowsLeft == 0){                setTimeout(function(){                    mergeScreenshotCanvas();                }, 500);                            }        }        function mergeScreenshotCanvas(){            //Merge the screenshots            for (var i = 0; i < screenshotBuf.length; i++){                var thisWindowID = screenshotBuf[i][0];                var thisOffsets = screenshotBuf[i][1];                var thisCanvas = screenshotBuf[i][2];                var imgLink = thisCanvas.toDataURL();                //Overlay the iframe with image of screenshot                let targetFw = getFloatWindowByID(thisWindowID);                $(targetFw).find(".iframecover").append(`<img src="${imgLink}"/>`);                $(targetFw).find(".iframecover").show();            }            html2canvas(document.querySelector("body")).then(basecanvas => {                downloadCanvas(basecanvas);                //Clear up the mess                screenshotBuf.forEach(function(entry){                    let targetFw = getFloatWindowByID(entry[0]);                    $(targetFw).find(".iframecover").html("");                    $(targetFw).find(".iframecover").hide();                });                 //Reset paramters                totalFloatWindowsLeft = 0;                screenshotBuf = [];            });                   }        function downloadCanvas(canvas){            var aDownloadLink = document.createElement('a');            aDownloadLink.download = `screenshot_${new Date().toLocaleString(undefined, {year: 'numeric', month: '2-digit', day: '2-digit', weekday:"long", hour: '2-digit', hour12: false, minute:'2-digit', second:'2-digit'}).split(":").join("_").split("/").join("-")}.png`;            aDownloadLink.href = canvas.toDataURL();            aDownloadLink.click();        }        */        //Function for converting bytes to human readable sizes        function formatBytes(a,b=2){if(0===a)return"0 Bytes";const c=0>b?0:b,d=Math.floor(Math.log(a)/Math.log(1024));return parseFloat((a/Math.pow(1024,d)).toFixed(c))+" "+["Bytes","KB","MB","GB","TB","PB","EB","ZB","YB"][d]}        /*            Background services for keeping desktop files updated            Same mechanism is used as file explorer        */        let desktopFileHash = "";        setInterval(function(){            getDesktopHash(function(hash){                if (desktopFileHash == ""){                    //Initialization                    desktopFileHash = hash;                }else if (desktopFileHash != hash){                    //Changed on desktop files. Refresh                    refresh(undefined, true);                    desktopFileHash = hash;                }                //Else, no file change on desktop            });        }, 15000);        function generateCSRFToken(callback){            $.ajax({                url: "../../system/csrf/new",                success: function(token){                    callback(token);                }            })        }        function getDesktopHash(callback){            $.ajax({                url: "system/file_system/listDirHash",                data: {dir: "user:/Desktop/"},                success: function(data){                    if (data.error !== undefined){                                            }                    callback(data);                }            })        }        function bindObjectToIMEEvents(object){            object.addEventListener("keydown", function(event){                if (window.ime && window.ime.handler != null){                    window.ime.handler(event);                }else{                    //No IME handler. Just continue the input                }            });            object.addEventListener("focus", function(event){                if (window.ime){                    //IME exists. Set this field to focused field                    window.ime.focus = event.target;                }            });        }        /*            Alternative account manager        */        function listAllStoredAccounts(){            $("#alternativeAccountList").empty();            //Request server side for the account pool            $.get("system/auth/u/list", function(data){                if (data.error != undefined){                    $("#alternativeAccountList").append(`<div style="padding: 0.4em; padding-left: 1em; padding-right: 1em;">                            <i class="ui green check circle icon"></i> ${applocale.getString("account/switch/noAlternative", "No other account stored on this browser")}                    </div>`);                    $("#signoutAllButton").addClass('disabled');                }else{                    if (data.length > 1){                        data.forEach(function(account){                            if (account.Username == userInfo.Username){                                //Skip                                return;                            }                            $.get("system/desktop/user?target=" + account.Username, function(data){                                let userIcon = data.UserIcon;                                if (userIcon == ""){                                    userIcon = "img/desktop/system_icon/user.svg"                                }                                $("#alternativeAccountList").append(`                                    <div class="alternativeAccount item ${account.IsExpired?"expired":""}" acname="${account.Username}" onclick="switchAccount(this);">                                        <div class="ui header">                                            <img class="usericon ui circular image" src="${userIcon}">                                            <div class="content" style="font-size: 95% !important;">                                                <span class="username">${account.Username}</span> ${(data.IsAdmin)?'<i style="margin-left: 0.4em; color: rgb(38, 50, 56);" title="Admin" class="small shield alternate icon themed text"></i>':""}                                                <div class="sub header usergroup">${!account.IsExpired?"<i class='ui green check circle icon' style='margin-right: 0px;'></i> " + applocale.getString("account/switch/sessionValid", "Session Valid"):"<i class='ui red times circle icon' style='margin-right: 0px;'></i> " + applocale.getString("account/switch/sessionExpired", "Session Expired")}</div>                                            </div>                                        </div>                                    </div>                                `);                            });                        });                        $("#signoutAllButton").removeClass('disabled');                    }else{                        $("#signoutAllButton").addClass('disabled');                        $("#alternativeAccountList").append(`<div style="padding: 0.4em; padding-left: 1em; padding-right: 1em;">                            <i class="ui green check circle icon"></i> ${applocale.getString("account/switch/noAlternative", "No other account stored on this browser")}                        </div>`);                        return;                    }                }            })        }        function switchAccount(object){            let targetUsername = $(object).attr("acname");            if (targetUsername == undefined || targetUsername == ""){                console.log("Unable to load username from element")                return;            }            //Check if it is expired            if ($(object).hasClass("expired")){                openSwitchAccountPanel();                return;            }            $.ajax({                url: "system/auth/u/switch",                data: {                    "username": targetUsername,                },                success: function(data){                    if (data.error != undefined){                        alert(data.error);                    }else{                        initDesktop();                    }                }            })        }        function logoutAllAccounts(){            if (confirm(applocale.getString("account/switch/logout/confirm", "This will logout all other accounts from this browser. Confirm?"))){                $.ajax({                    url: "system/auth/u/logoutAll",                    success: function(data){                        if (data.error != undefined){                            alert(data.error);                        }else{                            //Reset the browser pool id                            localStorage.removeItem("ao_acc");                            listAllStoredAccounts();                            hideToolPanel();                        }                    }                })            }        }           </script></body></html>
 |