diff --git a/The Colorful Creature.resource_order b/The Colorful Creature.resource_order index 7e3f38fd8..b68f68f88 100644 --- a/The Colorful Creature.resource_order +++ b/The Colorful Creature.resource_order @@ -1,5 +1,6 @@ { "FolderOrderSettings":[ + {"name":"AdMob","order":4,"path":"folders/Extensions/AdMob.yy",}, {"name":"Animation Curves","order":2,"path":"folders/Animation Curves.yy",}, {"name":"Extensions","order":12,"path":"folders/Extensions.yy",}, {"name":"Fonts","order":8,"path":"folders/Fonts.yy",}, @@ -55,7 +56,6 @@ {"name":"Hardmode","order":21,"path":"folders/Objects/Mainmenu/Hardmode.yy",}, {"name":"Iap Joke","order":25,"path":"folders/Objects/Mainmenu/Iap Joke.yy",}, {"name":"Level Select","order":28,"path":"folders/Objects/Mainmenu/Level Select.yy",}, - {"name":"New Games","order":30,"path":"folders/Objects/Mainmenu/New Games.yy",}, {"name":"Quests","order":20,"path":"folders/Objects/Mainmenu/Quests.yy",}, {"name":"Support","order":22,"path":"folders/Objects/Mainmenu/Support.yy",}, {"name":"Contributors & Translators","order":10,"path":"folders/Objects/Mainmenu/Support/Contributors & Translators.yy",}, @@ -200,8 +200,8 @@ {"name":"Other","order":11,"path":"folders/Sprites/Achievements/Achievement Icons/Other.yy",}, {"name":"Time","order":12,"path":"folders/Sprites/Achievements/Achievement Icons/Time.yy",}, {"name":"Workshop","order":14,"path":"folders/Sprites/Achievements/Achievement Icons/Workshop.yy",}, - {"name":"Android","order":16,"path":"folders/Sprites/Android.yy",}, - {"name":"Backgrounds","order":12,"path":"folders/Sprites/Backgrounds.yy",}, + {"name":"Android","order":15,"path":"folders/Sprites/Android.yy",}, + {"name":"Backgrounds","order":11,"path":"folders/Sprites/Backgrounds.yy",}, {"name":"Actual Backgrounds","order":4,"path":"folders/Sprites/Backgrounds/Actual Backgrounds.yy",}, {"name":"Slopes","order":1,"path":"folders/Sprites/Backgrounds/Slopes.yy",}, {"name":"Spikes","order":2,"path":"folders/Sprites/Backgrounds/Spikes.yy",}, @@ -215,22 +215,22 @@ {"name":"Slopes","order":41,"path":"folders/Sprites/Blocks/Slopes.yy",}, {"name":"White Block","order":7,"path":"folders/Sprites/Blocks/White Block.yy",}, {"name":"Yellow Block","order":4,"path":"folders/Sprites/Blocks/Yellow Block.yy",}, - {"name":"Commentary","order":17,"path":"folders/Sprites/Commentary.yy",}, - {"name":"Custom Levels","order":15,"path":"folders/Sprites/Custom Levels.yy",}, + {"name":"Commentary","order":16,"path":"folders/Sprites/Commentary.yy",}, + {"name":"Custom Levels","order":14,"path":"folders/Sprites/Custom Levels.yy",}, {"name":"Danger","order":7,"path":"folders/Sprites/Danger.yy",}, {"name":"Hammer","order":1,"path":"folders/Sprites/Danger/Bosses/Hammer.yy",}, {"name":"King","order":4,"path":"folders/Sprites/Danger/Bosses/King.yy",}, {"name":"Lava","order":3,"path":"folders/Sprites/Danger/Bosses/Lava.yy",}, {"name":"Piano","order":2,"path":"folders/Sprites/Danger/Bosses/Piano.yy",}, - {"name":"ENDING SLIDES","order":21,"path":"folders/Sprites/ENDING SLIDES.yy",}, - {"name":"Endless Run","order":11,"path":"folders/Sprites/Endless Run.yy",}, + {"name":"ENDING SLIDES","order":19,"path":"folders/Sprites/ENDING SLIDES.yy",}, + {"name":"Endless Run","order":10,"path":"folders/Sprites/Endless Run.yy",}, {"name":"Custom Endless Run","order":3,"path":"folders/Sprites/Endless Run/Custom Endless Run.yy",}, {"name":"Game","order":4,"path":"folders/Sprites/Game.yy",}, - {"name":"Hud","order":9,"path":"folders/Sprites/Hud.yy",}, + {"name":"Hud","order":8,"path":"folders/Sprites/Hud.yy",}, {"name":"Items","order":3,"path":"folders/Sprites/Items.yy",}, {"name":"Gravity","order":11,"path":"folders/Sprites/Items/Gravity.yy",}, {"name":"Old G and S","order":10,"path":"folders/Sprites/Items/Old G and S.yy",}, - {"name":"Level Editor","order":13,"path":"folders/Sprites/Level Editor.yy",}, + {"name":"Level Editor","order":12,"path":"folders/Sprites/Level Editor.yy",}, {"name":"Challenges","order":10,"path":"folders/Sprites/Main Menu/Challenges.yy",}, {"name":"Controller","order":13,"path":"folders/Sprites/Main Menu/Controller.yy",}, {"name":"Multiplayer","order":11,"path":"folders/Sprites/Main Menu/Multiplayer.yy",}, @@ -305,17 +305,21 @@ {"name":"Steam","order":10,"path":"folders/Sprites/Player Customization/Player Skins/Skins/Page 3/Steam.yy",}, {"name":"Page 4","order":3,"path":"folders/Sprites/Player Customization/Player Skins/Skins/Page 4.yy",}, {"name":"Kratos","order":1,"path":"folders/Sprites/Player Customization/Player Skins/Skins/Page 4/Kratos.yy",}, - {"name":"Settings","order":10,"path":"folders/Sprites/Settings.yy",}, - {"name":"Special Effects","order":14,"path":"folders/Sprites/Special Effects.yy",}, + {"name":"Settings","order":9,"path":"folders/Sprites/Settings.yy",}, + {"name":"Special Effects","order":13,"path":"folders/Sprites/Special Effects.yy",}, {"name":"Steamworks","order":20,"path":"folders/Steamworks.yy",}, {"name":"Tile Sets","order":3,"path":"folders/Tile Sets.yy",}, {"name":"Timelines","order":10,"path":"folders/Timelines.yy",}, ], "ResourceOrderSettings":[ - {"name":"AdMob","order":4,"path":"extensions/AdMob/AdMob.yy",}, + {"name":"AdMob","order":1,"path":"extensions/AdMob/AdMob.yy",}, + {"name":"AdMobIronSource","order":1,"path":"extensions/AdMobIronSource/AdMobIronSource.yy",}, + {"name":"AdMobMeta","order":2,"path":"extensions/AdMobMeta/AdMobMeta.yy",}, + {"name":"AdMobPangle","order":3,"path":"extensions/AdMobPangle/AdMobPangle.yy",}, + {"name":"AdMobUnityAds","order":4,"path":"extensions/AdMobUnityAds/AdMobUnityAds.yy",}, {"name":"Color_Blindness_Simulation","order":1,"path":"extensions/Color_Blindness_Simulation/Color_Blindness_Simulation.yy",}, - {"name":"GooglePlayService","order":3,"path":"extensions/GooglePlayService/GooglePlayService.yy",}, - {"name":"GooglePlayServices","order":5,"path":"extensions/GooglePlayServices/GooglePlayServices.yy",}, + {"name":"GooglePlayService","order":2,"path":"extensions/GooglePlayService/GooglePlayService.yy",}, + {"name":"GooglePlayServices","order":3,"path":"extensions/GooglePlayServices/GooglePlayServices.yy",}, {"name":"fnt_complete","order":8,"path":"fonts/fnt_complete/fnt_complete.yy",}, {"name":"fnt_cool","order":1,"path":"fonts/fnt_cool/fnt_cool.yy",}, {"name":"fnt_cool2","order":2,"path":"fonts/fnt_cool2/fnt_cool2.yy",}, @@ -468,7 +472,7 @@ {"name":"o_comradehatbutton","order":5,"path":"objects/o_comradehatbutton/o_comradehatbutton.yy",}, {"name":"o_conehatbutton","order":2,"path":"objects/o_conehatbutton/o_conehatbutton.yy",}, {"name":"o_contributorsPopup","order":1,"path":"objects/o_contributorsPopup/o_contributorsPopup.yy",}, - {"name":"o_controllertutormenu","order":32,"path":"objects/o_controllertutormenu/o_controllertutormenu.yy",}, + {"name":"o_controllertutormenu","order":33,"path":"objects/o_controllertutormenu/o_controllertutormenu.yy",}, {"name":"o_controllervibrationsettings","order":59,"path":"objects/o_controllervibrationsettings/o_controllervibrationsettings.yy",}, {"name":"o_controlsbuttonsettings","order":5,"path":"objects/o_controlsbuttonsettings/o_controlsbuttonsettings.yy",}, {"name":"o_controlsconfigMU","order":12,"path":"objects/o_controlsconfigMU/o_controlsconfigMU.yy",}, @@ -640,6 +644,7 @@ {"name":"o_iceblockbackground","order":6,"path":"objects/o_iceblockbackground/o_iceblockbackground.yy",}, {"name":"o_iceblockbackgroundslope","order":5,"path":"objects/o_iceblockbackgroundslope/o_iceblockbackgroundslope.yy",}, {"name":"o_impossiblebuttonHM","order":4,"path":"objects/o_impossiblebuttonHM/o_impossiblebuttonHM.yy",}, + {"name":"o_infilandgamead","order":30,"path":"objects/o_infilandgamead/o_infilandgamead.yy",}, {"name":"o_infinitelivessettings","order":31,"path":"objects/o_infinitelivessettings/o_infinitelivessettings.yy",}, {"name":"o_info","order":6,"path":"objects/o_info/o_info.yy",}, {"name":"o_inputtext","order":22,"path":"objects/o_inputtext/o_inputtext.yy",}, @@ -739,7 +744,6 @@ {"name":"o_mediumsettings","order":53,"path":"objects/o_mediumsettings/o_mediumsettings.yy",}, {"name":"o_metallicskinbutton","order":11,"path":"objects/o_metallicskinbutton/o_metallicskinbutton.yy",}, {"name":"o_monocleskinbutton","order":12,"path":"objects/o_monocleskinbutton/o_monocleskinbutton.yy",}, - {"name":"o_monophobiaechoesad","order":1,"path":"objects/o_monophobiaechoesad/o_monophobiaechoesad.yy",}, {"name":"o_monthbuttonC","order":1,"path":"objects/o_monthbuttonC/o_monthbuttonC.yy",}, {"name":"o_movingchallengebutton","order":14,"path":"objects/o_movingchallengebutton/o_movingchallengebutton.yy",}, {"name":"o_movingplatforms","order":5,"path":"objects/o_movingplatforms/o_movingplatforms.yy",}, @@ -759,6 +763,7 @@ {"name":"o_newcalendarreward","order":4,"path":"objects/o_newcalendarreward/o_newcalendarreward.yy",}, {"name":"o_news","order":27,"path":"objects/o_news/o_news.yy",}, {"name":"o_newsbanner","order":6,"path":"objects/o_newsbanner/o_newsbanner.yy",}, + {"name":"o_noadsinmenusettings","order":60,"path":"objects/o_noadsinmenusettings/o_noadsinmenusettings.yy",}, {"name":"o_noclipsettings","order":39,"path":"objects/o_noclipsettings/o_noclipsettings.yy",}, {"name":"o_objcountersettings","order":42,"path":"objects/o_objcountersettings/o_objcountersettings.yy",}, {"name":"o_oldendlessbutton","order":1,"path":"objects/o_oldendlessbutton/o_oldendlessbutton.yy",}, @@ -885,7 +890,7 @@ {"name":"o_spawnthing","order":1,"path":"objects/o_spawnthing/o_spawnthing.yy",}, {"name":"o_specialcoin","order":5,"path":"objects/o_specialcoin/o_specialcoin.yy",}, {"name":"o_specialcoinLE","order":11,"path":"objects/o_specialcoinLE/o_specialcoinLE.yy",}, - {"name":"o_speciallevelsbutton","order":31,"path":"objects/o_speciallevelsbutton/o_speciallevelsbutton.yy",}, + {"name":"o_speciallevelsbutton","order":32,"path":"objects/o_speciallevelsbutton/o_speciallevelsbutton.yy",}, {"name":"o_speed10","order":17,"path":"objects/o_speed10/o_speed10.yy",}, {"name":"o_speed10LE","order":23,"path":"objects/o_speed10LE/o_speed10LE.yy",}, {"name":"o_speed15","order":18,"path":"objects/o_speed15/o_speed15.yy",}, @@ -1827,7 +1832,6 @@ {"name":"s_antideathAIcon","order":7,"path":"sprites/s_antideathAIcon/s_antideathAIcon.yy",}, {"name":"s_arrowplayerskin","order":1,"path":"sprites/s_arrowplayerskin/s_arrowplayerskin.yy",}, {"name":"s_arrowskinbutton","order":3,"path":"sprites/s_arrowskinbutton/s_arrowskinbutton.yy",}, - {"name":"s_asteroidsplusplusad","order":19,"path":"sprites/s_asteroidsplusplusad/s_asteroidsplusplusad.yy",}, {"name":"s_audiosettings","order":4,"path":"sprites/s_audiosettings/s_audiosettings.yy",}, {"name":"s_autopausesettings","order":18,"path":"sprites/s_autopausesettings/s_autopausesettings.yy",}, {"name":"s_autothumbnailsettings","order":42,"path":"sprites/s_autothumbnailsettings/s_autothumbnailsettings.yy",}, @@ -2169,6 +2173,7 @@ {"name":"s_iceblockbackground","order":5,"path":"sprites/s_iceblockbackground/s_iceblockbackground.yy",}, {"name":"s_iceblockbackgroundslope","order":5,"path":"sprites/s_iceblockbackgroundslope/s_iceblockbackgroundslope.yy",}, {"name":"s_iceblocksides","order":12,"path":"sprites/s_iceblocksides/s_iceblocksides.yy",}, + {"name":"s_infilandgamead","order":17,"path":"sprites/s_infilandgamead/s_infilandgamead.yy",}, {"name":"s_infinitelivessettings","order":30,"path":"sprites/s_infinitelivessettings/s_infinitelivessettings.yy",}, {"name":"s_invisibleAIcon","order":2,"path":"sprites/s_invisibleAIcon/s_invisibleAIcon.yy",}, {"name":"s_invisibleCHALLENGEAIcon","order":13,"path":"sprites/s_invisibleCHALLENGEAIcon/s_invisibleCHALLENGEAIcon.yy",}, @@ -2204,7 +2209,7 @@ {"name":"s_kaizoplayeryellow","order":2,"path":"sprites/s_kaizoplayeryellow/s_kaizoplayeryellow.yy",}, {"name":"s_kaizoskinbutton","order":2,"path":"sprites/s_kaizoskinbutton/s_kaizoskinbutton.yy",}, {"name":"s_key","order":21,"path":"sprites/s_key/s_key.yy",}, - {"name":"s_keybanner","order":23,"path":"sprites/s_keybanner/s_keybanner.yy",}, + {"name":"s_keybanner","order":21,"path":"sprites/s_keybanner/s_keybanner.yy",}, {"name":"s_kindadeadplayerskin","order":1,"path":"sprites/s_kindadeadplayerskin/s_kindadeadplayerskin.yy",}, {"name":"s_kindadeadskinbutton","order":15,"path":"sprites/s_kindadeadskinbutton/s_kindadeadskinbutton.yy",}, {"name":"s_kinghaticon","order":3,"path":"sprites/s_kinghaticon/s_kinghaticon.yy",}, @@ -2285,11 +2290,10 @@ {"name":"s_mediumsettings","order":46,"path":"sprites/s_mediumsettings/s_mediumsettings.yy",}, {"name":"s_metallicplayerskin","order":1,"path":"sprites/s_metallicplayerskin/s_metallicplayerskin.yy",}, {"name":"s_metallicskinbutton","order":9,"path":"sprites/s_metallicskinbutton/s_metallicskinbutton.yy",}, - {"name":"s_moddedbanner","order":24,"path":"sprites/s_moddedbanner/s_moddedbanner.yy",}, + {"name":"s_moddedbanner","order":22,"path":"sprites/s_moddedbanner/s_moddedbanner.yy",}, {"name":"s_monocleglassesoutfit","order":1,"path":"sprites/s_monocleglassesoutfit/s_monocleglassesoutfit.yy",}, {"name":"s_monocleplayerskin","order":2,"path":"sprites/s_monocleplayerskin/s_monocleplayerskin.yy",}, {"name":"s_monocleskinbutton","order":10,"path":"sprites/s_monocleskinbutton/s_monocleskinbutton.yy",}, - {"name":"s_monophobiaechoesad","order":20,"path":"sprites/s_monophobiaechoesad/s_monophobiaechoesad.yy",}, {"name":"s_movingAIcon","order":21,"path":"sprites/s_movingAIcon/s_movingAIcon.yy",}, {"name":"s_multiplayerchoosecontrols","order":3,"path":"sprites/s_multiplayerchoosecontrols/s_multiplayerchoosecontrols.yy",}, {"name":"s_multiplayerplayer3button","order":1,"path":"sprites/s_multiplayerplayer3button/s_multiplayerplayer3button.yy",}, @@ -2299,7 +2303,8 @@ {"name":"s_MUplayerhudarrow","order":6,"path":"sprites/s_MUplayerhudarrow/s_MUplayerhudarrow.yy",}, {"name":"s_musicdistortionsettings","order":19,"path":"sprites/s_musicdistortionsettings/s_musicdistortionsettings.yy",}, {"name":"s_musicsettings","order":13,"path":"sprites/s_musicsettings/s_musicsettings.yy",}, - {"name":"s_newsbanner","order":22,"path":"sprites/s_newsbanner/s_newsbanner.yy",}, + {"name":"s_newsbanner","order":20,"path":"sprites/s_newsbanner/s_newsbanner.yy",}, + {"name":"s_noadsinmenusettings","order":59,"path":"sprites/s_noadsinmenusettings/s_noadsinmenusettings.yy",}, {"name":"s_noclipsettings","order":37,"path":"sprites/s_noclipsettings/s_noclipsettings.yy",}, {"name":"s_nocollision","order":7,"path":"sprites/s_nocollision/s_nocollision.yy",}, {"name":"s_nostalgiasettings","order":20,"path":"sprites/s_nostalgiasettings/s_nostalgiasettings.yy",}, diff --git a/The Colorful Creature.yyp b/The Colorful Creature.yyp index 4842bfd25..d19ec84ec 100644 --- a/The Colorful Creature.yyp +++ b/The Colorful Creature.yyp @@ -11,6 +11,8 @@ }, "defaultScriptType":1, "Folders":[ + {"$GMFolder":"","%Name":"AdMob","folderPath":"folders/Extensions/AdMob.yy","name":"AdMob","resourceType":"GMFolder","resourceVersion":"2.0",}, + {"$GMFolder":"","%Name":"Mediations","folderPath":"folders/Extensions/AdMob/Mediations.yy","name":"Mediations","resourceType":"GMFolder","resourceVersion":"2.0",}, {"$GMFolder":"","%Name":"Animation Curves","folderPath":"folders/Animation Curves.yy","name":"Animation Curves","resourceType":"GMFolder","resourceVersion":"2.0",}, {"$GMFolder":"","%Name":"Extensions","folderPath":"folders/Extensions.yy","name":"Extensions","resourceType":"GMFolder","resourceVersion":"2.0",}, {"$GMFolder":"","%Name":"Fonts","folderPath":"folders/Fonts.yy","name":"Fonts","resourceType":"GMFolder","resourceVersion":"2.0",}, @@ -70,7 +72,6 @@ {"$GMFolder":"","%Name":"Hardmode","folderPath":"folders/Objects/Mainmenu/Hardmode.yy","name":"Hardmode","resourceType":"GMFolder","resourceVersion":"2.0",}, {"$GMFolder":"","%Name":"Iap Joke","folderPath":"folders/Objects/Mainmenu/Iap Joke.yy","name":"Iap Joke","resourceType":"GMFolder","resourceVersion":"2.0",}, {"$GMFolder":"","%Name":"Level Select","folderPath":"folders/Objects/Mainmenu/Level Select.yy","name":"Level Select","resourceType":"GMFolder","resourceVersion":"2.0",}, - {"$GMFolder":"","%Name":"New Games","folderPath":"folders/Objects/Mainmenu/New Games.yy","name":"New Games","resourceType":"GMFolder","resourceVersion":"2.0",}, {"$GMFolder":"","%Name":"Quests","folderPath":"folders/Objects/Mainmenu/Quests.yy","name":"Quests","resourceType":"GMFolder","resourceVersion":"2.0",}, {"$GMFolder":"","%Name":"Support","folderPath":"folders/Objects/Mainmenu/Support.yy","name":"Support","resourceType":"GMFolder","resourceVersion":"2.0",}, {"$GMFolder":"","%Name":"Contributors & Translators","folderPath":"folders/Objects/Mainmenu/Support/Contributors & Translators.yy","name":"Contributors & Translators","resourceType":"GMFolder","resourceVersion":"2.0",}, @@ -449,6 +450,11 @@ "name":"The Colorful Creature", "resources":[ {"id":{"name":"AdMob","path":"extensions/AdMob/AdMob.yy",},}, + {"id":{"name":"AdMobAppLovin","path":"extensions/AdMobAppLovin/AdMobAppLovin.yy",},}, + {"id":{"name":"AdMobIronSource","path":"extensions/AdMobIronSource/AdMobIronSource.yy",},}, + {"id":{"name":"AdMobMeta","path":"extensions/AdMobMeta/AdMobMeta.yy",},}, + {"id":{"name":"AdMobPangle","path":"extensions/AdMobPangle/AdMobPangle.yy",},}, + {"id":{"name":"AdMobUnityAds","path":"extensions/AdMobUnityAds/AdMobUnityAds.yy",},}, {"id":{"name":"Basic_Fake_3D","path":"extensions/Basic_Fake_3D/Basic_Fake_3D.yy",},}, {"id":{"name":"Color_Blindness_Simulation","path":"extensions/Color_Blindness_Simulation/Color_Blindness_Simulation.yy",},}, {"id":{"name":"GooglePlayService","path":"extensions/GooglePlayService/GooglePlayService.yy",},}, @@ -506,7 +512,6 @@ {"id":{"name":"o_anyblock","path":"objects/o_anyblock/o_anyblock.yy",},}, {"id":{"name":"o_anyitem","path":"objects/o_anyitem/o_anyitem.yy",},}, {"id":{"name":"o_arrowskinbutton","path":"objects/o_arrowskinbutton/o_arrowskinbutton.yy",},}, - {"id":{"name":"o_asteroidsplusplusad","path":"objects/o_asteroidsplusplusad/o_asteroidsplusplusad.yy",},}, {"id":{"name":"o_audiosettings","path":"objects/o_audiosettings/o_audiosettings.yy",},}, {"id":{"name":"o_autopausesettings","path":"objects/o_autopausesettings/o_autopausesettings.yy",},}, {"id":{"name":"o_autothumbnailsettings","path":"objects/o_autothumbnailsettings/o_autothumbnailsettings.yy",},}, @@ -808,6 +813,7 @@ {"id":{"name":"o_iceblockbackgroundslope","path":"objects/o_iceblockbackgroundslope/o_iceblockbackgroundslope.yy",},}, {"id":{"name":"o_impossiblebuttonHM","path":"objects/o_impossiblebuttonHM/o_impossiblebuttonHM.yy",},}, {"id":{"name":"o_indicatorandroid","path":"objects/o_indicatorandroid/o_indicatorandroid.yy",},}, + {"id":{"name":"o_infilandgamead","path":"objects/o_infilandgamead/o_infilandgamead.yy",},}, {"id":{"name":"o_infinitelivessettings","path":"objects/o_infinitelivessettings/o_infinitelivessettings.yy",},}, {"id":{"name":"o_info","path":"objects/o_info/o_info.yy",},}, {"id":{"name":"o_inputtext","path":"objects/o_inputtext/o_inputtext.yy",},}, @@ -917,7 +923,6 @@ {"id":{"name":"o_mediumsettings","path":"objects/o_mediumsettings/o_mediumsettings.yy",},}, {"id":{"name":"o_metallicskinbutton","path":"objects/o_metallicskinbutton/o_metallicskinbutton.yy",},}, {"id":{"name":"o_monocleskinbutton","path":"objects/o_monocleskinbutton/o_monocleskinbutton.yy",},}, - {"id":{"name":"o_monophobiaechoesad","path":"objects/o_monophobiaechoesad/o_monophobiaechoesad.yy",},}, {"id":{"name":"o_monthbuttonC","path":"objects/o_monthbuttonC/o_monthbuttonC.yy",},}, {"id":{"name":"o_movingchallengebutton","path":"objects/o_movingchallengebutton/o_movingchallengebutton.yy",},}, {"id":{"name":"o_movingplatforms","path":"objects/o_movingplatforms/o_movingplatforms.yy",},}, @@ -939,6 +944,7 @@ {"id":{"name":"o_newcalendarreward","path":"objects/o_newcalendarreward/o_newcalendarreward.yy",},}, {"id":{"name":"o_news","path":"objects/o_news/o_news.yy",},}, {"id":{"name":"o_newsbanner","path":"objects/o_newsbanner/o_newsbanner.yy",},}, + {"id":{"name":"o_noadsinmenusettings","path":"objects/o_noadsinmenusettings/o_noadsinmenusettings.yy",},}, {"id":{"name":"o_noclipsettings","path":"objects/o_noclipsettings/o_noclipsettings.yy",},}, {"id":{"name":"o_normalskinbutton","path":"objects/o_normalskinbutton/o_normalskinbutton.yy",},}, {"id":{"name":"o_objcountersettings","path":"objects/o_objcountersettings/o_objcountersettings.yy",},}, @@ -2138,7 +2144,6 @@ {"id":{"name":"s_antideathAIcon","path":"sprites/s_antideathAIcon/s_antideathAIcon.yy",},}, {"id":{"name":"s_arrowplayerskin","path":"sprites/s_arrowplayerskin/s_arrowplayerskin.yy",},}, {"id":{"name":"s_arrowskinbutton","path":"sprites/s_arrowskinbutton/s_arrowskinbutton.yy",},}, - {"id":{"name":"s_asteroidsplusplusad","path":"sprites/s_asteroidsplusplusad/s_asteroidsplusplusad.yy",},}, {"id":{"name":"s_audiosettings","path":"sprites/s_audiosettings/s_audiosettings.yy",},}, {"id":{"name":"s_autopausesettings","path":"sprites/s_autopausesettings/s_autopausesettings.yy",},}, {"id":{"name":"s_autothumbnailsettings","path":"sprites/s_autothumbnailsettings/s_autothumbnailsettings.yy",},}, @@ -2507,6 +2512,7 @@ {"id":{"name":"s_iceblockbackground","path":"sprites/s_iceblockbackground/s_iceblockbackground.yy",},}, {"id":{"name":"s_iceblockbackgroundslope","path":"sprites/s_iceblockbackgroundslope/s_iceblockbackgroundslope.yy",},}, {"id":{"name":"s_iceblocksides","path":"sprites/s_iceblocksides/s_iceblocksides.yy",},}, + {"id":{"name":"s_infilandgamead","path":"sprites/s_infilandgamead/s_infilandgamead.yy",},}, {"id":{"name":"s_infinitelivessettings","path":"sprites/s_infinitelivessettings/s_infinitelivessettings.yy",},}, {"id":{"name":"s_invisibleAIcon","path":"sprites/s_invisibleAIcon/s_invisibleAIcon.yy",},}, {"id":{"name":"s_invisibleCHALLENGEAIcon","path":"sprites/s_invisibleCHALLENGEAIcon/s_invisibleCHALLENGEAIcon.yy",},}, @@ -2636,7 +2642,6 @@ {"id":{"name":"s_monocleglassesoutfit","path":"sprites/s_monocleglassesoutfit/s_monocleglassesoutfit.yy",},}, {"id":{"name":"s_monocleplayerskin","path":"sprites/s_monocleplayerskin/s_monocleplayerskin.yy",},}, {"id":{"name":"s_monocleskinbutton","path":"sprites/s_monocleskinbutton/s_monocleskinbutton.yy",},}, - {"id":{"name":"s_monophobiaechoesad","path":"sprites/s_monophobiaechoesad/s_monophobiaechoesad.yy",},}, {"id":{"name":"s_movingAIcon","path":"sprites/s_movingAIcon/s_movingAIcon.yy",},}, {"id":{"name":"s_multiplayerchoosecontrols","path":"sprites/s_multiplayerchoosecontrols/s_multiplayerchoosecontrols.yy",},}, {"id":{"name":"s_multiplayerplayer2button","path":"sprites/s_multiplayerplayer2button/s_multiplayerplayer2button.yy",},}, @@ -2648,6 +2653,7 @@ {"id":{"name":"s_musicdistortionsettings","path":"sprites/s_musicdistortionsettings/s_musicdistortionsettings.yy",},}, {"id":{"name":"s_musicsettings","path":"sprites/s_musicsettings/s_musicsettings.yy",},}, {"id":{"name":"s_newsbanner","path":"sprites/s_newsbanner/s_newsbanner.yy",},}, + {"id":{"name":"s_noadsinmenusettings","path":"sprites/s_noadsinmenusettings/s_noadsinmenusettings.yy",},}, {"id":{"name":"s_noclipsettings","path":"sprites/s_noclipsettings/s_noclipsettings.yy",},}, {"id":{"name":"s_nocollision","path":"sprites/s_nocollision/s_nocollision.yy",},}, {"id":{"name":"s_nohaticon","path":"sprites/s_nohaticon/s_nohaticon.yy",},}, diff --git a/extensions/AdMob/AdMob.yy b/extensions/AdMob/AdMob.yy index 5febb2a7f..6fcd5c949 100644 --- a/extensions/AdMob/AdMob.yy +++ b/extensions/AdMob/AdMob.yy @@ -3,7 +3,7 @@ "%Name":"AdMob", "androidactivityinject":"", "androidclassname":"GoogleMobileAdsGM", - "androidcodeinjection":"\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n compileOptions {\r\n sourceCompatibility 1.8\r\n targetCompatibility 1.8\r\n }\r\n\r\n\r\n\r\n\r\n\r\nimplementation 'com.google.android.gms:play-services-ads:21.2.0'\r\nconstraints {\r\n implementation('androidx.work:work-runtime:2.7.0')\r\n}\r\n\r\n// The include below was giving issues uploading to the google store.\r\n//GDPR -> https://developers.google.com/admob/ump/android/quick-start\r\n// implementation 'com.google.android.ads.consent:consent-library:1.0.8'\r\n\r\n//Mediations Here:\r\n\r\n\r\n\r\n\r\n\r\n\r\n \r\n\r\n\r\n", + "androidcodeinjection":"\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n compileOptions {\r\n sourceCompatibility 1.8\r\n targetCompatibility 1.8\r\n }\r\n\r\n\r\n\r\n\r\n\r\nimplementation 'com.google.android.gms:play-services-ads:23.1.0'\r\nconstraints {\r\n implementation('androidx.work:work-runtime:2.7.0')\r\n}\r\n\r\n// The include below was giving issues uploading to the google store.\r\n//GDPR -> https://developers.google.com/admob/ump/android/quick-start\r\n// implementation 'com.google.android.ads.consent:consent-library:1.0.8'\r\n\r\n//Mediations Here:\r\n\r\n\r\n\r\n\r\n\r\n\r\n \r\n\r\n\r\n", "androidinject":"\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n", "androidmanifestinject":"\r\n \r\n", "androidPermissions":[ @@ -16,7 +16,7 @@ "copyToTargets":12, "description":"", "exportToGame":true, - "extensionVersion":"1.0.9", + "extensionVersion":"1.3.10", "files":[ {"$GMExtensionFile":"","%Name":"AdMob.ext","constants":[ {"$GMExtensionConstant":"","%Name":"AdMob_Banner_NORMAL","hidden":false,"name":"AdMob_Banner_NORMAL","resourceType":"GMExtensionConstant","resourceVersion":"2.0","value":"0",}, @@ -42,9 +42,20 @@ {"$GMExtensionConstant":"","%Name":"AdMob_Consent_Mode_DEBUG_GEOGRAPHY_EEA","hidden":false,"name":"AdMob_Consent_Mode_DEBUG_GEOGRAPHY_EEA","resourceType":"GMExtensionConstant","resourceVersion":"2.0","value":"1",}, {"$GMExtensionConstant":"","%Name":"AdMob_Consent_Mode_DEBUG_GEOGRAPHY_NOT_EEA","hidden":false,"name":"AdMob_Consent_Mode_DEBUG_GEOGRAPHY_NOT_EEA","resourceType":"GMExtensionConstant","resourceVersion":"2.0","value":"2",}, {"$GMExtensionConstant":"","%Name":"AdMob_Consent_Mode_PRODUCTION","hidden":false,"name":"AdMob_Consent_Mode_PRODUCTION","resourceType":"GMExtensionConstant","resourceVersion":"2.0","value":"3",}, + {"$GMExtensionConstant":"","%Name":"ADMOB_OK","hidden":false,"name":"ADMOB_OK","resourceType":"GMExtensionConstant","resourceVersion":"2.0","value":"0",}, + {"$GMExtensionConstant":"","%Name":"ADMOB_ERROR_NOT_INITIALIZED","hidden":false,"name":"ADMOB_ERROR_NOT_INITIALIZED","resourceType":"GMExtensionConstant","resourceVersion":"2.0","value":"-1",}, + {"$GMExtensionConstant":"","%Name":"ADMOB_ERROR_INVALID_AD_ID","hidden":false,"name":"ADMOB_ERROR_INVALID_AD_ID","resourceType":"GMExtensionConstant","resourceVersion":"2.0","value":"-2",}, + {"$GMExtensionConstant":"","%Name":"ADMOB_ERROR_AD_LIMIT_REACHED","hidden":false,"name":"ADMOB_ERROR_AD_LIMIT_REACHED","resourceType":"GMExtensionConstant","resourceVersion":"2.0","value":"-3",}, + {"$GMExtensionConstant":"","%Name":"ADMOB_ERROR_NO_ADS_LOADED","hidden":false,"name":"ADMOB_ERROR_NO_ADS_LOADED","resourceType":"GMExtensionConstant","resourceVersion":"2.0","value":"-4",}, + {"$GMExtensionConstant":"","%Name":"ADMOB_ERROR_NO_ACTIVE_BANNER_AD","hidden":false,"name":"ADMOB_ERROR_NO_ACTIVE_BANNER_AD","resourceType":"GMExtensionConstant","resourceVersion":"2.0","value":"-5",}, + {"$GMExtensionConstant":"","%Name":"ADMOB_ERROR_ILLEGAL_CALL","hidden":false,"name":"ADMOB_ERROR_ILLEGAL_CALL","resourceType":"GMExtensionConstant","resourceVersion":"2.0","value":"-6",}, + {"$GMExtensionConstant":"","%Name":"ADMOB_ADVALUE_PRECISION_UNKNOWN","hidden":false,"name":"ADMOB_ADVALUE_PRECISION_UNKNOWN","resourceType":"GMExtensionConstant","resourceVersion":"2.0","value":"0",}, + {"$GMExtensionConstant":"","%Name":"ADMOB_ADVALUE_PRECISION_ESTIMATED","hidden":false,"name":"ADMOB_ADVALUE_PRECISION_ESTIMATED","resourceType":"GMExtensionConstant","resourceVersion":"2.0","value":"1",}, + {"$GMExtensionConstant":"","%Name":"ADMOB_ADVALUE_PRECISION_PUBLISHER_PROVIDED","hidden":false,"name":"ADMOB_ADVALUE_PRECISION_PUBLISHER_PROVIDED","resourceType":"GMExtensionConstant","resourceVersion":"2.0","value":"2",}, + {"$GMExtensionConstant":"","%Name":"ADMOB_ADVALUE_PRECISION_PRECISE","hidden":false,"name":"ADMOB_ADVALUE_PRECISION_PRECISE","resourceType":"GMExtensionConstant","resourceVersion":"2.0","value":"3",}, ],"copyToTargets":-1,"filename":"AdMob.ext","final":"","functions":[ {"$GMExtensionFunction":"","%Name":"AdMob_Initialize","argCount":1,"args":[],"documentation":"","externalName":"AdMob_Initialize","help":"AdMob_Initialize()","hidden":false,"kind":11,"name":"AdMob_Initialize","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, - {"$GMExtensionFunction":"","%Name":"AdMob_Interstitial_Init","argCount":1,"args":[1,],"documentation":"","externalName":"AdMob_Interstitial_Init","help":"AdMob_Interstitial_Init(interstitialID)","hidden":false,"kind":11,"name":"AdMob_Interstitial_Init","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, + {"$GMExtensionFunction":"","%Name":"AdMob_Interstitial_Set_AdUnit","argCount":1,"args":[1,],"documentation":"","externalName":"AdMob_Interstitial_Set_AdUnit","help":"AdMob_Interstitial_Set_AdUnit(interstitialID)","hidden":false,"kind":11,"name":"AdMob_Interstitial_Set_AdUnit","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, {"$GMExtensionFunction":"","%Name":"AdMob_Interstitial_Load","argCount":0,"args":[],"documentation":"","externalName":"AdMob_Interstitial_Load","help":"AdMob_Interstitial_Load()","hidden":false,"kind":11,"name":"AdMob_Interstitial_Load","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, {"$GMExtensionFunction":"","%Name":"AdMob_Banner_Create","argCount":4,"args":[2,2,],"documentation":"","externalName":"AdMob_Banner_Create","help":"AdMob_Banner_Create(size,bottom)","hidden":false,"kind":11,"name":"AdMob_Banner_Create","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, {"$GMExtensionFunction":"","%Name":"AdMob_Interstitial_Show","argCount":0,"args":[],"documentation":"","externalName":"AdMob_Interstitial_Show","help":"AdMob_Interstitial_Show()","hidden":false,"kind":11,"name":"AdMob_Interstitial_Show","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, @@ -52,12 +63,12 @@ {"$GMExtensionFunction":"","%Name":"AdMob_RewardedVideo_Load","argCount":0,"args":[],"documentation":"","externalName":"AdMob_RewardedVideo_Load","help":"AdMob_RewardedVideo_Load()","hidden":false,"kind":11,"name":"AdMob_RewardedVideo_Load","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, {"$GMExtensionFunction":"","%Name":"AdMob_RewardedVideo_IsLoaded","argCount":0,"args":[],"documentation":"","externalName":"AdMob_RewardedVideo_IsLoaded","help":"AdMob_RewardedVideo_IsLoaded()","hidden":false,"kind":11,"name":"AdMob_RewardedVideo_IsLoaded","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, {"$GMExtensionFunction":"","%Name":"AdMob_RewardedVideo_Show","argCount":0,"args":[],"documentation":"","externalName":"AdMob_RewardedVideo_Show","help":"AdMob_RewardedVideo_Show()","hidden":false,"kind":11,"name":"AdMob_RewardedVideo_Show","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, - {"$GMExtensionFunction":"","%Name":"AdMob_RewardedVideo_Init","argCount":1,"args":[1,],"documentation":"","externalName":"AdMob_RewardedVideo_Init","help":"AdMob_RewardedVideo_Init(RewardedID)","hidden":false,"kind":11,"name":"AdMob_RewardedVideo_Init","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, + {"$GMExtensionFunction":"","%Name":"AdMob_RewardedVideo_Set_AdUnit","argCount":1,"args":[1,],"documentation":"","externalName":"AdMob_RewardedVideo_Set_AdUnit","help":"AdMob_RewardedVideo_Set_AdUnit(RewardedID)","hidden":false,"kind":11,"name":"AdMob_RewardedVideo_Set_AdUnit","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, {"$GMExtensionFunction":"","%Name":"AdMob_Banner_Remove","argCount":0,"args":[],"documentation":"","externalName":"AdMob_Banner_Remove","help":"AdMob_Banner_Remove()","hidden":false,"kind":11,"name":"AdMob_Banner_Remove","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, - {"$GMExtensionFunction":"","%Name":"AdMob_Banner_Move","argCount":0,"args":[2,],"documentation":"","externalName":"AdMob_Banner_Move","help":"AdMob_Banner_Move(bottom)","hidden":false,"kind":4,"name":"AdMob_Banner_Move","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, - {"$GMExtensionFunction":"","%Name":"AdMob_Banner_Hide","argCount":0,"args":[],"documentation":"","externalName":"AdMob_Banner_Hide","help":"AdMob_Banner_Hide()","hidden":false,"kind":4,"name":"AdMob_Banner_Hide","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, - {"$GMExtensionFunction":"","%Name":"AdMob_Banner_Show","argCount":0,"args":[],"documentation":"","externalName":"AdMob_Banner_Show","help":"AdMob_Banner_Show()","hidden":false,"kind":4,"name":"AdMob_Banner_Show","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, - {"$GMExtensionFunction":"","%Name":"AdMob_Banner_Init","argCount":0,"args":[1,],"documentation":"","externalName":"AdMob_Banner_Init","help":"AdMob_Banner_Init(bannerId)","hidden":false,"kind":4,"name":"AdMob_Banner_Init","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, + {"$GMExtensionFunction":"","%Name":"AdMob_Banner_Move","argCount":0,"args":[2,],"documentation":"","externalName":"AdMob_Banner_Move","help":"AdMob_Banner_Move(bottom)","hidden":false,"kind":4,"name":"AdMob_Banner_Move","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, + {"$GMExtensionFunction":"","%Name":"AdMob_Banner_Hide","argCount":0,"args":[],"documentation":"","externalName":"AdMob_Banner_Hide","help":"AdMob_Banner_Hide()","hidden":false,"kind":4,"name":"AdMob_Banner_Hide","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, + {"$GMExtensionFunction":"","%Name":"AdMob_Banner_Show","argCount":0,"args":[],"documentation":"","externalName":"AdMob_Banner_Show","help":"AdMob_Banner_Show()","hidden":false,"kind":4,"name":"AdMob_Banner_Show","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, + {"$GMExtensionFunction":"","%Name":"AdMob_Banner_Set_AdUnit","argCount":0,"args":[1,],"documentation":"","externalName":"AdMob_Banner_Set_AdUnit","help":"AdMob_Banner_Set_AdUnit(bannerId)","hidden":false,"kind":4,"name":"AdMob_Banner_Set_AdUnit","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, {"$GMExtensionFunction":"","%Name":"AdMob_SetTestDeviceId","argCount":0,"args":[],"documentation":"","externalName":"AdMob_SetTestDeviceId","help":"AdMob_SetTestDeviceId()","hidden":false,"kind":4,"name":"AdMob_SetTestDeviceId","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, {"$GMExtensionFunction":"","%Name":"AdMob_Consent_RequestInfoUpdate","argCount":0,"args":[2,],"documentation":"","externalName":"AdMob_Consent_RequestInfoUpdate","help":"AdMob_Consent_RequestInfoUpdate(testing)","hidden":false,"kind":4,"name":"AdMob_Consent_RequestInfoUpdate","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, {"$GMExtensionFunction":"","%Name":"AdMob_Consent_Load","argCount":0,"args":[],"documentation":"","externalName":"AdMob_Consent_Load","help":"AdMob_Consent_Load()","hidden":false,"kind":4,"name":"AdMob_Consent_Load","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, @@ -66,21 +77,40 @@ {"$GMExtensionFunction":"","%Name":"AdMob_Consent_GetType","argCount":0,"args":[],"documentation":"","externalName":"AdMob_Consent_GetType","help":"AdMob_Consent_GetType()","hidden":false,"kind":4,"name":"AdMob_Consent_GetType","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, {"$GMExtensionFunction":"","%Name":"AdMob_Consent_IsFormAvailable","argCount":0,"args":[],"documentation":"","externalName":"AdMob_Consent_IsFormAvailable","help":"AdMob_Consent_IsFormAvailable()","hidden":false,"kind":4,"name":"AdMob_Consent_IsFormAvailable","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, {"$GMExtensionFunction":"","%Name":"AdMob_Consent_GetStatus","argCount":0,"args":[],"documentation":"","externalName":"AdMob_Consent_GetStatus","help":"AdMob_Consent_GetStatus()","hidden":false,"kind":4,"name":"AdMob_Consent_GetStatus","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, - {"$GMExtensionFunction":"","%Name":"AdMob_Targeting_COPPA","argCount":0,"args":[2,],"documentation":"","externalName":"AdMob_Targeting_COPPA","help":"AdMob_Targeting_COPPA(bool)","hidden":false,"kind":4,"name":"AdMob_Targeting_COPPA","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, - {"$GMExtensionFunction":"","%Name":"AdMob_Targeting_UnderAge","argCount":0,"args":[2,],"documentation":"","externalName":"AdMob_Targeting_UnderAge","help":"AdMob_Targeting_UnderAge(bool)","hidden":false,"kind":4,"name":"AdMob_Targeting_UnderAge","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, - {"$GMExtensionFunction":"","%Name":"AdMob_Targeting_MaxAdContentRating","argCount":0,"args":[2,],"documentation":"","externalName":"AdMob_Targeting_MaxAdContentRating","help":"AdMob_Targeting_MaxAdContentRating(maxRanking)","hidden":false,"kind":4,"name":"AdMob_Targeting_MaxAdContentRating","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, + {"$GMExtensionFunction":"","%Name":"AdMob_Targeting_COPPA","argCount":0,"args":[2,],"documentation":"","externalName":"AdMob_Targeting_COPPA","help":"AdMob_Targeting_COPPA(bool)","hidden":false,"kind":4,"name":"AdMob_Targeting_COPPA","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, + {"$GMExtensionFunction":"","%Name":"AdMob_Targeting_UnderAge","argCount":0,"args":[2,],"documentation":"","externalName":"AdMob_Targeting_UnderAge","help":"AdMob_Targeting_UnderAge(bool)","hidden":false,"kind":4,"name":"AdMob_Targeting_UnderAge","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, + {"$GMExtensionFunction":"","%Name":"AdMob_Targeting_MaxAdContentRating","argCount":0,"args":[2,],"documentation":"","externalName":"AdMob_Targeting_MaxAdContentRating","help":"AdMob_Targeting_MaxAdContentRating(maxRanking)","hidden":false,"kind":4,"name":"AdMob_Targeting_MaxAdContentRating","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, {"$GMExtensionFunction":"","%Name":"AdMob_Banner_GetWidth","argCount":0,"args":[],"documentation":"","externalName":"AdMob_Banner_GetWidth","help":"AdMob_Banner_GetWidth()","hidden":false,"kind":4,"name":"AdMob_Banner_GetWidth","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, {"$GMExtensionFunction":"","%Name":"AdMob_Banner_GetHeight","argCount":0,"args":[],"documentation":"","externalName":"AdMob_Banner_GetHeight","help":"AdMob_Banner_GetHeight()","hidden":false,"kind":4,"name":"AdMob_Banner_GetHeight","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, {"$GMExtensionFunction":"","%Name":"AdMob_Settings_SetVolume","argCount":0,"args":[2,],"documentation":"","externalName":"AdMob_Settings_SetVolume","help":"AdMob_Settings_SetVolume(volume)","hidden":false,"kind":4,"name":"AdMob_Settings_SetVolume","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, {"$GMExtensionFunction":"","%Name":"AdMob_Settings_SetMuted","argCount":0,"args":[2,],"documentation":"","externalName":"AdMob_Settings_SetMuted","help":"AdMob_Settings_SetMuted(bool)","hidden":false,"kind":4,"name":"AdMob_Settings_SetMuted","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, - {"$GMExtensionFunction":"","%Name":"AdMob_RewardedInterstitial_Init","argCount":0,"args":[1,],"documentation":"","externalName":"AdMob_RewardedInterstitial_Init","help":"AdMob_RewardedInterstitial_Init(id)","hidden":false,"kind":4,"name":"AdMob_RewardedInterstitial_Init","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, - {"$GMExtensionFunction":"","%Name":"AdMob_RewardedInterstitial_Load","argCount":0,"args":[],"documentation":"","externalName":"AdMob_RewardedInterstitial_Load","help":"AdMob_RewardedInterstitial_Load()","hidden":false,"kind":4,"name":"AdMob_RewardedInterstitial_Load","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, - {"$GMExtensionFunction":"","%Name":"AdMob_RewardedInterstitial_Show","argCount":0,"args":[],"documentation":"","externalName":"AdMob_RewardedInterstitial_Show","help":"AdMob_RewardedInterstitial_Show()","hidden":false,"kind":4,"name":"AdMob_RewardedInterstitial_Show","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, + {"$GMExtensionFunction":"","%Name":"AdMob_RewardedInterstitial_Set_AdUnit","argCount":0,"args":[1,],"documentation":"","externalName":"AdMob_RewardedInterstitial_Set_AdUnit","help":"AdMob_RewardedInterstitial_Set_AdUnit(id)","hidden":false,"kind":4,"name":"AdMob_RewardedInterstitial_Set_AdUnit","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, + {"$GMExtensionFunction":"","%Name":"AdMob_RewardedInterstitial_Load","argCount":0,"args":[],"documentation":"","externalName":"AdMob_RewardedInterstitial_Load","help":"AdMob_RewardedInterstitial_Load()","hidden":false,"kind":4,"name":"AdMob_RewardedInterstitial_Load","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, + {"$GMExtensionFunction":"","%Name":"AdMob_RewardedInterstitial_Show","argCount":0,"args":[],"documentation":"","externalName":"AdMob_RewardedInterstitial_Show","help":"AdMob_RewardedInterstitial_Show()","hidden":false,"kind":4,"name":"AdMob_RewardedInterstitial_Show","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, {"$GMExtensionFunction":"","%Name":"AdMob_RewardedInterstitial_IsLoaded","argCount":0,"args":[],"documentation":"","externalName":"AdMob_RewardedInterstitial_IsLoaded","help":"AdMob_RewardedInterstitial_IsLoaded()","hidden":false,"kind":4,"name":"AdMob_RewardedInterstitial_IsLoaded","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, {"$GMExtensionFunction":"","%Name":"AdMob_NonPersonalizedAds_Set","argCount":0,"args":[2,],"documentation":"","externalName":"AdMob_NonPersonalizedAds_Set","help":"AdMob_NonPersonalizedAds_Set(value)","hidden":false,"kind":4,"name":"AdMob_NonPersonalizedAds_Set","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, + {"$GMExtensionFunction":"","%Name":"AdMob_AppOpenAd_Set_AdUnit","argCount":0,"args":[1,],"documentation":"","externalName":"AdMob_AppOpenAd_Set_AdUnit","help":"AdMob_AppOpenAd_Set_AdUnit(String adUnitId)","hidden":false,"kind":4,"name":"AdMob_AppOpenAd_Set_AdUnit","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, + {"$GMExtensionFunction":"","%Name":"Admob_Interstitial_Max_Instances","argCount":0,"args":[2,],"documentation":"","externalName":"Admob_Interstitial_Max_Instances","help":"Admob_Interstitial_Max_Instances(value)","hidden":false,"kind":4,"name":"Admob_Interstitial_Max_Instances","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, + {"$GMExtensionFunction":"","%Name":"AdMob_RewardedVideo_Max_Instances","argCount":0,"args":[2,],"documentation":"","externalName":"AdMob_RewardedVideo_Max_Instances","help":"AdMob_RewardedVideo_Max_Instances(value)","hidden":false,"kind":4,"name":"AdMob_RewardedVideo_Max_Instances","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, + {"$GMExtensionFunction":"","%Name":"AdMob_RewardedInterstitial_Max_Instances","argCount":0,"args":[2,],"documentation":"","externalName":"AdMob_RewardedInterstitial_Max_Instances","help":"AdMob_RewardedInterstitial_Max_Instances(value)","hidden":false,"kind":4,"name":"AdMob_RewardedInterstitial_Max_Instances","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, + {"$GMExtensionFunction":"","%Name":"AdMob_Events_OnPaidEvent","argCount":0,"args":[2,],"documentation":"","externalName":"AdMob_Events_OnPaidEvent","help":"AdMob_Events_OnPaidEvent(enable)","hidden":false,"kind":4,"name":"AdMob_Events_OnPaidEvent","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, + {"$GMExtensionFunction":"","%Name":"Admob_Interstitial_Free_Loaded_Instances","argCount":0,"args":[2,],"documentation":"","externalName":"Admob_Interstitial_Free_Loaded_Instances","help":"Admob_Interstitial_Free_Loaded_Instances(num)","hidden":false,"kind":4,"name":"Admob_Interstitial_Free_Loaded_Instances","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, + {"$GMExtensionFunction":"","%Name":"AdMob_RewardedVideo_Free_Loaded_Instances","argCount":0,"args":[2,],"documentation":"","externalName":"AdMob_RewardedVideo_Free_Loaded_Instances","help":"AdMob_RewardedVideo_Free_Loaded_Instances(num)","hidden":false,"kind":4,"name":"AdMob_RewardedVideo_Free_Loaded_Instances","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, + {"$GMExtensionFunction":"","%Name":"AdMob_RewardedInterstitial_Free_Loaded_Instances","argCount":0,"args":[2,],"documentation":"","externalName":"AdMob_RewardedInterstitial_Free_Loaded_Instances","help":"AdMob_RewardedInterstitial_Free_Loaded_Instances(num)","hidden":false,"kind":4,"name":"AdMob_RewardedInterstitial_Free_Loaded_Instances","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, + {"$GMExtensionFunction":"","%Name":"AdMob_AppOpenAd_Enable","argCount":0,"args":[2,],"documentation":"","externalName":"AdMob_AppOpenAd_Enable","help":"AdMob_AppOpenAd_Enable(orientation)","hidden":false,"kind":4,"name":"AdMob_AppOpenAd_Enable","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, + {"$GMExtensionFunction":"","%Name":"AdMob_AppOpenAd_IsEnabled","argCount":0,"args":[],"documentation":"","externalName":"AdMob_AppOpenAd_IsEnabled","help":"AdMob_AppOpenAd_IsEnabled()","hidden":false,"kind":4,"name":"AdMob_AppOpenAd_IsEnabled","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, + {"$GMExtensionFunction":"","%Name":"AdMob_AppOpenAd_Disable","argCount":0,"args":[],"documentation":"","externalName":"AdMob_AppOpenAd_Disable","help":"AdMob_AppOpenAd_Disable()","hidden":false,"kind":4,"name":"AdMob_AppOpenAd_Disable","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, + {"$GMExtensionFunction":"","%Name":"AdMob_Interstitial_Instances_Count","argCount":0,"args":[],"documentation":"","externalName":"AdMob_Interstitial_Instances_Count","help":"AdMob_Interstitial_Instances_Count()","hidden":false,"kind":4,"name":"AdMob_Interstitial_Instances_Count","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, + {"$GMExtensionFunction":"","%Name":"AdMob_RewardedVideo_Instances_Count","argCount":0,"args":[],"documentation":"","externalName":"AdMob_RewardedVideo_Instances_Count","help":"AdMob_RewardedVideo_Instances_Count()","hidden":false,"kind":4,"name":"AdMob_RewardedVideo_Instances_Count","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, + {"$GMExtensionFunction":"","%Name":"AdMob_RewardedInterstitial_Instances_Count","argCount":0,"args":[],"documentation":"","externalName":"AdMob_RewardedInterstitial_Instances_Count","help":"AdMob_RewardedInterstitial_Instances_Count()","hidden":false,"kind":4,"name":"AdMob_RewardedInterstitial_Instances_Count","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, + {"$GMExtensionFunction":"","%Name":"AdMob_Interstitial_Init","argCount":0,"args":[1,],"documentation":"/// @deprected","externalName":"AdMob_Interstitial_Set_AdUnit","help":"AdMob_Interstitial_Init(unitId)","hidden":false,"kind":4,"name":"AdMob_Interstitial_Init","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, + {"$GMExtensionFunction":"","%Name":"AdMob_RewardedVideo_Init","argCount":0,"args":[1,],"documentation":"/// @deprected","externalName":"AdMob_RewardedVideo_Set_AdUnit","help":"AdMob_RewardedVideo_Init(unitId)","hidden":false,"kind":4,"name":"AdMob_RewardedVideo_Init","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, + {"$GMExtensionFunction":"","%Name":"AdMob_RewardedInterstitial_Init","argCount":0,"args":[1,],"documentation":"/// @deprected","externalName":"AdMob_RewardedInterstitial_Set_AdUnit","help":"AdMob_RewardedInterstitial_Init(unitId)","hidden":false,"kind":4,"name":"AdMob_RewardedInterstitial_Init","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, + {"$GMExtensionFunction":"","%Name":"AdMob_AppOpenAd_Init","argCount":0,"args":[1,],"documentation":"/// @deprected","externalName":"AdMob_AppOpenAd_Set_AdUnit","help":"AdMob_AppOpenAd_Init(unitId)","hidden":false,"kind":4,"name":"AdMob_AppOpenAd_Init","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, + {"$GMExtensionFunction":"","%Name":"AdMob_Banner_Init","argCount":0,"args":[1,],"documentation":"/// @deprected","externalName":"AdMob_Banner_Set_AdUnit","help":"AdMob_Banner_Init(adUnit)","hidden":false,"kind":4,"name":"AdMob_Banner_Init","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, ],"init":"","kind":4,"name":"AdMob.ext","order":[ {"name":"AdMob_Initialize","path":"extensions/AdMob/AdMob.yy",}, - {"name":"AdMob_Interstitial_Init","path":"extensions/AdMob/AdMob.yy",}, + {"name":"AdMob_Interstitial_Set_AdUnit","path":"extensions/AdMob/AdMob.yy",}, {"name":"AdMob_Interstitial_Load","path":"extensions/AdMob/AdMob.yy",}, {"name":"AdMob_Banner_Create","path":"extensions/AdMob/AdMob.yy",}, {"name":"AdMob_Interstitial_Show","path":"extensions/AdMob/AdMob.yy",}, @@ -88,12 +118,12 @@ {"name":"AdMob_RewardedVideo_Load","path":"extensions/AdMob/AdMob.yy",}, {"name":"AdMob_RewardedVideo_IsLoaded","path":"extensions/AdMob/AdMob.yy",}, {"name":"AdMob_RewardedVideo_Show","path":"extensions/AdMob/AdMob.yy",}, - {"name":"AdMob_RewardedVideo_Init","path":"extensions/AdMob/AdMob.yy",}, + {"name":"AdMob_RewardedVideo_Set_AdUnit","path":"extensions/AdMob/AdMob.yy",}, {"name":"AdMob_Banner_Remove","path":"extensions/AdMob/AdMob.yy",}, {"name":"AdMob_Banner_Move","path":"extensions/AdMob/AdMob.yy",}, {"name":"AdMob_Banner_Hide","path":"extensions/AdMob/AdMob.yy",}, {"name":"AdMob_Banner_Show","path":"extensions/AdMob/AdMob.yy",}, - {"name":"AdMob_Banner_Init","path":"extensions/AdMob/AdMob.yy",}, + {"name":"AdMob_Banner_Set_AdUnit","path":"extensions/AdMob/AdMob.yy",}, {"name":"AdMob_SetTestDeviceId","path":"extensions/AdMob/AdMob.yy",}, {"name":"AdMob_Consent_RequestInfoUpdate","path":"extensions/AdMob/AdMob.yy",}, {"name":"AdMob_Consent_Load","path":"extensions/AdMob/AdMob.yy",}, @@ -109,14 +139,23 @@ {"name":"AdMob_Banner_GetHeight","path":"extensions/AdMob/AdMob.yy",}, {"name":"AdMob_Settings_SetVolume","path":"extensions/AdMob/AdMob.yy",}, {"name":"AdMob_Settings_SetMuted","path":"extensions/AdMob/AdMob.yy",}, - {"name":"AdMob_RewardedInterstitial_Init","path":"extensions/AdMob/AdMob.yy",}, + {"name":"AdMob_RewardedInterstitial_Set_AdUnit","path":"extensions/AdMob/AdMob.yy",}, {"name":"AdMob_RewardedInterstitial_Load","path":"extensions/AdMob/AdMob.yy",}, {"name":"AdMob_RewardedInterstitial_Show","path":"extensions/AdMob/AdMob.yy",}, {"name":"AdMob_RewardedInterstitial_IsLoaded","path":"extensions/AdMob/AdMob.yy",}, {"name":"AdMob_NonPersonalizedAds_Set","path":"extensions/AdMob/AdMob.yy",}, + {"name":"Admob_Interstitial_Max_Instances","path":"extensions/AdMob/AdMob.yy",}, + {"name":"AdMob_RewardedVideo_Max_Instances","path":"extensions/AdMob/AdMob.yy",}, + {"name":"AdMob_RewardedInterstitial_Max_Instances","path":"extensions/AdMob/AdMob.yy",}, + {"name":"AdMob_Events_OnPaidEvent","path":"extensions/AdMob/AdMob.yy",}, + {"name":"Admob_Interstitial_Free_Loaded_Instances","path":"extensions/AdMob/AdMob.yy",}, + {"name":"AdMob_RewardedVideo_Free_Loaded_Instances","path":"extensions/AdMob/AdMob.yy",}, + {"name":"AdMob_RewardedInterstitial_Free_Loaded_Instances","path":"extensions/AdMob/AdMob.yy",}, + {"name":"AdMob_AppOpenAd_Set_AdUnit","path":"extensions/AdMob/AdMob.yy",}, + {"name":"AdMob_AppOpenAd_Enable","path":"extensions/AdMob/AdMob.yy",}, ],"origname":"","ProxyFiles":[],"resourceType":"GMExtensionFile","resourceVersion":"2.0","uncompress":false,"usesRunnerInterface":false,}, ], - "gradleinject":"\r\n\r\nimplementation 'com.google.android.gms:play-services-ads:21.2.0'\r\nconstraints {\r\n implementation('androidx.work:work-runtime:2.7.0')\r\n}\r\n\r\n// The include below was giving issues uploading to the google store.\r\n//GDPR -> https://developers.google.com/admob/ump/android/quick-start\r\n// implementation 'com.google.android.ads.consent:consent-library:1.0.8'\r\n\r\n//Mediations Here:\r\n\r\n\r\n", + "gradleinject":"\r\n\r\nimplementation 'com.google.android.gms:play-services-ads:23.1.0'\r\nconstraints {\r\n implementation('androidx.work:work-runtime:2.7.0')\r\n}\r\n\r\n// The include below was giving issues uploading to the google store.\r\n//GDPR -> https://developers.google.com/admob/ump/android/quick-start\r\n// implementation 'com.google.android.ads.consent:consent-library:1.0.8'\r\n\r\n//Mediations Here:\r\n\r\n\r\n", "hasConvertedCodeInjection":true, "helpfile":"", "HTML5CodeInjection":"", @@ -124,10 +163,10 @@ "IncludedResources":[], "installdir":"", "iosCocoaPodDependencies":"", - "iosCocoaPods":"\r\n\r\npod 'Google-Mobile-Ads-SDK'\r\n\r\n", - "ioscodeinjection":"\r\nGADIsAdManagerApp\r\n \r\n\r\nGADApplicationIdentifier\r\n${YYEXTOPT_AdMob_iOS_AppID}\r\n\r\nSKAdNetworkItems\r\n\r\n\r\nSKAdNetworkIdentifier\r\ncstr6suwn9.skadnetwork\r\n\r\n\r\n\r\n\r\n\r\n\r\npod 'Google-Mobile-Ads-SDK'\r\n\r\n\r\n\r\n", + "iosCocoaPods":"\r\npod 'Google-Mobile-Ads-SDK', '11.4.0'\r\n\r\n", + "ioscodeinjection":"\r\nGADIsAdManagerApp\r\n \r\n\r\nGADApplicationIdentifier\r\n${YYEXTOPT_AdMob_iOS_AppID}\r\n\r\nSKAdNetworkItems\r\n\r\n\r\n SKAdNetworkIdentifier\r\n cstr6suwn9.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n 4fzdc2evr5.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n 4pfyvq9l8r.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n 2fnua5tdw4.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n ydx93a7ass.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n 5a6flpkh64.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n p78axxw29g.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n v72qych5uu.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n ludvb6z3bs.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n cp8zw746q7.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n 3sh42y64q3.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n c6k4g5qg8m.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n s39g8k73mm.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n 3qy4746246.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n f38h382jlk.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n hs6bdukanm.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n v4nxqhlyqp.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n wzmmz9fp6w.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n yclnxrl5pm.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n t38b2kh725.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n 7ug5zh24hu.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n gta9lk7p23.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n vutu7akeur.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n y5ghdn5j9k.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n n6fk4nfna4.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n v9wttpbfk9.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n n38lu8286q.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n 47vhws6wlr.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n kbd757ywx3.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n 9t245vhmpl.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n eh6m2bh4zr.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n a2p9lx4jpn.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n 22mmun2rn5.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n 4468km3ulz.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n 2u9pt9hc89.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n 8s468mfl3y.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n klf5c3l5u5.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n ppxm28t8ap.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n ecpz2srf59.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n uw77j35x4d.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n pwa73g5rt2.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n mlmmfzh3r3.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n 578prtvx9j.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n 4dzt52r2t5.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n e5fvkxwrpn.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n 8c4e2ghe7u.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n zq492l623r.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n 3rd42ekr43.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n 3qcr597p9d.skadnetwork\r\n \r\n\r\n\r\n\r\n\r\npod 'Google-Mobile-Ads-SDK', '11.4.0'\r\n\r\n\r\n\r\n", "iosdelegatename":"", - "iosplistinject":"\r\nGADIsAdManagerApp\r\n \r\n\r\nGADApplicationIdentifier\r\n${YYEXTOPT_AdMob_iOS_AppID}\r\n\r\nSKAdNetworkItems\r\n\r\n\r\nSKAdNetworkIdentifier\r\ncstr6suwn9.skadnetwork\r\n\r\n\r\n", + "iosplistinject":"\r\nGADIsAdManagerApp\r\n \r\n\r\nGADApplicationIdentifier\r\n${YYEXTOPT_AdMob_iOS_AppID}\r\n\r\nSKAdNetworkItems\r\n\r\n\r\n SKAdNetworkIdentifier\r\n cstr6suwn9.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n 4fzdc2evr5.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n 4pfyvq9l8r.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n 2fnua5tdw4.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n ydx93a7ass.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n 5a6flpkh64.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n p78axxw29g.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n v72qych5uu.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n ludvb6z3bs.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n cp8zw746q7.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n 3sh42y64q3.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n c6k4g5qg8m.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n s39g8k73mm.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n 3qy4746246.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n f38h382jlk.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n hs6bdukanm.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n v4nxqhlyqp.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n wzmmz9fp6w.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n yclnxrl5pm.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n t38b2kh725.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n 7ug5zh24hu.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n gta9lk7p23.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n vutu7akeur.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n y5ghdn5j9k.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n n6fk4nfna4.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n v9wttpbfk9.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n n38lu8286q.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n 47vhws6wlr.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n kbd757ywx3.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n 9t245vhmpl.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n eh6m2bh4zr.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n a2p9lx4jpn.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n 22mmun2rn5.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n 4468km3ulz.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n 2u9pt9hc89.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n 8s468mfl3y.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n klf5c3l5u5.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n ppxm28t8ap.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n ecpz2srf59.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n uw77j35x4d.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n pwa73g5rt2.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n mlmmfzh3r3.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n 578prtvx9j.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n 4dzt52r2t5.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n e5fvkxwrpn.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n 8c4e2ghe7u.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n zq492l623r.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n 3rd42ekr43.skadnetwork\r\n \r\n \r\n SKAdNetworkIdentifier\r\n 3qcr597p9d.skadnetwork\r\n \r\n\r\n", "iosProps":true, "iosSystemFrameworkEntries":[ {"$GMExtensionFrameworkEntry":"","%Name":"AdSupport.framework","embed":0,"name":"AdSupport.framework","resourceType":"GMExtensionFrameworkEntry","resourceVersion":"2.0","weakReference":false,}, @@ -139,24 +178,36 @@ "macsourcedir":"", "name":"AdMob", "options":[ - {"$GMExtensionOption":"","%Name":"__label1","defaultValue":"### ANDROID CONFIG ###","description":"","displayName":"","exportToINI":false,"extensionId":null,"guid":"3069a5bf-6d7d-4073-a4f9-e5f8f3449075","hidden":false,"listItems":[],"name":"__label1","optType":5,"resourceType":"GMExtensionOption","resourceVersion":"2.0",}, + {"$GMExtensionOption":"","%Name":"__label1","defaultValue":"ANDROID OPTIONS:","description":"","displayName":"","exportToINI":false,"extensionId":null,"guid":"3069a5bf-6d7d-4073-a4f9-e5f8f3449075","hidden":false,"listItems":[],"name":"__label1","optType":5,"resourceType":"GMExtensionOption","resourceVersion":"2.0",}, {"$GMExtensionOption":"","%Name":"Android_AppID","defaultValue":"ca-app-pub-3940256099942544~3347511713","description":"The application ID, obtained from the AdMob dashboard.","displayName":"Application ID","exportToINI":false,"extensionId":null,"guid":"fb7dfcc4-8a4f-480d-80a1-4353f93c9a2d","hidden":false,"listItems":[],"name":"Android_AppID","optType":2,"resourceType":"GMExtensionOption","resourceVersion":"2.0",}, {"$GMExtensionOption":"","%Name":"Android_BANNER","defaultValue":"ca-app-pub-3940256099942544/6300978111","description":"The banner ad unit ID.","displayName":"Banner Unit ID","exportToINI":false,"extensionId":null,"guid":"b9284c2f-2652-43e0-8857-83c4b381d452","hidden":false,"listItems":[],"name":"Android_BANNER","optType":2,"resourceType":"GMExtensionOption","resourceVersion":"2.0",}, {"$GMExtensionOption":"","%Name":"Android_INTERSTITIAL","defaultValue":"ca-app-pub-3940256099942544/1033173712","description":"The interstitial ad unit ID.","displayName":"Interstital Unit ID","exportToINI":false,"extensionId":null,"guid":"4253cbf6-25ef-47ab-a865-b33f15272ba6","hidden":false,"listItems":[],"name":"Android_INTERSTITIAL","optType":2,"resourceType":"GMExtensionOption","resourceVersion":"2.0",}, {"$GMExtensionOption":"","%Name":"Android_REWARDED","defaultValue":"ca-app-pub-3940256099942544/5224354917","description":"The rewarded ad unit ID.","displayName":"Rewarded Unit ID","exportToINI":false,"extensionId":null,"guid":"b19aeb11-226a-4d31-a7b2-1960aa422c5d","hidden":false,"listItems":[],"name":"Android_REWARDED","optType":2,"resourceType":"GMExtensionOption","resourceVersion":"2.0",}, {"$GMExtensionOption":"","%Name":"Android_REWARDED_INTERSTITIAL","defaultValue":"ca-app-pub-3940256099942544/5354046379","description":"The rewarded interstitial ad unit ID.","displayName":"Rewarded Interstitial Unit ID","exportToINI":false,"extensionId":null,"guid":"f018b3be-1c77-4cc0-bc4f-98f23755f2a5","hidden":false,"listItems":[],"name":"Android_REWARDED_INTERSTITIAL","optType":2,"resourceType":"GMExtensionOption","resourceVersion":"2.0",}, - {"$GMExtensionOption":"","%Name":"__label2","defaultValue":"### iOS CONFIG ###","description":"","displayName":"","exportToINI":false,"extensionId":null,"guid":"dd7deddb-f012-47ed-9802-3003899c4691","hidden":false,"listItems":[],"name":"__label2","optType":5,"resourceType":"GMExtensionOption","resourceVersion":"2.0",}, + {"$GMExtensionOption":"","%Name":"Android_OPENAPPAD","defaultValue":"ca-app-pub-3940256099942544/9257395921","description":"","displayName":"App Open Ad ID","exportToINI":false,"extensionId":null,"guid":"62068c1c-784e-47b3-b748-a59448d35292","hidden":false,"listItems":[],"name":"Android_OPENAPPAD","optType":2,"resourceType":"GMExtensionOption","resourceVersion":"2.0",}, + {"$GMExtensionOption":"","%Name":"__label2","defaultValue":"iOS OPTIONS:","description":"","displayName":"","exportToINI":false,"extensionId":null,"guid":"dd7deddb-f012-47ed-9802-3003899c4691","hidden":false,"listItems":[],"name":"__label2","optType":5,"resourceType":"GMExtensionOption","resourceVersion":"2.0",}, {"$GMExtensionOption":"","%Name":"iOS_AppID","defaultValue":"ca-app-pub-3940256099942544~1458002511","description":"The application ID, obtained from the AdMob dashboard.","displayName":"Application ID","exportToINI":false,"extensionId":null,"guid":"538faebe-f399-430a-b961-576a73233bed","hidden":false,"listItems":[],"name":"iOS_AppID","optType":2,"resourceType":"GMExtensionOption","resourceVersion":"2.0",}, {"$GMExtensionOption":"","%Name":"iOS_BANNER","defaultValue":"ca-app-pub-3940256099942544/2934735716","description":"The banner ad unit ID.","displayName":"Banner Unit ID","exportToINI":false,"extensionId":null,"guid":"83b3436e-3ee8-432e-8fce-49754e27f5aa","hidden":false,"listItems":[],"name":"iOS_BANNER","optType":2,"resourceType":"GMExtensionOption","resourceVersion":"2.0",}, {"$GMExtensionOption":"","%Name":"iOS_INTERSTITIAL","defaultValue":"ca-app-pub-3940256099942544/4411468910","description":"The interstitial ad unit ID.","displayName":"Interstital Unit ID","exportToINI":false,"extensionId":null,"guid":"dabd5195-9778-41db-848d-e124050792cc","hidden":false,"listItems":[],"name":"iOS_INTERSTITIAL","optType":2,"resourceType":"GMExtensionOption","resourceVersion":"2.0",}, {"$GMExtensionOption":"","%Name":"iOS_REWARDED","defaultValue":"ca-app-pub-3940256099942544/1712485313","description":"The rewarded ad unit ID.","displayName":"Rewarded Unit ID","exportToINI":false,"extensionId":null,"guid":"f6d2fbcb-0a33-4b9b-9914-1e6afbc5b0f9","hidden":false,"listItems":[],"name":"iOS_REWARDED","optType":2,"resourceType":"GMExtensionOption","resourceVersion":"2.0",}, {"$GMExtensionOption":"","%Name":"iOS_REWARDED_INTERSTITIAL","defaultValue":"ca-app-pub-3940256099942544/6978759866","description":"The rewarded interstitial ad unit ID.","displayName":"Rewarded Interstitial Unit ID","exportToINI":false,"extensionId":null,"guid":"6ca59a1d-8267-4f89-a230-f3402bf7ab04","hidden":false,"listItems":[],"name":"iOS_REWARDED_INTERSTITIAL","optType":2,"resourceType":"GMExtensionOption","resourceVersion":"2.0",}, + {"$GMExtensionOption":"","%Name":"iOS_OPENAPPAD","defaultValue":"ca-app-pub-3940256099942544/5575463023","description":"","displayName":"App Open Ad ID","exportToINI":false,"extensionId":null,"guid":"a59b6674-9967-4d30-b607-61b9561a9c56","hidden":false,"listItems":[],"name":"iOS_OPENAPPAD","optType":2,"resourceType":"GMExtensionOption","resourceVersion":"2.0",}, + {"$GMExtensionOption":"","%Name":"__extOptLabel","defaultValue":"EXTRA OPTIONS:","description":"","displayName":"","exportToINI":false,"extensionId":null,"guid":"46974f59-b380-4f04-ad8b-f36a0ff91891","hidden":false,"listItems":[],"name":"__extOptLabel","optType":5,"resourceType":"GMExtensionOption","resourceVersion":"2.0",}, + {"$GMExtensionOption":"","%Name":"logLevel","defaultValue":"1","description":"","displayName":"Log Level","exportToINI":false,"extensionId":null,"guid":"cc2fb2da-05f1-4e87-909b-b5d19824d731","hidden":false,"listItems":[ + "0", + "1", + "2", + ],"name":"logLevel","optType":6,"resourceType":"GMExtensionOption","resourceVersion":"2.0",}, + {"$GMExtensionOption":"","%Name":"versionStable","defaultValue":"2023.1.0.0","description":"","displayName":"","exportToINI":false,"extensionId":null,"guid":"d0d19117-79cc-4668-8bed-1349ca551925","hidden":true,"listItems":[],"name":"versionStable","optType":2,"resourceType":"GMExtensionOption","resourceVersion":"2.0",}, + {"$GMExtensionOption":"","%Name":"versionBeta","defaultValue":"2023.100.0.0","description":"","displayName":"","exportToINI":false,"extensionId":null,"guid":"18b08591-a1fe-4892-a653-b6cd26479dec","hidden":true,"listItems":[],"name":"versionBeta","optType":2,"resourceType":"GMExtensionOption","resourceVersion":"2.0",}, + {"$GMExtensionOption":"","%Name":"versionDev","defaultValue":"9.9.1.293","description":"","displayName":"","exportToINI":false,"extensionId":null,"guid":"0f61eb8d-f68c-4777-bd04-c14e94f6dc9a","hidden":true,"listItems":[],"name":"versionDev","optType":2,"resourceType":"GMExtensionOption","resourceVersion":"2.0",}, + {"$GMExtensionOption":"","%Name":"versionLTS","defaultValue":"2022.0.1.24","description":"","displayName":"","exportToINI":false,"extensionId":null,"guid":"ae27ca8c-4569-427f-abd9-77ae24ab3184","hidden":true,"listItems":[],"name":"versionLTS","optType":2,"resourceType":"GMExtensionOption","resourceVersion":"2.0",}, ], "optionsFile":"options.json", "packageId":"", "parent":{ - "name":"Extensions", - "path":"folders/Extensions.yy", + "name":"AdMob", + "path":"folders/Extensions/AdMob.yy", }, "productId":"", "resourceType":"GMExtension", diff --git a/extensions/AdMob/AndroidSource/Java/GoogleMobileAdsGM.java b/extensions/AdMob/AndroidSource/Java/GoogleMobileAdsGM.java index 454f56ed3..28065a4c8 100644 --- a/extensions/AdMob/AndroidSource/Java/GoogleMobileAdsGM.java +++ b/extensions/AdMob/AndroidSource/Java/GoogleMobileAdsGM.java @@ -7,53 +7,45 @@ import android.content.SharedPreferences; import android.view.View; import android.app.Activity; -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; -import android.widget.Toast; -import android.widget.AbsoluteLayout; import android.view.ViewGroup; -import android.widget.Toast; + import java.lang.Exception; -import java.net.URL; + import android.provider.Settings; + +import java.nio.charset.StandardCharsets; +import java.util.Collections; import java.util.Map; -import java.util.Arrays; +import java.util.Objects; +import java.util.Queue; import java.util.ArrayList; import com.google.android.gms.ads.MobileAds; -import com.google.android.gms.ads.initialization.OnInitializationCompleteListener; import com.google.android.gms.ads.initialization.AdapterStatus; -import com.google.android.gms.ads.initialization.InitializationStatus; import com.google.android.gms.ads.AdRequest; import com.google.android.gms.ads.interstitial.InterstitialAd; import com.google.android.gms.ads.interstitial.InterstitialAdLoadCallback; import com.google.android.gms.ads.rewarded.RewardedAd; import com.google.android.gms.ads.rewarded.RewardedAdLoadCallback; -import com.google.android.gms.ads.rewarded.RewardItem; -import com.google.android.gms.ads.OnUserEarnedRewardListener; import com.google.android.gms.ads.FullScreenContentCallback; import com.google.android.gms.ads.rewardedinterstitial.RewardedInterstitialAd; import com.google.android.gms.ads.rewardedinterstitial.RewardedInterstitialAdLoadCallback; import com.google.android.gms.ads.AdView; import com.google.android.gms.ads.AdSize; import com.google.android.gms.ads.AdListener; -import com.google.android.gms.ads.mediation.MediationAdapter; import com.google.android.gms.ads.LoadAdError; import com.google.android.gms.ads.AdError; import com.google.android.gms.ads.RequestConfiguration; -import com.google.ads.mediation.admob.AdMobAdapter; +import com.google.android.gms.ads.appopen.AppOpenAd; +import com.google.android.gms.ads.appopen.AppOpenAd.AppOpenAdLoadCallback; -import com.google.android.ump.*;//UserMessagingPlatform; -import androidx.annotation.Nullable; +import com.google.android.ump.*; import android.widget.RelativeLayout; import android.view.ViewGroup.LayoutParams; -import android.view.ViewParent; -import android.view.Gravity; + import androidx.annotation.NonNull; -import android.widget.FrameLayout; import android.util.Log; @@ -62,103 +54,254 @@ import android.util.DisplayMetrics; import android.view.Display; +import java.util.Date; + +import android.os.Process; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadFactory; + +import com.google.android.gms.ads.OnPaidEventListener; +import com.google.android.gms.ads.AdValue; +import com.google.android.gms.ads.AdapterResponseInfo; + +import android.os.Bundle; +import com.google.ads.mediation.admob.AdMobAdapter; + public class GoogleMobileAdsGM extends RunnerSocial { private static final int EVENT_OTHER_SOCIAL = 70; + private static final int ADMOB_ERROR_NOT_INITIALIZED = -1; + private static final int ADMOB_ERROR_INVALID_AD_ID = -2; + private static final int ADMOB_ERROR_AD_LIMIT_REACHED = -3; + private static final int ADMOB_ERROR_NO_ADS_LOADED = -4; + private static final int ADMOB_ERROR_NO_ACTIVE_BANNER_AD = -5; + private static final int ADMOB_ERROR_ILLEGAL_CALL = -6; - public static Activity activity; + private static final String LOG_TAG = "AdMob"; + + private final Activity activity; + private final ViewGroup rootView; public GoogleMobileAdsGM() { activity = RunnerActivity.CurrentActivity; + rootView = activity.findViewById(android.R.id.content); } - //////////////////////////////////////////////////// GoogleMobileAds - //////////////////////////////////////////////////// //////////////////////////////////////////////////// + // #region Setup - public void AdMob_Initialize() { - RunnerActivity.ViewHandler.post(new Runnable() { + private ExecutorService executorService = createExecutorService(500); + + private ExecutorService createExecutorService(int keepAliveTime) { + int numberOfCores = Runtime.getRuntime().availableProcessors(); + TimeUnit keepAliveTimeUnit = TimeUnit.MILLISECONDS; + BlockingQueue taskQueue = new LinkedBlockingQueue<>(); + + executorService = new ThreadPoolExecutor( + numberOfCores, + numberOfCores * 2, + keepAliveTime, + keepAliveTimeUnit, + taskQueue, + new BackgroundThreadFactory()); + + return executorService; + } + + private static class BackgroundThreadFactory implements ThreadFactory { + private static int sTag = 1; + + @Override + public Thread newThread(Runnable runnable) { + Thread thread = new Thread(runnable); + thread.setName("AdmobInitThread" + (sTag++)); + thread.setPriority(Process.THREAD_PRIORITY_BACKGROUND); + thread.setUncaughtExceptionHandler((aThread, ex) -> Log.e(LOG_TAG, aThread.getName() + " encountered an error: " + ex.getMessage())); + return thread; + } + } + + Boolean isInitialized = false; + + public double AdMob_Initialize() { + + if (!validateNotInitialized("AdMob_Initialize")) return ADMOB_ERROR_ILLEGAL_CALL; + + // ThreadPoolExecutor + executorService.execute(new Runnable() { public void run() { - MobileAds.setRequestConfiguration(requestConfigurationBuilder()); + MobileAds.setRequestConfiguration(buildRequestConfiguration()); try { - // MobileAds.initialize(activity); - MobileAds.initialize(activity, new OnInitializationCompleteListener() { - @Override - public void onInitializationComplete(InitializationStatus initializationStatus) { - Map statusMap = initializationStatus.getAdapterStatusMap(); - for (String adapterClass : statusMap.keySet()) { - AdapterStatus status = statusMap.get(adapterClass); - Log.d("yoyo", String.format("Adapter name: %s, Description: %s, Latency: %d", - adapterClass, status.getDescription(), status.getLatency())); - } + MobileAds.initialize(activity, initializationStatus -> { + Map statusMap = initializationStatus.getAdapterStatusMap(); + for (String adapterClass : statusMap.keySet()) { + AdapterStatus status = statusMap.get(adapterClass); + assert status != null; + Log.d(LOG_TAG, String.format("Adapter name: %s, Description: %s, Latency: %d", + adapterClass, status.getDescription(), status.getLatency())); + } - int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); - RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_OnInitialized"); - RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_OnInitialized"); + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); - // Initialize ad types using extension options - AdMob_Banner_Init(RunnerJNILib.extOptGetString("AdMob", "Android_BANNER")); - AdMob_Interstitial_Init(RunnerJNILib.extOptGetString("AdMob", "Android_INTERSTITIAL")); - AdMob_RewardedVideo_Init(RunnerJNILib.extOptGetString("AdMob", "Android_REWARDED")); - AdMob_RewardedInterstitial_Init(RunnerJNILib.extOptGetString("AdMob", "Android_REWARDED_INTERSTITIAL")); - } + // Initialize ad types using extension options (if they are not empty) + String bannerUnitId = RunnerJNILib.extOptGetString("AdMob", "Android_BANNER"); + if (!bannerUnitId.isEmpty()) + AdMob_Banner_Set_AdUnit(bannerUnitId); + + String interstitialUnitId = RunnerJNILib.extOptGetString("AdMob", "Android_INTERSTITIAL"); + if (!interstitialUnitId.isEmpty()) + AdMob_Interstitial_Set_AdUnit(interstitialUnitId); + + String rewardedVideoUnitId = RunnerJNILib.extOptGetString("AdMob", "Android_REWARDED"); + if (!rewardedVideoUnitId.isEmpty()) + AdMob_RewardedVideo_Set_AdUnit(rewardedVideoUnitId); + + String rewardedInterstitialUnitId = RunnerJNILib.extOptGetString("AdMob", + "Android_REWARDED_INTERSTITIAL"); + if (!rewardedInterstitialUnitId.isEmpty()) + AdMob_RewardedInterstitial_Set_AdUnit(rewardedInterstitialUnitId); + + String appOpenUnitId = RunnerJNILib.extOptGetString("AdMob", "Android_OPENAPPAD"); + if (!appOpenUnitId.isEmpty()) + AdMob_AppOpenAd_Set_AdUnit(appOpenUnitId); + + isInitialized = true; }); } catch (Exception e) { - Log.i("yoyo", "GoogleMobileAds Init Error: " + e.toString()); - Log.i("yoyo", e.toString()); + Log.i(LOG_TAG, "GoogleMobileAds Init Error: " + e.toString()); + Log.i(LOG_TAG, e.toString()); } } }); + + return 0; + } + + private boolean isTestDevice = false; + + public double AdMob_SetTestDeviceId() { + if (!validateNotInitialized("AdMob_SetTestDeviceId")) return ADMOB_ERROR_ILLEGAL_CALL; + + isTestDevice = true; + return 0; + } + + boolean triggerOnPaidEvent = false; + + public void AdMob_Events_OnPaidEvent(double enabled) { + triggerOnPaidEvent = enabled >= 0.5; } - public String testDeviceID; + private RequestConfiguration buildRequestConfiguration() { + + RequestConfiguration.Builder requestConfigurationBuilder = MobileAds.getRequestConfiguration().toBuilder(); + + if (isTestDevice) { + List testDeviceIds = Collections.singletonList(getDeviceID()); + requestConfigurationBuilder.setTestDeviceIds(testDeviceIds); + } + + if (targetCOPPA) + requestConfigurationBuilder.setTagForChildDirectedTreatment(RequestConfiguration.TAG_FOR_CHILD_DIRECTED_TREATMENT_TRUE); + + if (targetUnderAge) + requestConfigurationBuilder.setTagForUnderAgeOfConsent(RequestConfiguration.TAG_FOR_UNDER_AGE_OF_CONSENT_TRUE); + + requestConfigurationBuilder.setMaxAdContentRating(maxAdContentRating); + + return requestConfigurationBuilder.build(); + } + + public void onPaidEventHandler(AdValue adValue, String adUnitId, String adType, + AdapterResponseInfo loadedAdapterResponseInfo, String mediationAdapterClassName) { + + + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_OnPaidEvent"); + + RunnerJNILib.DsMapAddString(dsMapIndex, "mediation_adapter_class_name", mediationAdapterClassName); + + RunnerJNILib.DsMapAddString(dsMapIndex, "unit_id", adUnitId); + RunnerJNILib.DsMapAddString(dsMapIndex, "ad_type", adType); + RunnerJNILib.DsMapAddDouble(dsMapIndex, "micros", adValue.getValueMicros()); + RunnerJNILib.DsMapAddString(dsMapIndex, "currency_code", adValue.getCurrencyCode()); + RunnerJNILib.DsMapAddDouble(dsMapIndex, "precision", adValue.getPrecisionType()); - public void AdMob_SetTestDeviceId() { - testID_on = true; + RunnerJNILib.DsMapAddString(dsMapIndex, "ad_source_name", loadedAdapterResponseInfo.getAdSourceName()); + RunnerJNILib.DsMapAddString(dsMapIndex, "ad_source_id", loadedAdapterResponseInfo.getAdSourceId()); + RunnerJNILib.DsMapAddString(dsMapIndex, "ad_source_instance_name", + loadedAdapterResponseInfo.getAdSourceInstanceName()); + RunnerJNILib.DsMapAddString(dsMapIndex, "ad_source_instance_id", + loadedAdapterResponseInfo.getAdSourceInstanceId()); + + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + } + + boolean nonPersonalizedAds = false; + public void AdMob_NonPersonalizedAds_Set(double value) { + nonPersonalizedAds = value >= 0.5; } - ///// BANNER - ///// ////////////////////////////////////////////////////////////////////////////////////// + // #endregion - private AdView adView = null; - private String bannerID; - private RelativeLayout layout; + // #region Banner - public void AdMob_Banner_Init(String adUnitId) { - bannerID = adUnitId; + private AdView bannerAdView = null; + private AdSize bannerSize = null; + private RelativeLayout bannerLayout = null; + + private String bannerAdUnitId = ""; + + public void AdMob_Banner_Set_AdUnit(String adUnitId) { + bannerAdUnitId = adUnitId; } - public void AdMob_Banner_Create(final double size, final double bottom) { + public double AdMob_Banner_Create(final double size, final double bottom) { + + final String callingMethod = "AdMob_Banner_Create"; + + if (!validateInitialized(callingMethod)) + return ADMOB_ERROR_NOT_INITIALIZED; + + if (!validateAdId(bannerAdUnitId, callingMethod)) + return ADMOB_ERROR_INVALID_AD_ID; + RunnerActivity.ViewHandler.post(new Runnable() { public void run() { - if (adView != null) { - layout.removeView(adView); - adView.destroy(); - adView = null; - - final ViewGroup rootView = activity.findViewById(android.R.id.content); - rootView.removeView(layout); - // layout.destroy(); - layout = null; + if (bannerAdView != null) { + deleteBannerAdView(); } - layout = new RelativeLayout(activity); + bannerLayout = new RelativeLayout(activity); + bannerAdView = new AdView(activity); + + if (triggerOnPaidEvent) { + final AdView bannerAdRef = bannerAdView; + bannerAdView.setOnPaidEventListener(adValue -> { + AdapterResponseInfo loadedAdapterResponseInfo = Objects.requireNonNull(bannerAdRef.getResponseInfo()) + .getLoadedAdapterResponseInfo(); + if (loadedAdapterResponseInfo == null) return; + onPaidEventHandler(adValue, bannerAdRef.getAdUnitId(), "Banner", loadedAdapterResponseInfo, + bannerAdRef.getResponseInfo().getMediationAdapterClassName()); + }); + } RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); - params.addRule(RelativeLayout.CENTER_HORIZONTAL); - if (bottom > 0.5) - params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM); - else - params.addRule(RelativeLayout.ALIGN_PARENT_TOP); - adView = new AdView(activity); - - layout.addView((View) adView, params); + params.addRule(RelativeLayout.CENTER_HORIZONTAL); + params.addRule((bottom > 0.5) ? RelativeLayout.ALIGN_PARENT_BOTTOM : RelativeLayout.ALIGN_PARENT_TOP); + bannerLayout.addView((View) bannerAdView, params); + rootView.addView((View) bannerLayout); - final ViewGroup rootView = activity.findViewById(android.R.id.content); - rootView.addView((View) layout); + bannerAdView.setAdListener(new AdListener() { - adView.setAdListener(new AdListener() { @Override public void onAdLoaded() { int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); @@ -167,7 +310,7 @@ public void onAdLoaded() { } @Override - public void onAdFailedToLoad(LoadAdError loadAdError) { + public void onAdFailedToLoad(@NonNull LoadAdError loadAdError) { int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_Banner_OnLoadFailed"); RunnerJNILib.DsMapAddString(dsMapIndex, "errorMessage", loadAdError.getMessage()); @@ -193,103 +336,146 @@ public void onAdClosed() { } }); - bannerSize = banner_size(size); - adView.setAdSize(bannerSize); - adView.setAdUnitId(bannerID); - adView.requestLayout(); - adView.setVisibility(View.VISIBLE); + bannerSize = getBannerSize(size); - adView.loadAd(AdMob_AdRequest()); + assert bannerSize != null; + bannerAdView.setAdSize(bannerSize); + bannerAdView.setAdUnitId(bannerAdUnitId); + bannerAdView.requestLayout(); + bannerAdView.setVisibility(View.VISIBLE); + + bannerAdView.loadAd(buildAdRequest()); } }); + + return 0; } - private AdSize bannerSize = null; - public double AdMob_Banner_GetWidth() { - if (bannerSize == null) - return 0; + // If there is no active banner ad, return 0 + if (bannerAdView == null) return 0; - int w = bannerSize.getWidthInPixels(RunnerJNILib.ms_context); - return w; + // Get the width of the banner in pixels + return bannerSize.getWidthInPixels(RunnerJNILib.ms_context); } public double AdMob_Banner_GetHeight() { - if (bannerSize == null) - return 0; + // If there is no active banner ad, return 0 + if (bannerAdView == null) return 0; + // Get the height of the banner in pixels int h = bannerSize.getHeightInPixels(RunnerJNILib.ms_context); + + // Special handling for SMART_BANNER to adjust height based on screen size and + // density if (bannerSize == AdSize.SMART_BANNER) { DisplayMetrics displayMetrics = (RunnerJNILib.ms_context).getResources().getDisplayMetrics(); + // Calculate screen height in density-independent pixels (DP) int screenHeightInDP = Math.round(displayMetrics.heightPixels / displayMetrics.density); + + // Get screen density int density = Math.round(displayMetrics.density); + + // Adjust height based on screen height in DP if (screenHeightInDP < 400) - h = 32 * density; + h = 32 * density; // Smaller screens else if (screenHeightInDP <= 720) - h = 50 * density; + h = 50 * density; // Medium screens else - h = 90 * density; + h = 90 * density; // Larger screens } return h; } - public void AdMob_Banner_Move(final double bottom) { - if (adView != null) { - RunnerActivity.ViewHandler.post(new Runnable() { - public void run() { - RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, - LayoutParams.WRAP_CONTENT); - params.addRule(RelativeLayout.CENTER_HORIZONTAL); - if (bottom > 0.5) - params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM); - else - params.addRule(RelativeLayout.ALIGN_PARENT_TOP); + public double AdMob_Banner_Move(final double bottom) { - adView.setLayoutParams(params); - } - }); - } - } + final String callingMethod = "AdMob_Banner_Move"; + + // If there is no active banner ad, return 0 + if (!validateActiveBannerAd(callingMethod)) + return ADMOB_ERROR_NO_ACTIVE_BANNER_AD; - public void AdMob_Banner_Show() { RunnerActivity.ViewHandler.post(new Runnable() { public void run() { - if (adView != null) - adView.setVisibility(View.VISIBLE); + + if (!validateActiveBannerAd(callingMethod)) + return; + + RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, + LayoutParams.WRAP_CONTENT); + params.addRule(RelativeLayout.CENTER_HORIZONTAL); + params.addRule(bottom > 0.5 ? RelativeLayout.ALIGN_PARENT_BOTTOM : RelativeLayout.ALIGN_PARENT_TOP); + bannerAdView.setLayoutParams(params); } }); + return 0; } - public void AdMob_Banner_Hide() { - RunnerActivity.ViewHandler.post(new Runnable() { - public void run() { - if (adView != null) - adView.setVisibility(View.GONE); - } + public double AdMob_Banner_Show() { + + final String callingMethod = "AdMob_Banner_Show"; + + if (!validateActiveBannerAd(callingMethod)) + return ADMOB_ERROR_NO_ACTIVE_BANNER_AD; + + RunnerActivity.ViewHandler.post(() -> { + + if (!validateActiveBannerAd(callingMethod)) + return; + + bannerAdView.setVisibility(View.VISIBLE); }); + return 0; } - public void AdMob_Banner_Remove() { - RunnerActivity.ViewHandler.post(new Runnable() { - public void run() { - if (adView != null) { - AdSize bannerSize = null; + public double AdMob_Banner_Hide() { - layout.removeView(adView); - adView.destroy(); - adView = null; + final String callingMethod = "AdMob_Banner_Hide"; - final ViewGroup rootView = activity.findViewById(android.R.id.content); - rootView.removeView(layout); - // layout.destroy(); - layout = null; - } - } + if (!validateActiveBannerAd(callingMethod)) + return ADMOB_ERROR_NO_ACTIVE_BANNER_AD; + + RunnerActivity.ViewHandler.post(() -> { + + if (!validateActiveBannerAd(callingMethod)) + return; + + bannerAdView.setVisibility(View.GONE); }); + return 0; } - private AdSize banner_size(double size) { + public double AdMob_Banner_Remove() { + + final String callingMethod = "AdMob_Banner_Remove"; + + if (!validateActiveBannerAd(callingMethod)) + return ADMOB_ERROR_NO_ACTIVE_BANNER_AD; + + RunnerActivity.ViewHandler.post(() -> { + + if (!validateActiveBannerAd(callingMethod)) + return; + + deleteBannerAdView(); + }); + return 0; + } + + private void deleteBannerAdView() { + // Remove bannerAdView from bannerLayout + bannerLayout.removeView(bannerAdView); + bannerAdView.destroy(); + bannerAdView = null; + // Remove bannerLayout from rootView + rootView.removeView(bannerLayout); + bannerLayout = null; + // Reset bannerSize + bannerSize = null; + } + + private AdSize getBannerSize(double size) { switch ((int) size) { case 0: return AdSize.BANNER; @@ -319,64 +505,129 @@ private AdSize banner_size(double size) { return null; } - ///// INTERSTITIAL - ///// //////////////////////////////////////////////////////////////////////////////// + //#endregion + + // #region Interstitial + + private int interstitialMaxLoadedInstances = 1; + private final ConcurrentLinkedQueue loadedInterstitialQueue = new ConcurrentLinkedQueue<>(); - private InterstitialAd mInterstitialAd = null; - private String mInterstitialID = null; + private String interstitialAdUnitId = ""; - public void AdMob_Interstitial_Init(String adUnitId) { - mInterstitialID = adUnitId; + public void AdMob_Interstitial_Set_AdUnit(String adUnitId) { + interstitialAdUnitId = adUnitId; } - public void AdMob_Interstitial_Load() { - if (mInterstitialAd == null) - RunnerActivity.ViewHandler.post(new Runnable() { - public void run() { - InterstitialAd.load(activity, mInterstitialID, AdMob_AdRequest(), new InterstitialAdLoadCallback() { - @Override - public void onAdLoaded(@NonNull InterstitialAd interstitialAd) { - mInterstitialAd = interstitialAd; + public void Admob_Interstitial_Free_Loaded_Instances(double count) { + if (count < 0) { + count = loadedInterstitialQueue.size(); + } - int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); - RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_Interstitial_OnLoaded"); - RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); - } + while (count > 0 && loadedInterstitialQueue.size() > 0) { + loadedInterstitialQueue.poll(); + count--; + } + } - @Override - public void onAdFailedToLoad(@NonNull LoadAdError loadAdError) { - mInterstitialAd = null; + public void Admob_Interstitial_Max_Instances(double value) { + interstitialMaxLoadedInstances = (int) value; - int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); - RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_Interstitial_OnLoadFailed"); - RunnerJNILib.DsMapAddString(dsMapIndex, "errorMessage", loadAdError.getMessage()); - RunnerJNILib.DsMapAddDouble(dsMapIndex, "errorCode", loadAdError.getCode()); - RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + int size = loadedInterstitialQueue.size(); + if (size <= value) return; + + Admob_Interstitial_Free_Loaded_Instances(size - value); + } + + public double AdMob_Interstitial_Load() { + + final String callingMethod = "AdMob_Interstitial_Load"; + + if (!validateInitialized(callingMethod)) + return ADMOB_ERROR_NOT_INITIALIZED; + + if (!validateAdId(interstitialAdUnitId, callingMethod)) + return ADMOB_ERROR_INVALID_AD_ID; + + if (!validateLoadedAdsLimit(loadedInterstitialQueue, interstitialMaxLoadedInstances, callingMethod)) + return ADMOB_ERROR_AD_LIMIT_REACHED; + + RunnerActivity.ViewHandler.post(new Runnable() { + + final String adUnitId = interstitialAdUnitId; + + public void run() { + InterstitialAd.load(activity, adUnitId, buildAdRequest(), new InterstitialAdLoadCallback() { + + @Override + public void onAdLoaded(@NonNull InterstitialAd interstitialAd) { + + if (!validateLoadedAdsLimit(loadedInterstitialQueue, interstitialMaxLoadedInstances, + callingMethod)) + return; + + loadedInterstitialQueue.add(interstitialAd); + + if (triggerOnPaidEvent) { + final InterstitialAd interstitialAdRef = interstitialAd; + interstitialAd.setOnPaidEventListener(adValue -> { + AdapterResponseInfo loadedAdapterResponseInfo = interstitialAdRef.getResponseInfo() + .getLoadedAdapterResponseInfo(); + if(loadedAdapterResponseInfo == null) return; + onPaidEventHandler(adValue, interstitialAdRef.getAdUnitId(), "Interstitial", + loadedAdapterResponseInfo, + interstitialAdRef.getResponseInfo().getMediationAdapterClassName()); + }); } - }); - } - }); + + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_Interstitial_OnLoaded"); + RunnerJNILib.DsMapAddString(dsMapIndex, "unit_id", adUnitId); + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + } + + @Override + public void onAdFailedToLoad(@NonNull LoadAdError loadAdError) { + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_Interstitial_OnLoadFailed"); + RunnerJNILib.DsMapAddString(dsMapIndex, "unit_id", adUnitId); + RunnerJNILib.DsMapAddString(dsMapIndex, "errorMessage", loadAdError.getMessage()); + RunnerJNILib.DsMapAddDouble(dsMapIndex, "errorCode", loadAdError.getCode()); + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + } + }); + } + }); + return 0; } - public void AdMob_Interstitial_Show() { - if (mInterstitialAd == null) - return; + public double AdMob_Interstitial_Show() { + + final String callingMethod = "AdMob_Interstitial_Show"; + if (!validateInitialized(callingMethod)) + return ADMOB_ERROR_NOT_INITIALIZED; + + if (!validateAdLoaded(loadedInterstitialQueue, callingMethod)) + return ADMOB_ERROR_NO_ADS_LOADED; + + final InterstitialAd interstitialAdRef = loadedInterstitialQueue.poll(); RunnerActivity.ViewHandler.post(new Runnable() { public void run() { - mInterstitialAd.setFullScreenContentCallback(new FullScreenContentCallback() { + assert interstitialAdRef != null; + interstitialAdRef.setFullScreenContentCallback(new FullScreenContentCallback() { @Override public void onAdDismissedFullScreenContent() { int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_Interstitial_OnDismissed"); + RunnerJNILib.DsMapAddString(dsMapIndex, "unit_id", interstitialAdRef.getAdUnitId()); RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); } @Override - public void onAdFailedToShowFullScreenContent(AdError adError) { - mInterstitialAd = null; + public void onAdFailedToShowFullScreenContent(@NonNull AdError adError) { int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_Interstitial_OnShowFailed"); + RunnerJNILib.DsMapAddString(dsMapIndex, "unit_id", interstitialAdRef.getAdUnitId()); RunnerJNILib.DsMapAddString(dsMapIndex, "errorMessage", adError.getMessage()); RunnerJNILib.DsMapAddDouble(dsMapIndex, "errorCode", adError.getCode()); RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); @@ -386,176 +637,325 @@ public void onAdFailedToShowFullScreenContent(AdError adError) { public void onAdShowedFullScreenContent() { int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_Interstitial_OnFullyShown"); + RunnerJNILib.DsMapAddString(dsMapIndex, "unit_id", interstitialAdRef.getAdUnitId()); RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); } }); - mInterstitialAd.show(activity); - mInterstitialAd = null; + interstitialAdRef.show(activity); + isShowingAd = true; } }); + return 0; } public double AdMob_Interstitial_IsLoaded() { - if (mInterstitialAd == null) - return 0.0; + return AdMob_Interstitial_Instances_Count() > 0 ? 1.0 : 0.0; + } - return 1.0; + public double AdMob_Interstitial_Instances_Count() { + return loadedInterstitialQueue.size(); } - ///// REWARDED VIDEO - ///// ////////////////////////////////////////////////////////////////////////////// + // #endregion + + // #region Rewarded Video - public RewardedAd mRewardedAd = null; - public String mRewardedAdID = null; + private int rewardedVideoMaxLoadedInstances = 1; + private final ConcurrentLinkedQueue loadedRewardedVideoQueue = new ConcurrentLinkedQueue<>(); - public void AdMob_RewardedVideo_Init(String adUnitId) { - mRewardedAdID = adUnitId; + private String rewardedVideoAdUnitId = ""; + + public void AdMob_RewardedVideo_Set_AdUnit(String adUnitId) { + rewardedVideoAdUnitId = adUnitId; } - public void AdMob_RewardedVideo_Load() { - if (mRewardedAd == null) - RunnerActivity.ViewHandler.post(new Runnable() { - public void run() { - RewardedAd.load(activity, mRewardedAdID, AdMob_AdRequest(), new RewardedAdLoadCallback() { - @Override - public void onAdFailedToLoad(@NonNull LoadAdError loadAdError) { - mRewardedAd = null; + public void AdMob_RewardedVideo_Free_Loaded_Instances(double count) { + if (count < 0) { + count = loadedRewardedVideoQueue.size(); + } - int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); - RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_RewardedVideo_OnLoadFailed"); - RunnerJNILib.DsMapAddString(dsMapIndex, "errorMessage", loadAdError.getMessage()); - RunnerJNILib.DsMapAddDouble(dsMapIndex, "errorCode", loadAdError.getCode()); - RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); - } + while (count > 0 && loadedRewardedVideoQueue.size() > 0) { + loadedRewardedVideoQueue.poll(); + count--; + } + } - @Override - public void onAdLoaded(@NonNull RewardedAd rewardedAd_) { - mRewardedAd = rewardedAd_; + public void AdMob_RewardedVideo_Max_Instances(double value) { + rewardedVideoMaxLoadedInstances = (int) value; - int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); - RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_RewardedVideo_OnLoaded"); - RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); - } - }); - } - }); + int size = loadedRewardedVideoQueue.size(); + if (size <= value) return; + + AdMob_RewardedVideo_Free_Loaded_Instances(size - value); } - public void AdMob_RewardedVideo_Show() { - if (mRewardedAd == null) - return; + public double AdMob_RewardedVideo_Load() { + + final String callingMethod = "AdMob_RewardedVideo_Load"; + + if (!validateInitialized(callingMethod)) + return ADMOB_ERROR_NOT_INITIALIZED; + + if (!validateAdId(rewardedVideoAdUnitId, callingMethod)) + return ADMOB_ERROR_INVALID_AD_ID; + + if (!validateLoadedAdsLimit(loadedRewardedVideoQueue, rewardedVideoMaxLoadedInstances, callingMethod)) + return ADMOB_ERROR_AD_LIMIT_REACHED; RunnerActivity.ViewHandler.post(new Runnable() { + + final String adUnitId = rewardedVideoAdUnitId; + public void run() { - mRewardedAd.setFullScreenContentCallback(new FullScreenContentCallback() { - @Override - public void onAdDismissedFullScreenContent() { - int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); - RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_RewardedVideo_OnDismissed"); - RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); - } + RewardedAd.load(activity, adUnitId, buildAdRequest(), new RewardedAdLoadCallback() { @Override - public void onAdFailedToShowFullScreenContent(AdError adError) { + public void onAdLoaded(@NonNull RewardedAd rewardedAd) { + + if (!validateLoadedAdsLimit(loadedRewardedVideoQueue, rewardedVideoMaxLoadedInstances, + callingMethod)) + return; + + loadedRewardedVideoQueue.add(rewardedAd); + + if (triggerOnPaidEvent) { + final RewardedAd rewardedAdRef = rewardedAd; + rewardedAd.setOnPaidEventListener(new OnPaidEventListener() { + @Override + public void onPaidEvent(@NonNull AdValue adValue) { + AdapterResponseInfo loadedAdapterResponseInfo = rewardedAdRef.getResponseInfo() + .getLoadedAdapterResponseInfo(); + if (loadedAdapterResponseInfo == null) return; + onPaidEventHandler(adValue, rewardedAdRef.getAdUnitId(), "RewardedVideo", + loadedAdapterResponseInfo, + rewardedAdRef.getResponseInfo().getMediationAdapterClassName()); + } + }); + } + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); - RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_RewardedVideo_OnShowFailed"); - RunnerJNILib.DsMapAddString(dsMapIndex, "errorMessage", adError.getMessage()); - RunnerJNILib.DsMapAddDouble(dsMapIndex, "errorCode", adError.getCode()); + RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_RewardedVideo_OnLoaded"); + RunnerJNILib.DsMapAddString(dsMapIndex, "unit_id", adUnitId); RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); } @Override - public void onAdShowedFullScreenContent() { + public void onAdFailedToLoad(@NonNull LoadAdError loadAdError) { + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); - RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_RewardedVideo_OnFullyShown"); + RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_RewardedVideo_OnLoadFailed"); + RunnerJNILib.DsMapAddString(dsMapIndex, "unit_id", adUnitId); + RunnerJNILib.DsMapAddString(dsMapIndex, "errorMessage", loadAdError.getMessage()); + RunnerJNILib.DsMapAddDouble(dsMapIndex, "errorCode", loadAdError.getCode()); RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); } }); + } + }); + return 0; + } - mRewardedAd.show(activity, new OnUserEarnedRewardListener() { - @Override - public void onUserEarnedReward(@NonNull RewardItem rewardItem) { + public double AdMob_RewardedVideo_Show() { + + final String callingMethod = "AdMob_RewardedVideo_Show"; + + if (!validateInitialized(callingMethod)) + return ADMOB_ERROR_NOT_INITIALIZED; + + if (!validateAdLoaded(loadedRewardedVideoQueue, callingMethod)) + return ADMOB_ERROR_NO_ADS_LOADED; + + final RewardedAd rewardedAd = loadedRewardedVideoQueue.poll(); + RunnerActivity.ViewHandler.post(() -> { + + assert rewardedAd != null; + rewardedAd.setFullScreenContentCallback(new FullScreenContentCallback() { + @Override + public void onAdDismissedFullScreenContent() { + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_RewardedVideo_OnDismissed"); + RunnerJNILib.DsMapAddString(dsMapIndex, "unit_id", rewardedAd.getAdUnitId()); + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + } + + @Override + public void onAdFailedToShowFullScreenContent(@NonNull AdError adError) { + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_RewardedVideo_OnShowFailed"); + RunnerJNILib.DsMapAddString(dsMapIndex, "unit_id", rewardedAd.getAdUnitId()); + RunnerJNILib.DsMapAddString(dsMapIndex, "errorMessage", adError.getMessage()); + RunnerJNILib.DsMapAddDouble(dsMapIndex, "errorCode", adError.getCode()); + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + } + + @Override + public void onAdShowedFullScreenContent() { + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_RewardedVideo_OnFullyShown"); + RunnerJNILib.DsMapAddString(dsMapIndex, "unit_id", rewardedAd.getAdUnitId()); + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + } + }); + + rewardedAd.show(activity, + rewardItem -> { int rewardAmount = rewardItem.getAmount(); String rewardType = rewardItem.getType(); int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_RewardedVideo_OnReward"); + RunnerJNILib.DsMapAddString(dsMapIndex, "unit_id", rewardedAd.getAdUnitId()); + RunnerJNILib.DsMapAddDouble(dsMapIndex, "reward_amount", rewardAmount); + RunnerJNILib.DsMapAddString(dsMapIndex, "reward_type", rewardType); RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); - } - }); - mRewardedAd = null; - } + }); + + isShowingAd = true; }); + return 0; } public double AdMob_RewardedVideo_IsLoaded() { - if (mRewardedAd == null) - return 0.0; + return AdMob_RewardedVideo_Instances_Count() > 0 ? 1.0 : 0.0; + } - return 1.0; + public double AdMob_RewardedVideo_Instances_Count() { + return loadedRewardedVideoQueue.size(); } - ///// REWARDED INTESTITIAL - ///// //////////////////////////////////////////////////////////////////////// + // #endregion - public RewardedInterstitialAd mRewardedInterstitialAd = null; - public String mRewardedInterstitialAdID = null; + // #region Rewarded Interstitial - public void AdMob_RewardedInterstitial_Init(String adUnitId) { - mRewardedInterstitialAdID = adUnitId; + private int rewardedInterstitialMaxLoadedInstances = 1; + private final ConcurrentLinkedQueue loadedRewardedInterstitialQueue = new ConcurrentLinkedQueue<>(); + + private String rewardedInterstitialAdUnitId = ""; + + public void AdMob_RewardedInterstitial_Set_AdUnit(String adUnitId) { + rewardedInterstitialAdUnitId = adUnitId; } - public void AdMob_RewardedInterstitial_Load() { - if (mRewardedInterstitialAd == null) - RunnerActivity.ViewHandler.post(new Runnable() { - public void run() { - RewardedInterstitialAd.load(activity, mRewardedInterstitialAdID, AdMob_AdRequest(), - new RewardedInterstitialAdLoadCallback() { - @Override - public void onAdFailedToLoad(@NonNull LoadAdError loadAdError) { - mRewardedInterstitialAd = null; - - int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); - RunnerJNILib.DsMapAddString(dsMapIndex, "type", - "AdMob_RewardedInterstitial_OnLoadFailed"); - RunnerJNILib.DsMapAddString(dsMapIndex, "errorMessage", loadAdError.getMessage()); - RunnerJNILib.DsMapAddDouble(dsMapIndex, "errorCode", loadAdError.getCode()); - RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); - } + public void AdMob_RewardedInterstitial_Free_Loaded_Instances(double count) { + if (count < 0) { + count = loadedRewardedInterstitialQueue.size(); + } - @Override - public void onAdLoaded(@NonNull RewardedInterstitialAd rewardedInterstitialAd_) { - mRewardedInterstitialAd = rewardedInterstitialAd_; + while (count > 0 && loadedRewardedInterstitialQueue.size() > 0) { + loadedRewardedInterstitialQueue.poll(); + count--; + } + } + + public void AdMob_RewardedInterstitial_Max_Instances(double value) { + rewardedInterstitialMaxLoadedInstances = (int) value; + + int size = loadedRewardedInterstitialQueue.size(); + if (size <= value) return; + + AdMob_RewardedInterstitial_Free_Loaded_Instances(size - value); + } - int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); - RunnerJNILib.DsMapAddString(dsMapIndex, "type", - "AdMob_RewardedInterstitial_OnLoaded"); - RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + public double AdMob_RewardedInterstitial_Load() { + + final String callingMethod = "AdMob_RewardedInterstitial_Load"; + + if (!validateInitialized(callingMethod)) + return ADMOB_ERROR_NOT_INITIALIZED; + + if (!validateAdId(rewardedInterstitialAdUnitId, callingMethod)) + return ADMOB_ERROR_INVALID_AD_ID; + + if (!validateLoadedAdsLimit(loadedRewardedInterstitialQueue, rewardedInterstitialMaxLoadedInstances, + callingMethod)) + return ADMOB_ERROR_AD_LIMIT_REACHED; + + RunnerActivity.ViewHandler.post(new Runnable() { + + final String adUnitId = rewardedInterstitialAdUnitId; + + public void run() { + RewardedInterstitialAd.load(activity, rewardedInterstitialAdUnitId, buildAdRequest(), + new RewardedInterstitialAdLoadCallback() { + @Override + public void onAdLoaded(@NonNull RewardedInterstitialAd rewardedInterstitialAd) { + + if (!validateLoadedAdsLimit(loadedRewardedInterstitialQueue, + rewardedInterstitialMaxLoadedInstances, callingMethod)) + return; + + loadedRewardedInterstitialQueue.add(rewardedInterstitialAd); + + if (triggerOnPaidEvent) { + final RewardedInterstitialAd rewardedInterstitialAdRef = rewardedInterstitialAd; + + rewardedInterstitialAd.setOnPaidEventListener(new OnPaidEventListener() { + @Override + public void onPaidEvent(@NonNull AdValue adValue) { + AdapterResponseInfo loadedAdapterResponseInfo = rewardedInterstitialAdRef + .getResponseInfo().getLoadedAdapterResponseInfo(); + if (loadedAdapterResponseInfo == null) return; + onPaidEventHandler(adValue, rewardedInterstitialAdRef.getAdUnitId(), + "RewardedInterstitial", loadedAdapterResponseInfo, + rewardedInterstitialAdRef.getResponseInfo() + .getMediationAdapterClassName()); + } + }); } - }); - } - }); + + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_RewardedInterstitial_OnLoaded"); + RunnerJNILib.DsMapAddString(dsMapIndex, "unit_id", adUnitId); + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + } + + @Override + public void onAdFailedToLoad(@NonNull LoadAdError loadAdError) { + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString(dsMapIndex, "type", + "AdMob_RewardedInterstitial_OnLoadFailed"); + RunnerJNILib.DsMapAddString(dsMapIndex, "unit_id", adUnitId); + RunnerJNILib.DsMapAddString(dsMapIndex, "errorMessage", loadAdError.getMessage()); + RunnerJNILib.DsMapAddDouble(dsMapIndex, "errorCode", loadAdError.getCode()); + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + } + }); + } + }); + return 0; } - public void AdMob_RewardedInterstitial_Show() { - if (mRewardedInterstitialAd == null) - return; + public double AdMob_RewardedInterstitial_Show() { + + final String callingMethod = "AdMob_RewardedInterstitial_Show"; + + if (!validateInitialized(callingMethod)) + return ADMOB_ERROR_NOT_INITIALIZED; + if (!validateAdLoaded(loadedRewardedInterstitialQueue, callingMethod)) + return ADMOB_ERROR_NO_ADS_LOADED; + + final RewardedInterstitialAd rewardedInterstitialAd = loadedRewardedInterstitialQueue.poll(); RunnerActivity.ViewHandler.post(new Runnable() { public void run() { - mRewardedInterstitialAd.setFullScreenContentCallback(new FullScreenContentCallback() { + + assert rewardedInterstitialAd != null; + rewardedInterstitialAd.setFullScreenContentCallback(new FullScreenContentCallback() { @Override public void onAdDismissedFullScreenContent() { int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_RewardedInterstitial_OnDismissed"); + RunnerJNILib.DsMapAddString(dsMapIndex, "unit_id", rewardedInterstitialAd.getAdUnitId()); RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); } @Override - public void onAdFailedToShowFullScreenContent(AdError adError) { + public void onAdFailedToShowFullScreenContent(@NonNull AdError adError) { + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_RewardedInterstitial_OnShowFailed"); + RunnerJNILib.DsMapAddString(dsMapIndex, "unit_id", rewardedInterstitialAd.getAdUnitId()); RunnerJNILib.DsMapAddString(dsMapIndex, "errorMessage", adError.getMessage()); RunnerJNILib.DsMapAddDouble(dsMapIndex, "errorCode", adError.getCode()); RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); @@ -565,129 +965,272 @@ public void onAdFailedToShowFullScreenContent(AdError adError) { public void onAdShowedFullScreenContent() { int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_RewardedInterstitial_OnFullyShown"); + RunnerJNILib.DsMapAddString(dsMapIndex, "unit_id", rewardedInterstitialAd.getAdUnitId()); RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); } }); - mRewardedInterstitialAd.show(activity, new OnUserEarnedRewardListener() { - @Override - public void onUserEarnedReward(@NonNull RewardItem rewardItem) { - int rewardAmount = rewardItem.getAmount(); - String rewardType = rewardItem.getType(); + rewardedInterstitialAd.show(activity, rewardItem -> { + int rewardAmount = rewardItem.getAmount(); + String rewardType = rewardItem.getType(); - int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); - RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_RewardedInterstitial_OnReward"); - RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); - } + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_RewardedInterstitial_OnReward"); + RunnerJNILib.DsMapAddString(dsMapIndex, "unit_id", rewardedInterstitialAd.getAdUnitId()); + RunnerJNILib.DsMapAddDouble(dsMapIndex, "reward_amount", rewardAmount); + RunnerJNILib.DsMapAddString(dsMapIndex, "reward_type", rewardType); + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); }); - mRewardedInterstitialAd = null; + + isShowingAd = true; } }); + return 0; } public double AdMob_RewardedInterstitial_IsLoaded() { - if (mRewardedInterstitialAd == null) - return 0.0; + return AdMob_RewardedInterstitial_Instances_Count() > 0 ? 1.0 : 0.0; + } - return 1.0; + public double AdMob_RewardedInterstitial_Instances_Count() { + return loadedRewardedInterstitialQueue.size(); } - ///// TARGETING - ///// /////////////////////////////////////////////////////////////////////////////////// + // #endregion - public void AdMob_Targeting_COPPA(double COPPA) { - targetCOPPA = COPPA > 0.5; + // #region App Open + + private Boolean isShowingAd = false; + private Boolean isAppOpenAdEnabled = false; + private AppOpenAd appOpenAdInstance = null; + + private long appOpenAdLoadTime = 0; + private int appOpenAdOrientation = AppOpenAd.APP_OPEN_AD_ORIENTATION_LANDSCAPE; + + private String appOpenAdUnitId = ""; + + public void AdMob_AppOpenAd_Set_AdUnit(String adUnitId) { + appOpenAdUnitId = adUnitId; } - public void AdMob_Targeting_UnderAge(double underAge) { - targetUnderAge = underAge >= 0.5; + public double AdMob_AppOpenAd_Enable(double orientation) { + + final String callingMethod = "AdMob_AppOpenAd_Enable"; + + if (!validateInitialized(callingMethod)) + return ADMOB_ERROR_NOT_INITIALIZED; + + if (!validateAdId(appOpenAdUnitId, callingMethod)) + return ADMOB_ERROR_INVALID_AD_ID; + + appOpenAdInstance = null; + isAppOpenAdEnabled = true; + appOpenAdOrientation = (orientation == 0) ? AppOpenAd.APP_OPEN_AD_ORIENTATION_LANDSCAPE + : AppOpenAd.APP_OPEN_AD_ORIENTATION_PORTRAIT; + loadAppOpenAd(); + + return 0; } - public void AdMob_Targeting_MaxAdContentRating(double contentRating) { - switch ((int) contentRating) { - case 0: - maxAdContentRating = RequestConfiguration.MAX_AD_CONTENT_RATING_G; - break; - case 1: - maxAdContentRating = RequestConfiguration.MAX_AD_CONTENT_RATING_PG; - break; - case 2: - maxAdContentRating = RequestConfiguration.MAX_AD_CONTENT_RATING_T; - break; - case 3: - maxAdContentRating = RequestConfiguration.MAX_AD_CONTENT_RATING_MA; - break; + public void AdMob_AppOpenAd_Disable() { + appOpenAdInstance = null; + isAppOpenAdEnabled = false; + } + + public double AdMob_AppOpenAd_IsEnabled() { + return isAppOpenAdEnabled ? 1.0 : 0.0; + } + + public void onResume() { + if (!isShowingAd) { + showAppOpenAd(); } + isShowingAd = false; } - private boolean testID_on = false; - private boolean targetCOPPA = false; - private boolean targetUnderAge = false; - private String maxAdContentRating = RequestConfiguration.MAX_AD_CONTENT_RATING_G; + private void loadAppOpenAd() { - private RequestConfiguration requestConfigurationBuilder() { - RequestConfiguration.Builder mRequestConfiguration = new RequestConfiguration.Builder(); + final String callingMethod = "__AdMob_AppOpenAd_Load"; - if (testID_on) { - List testDeviceIds = Arrays.asList(getDeviceID()); - mRequestConfiguration = mRequestConfiguration.setTestDeviceIds(testDeviceIds); - } + if (!isAppOpenAdEnabled) + return; - if (targetCOPPA) - mRequestConfiguration = mRequestConfiguration - .setTagForChildDirectedTreatment(RequestConfiguration.TAG_FOR_CHILD_DIRECTED_TREATMENT_TRUE); + if (!validateInitialized(callingMethod)) + return; - if (targetUnderAge) - mRequestConfiguration = mRequestConfiguration - .setTagForUnderAgeOfConsent(RequestConfiguration.TAG_FOR_UNDER_AGE_OF_CONSENT_TRUE); + if (!validateAdId(appOpenAdUnitId, callingMethod)) + return; + + RunnerActivity.ViewHandler.post(() -> { + + final String adUnitId = appOpenAdUnitId; - return mRequestConfiguration.build(); + AppOpenAd.load(activity, appOpenAdUnitId, buildAdRequest(), appOpenAdOrientation, + new AppOpenAdLoadCallback() { + @Override + public void onAdLoaded(@NonNull AppOpenAd appOpenAd) { + + appOpenAdLoadTime = (new Date()).getTime(); + appOpenAdInstance = appOpenAd; + + if (triggerOnPaidEvent) { + + final AppOpenAd appOpenAdRef = appOpenAd; + appOpenAd.setOnPaidEventListener(adValue -> { + AdapterResponseInfo loadedAdapterResponseInfo = appOpenAdRef + .getResponseInfo() + .getLoadedAdapterResponseInfo(); + if(loadedAdapterResponseInfo == null) return; + onPaidEventHandler(adValue, appOpenAdRef.getAdUnitId(), "AppOpen", + loadedAdapterResponseInfo, + appOpenAdRef.getResponseInfo().getMediationAdapterClassName()); + }); + } + + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_AppOpenAd_OnLoaded"); + RunnerJNILib.DsMapAddString(dsMapIndex, "unit_id", adUnitId); + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + } + + @Override + public void onAdFailedToLoad(@NonNull LoadAdError loadAdError) { + appOpenAdInstance = null; + + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_AppOpenAd_OnLoadFailed"); + RunnerJNILib.DsMapAddString(dsMapIndex, "unit_id", adUnitId); + RunnerJNILib.DsMapAddString(dsMapIndex, "errorMessage", loadAdError.getMessage()); + RunnerJNILib.DsMapAddDouble(dsMapIndex, "errorCode", loadAdError.getCode()); + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + } + }); + }); } - ///// UTILS - ///// /////////////////////////////////////////////////////////////////////////////////////// + private void showAppOpenAd() { + if (!isAppOpenAdEnabled) + return; - public void AdMob_NonPersonalizedAds_Set(double value) { - NPA = value >= 0.5; + final String callingMethod = "__AdMob_AppOpenAd_Show"; + + if (!validateInitialized(callingMethod)) + return; + + if (!appOpenAdIsValid(4, callingMethod)) { + appOpenAdInstance = null; + loadAppOpenAd(); + return; + } + + RunnerActivity.ViewHandler.post(() -> { + if (appOpenAdInstance == null) + return; + + appOpenAdInstance.setFullScreenContentCallback(new FullScreenContentCallback() { + @Override + public void onAdDismissedFullScreenContent() { + + appOpenAdInstance = null; + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_AppOpenAd_OnDismissed"); + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + loadAppOpenAd(); + } + + @Override + public void onAdFailedToShowFullScreenContent(@NonNull AdError adError) { + + appOpenAdInstance = null; + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_AppOpenAd_OnShowFailed"); + RunnerJNILib.DsMapAddString(dsMapIndex, "errorMessage", adError.getMessage()); + RunnerJNILib.DsMapAddDouble(dsMapIndex, "errorCode", adError.getCode()); + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + loadAppOpenAd(); + } + + @Override + public void onAdShowedFullScreenContent() { + appOpenAdInstance = null; + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_AppOpenAd_OnFullyShown"); + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + loadAppOpenAd(); + } + }); + + isShowingAd = true; + appOpenAdInstance.show(activity); + appOpenAdInstance = null; + }); } - public boolean NPA = false; + private Boolean appOpenAdIsValid(int expirationTimeHours, String callingMethod) { - private AdRequest AdMob_AdRequest() { - AdRequest.Builder builder = new AdRequest.Builder(); + if (appOpenAdInstance == null) { + Log.i(LOG_TAG, callingMethod + " :: There is no app open ad loaded."); + return false; + } - if (NPA) { - Bundle extras = new Bundle(); - extras.putString("npa", "1"); - builder.addNetworkExtrasBundle(AdMobAdapter.class, extras); + long dateDifference = (new Date()).getTime() - appOpenAdLoadTime; + boolean expired = dateDifference >= (3600000L * expirationTimeHours); + + if (expired) { + Log.i(LOG_TAG, callingMethod + " :: The loaded app open ad expired, reloading..."); + return false; } - return builder.build(); + return true; } - private String getDeviceID() { - String android_id = Settings.Secure.getString(activity.getContentResolver(), Settings.Secure.ANDROID_ID); - String deviceId = MD5(android_id).toUpperCase(); - return deviceId; + // #endregion + + // #region Targeting + + private boolean targetCOPPA = false; + public double AdMob_Targeting_COPPA(double COPPA) { + + if (!validateNotInitialized("AdMob_Targeting_COPPA")) return ADMOB_ERROR_ILLEGAL_CALL; + + targetCOPPA = COPPA > 0.5; + return 0; } - // https://stackoverflow.com/questions/4846484/md5-hashing-in-android/21333739#21333739 - private String MD5(String md5) { - try { - java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5"); - byte[] array = md.digest(md5.getBytes("UTF-8")); - StringBuffer sb = new StringBuffer(); - for (int i = 0; i < array.length; ++i) { - sb.append(Integer.toHexString((array[i] & 0xFF) | 0x100).substring(1, 3)); - } - return sb.toString(); - } catch (Exception e) { - return null; + private boolean targetUnderAge = false; + public double AdMob_Targeting_UnderAge(double underAge) { + + if (!validateNotInitialized("AdMob_Targeting_UnderAge")) return ADMOB_ERROR_ILLEGAL_CALL; + + targetUnderAge = underAge >= 0.5; + return 0; + } + + private String maxAdContentRating = RequestConfiguration.MAX_AD_CONTENT_RATING_G; + public double AdMob_Targeting_MaxAdContentRating(double contentRating) { + + if (!validateNotInitialized("AdMob_Targeting_MaxAdContentRating")) return ADMOB_ERROR_ILLEGAL_CALL; + + switch ((int) contentRating) { + case 0: + maxAdContentRating = RequestConfiguration.MAX_AD_CONTENT_RATING_G; + break; + case 1: + maxAdContentRating = RequestConfiguration.MAX_AD_CONTENT_RATING_PG; + break; + case 2: + maxAdContentRating = RequestConfiguration.MAX_AD_CONTENT_RATING_T; + break; + case 3: + maxAdContentRating = RequestConfiguration.MAX_AD_CONTENT_RATING_MA; + break; } + return 0; } - ///// CONSENT - ///// ///////////////////////////////////////////////////////////////////////////////////// + //#endregion + + // #region Consent // EU Consent: https://developers.google.com/admob/android/eu-consent public ConsentInformation consentInformation; @@ -698,34 +1241,28 @@ public void AdMob_Consent_RequestInfoUpdate(double mode) { if (mode != 3) { ConsentDebugSettings debugSettings = new ConsentDebugSettings.Builder(activity) - .setDebugGeography((int) mode)// ConsentDebugSettings.DebugGeography.DEBUG_GEOGRAPHY_EEA) + .setDebugGeography((int) mode) .addTestDeviceHashedId(getDeviceID()) .build(); - builder = builder.setConsentDebugSettings(debugSettings); + builder.setConsentDebugSettings(debugSettings); } ConsentRequestParameters params = builder.build(); consentInformation = UserMessagingPlatform.getConsentInformation(activity); consentInformation.requestConsentInfoUpdate(activity, params, - new ConsentInformation.OnConsentInfoUpdateSuccessListener() { - @Override - public void onConsentInfoUpdateSuccess() { - int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); - RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_Consent_OnRequestInfoUpdated"); - RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); - } + () -> { + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_Consent_OnRequestInfoUpdated"); + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); }, - new ConsentInformation.OnConsentInfoUpdateFailureListener() { - @Override - public void onConsentInfoUpdateFailure(FormError formError) { - int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); - RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_Consent_OnRequestInfoUpdateFailed"); - RunnerJNILib.DsMapAddString(dsMapIndex, "errorMessage", formError.getMessage()); - RunnerJNILib.DsMapAddDouble(dsMapIndex, "errorCode", formError.getErrorCode()); - RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); - } + formError -> { + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_Consent_OnRequestInfoUpdateFailed"); + RunnerJNILib.DsMapAddString(dsMapIndex, "errorMessage", formError.getMessage()); + RunnerJNILib.DsMapAddDouble(dsMapIndex, "errorCode", formError.getErrorCode()); + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); }); } @@ -754,56 +1291,37 @@ public double AdMob_Consent_IsFormAvailable() { return consentInformation == null ? 0.0 : (consentInformation.isConsentFormAvailable() ? 1.0 : 0.0); } - public ConsentForm consentForm; + public ConsentForm consentFormInstance; public void AdMob_Consent_Load() { - RunnerActivity.ViewHandler.post(new Runnable() { - public void run() { - UserMessagingPlatform.loadConsentForm(activity, - new UserMessagingPlatform.OnConsentFormLoadSuccessListener() { - @Override - public void onConsentFormLoadSuccess(ConsentForm consent_form) { - consentForm = consent_form; - int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); - RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_Consent_OnLoaded"); - RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); - } - }, - new UserMessagingPlatform.OnConsentFormLoadFailureListener() { - @Override - public void onConsentFormLoadFailure(FormError formError) { - int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); - RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_Consent_OnLoadFailed"); - RunnerJNILib.DsMapAddString(dsMapIndex, "errorMessage", formError.getMessage()); - RunnerJNILib.DsMapAddDouble(dsMapIndex, "errorCode", formError.getErrorCode()); - RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); - } - }); - } - }); + RunnerActivity.ViewHandler.post(() -> UserMessagingPlatform.loadConsentForm(activity, + consentForm -> { + consentFormInstance = consentForm; + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_Consent_OnLoaded"); + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + }, + formError -> { + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_Consent_OnLoadFailed"); + RunnerJNILib.DsMapAddString(dsMapIndex, "errorMessage", formError.getMessage()); + RunnerJNILib.DsMapAddDouble(dsMapIndex, "errorCode", formError.getErrorCode()); + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + })); } public void AdMob_Consent_Show() { - RunnerActivity.ViewHandler.post(new Runnable() { - public void run() { - consentForm.show(activity, new ConsentForm.OnConsentFormDismissedListener() { - @Override - public void onConsentFormDismissed(@Nullable FormError formError) { - if (formError == null) { - int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); - RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_Consent_OnShown"); - RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); - } else { - int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); - RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_Consent_OnShowFailed"); - RunnerJNILib.DsMapAddString(dsMapIndex, "errorMessage", formError.getMessage()); - RunnerJNILib.DsMapAddDouble(dsMapIndex, "errorCode", formError.getErrorCode()); - RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); - } - } - }); + RunnerActivity.ViewHandler.post(() -> consentFormInstance.show(activity, formError -> { + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + if (formError == null) { + RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_Consent_OnShown"); + } else { + RunnerJNILib.DsMapAddString(dsMapIndex, "type", "AdMob_Consent_OnShowFailed"); + RunnerJNILib.DsMapAddString(dsMapIndex, "errorMessage", formError.getMessage()); + RunnerJNILib.DsMapAddDouble(dsMapIndex, "errorCode", formError.getErrorCode()); } - }); + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + })); } public void AdMob_Consent_Reset() { @@ -811,28 +1329,55 @@ public void AdMob_Consent_Reset() { consentInformation.reset(); } - ///// SETTINGS - ///// //////////////////////////////////////////////////////////////////////////////////// + //#endregion + + // #region Settings public void AdMob_Settings_SetVolume(double value) { MobileAds.setAppVolume((float) value); - AdsSoundReLoad(); } public void AdMob_Settings_SetMuted(double value) { MobileAds.setAppMuted(value >= 0.5); - AdsSoundReLoad(); } - private void AdsSoundReLoad() { - if (mInterstitialID != null) { - mInterstitialAd = null; - AdMob_Interstitial_Load(); + //#endregion + + // #region Internals + + private AdRequest buildAdRequest() { + AdRequest.Builder builder = new AdRequest.Builder(); + + // As per Google's request + builder.setRequestAgent("gmext-admob-" + RunnerJNILib.extGetVersion("AdMob")); + + // This is deprectated and shouldn't be used keeping it for the sake of compatibility + if (nonPersonalizedAds) { + Bundle extras = new Bundle(); + extras.putString("npa", "1"); + builder.addNetworkExtrasBundle(AdMobAdapter.class, extras); } - if (mRewardedAdID != null) { - mRewardedAd = null; - AdMob_RewardedVideo_Load(); + return builder.build(); + } + + private String getDeviceID() { + String android_id = Settings.Secure.getString(activity.getContentResolver(), Settings.Secure.ANDROID_ID); + return Objects.requireNonNull(MD5(android_id)).toUpperCase(); + } + + // https://stackoverflow.com/questions/4846484/md5-hashing-in-android/21333739#21333739 + private String MD5(String md5) { + try { + java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5"); + byte[] array = md.digest(md5.getBytes(StandardCharsets.UTF_8)); + StringBuilder sb = new StringBuilder(); + for (byte b : array) { + sb.append(Integer.toHexString((b & 0xFF) | 0x100).substring(1, 3)); + } + return sb.toString(); + } catch (Exception e) { + return null; } } @@ -902,7 +1447,7 @@ private boolean hasAttribute(String input, int index) { private boolean hasConsentFor(List indexes, String purposeConsent, boolean hasVendorConsent) { for (Integer p : indexes) { if (!hasAttribute(purposeConsent, p)) { - Log.e("yoyo", "hasConsentFor: denied for purpose #" + p); + Log.e(LOG_TAG, "hasConsentFor: denied for purpose #" + p); return false; } } @@ -916,11 +1461,62 @@ private boolean hasConsentOrLegitimateInterestFor(List indexes, String boolean purposeConsentAndVendorConsent = hasAttribute(purposeConsent, p) && hasVendorConsent; boolean isOk = purposeAndVendorLI || purposeConsentAndVendorConsent; if (!isOk) { - Log.e("yoyo", "hasConsentOrLegitimateInterestFor: denied for #" + p); + Log.e(LOG_TAG, "hasConsentOrLegitimateInterestFor: denied for #" + p); return false; } } return true; } -} \ No newline at end of file + //#endregion + + // #region Validations + + private Boolean validateNotInitialized(String callingMethod) { + if (isInitialized) { + Log.i(LOG_TAG, callingMethod + " :: Method cannot be called after initialization."); + } + return !isInitialized; + } + + private Boolean validateInitialized(String callingMethod) { + if (!isInitialized) { + Log.i(LOG_TAG, callingMethod + " :: Extension was not initialized."); + } + return isInitialized; + } + + private Boolean validateActiveBannerAd(String callingMethod) { + if (bannerAdView == null) { + Log.i(LOG_TAG, callingMethod + " :: There is no active banner ad."); + return false; + } + return true; + } + + private Boolean validateAdId(String adUnitId, String callingMethod) { + if (adUnitId.isEmpty()) { + Log.i(LOG_TAG, callingMethod + " :: Extension was not initialized."); + return false; + } + return true; + } + + private Boolean validateLoadedAdsLimit(Queue queue, int maxSize, String callingMethod) { + if (queue.size() >= maxSize) { + Log.i(LOG_TAG, callingMethod + " :: Maximum number of loaded ads reached."); + return false; + } + return true; + } + + private Boolean validateAdLoaded(Queue queue, String callingMethod) { + if (queue.size() == 0) { + Log.i(LOG_TAG, callingMethod + " :: There is no loaded ad in queue."); + return false; + } + return true; + } + + // #endregion +} diff --git a/extensions/AdMob/docs/404.html b/extensions/AdMob/docs/404.html new file mode 100644 index 000000000..4c84caf21 --- /dev/null +++ b/extensions/AdMob/docs/404.html @@ -0,0 +1,162 @@ + + + + + + + + GMEXT-AdMob + + + + + + + + + + + + + + +
+ + +
+ +
+
+
    +
  • +
  • +
  • +
+
+
+
+
+ + +

404

+ +

Page not found

+ + +
+
+ +
+
+ +
+ +
+ +
+ + + + GitHub + + + + + +
+ + + + + + + + + + diff --git a/extensions/AdMob/docs/_Footer.html b/extensions/AdMob/docs/_Footer.html new file mode 100644 index 000000000..185901fda --- /dev/null +++ b/extensions/AdMob/docs/_Footer.html @@ -0,0 +1,167 @@ + + + + + + + + Footer - GMEXT-AdMob + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+ +
+
+
+
+ +

YoYoGames 2024

+ +
+
+ +
+
+ +
+ +
+ +
+ + + + GitHub + + + + + +
+ + + + + + + + + + diff --git a/extensions/AdMob/docs/_Sidebar.html b/extensions/AdMob/docs/_Sidebar.html new file mode 100644 index 000000000..77b19efc5 --- /dev/null +++ b/extensions/AdMob/docs/_Sidebar.html @@ -0,0 +1,189 @@ + + + + + + + + Sidebar - GMEXT-AdMob + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+ +
+
+ + +
+
+ +
+ +
+ +
+ + + + GitHub + + + + + +
+ + + + + + + + + + diff --git a/extensions/AdMob/docs/app_open.html b/extensions/AdMob/docs/app_open.html new file mode 100644 index 000000000..9b12853d0 --- /dev/null +++ b/extensions/AdMob/docs/app_open.html @@ -0,0 +1,434 @@ + + + + + + + + App Open - GMEXT-AdMob + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+ +
+
+
+
+ +

+

App Open

+

Functions

+

This module offers a collection of functions designed to address specific tasks and provide utilities for various purposes. Explore the available functions to make the most of the functionalities provided by this module.

+ +


+
+

Back To Top

+ +

AdMob_AppOpenAd_Init

+
+

⛔️ This function was deprecated with version 1.3.0.

+
+

Initializes the target identifier for app open ads functions.

+
+

Note

+

Please refer to AdMob_AppOpenAd_Set_AdUnit for more information.

+
+


+

Syntax:

+
+
AdMob_AppOpenAd_Init(adUnitId)
+
+ + + + + + + + + + + + + + + +
ArgumentTypeDescription
adUnitIdString
+


+

Returns:

+
+

N/A

+
+


+

Versioning:

+
    +
  • 1.3.0 - ⛔️ This function was deprecated.
  • +
+


+


+
+

Back To Top

+ +

AdMob_AppOpenAd_Set_AdUnit

+

Set the target identifier for app open ads functions, app open ads funcitons doesn't allow multiple pre-loaded identifiers.

+


+

Syntax:

+
+
AdMob_AppOpenAd_Set_AdUnit(adUnitId)
+
+ + + + + + + + + + + + + + + +
ArgumentTypeDescription
adUnitIdString
+


+

Returns:

+
+

N/A

+
+


+

Versioning:

+
    +
  • 1.3.0 - This function was introduced.
  • +
+


+


+
+

Back To Top

+ +

AdMob_AppOpenAd_Enable

+

Enable show App Open Ads when game resumes from background.

+

This function operates asynchronously, which means that it does not immediately return the requested result. Instead, upon completion of the task, it will trigger the Social Async Event.

+


+

Syntax:

+
+
AdMob_AppOpenAd_Enable(orientation)
+
+ + + + + + + + + + + + + + + +
ArgumentTypeDescription
orientationReal
+


+

Returns:

+
+

AdMobErrors

+
+


+

Triggers:

+
+

Social Async Event

+
+

This event is triggered when the ad view is closed by the user.

+ + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeString"AdMob_AppOpenAd_OnDismissed"
unit_idStringUnit identifier of the advertisment
+


+

This event is triggered is the awaited task fails.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeString"AdMob_AppOpenAd_OnShowFailed"
unit_idStringUnit identifier of the advertisment
errorMessageStringthe error code responsible for the failure
errorCodeRealthe error message of the error code
+


+

This event is triggered is the awaited task succeeds.

+ + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeString"AdMob_AppOpenAd_OnFullyShown"
unit_idStringUnit identifier of the advertisment
+


+

Versioning:

+
    +
  • 1.3.0 - This function was introduced.
  • +
+


+


+
+

Back To Top

+ +

AdMob_AppOpenAd_Disable

+

Disable show App Open Ads when game resume

+


+

Syntax:

+
+
AdMob_AppOpenAd_Disable()
+
+


+

Returns:

+
+

AdMobErrors

+
+


+

Versioning:

+
    +
  • 1.3.0 - This function was introduced.
  • +
+


+


+
+

Back To Top

+ +

AdMob_AppOpenAd_IsEnabled

+

Return the true if app open ads are enabled. Otherwise return false.

+


+

Syntax:

+
+
AdMob_AppOpenAd_IsEnabled()
+
+


+

Returns:

+
+

Boolean

+
+


+


+ +
+
+ +
+
+ +
+ +
+ +
+ + + + GitHub + + + + « Previous + + + Next » + + +
+ + + + + + + + + + diff --git a/extensions/AdMob/docs/assets/admob_android_ios_config.png b/extensions/AdMob/docs/assets/admob_android_ios_config.png new file mode 100644 index 000000000..08704193e Binary files /dev/null and b/extensions/AdMob/docs/assets/admob_android_ios_config.png differ diff --git a/extensions/AdMob/docs/assets/css/gmext_style.css b/extensions/AdMob/docs/assets/css/gmext_style.css new file mode 100644 index 000000000..9e2e42e83 --- /dev/null +++ b/extensions/AdMob/docs/assets/css/gmext_style.css @@ -0,0 +1,65 @@ +.wy-table-responsive table td, .wy-table-responsive th { + word-wrap: break-word; + white-space: normal; /* Allows text to wrap within cells */ +} + +.wy-table-responsive thead, +.wy-table-responsive tbody, +.wy-table-responsive th, +.wy-table-responsive tr { + width: 1000px; +} + +.wy-table-responsive th:not(:last-child), +.wy-table-responsive td:not(:last-child) { + width: 20%; /* Adjust based on the number of columns */ +} + +.wy-table-responsive img, +.wy-table-responsive iframe { + max-width: 100%; + height: auto; /* Maintain aspect ratio for images */ +} + +.wy-table-responsive pre, +.wy-table-responsive code { + overflow-x: auto; /* Allows horizontal scrolling for long unbreakable content */ + white-space: pre-wrap; /* Allows text to wrap within pre/code blocks */ + word-wrap: break-word; /* Breaks long words if necessary */ +} + +hr { + height: 2px; + background:#03759b; +} + +/* Adjust emoji size */ +.emojione { + height: 1em; /* Matches the line-height of surrounding text */ + width: 1em; /* Keeps the emoji width consistent with its height */ + vertical-align: middle; /* Aligns emoji with the middle of the text line */ +} + +.copy-code-button { + display: inline-flex; /* Use flexbox to center the icon */ + justify-content: center; /* Center content horizontally */ + align-items: center; /* Center content vertically */ + position: relative; + top: -0.5em; + right: -0.5em; + float: right; + width: 1.8em; /* Set both width */ + height: 1.8em; /* and height to make the button square */ + padding: 0; /* Adjust padding as needed */ + margin-bottom: -3em; + background-color: #007bff; /* Blue background */ + color: white; + border: none; + cursor: pointer; + border-radius: 3px; + font-size: 1em; /* Adjust the icon size as necessary */ +} + +.copy-code-button:hover { + background-color: #0056b3; +} diff --git a/extensions/AdMob/docs/assets/js/gmext_script.js b/extensions/AdMob/docs/assets/js/gmext_script.js new file mode 100644 index 000000000..f6bf67d59 --- /dev/null +++ b/extensions/AdMob/docs/assets/js/gmext_script.js @@ -0,0 +1,49 @@ +document.addEventListener('DOMContentLoaded', function() { + + // Top left link should point ot the github page + var link = document.querySelector('a.icon.icon-home'); + var githublink = document.querySelector('a.fa.fa-github') + if (link && githublink) { + link.href = githublink.href; + } + + // Point home icon to home.html + var home_link = document.querySelector('a.icon.icon-home[aria-label="Docs"]'); + home_link.href = 'home.html' + + // Remove the editor icon + var element = document.querySelector('li.wy-breadcrumbs-aside'); + if (element) { + element.remove(); + } + + // Add copy-to-clipboard on code blocks + const codeBlocks = document.querySelectorAll('pre code'); + codeBlocks.forEach(function(codeBlock) { + const button = document.createElement('button'); + button.className = 'copy-code-button'; + button.type = 'button'; + button.innerHTML = ''; // Clipboard icon + button.addEventListener('click', function() { + navigator.clipboard.writeText(codeBlock.innerText).then(() => { + const originalInnerHTML = button.innerHTML; + button.innerHTML = ''; // Check icon + button.style.backgroundColor = "#28a745"; // Change button to green + setTimeout(() => { + button.innerHTML = originalInnerHTML; // Reset icon + button.style.backgroundColor = ""; // Reset button color + }, 2000); // Reset icon and button color after 2 seconds + }, (err) => { + console.error('Failed to copy text: ', err); + }); + }); + + const pre = codeBlock.parentNode; + if (pre.parentNode.classList.contains('highlight')) { + const highlight = pre.parentNode; + highlight.parentNode.insertBefore(button, highlight); + } else { + pre.parentNode.insertBefore(button, pre); + } + }); +}); diff --git a/extensions/AdMob/docs/banner.html b/extensions/AdMob/docs/banner.html new file mode 100644 index 000000000..7dff2c095 --- /dev/null +++ b/extensions/AdMob/docs/banner.html @@ -0,0 +1,483 @@ + + + + + + + + Banner - GMEXT-AdMob + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+ +
+
+
+
+ +

+

Banner

+

Functions

+

This module offers a collection of functions designed to address specific tasks and provide utilities for various purposes. Explore the available functions to make the most of the functionalities provided by this module.

+ +


+
+

Back To Top

+ +

AdMob_Banner_Init

+
+

⛔️ This function was deprecated with version 1.3.0.

+
+

Initializes the target identifier for banner functions.

+
+

Note

+

Please refer to AdMob_Banner_Set_AdUnit for more information.

+
+


+

Syntax:

+
+
AdMob_Banner_Init(adUnitId)
+
+ + + + + + + + + + + + + + + +
ArgumentTypeDescription
adUnitIdString
+


+

Returns:

+
+

N/A

+
+


+

Versioning:

+
    +
  • 1.3.0 - ⛔️ This function was deprecated.
  • +
+


+


+
+

Back To Top

+ +

AdMob_Banner_Set_AdUnit

+

Set the target identifier for banner functions, Banner funcitons DOESN'T allow multiple preloaded identifiers.

+


+

Syntax:

+
+
AdMob_Banner_Set_AdUnit(adUnitId)
+
+ + + + + + + + + + + + + + + +
ArgumentTypeDescription
adUnitIdString
+


+

Returns:

+
+

N/A

+
+


+

Versioning:

+
    +
  • 1.3.0 - This function was introduced.
  • +
+


+


+
+

Back To Top

+ +

AdMob_Banner_Create

+

This function operates asynchronously, which means that it does not immediately return the requested result. Instead, upon completion of the task, it will trigger the Social Async Event.

+


+

Syntax:

+
+
AdMob_Banner_Create(size, bottom)
+
+ + + + + + + + + + + + + + + + + + + + +
ArgumentTypeDescription
sizeRealThe type of the banner to be displayed.
bottomBooleanWhether the banner should be placed at the bottom of the display.
+


+

Returns:

+
+

AdMobErrors

+
+


+

Triggers:

+
+

Social Async Event

+
+

This event is triggered is the awaited task succeeds.

+ + + + + + + + + + + + + + + +
KeyTypeDescription
typeString"AdMob_Banner_OnLoaded"
+


+

This event is triggered is the awaited task fails.

+ + + + + + + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeString"AdMob_Banner_OnLoadFailed"
errorMessageStringthe error code responsible for the failure
errorCodeRealthe error message of the error code
+


+


+
+

Back To Top

+ +

AdMob_Banner_GetWidth

+

This function can be used to get the width of the currently loaded banner ad block. The value returned is in pixels. NOTE: This function returns the width in screen pixels, it’s up to the developer to convert the value to the correct scale according to the render target being used.

+


+

Syntax:

+
+
AdMob_Banner_GetWidth()
+
+


+

Returns:

+
+

Real

+
+


+


+
+

Back To Top

+ +

AdMob_Banner_GetHeight

+

This function can be used to get the height of the currently loaded banner ad block. The value returned is in pixels. NOTE: This function returns the height in screen pixels, it’s up to the developer to convert the value to the correct scale according to the render target being used.

+


+

Syntax:

+
+
AdMob_Banner_GetHeight()
+
+


+

Returns:

+
+

Real

+
+


+


+
+

Back To Top

+ +

AdMob_Banner_Move

+

This function can be used to move a banner that has been previously added. You supply a boolean that will determine if the banner should be placed at the bottom or at the top of the display.

+


+

Syntax:

+
+
AdMob_Banner_Move(bottom)
+
+ + + + + + + + + + + + + + + +
ArgumentTypeDescription
bottomBooleanWhether the banner should be placed at the bottom of the display.
+


+

Returns:

+
+

AdMobErrors

+
+


+


+
+

Back To Top

+ +

AdMob_Banner_Show

+

This function can be used to show the currently active, but hidden, banner ad block. When called, the banner will be shown to the user again and will be able to receive input. You can hide the banner again at any time using the AdMob_Banner_Hide function.

+


+

Syntax:

+
+
AdMob_Banner_Show()
+
+


+

Returns:

+
+

AdMobErrors

+
+


+


+
+

Back To Top

+ +

AdMob_Banner_Hide

+

This function can be used to hide the currently active banner ad block. When called, the banner will be removed from the user’s view and will no longer receive input. You can show the banner again at any time using the AdMob_Banner_Show function.

+


+

Syntax:

+
+
AdMob_Banner_Hide()
+
+


+

Returns:

+
+

AdMobErrors

+
+


+


+
+

Back To Top

+ +

AdMob_Banner_Remove

+

This function will remove the currently active banner from the app. If you call this function then want to show ads again, you must call the AdMob_Banner_Create function first to add a new banner to the display.

+


+

Syntax:

+
+
AdMob_Banner_Remove()
+
+


+

Returns:

+
+

AdMobErrors

+
+


+


+ +
+
+ +
+
+ +
+ +
+ +
+ + + + GitHub + + + + « Previous + + + Next » + + +
+ + + + + + + + + + diff --git a/extensions/AdMob/docs/consent.html b/extensions/AdMob/docs/consent.html new file mode 100644 index 000000000..56ff2cb2e --- /dev/null +++ b/extensions/AdMob/docs/consent.html @@ -0,0 +1,483 @@ + + + + + + + + Consent - GMEXT-AdMob + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+ +
+
+
+
+ +

+

Consent

+

Functions

+

This module offers a collection of functions designed to address specific tasks and provide utilities for various purposes. Explore the available functions to make the most of the functionalities provided by this module.

+ +


+
+

Back To Top

+ +

AdMob_Consent_RequestInfoUpdate

+

Requests a consent information update (this needs to be called prior to AdMob_Consent_Load)

+

This function operates asynchronously, which means that it does not immediately return the requested result. Instead, upon completion of the task, it will trigger the Social Async Event.

+


+

Syntax:

+
+
AdMob_Consent_RequestInfoUpdate(mode)
+
+ + + + + + + + + + + + + + + +
ArgumentTypeDescription
modeAdMobConsentMode
+


+

Returns:

+
+

N/A

+
+


+

Triggers:

+
+

Social Async Event

+
+ + + + + + + + + + + + + + + +
KeyTypeDescription
typeString"AdMob_Consent_OnRequestInfoUpdated"
+


+ + + + + + + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeString"AdMob_Consent_OnRequestInfoUpdateFailed"
errorMessageStringthe error code responsible for the failure
errorCodeRealthe error message of the error code
+


+


+
+

Back To Top

+ +

AdMob_Consent_GetStatus

+

Allows to set the mode of the consent request being used. This function allows you to debug different regions and EEA and NON-EEA and should be passed in as a 'AdMob_Consent_Mode_*' constant. This function should be called before AdMob_Consent_GetStatus and AdMob_Consent_GetType in order to get the correct output from both functions.

+
+

Requires a previous call to AdMob_Consent_RequestInfoUpdate

+
+


+

Syntax:

+
+
AdMob_Consent_GetStatus()
+
+


+

Returns:

+
+

AdMobConsentStatus

+
+


+


+
+

Back To Top

+ +

AdMob_Consent_GetType

+

Returns the answer given by the user to a previous GDPR consent request.

+


+

Syntax:

+
+
AdMob_Consent_GetType()
+
+


+

Returns:

+
+

AdMobConsentType

+
+


+


+
+

Back To Top

+ +

AdMob_Consent_IsFormAvailable

+

Checks whether or not the GDPR consent form is available on this device.

+


+

Syntax:

+
+
AdMob_Consent_IsFormAvailable()
+
+


+

Returns:

+
+

N/A

+
+


+


+
+

Back To Top

+ +

AdMob_Consent_Load

+

Loads the consent form into memory so it can be displayed to the user. If you do not call this function before trying to show the GDPR consent, nothing will be shown.

+
+

Requires a previous call to AdMob_Consent_RequestInfoUpdate

+
+

This function operates asynchronously, which means that it does not immediately return the requested result. Instead, upon completion of the task, it will trigger the Social Async Event.

+


+

Syntax:

+
+
AdMob_Consent_Load()
+
+


+

Returns:

+
+

N/A

+
+


+

Triggers:

+
+

Social Async Event

+
+ + + + + + + + + + + + + + + +
KeyTypeDescription
typeString"AdMob_Consent_OnLoaded"
+


+ + + + + + + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeString"AdMob_Consent_OnLoadFailed"
errorMessageStringthe error code responsible for the failure
errorCodeRealthe error message of the error code
+


+


+
+

Back To Top

+ +

AdMob_Consent_Show

+

Shows the consent form to the user. If you do not call the AdMob_Consent_Load function before trying to show the GDPR consent, nothing will be shown.

+
+

Requires a previous call to AdMob_Consent_Load

+
+

This function operates asynchronously, which means that it does not immediately return the requested result. Instead, upon completion of the task, it will trigger the Social Async Event.

+


+

Syntax:

+
+
AdMob_Consent_Show()
+
+


+

Returns:

+
+

N/A

+
+


+

Triggers:

+
+

Social Async Event

+
+ + + + + + + + + + + + + + + +
KeyTypeDescription
typeString"AdMob_Consent_OnShown"
+


+ + + + + + + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeString"AdMob_Consent_OnShowFailed"
errorMessageStringthe error code responsible for the failure
errorCodeRealthe error message of the error code
+


+


+
+

Back To Top

+ +

AdMob_Consent_Reset

+

This function resets the consent status flag.

+


+

Syntax:

+
+
AdMob_Consent_Reset()
+
+


+

Returns:

+
+

N/A

+
+


+


+ +
+
+ +
+
+ +
+ +
+ +
+ + + + GitHub + + + + « Previous + + + Next » + + +
+ + + + + + + + + + diff --git a/extensions/AdMob/docs/constants.html b/extensions/AdMob/docs/constants.html new file mode 100644 index 000000000..ccb046774 --- /dev/null +++ b/extensions/AdMob/docs/constants.html @@ -0,0 +1,481 @@ + + + + + + + + Constants - GMEXT-AdMob + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+ +
+
+
+
+ +

+

Constants

+

The following are the available constanst to use with the AdMob API.

+

Constants

+

This module includes a set of predefined constants that can be utilized for various purposes. Browse through the available constants to find values relevant to your needs and enhance the efficiency of your code.

+ +


+
+

Back To Top

+ +

AdMobErrors

+

These set of constants represent the values errors values that can return from the AdMob function calls.

+

These constants are referenced by the following functions:

+ +


+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MemberDescription
ADMOB_OKThere were no errors.
ADMOB_ERROR_NOT_INITIALIZEDThe AdMob extension needs to be initialized prior to this call
ADMOB_ERROR_INVALID_AD_IDThe provided ad unit id is not valid.
ADMOB_ERROR_AD_LIMIT_REACHEDThe limit of loaded ads for this specific type was reached.
ADMOB_ERROR_NO_ADS_LOADEDThere are no loaded ads to be shown for this specific type.
ADMOB_ERROR_NO_ACTIVE_BANNER_ADThere is no active banner ad.
ADMOB_ERROR_ILLEGAL_CALLThe call you are trying to execute is illegal (used for functions that need to be called prior to initialization).
+


+
+

Back To Top

+ +

AdMobAdValuePrecision

+

These set of constants represent precision type of the reported ad value.

+

These constants are referenced by the following functions:

+ +


+ + + + + + + + + + + + + + + + + + + + + + + + + +
MemberDescription
ADMOB_ADVALUE_PRECISION_UNKNOWNAn unknown precision type.
ADMOB_ADVALUE_PRECISION_ESTIMATEDAn ad value estimated from aggregated data.
ADMOB_ADVALUE_PRECISION_PRECISEThe precise value paid for this ad.
ADMOB_ADVALUE_PRECISION_PUBLISHER_PROVIDEDA publisher-provided ad value, such as manual CPMs in a mediation group.
+


+
+

Back To Top

+ +

AdMobBanner

+

These set of constants represent the various types of available banners.

+


+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MemberDescription
AdMob_Banner_NORMALNormal sized banner (320x50 dp)
AdMob_Banner_LARGELarge sized banner (320x100 dp)
AdMob_Banner_MEDIUMIAB medium rectangle (300x250 dp)
AdMob_Banner_FULLIAB full-size banner (468x60 dp - tablets only)
AdMob_Banner_LEADERBOARDIAB leaderboard (728x90 dp - tablets only)
AdMob_Banner_SMARTA dynamic size banner (deprecated, see AdMob_Banner_ADAPTIVE)
AdMob_Banner_ADAPTIVEA dynamically sized banner
+


+
+

Back To Top

+ +

AdMobContentRating

+

These set of constants represent the various types of possible content ratings for ads.

+

These constants are referenced by the following functions:

+ +


+ + + + + + + + + + + + + + + + + + + + + + + + + +
MemberDescription
AdMob_ContentRating_GENERALContent suitable for general audiences.
AdMob_ContentRating_PARENTAL_GUIDANCEContent suitable for most audiences with parental guidance.
AdMob_ContentRating_TEENContent suitable for teen and older audiences.
AdMob_ContentRating_MATURE_AUDIENCEContent suitable only for mature audiences.
+


+
+

Back To Top

+ +

AdMobConsentStatus

+

These set of constants represent the various consent status.

+

These constants are referenced by the following functions:

+ +


+ + + + + + + + + + + + + + + + + + + + + + + + + +
MemberDescription
AdMob_Consent_Status_UNKNOWNConsent status is unknown.
AdMob_Consent_Status_NOT_REQUIREDUser consent not required.
AdMob_Consent_Status_REQUIREDUser consent required but not yet obtained.
AdMob_Consent_Status_OBTAINEDUser consent obtained. Personalized vs non-personalized undefined.
+


+
+

Back To Top

+ +

AdMobConsentType

+

These set of constants represent the given consent type.

+

These constants are referenced by the following functions:

+ +


+ + + + + + + + + + + + + + + + + + + + + + + + + +
MemberDescription
AdMob_Consent_Type_UNKNOWNConsent type is unknown (before consent was requested).
AdMob_Consent_Type_NON_PERSONALIZEDConsent was given for non-personalized ads.
AdMob_Consent_Type_PERSONALIZEDConsent was given for personalized ads.
AdMob_Consent_Type_DECLINEDConsent was declined for any kind of ads.
+


+
+

Back To Top

+ +

AdMobConsentMode

+

These set of constants represent the consent mode (these are used for testing porpuses).

+

These constants are referenced by the following functions:

+ +


+ + + + + + + + + + + + + + + + + + + + + + + + + +
MemberDescription
AdMob_Consent_Mode_DEBUG_GEOGRAPHY_DISABLEDDebug geography disabled.
AdMob_Consent_Mode_DEBUG_GEOGRAPHY_EEAGeography appears as in EEA for debug devices.
AdMob_Consent_Mode_DEBUG_GEOGRAPHY_NOT_EEAGeography appears as not in EEA for debug devices.
AdMob_Consent_Mode_PRODUCTIONSame as AdMob_Consent_Mode_DEBUG_GEOGRAPHY_DISABLED, used for production.
+


+ +
+
+ +
+
+ +
+ +
+ +
+ + + + GitHub + + + + « Previous + + + +
+ + + + + + + + + + diff --git a/extensions/AdMob/docs/css/fonts/Roboto-Slab-Bold.woff b/extensions/AdMob/docs/css/fonts/Roboto-Slab-Bold.woff new file mode 100644 index 000000000..6cb600001 Binary files /dev/null and b/extensions/AdMob/docs/css/fonts/Roboto-Slab-Bold.woff differ diff --git a/extensions/AdMob/docs/css/fonts/Roboto-Slab-Bold.woff2 b/extensions/AdMob/docs/css/fonts/Roboto-Slab-Bold.woff2 new file mode 100644 index 000000000..7059e2314 Binary files /dev/null and b/extensions/AdMob/docs/css/fonts/Roboto-Slab-Bold.woff2 differ diff --git a/extensions/AdMob/docs/css/fonts/Roboto-Slab-Regular.woff b/extensions/AdMob/docs/css/fonts/Roboto-Slab-Regular.woff new file mode 100644 index 000000000..f815f63f9 Binary files /dev/null and b/extensions/AdMob/docs/css/fonts/Roboto-Slab-Regular.woff differ diff --git a/extensions/AdMob/docs/css/fonts/Roboto-Slab-Regular.woff2 b/extensions/AdMob/docs/css/fonts/Roboto-Slab-Regular.woff2 new file mode 100644 index 000000000..f2c76e5bd Binary files /dev/null and b/extensions/AdMob/docs/css/fonts/Roboto-Slab-Regular.woff2 differ diff --git a/extensions/AdMob/docs/css/fonts/fontawesome-webfont.eot b/extensions/AdMob/docs/css/fonts/fontawesome-webfont.eot new file mode 100644 index 000000000..e9f60ca95 Binary files /dev/null and b/extensions/AdMob/docs/css/fonts/fontawesome-webfont.eot differ diff --git a/extensions/AdMob/docs/css/fonts/fontawesome-webfont.svg b/extensions/AdMob/docs/css/fonts/fontawesome-webfont.svg new file mode 100644 index 000000000..855c845e5 --- /dev/null +++ b/extensions/AdMob/docs/css/fonts/fontawesome-webfont.svg @@ -0,0 +1,2671 @@ + + + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/extensions/AdMob/docs/css/fonts/fontawesome-webfont.ttf b/extensions/AdMob/docs/css/fonts/fontawesome-webfont.ttf new file mode 100644 index 000000000..35acda2fa Binary files /dev/null and b/extensions/AdMob/docs/css/fonts/fontawesome-webfont.ttf differ diff --git a/extensions/AdMob/docs/css/fonts/fontawesome-webfont.woff b/extensions/AdMob/docs/css/fonts/fontawesome-webfont.woff new file mode 100644 index 000000000..400014a4b Binary files /dev/null and b/extensions/AdMob/docs/css/fonts/fontawesome-webfont.woff differ diff --git a/extensions/AdMob/docs/css/fonts/fontawesome-webfont.woff2 b/extensions/AdMob/docs/css/fonts/fontawesome-webfont.woff2 new file mode 100644 index 000000000..4d13fc604 Binary files /dev/null and b/extensions/AdMob/docs/css/fonts/fontawesome-webfont.woff2 differ diff --git a/extensions/AdMob/docs/css/fonts/lato-bold-italic.woff b/extensions/AdMob/docs/css/fonts/lato-bold-italic.woff new file mode 100644 index 000000000..88ad05b9f Binary files /dev/null and b/extensions/AdMob/docs/css/fonts/lato-bold-italic.woff differ diff --git a/extensions/AdMob/docs/css/fonts/lato-bold-italic.woff2 b/extensions/AdMob/docs/css/fonts/lato-bold-italic.woff2 new file mode 100644 index 000000000..c4e3d804b Binary files /dev/null and b/extensions/AdMob/docs/css/fonts/lato-bold-italic.woff2 differ diff --git a/extensions/AdMob/docs/css/fonts/lato-bold.woff b/extensions/AdMob/docs/css/fonts/lato-bold.woff new file mode 100644 index 000000000..c6dff51f0 Binary files /dev/null and b/extensions/AdMob/docs/css/fonts/lato-bold.woff differ diff --git a/extensions/AdMob/docs/css/fonts/lato-bold.woff2 b/extensions/AdMob/docs/css/fonts/lato-bold.woff2 new file mode 100644 index 000000000..bb195043c Binary files /dev/null and b/extensions/AdMob/docs/css/fonts/lato-bold.woff2 differ diff --git a/extensions/AdMob/docs/css/fonts/lato-normal-italic.woff b/extensions/AdMob/docs/css/fonts/lato-normal-italic.woff new file mode 100644 index 000000000..76114bc03 Binary files /dev/null and b/extensions/AdMob/docs/css/fonts/lato-normal-italic.woff differ diff --git a/extensions/AdMob/docs/css/fonts/lato-normal-italic.woff2 b/extensions/AdMob/docs/css/fonts/lato-normal-italic.woff2 new file mode 100644 index 000000000..3404f37e2 Binary files /dev/null and b/extensions/AdMob/docs/css/fonts/lato-normal-italic.woff2 differ diff --git a/extensions/AdMob/docs/css/fonts/lato-normal.woff b/extensions/AdMob/docs/css/fonts/lato-normal.woff new file mode 100644 index 000000000..ae1307ff5 Binary files /dev/null and b/extensions/AdMob/docs/css/fonts/lato-normal.woff differ diff --git a/extensions/AdMob/docs/css/fonts/lato-normal.woff2 b/extensions/AdMob/docs/css/fonts/lato-normal.woff2 new file mode 100644 index 000000000..3bf984332 Binary files /dev/null and b/extensions/AdMob/docs/css/fonts/lato-normal.woff2 differ diff --git a/extensions/AdMob/docs/css/theme.css b/extensions/AdMob/docs/css/theme.css new file mode 100644 index 000000000..ad773009b --- /dev/null +++ b/extensions/AdMob/docs/css/theme.css @@ -0,0 +1,13 @@ +/* + * This file is copied from the upstream ReadTheDocs Sphinx + * theme. To aid upgradability this file should *not* be edited. + * modifications we need should be included in theme_extra.css. + * + * https://github.com/readthedocs/sphinx_rtd_theme + */ + + /* sphinx_rtd_theme version 1.2.0 | MIT license */ +html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden],audio:not([controls]){display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;text-decoration:none}ins,mark{color:#000}mark{background:#ff0;font-style:italic;font-weight:700}.rst-content code,.rst-content tt,code,kbd,pre,samp{font-family:monospace,serif;_font-family:courier new,monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:after,q:before{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}dl,ol,ul{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure,form{margin:0}label{cursor:pointer}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type=button],input[type=reset],input[type=submit]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}textarea{resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:.2em 0;background:#ccc;color:#000;padding:.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none!important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{body,html,section{background:none!important}*{box-shadow:none!important;text-shadow:none!important;filter:none!important;-ms-filter:none!important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}.rst-content .toctree-wrapper>p.caption,h2,h3,p{orphans:3;widows:3}.rst-content .toctree-wrapper>p.caption,h2,h3{page-break-after:avoid}}.btn,.fa:before,.icon:before,.rst-content .admonition,.rst-content .admonition-title:before,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .code-block-caption .headerlink:before,.rst-content .danger,.rst-content .eqno .headerlink:before,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-alert,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before,input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week],select,textarea{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:FontAwesome;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713);src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix&v=4.7.0) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#fontawesomeregular) format("svg");font-weight:400;font-style:normal}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14286em;width:2.14286em;top:.14286em;text-align:center}.fa-li.fa-lg{left:-1.85714em}.fa-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa-pull-left.icon,.fa.fa-pull-left,.rst-content .code-block-caption .fa-pull-left.headerlink,.rst-content .eqno .fa-pull-left.headerlink,.rst-content .fa-pull-left.admonition-title,.rst-content code.download span.fa-pull-left:first-child,.rst-content dl dt .fa-pull-left.headerlink,.rst-content h1 .fa-pull-left.headerlink,.rst-content h2 .fa-pull-left.headerlink,.rst-content h3 .fa-pull-left.headerlink,.rst-content h4 .fa-pull-left.headerlink,.rst-content h5 .fa-pull-left.headerlink,.rst-content h6 .fa-pull-left.headerlink,.rst-content p .fa-pull-left.headerlink,.rst-content table>caption .fa-pull-left.headerlink,.rst-content tt.download span.fa-pull-left:first-child,.wy-menu-vertical li.current>a button.fa-pull-left.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-left.toctree-expand,.wy-menu-vertical li button.fa-pull-left.toctree-expand{margin-right:.3em}.fa-pull-right.icon,.fa.fa-pull-right,.rst-content .code-block-caption .fa-pull-right.headerlink,.rst-content .eqno .fa-pull-right.headerlink,.rst-content .fa-pull-right.admonition-title,.rst-content code.download span.fa-pull-right:first-child,.rst-content dl dt .fa-pull-right.headerlink,.rst-content h1 .fa-pull-right.headerlink,.rst-content h2 .fa-pull-right.headerlink,.rst-content h3 .fa-pull-right.headerlink,.rst-content h4 .fa-pull-right.headerlink,.rst-content h5 .fa-pull-right.headerlink,.rst-content h6 .fa-pull-right.headerlink,.rst-content p .fa-pull-right.headerlink,.rst-content table>caption .fa-pull-right.headerlink,.rst-content tt.download span.fa-pull-right:first-child,.wy-menu-vertical li.current>a button.fa-pull-right.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-right.toctree-expand,.wy-menu-vertical li button.fa-pull-right.toctree-expand{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.pull-left.icon,.rst-content .code-block-caption .pull-left.headerlink,.rst-content .eqno .pull-left.headerlink,.rst-content .pull-left.admonition-title,.rst-content code.download span.pull-left:first-child,.rst-content dl dt .pull-left.headerlink,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content p .pull-left.headerlink,.rst-content table>caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.wy-menu-vertical li.current>a button.pull-left.toctree-expand,.wy-menu-vertical li.on a button.pull-left.toctree-expand,.wy-menu-vertical li button.pull-left.toctree-expand{margin-right:.3em}.fa.pull-right,.pull-right.icon,.rst-content .code-block-caption .pull-right.headerlink,.rst-content .eqno .pull-right.headerlink,.rst-content .pull-right.admonition-title,.rst-content code.download span.pull-right:first-child,.rst-content dl dt .pull-right.headerlink,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content p .pull-right.headerlink,.rst-content table>caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.wy-menu-vertical li.current>a button.pull-right.toctree-expand,.wy-menu-vertical li.on a button.pull-right.toctree-expand,.wy-menu-vertical li button.pull-right.toctree-expand{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);-ms-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scaleY(-1);-ms-transform:scaleY(-1);transform:scaleY(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-close:before,.fa-remove:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-cog:before,.fa-gear:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-repeat:before,.fa-rotate-right:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-image:before,.fa-photo:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:""}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before,.rst-content .admonition-title:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before,.icon-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-exclamation-triangle:before,.fa-warning:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-cogs:before,.fa-gears:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook-f:before,.fa-facebook:before{content:""}.fa-github:before,.icon-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-feed:before,.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-floppy-o:before,.fa-save:before{content:""}.fa-square:before{content:""}.fa-bars:before,.fa-navicon:before,.fa-reorder:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.icon-caret-down:before,.wy-dropdown .caret:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-sort:before,.fa-unsorted:before{content:""}.fa-sort-desc:before,.fa-sort-down:before{content:""}.fa-sort-asc:before,.fa-sort-up:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-gavel:before,.fa-legal:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-bolt:before,.fa-flash:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-clipboard:before,.fa-paste:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-chain-broken:before,.fa-unlink:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-caret-square-o-down:before,.fa-toggle-down:before{content:""}.fa-caret-square-o-up:before,.fa-toggle-up:before{content:""}.fa-caret-square-o-right:before,.fa-toggle-right:before{content:""}.fa-eur:before,.fa-euro:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-inr:before,.fa-rupee:before{content:""}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen:before{content:""}.fa-rouble:before,.fa-rub:before,.fa-ruble:before{content:""}.fa-krw:before,.fa-won:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before,.icon-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before,.fa-gratipay:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-caret-square-o-left:before,.fa-toggle-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-try:before,.fa-turkish-lira:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li button.toctree-expand:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-bank:before,.fa-institution:before,.fa-university:before{content:""}.fa-graduation-cap:before,.fa-mortar-board:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper-pp:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-image-o:before,.fa-file-photo-o:before,.fa-file-picture-o:before{content:""}.fa-file-archive-o:before,.fa-file-zip-o:before{content:""}.fa-file-audio-o:before,.fa-file-sound-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-ring:before,.fa-life-saver:before,.fa-support:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-rebel:before,.fa-resistance:before{content:""}.fa-empire:before,.fa-ge:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-hacker-news:before,.fa-y-combinator-square:before,.fa-yc-square:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-paper-plane:before,.fa-send:before{content:""}.fa-paper-plane-o:before,.fa-send-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-futbol-o:before,.fa-soccer-ball-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-ils:before,.fa-shekel:before,.fa-sheqel:before{content:""}.fa-meanpath:before{content:""}.fa-buysellads:before{content:""}.fa-connectdevelop:before{content:""}.fa-dashcube:before{content:""}.fa-forumbee:before{content:""}.fa-leanpub:before{content:""}.fa-sellsy:before{content:""}.fa-shirtsinbulk:before{content:""}.fa-simplybuilt:before{content:""}.fa-skyatlas:before{content:""}.fa-cart-plus:before{content:""}.fa-cart-arrow-down:before{content:""}.fa-diamond:before{content:""}.fa-ship:before{content:""}.fa-user-secret:before{content:""}.fa-motorcycle:before{content:""}.fa-street-view:before{content:""}.fa-heartbeat:before{content:""}.fa-venus:before{content:""}.fa-mars:before{content:""}.fa-mercury:before{content:""}.fa-intersex:before,.fa-transgender:before{content:""}.fa-transgender-alt:before{content:""}.fa-venus-double:before{content:""}.fa-mars-double:before{content:""}.fa-venus-mars:before{content:""}.fa-mars-stroke:before{content:""}.fa-mars-stroke-v:before{content:""}.fa-mars-stroke-h:before{content:""}.fa-neuter:before{content:""}.fa-genderless:before{content:""}.fa-facebook-official:before{content:""}.fa-pinterest-p:before{content:""}.fa-whatsapp:before{content:""}.fa-server:before{content:""}.fa-user-plus:before{content:""}.fa-user-times:before{content:""}.fa-bed:before,.fa-hotel:before{content:""}.fa-viacoin:before{content:""}.fa-train:before{content:""}.fa-subway:before{content:""}.fa-medium:before{content:""}.fa-y-combinator:before,.fa-yc:before{content:""}.fa-optin-monster:before{content:""}.fa-opencart:before{content:""}.fa-expeditedssl:before{content:""}.fa-battery-4:before,.fa-battery-full:before,.fa-battery:before{content:""}.fa-battery-3:before,.fa-battery-three-quarters:before{content:""}.fa-battery-2:before,.fa-battery-half:before{content:""}.fa-battery-1:before,.fa-battery-quarter:before{content:""}.fa-battery-0:before,.fa-battery-empty:before{content:""}.fa-mouse-pointer:before{content:""}.fa-i-cursor:before{content:""}.fa-object-group:before{content:""}.fa-object-ungroup:before{content:""}.fa-sticky-note:before{content:""}.fa-sticky-note-o:before{content:""}.fa-cc-jcb:before{content:""}.fa-cc-diners-club:before{content:""}.fa-clone:before{content:""}.fa-balance-scale:before{content:""}.fa-hourglass-o:before{content:""}.fa-hourglass-1:before,.fa-hourglass-start:before{content:""}.fa-hourglass-2:before,.fa-hourglass-half:before{content:""}.fa-hourglass-3:before,.fa-hourglass-end:before{content:""}.fa-hourglass:before{content:""}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:""}.fa-hand-paper-o:before,.fa-hand-stop-o:before{content:""}.fa-hand-scissors-o:before{content:""}.fa-hand-lizard-o:before{content:""}.fa-hand-spock-o:before{content:""}.fa-hand-pointer-o:before{content:""}.fa-hand-peace-o:before{content:""}.fa-trademark:before{content:""}.fa-registered:before{content:""}.fa-creative-commons:before{content:""}.fa-gg:before{content:""}.fa-gg-circle:before{content:""}.fa-tripadvisor:before{content:""}.fa-odnoklassniki:before{content:""}.fa-odnoklassniki-square:before{content:""}.fa-get-pocket:before{content:""}.fa-wikipedia-w:before{content:""}.fa-safari:before{content:""}.fa-chrome:before{content:""}.fa-firefox:before{content:""}.fa-opera:before{content:""}.fa-internet-explorer:before{content:""}.fa-television:before,.fa-tv:before{content:""}.fa-contao:before{content:""}.fa-500px:before{content:""}.fa-amazon:before{content:""}.fa-calendar-plus-o:before{content:""}.fa-calendar-minus-o:before{content:""}.fa-calendar-times-o:before{content:""}.fa-calendar-check-o:before{content:""}.fa-industry:before{content:""}.fa-map-pin:before{content:""}.fa-map-signs:before{content:""}.fa-map-o:before{content:""}.fa-map:before{content:""}.fa-commenting:before{content:""}.fa-commenting-o:before{content:""}.fa-houzz:before{content:""}.fa-vimeo:before{content:""}.fa-black-tie:before{content:""}.fa-fonticons:before{content:""}.fa-reddit-alien:before{content:""}.fa-edge:before{content:""}.fa-credit-card-alt:before{content:""}.fa-codiepie:before{content:""}.fa-modx:before{content:""}.fa-fort-awesome:before{content:""}.fa-usb:before{content:""}.fa-product-hunt:before{content:""}.fa-mixcloud:before{content:""}.fa-scribd:before{content:""}.fa-pause-circle:before{content:""}.fa-pause-circle-o:before{content:""}.fa-stop-circle:before{content:""}.fa-stop-circle-o:before{content:""}.fa-shopping-bag:before{content:""}.fa-shopping-basket:before{content:""}.fa-hashtag:before{content:""}.fa-bluetooth:before{content:""}.fa-bluetooth-b:before{content:""}.fa-percent:before{content:""}.fa-gitlab:before,.icon-gitlab:before{content:""}.fa-wpbeginner:before{content:""}.fa-wpforms:before{content:""}.fa-envira:before{content:""}.fa-universal-access:before{content:""}.fa-wheelchair-alt:before{content:""}.fa-question-circle-o:before{content:""}.fa-blind:before{content:""}.fa-audio-description:before{content:""}.fa-volume-control-phone:before{content:""}.fa-braille:before{content:""}.fa-assistive-listening-systems:before{content:""}.fa-american-sign-language-interpreting:before,.fa-asl-interpreting:before{content:""}.fa-deaf:before,.fa-deafness:before,.fa-hard-of-hearing:before{content:""}.fa-glide:before{content:""}.fa-glide-g:before{content:""}.fa-sign-language:before,.fa-signing:before{content:""}.fa-low-vision:before{content:""}.fa-viadeo:before{content:""}.fa-viadeo-square:before{content:""}.fa-snapchat:before{content:""}.fa-snapchat-ghost:before{content:""}.fa-snapchat-square:before{content:""}.fa-pied-piper:before{content:""}.fa-first-order:before{content:""}.fa-yoast:before{content:""}.fa-themeisle:before{content:""}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:""}.fa-fa:before,.fa-font-awesome:before{content:""}.fa-handshake-o:before{content:""}.fa-envelope-open:before{content:""}.fa-envelope-open-o:before{content:""}.fa-linode:before{content:""}.fa-address-book:before{content:""}.fa-address-book-o:before{content:""}.fa-address-card:before,.fa-vcard:before{content:""}.fa-address-card-o:before,.fa-vcard-o:before{content:""}.fa-user-circle:before{content:""}.fa-user-circle-o:before{content:""}.fa-user-o:before{content:""}.fa-id-badge:before{content:""}.fa-drivers-license:before,.fa-id-card:before{content:""}.fa-drivers-license-o:before,.fa-id-card-o:before{content:""}.fa-quora:before{content:""}.fa-free-code-camp:before{content:""}.fa-telegram:before{content:""}.fa-thermometer-4:before,.fa-thermometer-full:before,.fa-thermometer:before{content:""}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:""}.fa-thermometer-2:before,.fa-thermometer-half:before{content:""}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:""}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:""}.fa-shower:before{content:""}.fa-bath:before,.fa-bathtub:before,.fa-s15:before{content:""}.fa-podcast:before{content:""}.fa-window-maximize:before{content:""}.fa-window-minimize:before{content:""}.fa-window-restore:before{content:""}.fa-times-rectangle:before,.fa-window-close:before{content:""}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:""}.fa-bandcamp:before{content:""}.fa-grav:before{content:""}.fa-etsy:before{content:""}.fa-imdb:before{content:""}.fa-ravelry:before{content:""}.fa-eercast:before{content:""}.fa-microchip:before{content:""}.fa-snowflake-o:before{content:""}.fa-superpowers:before{content:""}.fa-wpexplorer:before{content:""}.fa-meetup:before{content:""}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{font-family:inherit}.fa:before,.icon:before,.rst-content .admonition-title:before,.rst-content .code-block-caption .headerlink:before,.rst-content .eqno .headerlink:before,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before{font-family:FontAwesome;display:inline-block;font-style:normal;font-weight:400;line-height:1;text-decoration:inherit}.rst-content .code-block-caption a .headerlink,.rst-content .eqno a .headerlink,.rst-content a .admonition-title,.rst-content code.download a span:first-child,.rst-content dl dt a .headerlink,.rst-content h1 a .headerlink,.rst-content h2 a .headerlink,.rst-content h3 a .headerlink,.rst-content h4 a .headerlink,.rst-content h5 a .headerlink,.rst-content h6 a .headerlink,.rst-content p.caption a .headerlink,.rst-content p a .headerlink,.rst-content table>caption a .headerlink,.rst-content tt.download a span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li a button.toctree-expand,a .fa,a .icon,a .rst-content .admonition-title,a .rst-content .code-block-caption .headerlink,a .rst-content .eqno .headerlink,a .rst-content code.download span:first-child,a .rst-content dl dt .headerlink,a .rst-content h1 .headerlink,a .rst-content h2 .headerlink,a .rst-content h3 .headerlink,a .rst-content h4 .headerlink,a .rst-content h5 .headerlink,a .rst-content h6 .headerlink,a .rst-content p.caption .headerlink,a .rst-content p .headerlink,a .rst-content table>caption .headerlink,a .rst-content tt.download span:first-child,a .wy-menu-vertical li button.toctree-expand{display:inline-block;text-decoration:inherit}.btn .fa,.btn .icon,.btn .rst-content .admonition-title,.btn .rst-content .code-block-caption .headerlink,.btn .rst-content .eqno .headerlink,.btn .rst-content code.download span:first-child,.btn .rst-content dl dt .headerlink,.btn .rst-content h1 .headerlink,.btn .rst-content h2 .headerlink,.btn .rst-content h3 .headerlink,.btn .rst-content h4 .headerlink,.btn .rst-content h5 .headerlink,.btn .rst-content h6 .headerlink,.btn .rst-content p .headerlink,.btn .rst-content table>caption .headerlink,.btn .rst-content tt.download span:first-child,.btn .wy-menu-vertical li.current>a button.toctree-expand,.btn .wy-menu-vertical li.on a button.toctree-expand,.btn .wy-menu-vertical li button.toctree-expand,.nav .fa,.nav .icon,.nav .rst-content .admonition-title,.nav .rst-content .code-block-caption .headerlink,.nav .rst-content .eqno .headerlink,.nav .rst-content code.download span:first-child,.nav .rst-content dl dt .headerlink,.nav .rst-content h1 .headerlink,.nav .rst-content h2 .headerlink,.nav .rst-content h3 .headerlink,.nav .rst-content h4 .headerlink,.nav .rst-content h5 .headerlink,.nav .rst-content h6 .headerlink,.nav .rst-content p .headerlink,.nav .rst-content table>caption .headerlink,.nav .rst-content tt.download span:first-child,.nav .wy-menu-vertical li.current>a button.toctree-expand,.nav .wy-menu-vertical li.on a button.toctree-expand,.nav .wy-menu-vertical li button.toctree-expand,.rst-content .btn .admonition-title,.rst-content .code-block-caption .btn .headerlink,.rst-content .code-block-caption .nav .headerlink,.rst-content .eqno .btn .headerlink,.rst-content .eqno .nav .headerlink,.rst-content .nav .admonition-title,.rst-content code.download .btn span:first-child,.rst-content code.download .nav span:first-child,.rst-content dl dt .btn .headerlink,.rst-content dl dt .nav .headerlink,.rst-content h1 .btn .headerlink,.rst-content h1 .nav .headerlink,.rst-content h2 .btn .headerlink,.rst-content h2 .nav .headerlink,.rst-content h3 .btn .headerlink,.rst-content h3 .nav .headerlink,.rst-content h4 .btn .headerlink,.rst-content h4 .nav .headerlink,.rst-content h5 .btn .headerlink,.rst-content h5 .nav .headerlink,.rst-content h6 .btn .headerlink,.rst-content h6 .nav .headerlink,.rst-content p .btn .headerlink,.rst-content p .nav .headerlink,.rst-content table>caption .btn .headerlink,.rst-content table>caption .nav .headerlink,.rst-content tt.download .btn span:first-child,.rst-content tt.download .nav span:first-child,.wy-menu-vertical li .btn button.toctree-expand,.wy-menu-vertical li.current>a .btn button.toctree-expand,.wy-menu-vertical li.current>a .nav button.toctree-expand,.wy-menu-vertical li .nav button.toctree-expand,.wy-menu-vertical li.on a .btn button.toctree-expand,.wy-menu-vertical li.on a .nav button.toctree-expand{display:inline}.btn .fa-large.icon,.btn .fa.fa-large,.btn .rst-content .code-block-caption .fa-large.headerlink,.btn .rst-content .eqno .fa-large.headerlink,.btn .rst-content .fa-large.admonition-title,.btn .rst-content code.download span.fa-large:first-child,.btn .rst-content dl dt .fa-large.headerlink,.btn .rst-content h1 .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.btn .rst-content p .fa-large.headerlink,.btn .rst-content table>caption .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.btn .wy-menu-vertical li button.fa-large.toctree-expand,.nav .fa-large.icon,.nav .fa.fa-large,.nav .rst-content .code-block-caption .fa-large.headerlink,.nav .rst-content .eqno .fa-large.headerlink,.nav .rst-content .fa-large.admonition-title,.nav .rst-content code.download span.fa-large:first-child,.nav .rst-content dl dt .fa-large.headerlink,.nav .rst-content h1 .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.nav .rst-content p .fa-large.headerlink,.nav .rst-content table>caption .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.nav .wy-menu-vertical li button.fa-large.toctree-expand,.rst-content .btn .fa-large.admonition-title,.rst-content .code-block-caption .btn .fa-large.headerlink,.rst-content .code-block-caption .nav .fa-large.headerlink,.rst-content .eqno .btn .fa-large.headerlink,.rst-content .eqno .nav .fa-large.headerlink,.rst-content .nav .fa-large.admonition-title,.rst-content code.download .btn span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.rst-content dl dt .btn .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.rst-content p .btn .fa-large.headerlink,.rst-content p .nav .fa-large.headerlink,.rst-content table>caption .btn .fa-large.headerlink,.rst-content table>caption .nav .fa-large.headerlink,.rst-content tt.download .btn span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.wy-menu-vertical li .btn button.fa-large.toctree-expand,.wy-menu-vertical li .nav button.fa-large.toctree-expand{line-height:.9em}.btn .fa-spin.icon,.btn .fa.fa-spin,.btn .rst-content .code-block-caption .fa-spin.headerlink,.btn .rst-content .eqno .fa-spin.headerlink,.btn .rst-content .fa-spin.admonition-title,.btn .rst-content code.download span.fa-spin:first-child,.btn .rst-content dl dt .fa-spin.headerlink,.btn .rst-content h1 .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.btn .rst-content p .fa-spin.headerlink,.btn .rst-content table>caption .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.btn .wy-menu-vertical li button.fa-spin.toctree-expand,.nav .fa-spin.icon,.nav .fa.fa-spin,.nav .rst-content .code-block-caption .fa-spin.headerlink,.nav .rst-content .eqno .fa-spin.headerlink,.nav .rst-content .fa-spin.admonition-title,.nav .rst-content code.download span.fa-spin:first-child,.nav .rst-content dl dt .fa-spin.headerlink,.nav .rst-content h1 .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.nav .rst-content p .fa-spin.headerlink,.nav .rst-content table>caption .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.nav .wy-menu-vertical li button.fa-spin.toctree-expand,.rst-content .btn .fa-spin.admonition-title,.rst-content .code-block-caption .btn .fa-spin.headerlink,.rst-content .code-block-caption .nav .fa-spin.headerlink,.rst-content .eqno .btn .fa-spin.headerlink,.rst-content .eqno .nav .fa-spin.headerlink,.rst-content .nav .fa-spin.admonition-title,.rst-content code.download .btn span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.rst-content dl dt .btn .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.rst-content p .btn .fa-spin.headerlink,.rst-content p .nav .fa-spin.headerlink,.rst-content table>caption .btn .fa-spin.headerlink,.rst-content table>caption .nav .fa-spin.headerlink,.rst-content tt.download .btn span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.wy-menu-vertical li .btn button.fa-spin.toctree-expand,.wy-menu-vertical li .nav button.fa-spin.toctree-expand{display:inline-block}.btn.fa:before,.btn.icon:before,.rst-content .btn.admonition-title:before,.rst-content .code-block-caption .btn.headerlink:before,.rst-content .eqno .btn.headerlink:before,.rst-content code.download span.btn:first-child:before,.rst-content dl dt .btn.headerlink:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content p .btn.headerlink:before,.rst-content table>caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.wy-menu-vertical li button.btn.toctree-expand:before{opacity:.5;-webkit-transition:opacity .05s ease-in;-moz-transition:opacity .05s ease-in;transition:opacity .05s ease-in}.btn.fa:hover:before,.btn.icon:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content .code-block-caption .btn.headerlink:hover:before,.rst-content .eqno .btn.headerlink:hover:before,.rst-content code.download span.btn:first-child:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content p .btn.headerlink:hover:before,.rst-content table>caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.wy-menu-vertical li button.btn.toctree-expand:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .icon:before,.btn-mini .rst-content .admonition-title:before,.btn-mini .rst-content .code-block-caption .headerlink:before,.btn-mini .rst-content .eqno .headerlink:before,.btn-mini .rst-content code.download span:first-child:before,.btn-mini .rst-content dl dt .headerlink:before,.btn-mini .rst-content h1 .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.btn-mini .rst-content p .headerlink:before,.btn-mini .rst-content table>caption .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.btn-mini .wy-menu-vertical li button.toctree-expand:before,.rst-content .btn-mini .admonition-title:before,.rst-content .code-block-caption .btn-mini .headerlink:before,.rst-content .eqno .btn-mini .headerlink:before,.rst-content code.download .btn-mini span:first-child:before,.rst-content dl dt .btn-mini .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.rst-content p .btn-mini .headerlink:before,.rst-content table>caption .btn-mini .headerlink:before,.rst-content tt.download .btn-mini span:first-child:before,.wy-menu-vertical li .btn-mini button.toctree-expand:before{font-size:14px;vertical-align:-15%}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.wy-alert{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.rst-content .admonition-title,.wy-alert-title{font-weight:700;display:block;color:#fff;background:#6ab0de;padding:6px 12px;margin:-12px -12px 12px}.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.admonition,.rst-content .wy-alert-danger.admonition-todo,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.wy-alert.wy-alert-danger{background:#fdf3f2}.rst-content .danger .admonition-title,.rst-content .danger .wy-alert-title,.rst-content .error .admonition-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.rst-content .wy-alert-danger.admonition .admonition-title,.rst-content .wy-alert-danger.admonition .wy-alert-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.wy-alert.wy-alert-danger .wy-alert-title{background:#f29f97}.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .warning,.rst-content .wy-alert-warning.admonition,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.note,.rst-content .wy-alert-warning.seealso,.rst-content .wy-alert-warning.tip,.wy-alert.wy-alert-warning{background:#ffedcc}.rst-content .admonition-todo .admonition-title,.rst-content .admonition-todo .wy-alert-title,.rst-content .attention .admonition-title,.rst-content .attention .wy-alert-title,.rst-content .caution .admonition-title,.rst-content .caution .wy-alert-title,.rst-content .warning .admonition-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.admonition .admonition-title,.rst-content .wy-alert-warning.admonition .wy-alert-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.wy-alert.wy-alert-warning .wy-alert-title{background:#f0b37e}.rst-content .note,.rst-content .seealso,.rst-content .wy-alert-info.admonition,.rst-content .wy-alert-info.admonition-todo,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.wy-alert.wy-alert-info{background:#e7f2fa}.rst-content .note .admonition-title,.rst-content .note .wy-alert-title,.rst-content .seealso .admonition-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .admonition-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.rst-content .wy-alert-info.admonition .admonition-title,.rst-content .wy-alert-info.admonition .wy-alert-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.wy-alert.wy-alert-info .wy-alert-title{background:#6ab0de}.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.admonition,.rst-content .wy-alert-success.admonition-todo,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.warning,.wy-alert.wy-alert-success{background:#dbfaf4}.rst-content .hint .admonition-title,.rst-content .hint .wy-alert-title,.rst-content .important .admonition-title,.rst-content .important .wy-alert-title,.rst-content .tip .admonition-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .admonition-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.rst-content .wy-alert-success.admonition .admonition-title,.rst-content .wy-alert-success.admonition .wy-alert-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.wy-alert.wy-alert-success .wy-alert-title{background:#1abc9c}.rst-content .wy-alert-neutral.admonition,.rst-content .wy-alert-neutral.admonition-todo,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.wy-alert.wy-alert-neutral{background:#f3f6f6}.rst-content .wy-alert-neutral.admonition-todo .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.rst-content .wy-alert-neutral.admonition .admonition-title,.rst-content .wy-alert-neutral.admonition .wy-alert-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.wy-alert.wy-alert-neutral .wy-alert-title{color:#404040;background:#e1e4e5}.rst-content .wy-alert-neutral.admonition-todo a,.rst-content .wy-alert-neutral.admonition a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.wy-alert.wy-alert-neutral a{color:#2980b9}.rst-content .admonition-todo p:last-child,.rst-content .admonition p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .note p:last-child,.rst-content .seealso p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.wy-alert p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all .3s ease-in;-moz-transition:all .3s ease-in;transition:all .3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27ae60}.wy-tray-container li.wy-tray-item-info{background:#2980b9}.wy-tray-container li.wy-tray-item-warning{background:#e67e22}.wy-tray-container li.wy-tray-item-danger{background:#e74c3c}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width:768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px;color:#fff;border:1px solid rgba(0,0,0,.1);background-color:#27ae60;text-decoration:none;font-weight:400;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 2px -1px hsla(0,0%,100%,.5),inset 0 -2px 0 0 rgba(0,0,0,.1);outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all .1s linear;-moz-transition:all .1s linear;transition:all .1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:inset 0 -1px 0 0 rgba(0,0,0,.05),inset 0 2px 0 0 rgba(0,0,0,.1);padding:8px 12px 6px}.btn:visited{color:#fff}.btn-disabled,.btn-disabled:active,.btn-disabled:focus,.btn-disabled:hover,.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980b9!important}.btn-info:hover{background-color:#2e8ece!important}.btn-neutral{background-color:#f3f6f6!important;color:#404040!important}.btn-neutral:hover{background-color:#e5ebeb!important;color:#404040}.btn-neutral:visited{color:#404040!important}.btn-success{background-color:#27ae60!important}.btn-success:hover{background-color:#295!important}.btn-danger{background-color:#e74c3c!important}.btn-danger:hover{background-color:#ea6153!important}.btn-warning{background-color:#e67e22!important}.btn-warning:hover{background-color:#e98b39!important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f!important}.btn-link{background-color:transparent!important;color:#2980b9;box-shadow:none;border-color:transparent!important}.btn-link:active,.btn-link:hover{background-color:transparent!important;color:#409ad5!important;box-shadow:none}.btn-link:visited{color:#9b59b6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:after,.wy-btn-group:before{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:1px solid #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980b9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:1px solid #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type=search]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980b9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned .wy-help-inline,.wy-form-aligned input,.wy-form-aligned label,.wy-form-aligned select,.wy-form-aligned textarea{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{margin:0}fieldset,legend{border:0;padding:0}legend{width:100%;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label,legend{display:block}label{margin:0 0 .3125em;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;max-width:1200px;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:after,.wy-control-group:before{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#e74c3c}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full input[type=color],.wy-control-group .wy-form-full input[type=date],.wy-control-group .wy-form-full input[type=datetime-local],.wy-control-group .wy-form-full input[type=datetime],.wy-control-group .wy-form-full input[type=email],.wy-control-group .wy-form-full input[type=month],.wy-control-group .wy-form-full input[type=number],.wy-control-group .wy-form-full input[type=password],.wy-control-group .wy-form-full input[type=search],.wy-control-group .wy-form-full input[type=tel],.wy-control-group .wy-form-full input[type=text],.wy-control-group .wy-form-full input[type=time],.wy-control-group .wy-form-full input[type=url],.wy-control-group .wy-form-full input[type=week],.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves input[type=color],.wy-control-group .wy-form-halves input[type=date],.wy-control-group .wy-form-halves input[type=datetime-local],.wy-control-group .wy-form-halves input[type=datetime],.wy-control-group .wy-form-halves input[type=email],.wy-control-group .wy-form-halves input[type=month],.wy-control-group .wy-form-halves input[type=number],.wy-control-group .wy-form-halves input[type=password],.wy-control-group .wy-form-halves input[type=search],.wy-control-group .wy-form-halves input[type=tel],.wy-control-group .wy-form-halves input[type=text],.wy-control-group .wy-form-halves input[type=time],.wy-control-group .wy-form-halves input[type=url],.wy-control-group .wy-form-halves input[type=week],.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds input[type=color],.wy-control-group .wy-form-thirds input[type=date],.wy-control-group .wy-form-thirds input[type=datetime-local],.wy-control-group .wy-form-thirds input[type=datetime],.wy-control-group .wy-form-thirds input[type=email],.wy-control-group .wy-form-thirds input[type=month],.wy-control-group .wy-form-thirds input[type=number],.wy-control-group .wy-form-thirds input[type=password],.wy-control-group .wy-form-thirds input[type=search],.wy-control-group .wy-form-thirds input[type=tel],.wy-control-group .wy-form-thirds input[type=text],.wy-control-group .wy-form-thirds input[type=time],.wy-control-group .wy-form-thirds input[type=url],.wy-control-group .wy-form-thirds input[type=week],.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full{float:left;display:block;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.35765%;width:48.82117%}.wy-control-group .wy-form-halves:last-child,.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(odd){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.35765%;width:31.76157%}.wy-control-group .wy-form-thirds:last-child,.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control,.wy-control-no-input{margin:6px 0 0;font-size:90%}.wy-control-no-input{display:inline-block}.wy-control-group.fluid-input input[type=color],.wy-control-group.fluid-input input[type=date],.wy-control-group.fluid-input input[type=datetime-local],.wy-control-group.fluid-input input[type=datetime],.wy-control-group.fluid-input input[type=email],.wy-control-group.fluid-input input[type=month],.wy-control-group.fluid-input input[type=number],.wy-control-group.fluid-input input[type=password],.wy-control-group.fluid-input input[type=search],.wy-control-group.fluid-input input[type=tel],.wy-control-group.fluid-input input[type=text],.wy-control-group.fluid-input input[type=time],.wy-control-group.fluid-input input[type=url],.wy-control-group.fluid-input input[type=week]{width:100%}.wy-form-message-inline{padding-left:.3em;color:#666;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;*overflow:visible}input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}input[type=datetime-local]{padding:.34375em .625em}input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{padding:0;margin-right:.3125em;*height:13px;*width:13px}input[type=checkbox],input[type=radio],input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}input[type=color]:focus,input[type=date]:focus,input[type=datetime-local]:focus,input[type=datetime]:focus,input[type=email]:focus,input[type=month]:focus,input[type=number]:focus,input[type=password]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=time]:focus,input[type=url]:focus,input[type=week]:focus{outline:0;outline:thin dotted\9;border-color:#333}input.no-focus:focus{border-color:#ccc!important}input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus{outline:thin dotted #333;outline:1px auto #129fea}input[type=color][disabled],input[type=date][disabled],input[type=datetime-local][disabled],input[type=datetime][disabled],input[type=email][disabled],input[type=month][disabled],input[type=number][disabled],input[type=password][disabled],input[type=search][disabled],input[type=tel][disabled],input[type=text][disabled],input[type=time][disabled],input[type=url][disabled],input[type=week][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,select:focus:invalid,textarea:focus:invalid{color:#e74c3c;border:1px solid #e74c3c}input:focus:invalid:focus,select:focus:invalid:focus,textarea:focus:invalid:focus{border-color:#e74c3c}input[type=checkbox]:focus:invalid:focus,input[type=file]:focus:invalid:focus,input[type=radio]:focus:invalid:focus{outline-color:#e74c3c}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif}select,textarea{padding:.5em .625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}input[readonly],select[disabled],select[readonly],textarea[disabled],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type=checkbox][disabled],input[type=radio][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:1px solid #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{position:relative;display:block;height:24px;margin-top:12px;cursor:pointer}.wy-switch:before{left:0;top:0;width:36px;height:12px;background:#ccc}.wy-switch:after,.wy-switch:before{position:absolute;content:"";display:block;border-radius:4px;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch:after{width:18px;height:18px;background:#999;left:-3px;top:-3px}.wy-switch span{position:absolute;left:48px;display:block;font-size:12px;color:#ccc;line-height:1}.wy-switch.active:before{background:#1e8449}.wy-switch.active:after{left:24px;background:#27ae60}.wy-switch.disabled{cursor:not-allowed;opacity:.8}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#e74c3c}.wy-control-group.wy-control-group-error input[type=color],.wy-control-group.wy-control-group-error input[type=date],.wy-control-group.wy-control-group-error input[type=datetime-local],.wy-control-group.wy-control-group-error input[type=datetime],.wy-control-group.wy-control-group-error input[type=email],.wy-control-group.wy-control-group-error input[type=month],.wy-control-group.wy-control-group-error input[type=number],.wy-control-group.wy-control-group-error input[type=password],.wy-control-group.wy-control-group-error input[type=search],.wy-control-group.wy-control-group-error input[type=tel],.wy-control-group.wy-control-group-error input[type=text],.wy-control-group.wy-control-group-error input[type=time],.wy-control-group.wy-control-group-error input[type=url],.wy-control-group.wy-control-group-error input[type=week],.wy-control-group.wy-control-group-error textarea{border:1px solid #e74c3c}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:.5em .625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27ae60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#e74c3c}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#e67e22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980b9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width:480px){.wy-form button[type=submit]{margin:.7em 0 0}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=text],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week],.wy-form label{margin-bottom:.3em;display:block}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0}.wy-form-message,.wy-form-message-inline,.wy-form .wy-help-inline{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width:768px){.tablet-hide{display:none}}@media screen and (max-width:480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.rst-content table.docutils,.rst-content table.field-list,.wy-table{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.rst-content table.docutils caption,.rst-content table.field-list caption,.wy-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.rst-content table.docutils td,.rst-content table.docutils th,.rst-content table.field-list td,.rst-content table.field-list th,.wy-table td,.wy-table th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.rst-content table.docutils td:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list td:first-child,.rst-content table.field-list th:first-child,.wy-table td:first-child,.wy-table th:first-child{border-left-width:0}.rst-content table.docutils thead,.rst-content table.field-list thead,.wy-table thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.rst-content table.docutils thead th,.rst-content table.field-list thead th,.wy-table thead th{font-weight:700;border-bottom:2px solid #e1e4e5}.rst-content table.docutils td,.rst-content table.field-list td,.wy-table td{background-color:transparent;vertical-align:middle}.rst-content table.docutils td p,.rst-content table.field-list td p,.wy-table td p{line-height:18px}.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child,.wy-table td p:last-child{margin-bottom:0}.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min,.wy-table .wy-table-cell-min{width:1%;padding-right:0}.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:grey;font-size:90%}.wy-table-tertiary{color:grey;font-size:80%}.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td,.wy-table-backed,.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td{background-color:#f3f6f6}.rst-content table.docutils,.wy-table-bordered-all{border:1px solid #e1e4e5}.rst-content table.docutils td,.wy-table-bordered-all td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.rst-content table.docutils tbody>tr:last-child td,.wy-table-bordered-all tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0!important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980b9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9b59b6}html{height:100%}body,html{overflow-x:hidden}body{font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;font-weight:400;color:#404040;min-height:100%;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#e67e22!important}a.wy-text-warning:hover{color:#eb9950!important}.wy-text-info{color:#2980b9!important}a.wy-text-info:hover{color:#409ad5!important}.wy-text-success{color:#27ae60!important}a.wy-text-success:hover{color:#36d278!important}.wy-text-danger{color:#e74c3c!important}a.wy-text-danger:hover{color:#ed7669!important}.wy-text-neutral{color:#404040!important}a.wy-text-neutral:hover{color:#595959!important}.rst-content .toctree-wrapper>p.caption,h1,h2,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif}p{line-height:24px;font-size:16px;margin:0 0 24px}h1{font-size:175%}.rst-content .toctree-wrapper>p.caption,h2{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}.rst-content code,.rst-content tt,code{white-space:nowrap;max-width:100%;background:#fff;border:1px solid #e1e4e5;font-size:75%;padding:0 5px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#e74c3c;overflow-x:auto}.rst-content tt.code-large,code.code-large{font-size:90%}.rst-content .section ul,.rst-content .toctree-wrapper ul,.rst-content section ul,.wy-plain-list-disc,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.rst-content .section ul li,.rst-content .toctree-wrapper ul li,.rst-content section ul li,.wy-plain-list-disc li,article ul li{list-style:disc;margin-left:24px}.rst-content .section ul li p:last-child,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li p:last-child,.rst-content .toctree-wrapper ul li ul,.rst-content section ul li p:last-child,.rst-content section ul li ul,.wy-plain-list-disc li p:last-child,.wy-plain-list-disc li ul,article ul li p:last-child,article ul li ul{margin-bottom:0}.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,.rst-content section ul li li,.wy-plain-list-disc li li,article ul li li{list-style:circle}.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,.rst-content section ul li li li,.wy-plain-list-disc li li li,article ul li li li{list-style:square}.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,.rst-content section ul li ol li,.wy-plain-list-disc li ol li,article ul li ol li{list-style:decimal}.rst-content .section ol,.rst-content .section ol.arabic,.rst-content .toctree-wrapper ol,.rst-content .toctree-wrapper ol.arabic,.rst-content section ol,.rst-content section ol.arabic,.wy-plain-list-decimal,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.rst-content .section ol.arabic li,.rst-content .section ol li,.rst-content .toctree-wrapper ol.arabic li,.rst-content .toctree-wrapper ol li,.rst-content section ol.arabic li,.rst-content section ol li,.wy-plain-list-decimal li,article ol li{list-style:decimal;margin-left:24px}.rst-content .section ol.arabic li ul,.rst-content .section ol li p:last-child,.rst-content .section ol li ul,.rst-content .toctree-wrapper ol.arabic li ul,.rst-content .toctree-wrapper ol li p:last-child,.rst-content .toctree-wrapper ol li ul,.rst-content section ol.arabic li ul,.rst-content section ol li p:last-child,.rst-content section ol li ul,.wy-plain-list-decimal li p:last-child,.wy-plain-list-decimal li ul,article ol li p:last-child,article ol li ul{margin-bottom:0}.rst-content .section ol.arabic li ul li,.rst-content .section ol li ul li,.rst-content .toctree-wrapper ol.arabic li ul li,.rst-content .toctree-wrapper ol li ul li,.rst-content section ol.arabic li ul li,.rst-content section ol li ul li,.wy-plain-list-decimal li ul li,article ol li ul li{list-style:disc}.wy-breadcrumbs{*zoom:1}.wy-breadcrumbs:after,.wy-breadcrumbs:before{display:table;content:""}.wy-breadcrumbs:after{clear:both}.wy-breadcrumbs>li{display:inline-block;padding-top:5px}.wy-breadcrumbs>li.wy-breadcrumbs-aside{float:right}.rst-content .wy-breadcrumbs>li code,.rst-content .wy-breadcrumbs>li tt,.wy-breadcrumbs>li .rst-content tt,.wy-breadcrumbs>li code{all:inherit;color:inherit}.breadcrumb-item:before{content:"/";color:#bbb;font-size:13px;padding:0 6px 0 3px}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width:480px){.wy-breadcrumbs-extra,.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}html{font-size:16px}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:after,.wy-menu-horiz:before{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz li,.wy-menu-horiz ul{display:inline-block}.wy-menu-horiz li:hover{background:hsla(0,0%,100%,.1)}.wy-menu-horiz li.divide-left{border-left:1px solid #404040}.wy-menu-horiz li.divide-right{border-right:1px solid #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical{width:300px}.wy-menu-vertical header,.wy-menu-vertical p.caption{color:#55a5d9;height:32px;line-height:32px;padding:0 1.618em;margin:12px 0 0;display:block;font-weight:700;text-transform:uppercase;font-size:85%;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:1px solid #404040}.wy-menu-vertical li.divide-bottom{border-bottom:1px solid #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:grey;border-right:1px solid #c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.rst-content .wy-menu-vertical li tt,.wy-menu-vertical li .rst-content tt,.wy-menu-vertical li code{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li button.toctree-expand{display:block;float:left;margin-left:-1.2em;line-height:18px;color:#4d4d4d;border:none;background:none;padding:0}.wy-menu-vertical li.current>a,.wy-menu-vertical li.on a{color:#404040;font-weight:700;position:relative;background:#fcfcfc;border:none;padding:.4045em 1.618em}.wy-menu-vertical li.current>a:hover,.wy-menu-vertical li.on a:hover{background:#fcfcfc}.wy-menu-vertical li.current>a:hover button.toctree-expand,.wy-menu-vertical li.on a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand{display:block;line-height:18px;color:#333}.wy-menu-vertical li.toctree-l1.current>a{border-bottom:1px solid #c9c9c9;border-top:1px solid #c9c9c9}.wy-menu-vertical .toctree-l1.current .toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .toctree-l11>ul{display:none}.wy-menu-vertical .toctree-l1.current .current.toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .current.toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .current.toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .current.toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .current.toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .current.toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .current.toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .current.toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .current.toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .current.toctree-l11>ul{display:block}.wy-menu-vertical li.toctree-l3,.wy-menu-vertical li.toctree-l4{font-size:.9em}.wy-menu-vertical li.toctree-l2 a,.wy-menu-vertical li.toctree-l3 a,.wy-menu-vertical li.toctree-l4 a,.wy-menu-vertical li.toctree-l5 a,.wy-menu-vertical li.toctree-l6 a,.wy-menu-vertical li.toctree-l7 a,.wy-menu-vertical li.toctree-l8 a,.wy-menu-vertical li.toctree-l9 a,.wy-menu-vertical li.toctree-l10 a{color:#404040}.wy-menu-vertical li.toctree-l2 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l3 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l4 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l5 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l6 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l7 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l8 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l9 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l10 a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a,.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a,.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a,.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a,.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a,.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a,.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a,.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{display:block}.wy-menu-vertical li.toctree-l2.current>a{padding:.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{padding:.4045em 1.618em .4045em 4.045em}.wy-menu-vertical li.toctree-l3.current>a{padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{padding:.4045em 1.618em .4045em 5.663em}.wy-menu-vertical li.toctree-l4.current>a{padding:.4045em 5.663em}.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a{padding:.4045em 1.618em .4045em 7.281em}.wy-menu-vertical li.toctree-l5.current>a{padding:.4045em 7.281em}.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a{padding:.4045em 1.618em .4045em 8.899em}.wy-menu-vertical li.toctree-l6.current>a{padding:.4045em 8.899em}.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a{padding:.4045em 1.618em .4045em 10.517em}.wy-menu-vertical li.toctree-l7.current>a{padding:.4045em 10.517em}.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a{padding:.4045em 1.618em .4045em 12.135em}.wy-menu-vertical li.toctree-l8.current>a{padding:.4045em 12.135em}.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a{padding:.4045em 1.618em .4045em 13.753em}.wy-menu-vertical li.toctree-l9.current>a{padding:.4045em 13.753em}.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a{padding:.4045em 1.618em .4045em 15.371em}.wy-menu-vertical li.toctree-l10.current>a{padding:.4045em 15.371em}.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{padding:.4045em 1.618em .4045em 16.989em}.wy-menu-vertical li.toctree-l2.current>a,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{background:#c9c9c9}.wy-menu-vertical li.toctree-l2 button.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3.current>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{background:#bdbdbd}.wy-menu-vertical li.toctree-l3 button.toctree-expand{color:#969696}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical li ul li a{margin-bottom:0;color:#d9d9d9;font-weight:400}.wy-menu-vertical a{line-height:18px;padding:.4045em 1.618em;display:block;position:relative;font-size:90%;color:#d9d9d9}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover button.toctree-expand{color:#d9d9d9}.wy-menu-vertical a:active{background-color:#2980b9;cursor:pointer;color:#fff}.wy-menu-vertical a:active button.toctree-expand{color:#fff}.wy-side-nav-search{display:block;width:300px;padding:.809em;margin-bottom:.809em;z-index:200;background-color:#2980b9;text-align:center;color:#fcfcfc}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto .809em;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-side-nav-search .wy-dropdown>a,.wy-side-nav-search>a{color:#fcfcfc;font-size:100%;font-weight:700;display:inline-block;padding:4px 6px;margin-bottom:.809em;max-width:100%}.wy-side-nav-search .wy-dropdown>a:hover,.wy-side-nav-search>a:hover{background:hsla(0,0%,100%,.1)}.wy-side-nav-search .wy-dropdown>a img.logo,.wy-side-nav-search>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search .wy-dropdown>a.icon img.logo,.wy-side-nav-search>a.icon img.logo{margin-top:.85em}.wy-side-nav-search>div.version{margin-top:-.4045em;margin-bottom:.809em;font-weight:400;color:hsla(0,0%,100%,.3)}.wy-nav .wy-menu-vertical header{color:#2980b9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980b9;color:#fff}[data-menu-wrap]{-webkit-transition:all .2s ease-in;-moz-transition:all .2s ease-in;transition:all .2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:#fcfcfc}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:hidden;min-height:100%;color:#9b9b9b;background:#343131;z-index:200}.wy-side-scroll{width:320px;position:relative;overflow-x:hidden;overflow-y:scroll;height:100%}.wy-nav-top{display:none;background:#2980b9;color:#fff;padding:.4045em .809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:after,.wy-nav-top:before{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:700}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer;padding-top:inherit}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:grey}footer p{margin-bottom:12px}.rst-content footer span.commit tt,footer span.commit .rst-content tt,footer span.commit code{padding:0;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:1em;background:none;border:none;color:grey}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:after,.rst-footer-buttons:before{width:100%;display:table;content:""}.rst-footer-buttons:after{clear:both}.rst-breadcrumbs-buttons{margin-top:12px;*zoom:1}.rst-breadcrumbs-buttons:after,.rst-breadcrumbs-buttons:before{display:table;content:""}.rst-breadcrumbs-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:1px solid #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:1px solid #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:grey;font-size:90%}.genindextable li>ul{margin-left:24px}@media screen and (max-width:768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-menu.wy-menu-vertical,.wy-side-nav-search,.wy-side-scroll{width:auto}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width:1100px){.wy-nav-content-wrap{background:rgba(0,0,0,.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,.wy-nav-side,footer{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60;*zoom:1}.rst-versions .rst-current-version:after,.rst-versions .rst-current-version:before{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-content .code-block-caption .rst-versions .rst-current-version .headerlink,.rst-content .eqno .rst-versions .rst-current-version .headerlink,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-content p .rst-versions .rst-current-version .headerlink,.rst-content table>caption .rst-versions .rst-current-version .headerlink,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .icon,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-versions .rst-current-version .rst-content .code-block-caption .headerlink,.rst-versions .rst-current-version .rst-content .eqno .headerlink,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-versions .rst-current-version .rst-content p .headerlink,.rst-versions .rst-current-version .rst-content table>caption .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-versions .rst-current-version .wy-menu-vertical li button.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version button.toctree-expand{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}.rst-content .toctree-wrapper>p.caption,.rst-content h1,.rst-content h2,.rst-content h3,.rst-content h4,.rst-content h5,.rst-content h6{margin-bottom:24px}.rst-content img{max-width:100%;height:auto}.rst-content div.figure,.rst-content figure{margin-bottom:24px}.rst-content div.figure .caption-text,.rst-content figure .caption-text{font-style:italic}.rst-content div.figure p:last-child.caption,.rst-content figure p:last-child.caption{margin-bottom:0}.rst-content div.figure.align-center,.rst-content figure.align-center{text-align:center}.rst-content .section>a>img,.rst-content .section>img,.rst-content section>a>img,.rst-content section>img{margin-bottom:24px}.rst-content abbr[title]{text-decoration:none}.rst-content.style-external-links a.reference.external:after{font-family:FontAwesome;content:"\f08e";color:#b3b3b3;vertical-align:super;font-size:60%;margin:0 .2em}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content pre.literal-block{white-space:pre;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;display:block;overflow:auto}.rst-content div[class^=highlight],.rst-content pre.literal-block{border:1px solid #e1e4e5;overflow-x:auto;margin:1px 0 24px}.rst-content div[class^=highlight] div[class^=highlight],.rst-content pre.literal-block div[class^=highlight]{padding:0;border:none;margin:0}.rst-content div[class^=highlight] td.code{width:100%}.rst-content .linenodiv pre{border-right:1px solid #e6e9ea;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;user-select:none;pointer-events:none}.rst-content div[class^=highlight] pre{white-space:pre;margin:0;padding:12px;display:block;overflow:auto}.rst-content div[class^=highlight] pre .hll{display:block;margin:0 -12px;padding:0 12px}.rst-content .linenodiv pre,.rst-content div[class^=highlight] pre,.rst-content pre.literal-block{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:12px;line-height:1.4}.rst-content div.highlight .gp,.rst-content div.highlight span.linenos{user-select:none;pointer-events:none}.rst-content div.highlight span.linenos{display:inline-block;padding-left:0;padding-right:12px;margin-right:12px;border-right:1px solid #e6e9ea}.rst-content .code-block-caption{font-style:italic;font-size:85%;line-height:1;padding:1em 0;text-align:center}@media print{.rst-content .codeblock,.rst-content div[class^=highlight],.rst-content div[class^=highlight] pre{white-space:pre-wrap}}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning{clear:both}.rst-content .admonition-todo .last,.rst-content .admonition-todo>:last-child,.rst-content .admonition .last,.rst-content .admonition>:last-child,.rst-content .attention .last,.rst-content .attention>:last-child,.rst-content .caution .last,.rst-content .caution>:last-child,.rst-content .danger .last,.rst-content .danger>:last-child,.rst-content .error .last,.rst-content .error>:last-child,.rst-content .hint .last,.rst-content .hint>:last-child,.rst-content .important .last,.rst-content .important>:last-child,.rst-content .note .last,.rst-content .note>:last-child,.rst-content .seealso .last,.rst-content .seealso>:last-child,.rst-content .tip .last,.rst-content .tip>:last-child,.rst-content .warning .last,.rst-content .warning>:last-child{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent!important;border-color:rgba(0,0,0,.1)!important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha>li,.rst-content .toctree-wrapper ol.loweralpha,.rst-content .toctree-wrapper ol.loweralpha>li,.rst-content section ol.loweralpha,.rst-content section ol.loweralpha>li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha>li,.rst-content .toctree-wrapper ol.upperalpha,.rst-content .toctree-wrapper ol.upperalpha>li,.rst-content section ol.upperalpha,.rst-content section ol.upperalpha>li{list-style:upper-alpha}.rst-content .section ol li>*,.rst-content .section ul li>*,.rst-content .toctree-wrapper ol li>*,.rst-content .toctree-wrapper ul li>*,.rst-content section ol li>*,.rst-content section ul li>*{margin-top:12px;margin-bottom:12px}.rst-content .section ol li>:first-child,.rst-content .section ul li>:first-child,.rst-content .toctree-wrapper ol li>:first-child,.rst-content .toctree-wrapper ul li>:first-child,.rst-content section ol li>:first-child,.rst-content section ul li>:first-child{margin-top:0}.rst-content .section ol li>p,.rst-content .section ol li>p:last-child,.rst-content .section ul li>p,.rst-content .section ul li>p:last-child,.rst-content .toctree-wrapper ol li>p,.rst-content .toctree-wrapper ol li>p:last-child,.rst-content .toctree-wrapper ul li>p,.rst-content .toctree-wrapper ul li>p:last-child,.rst-content section ol li>p,.rst-content section ol li>p:last-child,.rst-content section ul li>p,.rst-content section ul li>p:last-child{margin-bottom:12px}.rst-content .section ol li>p:only-child,.rst-content .section ol li>p:only-child:last-child,.rst-content .section ul li>p:only-child,.rst-content .section ul li>p:only-child:last-child,.rst-content .toctree-wrapper ol li>p:only-child,.rst-content .toctree-wrapper ol li>p:only-child:last-child,.rst-content .toctree-wrapper ul li>p:only-child,.rst-content .toctree-wrapper ul li>p:only-child:last-child,.rst-content section ol li>p:only-child,.rst-content section ol li>p:only-child:last-child,.rst-content section ul li>p:only-child,.rst-content section ul li>p:only-child:last-child{margin-bottom:0}.rst-content .section ol li>ol,.rst-content .section ol li>ul,.rst-content .section ul li>ol,.rst-content .section ul li>ul,.rst-content .toctree-wrapper ol li>ol,.rst-content .toctree-wrapper ol li>ul,.rst-content .toctree-wrapper ul li>ol,.rst-content .toctree-wrapper ul li>ul,.rst-content section ol li>ol,.rst-content section ol li>ul,.rst-content section ul li>ol,.rst-content section ul li>ul{margin-bottom:12px}.rst-content .section ol.simple li>*,.rst-content .section ol.simple li ol,.rst-content .section ol.simple li ul,.rst-content .section ul.simple li>*,.rst-content .section ul.simple li ol,.rst-content .section ul.simple li ul,.rst-content .toctree-wrapper ol.simple li>*,.rst-content .toctree-wrapper ol.simple li ol,.rst-content .toctree-wrapper ol.simple li ul,.rst-content .toctree-wrapper ul.simple li>*,.rst-content .toctree-wrapper ul.simple li ol,.rst-content .toctree-wrapper ul.simple li ul,.rst-content section ol.simple li>*,.rst-content section ol.simple li ol,.rst-content section ol.simple li ul,.rst-content section ul.simple li>*,.rst-content section ul.simple li ol,.rst-content section ul.simple li ul{margin-top:0;margin-bottom:0}.rst-content .line-block{margin-left:0;margin-bottom:24px;line-height:24px}.rst-content .line-block .line-block{margin-left:24px;margin-bottom:0}.rst-content .topic-title{font-weight:700;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0 0 24px 24px}.rst-content .align-left{float:left;margin:0 24px 24px 0}.rst-content .align-center{margin:auto}.rst-content .align-center:not(table){display:block}.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink{opacity:0;font-size:14px;font-family:FontAwesome;margin-left:.5em}.rst-content .code-block-caption .headerlink:focus,.rst-content .code-block-caption:hover .headerlink,.rst-content .eqno .headerlink:focus,.rst-content .eqno:hover .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink:focus,.rst-content .toctree-wrapper>p.caption:hover .headerlink,.rst-content dl dt .headerlink:focus,.rst-content dl dt:hover .headerlink,.rst-content h1 .headerlink:focus,.rst-content h1:hover .headerlink,.rst-content h2 .headerlink:focus,.rst-content h2:hover .headerlink,.rst-content h3 .headerlink:focus,.rst-content h3:hover .headerlink,.rst-content h4 .headerlink:focus,.rst-content h4:hover .headerlink,.rst-content h5 .headerlink:focus,.rst-content h5:hover .headerlink,.rst-content h6 .headerlink:focus,.rst-content h6:hover .headerlink,.rst-content p.caption .headerlink:focus,.rst-content p.caption:hover .headerlink,.rst-content p .headerlink:focus,.rst-content p:hover .headerlink,.rst-content table>caption .headerlink:focus,.rst-content table>caption:hover .headerlink{opacity:1}.rst-content p a{overflow-wrap:anywhere}.rst-content .wy-table td p,.rst-content .wy-table td ul,.rst-content .wy-table th p,.rst-content .wy-table th ul,.rst-content table.docutils td p,.rst-content table.docutils td ul,.rst-content table.docutils th p,.rst-content table.docutils th ul,.rst-content table.field-list td p,.rst-content table.field-list td ul,.rst-content table.field-list th p,.rst-content table.field-list th ul{font-size:inherit}.rst-content .btn:focus{outline:2px solid}.rst-content table>caption .headerlink:after{font-size:12px}.rst-content .centered{text-align:center}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:1px solid #e1e4e5}.rst-content .sidebar dl,.rst-content .sidebar p,.rst-content .sidebar ul{font-size:90%}.rst-content .sidebar .last,.rst-content .sidebar>:last-child{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif;font-weight:700;background:#e1e4e5;padding:6px 12px;margin:-24px -24px 24px;font-size:100%}.rst-content .highlighted{background:#f1c40f;box-shadow:0 0 0 2px #f1c40f;display:inline;font-weight:700}.rst-content .citation-reference,.rst-content .footnote-reference{vertical-align:baseline;position:relative;top:-.4em;line-height:0;font-size:90%}.rst-content .citation-reference>span.fn-bracket,.rst-content .footnote-reference>span.fn-bracket{display:none}.rst-content .hlist{width:100%}.rst-content dl dt span.classifier:before{content:" : "}.rst-content dl dt span.classifier-delimiter{display:none!important}html.writer-html4 .rst-content table.docutils.citation,html.writer-html4 .rst-content table.docutils.footnote{background:none;border:none}html.writer-html4 .rst-content table.docutils.citation td,html.writer-html4 .rst-content table.docutils.citation tr,html.writer-html4 .rst-content table.docutils.footnote td,html.writer-html4 .rst-content table.docutils.footnote tr{border:none;background-color:transparent!important;white-space:normal}html.writer-html4 .rst-content table.docutils.citation td.label,html.writer-html4 .rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{display:grid;grid-template-columns:auto minmax(80%,95%)}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{display:inline-grid;grid-template-columns:max-content auto}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{display:grid;grid-template-columns:auto auto minmax(.65rem,auto) minmax(40%,95%)}html.writer-html5 .rst-content aside.citation>span.label,html.writer-html5 .rst-content aside.footnote>span.label,html.writer-html5 .rst-content div.citation>span.label{grid-column-start:1;grid-column-end:2}html.writer-html5 .rst-content aside.citation>span.backrefs,html.writer-html5 .rst-content aside.footnote>span.backrefs,html.writer-html5 .rst-content div.citation>span.backrefs{grid-column-start:2;grid-column-end:3;grid-row-start:1;grid-row-end:3}html.writer-html5 .rst-content aside.citation>p,html.writer-html5 .rst-content aside.footnote>p,html.writer-html5 .rst-content div.citation>p{grid-column-start:4;grid-column-end:5}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{margin-bottom:24px}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{padding-left:1rem}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dd,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dd,html.writer-html5 .rst-content dl.footnote>dt{margin-bottom:0}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{font-size:.9rem}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.footnote>dt{margin:0 .5rem .5rem 0;line-height:1.2rem;word-break:break-all;font-weight:400}html.writer-html5 .rst-content dl.citation>dt>span.brackets:before,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:before{content:"["}html.writer-html5 .rst-content dl.citation>dt>span.brackets:after,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:after{content:"]"}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a{word-break:keep-all}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a:not(:first-child):before,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.footnote>dd{margin:0 0 .5rem;line-height:1.2rem}html.writer-html5 .rst-content dl.citation>dd p,html.writer-html5 .rst-content dl.footnote>dd p{font-size:.9rem}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{padding-left:1rem;padding-right:1rem;font-size:.9rem;line-height:1.2rem}html.writer-html5 .rst-content aside.citation p,html.writer-html5 .rst-content aside.footnote p,html.writer-html5 .rst-content div.citation p{font-size:.9rem;line-height:1.2rem;margin-bottom:12px}html.writer-html5 .rst-content aside.citation span.backrefs,html.writer-html5 .rst-content aside.footnote span.backrefs,html.writer-html5 .rst-content div.citation span.backrefs{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content aside.citation span.backrefs>a,html.writer-html5 .rst-content aside.footnote span.backrefs>a,html.writer-html5 .rst-content div.citation span.backrefs>a{word-break:keep-all}html.writer-html5 .rst-content aside.citation span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content aside.footnote span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content div.citation span.backrefs>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content aside.citation span.label,html.writer-html5 .rst-content aside.footnote span.label,html.writer-html5 .rst-content div.citation span.label{line-height:1.2rem}html.writer-html5 .rst-content aside.citation-list,html.writer-html5 .rst-content aside.footnote-list,html.writer-html5 .rst-content div.citation-list{margin-bottom:24px}html.writer-html5 .rst-content dl.option-list kbd{font-size:.9rem}.rst-content table.docutils.footnote,html.writer-html4 .rst-content table.docutils.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content aside.footnote-list aside.footnote,html.writer-html5 .rst-content div.citation-list>div.citation,html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{color:grey}.rst-content table.docutils.footnote code,.rst-content table.docutils.footnote tt,html.writer-html4 .rst-content table.docutils.citation code,html.writer-html4 .rst-content table.docutils.citation tt,html.writer-html5 .rst-content aside.footnote-list aside.footnote code,html.writer-html5 .rst-content aside.footnote-list aside.footnote tt,html.writer-html5 .rst-content aside.footnote code,html.writer-html5 .rst-content aside.footnote tt,html.writer-html5 .rst-content div.citation-list>div.citation code,html.writer-html5 .rst-content div.citation-list>div.citation tt,html.writer-html5 .rst-content dl.citation code,html.writer-html5 .rst-content dl.citation tt,html.writer-html5 .rst-content dl.footnote code,html.writer-html5 .rst-content dl.footnote tt{color:#555}.rst-content .wy-table-responsive.citation,.rst-content .wy-table-responsive.footnote{margin-bottom:0}.rst-content .wy-table-responsive.citation+:not(.citation),.rst-content .wy-table-responsive.footnote+:not(.footnote){margin-top:24px}.rst-content .wy-table-responsive.citation:last-child,.rst-content .wy-table-responsive.footnote:last-child{margin-bottom:24px}.rst-content table.docutils th{border-color:#e1e4e5}html.writer-html5 .rst-content table.docutils th{border:1px solid #e1e4e5}html.writer-html5 .rst-content table.docutils td>p,html.writer-html5 .rst-content table.docutils th>p{line-height:1rem;margin-bottom:0;font-size:.9rem}.rst-content table.docutils td .last,.rst-content table.docutils td .last>:last-child{margin-bottom:0}.rst-content table.field-list,.rst-content table.field-list td{border:none}.rst-content table.field-list td p{line-height:inherit}.rst-content table.field-list td>strong{display:inline-block}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left}.rst-content code,.rst-content tt{color:#000;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;padding:2px 5px}.rst-content code big,.rst-content code em,.rst-content tt big,.rst-content tt em{font-size:100%!important;line-height:normal}.rst-content code.literal,.rst-content tt.literal{color:#e74c3c;white-space:normal}.rst-content code.xref,.rst-content tt.xref,a .rst-content code,a .rst-content tt{font-weight:700;color:#404040;overflow-wrap:normal}.rst-content kbd,.rst-content pre,.rst-content samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace}.rst-content a code,.rst-content a tt{color:#2980b9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:700;margin-bottom:12px}.rst-content dl ol,.rst-content dl p,.rst-content dl table,.rst-content dl ul{margin-bottom:12px}.rst-content dl dd{margin:0 0 12px 24px;line-height:24px}.rst-content dl dd>ol:last-child,.rst-content dl dd>p:last-child,.rst-content dl dd>table:last-child,.rst-content dl dd>ul:last-child{margin-bottom:0}html.writer-html4 .rst-content dl:not(.docutils),html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple){margin-bottom:24px}html.writer-html4 .rst-content dl:not(.docutils)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{display:table;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980b9;border-top:3px solid #6ab0de;padding:6px;position:relative}html.writer-html4 .rst-content dl:not(.docutils)>dt:before,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:before{color:#6ab0de}html.writer-html4 .rst-content dl:not(.docutils)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{margin-bottom:6px;border:none;border-left:3px solid #ccc;background:#f0f0f0;color:#555}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils)>dt:first-child,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:first-child{margin-top:0}html.writer-html4 .rst-content dl:not(.docutils) code.descclassname,html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descclassname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{background-color:transparent;border:none;padding:0;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .optional,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .property,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .property{display:inline-block;padding-right:8px;max-width:100%}html.writer-html4 .rst-content dl:not(.docutils) .k,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .k{font-style:italic}html.writer-html4 .rst-content dl:not(.docutils) .descclassname,html.writer-html4 .rst-content dl:not(.docutils) .descname,html.writer-html4 .rst-content dl:not(.docutils) .sig-name,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .sig-name{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#000}.rst-content .viewcode-back,.rst-content .viewcode-link{display:inline-block;color:#27ae60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:700}.rst-content code.download,.rst-content tt.download{background:inherit;padding:inherit;font-weight:400;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content code.download span:first-child,.rst-content tt.download span:first-child{-webkit-font-smoothing:subpixel-antialiased}.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{margin-right:4px}.rst-content .guilabel{border:1px solid #7fbbe3;background:#e7f2fa;font-size:80%;font-weight:700;border-radius:4px;padding:2.4px 6px;margin:auto 2px}.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>.kbd,.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>kbd{color:inherit;font-size:80%;background-color:#fff;border:1px solid #a6a6a6;border-radius:4px;box-shadow:0 2px grey;padding:2.4px 6px;margin:auto 0}.rst-content .versionmodified{font-style:italic}@media screen and (max-width:480px){.rst-content .sidebar{width:100%}}span[id*=MathJax-Span]{color:#404040}.math{text-align:center}@font-face{font-family:Lato;src:url(fonts/lato-normal.woff2?bd03a2cc277bbbc338d464e679fe9942) format("woff2"),url(fonts/lato-normal.woff?27bd77b9162d388cb8d4c4217c7c5e2a) format("woff");font-weight:400;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold.woff2?cccb897485813c7c256901dbca54ecf2) format("woff2"),url(fonts/lato-bold.woff?d878b6c29b10beca227e9eef4246111b) format("woff");font-weight:700;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold-italic.woff2?0b6bb6725576b072c5d0b02ecdd1900d) format("woff2"),url(fonts/lato-bold-italic.woff?9c7e4e9eb485b4a121c760e61bc3707c) format("woff");font-weight:700;font-style:italic;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-normal-italic.woff2?4eb103b4d12be57cb1d040ed5e162e9d) format("woff2"),url(fonts/lato-normal-italic.woff?f28f2d6482446544ef1ea1ccc6dd5892) format("woff");font-weight:400;font-style:italic;font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:400;src:url(fonts/Roboto-Slab-Regular.woff2?7abf5b8d04d26a2cafea937019bca958) format("woff2"),url(fonts/Roboto-Slab-Regular.woff?c1be9284088d487c5e3ff0a10a92e58c) format("woff");font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:700;src:url(fonts/Roboto-Slab-Bold.woff2?9984f4a9bda09be08e83f2506954adbe) format("woff2"),url(fonts/Roboto-Slab-Bold.woff?bed5564a116b05148e3b3bea6fb1162a) format("woff");font-display:block} diff --git a/extensions/AdMob/docs/css/theme_extra.css b/extensions/AdMob/docs/css/theme_extra.css new file mode 100644 index 000000000..9f4b063c2 --- /dev/null +++ b/extensions/AdMob/docs/css/theme_extra.css @@ -0,0 +1,191 @@ +/* + * Wrap inline code samples otherwise they shoot of the side and + * can't be read at all. + * + * https://github.com/mkdocs/mkdocs/issues/313 + * https://github.com/mkdocs/mkdocs/issues/233 + * https://github.com/mkdocs/mkdocs/issues/834 + */ +.rst-content code { + white-space: pre-wrap; + word-wrap: break-word; + padding: 2px 5px; +} + +/** + * Make code blocks display as blocks and give them the appropriate + * font size and padding. + * + * https://github.com/mkdocs/mkdocs/issues/855 + * https://github.com/mkdocs/mkdocs/issues/834 + * https://github.com/mkdocs/mkdocs/issues/233 + */ +.rst-content pre code { + white-space: pre; + word-wrap: normal; + display: block; + padding: 12px; + font-size: 12px; +} + +/** + * Fix code colors + * + * https://github.com/mkdocs/mkdocs/issues/2027 + */ +.rst-content code { + color: #E74C3C; +} + +.rst-content pre code { + color: #000; + background: #f8f8f8; +} + +/* + * Fix link colors when the link text is inline code. + * + * https://github.com/mkdocs/mkdocs/issues/718 + */ +a code { + color: #2980B9; +} +a:hover code { + color: #3091d1; +} +a:visited code { + color: #9B59B6; +} + +/* + * The CSS classes from highlight.js seem to clash with the + * ReadTheDocs theme causing some code to be incorrectly made + * bold and italic. + * + * https://github.com/mkdocs/mkdocs/issues/411 + */ +pre .cs, pre .c { + font-weight: inherit; + font-style: inherit; +} + +/* + * Fix some issues with the theme and non-highlighted code + * samples. Without and highlighting styles attached the + * formatting is broken. + * + * https://github.com/mkdocs/mkdocs/issues/319 + */ +.rst-content .no-highlight { + display: block; + padding: 0.5em; + color: #333; +} + + +/* + * Additions specific to the search functionality provided by MkDocs + */ + +.search-results { + margin-top: 23px; +} + +.search-results article { + border-top: 1px solid #E1E4E5; + padding-top: 24px; +} + +.search-results article:first-child { + border-top: none; +} + +form .search-query { + width: 100%; + border-radius: 50px; + padding: 6px 12px; /* csslint allow: box-model */ + border-color: #D1D4D5; +} + +/* + * Improve inline code blocks within admonitions. + * + * https://github.com/mkdocs/mkdocs/issues/656 + */ + .rst-content .admonition code { + color: #404040; + border: 1px solid #c7c9cb; + border: 1px solid rgba(0, 0, 0, 0.2); + background: #f8fbfd; + background: rgba(255, 255, 255, 0.7); +} + +/* + * Account for wide tables which go off the side. + * Override borders to avoid weirdness on narrow tables. + * + * https://github.com/mkdocs/mkdocs/issues/834 + * https://github.com/mkdocs/mkdocs/pull/1034 + */ +.rst-content .section .docutils { + width: 100%; + overflow: auto; + display: block; + border: none; +} + +td, th { + border: 1px solid #e1e4e5 !important; /* csslint allow: important */ + border-collapse: collapse; +} + +/* + * Without the following amendments, the navigation in the theme will be + * slightly cut off. This is due to the fact that the .wy-nav-side has a + * padding-bottom of 2em, which must not necessarily align with the font-size of + * 90 % on the .rst-current-version container, combined with the padding of 12px + * above and below. These amendments fix this in two steps: First, make sure the + * .rst-current-version container has a fixed height of 40px, achieved using + * line-height, and then applying a padding-bottom of 40px to this container. In + * a second step, the items within that container are re-aligned using flexbox. + * + * https://github.com/mkdocs/mkdocs/issues/2012 + */ + .wy-nav-side { + padding-bottom: 40px; +} + +/* + * The second step of above amendment: Here we make sure the items are aligned + * correctly within the .rst-current-version container. Using flexbox, we + * achieve it in such a way that it will look like the following: + * + * [No repo_name] + * Next >> // On the first page + * << Previous Next >> // On all subsequent pages + * + * [With repo_name] + * Next >> // On the first page + * << Previous Next >> // On all subsequent pages + * + * https://github.com/mkdocs/mkdocs/issues/2012 + */ +.rst-versions .rst-current-version { + padding: 0 12px; + display: flex; + font-size: initial; + justify-content: space-between; + align-items: center; + line-height: 40px; +} + +/* + * Please note that this amendment also involves removing certain inline-styles + * from the file ./mkdocs/themes/readthedocs/versions.html. + * + * https://github.com/mkdocs/mkdocs/issues/2012 + */ +.rst-current-version span { + flex: 1; + text-align: center; +} diff --git a/extensions/AdMob/docs/general.html b/extensions/AdMob/docs/general.html new file mode 100644 index 000000000..4f3cf4766 --- /dev/null +++ b/extensions/AdMob/docs/general.html @@ -0,0 +1,327 @@ + + + + + + + + General - GMEXT-AdMob + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+ +
+
+
+
+ +

+

General

+

Functions

+

This module offers a collection of functions designed to address specific tasks and provide utilities for various purposes. Explore the available functions to make the most of the functionalities provided by this module.

+ +


+
+

Back To Top

+ +

AdMob_Initialize

+

This function initializes the Google AdMob API and should be called at the start of your game.

+


+

Syntax:

+
+
AdMob_Initialize()
+
+


+

Returns:

+
+

N/A

+
+


+


+
+

Back To Top

+ +

AdMob_SetTestDeviceId

+

This function tells the app to use test ads instead of “live” ads, essential for testing whether your ads work without generating potentially fraudulent click-throughs. This function should be called BEFORE calling AdMob_Initialize.

+


+

Syntax:

+
+
AdMob_SetTestDeviceId()
+
+


+

Returns:

+
+

N/A

+
+


+


+
+

Back To Top

+ +

AdMob_Events_OnPaidEvent

+

Enable the paid load callbacks, NOTE: You should enable this feature in your console too https://support.google.com/admob/answer/11322405

+

This function operates asynchronously, which means that it does not immediately return the requested result. Instead, upon completion of the task, it will trigger the Social Async Event.

+


+

Syntax:

+
+
AdMob_Events_OnPaidEvent(enable)
+
+ + + + + + + + + + + + + + + +
ArgumentTypeDescription
enableReal
+


+

Returns:

+
+

N/A

+
+


+

Triggers:

+
+

Social Async Event

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeString"AdMob_OnPaidEvent"
mediation_adapter_class_nameStringThe mediation adapter class name of the ad network that loaded the ad.
unit_idStringidentifier of the ad
ad_typeString'Banner","Interstitial","Rewarded","RewardedInterstitial" or "AppOpen"
microsRealThe ad's value in micro-units, where 1,000,000 micro-units equal one unit of the currency.
currency_codeStringThe value's ISO 4217 currency code.
precisionAdMobAdValuePrecisionThe precision type of the reported ad value.
ad_source_nameStringGets the ad source representing the specific ad network that serves the impression. For campaigns, Mediated House Ads is returned for a mediated ads campaign goal type, and Reservation Campaign is returned for impression and click goal types. See Ad sources for the list of possible ad source names when an ad network serves the ad.
ad_source_idStringGets the ad source ID associated with this adapter response. For campaigns, 6060308706800320801 is returned for a mediated ads campaign goal type, and 7068401028668408324 is returned for impression and click goal types. See Ad sources for the list of possible ad source IDs when an ad network serves the ad.
ad_source_instance_nameStringGets the ad source instance name associated with this adapter response.
ad_source_instance_idStringGets the ad source instance ID associated with this adapter response.
+


+


+ +
+
+ +
+
+ +
+ +
+ +
+ + + + GitHub + + + + « Previous + + + Next » + + +
+ + + + + + + + + + diff --git a/extensions/AdMob/docs/home.html b/extensions/AdMob/docs/home.html new file mode 100644 index 000000000..c85c4754d --- /dev/null +++ b/extensions/AdMob/docs/home.html @@ -0,0 +1,218 @@ + + + + + + + + AdMob Extension - GMEXT-AdMob + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+ +
+
+
+
+ +

+

AdMob

+

This is the AdMob extension which provides functionality to developers to add Google Ads to their game. In this wiki you can find the full available API documentation and guides necessary to get started.

+

Extension’s Features

+
    +
  • Enable test mode (development)
  • +
  • Request GDPR Consent
  • +
  • Target ads to your specific audience
  • +
  • Under-age
  • +
  • Children
  • +
  • Max Rating system
  • +
  • Use 5 distinct types of ads:
  • +
  • Banners (7 different banner types)
  • +
  • Interstitial
  • +
  • RewardedVideos
  • +
  • RewardedInterstitial
  • +
  • AppOpenAd
  • +
  • Allows ad volume control (including mute toggle)
  • +
+

Guides

+

Before you start using this extension make sure to follow our Setup guide. Which will get you up and running.

+

To get started using this extension, follow the Quick Start Guide.

+

For the recommended workflow see the Workflow page.

+

Modules

+

The following are the available modules from the AdMob API:

+ +


+
+ +
+
+ +
+
+ +
+ +
+ +
+ + + + GitHub + + + + + Next » + + +
+ + + + + + + + + + diff --git a/extensions/AdMob/docs/img/favicon.ico b/extensions/AdMob/docs/img/favicon.ico new file mode 100644 index 000000000..e85006a3c Binary files /dev/null and b/extensions/AdMob/docs/img/favicon.ico differ diff --git a/extensions/AdMob/docs/index.html b/extensions/AdMob/docs/index.html new file mode 100644 index 000000000..aecccf3a0 --- /dev/null +++ b/extensions/AdMob/docs/index.html @@ -0,0 +1,186 @@ + + + + + + + + GMEXT-AdMob + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+ +
+
+
+
+ +

Welcome to MkDocs

+

For full documentation visit mkdocs.org.

+

Commands

+
    +
  • mkdocs new [dir-name] - Create a new project.
  • +
  • mkdocs serve - Start the live-reloading docs server.
  • +
  • mkdocs build - Build the documentation site.
  • +
  • mkdocs -h - Print help message and exit.
  • +
+

Project layout

+
mkdocs.yml    # The configuration file.
+docs/
+    index.md  # The documentation homepage.
+    ...       # Other markdown pages, images and other files.
+
+ +
+
+ +
+
+ +
+ +
+ +
+ + + + GitHub + + + + + +
+ + + + + + + + + + + + diff --git a/extensions/AdMob/docs/interstitial.html b/extensions/AdMob/docs/interstitial.html new file mode 100644 index 000000000..d27428a90 --- /dev/null +++ b/extensions/AdMob/docs/interstitial.html @@ -0,0 +1,570 @@ + + + + + + + + Interstitial - GMEXT-AdMob + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+ +
+
+
+
+ +

+

Interstitial

+

Functions

+

This module offers a collection of functions designed to address specific tasks and provide utilities for various purposes. Explore the available functions to make the most of the functionalities provided by this module.

+ +


+
+

Back To Top

+ +

AdMob_Interstitial_Init

+
+

⛔️ This function was deprecated with version 1.3.0.

+
+

Initializes the target identifier for interstitial ad functions.

+
+

Note

+

Please refer to AdMob_Interstitial_Set_AdUnit for more information.

+
+


+

Syntax:

+
+
AdMob_Interstitial_Init(adUnitId)
+
+ + + + + + + + + + + + + + + +
ArgumentTypeDescription
adUnitIdString
+


+

Returns:

+
+

N/A

+
+


+

Versioning:

+
    +
  • 1.3.0 - ⛔️ This function was deprecated.
  • +
+


+


+
+

Back To Top

+ +

AdMob_Interstitial_Set_AdUnit

+

Set the target identifier for interstitial functions, Interstitials functions allow multiple identifiers

+


+

Syntax:

+
+
AdMob_Interstitial_Set_AdUnit(adUnitId)
+
+ + + + + + + + + + + + + + + +
ArgumentTypeDescription
adUnitIdString
+


+

Returns:

+
+

N/A

+
+


+

Versioning:

+
    +
  • 1.3.0 - This function was introduced.
  • +
+


+


+
+

Back To Top

+ +

Admob_Interstitial_Free_Load_Instances

+

Release Interstitial load instances (passing -1 will free all the loaded instances).

+


+

Syntax:

+
+
Admob_Interstitial_Free_Load_Instances(count)
+
+ + + + + + + + + + + + + + + +
ArgumentTypeDescription
countReal
+


+

Returns:

+
+

N/A

+
+


+

Versioning:

+
    +
  • 1.3.0 - This function was introduced.
  • +
+


+


+
+

Back To Top

+ +

Admob_Interstitial_Max_Instances

+

Set the max number of Interstitial load instances, this allow present consecutiva ads. Default value is 1.

+


+

Syntax:

+
+
Admob_Interstitial_Max_Instances(count)
+
+ + + + + + + + + + + + + + + +
ArgumentTypeDescription
countReal
+


+

Returns:

+
+

N/A

+
+


+

Versioning:

+
    +
  • 1.3.0 - This function was introduced.
  • +
+


+


+
+

Back To Top

+ +

AdMob_Interstitial_Load

+

This function should be called when you want to load an interstitial ad. Calling it will send a request to the ad server to provide an interstitial ad, which will then be loaded into the app for display. This function does not show the ad, just stores it in memory ready for being shown. If you do not call this function before trying to show an ad, nothing will be shown. Note that you can check whether an interstitial is loaded or not using the function AdMob_Interstitial_IsLoaded.

+

This function operates asynchronously, which means that it does not immediately return the requested result. Instead, upon completion of the task, it will trigger the Social Async Event.

+


+

Syntax:

+
+
AdMob_Interstitial_Load()
+
+


+

Returns:

+
+

AdMobErrors

+
+


+

Triggers:

+
+

Social Async Event

+
+

This event is triggered is the awaited task succeeds.

+ + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeString"AdMob_Interstitial_OnLoaded"
unit_idStringUnit identifier of the advertisment
+


+

This event is triggered is the awaited task fails.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeString"AdMob_Interstitial_OnLoadFailed"
unit_idStringUnit identifier of the advertisment
errorMessageStringthe error code responsible for the failure
errorCodeRealthe error message of the error code
+


+


+
+

Back To Top

+ +

AdMob_Interstitial_Show

+

This function will show the interstitial ad, if one is available and loaded. You can check whether an ad is available using the function AdMob_Interstitial_IsLoaded. Note that while an interstitial is being shown, your app will be put into the background and will effectively be “paused”.

+

This function operates asynchronously, which means that it does not immediately return the requested result. Instead, upon completion of the task, it will trigger the Social Async Event.

+


+

Syntax:

+
+
AdMob_Interstitial_Show()
+
+


+

Returns:

+
+

AdMobErrors

+
+


+

Triggers:

+
+

Social Async Event

+
+

This event is triggered is the ad view is closed by the user.

+ + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeString"AdMob_Interstitial_OnDismissed"
unit_idStringUnit identifier of the advertisment
+


+

This event is triggered is the awaited task fails.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeString"AdMob_Interstitial_OnShowFailed"
unit_idStringUnit identifier of the advertisment
errorMessageStringthe error code responsible for the failure
errorCodeRealthe error message of the error code
+


+

This event is triggered is the awaited task succeeds.

+ + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeString"AdMob_Interstitial_OnFullyShown"
unit_idStringUnit identifier of the advertisment
+


+


+
+

Back To Top

+ +

AdMob_Interstitial_IsLoaded

+

This function will return whether or not the interstitial ad is loaded.

+


+

Syntax:

+
+
AdMob_Interstitial_IsLoaded()
+
+


+

Returns:

+
+

Boolean

+
+


+


+
+

Back To Top

+ +

AdMob_Interstitial_Instances_Count

+

Return the number of Interstitial load instances are ready.

+


+

Syntax:

+
+
AdMob_Interstitial_Instances_Count()
+
+


+

Returns:

+
+

Boolean

+
+


+

Versioning:

+
    +
  • 1.3.0 - This function was introduced.
  • +
+


+


+ +
+
+ +
+
+ +
+ +
+ +
+ + + + GitHub + + + + « Previous + + + Next » + + +
+ + + + + + + + + + diff --git a/extensions/AdMob/docs/js/html5shiv.min.js b/extensions/AdMob/docs/js/html5shiv.min.js new file mode 100644 index 000000000..1a01c94ba --- /dev/null +++ b/extensions/AdMob/docs/js/html5shiv.min.js @@ -0,0 +1,4 @@ +/** +* @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed +*/ +!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document); diff --git a/extensions/AdMob/docs/js/jquery-3.6.0.min.js b/extensions/AdMob/docs/js/jquery-3.6.0.min.js new file mode 100644 index 000000000..c4c6022f2 --- /dev/null +++ b/extensions/AdMob/docs/js/jquery-3.6.0.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0"),n("table.docutils.footnote").wrap("
"),n("table.docutils.citation").wrap("
"),n(".wy-menu-vertical ul").not(".simple").siblings("a").each((function(){var t=n(this);expand=n(''),expand.on("click",(function(n){return e.toggleCurrent(t),n.stopPropagation(),!1})),t.prepend(expand)}))},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),t=e.find('[href="'+n+'"]');if(0===t.length){var i=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(t=e.find('[href="#'+i.attr("id")+'"]')).length&&(t=e.find('[href="#"]'))}if(t.length>0){$(".wy-menu-vertical .current").removeClass("current").attr("aria-expanded","false"),t.addClass("current").attr("aria-expanded","true"),t.closest("li.toctree-l1").parent().addClass("current").attr("aria-expanded","true");for(let n=1;n<=10;n++)t.closest("li.toctree-l"+n).addClass("current").attr("aria-expanded","true");t[0].scrollIntoView()}}catch(n){console.log("Error expanding nav for anchor",n)}},onScroll:function(){this.winScroll=!1;var n=this.win.scrollTop(),e=n+this.winHeight,t=this.navBar.scrollTop()+(n-this.winPosition);n<0||e>this.docHeight||(this.navBar.scrollTop(t),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",(function(){this.linkScroll=!1}))},toggleCurrent:function(n){var e=n.closest("li");e.siblings("li.current").removeClass("current").attr("aria-expanded","false"),e.siblings().find("li.current").removeClass("current").attr("aria-expanded","false");var t=e.find("> ul li");t.length&&(t.removeClass("current").attr("aria-expanded","false"),e.toggleClass("current").attr("aria-expanded",(function(n,e){return"true"==e?"false":"true"})))}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:n.exports.ThemeNav,StickyNav:n.exports.ThemeNav}),function(){for(var n=0,e=["ms","moz","webkit","o"],t=0;t + + + + + + + Quick Start Guide - GMEXT-AdMob + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+ +
+
+
+
+ +

Quick Start Guide

+

This section aims to deliver an easy and simple set of examples that should help you migrate your project from a previous version of the AdMob extension into this new, updated version. The first thing to notice is that all previously named “GoogleMobileAds_*” functions have been renamed to “AdMob_*” providing a more compact naming convention which is consistent with the Google API function names outside the GameMaker environment.

+

Initialization

+

The first thing to look for when creating an AdMob GameMaker project is initializing your API.

+

[Old Version]

+
// On the previous version you would need to provide application id and
+// an interstitial id to the API initialization function.
+GoogleMobileAds_Init(interstitialId, applicationId);
+
+// Optionally you could set your device to test mode to use test ads instead
+// of ‘live’ ones. You would provide the enable flag and the device id.
+GoogleMobileAds_UseTestAds(enable, deviceId); // <----- this is OPTIONAL
+

[New Version]

+
// If you are using Test Ads the ‘AdMob_SetTestDeviceId’ function needs to be
+// called BEFORE initialization (no arguments are required).
+AdMob_SetTestDeviceId(); // <----- this is OPTIONAL (development only)
+
+// In the new version you just need to call the initialization method without
+// any arguments, as the extension now gets the application id from the
+// “extension options” automatically (Setup, 2.), and the ad ids are setup on
+// a per ad-type basis.
+AdMob_Initialize();
+ +

One of the first concepts requiring your attention when setting up a project using AdMob is that, depending on the user's geographic location, you might need to ask for permission to use their personal information to personalize the ads that are shown.

+

[Old Version]

+

In previous versions you could ask the user for their consent to collect data for personalized ads using one of the following setups:

+
// You could forcefully show the consent form providing a privacy URL and
+// options for personalized ads, non-personalized ads and ad-free version of
+// your game.
+GoogleMobileAds_ConsentFormShow(privacyPolicy, personalized, nonPersonalized, adFree);
+

OR

+
// You could show the consent form ONLY if the user hasn’t yet answered it.
+GoogleMobileAds_ConsentUpdate(publisherId, privacyPolicy, personalized, nonPersonalized, adFree);
+

[New Version]

+

The new version has added functionality that requires you to:

+
    +
  1. check the consent status;
  2. +
  3. load the consent form before showing it to the user;
  4. +
  5. show the form (this replaces the old ’GoogleMobileAds_ConsentFormShow’)
  6. +
+

The first steps towards requesting user consent are the following:

+
// First of all we need to set the Consent Mode, which can be used for
+// debugging purposes to run tests as a  user in a different geographic area;
+// more info: Consent Mode. This function will generate an ASYNC SOCIAL EVENT.
+AdMob_Consent_RequestInfoUpdate(AdMob_Consent_Mode_PRODUCTION);
+

After setting the consent mode we need to add some code to the ASYNC SOCIAL EVENT, to check for the events generated by the AdMob_Consent_RequestInfoUpdate function call. +Here is what each event allows us to do:

+
    +
  1. “AdMob_Consent_OnRequestInfoUpdated” → we check status & load form;
  2. +
  3. “AdMob_Consent_OnLoaded” → we show the consent form;
  4. +
  5. “AdMob_Consent_OnShown” → we get the user’s consent type;
  6. +
+

Given below is the fully documented template code that you can use in your ASYNC SOCIAL EVENT:

+
// Early exit if there is no 'type' key defined
+if (!ds_map_exists(async_load, "type")) exit;
+
+// All the events triggered by the AdMob extension have a “type” key
+// containing a string that starts with “AdMob_”.
+switch(async_load[? "type"])
+{
+    // AdMob_Consent_RequestInfoUpdate() succeeded
+    case "AdMob_Consent_OnRequestInfoUpdated":
+
+        // Now we need to get the consent Status, this will tell us if we
+        // are required to ask the user for GDPR consent.
+        if (AdMob_Consent_GetStatus() == AdMob_Consent_Status_REQUIRED)
+
+            // Since we are REQUIRED, we now need to load the consent
+            // form before we can show it. For this we use the function
+            // below (more info: AdMob_Consent_Load). This function call
+            // will also generate an ASYNC SOCIAL EVENT.
+            AdMob_Consent_Load();
+        break;
+
+    // AdMob_Consent_RequestInfoUpdate() failed
+    case "AdMob_Consent_OnRequestInfoUpdateFailed":
+
+        // This means there was a problem while setting the consent
+        // mode. Here we can add some code to deal with it.
+        break;
+
+    // AdMob_Consent_Load() succeeded
+    case "AdMob_Consent_OnLoaded":
+
+        // We have successfully loaded the consent form and we are now
+        // ready to show it to the user (more info: AdMob_Consent_Show)
+        AdMob_Consent_Show();
+        break;
+
+    // AdMob_Consent_Load() failed
+    case "AdMob_Consent_OnLoadFailed":
+
+        // This means there was a problem while loading the consent
+        // form. Here we can add some code to deal with it.
+        break;
+
+    // AdMob_Consent_Show() succeeded and the user already answered it
+    case "AdMob_Consent_OnShown":
+
+        // At this point we now have the consent information from the
+        // user. We can use both the GetStatus and GetType functions to
+        // get the obtained information (more info:
+        // AdMob_Consent_GetStatus and AdMob_Consent_GetType)
+        global.ConsentStatus = AdMob_Consent_GetStatus();
+        global.ConsentType = AdMob_Consent_GetType();
+        break;
+}
+

Targeting

+

This new version of the AdMob extension allows the developer to target ads to a specific audience. This could already be done in previous versions but the new version now has more features specifically for targeting.

+

[Old Version]

+

In previous versions the developer could mark a user as underage ads using the following function:

+
// The function below classifies users as under age and only non-personalised
+// ads can be shown, regardless of any other setting, and the consent form
+// will not be shown.
+GoogleMobileAds_ConsentSetUserUnderAge(true);
+

[New Version]

+

In the new version of the extension the developer is presented with more features that will help target the right kind of ads to the right kind of audience:

+
// The function below allows the developer to enable or disable ads for
+// under-age users (much like the old version). Note that it is up to the
+// developer to identify the age of the consumer.
+AdMob_Targeting_UnderAge(true);
+
+// The function below allows the developer to enable or disable ads for
+// children. Note that it is up to the developer to identify the age of the
+// consumer.
+AdMob_Targeting_COPPA(true);
+
+// The new version of the AdMob extension allows for even further control
+// over the filtering of the ads being displayed to the user. The function
+// below allows the developer to set a maximum content rating of the ads to be
+// displayed (info: AdMob_Targeting_MaxAdContentRating and Content Rating constant.
+AdMob_Targeting_MaxAdContentRating(AdMob_ContentRating_GENERAL);
+ +

There have been a lot of API changes since the previous version, that said let’s jump in on a quick set up for adding banner ads to your application.

+

[Function Mappings]

+

Even though not all old functions map perfectly into the new API the following list should get you started with some of the changes (check the section below for more details):

+
    +
  • AdMob_Banner_Init(...) initializes the banner ads with a unique id.
  • +
  • AdMob_Banner_Create(...) replaces GoogleMobileAds_AddBanner(...)
  • +
  • triggers the Social event “AdMob_Banner_OnLoaded” if creation succeeds
  • +
  • triggers the Social event “AdMob_Banner_OnLoadFailed” if creation failed
  • +
  • AdMob_Banner_Move(...) replaces GoogleMobileAds_MoveBanner(...)
  • +
  • AdMob_Banner_Remove() replaces GoogleMobileAds_RemoveBanner()
  • +
  • AdMob_Banner_Show() replaces GoogleMobileAds_ShowBanner()
  • +
  • AdMob_Banner_Hide() replaces GoogleMobileAds_HideBanner()
  • +
+

[New Version]

+

The first step we should take towards adding banners is to use a manager object with the following CREATE EVENT (remember that you need to initialize the API first - Initialization)

+
// After API initialization we can proceed to initialize the banner options.
+// This function requires a unique ad block id string that can be obtained
+// from the google developer console (more info: AdMob_Banner_Init).
+// This function will generate an ASYNC SOCIAL EVENT.
+var banner_id = "ca-app-pub-3940256099942544/6300978111"
+AdMob_Banner_Init(banner_id);
+

The second step requires us to make sure the API was initialized, so for this example we will use the ASYNC SOCIAL EVENT to check for the events generated by the AdMob_Initialize function call.

+
// Early exit if there is no 'type' key defined
+if (!ds_map_exists(async_load, "type")) exit;
+
+// All the events triggered by the AdMob extension have a “type” key
+// containing a string that starts with “AdMob_”.
+switch(async_load[? "type"])
+{
+    // AdMob_Initialize() finished initializing the API
+    case "AdMob_OnInitialized":
+
+        // Now that we are sure that the API was initialized we can create
+        // our new banner on the device display.
+
+        // The function below will create a new banner of a given type,
+        // allowing the developer to also select the position of the
+        // banner (this can be either at the top or the bottom of the
+        // screen (more info: AdMob_Banner_Create and Banner Type).
+        var banner_type = AdMob_Banner_ADAPTIVE;
+        var bottom = true;
+        AdMob_Banner_Create(banner_type, bottom)
+        break;
+
+    // AdMob_Banner_Create() succeeded
+    case "AdMob_Banner_OnLoaded":
+
+        // At this point we should now have a banner on the screen.
+        break;
+
+    // AdMob_Banner_Create() failed
+    case "AdMob_Banner_OnLoadFailed":
+
+        // At this point there was a problem while creating the banner.
+        // Here we can add some code to deal with it.
+
+        // NOTE: Don’t try to create a banner here because it can lead to
+        // an infinite loop if the banner creation fails constantly.
+        break;
+}
+

Interstitial Ads

+

Interstitial ads are ads that will fill up the entire screen and need to be dismissed in order for the application to continue execution. Initial setup for interstitials is very similar to Banner ads (more info: Banner Ads). Let’s look at some code to quickly set up interstitial ads for your application.

+

[Function Mappings]

+

Even though not all old functions map perfectly into the new API, the following list should get you started with some of the changes (check the section below for more details):

+
    +
  • AdMob_Interstitial_Init(...) initializes the interstitial ads with a unique id.
  • +
  • AdMob_Interstitial_Load() replaces GoogleMobileAds_LoadInterstitial()
  • +
  • triggers the Social event “AdMob_Interstitial_OnLoaded” if load succeeds
  • +
  • triggers the Social event “AdMob_Interstitial_OnLoadFailed” if load fails
  • +
  • AdMob_Interstitial_IsLoaded() replaces GoogleMobileAds_InterstitialStatus()
  • +
  • AdMob_Interstitial_Show() replaces GoogleMobileAds_ShowInterstitial(...)
  • +
  • triggers the Social event “AdMob_Interstitial_OnFullyShown” if show succeeds
  • +
  • triggers the Social event “AdMob_Interstitial_OnShowFailed” if show fails
  • +
  • triggers the Social event “AdMob_Interstitial_OnDismissed” upon dismissing
  • +
+

[New Version]

+

The first step we should take towards adding interstitials is to use a manager object with the following CREATE EVENT (remember that you need to initialize the API first - Initialization)

+
// After API initialization we can proceed to initialize the interstitial
+// options. This requires a unique ad block id string that can be obtained
+// from the google developer console. (more info: AdMob_Interstitial_Init).
+// This function will generate a SOCIAL ASYNC EVENT.
+var interstitial_id = "ca-app-pub-3940256099942544/1033173712"
+AdMob_Interstitial_Init(interstitial_id);
+

The second step requires us to make sure the API was initialized so for this example we will use the ASYNC SOCIAL EVENT, to check for the events generated by the AdMob_Initialize function call.

+
// Early exit if there is no 'type' key defined
+if (!ds_map_exists(async_load, "type")) exit;
+
+// All the events triggered by the AdMob extension have a “type” key
+// containing a string that starts with “AdMob_”.
+switch(async_load[? "type"])
+{
+    // AdMob_Initialize() finished initializing the API
+    case "AdMob_OnInitialized":
+
+        // Now that we are sure that the API got initialized we can load
+        // a new interstitial ad.(more info: AdMob_Interstitial_Load).
+        // This function will generate an ASYNC SOCIAL EVENT.
+        AdMob_Interstitial_Load();
+        break;
+
+    // AdMob_Interstitial_Load() succeeded
+    case "AdMob_Interstitial_OnLoaded":
+
+        // At this point we should now have the interstitial ad loaded and
+        // and we can check that using the ´AdMob_Interstitial_IsLoaded´
+        // function. We are now ready to show the interstitial ad to the
+        // user (more info: AdMob_Interstitial_Show). This function will
+        // generate an ASYNC SOCIAL EVENT.
+        AdMob_Interstitial_Show();
+        break;
+
+    // AdMob_Interstitial_Load() failed
+    case "AdMob_Interstitial_OnLoadFailed":
+
+        // At this point there was a problem while loading the
+        // interstitial ad. Here we can add some code to deal with it.
+
+        // NOTE: Don’t try to reload the interstitial ad here because
+        // it can lead to an infinite loop.
+        break;
+
+    // AdMob_Interstitial_Show() succeeded
+    case "AdMob_Interstitial_OnFullyShown":
+
+        // At this point the interstitial ad is on screen and the user is
+        // looking at it. Note that at this point in time your game is
+        // paused and will remain paused until the interstitial gets
+        // dismissed.
+        break;
+
+    // AdMob_Interstitial_Show() failed
+    case "AdMob_Interstitial_OnShowFailed":
+
+        // At this point the interstitial ad failed to get shown to the
+        // user. You can add code to deal with the problem here.
+
+        // NOTE: Don’t try to reload/show the interstitial ad here
+        // because it can lead to an infinite loop.
+        break;
+
+    // Interstitial got dismissed
+    case "AdMob_Interstitial_OnDismissed":
+
+        // At this point the interstitial ad got dismissed by the user and
+        // the game logic is running again.
+        break;
+
+}
+

Rewarded Video Ads

+

Rewarded video ads are ads that will fill up the entire screen and play a video, at the end of which the user can be rewarded in some way, and similar to interstitial ads they also need to be dismissed in order for the application to continue execution. Rewarded Video ads setup is very similar to other previous ads (more info: Banner Ads and Interstitial Ads). Let’s look at some code to quickly set up rewarded video ads on your application.

+

[Function Mappings]

+

Even though not all old functions map perfectly into the new API the following list should get you started with some of the changes (check the section below for more details):

+
    +
  • AdMob_RewardedVideo_Init(...) initializes the interstitial ads with a unique id.
  • +
  • AdMob_RewardedVideo_Load() replaces GoogleMobileAds_LoadRewardedVideo()
  • +
  • triggers the event “AdMob_RewardedVideo_OnLoaded” if load succeeds
  • +
  • triggers the event “AdMob_RewardedVideo_OnLoadFailed” if load fails
  • +
  • AdMob_RewardedVideo_IsLoaded() replaces GoogleMobileAds_RewardedVideoStatus()
  • +
  • AdMob_RewardedVideo_Show() replaces GoogleMobileAds_ShowRewardedVideo(...)
  • +
  • triggers the event “AdMob_RewardedVideo_OnFullyShown” if show succeeds
  • +
  • triggers the event “AdMob_RewardedVideo_OnShowFailed” if show fails
  • +
  • triggers the event “AdMob_RewardedVideo_OnDismissed” upon dismissing
  • +
  • triggers the event “AdMob_RewardedVideo_OnReward” when reward conditions are met.
  • +
+

[New Version]

+

The first step we should take towards adding rewarded videos is to use a manager object with the following CREATE EVENT (remember that you need to initialize the API first - Initialization)

+
// After API initialization we can proceed to initialize the rewarded video
+// options. This requires an unique ad block id string that can be obtained
+// from the google developer console. (more info: AdMob_RewardedVideo_Init).
+// This function will generate an ASYNC SOCIAL EVENT.
+var rewarded_id = "ca-app-pub-3940256099942544/1033173712"
+AdMob_RewardedVideo_Init(rewarded_id);
+

The second step requires us to make sure the API was initialized. For this example we will use the ASYNC SOCIAL EVENT, to check for the events generated by the AdMob_Initialize function call.

+
// Early exit if there is no 'type' key defined
+if (!ds_map_exists(async_load, "type")) exit;
+
+// All the events triggered by the AdMob extension have a “type” key
+// containing a string that starts with “AdMob_”.
+switch(async_load[? "type"])
+{
+    // AdMob_Initialize() finished initializing the API
+    case "AdMob_OnInitialized":
+
+        // Now that we are sure that the API got initialized we can load
+        // a new rewarded video ad.(more info: AdMob_RewardedVideo_Load).
+        // This function will generate an ASYNC SOCIAL EVENT.
+        AdMob_RewardedVideo_Load();
+        break;
+
+    // AdMob_RewardedVideo_Load() succeeded
+    case "AdMob_RewardedVideo_OnLoaded":
+
+        // At this point we should now have the rewarded ad loaded and
+        // and we can check that using the ´AdMob_RewardedVideo_IsLoaded´
+        // function. We are now ready to show the rewarded video ad to the
+        // user (more info: AdMob_RewardedVideo_Show). This function will
+        // generate an ASYNC SOCIAL EVENT.
+        AdMob_RewardedVideo_Show();
+        break;
+
+    // AdMob_RewardedVideo_Load() failed
+    case "AdMob_RewardedVideo_OnLoadFailed":
+
+        // At this point there was a problem while loading the
+        // interstitial ad. Here we can add some code to deal with it.
+
+        // NOTE: Don’t try to reload the interstitial ad here because
+        // it can lead to an infinite loop.
+        break;
+
+    // AdMob_RewardedVideo_Show() succeeded
+    case "AdMob_RewardedVideo_OnFullyShown":
+
+        // At this point the rewarded video ad is playing and the user is
+        // looking at it. Note that at this point in time your game is
+        // paused and will remain paused until the rewarded video ad gets
+        // dismissed.
+        break;
+
+    // AdMob_RewardedVideo_Show() failed
+    case "AdMob_RewardedVideo_OnShowFailed":
+
+        // At this point the rewarded video ad failed to get shown to the
+        // user. You can add code to deal with the problem here.
+
+        // NOTE: Don’t try to reload/show the rewarded video here
+        // because it can lead to an infinite loop.
+        break;
+
+    // RewardedVideo got dismissed
+    case "AdMob_RewardedVideo_OnDismissed":
+
+        // At this point the rewarded video ad got dismissed by the user
+        // and the game logic is running again.
+        break;
+
+    // RewardedVideo triggered the reward event
+    case "AdMob_RewardedVideo_OnReward":
+
+        // At this point the user watched enough of the rewarded video and
+        // can be rewarded for it. Here we can add the reward code.
+        show_debug_message("You got 1000 points");
+        break;
+
+}
+

Rewarded Interstitial Ads

+

Rewarded interstitial is a type of incentivized ad format that allows you offer rewards for ads that appear automatically during natural app transitions. Unlike rewarded ads, users aren't required to opt-in to view a rewarded interstitial, and similar to interstitial ads they also need to be dismissed in order for the application to continue execution. Rewarded interstitial ads setup is very similar to other previous ads (more info: Banner Ads and Interstitial Ads). Let’s look at some code to quickly set up rewarded interstitial ads on your application.

+

[Function Mappings]

+

Even though not all old functions map perfectly into the new API the following list should get you started with some of the changes (check the section below for more details):

+
    +
  • AdMob_RewardedInterstitial_Init(...) initializes the interstitial ads with a unique id.
  • +
  • AdMob_RewardedInterstitial_Load()
  • +
  • triggers the event “AdMob_RewardedInsterstitial_OnLoaded” if load succeeds
  • +
  • triggers the event “AdMob_RewardedInsterstitial_OnLoadFailed” if load fails
  • +
  • AdMob_RewardedInterstitial_IsLoaded()
  • +
  • AdMob_RewardedInterstitial_Show()
  • +
  • triggers the event “AdMob_RewardedInsterstitial_OnFullyShown” if show succeeds
  • +
  • triggers the event “AdMob_RewardedInsterstitial_OnShowFailed” if show fails
  • +
  • triggers the event “AdMob_RewardedInsterstitial_OnDismissed” upon dismissing
  • +
  • triggers the event “AdMob_RewardedInsterstitial_OnReward” when reward conditions are met.
  • +
+

[Code Sample]

+

The first step we should take towards adding rewarded interstitial is to use a manager object with the following CREATE EVENT (remember that you need to initialize the API first - Initialization)

+
// After API initialization we can proceed to initialize the rewarded
+// interstitial options. This requires an unique ad block id string that can
+// be obtained from the google developer console. (more info:
+// AdMob_RewardedInterstitial_Init).
+// This function will generate an ASYNC SOCIAL EVENT.
+var rewarded_interstitial_id = "ca-app-pub-3940256099942544/5354046379"
+AdMob_RewardedVideo_Init(rewarded_interstitial_id);
+

The second step requires us to make sure the API was initialized. For this example we will use the ASYNC SOCIAL EVENT, to check for the events generated by the AdMob_Initialize function call.

+
// Early exit if there is no 'type' key defined
+if (!ds_map_exists(async_load, "type")) exit;
+
+// All the events triggered by the AdMob extension have a “type” key
+// containing a string that starts with “AdMob_”.
+switch(async_load[? "type"])
+{
+    // AdMob_Initialize() finished initializing the API
+    case "AdMob_OnInitialized":
+
+        // Now that we are sure that the API got initialized we can load
+        // a new rewarded interstitial ad.
+        // (more info: AdMob_RewardedInterstitial_Load).
+        // This function will generate an ASYNC SOCIAL EVENT.
+        AdMob_RewardedInterstitial_Load();
+        break;
+
+    // AdMob_RewardedInterstitial_Load() succeeded
+    case "AdMob_RewardedInterstitial_OnLoaded":
+
+        // At this point we should now have the rewarded ad loaded and
+        // and we can check that using the
+        // ´AdMob_RewardedInterstitial_IsLoaded´ function. We are now
+        // ready to show the rewarded interstitial ad to the user
+        // (more info: AdMob_RewardedInterstitial_Show).
+        // This function will generate an ASYNC SOCIAL EVENT.
+        AdMob_RewardedInterstitial_Show();
+        break;
+
+    // AdMob_RewardedInterstitial_Load() failed
+    case "AdMob_RewardedInterstitial_OnLoadFailed":
+
+        // At this point there was a problem while loading the
+        // interstitial ad. Here we can add some code to deal with it.
+
+        // NOTE: Don’t try to reload the interstitial ad here because
+        // it can lead to an infinite loop.
+        break;
+
+    // AdMob_RewardedInterstitial_Show() succeeded
+    case "AdMob_RewardedInterstitial_OnFullyShown":
+
+        // At this point the rewarded video ad is playing and the user is
+        // looking at it. Note that at this point in time your game is
+        // paused and will remain paused until the rewarded video ad gets
+        // dismissed.
+        break;
+
+    // AdMob_RewardedInterstitial_Show() failed
+    case "AdMob_RewardedInterstitial_OnShowFailed":
+
+        // At this point the rewarded video ad failed to get shown to the
+        // user. You can add code to deal with the problem here.
+
+        // NOTE: Don’t try to reload/show the rewarded video here
+        // because it can lead to an infinite loop.
+        break;
+
+    // RewardedInterstitial got dismissed
+    case "AdMob_RewardedInterstitial_OnDismissed":
+
+        // At this point the rewarded interstitial ad got dismissed by the
+        // user and the game logic is running again.
+        break;
+
+    // RewardedInterstitial triggered the reward event
+    case "AdMob_RewardedInterstitial_OnReward":
+
+        // At this point the user watched enough of the rewarded video and
+        // can be rewarded for it. Here we can add the reward code.
+        show_debug_message("You got 1000 points");
+        break;
+
+}
+ +
+
+ +
+
+ +
+ +
+ +
+ + + + GitHub + + + + « Previous + + + Next » + + +
+ + + + + + + + + + diff --git a/extensions/AdMob/docs/reward_interstitial.html b/extensions/AdMob/docs/reward_interstitial.html new file mode 100644 index 000000000..9664d0913 --- /dev/null +++ b/extensions/AdMob/docs/reward_interstitial.html @@ -0,0 +1,593 @@ + + + + + + + + Rewarded Interstitial - GMEXT-AdMob + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+ +
+
+
+
+ +

+

Rewarded Interstitial

+

Functions

+

This module offers a collection of functions designed to address specific tasks and provide utilities for various purposes. Explore the available functions to make the most of the functionalities provided by this module.

+ +


+
+

Back To Top

+ +

AdMob_RewardedInterstitial_Init

+
+

⛔️ This function was deprecated with version 1.3.0.

+
+

Initializes the target identifier for rewarded interstitial ad functions.

+
+

Note

+

Please refer to AdMob_RewardedInterstitial_Set_AdUnit for more information.

+
+


+

Syntax:

+
+
AdMob_RewardedInterstitial_Init(adUnitId)
+
+ + + + + + + + + + + + + + + +
ArgumentTypeDescription
adUnitIdString
+


+

Returns:

+
+

N/A

+
+


+

Versioning:

+
    +
  • 1.3.0 - ⛔️ This function was deprecated.
  • +
+


+


+
+

Back To Top

+ +

AdMob_RewardedInterstitial_Set_AdUnit

+

Set the target identifier for rewarded interstitial functions, Rewarded interstitial funcitons allow multiple identifiers

+


+

Syntax:

+
+
AdMob_RewardedInterstitial_Set_AdUnit(adUnitId)
+
+ + + + + + + + + + + + + + + +
ArgumentTypeDescription
adUnitIdString
+


+

Returns:

+
+

N/A

+
+


+

Versioning:

+
    +
  • 1.3.0 - This function was introduced.
  • +
+


+


+
+

Back To Top

+ +

AdMob_RewardedInterstitial_Free_Load_Instances

+

Release Rewarded Interstitial load instances (passing -1 will free all the loaded instances).

+


+

Syntax:

+
+
AdMob_RewardedInterstitial_Free_Load_Instances(count)
+
+ + + + + + + + + + + + + + + +
ArgumentTypeDescription
countReal
+


+

Returns:

+
+

N/A

+
+


+

Versioning:

+
    +
  • 1.3.0 - This function was introduced.
  • +
+


+


+
+

Back To Top

+ +

AdMob_RewardedInterstitial_Max_Instances

+

Set the max number of Rewarded Insterstitials load instances, this allow present consecutiva ads. Default value is 1.

+


+

Syntax:

+
+
AdMob_RewardedInterstitial_Max_Instances(count)
+
+ + + + + + + + + + + + + + + +
ArgumentTypeDescription
countReal
+


+

Returns:

+
+

N/A

+
+


+

Versioning:

+
    +
  • 1.3.0 - This function was introduced.
  • +
+


+


+
+

Back To Top

+ +

AdMob_RewardedInterstitial_Load

+

This function should be called when you want to load a rewarded interstitial ad. Calling it will send a request to the ad server to provide a rewarded ad, which will then be loaded into the app for display. This function does not show the ad, just stores it in memory ready for showing. If you do not call this function before trying to show an ad, nothing will be shown. Note that you can check whether a rewarded interstitial is loaded or not using the function AdMob_RewardedInterstitial_IsLoaded.

+

This function operates asynchronously, which means that it does not immediately return the requested result. Instead, upon completion of the task, it will trigger the Social Async Event.

+


+

Syntax:

+
+
AdMob_RewardedInterstitial_Load()
+
+


+

Returns:

+
+

AdMobErrors

+
+


+

Triggers:

+
+

Social Async Event

+
+

This event is triggered is the awaited task fails.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeString"AdMob_RewardedInterstitial_OnLoadFailed"
unit_idStringUnit identifier of the advertisment
errorMessageStringthe error code responsible for the failure
errorCodeRealthe error message of the error code
+


+

This event is triggered is the awaited task succeeds.

+ + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeString"AdMob_RewardedInterstitial_OnLoaded"
unit_idStringUnit identifier of the advertisment
+


+


+
+

Back To Top

+ +

AdMob_RewardedInterstitial_Show

+

This function will show the rewarded video ad, if one is available and loaded. You can check whether an ad has previously been loaded using the function AdMob_RewardedInterstitial_IsLoaded. Note that while a rewarded interstitial ad is being shown, your app will be put into the background and will effectively be “paused”.

+

This function operates asynchronously, which means that it does not immediately return the requested result. Instead, upon completion of the task, it will trigger the Social Async Event.

+


+

Syntax:

+
+
AdMob_RewardedInterstitial_Show()
+
+


+

Returns:

+
+

AdMobErrors

+
+


+

Triggers:

+
+

Social Async Event

+
+

This event is triggered when the ad view is closed by the user.

+ + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeString"AdMob_RewardedInterstitial_OnDismissed"
unit_idStringUnit identifier of the advertisment
+


+

This event is triggered is the awaited task fails.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeString"AdMob_RewardedInterstitial_OnShowFailed"
unit_idStringUnit identifier of the advertisment
errorMessageStringthe error code responsible for the failure
errorCodeRealthe error message of the error code
+


+

This event is triggered is the awaited task succeeds.

+ + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeString"AdMob_RewardedInterstitial_OnFullyShown"
unit_idStringUnit identifier of the advertisment
+


+

This event is triggered if the user should be rewarded.

+ + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeString"AdMob_RewardedInterstitial_OnReward"
unit_idStringUnit identifier of the advertisment
+


+


+
+

Back To Top

+ +

AdMob_RewardedInterstitial_IsLoaded

+

This function will return whether the rewarded interstitial ad has been loaded or not.

+


+

Syntax:

+
+
AdMob_RewardedInterstitial_IsLoaded()
+
+


+

Returns:

+
+

Boolean

+
+


+


+
+

Back To Top

+ +

AdMob_RewardedInterstitial_Instances_Count

+

Return the number of Rewarded Interstitial load instances are ready.

+


+

Syntax:

+
+
AdMob_RewardedInterstitial_Instances_Count()
+
+


+

Returns:

+
+

Real

+
+


+

Versioning:

+
    +
  • 1.3.0 - This function was introduced.
  • +
+


+


+ +
+
+ +
+
+ +
+ +
+ +
+ + + + GitHub + + + + « Previous + + + Next » + + +
+ + + + + + + + + + diff --git a/extensions/AdMob/docs/reward_video.html b/extensions/AdMob/docs/reward_video.html new file mode 100644 index 000000000..a907b7b82 --- /dev/null +++ b/extensions/AdMob/docs/reward_video.html @@ -0,0 +1,593 @@ + + + + + + + + Rewarded Video - GMEXT-AdMob + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+ +
+
+
+
+ +

+

Rewarded Video

+

Functions

+

This module offers a collection of functions designed to address specific tasks and provide utilities for various purposes. Explore the available functions to make the most of the functionalities provided by this module.

+ +


+
+

Back To Top

+ +

AdMob_RewardedVideo_Init

+
+

⛔️ This function was deprecated with version 1.3.0.

+
+

Initializes the target identifier for rewarded video ad functions.

+
+

Note

+

Please refer to AdMob_RewardedVideo_Set_AdUnit for more information.

+
+


+

Syntax:

+
+
AdMob_RewardedVideo_Init(adUnitId)
+
+ + + + + + + + + + + + + + + +
ArgumentTypeDescription
adUnitIdString
+


+

Returns:

+
+

N/A

+
+


+

Versioning:

+
    +
  • 1.3.0 - ⛔️ This function was deprecated.
  • +
+


+


+
+

Back To Top

+ +

AdMob_RewardedVideo_Set_AdUnit

+

Set the target identifier for rewarded video functions, Rewarded video funcitons allow multiple identifiers

+


+

Syntax:

+
+
AdMob_RewardedVideo_Set_AdUnit(adUnitId)
+
+ + + + + + + + + + + + + + + +
ArgumentTypeDescription
adUnitIdString
+


+

Returns:

+
+

N/A

+
+


+

Versioning:

+
    +
  • 1.3.0 - This function was introduced.
  • +
+


+


+
+

Back To Top

+ +

AdMob_RewardedVideo_Free_Load_Instances

+

Release Rewarded Video load instances (passing -1 will free all the loaded instances).

+


+

Syntax:

+
+
AdMob_RewardedVideo_Free_Load_Instances(count)
+
+ + + + + + + + + + + + + + + +
ArgumentTypeDescription
countReal
+


+

Returns:

+
+

N/A

+
+


+

Versioning:

+
    +
  • 1.3.0 - This function was introduced.
  • +
+


+


+
+

Back To Top

+ +

AdMob_RewardedVideo_Max_Instances

+

Set the max number of Rewarded Video load instances, this allow present consecutiva ads. Default value is 1.

+


+

Syntax:

+
+
AdMob_RewardedVideo_Max_Instances(count)
+
+ + + + + + + + + + + + + + + +
ArgumentTypeDescription
countReal
+


+

Returns:

+
+

N/A

+
+


+

Versioning:

+
    +
  • 1.3.0 - This function was introduced.
  • +
+


+


+
+

Back To Top

+ +

AdMob_RewardedVideo_Load

+

This function should be called when you want to load a rewarded video ad. Calling it will send a request to the ad server to provide a rewarded ad, which will then be loaded into the app for display. This function does not show the ad, just stores it in memory ready for showing. If you do not call this function before trying to show an ad, nothing will be shown. Note that you can check whether a rewarded video is loaded or not using the function AdMob_RewardedVideo_IsLoaded.

+

This function operates asynchronously, which means that it does not immediately return the requested result. Instead, upon completion of the task, it will trigger the Social Async Event.

+


+

Syntax:

+
+
AdMob_RewardedVideo_Load()
+
+


+

Returns:

+
+

AdMobErrors

+
+


+

Triggers:

+
+

Social Async Event

+
+

This event is triggered is the awaited task fails.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeString"AdMob_RewardedVideo_OnLoadFailed"
unit_idStringUnit identifier of the advertisment
errorMessageStringthe error code responsible for the failure
errorCodeRealthe error message of the error code
+


+

This event is triggered is the awaited task succeeds.

+ + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeString"AdMob_RewardedVideo_OnLoaded"
unit_idStringUnit identifier of the advertisment
+


+


+
+

Back To Top

+ +

AdMob_RewardedVideo_Show

+

This function will show the rewarded video ad, if one is available and loaded. You can check whether an ad has previously been loaded using the function AdMob_RewardedVideo_IsLoaded. Note that while a rewarded video ad is being shown, your app will be put into the background and will effectively be “paused”.

+

This function operates asynchronously, which means that it does not immediately return the requested result. Instead, upon completion of the task, it will trigger the Social Async Event.

+


+

Syntax:

+
+
AdMob_RewardedVideo_Show()
+
+


+

Returns:

+
+

AdMobErrors

+
+


+

Triggers:

+
+

Social Async Event

+
+

This event is triggered when the ad view is closed by the user.

+ + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeString"AdMob_RewardedVideo_OnDismissed"
unit_idStringUnit identifier of the advertisment
+


+

This event is triggered is the awaited task fails.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeString"AdMob_RewardedVideo_OnShowFailed"
unit_idStringUnit identifier of the advertisment
errorMessageStringthe error code responsible for the failure
errorCodeRealthe error message of the error code
+


+

This event is triggered is the awaited task succeeds.

+ + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeString"AdMob_RewardedVideo_OnFullyShown"
unit_idStringUnit identifier of the advertisment
+


+

This event is triggered if the user should be rewarded.

+ + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeString"AdMob_RewardedVideo_OnReward"
unit_idStringUnit identifier of the advertisment
+


+


+
+

Back To Top

+ +

AdMob_RewardedVideo_IsLoaded

+

This function will return whether the rewarded video ad has been loaded or not.

+


+

Syntax:

+
+
AdMob_RewardedVideo_IsLoaded()
+
+


+

Returns:

+
+

Boolean

+
+


+


+
+

Back To Top

+ +

AdMob_RewardedVideo_Instances_Count

+

Return the number of Rewarded video load instances are ready.

+


+

Syntax:

+
+
AdMob_RewardedVideo_Instances_Count()
+
+


+

Returns:

+
+

Real

+
+


+

Versioning:

+
    +
  • 1.3.0 - This function was introduced.
  • +
+


+


+ +
+
+ +
+
+ +
+ +
+ +
+ + + + GitHub + + + + « Previous + + + Next » + + +
+ + + + + + + + + + diff --git a/extensions/AdMob/docs/settings.html b/extensions/AdMob/docs/settings.html new file mode 100644 index 000000000..5eadbcf11 --- /dev/null +++ b/extensions/AdMob/docs/settings.html @@ -0,0 +1,253 @@ + + + + + + + + Settings - GMEXT-AdMob + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+ +
+
+
+
+ +

+

Settings

+

Functions

+

This module offers a collection of functions designed to address specific tasks and provide utilities for various purposes. Explore the available functions to make the most of the functionalities provided by this module.

+ +


+
+

Back To Top

+ +

AdMob_Settings_SetVolume

+

This method provides control over the sound’s loudness when playing rewarded video ads. This method will trigger a reload of the current Interstitial and RewardedVideo ads.

+


+

Syntax:

+
+
AdMob_Settings_SetVolume(value)
+
+ + + + + + + + + + + + + + + +
ArgumentTypeDescription
valueRealThe amount to set the volume to.
+


+

Returns:

+
+

N/A

+
+


+


+
+

Back To Top

+ +

AdMob_Settings_SetMuted

+

This method provides control over muting the sound when playing rewarded video ads. This method will trigger a reload of the current Interstitial and RewardedVideo ads.

+


+

Syntax:

+
+
AdMob_Settings_SetMuted(value)
+
+ + + + + + + + + + + + + + + +
ArgumentTypeDescription
valueReal
+


+

Returns:

+
+

N/A

+
+


+


+ +
+
+ +
+
+ +
+ +
+ +
+ + + + GitHub + + + + « Previous + + + Next » + + +
+ + + + + + + + + + diff --git a/extensions/AdMob/docs/setup.html b/extensions/AdMob/docs/setup.html new file mode 100644 index 000000000..582276da3 --- /dev/null +++ b/extensions/AdMob/docs/setup.html @@ -0,0 +1,191 @@ + + + + + + + + Setup - GMEXT-AdMob + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+ +
+
+
+
+ +

Setup [NEW]

+

The AdMob extension is to be used alongside your Google AdMob account (web page). All the required personal ad ids and consent messages should be handled through there.

+


+
+

Warning

+

To build and deploy to iOS it’s required for the developer to install CocoaPods. (installation guide)

+
+


+
    +
  1. For GDPR consent you should look to follow the options below:\ +AdMob ConsolePrivacy and MessagingGo to funding choices(select your project)Create (new message)EU Consent → fill all the necessary details.
  2. +
  3. For setting up the AdMob extension you should use the new extension options accessible from double clicking the extension on the IDE. Here you are presented with options to configure both the Android and the iOS exports. +Android iOS Config Options! +Just replace the Application ID with your Google Application ID and use your personal Ad UnitIDs (for Banners, Interstitial, Rewarded and Rewarded Interstitial)
  4. +
+ +
+
+ +
+
+ +
+ +
+ +
+ + + + GitHub + + + + « Previous + + + Next » + + +
+ + + + + + + + + + diff --git a/extensions/AdMob/docs/sitemap.xml b/extensions/AdMob/docs/sitemap.xml new file mode 100644 index 000000000..0f8724efd --- /dev/null +++ b/extensions/AdMob/docs/sitemap.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/extensions/AdMob/docs/sitemap.xml.gz b/extensions/AdMob/docs/sitemap.xml.gz new file mode 100644 index 000000000..1088eba9a Binary files /dev/null and b/extensions/AdMob/docs/sitemap.xml.gz differ diff --git a/extensions/AdMob/docs/targeting.html b/extensions/AdMob/docs/targeting.html new file mode 100644 index 000000000..952a45972 --- /dev/null +++ b/extensions/AdMob/docs/targeting.html @@ -0,0 +1,299 @@ + + + + + + + + Targeting - GMEXT-AdMob + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+ +
+
+
+
+ +

+

Targeting

+

Functions

+

This module offers a collection of functions designed to address specific tasks and provide utilities for various purposes. Explore the available functions to make the most of the functionalities provided by this module.

+ +


+
+

Back To Top

+ +

AdMob_Targeting_COPPA

+

Toggles on/off ads for children. This function should be called BEFORE calling AdMob_Initialize.

+
+

Warning

+

Should be called before AdMob_Initialize.

+
+


+

Syntax:

+
+
AdMob_Targeting_COPPA(COPPA)
+
+ + + + + + + + + + + + + + + +
ArgumentTypeDescription
COPPABoolean
+


+

Returns:

+
+

N/A

+
+


+


+
+

Back To Top

+ +

AdMob_Targeting_UnderAge

+

Toggles on/off ads for under aged users. This function should be called BEFORE calling AdMob_Initialize.

+
+

Warning

+

Should be called before AdMob_Initialize.

+
+


+

Syntax:

+
+
AdMob_Targeting_UnderAge(underAge)
+
+ + + + + + + + + + + + + + + +
ArgumentTypeDescription
underAgeBoolean
+


+

Returns:

+
+

N/A

+
+


+


+
+

Back To Top

+ +

AdMob_Targeting_MaxAdContentRating

+

Allows for setting the maximum content rating of the ads to be displayed. This function should be called BEFORE calling AdMob_Initialize.

+
+

Warning

+

Should be called before AdMob_Initialize.

+
+


+

Syntax:

+
+
AdMob_Targeting_MaxAdContentRating(contentRating)
+
+ + + + + + + + + + + + + + + +
ArgumentTypeDescription
contentRatingAdMobContentRating
+


+

Returns:

+
+

N/A

+
+


+


+ +
+
+ +
+
+ +
+ +
+ +
+ + + + GitHub + + + + « Previous + + + Next » + + +
+ + + + + + + + + + diff --git a/extensions/AdMob/docs/workflow.html b/extensions/AdMob/docs/workflow.html new file mode 100644 index 000000000..4c1b15cde --- /dev/null +++ b/extensions/AdMob/docs/workflow.html @@ -0,0 +1,203 @@ + + + + + + + + Workflow - GMEXT-AdMob + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+ +
+
+
+
+ +

Workflow

+

This is the recommended workflow for using AdMob extension functions calls both on Android and iOS.

+

iOS

+
    +
  • Import AppTrackingTransparency extension from marketplace. This is required for personalized ads.
  • +
  • Request app tracking on an initialization room before initializing AdMob.
  • +
+

Android & iOS

+ + +
+
+ +
+
+ +
+ +
+ +
+ + + + GitHub + + + + « Previous + + + Next » + + +
+ + + + + + + + + + diff --git a/extensions/AdMob/iOSSource/GoogleMobileAdsGM.h b/extensions/AdMob/iOSSource/GoogleMobileAdsGM.h index 2f3f151c0..910da6cf4 100644 --- a/extensions/AdMob/iOSSource/GoogleMobileAdsGM.h +++ b/extensions/AdMob/iOSSource/GoogleMobileAdsGM.h @@ -6,32 +6,44 @@ #import #import -@interface GoogleMobileAdsGM:NSObject -{ - NSMutableDictionary *ListenerMap; - Boolean testingAds; - Boolean NPA; -} +@class ThreadSafeQueue; +@interface GoogleMobileAdsGM : NSObject + +@property(nonatomic, assign) Boolean isInitialized; +@property(nonatomic, assign) Boolean isTestDevice; +@property(nonatomic, assign) Boolean nonPersonalizedAds; + +@property(nonatomic, strong) NSString *interstitialAdUnitId; +@property(nonatomic, assign) int interstitialMaxLoadedInstances; +@property(nonatomic, strong) ThreadSafeQueue *loadedInterstitialQueue; +@property(nonatomic, strong) GADInterstitialAd *interstitialKeepMe; + +@property(nonatomic, strong) NSString *rewardedVideoUnitId; +@property(nonatomic, assign) int rewardedVideoMaxLoadedInstances; +@property(nonatomic, strong) ThreadSafeQueue *loadedRewardedVideoQueue; +@property(nonatomic, strong) GADRewardedAd *rewardVideoAdKeepMe; + +@property(nonatomic, strong) NSString *rewardedInterstitialAdUnitId; +@property(nonatomic, assign) int rewardedInterstitialMaxLoadedInstances; +@property(nonatomic, strong) ThreadSafeQueue *loadedRewardedInterstitialQueue; +@property(nonatomic, strong) GADRewardedInterstitialAd *rewardedInterstitialAdKeepMe; + +@property(nonatomic, assign) bool triggerOnPaidEvent; + +@property(nonatomic, strong) NSString *bannerAdUnitId; @property(nonatomic, strong) GADBannerView *bannerView; -@property(nonatomic, strong) GADInterstitialAd*interstitial; -@property(nonatomic, strong) GADInterstitialAd*interstitial_keepMe; -@property(nonatomic, strong) NSString *BannerAdID; -@property(nonatomic, strong) NSString *rewardAdID; -@property(nonatomic, strong) NSString *interstitialAdID; -@property(nonatomic, strong) GADRewardedAd *rewardAd; -@property(nonatomic, strong) GADRewardedAd *rewardAd_keepMe; -@property(nonatomic, strong) NSString *rewardAd_ID; -@property(nonatomic, strong) GADRewardedInterstitialAd *rewardedInterstitialAd; -@property(nonatomic, strong) GADRewardedInterstitialAd *rewardedInterstitialAd_keepMe; -@property(nonatomic, strong) NSString *rewardInterstitialAd_ID; - -@property(nonatomic, strong) UMPConsentForm *myForm; - -@property(nonatomic, strong) GADRequest *request_interstitial; -@property(nonatomic, strong) GADRequest *request_rewarded; +@property(nonatomic, strong) NSString *appOpenAdUnitId; +@property(nonatomic, strong) GADAppOpenAd *appOpenAdInstance; +@property(nonatomic, assign) UIInterfaceOrientation appOpenAdOrientation; +@property(nonatomic, strong) NSDate *appOpenAdLoadTime; +@property(nonatomic, assign) bool isAppOpenAdEnabled; +@property(nonatomic, assign) bool isShowingAd; + +@property(nonatomic, strong) UMPConsentForm *consentForm; + @end diff --git a/extensions/AdMob/iOSSource/GoogleMobileAdsGM.mm b/extensions/AdMob/iOSSource/GoogleMobileAdsGM.mm index e57d12ad5..87a604df0 100644 --- a/extensions/AdMob/iOSSource/GoogleMobileAdsGM.mm +++ b/extensions/AdMob/iOSSource/GoogleMobileAdsGM.mm @@ -1,6 +1,5 @@ #import "GoogleMobileAdsGM.h" -const int EVENT_OTHER_SOCIAL = 70; extern int CreateDsMap( int _num, ... ); extern void CreateAsynEventWithDSMap(int dsmapindex, int event_index); extern UIViewController *g_controller; @@ -22,27 +21,119 @@ extern "C" int dsListGetSize(int _dsList); extern "C" const char* extOptGetString(char* _ext, char* _opt); +extern "C" const char* extGetVersion(char* _ext); extern "C" void createSocialAsyncEventWithDSMap(int dsmapindex); +@interface ThreadSafeQueue : NSObject + +@property (nonatomic, strong) NSMutableArray *array; +@property (strong, nonatomic) id retainedObject; + +- (void)enqueue:(id)object; +- (id)dequeue; +- (void)dequeueMultiple:(int) count; +- (NSUInteger)size; + +@end + +@implementation ThreadSafeQueue + +- (instancetype)init { + self = [super init]; + if (self) { + _array = [[NSMutableArray alloc] init]; + } + return self; +} + +- (void)enqueue:(id)object { + @synchronized(self) { + [_array addObject:object]; + } +} + +- (id)dequeue { + self.retainedObject = nil; + @synchronized(self) { + if ([_array count] > 0) { + self.retainedObject = [_array firstObject]; + [_array removeObjectAtIndex:0]; + } + } + return self.retainedObject; +} + +- (void)dequeueMultiple:(int) count { + @synchronized (_array) { + NSRange range; + if (_array.count < count) { + range = NSMakeRange(0, _array.count); + } else { + range = NSMakeRange(0, count); + } + [_array removeObjectsInRange:range]; + } +} + +- (NSUInteger)size { + NSUInteger count; + @synchronized(self) { + count = [_array count]; + } + return count; +} + +@end + @implementation GoogleMobileAdsGM +const int ADMOB_ERROR_NOT_INITIALIZED = -1; +const int ADMOB_ERROR_INVALID_AD_ID = -2; +const int ADMOB_ERROR_AD_LIMIT_REACHED = -3; +const int ADMOB_ERROR_NO_ADS_LOADED = -4; +const int ADMOB_ERROR_NO_ACTIVE_BANNER_AD = -5; +const int ADMOB_ERROR_ILLEGAL_CALL = -6; + -(id)init { if ( self = [super init] ) { + + self.isInitialized = false; + self.isTestDevice = false; + self.nonPersonalizedAds = false; + + self.bannerAdUnitId = @""; + self.interstitialAdUnitId = @""; + self.rewardedVideoUnitId = @""; + self.rewardedInterstitialAdUnitId = @""; + self.appOpenAdUnitId = @""; + + self.interstitialMaxLoadedInstances = 1; + self.loadedInterstitialQueue = [[ThreadSafeQueue alloc] init]; + + self.rewardedVideoMaxLoadedInstances = 1; + self.loadedRewardedVideoQueue = [[ThreadSafeQueue alloc] init]; + + self.rewardedInterstitialMaxLoadedInstances = 1; + self.loadedRewardedInterstitialQueue = [[ThreadSafeQueue alloc] init]; + + self.triggerOnPaidEvent = false; + + self.isAppOpenAdEnabled = false; + self.appOpenAdOrientation = UIInterfaceOrientationLandscapeRight; - testingAds = false; - NPA = false; - return self; } return NULL; } -/////////////////////////////////////////////////////GoogleMobileAds +#pragma mark - Setup Methods --(void) AdMob_Initialize -{ - if (testingAds) { +-(double) AdMob_Initialize +{ + if (![self validateNotInitializedWithCallingMethod:__FUNCTION__]) return ADMOB_ERROR_ILLEGAL_CALL; + + if (self.isTestDevice) { #if TARGET_OS_SIMULATOR GADMobileAds.sharedInstance.requestConfiguration.testDeviceIdentifiers = @[ GADSimulatorID ]; NSLog(@"Testing on Simulator: %@", GADSimulatorID); @@ -66,74 +157,129 @@ -(void) AdMob_Initialize } // Initialize ad types using extension options (defaults) - self.BannerAdID = [NSString stringWithUTF8String: extOptGetString((char*)"AdMob", (char*)"iOS_BANNER")]; - self.interstitialAdID = [NSString stringWithUTF8String: extOptGetString((char*)"AdMob", (char*)"iOS_INTERSTITIAL")]; - self.rewardAd_ID = [NSString stringWithUTF8String: extOptGetString((char*)"AdMob", (char*)"iOS_REWARDED")]; - self.rewardInterstitialAd_ID = [NSString stringWithUTF8String: extOptGetString((char*)"AdMob", (char*)"iOS_REWARDED_INTERSTITIAL")]; + const char* temp; + temp = extOptGetString((char*)"AdMob", (char*)"iOS_BANNER"); + if (temp && strlen(temp) > 0) { + self.bannerAdUnitId = [NSString stringWithUTF8String: temp]; + } + + temp = extOptGetString((char*)"AdMob", (char*)"iOS_INTERSTITIAL"); + if (temp && strlen(temp) > 0) { + self.interstitialAdUnitId = [NSString stringWithUTF8String: temp]; + } + + temp = extOptGetString((char*)"AdMob", (char*)"iOS_REWARDED"); + if (temp && strlen(temp) > 0) { + self.rewardedVideoUnitId = [NSString stringWithUTF8String: temp]; + } + + temp = extOptGetString((char*)"AdMob", (char*)"iOS_REWARDED_INTERSTITIAL"); + if (temp && strlen(temp) > 0) { + self.rewardedInterstitialAdUnitId = [NSString stringWithUTF8String: temp]; + } + + temp = extOptGetString((char*)"AdMob", (char*)"iOS_OPENAPPAD"); + if (temp && strlen(temp) > 0) { + self.appOpenAdUnitId = [NSString stringWithUTF8String: temp]; + } int dsMapIndex = dsMapCreate(); dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_OnInitialized"); createSocialAsyncEventWithDSMap(dsMapIndex); + self.isInitialized = true; }]; + + return 0; } - --(void) AdMob_SetTestDeviceId +-(double) AdMob_SetTestDeviceId { - testingAds = true; -} - -- (void)adViewDidReceiveAd:(GADBannerView *)adView { - NSLog(@"adViewDidReceiveAd"); + if (![self validateNotInitializedWithCallingMethod:__FUNCTION__]) return ADMOB_ERROR_ILLEGAL_CALL; - int dsMapIndex = dsMapCreate(); - dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_Banner_OnLoaded"); - createSocialAsyncEventWithDSMap(dsMapIndex); + self.isTestDevice = true; + return 0; } -- (void)adView:(GADBannerView *)adView didFailToReceiveAdWithError:(NSError *)error { - NSLog(@"adView:didFailToReceiveAdWithError: %@", [error localizedDescription]); - - int dsMapIndex = dsMapCreate(); - dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_Banner_OnLoadFailed"); - createSocialAsyncEventWithDSMap(dsMapIndex); +-(void) AdMob_Events_OnPaidEvent:(double) enable +{ + self.triggerOnPaidEvent = enable >= 0.5; } -- (void)adViewWillPresentScreen:(GADBannerView *)adView { - NSLog(@"adViewWillPresentScreen"); -} +-(void)onPaidEventHandler:(GADAdValue*) value adUnitId:(const NSString*)adUnitId adType:(NSString*)adType loadedAdNetworkResponseInfo:(GADAdNetworkResponseInfo*)loadedAdNetworkResponseInfo mediationAdapterClassName:(NSString*)mediationAdapterClassName +{ + int dsMapIndex = dsMapCreate(); + dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_OnPaidEvent"); + + dsMapAddString(dsMapIndex, (char*)"mediation_adapter_class_name", (char*)[mediationAdapterClassName UTF8String]); + + dsMapAddString(dsMapIndex, (char*)"unit_id", (char*)[adUnitId UTF8String]); + dsMapAddString(dsMapIndex, (char*)"ad_type", (char*)[adType UTF8String]); + + dsMapAddDouble(dsMapIndex, (char*)"micros", value.value.doubleValue); + dsMapAddString(dsMapIndex, (char*)"currency_code", (char*)[value.currencyCode UTF8String]); + dsMapAddDouble(dsMapIndex, (char*)"precision", (double)value.precision); + + dsMapAddString(dsMapIndex, (char*)"ad_source_name", (char*)[loadedAdNetworkResponseInfo.adSourceName UTF8String]); + dsMapAddString(dsMapIndex, (char*)"ad_source_id", (char*)[loadedAdNetworkResponseInfo.adSourceID UTF8String]); + dsMapAddString(dsMapIndex, (char*)"ad_source_instance_name", (char*)[loadedAdNetworkResponseInfo.adSourceInstanceName UTF8String]); + dsMapAddString(dsMapIndex, (char*)"ad_source_instance_id", (char*)[loadedAdNetworkResponseInfo.adSourceInstanceID UTF8String]); + + createSocialAsyncEventWithDSMap(dsMapIndex); +}; -- (void)adViewWillDismissScreen:(GADBannerView *)adView { - NSLog(@"adViewWillDismissScreen"); +-(void) AdMob_NonPersonalizedAds_Set:(double) value +{ + self.nonPersonalizedAds = value >= 0.5; } -- (void)adViewDidDismissScreen:(GADBannerView *)adView { - NSLog(@"adViewDidDismissScreen"); +#pragma mark - Delegate Methods + +-(void)bannerView:(nonnull GADBannerView *)bannerView didFailToReceiveAdWithError:(nonnull NSError *)error +{ + int dsMapIndex = dsMapCreate(); + dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_Banner_OnLoadFailed"); + dsMapAddDouble(dsMapIndex, (char*)"errorCode", error.code); + dsMapAddString(dsMapIndex, (char*)"errorMessage", (char*)[error.localizedDescription UTF8String]); + createSocialAsyncEventWithDSMap(dsMapIndex); } -- (void)adViewWillLeaveApplication:(GADBannerView *)adView { - NSLog(@"adViewWillLeaveApplication"); +-(void)bannerViewDidReceiveAd:(nonnull GADBannerView *)bannerView +{ + int dsMapIndex = dsMapCreate(); + dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_Banner_OnLoaded"); + dsMapAddString(dsMapIndex, (char*)"unit_id", (char*)[bannerView.adUnitID UTF8String]); + createSocialAsyncEventWithDSMap(dsMapIndex); } -/// Tells the delegate that the ad failed to present full screen content. -- (void)ad:(nonnull id)ad didFailToPresentFullScreenContentWithError:(nonnull NSError *)error +-(void)ad:(nonnull id)presentingAd didFailToPresentFullScreenContentWithError:(nonnull NSError *)error { - NSLog(@"Ad did fail to present full screen content."); + self.isShowingAd = false; + int dsMapIndex = dsMapCreate(); + if ([presentingAd isMemberOfClass:[GADInterstitialAd class]]) + { + dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_Interstitial_OnShowFailed"); + dsMapAddString(dsMapIndex, (char*)"unit_id", (char*)[((GADInterstitialAd*)presentingAd).adUnitID UTF8String]); - if ([ad isMemberOfClass:[GADInterstitialAd class]]) + } + else if ([presentingAd isMemberOfClass:[GADRewardedAd class]]) { - dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_Interstitial_OnShowFailed"); + dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_RewardedVideo_OnShowFailed"); + dsMapAddString(dsMapIndex, (char*)"unit_id", (char*)[((GADRewardedAd*)presentingAd).adUnitID UTF8String]); + } - else if ([ad isMemberOfClass:[GADRewardedAd class]]) + else if ([presentingAd isMemberOfClass:[GADRewardedInterstitialAd class]]) { - dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_RewardedVideo_OnShowFailed"); + dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_RewardedInterstitial_OnShowFailed"); + dsMapAddString(dsMapIndex, (char*)"unit_id", (char*)[((GADRewardedInterstitialAd*)presentingAd).adUnitID UTF8String]); + } - - else if ([ad isMemberOfClass:[GADRewardedInterstitialAd class]]) + else if([presentingAd isMemberOfClass:[GADAppOpenAd class]]) { - dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_RewardedInterstitial_OnShowFailed"); + dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_AppOpen_OnShowFailed"); + dsMapAddString(dsMapIndex, (char*)"unit_id", (char*)[self.appOpenAdUnitId UTF8String]); + [self loadAppOpenAd]; } dsMapAddDouble(dsMapIndex, (char*)"errorCode", error.code); @@ -141,454 +287,734 @@ - (void)ad:(nonnull id)ad didFailToPresentFullScreenC createSocialAsyncEventWithDSMap(dsMapIndex); } -/// Tells the delegate that the ad presented full screen content. -- (void)adDidPresentFullScreenContent:(nonnull id)ad +-(void)adDidPresentFullScreenContent:(nonnull id)presentingAd { - NSLog(@"Ad did present full screen content."); - if([ad isMemberOfClass:[GADInterstitialAd class]]) + if([presentingAd isMemberOfClass:[GADInterstitialAd class]]) { - int dsMapIndex = dsMapCreate(); - dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_Interstitial_OnFullyShown"); - createSocialAsyncEventWithDSMap(dsMapIndex); + int dsMapIndex = dsMapCreate(); + dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_Interstitial_OnFullyShown"); + dsMapAddString(dsMapIndex, (char*)"unit_id", (char*)[((GADInterstitialAd*)presentingAd).adUnitID UTF8String]); + createSocialAsyncEventWithDSMap(dsMapIndex); } - - if([ad isMemberOfClass:[GADRewardedAd class]]) + else if([presentingAd isMemberOfClass:[GADRewardedAd class]]) { - int dsMapIndex = dsMapCreate(); - dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_RewardedVideo_OnFullyShown"); - createSocialAsyncEventWithDSMap(dsMapIndex); + int dsMapIndex = dsMapCreate(); + dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_RewardedVideo_OnFullyShown"); + dsMapAddString(dsMapIndex, (char*)"unit_id", (char*)[((GADRewardedAd*)presentingAd).adUnitID UTF8String]); + createSocialAsyncEventWithDSMap(dsMapIndex); } - - if([ad isMemberOfClass:[GADRewardedInterstitialAd class]]) + else if([presentingAd isMemberOfClass:[GADRewardedInterstitialAd class]]) { - int dsMapIndex = dsMapCreate(); - dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_RewardedInterstitial_OnFullyShown"); - createSocialAsyncEventWithDSMap(dsMapIndex); + int dsMapIndex = dsMapCreate(); + dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_RewardedInterstitial_OnFullyShown"); + dsMapAddString(dsMapIndex, (char*)"unit_id", (char*)[((GADRewardedInterstitialAd*)presentingAd).adUnitID UTF8String]); + createSocialAsyncEventWithDSMap(dsMapIndex); + } + else if([presentingAd isMemberOfClass:[GADAppOpenAd class]]) + { + int dsMapIndex = dsMapCreate(); + dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_AppOpen_OnFullyShown"); + dsMapAddString(dsMapIndex, (char*)"unit_id", (char*)[self.appOpenAdUnitId UTF8String]); + createSocialAsyncEventWithDSMap(dsMapIndex); + + [self loadAppOpenAd]; } } -/// Tells the delegate that the ad dismissed full screen content. -- (void)adDidDismissFullScreenContent:(nonnull id)ad +-(void)adDidDismissFullScreenContent:(nonnull id)presentingAd { - NSLog(@"Ad did dismiss full screen content."); - if([ad isMemberOfClass:[GADInterstitialAd class]]) + self.isShowingAd = false; + + if([presentingAd isMemberOfClass:[GADInterstitialAd class]]) { - int dsMapIndex = dsMapCreate(); - dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_Interstitial_OnDismissed"); - createSocialAsyncEventWithDSMap(dsMapIndex); + int dsMapIndex = dsMapCreate(); + dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_Interstitial_OnDismissed"); + dsMapAddString(dsMapIndex, (char*)"unit_id", (char*)[((GADInterstitialAd*)presentingAd).adUnitID UTF8String]); + createSocialAsyncEventWithDSMap(dsMapIndex); } - - if([ad isMemberOfClass:[GADRewardedAd class]]) + else if([presentingAd isMemberOfClass:[GADRewardedAd class]]) { - int dsMapIndex = dsMapCreate(); - dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_RewardedVideo_OnDismissed"); - createSocialAsyncEventWithDSMap(dsMapIndex); + int dsMapIndex = dsMapCreate(); + dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_RewardedVideo_OnDismissed"); + dsMapAddString(dsMapIndex, (char*)"unit_id", (char*)[((GADRewardedAd*)presentingAd).adUnitID UTF8String]); + createSocialAsyncEventWithDSMap(dsMapIndex); } - - if([ad isMemberOfClass:[GADRewardedInterstitialAd class]]) + else if([presentingAd isMemberOfClass:[GADRewardedInterstitialAd class]]) + { + int dsMapIndex = dsMapCreate(); + dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_RewardedInterstitial_OnDismissed"); + dsMapAddString(dsMapIndex, (char*)"unit_id", (char*)[((GADRewardedInterstitialAd*)presentingAd).adUnitID UTF8String]); + createSocialAsyncEventWithDSMap(dsMapIndex); + } + else if([presentingAd isMemberOfClass:[GADAppOpenAd class]]) { - int dsMapIndex = dsMapCreate(); - dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_RewardedInterstitial_OnDismissed"); - createSocialAsyncEventWithDSMap(dsMapIndex); + int dsMapIndex = dsMapCreate(); + dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_AppOpen_OnDismissed"); + dsMapAddString(dsMapIndex, (char*)"unit_id", (char*)[self.appOpenAdUnitId UTF8String]); + createSocialAsyncEventWithDSMap(dsMapIndex); + + [self loadAppOpenAd]; } + } -///// BANNER ////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - Banner Methods --(void) AdMob_Banner_Init:(NSString*) bannerID +-(void) AdMob_Banner_Set_AdUnit:(NSString*) adUnitId { - self.BannerAdID = bannerID; + self.bannerAdUnitId = adUnitId; } --(void) AdMob_Banner_Create:(double) size bottom: (double)bottom +-(double) AdMob_Banner_Create:(double) size bottom: (double)bottom { + if (![self validateInitializedWithCallingMethod:__FUNCTION__]) return ADMOB_ERROR_NOT_INITIALIZED; + + if (![self validateAdId:self.bannerAdUnitId callingMethod:__FUNCTION__]) return ADMOB_ERROR_INVALID_AD_ID; + if(self.bannerView != nil) { - [self.bannerView removeFromSuperview]; - self.bannerView.delegate = nil; - //[self.bannerView release]; - self.bannerView = nil; + [self deleteBannerAdView]; } - - self.bannerView = [[GADBannerView alloc] - initWithAdSize:GADAdSizeBanner]; + + GADAdSize bannerSize = getBannerSize(size); + self.bannerView = [[GADBannerView alloc] initWithAdSize:bannerSize]; self.bannerView.translatesAutoresizingMaskIntoConstraints = NO; - [g_glView addSubview:self.bannerView]; - - GADAdSize bannerSize; - switch((int)size) - { - case 0: {bannerSize = GADAdSizeBanner; break;} - case 1: {bannerSize = GADAdSizeLargeBanner; break;} - case 2: {bannerSize = GADAdSizeMediumRectangle; break;} - case 3: {bannerSize = GADAdSizeFullBanner; break;} - case 4: {bannerSize = GADAdSizeLeaderboard; break;} - case 5: { - - UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation; - if(orientation == UIInterfaceOrientationPortrait or orientation == 0) - { - NSLog(@"Orientation: isPortail"); - bannerSize = kGADAdSizeSmartBannerPortrait; - } - else - { - NSLog(@"Orientation: isLandscape"); - bannerSize = kGADAdSizeSmartBannerLandscape; - } - break;} - - case 6:{ - NSLog(@"Adaptative"); - CGRect frame = g_controller.view.frame; - if (@available(iOS 11.0, *)) { - frame = UIEdgeInsetsInsetRect(g_controller.view.frame, g_controller.view.safeAreaInsets); - } - CGFloat viewWidth = frame.size.width; - bannerSize = GADCurrentOrientationAnchoredAdaptiveBannerAdSizeWithWidth(viewWidth); - break;} - - default: {NSLog(@"AddBanner illegal banner size type"); break;}//return; - } - - self.bannerView = [[GADBannerView alloc] initWithAdSize:bannerSize]; - self.bannerView.adUnitID = self.BannerAdID; + self.bannerView.adUnitID = self.bannerAdUnitId; self.bannerView.rootViewController = g_controller; self.bannerView.delegate = self; [g_glView addSubview:self.bannerView]; + + if(self.triggerOnPaidEvent) { + self.bannerView.paidEventHandler = ^void(GADAdValue *_Nonnull value) + { + GADAdNetworkResponseInfo *loadedAdNetworkResponseInfo = self.bannerView.responseInfo.loadedAdNetworkResponseInfo; + [self onPaidEventHandler:value adUnitId: self.bannerView.adUnitID adType:@"Banner" loadedAdNetworkResponseInfo:loadedAdNetworkResponseInfo + mediationAdapterClassName:self.bannerView.responseInfo.adNetworkInfoArray[0].adNetworkClassName]; + }; + } [self AdMob_Banner_Move:bottom]; - GADRequest *request = [self AdMob_AdRequest]; - + GADRequest *request = [self buildAdRequest]; [self.bannerView loadRequest:request]; + return 0; } --(void) AdMob_Banner_Move: (double)bottom +- (void)addBannerViewToTopView:(UIView *)bannerView { - int x_ = 1; - int y_; - if(bottom) - y_ = 2; - else - y_ = 0; + bannerView.translatesAutoresizingMaskIntoConstraints = NO; + [g_glView addSubview:bannerView]; + [g_glView addConstraints:@[ + [NSLayoutConstraint constraintWithItem:bannerView + attribute:NSLayoutAttributeTop + relatedBy:NSLayoutRelationEqual + toItem:g_controller.topLayoutGuide + attribute:NSLayoutAttributeBottom + multiplier:1 + constant:0], + [NSLayoutConstraint constraintWithItem:bannerView + attribute:NSLayoutAttributeCenterX + relatedBy:NSLayoutRelationEqual + toItem:g_controller.view + attribute:NSLayoutAttributeCenterX + multiplier:1 + constant:0] + ]]; +} + +-(void)addBannerViewToBottomView:(UIView *)bannerView +{ + bannerView.translatesAutoresizingMaskIntoConstraints = NO; + [g_glView addSubview:bannerView]; + [g_glView addConstraints:@[ + [NSLayoutConstraint constraintWithItem:bannerView + attribute:NSLayoutAttributeBottom + relatedBy:NSLayoutRelationEqual + toItem:g_controller.bottomLayoutGuide + attribute:NSLayoutAttributeTop + multiplier:1 + constant:0], + [NSLayoutConstraint constraintWithItem:bannerView + attribute:NSLayoutAttributeCenterX + relatedBy:NSLayoutRelationEqual + toItem:g_controller.view + attribute:NSLayoutAttributeCenterX + multiplier:1 + constant:0] + ]]; +} + +-(double)AdMob_Banner_Move:(double)bottom +{ + + if (![self validateInitializedWithCallingMethod:__FUNCTION__]) return ADMOB_ERROR_NOT_INITIALIZED; - if(self.bannerView != nil) - { - - CGSize size = CGSizeFromGADAdSize( self.bannerView.adSize ); - int adW = size.width; - int adH = size.height; - - //display -> view coords - int x = -1; - int y = -1; - - switch((int)x_) - { - case 0: - x = 0; - break; - - case 1: - x = (int)(g_glView.bounds.size.width - adW) / 2; - break; - - case 2: - x = (int)(g_glView.bounds.size.width) - adW; - break; - - } - - switch((int)y_) - { - case 0: - y = 0; - break; - - case 1: - y = (int)(g_glView.bounds.size.height - adH) / 2; - break; - - case 2: - y = (int)(1.0 * g_glView.bounds.size.height) - adH; - break; - - } + if (![self validateActiveBannerAdWithCallingMethod:__FUNCTION__]) return ADMOB_ERROR_NO_ACTIVE_BANNER_AD; + + if(self.bannerView != nil) { - CGRect frame = self.bannerView.frame; - frame.origin.x = x; - frame.origin.y = y; - self.bannerView.frame = frame; + [self.bannerView removeFromSuperview]; + if(bottom>0.5) + [self addBannerViewToBottomView:self.bannerView]; + else + [self addBannerViewToTopView:self.bannerView]; + } + + return 0; } -(double) AdMob_Banner_GetWidth -{ - if(self.bannerView == nil) - return 0; - - CGSize size = CGSizeFromGADAdSize(self.bannerView.adSize); - int adW = size.width; - //->display width - int dispW = (int)(( adW * g_DeviceWidth ) / g_glView.bounds.size.width); - return dispW; - +{ + if (!self.bannerView) return 0; + + CGSize size = CGSizeFromGADAdSize(self.bannerView.adSize); + int adW = size.width; + + int dispW = (int)(( adW * g_DeviceWidth ) / g_glView.bounds.size.width); + return dispW; } -(double) AdMob_Banner_GetHeight -{ - if(self.bannerView == nil) - return 0; - - CGSize size = CGSizeFromGADAdSize(self.bannerView.adSize); - int adH = size.height; - //->display height - int dispH = (int)(( adH * g_DeviceHeight ) / g_glView.bounds.size.height); - return dispH; +{ + if (!self.bannerView) return 0; + + CGSize size = CGSizeFromGADAdSize(self.bannerView.adSize); + int adH = size.height; + + int dispH = (int)(( adH * g_DeviceHeight ) / g_glView.bounds.size.height); + return dispH; } --(void) AdMob_Banner_Hide +-(double) AdMob_Banner_Hide { + if (![self validateInitializedWithCallingMethod:__FUNCTION__]) return ADMOB_ERROR_NOT_INITIALIZED; + + if (![self validateActiveBannerAdWithCallingMethod:__FUNCTION__]) return ADMOB_ERROR_NO_ACTIVE_BANNER_AD; + if( self.bannerView != nil ) { self.bannerView.hidden = true; } - + return 0; } --(void) AdMob_Banner_Show +-(double) AdMob_Banner_Show { + if (![self validateInitializedWithCallingMethod:__FUNCTION__]) return ADMOB_ERROR_NOT_INITIALIZED; + + if (![self validateActiveBannerAdWithCallingMethod:__FUNCTION__]) return ADMOB_ERROR_NO_ACTIVE_BANNER_AD; + if( self.bannerView != nil ) { self.bannerView.hidden = false; } + return 0; +} + +-(double) AdMob_Banner_Remove +{ + if (![self validateInitializedWithCallingMethod:__FUNCTION__]) return ADMOB_ERROR_NOT_INITIALIZED; + + if (![self validateActiveBannerAdWithCallingMethod:__FUNCTION__]) return ADMOB_ERROR_NO_ACTIVE_BANNER_AD; + + [self deleteBannerAdView]; + + return 0; +} +-(void) deleteBannerAdView{ + [self.bannerView removeFromSuperview]; + self.bannerView.delegate = nil; + self.bannerView = nil; } --(void) AdMob_Banner_Remove +static GADAdSize getBannerSize(double size) { - if( self.bannerView != nil ) + switch((int)size) { - [self.bannerView removeFromSuperview]; - self.bannerView.delegate = nil; - //[self.bannerView release]; - self.bannerView = nil; + case 0: return GADAdSizeBanner; + case 1: return GADAdSizeLargeBanner; + case 2: return GADAdSizeMediumRectangle; + case 3: return GADAdSizeFullBanner; + case 4: return GADAdSizeLeaderboard; + case 5: + { + UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation; + if(orientation == UIInterfaceOrientationPortrait or orientation == 0) + { + return GADPortraitInlineAdaptiveBannerAdSizeWithWidth(g_controller.view.frame.size.width); + } + else + { + return GADPortraitInlineAdaptiveBannerAdSizeWithWidth(g_controller.view.frame.size.height); + } + break; + } + case 6: + { + CGRect frame = g_controller.view.frame; + if (@available(iOS 11.0, *)) { + frame = UIEdgeInsetsInsetRect(g_controller.view.frame, g_controller.view.safeAreaInsets); + } + CGFloat viewWidth = frame.size.width; + return GADCurrentOrientationAnchoredAdaptiveBannerAdSizeWithWidth(viewWidth); + break; + } + default: {NSLog(@"AddBanner illegal banner size type"); break;} } + + return GADAdSize(); } -///// INTERSTITIAL //////////////////////////////////////////////////////////////////////////////// +#pragma mark - Interstitial Methods --(void) AdMob_Interstitial_Init:(NSString*) interstitialID +-(void) AdMob_Interstitial_Set_AdUnit:(NSString*) adUnitId { - self.interstitialAdID = interstitialID; + self.interstitialAdUnitId = adUnitId; } --(void) AdMob_Interstitial_Load +-(void) Admob_Interstitial_Free_Loaded_Instances:(double) count { - if(self.interstitial != nil) - return; + [self.loadedInterstitialQueue dequeueMultiple:count]; +} + +-(void) Admob_Interstitial_Max_Instances:(double) value +{ + self.interstitialMaxLoadedInstances = value; + + NSUInteger size = [self.loadedInterstitialQueue size]; + if (value >= size) return; + + [self Admob_Interstitial_Free_Loaded_Instances: size - value]; +} + +-(double) AdMob_Interstitial_Load +{ + if (![self validateInitializedWithCallingMethod:__FUNCTION__]) return ADMOB_ERROR_NOT_INITIALIZED; + + if (![self validateAdId:self.interstitialAdUnitId callingMethod:__FUNCTION__]) return ADMOB_ERROR_INVALID_AD_ID; + + if (![self validateLoadedAdsLimit:self.loadedInterstitialQueue maxSize:self.interstitialMaxLoadedInstances callingMethod:__FUNCTION__]) return ADMOB_ERROR_AD_LIMIT_REACHED; + + const NSString* adUnitId = self.interstitialAdUnitId; - self.request_interstitial = [GADRequest request]; - [GADInterstitialAd loadWithAdUnitID: self.interstitialAdID request:self.request_interstitial completionHandler:^(GADInterstitialAd *ad, NSError *error) + GADRequest* request = [self buildAdRequest]; + [GADInterstitialAd loadWithAdUnitID: self.interstitialAdUnitId request: request completionHandler:^(GADInterstitialAd *interstitialAd, NSError *error) { if (error) { - self.interstitial = nil; - - int dsMapIndex = dsMapCreate(); - dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_Interstitial_OnLoadFailed"); - createSocialAsyncEventWithDSMap(dsMapIndex); - + int dsMapIndex = dsMapCreate(); + dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_Interstitial_OnLoadFailed"); + dsMapAddString(dsMapIndex, (char*)"unit_id", (char*)[adUnitId UTF8String]); + dsMapAddString(dsMapIndex, (char*)"errorMessage", (char*)[error.localizedDescription UTF8String]); + dsMapAddDouble(dsMapIndex, (char*)"errorCode", (double)error.code); + createSocialAsyncEventWithDSMap(dsMapIndex); return; } - self.interstitial = ad; - self.interstitial.fullScreenContentDelegate = self; - - int dsMapIndex = dsMapCreate(); - dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_Interstitial_OnLoaded"); - createSocialAsyncEventWithDSMap(dsMapIndex); + if (![self validateLoadedAdsLimit:self.loadedInterstitialQueue maxSize:self.interstitialMaxLoadedInstances callingMethod:__FUNCTION__]) return; + + [self.loadedInterstitialQueue enqueue:interstitialAd]; + + interstitialAd.fullScreenContentDelegate = self; + + if (self.triggerOnPaidEvent) { + const GADInterstitialAd* interstitialRef = interstitialAd; + + interstitialAd.paidEventHandler = ^void(GADAdValue *_Nonnull value) + { + GADAdNetworkResponseInfo *loadedAdNetworkResponseInfo = interstitialRef.responseInfo.loadedAdNetworkResponseInfo; + [self onPaidEventHandler:value adUnitId:interstitialRef.adUnitID adType:@"Interstitial" loadedAdNetworkResponseInfo:loadedAdNetworkResponseInfo mediationAdapterClassName:interstitialRef.responseInfo.adNetworkInfoArray[0].adNetworkClassName]; + }; + } + + int dsMapIndex = dsMapCreate(); + dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_Interstitial_OnLoaded"); + dsMapAddString(dsMapIndex, (char*)"unit_id", (char*)[adUnitId UTF8String]); + createSocialAsyncEventWithDSMap(dsMapIndex); }]; + + return 0; } --(void) AdMob_Interstitial_Show +-(double) AdMob_Interstitial_Show { - if (self.interstitial) - { - [self.interstitial presentFromRootViewController:g_controller]; - self.interstitial_keepMe = self.interstitial; - self.interstitial = nil; - } + if (![self validateInitializedWithCallingMethod:__FUNCTION__]) return ADMOB_ERROR_NOT_INITIALIZED; + + if (![self validateAdLoaded:self.loadedInterstitialQueue callingMethod:__FUNCTION__]) return ADMOB_ERROR_NO_ADS_LOADED; + + self.interstitialKeepMe = [self.loadedInterstitialQueue dequeue]; + + [self.interstitialKeepMe presentFromRootViewController:g_controller]; + + self.isShowingAd = true; + + return 0; } -(double) AdMob_Interstitial_IsLoaded { - if(self.interstitial == nil) - return 0.0; - - if(self.interstitial) - { - return 1; - } - else - return 0; + return [self AdMob_Interstitial_Instances_Count] > 0 ? 1.0 : 0.0; +} + +-(double) AdMob_Interstitial_Instances_Count +{ + return [self.loadedInterstitialQueue size]; } -///// REWARDED VIDEO ////////////////////////////////////////////////////////////////////////////// +#pragma mark - Rewarded Video Methods --(void) AdMob_RewardedVideo_Init:(NSString*) AdId +-(void) AdMob_RewardedVideo_Set_AdUnit:(NSString*) adUnitId { - self.rewardAd_ID = AdId; + self.rewardedVideoUnitId = adUnitId; } --(void) AdMob_RewardedVideo_Load +-(void) AdMob_RewardedVideo_Free_Loaded_Instances:(double) count { - if(self.rewardAd != nil) - return; + [self.loadedRewardedVideoQueue dequeueMultiple: count]; +} + +-(void) AdMob_RewardedVideo_Max_Instances:(double) value +{ + self.rewardedVideoMaxLoadedInstances = value; - self.request_rewarded = [GADRequest request]; - [GADRewardedAd loadWithAdUnitID: self.rewardAd_ID request: self.request_rewarded completionHandler:^(GADRewardedAd *ad, NSError *error) - { - int dsMapIndex = dsMapCreate(); + NSUInteger size = [self.loadedRewardedVideoQueue size]; + if (value >= size) return; + + [self AdMob_RewardedVideo_Free_Loaded_Instances: size - value]; +} +-(double) AdMob_RewardedVideo_Load +{ + if (![self validateInitializedWithCallingMethod:__FUNCTION__]) return ADMOB_ERROR_NOT_INITIALIZED; + + if (![self validateAdId:self.rewardedVideoUnitId callingMethod:__FUNCTION__]) return ADMOB_ERROR_INVALID_AD_ID; + + if (![self validateLoadedAdsLimit:self.loadedRewardedVideoQueue maxSize:self.rewardedVideoMaxLoadedInstances callingMethod:__FUNCTION__]) return ADMOB_ERROR_AD_LIMIT_REACHED; + + const NSString* adUnitId = self.rewardedVideoUnitId; + + GADRequest* request = [self buildAdRequest]; + [GADRewardedAd loadWithAdUnitID: self.rewardedVideoUnitId request: request completionHandler:^(GADRewardedAd *rewardedAd, NSError *error) + { if (error) { - self.rewardAd = nil; - - dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_RewardedVideo_OnLoadFailed"); + int dsMapIndex = dsMapCreate(); + dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_RewardedVideo_OnLoadFailed"); + dsMapAddString(dsMapIndex, (char*)"unit_id", (char*)[adUnitId UTF8String]); dsMapAddDouble(dsMapIndex, (char*)"errorCode", error.code); dsMapAddString(dsMapIndex, (char*)"errorMessage", (char*)[error.localizedDescription UTF8String]); + createSocialAsyncEventWithDSMap(dsMapIndex); + return; } - else - { - self.rewardAd = ad; - self.rewardAd.fullScreenContentDelegate = self; - dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_RewardedVideo_OnLoaded"); - } + if (![self validateLoadedAdsLimit:self.loadedRewardedVideoQueue maxSize:self.rewardedVideoMaxLoadedInstances callingMethod:__FUNCTION__]) return; - createSocialAsyncEventWithDSMap(dsMapIndex); + [self.loadedRewardedVideoQueue enqueue: rewardedAd]; + + rewardedAd.fullScreenContentDelegate = self; + + if(self.triggerOnPaidEvent) { + const GADRewardedAd* rewardedRef = rewardedAd; + + rewardedAd.paidEventHandler = ^void(GADAdValue *_Nonnull value) + { + GADAdNetworkResponseInfo *loadedAdNetworkResponseInfo = rewardedRef.responseInfo.loadedAdNetworkResponseInfo; + [self onPaidEventHandler:value adUnitId:rewardedRef.adUnitID adType:@"Rewarded" loadedAdNetworkResponseInfo:loadedAdNetworkResponseInfo mediationAdapterClassName:rewardedRef.responseInfo.adNetworkInfoArray[0].adNetworkClassName]; + }; + } + + int dsMapIndex = dsMapCreate(); + dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_RewardedVideo_OnLoaded"); + dsMapAddString(dsMapIndex, (char*)"unit_id", (char*)[adUnitId UTF8String]); + createSocialAsyncEventWithDSMap(dsMapIndex); }]; + + return 0; } --(void) AdMob_RewardedVideo_Show +-(double) AdMob_RewardedVideo_Show { - if(self.rewardAd == nil) - return; - - [self.rewardAd presentFromRootViewController:g_controller userDidEarnRewardHandler:^ - { - //NSDecimalNumber *amount = self.rewardAd.adReward.amount; - - int dsMapIndex = dsMapCreate(); - dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_RewardedVideo_OnReward"); - createSocialAsyncEventWithDSMap(dsMapIndex); - - }]; - - self.rewardAd_keepMe = self.rewardAd; - self.rewardAd = nil; + if (![self validateInitializedWithCallingMethod:__FUNCTION__]) return ADMOB_ERROR_NOT_INITIALIZED; + + if (![self validateAdLoaded:self.loadedRewardedVideoQueue callingMethod:__FUNCTION__]) return ADMOB_ERROR_NO_ADS_LOADED; + + self.rewardVideoAdKeepMe = [self.loadedRewardedVideoQueue dequeue]; + + [self.rewardVideoAdKeepMe presentFromRootViewController:g_controller userDidEarnRewardHandler:^ + { + int dsMapIndex = dsMapCreate(); + dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_RewardedVideo_OnReward"); + dsMapAddString(dsMapIndex, (char*)"unit_id", (char*)[self.rewardVideoAdKeepMe.adUnitID UTF8String]); + dsMapAddDouble(dsMapIndex, (char*)"reward_amount", [self.rewardVideoAdKeepMe.adReward.amount doubleValue]); + dsMapAddString(dsMapIndex, (char*)"reward_type", (char*)[self.rewardVideoAdKeepMe.adReward.type UTF8String]); + createSocialAsyncEventWithDSMap(dsMapIndex); + }]; + + self.isShowingAd = true; + + return 0; } -(double) AdMob_RewardedVideo_IsLoaded { - if(self.rewardAd) - return 1.0; - else - return 0.0; + return [self AdMob_RewardedVideo_Instances_Count] > 0 ? 1.0 : 0.0; +} + +-(double) AdMob_RewardedVideo_Instances_Count +{ + return [self.loadedRewardedVideoQueue size]; } -///// REWARDED INTESTITIAL //////////////////////////////////////////////////////////////////////// +#pragma mark - Rewarded Interstitial Methods --(void) AdMob_RewardedInterstitial_Init:(NSString*) AdId +-(void) AdMob_RewardedInterstitial_Set_UnitId:(NSString*) adUnitId { - self.rewardInterstitialAd_ID = AdId; + self.rewardedInterstitialAdUnitId = adUnitId; } --(void) AdMob_RewardedInterstitial_Load +-(void) AdMob_RewardedInterstitial_Free_Loaded_Instances:(double) count { - if(self.rewardedInterstitialAd != nil) - return; - - [GADRewardedInterstitialAd loadWithAdUnitID:self.rewardInterstitialAd_ID request:[GADRequest request] completionHandler:^(GADRewardedInterstitialAd* _Nullable ad, NSError* _Nullable error) - { - int dsMapIndex = dsMapCreate(); + [self.loadedRewardedInterstitialQueue dequeueMultiple: count]; +} + +-(void) AdMob_RewardedInterstitial_Max_Instances:(double) value +{ + self.rewardedInterstitialMaxLoadedInstances = value; + + NSUInteger size = [self.loadedRewardedInterstitialQueue size]; + if (value >= size) return; + + [self AdMob_RewardedInterstitial_Free_Loaded_Instances: size - value]; +} +-(double) AdMob_RewardedInterstitial_Load +{ + if (![self validateInitializedWithCallingMethod:__FUNCTION__]) return ADMOB_ERROR_NOT_INITIALIZED; + + if (![self validateAdId:self.rewardedInterstitialAdUnitId callingMethod:__FUNCTION__]) return ADMOB_ERROR_INVALID_AD_ID; + + if (![self validateLoadedAdsLimit:self.loadedRewardedInterstitialQueue maxSize:self.rewardedInterstitialMaxLoadedInstances callingMethod:__FUNCTION__]) return ADMOB_ERROR_AD_LIMIT_REACHED; + + const NSString* adUnitId = self.rewardedInterstitialAdUnitId; + + GADRequest* request = [self buildAdRequest]; + [GADRewardedInterstitialAd loadWithAdUnitID:self.rewardedInterstitialAdUnitId request:request completionHandler:^(GADRewardedInterstitialAd* _Nullable rewardedInterstitialAd, NSError* _Nullable error) + { if (error) { - self.rewardedInterstitialAd = nil; - - dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_RewardedInterstitial_OnLoadFailed"); + int dsMapIndex = dsMapCreate(); + dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_RewardedInterstitial_OnLoadFailed"); + dsMapAddString(dsMapIndex, (char*)"unit_id", (char*)[adUnitId UTF8String]); dsMapAddDouble(dsMapIndex, (char*)"errorCode", error.code); dsMapAddString(dsMapIndex, (char*)"errorMessage", (char*)[error.localizedDescription UTF8String]); + createSocialAsyncEventWithDSMap(dsMapIndex); + return; } - else - { - self.rewardedInterstitialAd = ad; - self.rewardedInterstitialAd.fullScreenContentDelegate = self; - dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_RewardedInterstitial_OnLoaded"); - } + if (![self validateLoadedAdsLimit:self.loadedRewardedInterstitialQueue maxSize:self.rewardedInterstitialMaxLoadedInstances callingMethod:__FUNCTION__]) return; + + [self.loadedRewardedInterstitialQueue enqueue: rewardedInterstitialAd]; + + rewardedInterstitialAd.fullScreenContentDelegate = self; - createSocialAsyncEventWithDSMap(dsMapIndex); + if(self.triggerOnPaidEvent) { + const GADRewardedInterstitialAd* rewardedInterstitialRef = rewardedInterstitialAd; + + rewardedInterstitialAd.paidEventHandler = ^void(GADAdValue *_Nonnull value) + { + GADAdNetworkResponseInfo *loadedAdNetworkResponseInfo = rewardedInterstitialRef.responseInfo.loadedAdNetworkResponseInfo; + [self onPaidEventHandler:value adUnitId:rewardedInterstitialRef.adUnitID adType:@"RewardedInterstitial" loadedAdNetworkResponseInfo:loadedAdNetworkResponseInfo mediationAdapterClassName:rewardedInterstitialRef.responseInfo.adNetworkInfoArray[0].adNetworkClassName]; + }; + } + + int dsMapIndex = dsMapCreate(); + dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_RewardedInterstitial_OnLoaded"); + dsMapAddString(dsMapIndex, (char*)"unit_id", (char*)[adUnitId UTF8String]); + createSocialAsyncEventWithDSMap(dsMapIndex); }]; + + return 0; } --(void) AdMob_RewardedInterstitial_Show +-(double) AdMob_RewardedInterstitial_Show { - if(self.rewardedInterstitialAd == nil) - return; - - [self.rewardedInterstitialAd presentFromRootViewController:g_controller userDidEarnRewardHandler:^ - { - //GADAdReward *reward = self.rewardedInterstitialAd.adReward; - - int dsMapIndex = dsMapCreate(); - dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_RewardedInterstitial_OnReward"); - createSocialAsyncEventWithDSMap(dsMapIndex); - }]; - - self.rewardedInterstitialAd_keepMe = self.rewardedInterstitialAd; - self.rewardedInterstitialAd = nil; + if (![self validateInitializedWithCallingMethod:__FUNCTION__]) return ADMOB_ERROR_NOT_INITIALIZED; + + if (![self validateAdLoaded:self.loadedRewardedInterstitialQueue callingMethod:__FUNCTION__]) return ADMOB_ERROR_NO_ADS_LOADED; + + self.rewardedInterstitialAdKeepMe = [self.loadedRewardedInterstitialQueue dequeue]; + + [self.rewardedInterstitialAdKeepMe presentFromRootViewController:g_controller userDidEarnRewardHandler:^ + { + int dsMapIndex = dsMapCreate(); + dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_RewardedInterstitial_OnReward"); + dsMapAddString(dsMapIndex, (char*)"unit_id", (char*)[self.rewardedInterstitialAdKeepMe.adUnitID UTF8String]); + dsMapAddDouble(dsMapIndex, (char*)"reward_amount", [self.rewardedInterstitialAdKeepMe.adReward.amount doubleValue]); + dsMapAddString(dsMapIndex, (char*)"reward_type", (char*)[self.rewardedInterstitialAdKeepMe.adReward.type UTF8String]); + createSocialAsyncEventWithDSMap(dsMapIndex); + }]; + + self.isShowingAd = true; + return 0; } -(double) AdMob_RewardedInterstitial_IsLoaded { - if(self.rewardedInterstitialAd) - return 1.0; - else - return 0.0; + return [self AdMob_RewardedInterstitial_Instances_Count] > 0 ? 1.0 : 0.0; +} + +-(double) AdMob_RewardedInterstitial_Instances_Count +{ + return [self.loadedRewardedInterstitialQueue size]; +} + +#pragma mark - App Open Methods + +-(void) AdMob_AppOpenAd_Set_UnitId:(NSString*) adUnitId +{ + self.appOpenAdUnitId = adUnitId; +} + +-(double) AdMob_AppOpenAd_Enable:(double) orientation +{ + if (![self validateInitializedWithCallingMethod:__FUNCTION__]) return ADMOB_ERROR_NOT_INITIALIZED; + + if (![self validateAdId:self.appOpenAdUnitId callingMethod:__FUNCTION__]) return ADMOB_ERROR_INVALID_AD_ID; + + self.isAppOpenAdEnabled = true; + self.appOpenAdInstance = nil; + self.appOpenAdOrientation = (orientation == 0) ? UIInterfaceOrientationLandscapeRight : UIInterfaceOrientationPortrait; + [self loadAppOpenAd]; + + return 0; +} + +-(void) AdMob_AppOpenAd_Disable +{ + self.isAppOpenAdEnabled = false; + self.appOpenAdInstance = nil; +} + +-(double) AdMob_AppOpenAd_IsEnabled +{ + return self.isAppOpenAdEnabled ? 1.0 : 0.0; +} + +-(void) onResume +{ + [self showAppOpenAd]; +} + +-(void) loadAppOpenAd +{ + if (!self.isAppOpenAdEnabled) return; + + if (![self validateInitializedWithCallingMethod:"__AdMob_AppOpenAd_Load"]) return; + + if (![self validateAdId:self.appOpenAdUnitId callingMethod:"__AdMob_AppOpenAd_Load"]) return; + + const NSString* adUnitId = self.appOpenAdUnitId; + + self.appOpenAdInstance = nil; + + GADRequest* request = [self buildAdRequest]; + + [GADAppOpenAd loadWithAdUnitID: self.appOpenAdUnitId request:request /*orientation:self.appOpenAdOrientation*/ completionHandler:^(GADAppOpenAd *_Nullable appOpenAdInstance, NSError *_Nullable error) { + if (error) { + + int dsMapIndex = dsMapCreate(); + dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_AppOpenAd_OnLoadFailed"); + dsMapAddString(dsMapIndex, (char*)"unit_id", (char*)[adUnitId UTF8String]); + dsMapAddDouble(dsMapIndex, (char*)"errorCode", error.code); + dsMapAddString(dsMapIndex, (char*)"errorMessage", (char*)[error.localizedDescription UTF8String]); + createSocialAsyncEventWithDSMap(dsMapIndex); + + return; + } + self.appOpenAdInstance = appOpenAdInstance; + self.appOpenAdInstance.fullScreenContentDelegate = self; + self.appOpenAdLoadTime = [NSDate date]; + + if(self.triggerOnPaidEvent) + self.appOpenAdInstance.paidEventHandler = ^void(GADAdValue *_Nonnull value) + { + GADAdNetworkResponseInfo *loadedAdNetworkResponseInfo = self.appOpenAdInstance.responseInfo.loadedAdNetworkResponseInfo; + [self onPaidEventHandler:value adUnitId:adUnitId adType:@"AppOpen" loadedAdNetworkResponseInfo:loadedAdNetworkResponseInfo mediationAdapterClassName:self.appOpenAdInstance.responseInfo.adNetworkInfoArray[0].adNetworkClassName]; + }; + + int dsMapIndex = dsMapCreate(); + dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_AppOpenAd_OnLoaded"); + dsMapAddString(dsMapIndex, (char*)"unit_id", (char*)[adUnitId UTF8String]); + createSocialAsyncEventWithDSMap(dsMapIndex); + }]; +} + +-(void) showAppOpenAd +{ + if(!self.isAppOpenAdEnabled) + return; + + if(![self appOpenAdIsValid:4 callingMethod:"__AdMob_AppOpenAd_Show"]) { + [self loadAppOpenAd]; + return; + } + + self.appOpenAdInstance.fullScreenContentDelegate = self; + [self.appOpenAdInstance presentFromRootViewController:g_controller]; +} + +-(BOOL)appOpenAdIsValid:(int) expirationTimeInHours callingMethod:(const char *)callingMethod { + if (self.appOpenAdInstance == nil) { + NSLog(@"%s :: There is no app open ad loaded.", callingMethod); + return NO; + } + + NSTimeInterval dateDifference = [[NSDate date] timeIntervalSinceDate: self.appOpenAdLoadTime]; + BOOL expired = dateDifference >= (3600 * expirationTimeInHours); + + if (expired) { + NSLog(@"%s :: The loaded app open ad expired, reloading...", callingMethod); + return NO; + } + + return YES; } -///// TARGETING /////////////////////////////////////////////////////////////////////////////////// +#pragma mark - Targeting Methods //https://developers.google.com/admob/ios/targeting#child-directed_setting --(void) AdMob_Targeting_COPPA:(double) COPPA +-(double) AdMob_Targeting_COPPA:(double) COPPA { - if(COPPA > 0.5) - [GADMobileAds.sharedInstance.requestConfiguration tagForChildDirectedTreatment:YES]; - else - [GADMobileAds.sharedInstance.requestConfiguration tagForChildDirectedTreatment:NO]; + if (![self validateNotInitializedWithCallingMethod:__FUNCTION__]) return ADMOB_ERROR_ILLEGAL_CALL; + + if(COPPA>0.5) + [GADMobileAds.sharedInstance.requestConfiguration tagForChildDirectedTreatment]; + + return 0; } //https://developers.google.com/admob/ios/targeting#users_under_the_age_of_consent --(void) AdMob_Targeting_UnderAge:(double) underAge +-(double) AdMob_Targeting_UnderAge:(double) underAge { - if(underAge > 0.5) - [GADMobileAds.sharedInstance.requestConfiguration tagForUnderAgeOfConsent:YES]; - else - [GADMobileAds.sharedInstance.requestConfiguration tagForUnderAgeOfConsent:NO]; + if (![self validateNotInitializedWithCallingMethod:__FUNCTION__]) return ADMOB_ERROR_ILLEGAL_CALL; + + if(underAge>0.5) + [GADMobileAds.sharedInstance.requestConfiguration tagForUnderAgeOfConsent]; + + return 0; } //https://developers.google.com/admob/ios/targeting#ad_content_filtering -///[GADMobileAds.sharedInstance.requestConfiguration tagForUnderAgeOfConsent:YES]; --(void) AdMob_Targeting_MaxAdContentRating:(double) maxAdContentRating +-(double) AdMob_Targeting_MaxAdContentRating:(double) maxAdContentRating { + if (![self validateNotInitializedWithCallingMethod:__FUNCTION__]) return ADMOB_ERROR_ILLEGAL_CALL; + switch((int) maxAdContentRating) { case 0: @@ -606,29 +1032,11 @@ -(void) AdMob_Targeting_MaxAdContentRating:(double) maxAdContentRating [GADMobileAds.sharedInstance.requestConfiguration setMaxAdContentRating:GADMaxAdContentRatingMatureAudience]; break; } -} - -///// UTILS /////////////////////////////////////////////////////////////////////////////////////// --(void) AdMob_NonPersonalizedAds_Set:(double) value -{ - self->NPA = value >= 0.5; -} - --(GADRequest*) AdMob_AdRequest -{ - GADRequest *request = [GADRequest request]; - if(self->NPA) - { - GADExtras *extras = [[GADExtras alloc] init]; - extras.additionalParameters = @{@"npa": @"1"}; - [request registerAdNetworkExtras: extras]; - } - - return request; + return 0; } -///// CONSENT ///////////////////////////////////////////////////////////////////////////////////// +#pragma mark - Consent Methods -(void) AdMob_Consent_RequestInfoUpdate:(double) testing { @@ -636,8 +1044,6 @@ -(void) AdMob_Consent_RequestInfoUpdate:(double) testing if(testing != 3) { - NSLog(@"Testing the UMP"); - UMPDebugSettings *debugSettings = [[UMPDebugSettings alloc] init]; debugSettings.testDeviceIdentifiers = @[ [[[UIDevice currentDevice] identifierForVendor] UUIDString] ]; @@ -645,14 +1051,13 @@ -(void) AdMob_Consent_RequestInfoUpdate:(double) testing parameters.debugSettings = debugSettings; } - parameters.tagForUnderAgeOfConsent = NO; [UMPConsentInformation.sharedInstance requestConsentInfoUpdateWithParameters:parameters completionHandler:^(NSError *_Nullable error) { int dsMapIndex = dsMapCreate(); if (error) - { - dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_Consent_OnRequestInfoUpdateFailed"); + { + dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_Consent_OnRequestInfoUpdateFailed"); dsMapAddDouble(dsMapIndex, (char*)"errorCode", error.code); dsMapAddString(dsMapIndex, (char*)"errorMessage", (char*)[error.localizedDescription UTF8String]); } @@ -661,13 +1066,13 @@ -(void) AdMob_Consent_RequestInfoUpdate:(double) testing dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_Consent_OnRequestInfoUpdated"); } - createSocialAsyncEventWithDSMap(dsMapIndex); + createSocialAsyncEventWithDSMap(dsMapIndex); }]; } -(double) AdMob_Consent_GetStatus { - https://developers.google.com/admob/ump/android/api/reference/com/google/android/ump/ConsentInformation.ConsentStatus.html#REQUIRED + // https://developers.google.com/admob/ump/android/api/reference/com/google/android/ump/ConsentInformation.ConsentStatus.html#REQUIRED switch(UMPConsentInformation.sharedInstance.consentStatus) { case 0: //UNKNOWN @@ -689,62 +1094,58 @@ -(double) AdMob_Consent_GetType { if (UMPConsentInformation.sharedInstance.consentStatus == UMPConsentStatusObtained) { - // if (!canShowAds()) return 3.0; // DECLINED + if (!canShowAds()) return 3.0; // DECLINED - return canShowPersonalizedAds() ? /* PERSONALIZED */2.0 : /* NON-PERSONALIZED */1.0; + return canShowPersonalizedAds() ? /* PERSONALIZED */2.0 : /* NON-PERSONALIZED */1.0; } return 0; // UNKNOWN } -(double) AdMob_Consent_IsFormAvailable { - if(UMPConsentInformation.sharedInstance.formStatus == 1) - return 1.0; - else - return 0.0; + return (UMPConsentInformation.sharedInstance.formStatus == 1) ? 1.0 : 0.0; } -(void) AdMob_Consent_Load { - [UMPConsentForm loadWithCompletionHandler:^(UMPConsentForm *form_, NSError *loadError) + [UMPConsentForm loadWithCompletionHandler:^(UMPConsentForm *form, NSError *loadError) { int dsMapIndex = dsMapCreate(); if (loadError) - { - dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_Consent_OnLoadFailed"); + { + dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_Consent_OnLoadFailed"); dsMapAddDouble(dsMapIndex, (char*)"errorCode", loadError.code); dsMapAddString(dsMapIndex, (char*)"errorMessage", (char*)[loadError.localizedDescription UTF8String]); } else { - self.myForm = form_; - + self.consentForm = form; dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_Consent_OnLoaded"); } - createSocialAsyncEventWithDSMap(dsMapIndex); + createSocialAsyncEventWithDSMap(dsMapIndex); }]; } -(void) AdMob_Consent_Show { - [self.myForm presentFromViewController:g_controller completionHandler:^(NSError *_Nullable dismissError) + [self.consentForm presentFromViewController:g_controller completionHandler:^(NSError *_Nullable dismissError) { int dsMapIndex = dsMapCreate(); if (UMPConsentInformation.sharedInstance.consentStatus == UMPConsentStatusObtained and !dismissError) - { + { dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_Consent_OnShown"); } else { - dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_Consent_OnShowFailed"); + dsMapAddString(dsMapIndex, (char*)"type", (char*)"AdMob_Consent_OnShowFailed"); dsMapAddDouble(dsMapIndex, (char*)"errorCode", dismissError.code); dsMapAddString(dsMapIndex, (char*)"errorMessage", (char*)[dismissError.localizedDescription UTF8String]); } - createSocialAsyncEventWithDSMap(dsMapIndex); + createSocialAsyncEventWithDSMap(dsMapIndex); }]; } @@ -753,22 +1154,37 @@ -(void) AdMob_Consent_Reset [UMPConsentInformation.sharedInstance reset]; } -///// SETTINGS //////////////////////////////////////////////////////////////////////////////////// +#pragma mark - Settings Methods -(void) AdMob_Settings_SetVolume:(double) value { - GADMobileAds.sharedInstance.applicationVolume = value; + GADMobileAds.sharedInstance.applicationVolume = value; } - + -(void) AdMob_Settings_SetMuted:(double) value { - if(value >= 0.5) - GADMobileAds.sharedInstance.applicationMuted = YES; - else - GADMobileAds.sharedInstance.applicationMuted = NO; + GADMobileAds.sharedInstance.applicationMuted = (value >= 0.5) ? YES : NO; } -///// UTILITIES /////////////////////////////////////////////////////////////////////////////////// +///// INTERNAL /////////////////////////////////////////////////////////////////////////////////// + +-(GADRequest*) buildAdRequest +{ + GADRequest *request = [GADRequest request]; + + // As per Google's request + request.requestAgent = [NSString stringWithFormat:@"gmext-admob-%s", extGetVersion((char*)"AdMob")]; + + // This is deprectated and shouldn't be used keeping it for the sake of compatibility + if (self.nonPersonalizedAds) + { + GADExtras *extras = [[GADExtras alloc] init]; + extras.additionalParameters = @{@"npa": @"1"}; + [request registerAdNetworkExtras: extras]; + } + + return request; +} const char * getDeviceId() { @@ -790,10 +1206,10 @@ -(void) AdMob_Settings_SetMuted:(double) value // https://stackoverflow.com/questions/69307205/mandatory-consent-for-admob-user-messaging-platform Boolean canShowAds() { - NSString *purposeConsent = [[NSUserDefaults standardUserDefaults] stringForKey:@"IABTCF_PurposeConsents"]; - NSString *vendorConsent = [[NSUserDefaults standardUserDefaults] stringForKey:@"IABTCF_VendorConsents"]; - NSString *vendorLI = [[NSUserDefaults standardUserDefaults] stringForKey:@"IABTCF_VendorLegitimateInterests"]; - NSString *purposeLI = [[NSUserDefaults standardUserDefaults] stringForKey:@"IABTCF_PurposeLegitimateInterests"]; + NSString *purposeConsent = [[NSUserDefaults standardUserDefaults] stringForKey:@"IABTCF_PurposeConsents"]; + NSString *vendorConsent = [[NSUserDefaults standardUserDefaults] stringForKey:@"IABTCF_VendorConsents"]; + NSString *vendorLI = [[NSUserDefaults standardUserDefaults] stringForKey:@"IABTCF_VendorLegitimateInterests"]; + NSString *purposeLI = [[NSUserDefaults standardUserDefaults] stringForKey:@"IABTCF_PurposeLegitimateInterests"]; int googleId = 755; Boolean hasGoogleVendorConsent = hasAttribute(vendorConsent, googleId); @@ -802,15 +1218,15 @@ Boolean canShowAds() int indexes[1] = {1}; int indexesLI[4] = {2, 7, 9, 10}; - return hasConsentFor(indexes, 1, purposeConsent, hasGoogleVendorConsent) && hasConsentOrLegitimateInterestFor(indexesLI, 4, purposeConsent, purposeLI, hasGoogleVendorConsent, hasGoogleVendorLI); + return hasConsentFor(indexes, 1, purposeConsent, hasGoogleVendorConsent) && hasConsentOrLegitimateInterestFor(indexesLI, 4, purposeConsent, purposeLI, hasGoogleVendorConsent, hasGoogleVendorLI); } Boolean canShowPersonalizedAds() { - NSString *purposeConsent = [[NSUserDefaults standardUserDefaults] stringForKey:@"IABTCF_PurposeConsents"]; - NSString *vendorConsent = [[NSUserDefaults standardUserDefaults] stringForKey:@"IABTCF_VendorConsents"]; - NSString *vendorLI = [[NSUserDefaults standardUserDefaults] stringForKey:@"IABTCF_VendorLegitimateInterests"]; - NSString *purposeLI = [[NSUserDefaults standardUserDefaults] stringForKey:@"IABTCF_PurposeLegitimateInterests"]; + NSString *purposeConsent = [[NSUserDefaults standardUserDefaults] stringForKey:@"IABTCF_PurposeConsents"]; + NSString *vendorConsent = [[NSUserDefaults standardUserDefaults] stringForKey:@"IABTCF_VendorConsents"]; + NSString *vendorLI = [[NSUserDefaults standardUserDefaults] stringForKey:@"IABTCF_VendorLegitimateInterests"]; + NSString *purposeLI = [[NSUserDefaults standardUserDefaults] stringForKey:@"IABTCF_PurposeLegitimateInterests"]; int googleId = 755; Boolean hasGoogleVendorConsent = hasAttribute(vendorConsent, googleId); @@ -819,7 +1235,7 @@ Boolean canShowPersonalizedAds() int indexes[3] = {1, 3, 4}; int indexesLI[4] = {2, 7, 9, 10}; - return hasConsentFor(indexes, 3, purposeConsent, hasGoogleVendorConsent) && hasConsentOrLegitimateInterestFor(indexesLI, 4, purposeConsent, purposeLI, hasGoogleVendorConsent, hasGoogleVendorLI); + return hasConsentFor(indexes, 3, purposeConsent, hasGoogleVendorConsent) && hasConsentOrLegitimateInterestFor(indexesLI, 4, purposeConsent, purposeLI, hasGoogleVendorConsent, hasGoogleVendorLI); } Boolean hasAttribute(NSString* input, int index) @@ -860,4 +1276,53 @@ Boolean hasConsentOrLegitimateInterestFor(int* indexes, int size, NSString* purp return true; } +/// VALIDATIONS + +- (BOOL)validateNotInitializedWithCallingMethod:(const char *)callingMethod { + if (self.isInitialized) { + NSLog(@"%s :: Method cannot be called after initialization.", callingMethod); + } + return !self.isInitialized; +} + +- (BOOL)validateInitializedWithCallingMethod:(const char *)callingMethod { + if (!self.isInitialized) { + NSLog(@"%s :: Extension was not initialized.", callingMethod); + } + return self.isInitialized; +} + +- (BOOL)validateActiveBannerAdWithCallingMethod:(const char *)callingMethod { + if (self.bannerView == nil) { + NSLog(@"%s :: There is no active banner ad.", callingMethod); + return NO; + } + return YES; +} + +- (BOOL)validateAdId:(NSString *)adUnitId callingMethod:(const char *)callingMethod { + if (adUnitId.length == 0) { + NSLog(@"%s :: Extension was not initialized.", callingMethod); + return NO; + } + return YES; +} + +- (BOOL)validateLoadedAdsLimit:(ThreadSafeQueue *)queue maxSize:(int)maxSize callingMethod:(const char *)callingMethod { + if ([queue size] >= maxSize) { + NSLog(@"%s :: Maximum number of loaded ads reached.", callingMethod); + return NO; + } + return YES; +} + +- (BOOL)validateAdLoaded:(ThreadSafeQueue *)queue callingMethod:(const char *)callingMethod { + if ([queue size] == 0) { + NSLog(@"%s :: There is no loaded ad in queue.", callingMethod); + return NO; + } + return YES; +} + + @end diff --git a/extensions/AdMob/pre_build_step.bat b/extensions/AdMob/pre_build_step.bat new file mode 100644 index 000000000..5886b4269 --- /dev/null +++ b/extensions/AdMob/pre_build_step.bat @@ -0,0 +1,19 @@ +@echo off +set Utils="%~dp0\scriptUtils.bat" + +:: ###################################################################################### +:: Script Logic + +:: Always init the script +call %Utils% scriptInit + +:: Version locks +call %Utils% optionGetValue "versionStable" RUNTIME_VERSION_STABLE +call %Utils% optionGetValue "versionBeta" RUNTIME_VERSION_BETA +call %Utils% optionGetValue "versionDev" RUNTIME_VERSION_DEV +call %Utils% optionGetValue "versionLTS" RUNTIME_VERSION_LTS + +:: Checks IDE and Runtime versions +call %Utils% versionLockCheck "%YYruntimeVersion%" %RUNTIME_VERSION_STABLE% %RUNTIME_VERSION_BETA% %RUNTIME_VERSION_DEV% %RUNTIME_VERSION_LTS% + +exit %errorlevel% \ No newline at end of file diff --git a/extensions/AdMob/pre_build_step.sh b/extensions/AdMob/pre_build_step.sh new file mode 100644 index 000000000..26fb61a78 --- /dev/null +++ b/extensions/AdMob/pre_build_step.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +sed -i -e 's/\r$//' "$(dirname "$0")/scriptUtils.sh" +chmod +x "$(dirname "$0")/scriptUtils.sh" +source "$(dirname "$0")/scriptUtils.sh" + +# ###################################################################################### +# Script Logic + +# Always init the script +scriptInit + +# Version locks +optionGetValue "versionStable" RUNTIME_VERSION_STABLE +optionGetValue "versionBeta" RUNTIME_VERSION_BETA +optionGetValue "versionDev" RUNTIME_VERSION_DEV +optionGetValue "versionLTS" RUNTIME_VERSION_LTS + +# Checks IDE and Runtime versions +versionLockCheck "$YYruntimeVersion" $RUNTIME_VERSION_STABLE $RUNTIME_VERSION_BETA $RUNTIME_VERSION_DEV $RUNTIME_VERSION_LTS + +exit 0 \ No newline at end of file diff --git a/extensions/AdMob/scriptUtils.bat b/extensions/AdMob/scriptUtils.bat new file mode 100644 index 000000000..26adce792 --- /dev/null +++ b/extensions/AdMob/scriptUtils.bat @@ -0,0 +1,311 @@ +@echo off + +set SCRIPT_PATH="%~0" +shift & goto :%~1 + +:scriptInit + set "LOG_LABEL=UNSET" + set "LOG_LEVEL=-1" + + :: Get extension data + call :pathExtractBase %SCRIPT_PATH% EXTENSION_NAME + call :extensionGetVersion EXTENSION_VERSION + if not defined EXTENSION_VERSION set "EXTENSION_VERSION=0.0.0" + + :: Setup logger + call :toUpper %EXTENSION_NAME% LOG_LABEL + call :optionGetValue "logLevel" LOG_LEVEL + if not defined LOG_LEVEL set "LOG_LEVEL=0" + + :: Check if the operation succeeded + if %errorlevel% neq 0 ( + call :log "INIT" "Script initialization failed (v%EXTENSION_VERSION% :: %LOG_LEVEL%)." + ) else ( + call :log "INIT" "Script initialization succeeded (v%EXTENSION_VERSION% :: %LOG_LEVEL%)." + ) +exit /b 0 + +:extensionGetVersion result + :: Need to enabled delayed expansion + setlocal enabledelayedexpansion + + set "result=!GMEXT_%EXTENSION_NAME%_version!" + call :logInformation "Accessed extension version with value '%result%'." + + :: Need to end local (to push into main scope) + endlocal & set "%~1=%result%" +exit /b 0 + +:: Gets an extension option value +:optionGetValue str result + :: Need to enabled delayed expansion + setlocal enabledelayedexpansion + + set "result=!YYEXTOPT_%EXTENSION_NAME%_%~1!" + call :logInformation "Accessed extension option '%~1' with value '%result%'." + + :: Need to end local (to push into main scope) + endlocal & set "%~2=%result%" +exit /b 0 + +:: Converts a string to uppercase and stores it into a variable +:toUpper str result + for /f "usebackq delims=" %%i in (`powershell.exe -Command "$str = '%~1'.ToUpper(); Write-Output $str"`) do set "%~2=%%i" + call :logInformation "Converted string '%~1' to uppercase." +exit /b 0 + +:: Extracts folder path from a filepath, if a folder path is provided return it instead +:pathExtractDirectory fullpath result + set "%~2=%~dp1" + call :logInformation "Extracted directory path from '%~1'." +exit /b 0 + +:: Extracts the parent folder path from a filepath. The input 'path\to\my\file.txt' must result in 'my' +:pathExtractBase fullpath result + for %%I in ("%~dp1\.") do set "%~2=%%~nI%%~xI" + call :logInformation "Extracted base name from '%~1'." +exit /b 0 + +:: Resolves a relative path if required +:pathResolve basePath relativePath result + + :: Need to enabled delayed expansion + setlocal enabledelayedexpansion + + for /f "delims=" %%i in ('powershell -Command "Push-Location '%~1'; $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath('%~2'); Pop-Location;"') do set "result=%%i" + call :logInformation "Resolved relative path into '%result%'." + + :: Need to end local (to push into main scope) + endlocal & set "%~3=%result%" +exit /b 0 + +:: This function resolves the path if required and stores it into a variable (displays log messages) +:pathResolveExisting basePath relativePath result + :: Resolve the path + call :pathResolve "%~1" "%~2" "%~3" + + :: Need to enabled delayed expansion + setlocal enabledelayedexpansion + + :: Check if the path exists + if not exist "!%~3%!" ( + call :logError "Path '!%~3%!' does not exist." + endlocal & exit /b 1 + ) + :: Need to end local (to push into main scope) + endlocal +exit /b 0 + +:: Copies a file or folder to the specified destination folder (displays log messages) +:itemCopyTo srcPath destFolder + + call :pathResolve "%cd%" "%~2" destination + + if not exist "%~1" ( + call :logError "Failed to copy '%~1' to '%destination%' (source doesn't exist)." + exit /b 1 + ) + + for /f "delims=" %%a in ('dir /b /a:d "%~1" 2^>nul') do ( + if "%%~a" == "%~nx1" ( + powershell -NoLogo -NoProfile -Command "New-Item -ItemType Directory -Force -Path '%destination%'; Copy-Item -Path '%~1' -Destination '%destination%' -Recurse" + ) + ) + + for /f "delims=" %%a in ('dir /b /a:-d "%~1" 2^>nul') do ( + if "%%~a" == "%~nx1" ( + powershell -NoLogo -NoProfile -Command "New-Item -ItemType Directory -Force -Path (Split-Path -Parent '%destination%'); Copy-Item -Path '%~1' -Destination '%destination%' -Force" + ) + ) + + :: Check if the copy operation succeeded + if %errorlevel% neq 0 ( + call :logError "Failed to copy '%~1' to '%destination%'." + exit /b 1 + ) + + call :logInformation "Copied '%~1' to '%destination%'." +exit /b 0 + +:: Deletes a file or folder at the specified path (displays log messages) +:itemDelete targetPath + + call :pathResolve "%cd%" "%~1" target + + if exist "%~1\." ( + :: Is a folder + powershell -NoLogo -NoProfile -Command "Remove-Item -Path '%~1' -Recurse -Force" + ) else if exist "%~1" ( + :: Is a file + powershell -NoLogo -NoProfile -Command "Remove-Item -Path '%~1' -Force" + ) else ( + call :logWarning "Path '%target%' does not exist. Skipping deletion." + exit /b 0 + ) + + :: Check if the deletion operation succeeded + if %errorlevel% neq 0 ( + call :logError "Failed to delete '%target%'." + exit /b 1 + ) + + call :logInformation "Deleted '%target%'." +exit /b 0 + +:: Generates the SHA256 hash of a file and stores it into a variable (displays log messages) +:fileGetHash filepath result + for /f "usebackq delims=" %%i in (`powershell -Command "(Get-FileHash -Path '%~1' -Algorithm SHA256).Hash"`) do set "%~2=%%i" + call :logInformation "Generated SHA256 hash of '%~1'." +exit /b 0 + +:: Extracts the contents of a zip file to the specified destination folder (displays log messages) +:fileExtract srcFile destFolder + powershell -Command "if (!(Test-Path '%~2')) { New-Item -ItemType Directory -Path '%~2' }" + powershell -Command "$ErrorActionPreference = 'Stop'; Expand-Archive -Path '%~1' -DestinationPath '%~2'" + + :: Check if the extraction operation succeeded + if %errorlevel% neq 0 ( + call :logError "Failed to extract contents of '%~1' to '%~2'." + exit /b 1 + ) + + call :logInformation "Extracted contents of '%~1' to '%~2'." +exit /b 0 + +:: Compresses the contents of a folder into a zip file (displays log messages) +:folderCompress srcFolder destFile + powershell -Command "Compress-Archive -Path '%~1\*' -DestinationPath '%~2'" -Force + + :: Check if the compression operation succeeded + if %errorlevel% neq 0 ( + call :logError "Failed to compress contents of '%~1' into '%~2'." + exit /b 1 + ) + + call :logInformation "Compressed contents of '%~1' into '%~2'." +exit /b 0 + +:: Extracts a specified part of a version string and stores it into a variable (displays log messages) +:versionExtract version part result + :: Use PowerShell to extract the specified part of the version string + for /f "usebackq delims=" %%i in (`powershell -Command "$version = New-Object Version '%~1'; Write-Output $version.%~2"`) do set "%~3=%%i" + + :: Need to enabled delayed expansion + setlocal enabledelayedexpansion + call :logInformation "Extracted part %~2 of version '%~1' with value '!%~3%!'." + endlocal +exit /b 0 + +:: Compares two version numbers (major.minor.build.rev) and saves result into variable +:versionCompare version1 version2 result + for /f "tokens=* usebackq" %%F in (`powershell -NoLogo -NoProfile -Command ^([System.Version]'%~1'^).compareTo^([System.Version]'%~2'^)`) do ( set "%~3=%%F" ) + call :logInformation "Compared version '%~1' with version '%~2'." +exit /b 0 + +:: Check minimum required versions for STABLE|BETA|DEV releases +:versionLockCheck version stableVersion betaVersion devVersion ltsVersion + + call :versionExtract "%~1" Major majorVersion + call :versionExtract "%~1" Minor minorVersion + + set "runnerBuild=" + + if %minorVersion% equ 0 ( + :: LTS version + set "runnerBuild=LTS" + call :assertVersionRequired "%~1" "%~5" "The %%runnerBuild%% runtime version needs to be at least v%~5." + + ) else ( + if %majorVersion% geq 2020 ( + if %minorVersion% geq 100 ( + :: Beta version + set "runnerBuild=BETA" + call :assertVersionRequired "%~1" "%~3" "The %%runnerBuild%% runtime version needs to be at least v%~3." + ) else ( + :: Stable version + set "runnerBuild=STABLE" + call :assertVersionRequired "%~1" "%~2" "The %%runnerBuild%% runtime version needs to be at least v%~2." + ) + ) else ( + :: Dev version + set "runnerBuild=DEV" + call :assertVersionRequired "%~1" "%~4" "The %%runnerBuild%% runtime version needs to be at least v%~4." + ) + ) + + call :logInformation "Version lock check passed successfully, with %%runnerBuild%% version '%~1'." +exit /b 0 + +:: ASSERTS + +:: Asserts the SHA256 hash of a file, logs an error message and throws an error if they do not match (displays log messages) +:assertFileHashEquals filepath expected message + :: Generate hash + call :fileGetHash "%~1" actualHash + + :: Compare the actual hash with the expected hash + if not "%actualHash%" == "%~2" ( + call :logError "%~3" + exit /b 1 + ) + + :: Log a message + call :logInformation "Asserted SHA256 hash of '%~1' matches expected hash." +exit /b 0 + +:: Asserts that the given version string is greater than the expected version string, logs an error message and throws an error if not (displays log messages) +:assertVersionRequired version expected message + :: Compare the two version strings using :versionCompare + set "compareResult=" + call :versionCompare "%~1" "%~2" compareResult + + :: Check the result and log an error message and throw an error if not greater + if %compareResult% lss 0 ( + call :logError "%~3" + exit /b 1 + ) + + :: Log a message + call :logInformation "Asserted that version '%~1' is greater than or equal to version '%~2'." +exit /b 0 + +:: Asserts that the given version string is equal to the expected version string, logs an error message and throws an error if not (displays log messages) +:assertVersionEquals version expected message + :: Compare the two version strings using :versionCompare + set "compareResult=" + call :versionCompare "%~1" "%~2" compareResult + + :: Check the result and log an error message and throw an error if not equal + if %compareResult% neq 0 ( + call :logError "%~3" + exit /b 1 + ) + + :: Log a message + call :logInformation "Asserted that version '%~1' equals version '%~2'." +exit /b 0 + +:: LOGGING + +:: Logs information +:logInformation message + if %LOG_LEVEL% geq 2 call :log "INFO" "%~1" +exit /b 0 + +:: Logs warning +:logWarning message + if %LOG_LEVEL% geq 1 call :log "WARN" "%~1" +exit /b 0 + +:: Logs error +:logError message + if %LOG_LEVEL% geq 0 call :log "ERROR" "%~1" + exit 1 +exit /b 0 + +:: General log function +:log tag message + echo [%LOG_LABEL%] %~1: %~2 +exit /b 0 + + diff --git a/extensions/AdMob/scriptUtils.sh b/extensions/AdMob/scriptUtils.sh new file mode 100644 index 000000000..913d6eb5b --- /dev/null +++ b/extensions/AdMob/scriptUtils.sh @@ -0,0 +1,451 @@ +#!/bin/bash + +SCRIPT_PATH="$0" + +# Auxiliar Functions + +# Script initialization +# Usage: scriptInit +scriptInit() { + LOG_LABEL="UNSET" + LOG_LEVEL=-1 + EXTENSION_NAME= + + # Get extension data + pathExtractBase $SCRIPT_PATH EXTENSION_NAME + extensionGetVersion EXTENSION_VERSION + if [ -z "$EXTENSION_VERSION" ]; then + EXTENSION_VERSION="0.0.0" + fi + + # Setup logger + toUpper $EXTENSION_NAME LOG_LABEL + optionGetValue "logLevel" LOG_LEVEL + if [ -z "$LOG_LEVEL" ]; then + LOG_LEVEL=2 + fi + + # Check if the operation succeeded + if [ "$?" -ne 0 ]; then + log "INIT" "Script initialization failed (v$EXTENSION_VERSION :: $LOG_LEVEL)." + else + log "INIT" "Script initialization succeeded (v$EXTENSION_VERSION :: $LOG_LEVEL)." + fi +} + +# Gets the extension version value +# Usage: extensionGetVersion result +extensionGetVersion() { + # Enable indirect variable reference + set -f + local var="GMEXT_${EXTENSION_NAME}_version" + local result="${!var}" + set +f + + logInformation "Accessed extension version with value '${result}'." + eval "$1=\"\$result\"" +} + +# Gets an extension option value +# Usage: optionGetValue optionName result +optionGetValue() { + + # Enable indirect variable reference + set -f + local var="YYEXTOPT_${EXTENSION_NAME}_$1" + local result="${!var}" + set +f + + logInformation "Accessed extension option '${1}' with value '${result}'." + eval "$2=\"\$result\"" +} + +# Sets a string to uppercase +toUpper() { # str result + eval "$2=$(echo $1 | tr '[:lower:]' '[:upper:]')" + logInformation "Converted string '$1' to upper case." +} + +# Extracts the full folder path from a filepath +# Usage: pathExtractDirectory fullpath result +pathExtractDirectory() { + eval "$2=\"$(dirname "$1")\"" + logInformation "Extracted directory path from '$1'." +} + +# Extracts the parent folder from a path +# Usage: pathExtractBase fullpath result +pathExtractBase() { + eval "$2=\"$(basename $(dirname "$1"))\"" + logInformation "Extracted base name from '$1'." +} + +# Resolves a relative or absolute path to an absolute path +# Usage: pathResolve basePath relativePath result +pathResolve() { + local basePath="$1" + local relativePath="$2" + local resolvedPath= + + # Ensure 'basePath' ends with a forward slash + [[ "${basePath: -1}" != "/" ]] && basePath+="/" + + # If 'relativePath' starts with "/", set 'combined_path' to 'relativePath' + if [[ "${relativePath:0:1}" == "/" ]]; then + combined_path="$relativePath" + else + # Concatenate the paths + combined_path="$basePath$relativePath" + fi + + # Split the path into an array by the character "/" + IFS="/" read -ra path_parts <<< "$combined_path" + + # Remove any entries that are "." and if an entry is "..", remove that entry and the previous one + result=() + for part in "${path_parts[@]}"; do + if [ "$part" == "." ] || [ -z "$part" ]; then + continue + elif [ "$part" == ".." ]; then + unset result[${#result[@]}-1] + else + result+=("$part") + fi + done + + # Merge the final array using "/" as a delimiter + resolvedPath="/" + for i in "${!result[@]}"; do + resolvedPath+="${result[i]}" + if [ "$i" -lt $((${#result[@]}-1)) ]; then + resolvedPath+="/" + fi + done + + # Return the merged result + logInformation "Resolved path into '$resolvedPath'." + eval "$3=\"$resolvedPath\"" +} + +# Resolves an existing relative path if required (handles errors) +# Usage: pathResolveExisting basePath relativePath result +pathResolveExisting() { + local existingPath="" + pathResolve "$1" "$2" existingPath + + # Check if the path is valid + if [ ! -e "$existingPath" ]; then + logError "Path '$existingPath' does not exist or is not accessible." + fi + + eval "$3=\"$existingPath\"" +} + +# Copies a file or folder to the specified destination folder +# Usage: itemCopyTo srcPath destFolder +itemCopyTo() { + local source="$1" + local destination="$2" + local resolved_destination="" + + # Resolve the destination folder to an absolute path + pathResolve "$PWD" "$destination" resolved_destination + + # If 'resolved_destination' ends with a "/", ensure the path exists + if [[ "${resolved_destination: -1}" == "/" ]]; then + mkdir -p "$resolved_destination" + else + # Create all parent directories up until the destination path + parent_directory=$(dirname "$resolved_destination") + mkdir -p "$parent_directory" + fi + + if [ -d "$source" ]; then + # Source is a folder + cp -rf "$source" "$resolved_destination" + elif [ -f "$source" ]; then + # Source is a file + cp -f "$source" "$resolved_destination" + else + logError "Failed to copy '$source' does not exist or is not accessible." + exit 1 + fi + + if [ $? -ne 0 ]; then + logError "Failed to copy '$source' to '$resolved_destination'." + exit 1 + fi + + logInformation "Copied '$source' to '$resolved_destination'." +} + +# Deletes a file or folder given a path +# Usage: itemDelete folderPath +itemDelete() { + target_path="$1" + + if [ -d "$target_path" ]; then + # Is a folder + rm -rf "$target_path" + elif [ -f "$target_path" ]; then + # Is a file + rm -f "$target_path" + else + logWarning "Path '$target_path' does not exist. Skipping deletion." + return 0 + fi + + if [ $? -ne 0 ]; then + logError "Failed to delete '$target_path'." + return 1 + fi + + logInformation "Deleted '$target_path'." + return 0 +} + +# Generates the SHA256 hash of a file and stores it into a variable +# Usage: fileGetHash filepath result +fileGetHash() { + local file="$1" + local hash="" + + if [ ! -f "$file" ]; then + logError "Failed to generate hash for '$file' does not exist or is not a file." + exit 1 + fi + + hash=$(shasum -a 256 "$file" | awk '{print $1}') + + if [ $? -ne 0 ]; then + logError "Failed to generate hash for '$file'." + exit 1 + fi + + toUpper "$hash" hash + + eval "$2=\"$hash\"" + logInformation "Generated SHA256 hash of '$file'." +} + +# Extracts the contents of a zip file to the specified destination folder +# Usage: fileExtract srcFile destFolder +fileExtract() { + local source="$1" + local destination="$2" + + # Create the destination folder if it doesn't exist + mkdir -p "$destination" + + # Extract the zip file to the destination folder + unzip -q "$source" -d "$destination" + + if [ $? -ne 0 ]; then + logError "Failed to extract contents of '$source' to '$destination'." + exit 1 + fi + + logInformation "Extracted contents of '$source' to '$destination'." +} + +# Compresses the contents of a folder into a zip file +# Usage: folderCompress srcFolder destFile +folderCompress() { + local source="$1" + local destination="$2" + + # Compress the contents of the folder to the destination file + zip -j -r -q "$destination" "$source" + + if [ $? -ne 0 ]; then + logError "Failed to compress contents of '$source' into '$destination'." + exit 1 + fi + + logInformation "Compressed contents of '$source' into '$destination'." +} + +# Extracts a specified part of a version string and stores it into a variable +# Usage: versionExtract version part result +versionExtract() { + local version="$1" + local part="$2" + + # Use awk to extract the specified part of the version string + local result="$(echo "$version" | awk -F '.' "{print \$$part}")" + + # Store the result in the specified variable + eval "$3=\"$result\"" + + # Display a log message + logInformation "Extracted part $part of version '$version' with value '$result'." +} + +# Compares two version numbers (w.x.y.z) and saves result into variable +# Usage: versionCompare version1 version2 result +versionCompare() { + local version1="$1" + local version2="$2" + + # Use awk to split the version numbers into components + local version1_parts=($(echo "$version1" | awk -F '.' '{print $1,$2,$3,$4}')) + local version2_parts=($(echo "$version2" | awk -F '.' '{print $1,$2,$3,$4}')) + + # Compare the components of the version numbers + for i in {0..3}; do + if [ "${version1_parts[$i]}" -lt "${version2_parts[$i]}" ]; then + result=-1 + break + elif [ "${version1_parts[$i]}" -gt "${version2_parts[$i]}" ]; then + result=1 + break + else + result=0 + fi + done + + # Store the result in the specified variable + eval "$3=\"$result\"" + + # Display a log message + logInformation "Compared version '$version1' with version '$version2'." +} + +# Check minimum required versions for STABLE|BETA|DEV releases +# Usage: versionLockCheck version stableVersion betaVersion devVersion +versionLockCheck() { + local version="$1" + local stableVersion="$2" + local betaVersion="$3" + local devVersion="$4" + local ltsVersion="$5" + + # Extract the major and minor version numbers from the given version + local runnerBuild= + local majorVersion= + local minorVersion= + versionExtract "$version" 1 majorVersion + versionExtract "$version" 2 minorVersion + + if [ "$minorVersion" -eq 0 ]; then + # LTS version + runnerBuild=LTS + assertVersionRequired "$version" "$ltsVersion" "The $runnerBuild runtime version needs to be at least v$ltsVersion." + + elif [ "$majorVersion" -ge 2020 ]; then + if [ "$minorVersion" -ge 100 ]; then + # Beta version + runnerBuild=BETA + assertVersionRequired "$version" "$betaVersion" "The $runnerBuild runtime version needs to be at least v$betaVersion." + else + # Stable version + runnerBuild=STABLE + assertVersionRequired "$version" "$stableVersion" "The $runnerBuild runtime version needs to be at least v$stableVersion." + fi + else + # Dev version + runnerBuild=DEV + assertVersionRequired "$version" "$devVersion" "The $runnerBuild runtime version needs to be at least v$devVersion." + fi + + logInformation "Version lock check passed successfully, with version '$version'." +} + +# ASSERTS + +# Asserts the SHA256 hash of a file, logs an error message and throws an error if they do not match +# Usage: assertFileHashEquals filepath expected message +assertFileHashEquals() { + local filepath="$1" + local expected="$2" + local message="$3" + + # Generate hash + local actualHash= + fileGetHash "$filepath" actualHash + + # Compare the actual hash with the expected hash + if [ "$actualHash" != "$expected" ]; then + logError "$message" + exit 1 + fi + + # Log a message + logInformation "Asserted SHA256 hash of '$filepath' matches expected hash." +} + +# Asserts that the given version string is greater than the expected version string, logs an error message and throws an error if not +# Usage: assertVersionRequired version expected message +assertVersionRequired() { + local version="$1" + local expected="$2" + local message="$3" + + # Compare the two version strings using versionCompare + local compareResult= + versionCompare "$version" "$expected" compareResult + + # Check the result and log an error message and throw an error if not greater + if [ "$compareResult" -lt 0 ]; then + logError "$message" + exit 1 + fi + + # Log a message + logInformation "Asserted that version '$version' is greater than or equal to version '$expected'." +} + +# Asserts that the given version string is equal to the expected version string, logs an error message and throws an error if not +# Usage: assertVersionEquals version expected message +assertVersionEquals() { + local version="$1" + local expected="$2" + local message="$3" + + # Compare the two version strings using versionCompare + local compareResult= + versionCompare "$version" "$expected" compareResult + + # Check the result and log an error message and throw an error if not equal + if [ "$compareResult" -ne 0 ]; then + logError "$message" + exit 1 + fi + + # Log a message + logInformation "Asserted that version '$version' equals version '$expected'." +} + +# Logging + +# Logs information +# Usage: logInformation message +logInformation() { + if [ "$LOG_LEVEL" -ge 2 ]; then + log "INFO" "$1" + fi +} + +# Logs warning +# Usage: logWarning message +logWarning() { + if [ "$LOG_LEVEL" -ge 1 ]; then + log "WARN" "$1" + fi +} + +# Logs error +# Usage: logError message +logError() { + if [ "$LOG_LEVEL" -ge 0 ]; then + log "ERROR" "$1" + fi + exit 1 +} + +# General log function +# Usage: log tag message +log() { + echo "[$LOG_LABEL] $1: $2" +} + diff --git a/extensions/AdMob/scriptUtils.sh-e b/extensions/AdMob/scriptUtils.sh-e new file mode 100644 index 000000000..913d6eb5b --- /dev/null +++ b/extensions/AdMob/scriptUtils.sh-e @@ -0,0 +1,451 @@ +#!/bin/bash + +SCRIPT_PATH="$0" + +# Auxiliar Functions + +# Script initialization +# Usage: scriptInit +scriptInit() { + LOG_LABEL="UNSET" + LOG_LEVEL=-1 + EXTENSION_NAME= + + # Get extension data + pathExtractBase $SCRIPT_PATH EXTENSION_NAME + extensionGetVersion EXTENSION_VERSION + if [ -z "$EXTENSION_VERSION" ]; then + EXTENSION_VERSION="0.0.0" + fi + + # Setup logger + toUpper $EXTENSION_NAME LOG_LABEL + optionGetValue "logLevel" LOG_LEVEL + if [ -z "$LOG_LEVEL" ]; then + LOG_LEVEL=2 + fi + + # Check if the operation succeeded + if [ "$?" -ne 0 ]; then + log "INIT" "Script initialization failed (v$EXTENSION_VERSION :: $LOG_LEVEL)." + else + log "INIT" "Script initialization succeeded (v$EXTENSION_VERSION :: $LOG_LEVEL)." + fi +} + +# Gets the extension version value +# Usage: extensionGetVersion result +extensionGetVersion() { + # Enable indirect variable reference + set -f + local var="GMEXT_${EXTENSION_NAME}_version" + local result="${!var}" + set +f + + logInformation "Accessed extension version with value '${result}'." + eval "$1=\"\$result\"" +} + +# Gets an extension option value +# Usage: optionGetValue optionName result +optionGetValue() { + + # Enable indirect variable reference + set -f + local var="YYEXTOPT_${EXTENSION_NAME}_$1" + local result="${!var}" + set +f + + logInformation "Accessed extension option '${1}' with value '${result}'." + eval "$2=\"\$result\"" +} + +# Sets a string to uppercase +toUpper() { # str result + eval "$2=$(echo $1 | tr '[:lower:]' '[:upper:]')" + logInformation "Converted string '$1' to upper case." +} + +# Extracts the full folder path from a filepath +# Usage: pathExtractDirectory fullpath result +pathExtractDirectory() { + eval "$2=\"$(dirname "$1")\"" + logInformation "Extracted directory path from '$1'." +} + +# Extracts the parent folder from a path +# Usage: pathExtractBase fullpath result +pathExtractBase() { + eval "$2=\"$(basename $(dirname "$1"))\"" + logInformation "Extracted base name from '$1'." +} + +# Resolves a relative or absolute path to an absolute path +# Usage: pathResolve basePath relativePath result +pathResolve() { + local basePath="$1" + local relativePath="$2" + local resolvedPath= + + # Ensure 'basePath' ends with a forward slash + [[ "${basePath: -1}" != "/" ]] && basePath+="/" + + # If 'relativePath' starts with "/", set 'combined_path' to 'relativePath' + if [[ "${relativePath:0:1}" == "/" ]]; then + combined_path="$relativePath" + else + # Concatenate the paths + combined_path="$basePath$relativePath" + fi + + # Split the path into an array by the character "/" + IFS="/" read -ra path_parts <<< "$combined_path" + + # Remove any entries that are "." and if an entry is "..", remove that entry and the previous one + result=() + for part in "${path_parts[@]}"; do + if [ "$part" == "." ] || [ -z "$part" ]; then + continue + elif [ "$part" == ".." ]; then + unset result[${#result[@]}-1] + else + result+=("$part") + fi + done + + # Merge the final array using "/" as a delimiter + resolvedPath="/" + for i in "${!result[@]}"; do + resolvedPath+="${result[i]}" + if [ "$i" -lt $((${#result[@]}-1)) ]; then + resolvedPath+="/" + fi + done + + # Return the merged result + logInformation "Resolved path into '$resolvedPath'." + eval "$3=\"$resolvedPath\"" +} + +# Resolves an existing relative path if required (handles errors) +# Usage: pathResolveExisting basePath relativePath result +pathResolveExisting() { + local existingPath="" + pathResolve "$1" "$2" existingPath + + # Check if the path is valid + if [ ! -e "$existingPath" ]; then + logError "Path '$existingPath' does not exist or is not accessible." + fi + + eval "$3=\"$existingPath\"" +} + +# Copies a file or folder to the specified destination folder +# Usage: itemCopyTo srcPath destFolder +itemCopyTo() { + local source="$1" + local destination="$2" + local resolved_destination="" + + # Resolve the destination folder to an absolute path + pathResolve "$PWD" "$destination" resolved_destination + + # If 'resolved_destination' ends with a "/", ensure the path exists + if [[ "${resolved_destination: -1}" == "/" ]]; then + mkdir -p "$resolved_destination" + else + # Create all parent directories up until the destination path + parent_directory=$(dirname "$resolved_destination") + mkdir -p "$parent_directory" + fi + + if [ -d "$source" ]; then + # Source is a folder + cp -rf "$source" "$resolved_destination" + elif [ -f "$source" ]; then + # Source is a file + cp -f "$source" "$resolved_destination" + else + logError "Failed to copy '$source' does not exist or is not accessible." + exit 1 + fi + + if [ $? -ne 0 ]; then + logError "Failed to copy '$source' to '$resolved_destination'." + exit 1 + fi + + logInformation "Copied '$source' to '$resolved_destination'." +} + +# Deletes a file or folder given a path +# Usage: itemDelete folderPath +itemDelete() { + target_path="$1" + + if [ -d "$target_path" ]; then + # Is a folder + rm -rf "$target_path" + elif [ -f "$target_path" ]; then + # Is a file + rm -f "$target_path" + else + logWarning "Path '$target_path' does not exist. Skipping deletion." + return 0 + fi + + if [ $? -ne 0 ]; then + logError "Failed to delete '$target_path'." + return 1 + fi + + logInformation "Deleted '$target_path'." + return 0 +} + +# Generates the SHA256 hash of a file and stores it into a variable +# Usage: fileGetHash filepath result +fileGetHash() { + local file="$1" + local hash="" + + if [ ! -f "$file" ]; then + logError "Failed to generate hash for '$file' does not exist or is not a file." + exit 1 + fi + + hash=$(shasum -a 256 "$file" | awk '{print $1}') + + if [ $? -ne 0 ]; then + logError "Failed to generate hash for '$file'." + exit 1 + fi + + toUpper "$hash" hash + + eval "$2=\"$hash\"" + logInformation "Generated SHA256 hash of '$file'." +} + +# Extracts the contents of a zip file to the specified destination folder +# Usage: fileExtract srcFile destFolder +fileExtract() { + local source="$1" + local destination="$2" + + # Create the destination folder if it doesn't exist + mkdir -p "$destination" + + # Extract the zip file to the destination folder + unzip -q "$source" -d "$destination" + + if [ $? -ne 0 ]; then + logError "Failed to extract contents of '$source' to '$destination'." + exit 1 + fi + + logInformation "Extracted contents of '$source' to '$destination'." +} + +# Compresses the contents of a folder into a zip file +# Usage: folderCompress srcFolder destFile +folderCompress() { + local source="$1" + local destination="$2" + + # Compress the contents of the folder to the destination file + zip -j -r -q "$destination" "$source" + + if [ $? -ne 0 ]; then + logError "Failed to compress contents of '$source' into '$destination'." + exit 1 + fi + + logInformation "Compressed contents of '$source' into '$destination'." +} + +# Extracts a specified part of a version string and stores it into a variable +# Usage: versionExtract version part result +versionExtract() { + local version="$1" + local part="$2" + + # Use awk to extract the specified part of the version string + local result="$(echo "$version" | awk -F '.' "{print \$$part}")" + + # Store the result in the specified variable + eval "$3=\"$result\"" + + # Display a log message + logInformation "Extracted part $part of version '$version' with value '$result'." +} + +# Compares two version numbers (w.x.y.z) and saves result into variable +# Usage: versionCompare version1 version2 result +versionCompare() { + local version1="$1" + local version2="$2" + + # Use awk to split the version numbers into components + local version1_parts=($(echo "$version1" | awk -F '.' '{print $1,$2,$3,$4}')) + local version2_parts=($(echo "$version2" | awk -F '.' '{print $1,$2,$3,$4}')) + + # Compare the components of the version numbers + for i in {0..3}; do + if [ "${version1_parts[$i]}" -lt "${version2_parts[$i]}" ]; then + result=-1 + break + elif [ "${version1_parts[$i]}" -gt "${version2_parts[$i]}" ]; then + result=1 + break + else + result=0 + fi + done + + # Store the result in the specified variable + eval "$3=\"$result\"" + + # Display a log message + logInformation "Compared version '$version1' with version '$version2'." +} + +# Check minimum required versions for STABLE|BETA|DEV releases +# Usage: versionLockCheck version stableVersion betaVersion devVersion +versionLockCheck() { + local version="$1" + local stableVersion="$2" + local betaVersion="$3" + local devVersion="$4" + local ltsVersion="$5" + + # Extract the major and minor version numbers from the given version + local runnerBuild= + local majorVersion= + local minorVersion= + versionExtract "$version" 1 majorVersion + versionExtract "$version" 2 minorVersion + + if [ "$minorVersion" -eq 0 ]; then + # LTS version + runnerBuild=LTS + assertVersionRequired "$version" "$ltsVersion" "The $runnerBuild runtime version needs to be at least v$ltsVersion." + + elif [ "$majorVersion" -ge 2020 ]; then + if [ "$minorVersion" -ge 100 ]; then + # Beta version + runnerBuild=BETA + assertVersionRequired "$version" "$betaVersion" "The $runnerBuild runtime version needs to be at least v$betaVersion." + else + # Stable version + runnerBuild=STABLE + assertVersionRequired "$version" "$stableVersion" "The $runnerBuild runtime version needs to be at least v$stableVersion." + fi + else + # Dev version + runnerBuild=DEV + assertVersionRequired "$version" "$devVersion" "The $runnerBuild runtime version needs to be at least v$devVersion." + fi + + logInformation "Version lock check passed successfully, with version '$version'." +} + +# ASSERTS + +# Asserts the SHA256 hash of a file, logs an error message and throws an error if they do not match +# Usage: assertFileHashEquals filepath expected message +assertFileHashEquals() { + local filepath="$1" + local expected="$2" + local message="$3" + + # Generate hash + local actualHash= + fileGetHash "$filepath" actualHash + + # Compare the actual hash with the expected hash + if [ "$actualHash" != "$expected" ]; then + logError "$message" + exit 1 + fi + + # Log a message + logInformation "Asserted SHA256 hash of '$filepath' matches expected hash." +} + +# Asserts that the given version string is greater than the expected version string, logs an error message and throws an error if not +# Usage: assertVersionRequired version expected message +assertVersionRequired() { + local version="$1" + local expected="$2" + local message="$3" + + # Compare the two version strings using versionCompare + local compareResult= + versionCompare "$version" "$expected" compareResult + + # Check the result and log an error message and throw an error if not greater + if [ "$compareResult" -lt 0 ]; then + logError "$message" + exit 1 + fi + + # Log a message + logInformation "Asserted that version '$version' is greater than or equal to version '$expected'." +} + +# Asserts that the given version string is equal to the expected version string, logs an error message and throws an error if not +# Usage: assertVersionEquals version expected message +assertVersionEquals() { + local version="$1" + local expected="$2" + local message="$3" + + # Compare the two version strings using versionCompare + local compareResult= + versionCompare "$version" "$expected" compareResult + + # Check the result and log an error message and throw an error if not equal + if [ "$compareResult" -ne 0 ]; then + logError "$message" + exit 1 + fi + + # Log a message + logInformation "Asserted that version '$version' equals version '$expected'." +} + +# Logging + +# Logs information +# Usage: logInformation message +logInformation() { + if [ "$LOG_LEVEL" -ge 2 ]; then + log "INFO" "$1" + fi +} + +# Logs warning +# Usage: logWarning message +logWarning() { + if [ "$LOG_LEVEL" -ge 1 ]; then + log "WARN" "$1" + fi +} + +# Logs error +# Usage: logError message +logError() { + if [ "$LOG_LEVEL" -ge 0 ]; then + log "ERROR" "$1" + fi + exit 1 +} + +# General log function +# Usage: log tag message +log() { + echo "[$LOG_LABEL] $1: $2" +} + diff --git a/extensions/AdMobAppLovin/AdMobAppLovin.yy b/extensions/AdMobAppLovin/AdMobAppLovin.yy new file mode 100644 index 000000000..14d4607d7 --- /dev/null +++ b/extensions/AdMobAppLovin/AdMobAppLovin.yy @@ -0,0 +1,62 @@ +{ + "$GMExtension":"", + "%Name":"AdMobAppLovin", + "androidactivityinject":"", + "androidclassname":"", + "androidcodeinjection":"\r\n\r\n implementation(\"com.google.ads.mediation:applovin:12.5.0.0\")\r\n\r\n", + "androidinject":"", + "androidmanifestinject":"", + "androidPermissions":[], + "androidProps":true, + "androidsourcedir":"", + "author":"", + "classname":"", + "copyToTargets":0, + "description":"", + "exportToGame":true, + "extensionVersion":"1.0.0", + "files":[], + "gradleinject":"\r\n implementation(\"com.google.ads.mediation:applovin:12.5.0.0\")\r\n", + "hasConvertedCodeInjection":true, + "helpfile":"", + "HTML5CodeInjection":"", + "html5Props":false, + "IncludedResources":[], + "installdir":"", + "iosCocoaPodDependencies":"", + "iosCocoaPods":"\r\npod 'GoogleMobileAdsMediationAppLovin'\r\n", + "ioscodeinjection":"\r\n\r\npod 'GoogleMobileAdsMediationAppLovin'\r\n\r\n", + "iosdelegatename":"", + "iosplistinject":"", + "iosProps":true, + "iosSystemFrameworkEntries":[], + "iosThirdPartyFrameworkEntries":[], + "license":"", + "maccompilerflags":"", + "maclinkerflags":"", + "macsourcedir":"", + "name":"AdMobAppLovin", + "options":[], + "optionsFile":"options.json", + "packageId":"", + "parent":{ + "name":"Mediations", + "path":"folders/Extensions/AdMob/Mediations.yy", + }, + "productId":"", + "resourceType":"GMExtension", + "resourceVersion":"2.0", + "sourcedir":"", + "supportedTargets":-1, + "tvosclassname":null, + "tvosCocoaPodDependencies":"", + "tvosCocoaPods":"", + "tvoscodeinjection":"", + "tvosdelegatename":null, + "tvosmaccompilerflags":"", + "tvosmaclinkerflags":"", + "tvosplistinject":"", + "tvosProps":false, + "tvosSystemFrameworkEntries":[], + "tvosThirdPartyFrameworkEntries":[], +} \ No newline at end of file diff --git a/extensions/AdMobIronSource/AdMobIronSource.yy b/extensions/AdMobIronSource/AdMobIronSource.yy new file mode 100644 index 000000000..cf93a7a59 --- /dev/null +++ b/extensions/AdMobIronSource/AdMobIronSource.yy @@ -0,0 +1,62 @@ +{ + "$GMExtension":"", + "%Name":"AdMobIronSource", + "androidactivityinject":"", + "androidclassname":"", + "androidcodeinjection":"\r\n\r\n implementation(\"com.google.ads.mediation:ironsource:8.1.0.0\")\r\n\r\n\r\n\r\n\r\nrepositories\r\n{\r\n maven {\r\n url 'https://android-sdk.is.com/'\r\n }\r\n}\r\n\r\n", + "androidinject":"", + "androidmanifestinject":"", + "androidPermissions":[], + "androidProps":true, + "androidsourcedir":"", + "author":"", + "classname":"", + "copyToTargets":0, + "description":"", + "exportToGame":true, + "extensionVersion":"1.0.0", + "files":[], + "gradleinject":"\r\n implementation(\"com.google.ads.mediation:ironsource:8.1.0.0\")\r\n", + "hasConvertedCodeInjection":true, + "helpfile":"", + "HTML5CodeInjection":"", + "html5Props":false, + "IncludedResources":[], + "installdir":"", + "iosCocoaPodDependencies":"", + "iosCocoaPods":"\r\npod 'GoogleMobileAdsMediationIronSource'\r\n", + "ioscodeinjection":"\r\n\r\npod 'GoogleMobileAdsMediationIronSource'\r\n\r\n", + "iosdelegatename":"", + "iosplistinject":"", + "iosProps":true, + "iosSystemFrameworkEntries":[], + "iosThirdPartyFrameworkEntries":[], + "license":"", + "maccompilerflags":"", + "maclinkerflags":"", + "macsourcedir":"", + "name":"AdMobIronSource", + "options":[], + "optionsFile":"options.json", + "packageId":"", + "parent":{ + "name":"Mediations", + "path":"folders/Extensions/AdMob/Mediations.yy", + }, + "productId":"", + "resourceType":"GMExtension", + "resourceVersion":"2.0", + "sourcedir":"", + "supportedTargets":-1, + "tvosclassname":null, + "tvosCocoaPodDependencies":"", + "tvosCocoaPods":"", + "tvoscodeinjection":"", + "tvosdelegatename":null, + "tvosmaccompilerflags":"", + "tvosmaclinkerflags":"", + "tvosplistinject":"", + "tvosProps":false, + "tvosSystemFrameworkEntries":[], + "tvosThirdPartyFrameworkEntries":[], +} \ No newline at end of file diff --git a/extensions/AdMobMeta/AdMobMeta.yy b/extensions/AdMobMeta/AdMobMeta.yy new file mode 100644 index 000000000..f1ceaa870 --- /dev/null +++ b/extensions/AdMobMeta/AdMobMeta.yy @@ -0,0 +1,62 @@ +{ + "$GMExtension":"", + "%Name":"AdMobMeta", + "androidactivityinject":"", + "androidclassname":"", + "androidcodeinjection":"\r\n\r\n implementation(\"com.google.ads.mediation:facebook:6.17.0.0\")\r\n\r\n\r\n", + "androidinject":"", + "androidmanifestinject":"", + "androidPermissions":[], + "androidProps":true, + "androidsourcedir":"", + "author":"", + "classname":"", + "copyToTargets":0, + "description":"", + "exportToGame":true, + "extensionVersion":"1.0.0", + "files":[], + "gradleinject":"\r\n implementation(\"com.google.ads.mediation:facebook:6.17.0.0\")\r\n", + "hasConvertedCodeInjection":true, + "helpfile":"", + "HTML5CodeInjection":"", + "html5Props":false, + "IncludedResources":[], + "installdir":"", + "iosCocoaPodDependencies":"", + "iosCocoaPods":"\r\npod 'GoogleMobileAdsMediationFacebook'\r\n", + "ioscodeinjection":"\r\n\r\npod 'GoogleMobileAdsMediationFacebook'\r\n\r\n", + "iosdelegatename":"", + "iosplistinject":"", + "iosProps":true, + "iosSystemFrameworkEntries":[], + "iosThirdPartyFrameworkEntries":[], + "license":"", + "maccompilerflags":"", + "maclinkerflags":"", + "macsourcedir":"", + "name":"AdMobMeta", + "options":[], + "optionsFile":"options.json", + "packageId":"", + "parent":{ + "name":"Mediations", + "path":"folders/Extensions/AdMob/Mediations.yy", + }, + "productId":"", + "resourceType":"GMExtension", + "resourceVersion":"2.0", + "sourcedir":"", + "supportedTargets":-1, + "tvosclassname":null, + "tvosCocoaPodDependencies":"", + "tvosCocoaPods":"", + "tvoscodeinjection":"", + "tvosdelegatename":null, + "tvosmaccompilerflags":"", + "tvosmaclinkerflags":"", + "tvosplistinject":"", + "tvosProps":false, + "tvosSystemFrameworkEntries":[], + "tvosThirdPartyFrameworkEntries":[], +} \ No newline at end of file diff --git a/extensions/AdMobPangle/AdMobPangle.yy b/extensions/AdMobPangle/AdMobPangle.yy new file mode 100644 index 000000000..9aad8c5a3 --- /dev/null +++ b/extensions/AdMobPangle/AdMobPangle.yy @@ -0,0 +1,62 @@ +{ + "$GMExtension":"", + "%Name":"AdMobPangle", + "androidactivityinject":"", + "androidclassname":"", + "androidcodeinjection":"\r\n\r\nrepositories\r\n{\r\n maven {\r\n url 'https://artifact.bytedance.com/repository/pangle/'\r\n }\r\n}\r\n\r\n\r\n\r\n\r\n implementation(\"com.google.ads.mediation:pangle:6.0.0.4.0\")\r\n\r\n\r\n\r\n", + "androidinject":"", + "androidmanifestinject":"", + "androidPermissions":[], + "androidProps":true, + "androidsourcedir":"", + "author":"", + "classname":"", + "copyToTargets":0, + "description":"", + "exportToGame":true, + "extensionVersion":"1.0.0", + "files":[], + "gradleinject":"\r\n implementation(\"com.google.ads.mediation:pangle:6.0.0.4.0\")\r\n", + "hasConvertedCodeInjection":true, + "helpfile":"", + "HTML5CodeInjection":"", + "html5Props":false, + "IncludedResources":[], + "installdir":"", + "iosCocoaPodDependencies":"", + "iosCocoaPods":"\r\npod 'GoogleMobileAdsMediationPangle'\r\n", + "ioscodeinjection":"\r\n\r\npod 'GoogleMobileAdsMediationPangle'\r\n\r\n", + "iosdelegatename":"", + "iosplistinject":"", + "iosProps":true, + "iosSystemFrameworkEntries":[], + "iosThirdPartyFrameworkEntries":[], + "license":"", + "maccompilerflags":"", + "maclinkerflags":"", + "macsourcedir":"", + "name":"AdMobPangle", + "options":[], + "optionsFile":"options.json", + "packageId":"", + "parent":{ + "name":"Mediations", + "path":"folders/Extensions/AdMob/Mediations.yy", + }, + "productId":"", + "resourceType":"GMExtension", + "resourceVersion":"2.0", + "sourcedir":"", + "supportedTargets":-1, + "tvosclassname":null, + "tvosCocoaPodDependencies":"", + "tvosCocoaPods":"", + "tvoscodeinjection":"", + "tvosdelegatename":null, + "tvosmaccompilerflags":"", + "tvosmaclinkerflags":"", + "tvosplistinject":"", + "tvosProps":false, + "tvosSystemFrameworkEntries":[], + "tvosThirdPartyFrameworkEntries":[], +} \ No newline at end of file diff --git a/extensions/AdMobUnityAds/AdMobUnityAds.yy b/extensions/AdMobUnityAds/AdMobUnityAds.yy new file mode 100644 index 000000000..bd0f3bdb5 --- /dev/null +++ b/extensions/AdMobUnityAds/AdMobUnityAds.yy @@ -0,0 +1,62 @@ +{ + "$GMExtension":"", + "%Name":"AdMobUnityAds", + "androidactivityinject":"", + "androidclassname":"", + "androidcodeinjection":"\r\n\r\n implementation(\"com.unity3d.ads:unity-ads:4.11.3\")\r\n implementation(\"com.google.ads.mediation:unity:4.12.0.0\")\r\n\r\n\r\n", + "androidinject":"", + "androidmanifestinject":"", + "androidPermissions":[], + "androidProps":true, + "androidsourcedir":"", + "author":"", + "classname":"", + "copyToTargets":0, + "description":"", + "exportToGame":true, + "extensionVersion":"1.0.0", + "files":[], + "gradleinject":"\r\n implementation(\"com.unity3d.ads:unity-ads:4.11.3\")\r\n implementation(\"com.google.ads.mediation:unity:4.12.0.0\")\r\n", + "hasConvertedCodeInjection":true, + "helpfile":"", + "HTML5CodeInjection":"", + "html5Props":false, + "IncludedResources":[], + "installdir":"", + "iosCocoaPodDependencies":"", + "iosCocoaPods":"\r\npod 'GoogleMobileAdsMediationUnity'\r\n", + "ioscodeinjection":"\r\n\r\npod 'GoogleMobileAdsMediationUnity'\r\n\r\n", + "iosdelegatename":"", + "iosplistinject":"", + "iosProps":true, + "iosSystemFrameworkEntries":[], + "iosThirdPartyFrameworkEntries":[], + "license":"", + "maccompilerflags":"", + "maclinkerflags":"", + "macsourcedir":"", + "name":"AdMobUnityAds", + "options":[], + "optionsFile":"options.json", + "packageId":"", + "parent":{ + "name":"Mediations", + "path":"folders/Extensions/AdMob/Mediations.yy", + }, + "productId":"", + "resourceType":"GMExtension", + "resourceVersion":"2.0", + "sourcedir":"", + "supportedTargets":-1, + "tvosclassname":null, + "tvosCocoaPodDependencies":"", + "tvosCocoaPods":"", + "tvoscodeinjection":"", + "tvosdelegatename":null, + "tvosmaccompilerflags":"", + "tvosmaclinkerflags":"", + "tvosplistinject":"", + "tvosProps":false, + "tvosSystemFrameworkEntries":[], + "tvosThirdPartyFrameworkEntries":[], +} \ No newline at end of file diff --git a/extensions/GooglePlayServices/AndroidSource/Java/YYGooglePlayServices.java b/extensions/GooglePlayServices/AndroidSource/Java/YYGooglePlayServices.java index 11a35b928..d4d8ebe1c 100644 --- a/extensions/GooglePlayServices/AndroidSource/Java/YYGooglePlayServices.java +++ b/extensions/GooglePlayServices/AndroidSource/Java/YYGooglePlayServices.java @@ -12,7 +12,7 @@ import android.widget.AbsoluteLayout; import android.view.ViewGroup; import android.view.View; -import androidx.annotation.NonNull;//import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.net.Uri; import android.graphics.Bitmap; import android.widget.ImageView; @@ -37,19 +37,15 @@ import java.util.ArrayList; +import com.google.android.gms.games.PlayGamesSdk; +import com.google.android.gms.games.PlayGames; +import com.google.android.gms.games.AuthenticationResult; + import com.google.android.gms.tasks.OnCompleteListener; import com.google.android.gms.tasks.Task; import com.google.android.gms.tasks.OnFailureListener; import com.google.android.gms.tasks.OnSuccessListener; -import com.google.android.gms.auth.api.Auth; - -import com.google.android.gms.auth.api.signin.GoogleSignIn; -import com.google.android.gms.auth.api.signin.GoogleSignInClient; -import com.google.android.gms.auth.api.signin.GoogleSignInResult; -import com.google.android.gms.auth.api.signin.GoogleSignInAccount; -import com.google.android.gms.auth.api.signin.GoogleSignInOptions; - import com.google.android.gms.games.Game; import com.google.android.gms.games.Games; import com.google.android.gms.games.AnnotatedData; @@ -58,6 +54,8 @@ import com.google.android.gms.games.PlayerBuffer; import com.google.android.gms.games.PlayersClient; +import com.google.android.gms.games.stats.PlayerStats; + import com.google.android.gms.games.achievement.Achievement; import com.google.android.gms.games.achievement.AchievementBuffer; @@ -93,123 +91,154 @@ public class YYGooglePlayServices extends RunnerSocial { private static final int EVENT_OTHER_SOCIAL = 70; - private GoogleSignInClient mGoogleSignInClient = null; - private GoogleSignInAccount signedInAccount = null; - private Player mPlayer = null; - private SnapshotsClient mSnapshotsClient; - private HashMap mapSnapshot; - private static Activity activity; - private static final int RC_SIGN_IN = 328; + private HashMap mapSnapshot; + private static Activity activity = RunnerActivity.CurrentActivity; - int Ind; + int AsyncInd = 0; public YYGooglePlayServices() { - Ind = 1; - activity = RunnerActivity.CurrentActivity; + PlayGamesSdk.initialize(activity); mapSnapshot = new HashMap(); - - int ms = 500; - if(Build.VERSION.SDK_INT <= 8) - ms = 3000;// 3 seconds - - if(GooglePlayServices_IsSignedIn() < 0.5)//if not signedin + } + + private double getAsyncInd() + { + AsyncInd++; + return(AsyncInd); + } + + public double GooglePlayServices_IsAvailable() + { + return (double) GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(activity) == ConnectionResult.SUCCESS ? 1.0 : 0.0; + } + + public double GooglePlayServices_SignIn() + { + final double ind = getAsyncInd(); + PlayGames.getGamesSignInClient(activity).signIn().addOnCompleteListener(new OnCompleteListener() { - new java.util.Timer().schedule( new java.util.TimerTask() + @Override + public void onComplete(@NonNull Task isAuthenticatedTask) { - @Override - public void run() + //Task error Verfication + try{isAuthenticatedTask.getResult();} + catch(Exception e) { - GooglePlayServices_signInSilently(); + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_SignIn"); + RunnerJNILib.DsMapAddDouble( dsMapIndex, "ind", ind ); + RunnerJNILib.DsMapAddDouble(dsMapIndex,"success",0); + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + return; } - },ms); - } + + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_SignIn"); + RunnerJNILib.DsMapAddDouble( dsMapIndex, "ind", ind ); + if(isAuthenticatedTask.isSuccessful()) + { + RunnerJNILib.DsMapAddDouble(dsMapIndex,"isAuthenticated",isAuthenticatedTask.getResult().isAuthenticated()?1.0:0.0); + RunnerJNILib.DsMapAddDouble(dsMapIndex,"success",1); + } + else + { + Exception exception = isAuthenticatedTask.getException(); + RunnerJNILib.DsMapAddDouble(dsMapIndex,"success",0); + } + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex,EVENT_OTHER_SOCIAL); + } + }); + + return(ind); } - @Override - public void onResume() + public double GooglePlayServices_IsAuthenticated() { - int ms = 500; - if(Build.VERSION.SDK_INT <= 8) - ms = 3000;// 3 seconds - - if(GooglePlayServices_IsSignedIn() < 0.5)//if not signedin + final double ind = getAsyncInd(); + PlayGames.getGamesSignInClient(activity).isAuthenticated().addOnCompleteListener(new OnCompleteListener() { - new java.util.Timer().schedule( new java.util.TimerTask() + @Override + public void onComplete(@NonNull Task isAuthenticatedTask) { - @Override - public void run() + //Task error Verfication + try{isAuthenticatedTask.getResult();} + catch(Exception e) + { + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_IsAuthenticated"); + RunnerJNILib.DsMapAddDouble( dsMapIndex, "ind", ind ); + RunnerJNILib.DsMapAddDouble(dsMapIndex,"success",0); + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + return; + } + + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_IsAuthenticated"); + RunnerJNILib.DsMapAddDouble( dsMapIndex, "ind", ind ); + if(isAuthenticatedTask.isSuccessful()) + { + RunnerJNILib.DsMapAddDouble(dsMapIndex,"isAuthenticated",isAuthenticatedTask.getResult().isAuthenticated()?1.0:0.0); + RunnerJNILib.DsMapAddDouble(dsMapIndex,"success",1); + } + else { - GooglePlayServices_signInSilently(); + Exception exception = isAuthenticatedTask.getException(); + RunnerJNILib.DsMapAddDouble(dsMapIndex,"success",0); } - },ms); - } - } - - public double GooglePlayServices_IsAvailable() - { - return (double) GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(activity) == ConnectionResult.SUCCESS ?1.0:0.0; + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex,EVENT_OTHER_SOCIAL); + } + }); + return(ind); } - private void signin_success(GoogleSignInAccount GoogleSignInAccount_) + public double GooglePlayServices_RequestServerSideAccess(String serverClientId, double forceRefreshToken) { - try + final double ind = getAsyncInd(); + PlayGames.getGamesSignInClient(activity).requestServerSideAccess(serverClientId,forceRefreshToken>=0.5).addOnCompleteListener(new OnCompleteListener() { - signedInAccount = GoogleSignInAccount_; - - if(GooglePlayServices_IsSignedIn() > 0.5) + @Override + public void onComplete(@NonNull Task task) { - GooglePlayServices_setViewForPopups(); - mSnapshotsClient = Games.getSnapshotsClient(activity,signedInAccount); + //Task error Verfication + try{task.getResult();} + catch(Exception e) + { + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_RequestServerSideAccess"); + RunnerJNILib.DsMapAddDouble( dsMapIndex, "ind", ind ); + RunnerJNILib.DsMapAddDouble(dsMapIndex,"success",0); + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + return; + } + + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_RequestServerSideAccess"); + RunnerJNILib.DsMapAddDouble( dsMapIndex, "ind", ind ); + if (task.isSuccessful()) + { + RunnerJNILib.DsMapAddString(dsMapIndex,"authCode",task.getResult()); + RunnerJNILib.DsMapAddDouble(dsMapIndex,"success",1); + } + else + { + Exception exception = task.getException(); + RunnerJNILib.DsMapAddDouble(dsMapIndex,"success",0); + } + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex,EVENT_OTHER_SOCIAL); } - } - catch(Exception e) - { - Log.e("yoyo", e.getMessage(), e); - } + }); + return(ind); } - @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { - - super.onActivityResult(requestCode, resultCode, data); - int dsMapIndex; switch(requestCode) { - - case RC_SIGN_IN: - - dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); - RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_SignIn" ); - - GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data); - - boolean ok = false; - if(result != null) - if(result.isSuccess()) - ok = true; - - if(ok) - { - RunnerJNILib.DsMapAddDouble( dsMapIndex, "success", 1 ); - signin_success(result.getSignInAccount()); - } - else - { - RunnerJNILib.DsMapAddString(dsMapIndex, "errorMessage:",result.getStatus().getStatusMessage()); - RunnerJNILib.DsMapAddDouble(dsMapIndex, "errorCode:",(double) resultCode); - RunnerJNILib.DsMapAddDouble(dsMapIndex, "success", 0 ); - } - - RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); - - - break; case RC_SAVED_GAMES: @@ -217,6 +246,7 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_SavedGames_ShowSavedGamesUI_OnExit"); + RunnerJNILib.DsMapAddDouble( dsMapIndex, "ind", ind_ShowSavedGamesUI ); RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); } else @@ -226,7 +256,8 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) SnapshotMetadata snapshotMetadata = data.getParcelableExtra(SnapshotsClient.EXTRA_SNAPSHOT_METADATA); dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_SavedGames_ShowSavedGamesUI_OnOpen"); - RunnerJNILib.DsMapAddString( dsMapIndex, "snapshotMetadata", SnapshotMetadataJSON(snapshotMetadata)); + RunnerJNILib.DsMapAddDouble( dsMapIndex, "ind", ind_ShowSavedGamesUI ); + RunnerJNILib.DsMapAddString( dsMapIndex, "snapshotMetadata", SnapshotMetadataJSON(snapshotMetadata).toString()); RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); GooglePlayServices_SavedGames_Open(snapshotMetadata.getUniqueName()); } @@ -235,6 +266,7 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_SavedGames_ShowSavedGamesUI_OnNew"); + RunnerJNILib.DsMapAddDouble( dsMapIndex, "ind", ind_ShowSavedGamesUI ); RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); } } @@ -255,167 +287,44 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) } } - ////////////////////////////////////////////////////////////////Sign In - - public double GooglePlayServices_IsSignedIn() - { - if(GoogleSignIn.getLastSignedInAccount(activity) != null && signedInAccount != null) - return 1.0; - else - return 0.0; - } - - - public void GooglePlayServices_signInSilently() - { - GoogleSignInClient signInClient = GooglePlayServices_signInClient(); - signInClient.silentSignIn().addOnCompleteListener(activity,new OnCompleteListener() - { - @Override - public void onComplete(@NonNull Task task) - { - int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); - RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_SignIn" ); - - if (task.isSuccessful()) - { - RunnerJNILib.DsMapAddDouble( dsMapIndex, "success", 1 ); - signin_success(task.getResult()); - } - else - { - Exception exception = task.getException(); - RunnerJNILib.DsMapAddDouble( dsMapIndex, "success", 0 ); - } - RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); - } - }); - } - - - public void GooglePlayServices_StartSignInIntent() - { - Log.i("yoyo","GooglePlayServices_StartSignInIntent"); - GoogleSignInClient signInClient = GooglePlayServices_signInClient(); - Intent intent = signInClient.getSignInIntent(); - activity.startActivityForResult(intent, RC_SIGN_IN); - } - - - public void GooglePlayServices_SignOut() - { - GoogleSignInClient signInClient = GooglePlayServices_signInClient(); - signInClient.signOut().addOnCompleteListener(activity,new OnCompleteListener() - { - @Override - public void onComplete(@NonNull Task task) - { - // at this point, the user is signed out. - - int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); - RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_SignOut" ); - - if (task.isSuccessful()) - { - // Task completed successfully - task.getResult(); - RunnerJNILib.DsMapAddDouble( dsMapIndex, "success", 1 ); - } - else - { - // Task failed with an exception - Exception exception = task.getException(); - RunnerJNILib.DsMapAddDouble( dsMapIndex, "success", 0 ); - } - - RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); - } - }); - } + // ==================================== + // Player Info + // ==================================== - public void GooglePlayServices_RevokeAccess() + public double GooglePlayServices_Player_Current() { - GoogleSignInClient signInClient = GooglePlayServices_signInClient(); - signInClient.revokeAccess().addOnCompleteListener(activity,new OnCompleteListener() + final double ind = getAsyncInd(); + + PlayGames.getPlayersClient(activity).getCurrentPlayer().addOnCompleteListener(new OnCompleteListener() { @Override - public void onComplete(@NonNull Task task) + public void onComplete(@NonNull Task task) { - // at this point, the user is signed out. - - int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); - RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_RevokeAccess" ); - - if (task.isSuccessful()) - { - // Task completed successfully - task.getResult(); - RunnerJNILib.DsMapAddDouble( dsMapIndex, "success", 1 ); - } - else + //Task error Verfication + try{task.getResult();} + catch(Exception e) { - // Task failed with an exception - Exception exception = task.getException(); - RunnerJNILib.DsMapAddDouble( dsMapIndex, "success", 0 ); + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_Player_Current"); + RunnerJNILib.DsMapAddDouble( dsMapIndex, "ind", ind ); + RunnerJNILib.DsMapAddDouble(dsMapIndex,"success",0); + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + return; } - RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); - - } - }); - } - //////////////////////////////////////////////////////////// Account Info - - public String GooglePlayServices_GetAccount() - { - // https://developers.google.com/android/reference/com/google/android/gms/auth/api/signin/GoogleSignInAccount - HashMap map = new HashMap(); - - if(signedInAccount.getDisplayName()!=null) - map.put("displayName",signedInAccount.getDisplayName()); - if(signedInAccount.getEmail()!=null) - map.put("email",signedInAccount.getEmail()); - if(signedInAccount.getFamilyName()!=null) - map.put("familyName",signedInAccount.getFamilyName()); - if(signedInAccount.getGivenName()!=null) - map.put("givenName",signedInAccount.getGivenName()); - if(signedInAccount.getIdToken()!=null) - map.put("IdToken",signedInAccount.getIdToken()); - if(signedInAccount.getPhotoUrl()!=null) - map.put("photoUrl",signedInAccount.getPhotoUrl().toString()); - if(signedInAccount.getServerAuthCode()!=null) - map.put("serverAuthCode",signedInAccount.getServerAuthCode()); - - JSONObject obj = new JSONObject(map); - - return obj.toString(); - } - - //////////////////////////////////////////////////////////////////Player Info - - //https://developers.google.com/android/reference/com/google/android/gms/games/PlayersClient - public void GooglePlayServices_Player_Current() - { - PlayersClient playersClient = Games.getPlayersClient(activity, signedInAccount); - playersClient.getCurrentPlayer().addOnCompleteListener(new OnCompleteListener() - { - @Override - public void onComplete(@NonNull Task task) - { int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_Player_Current" ); + RunnerJNILib.DsMapAddDouble( dsMapIndex, "ind", ind ); if (task.isSuccessful()) { - // Task completed successfully Player mPlayer = task.getResult(); - RunnerJNILib.DsMapAddString( dsMapIndex, "player", PlayerJSON(mPlayer) ); + RunnerJNILib.DsMapAddString( dsMapIndex, "player", PlayerJSON(mPlayer).toString() ); RunnerJNILib.DsMapAddDouble( dsMapIndex, "success", 1 ); } else { - // Task failed with an exception Exception exception = task.getException(); RunnerJNILib.DsMapAddDouble( dsMapIndex, "success", 0 ); } @@ -423,17 +332,29 @@ public void onComplete(@NonNull Task task) RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); } }); + + return(ind); } public void GooglePlayServices_Player_CurrentID() { - PlayersClient playersClient = Games.getPlayersClient(activity, signedInAccount); - playersClient.getCurrentPlayerId().addOnCompleteListener(new OnCompleteListener() + PlayGames.getPlayersClient(activity).getCurrentPlayerId().addOnCompleteListener(new OnCompleteListener() { @Override public void onComplete(@NonNull Task task) { + //Task error Verfication + try{task.getResult();} + catch(Exception e) + { + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_Player_CurrentID"); + RunnerJNILib.DsMapAddDouble(dsMapIndex,"success",0); + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + return; + } + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); RunnerJNILib.DsMapAddString(dsMapIndex,"type", "GooglePlayServices_Player_CurrentID"); @@ -452,36 +373,56 @@ public void onComplete(@NonNull Task task) } }); } - - - ////////////////////////////////////////////////////////////////////////////////Achievements - + + // ==================================== + // Achievements + // ==================================== + private static final int RC_ACHIEVEMENT_UI = 9003; public void GooglePlayServices_Achievements_Show() { - - Games.getAchievementsClient(activity, signedInAccount).getAchievementsIntent().addOnSuccessListener(new OnSuccessListener() + PlayGames.getAchievementsClient(activity).getAchievementsIntent().addOnSuccessListener(new OnSuccessListener() { @Override public void onSuccess(Intent intent) { - activity.startActivityForResult(intent,RC_ACHIEVEMENT_UI); + try + { + activity.startActivityForResult(intent, RC_ACHIEVEMENT_UI); + } + catch(Exception e) + { + Log.e("yoyo", "ERROR GooglePlayServices_Achievements_Show: " + e.getMessage(), e); + } } }); } - public void GooglePlayServices_Achievements_Increment(final String arch_id,double steps) + public double GooglePlayServices_Achievements_Increment(final String arch_id,double steps) { - Games.getAchievementsClient(activity, signedInAccount).incrementImmediate(arch_id, (int)steps).addOnCompleteListener(new OnCompleteListener() + final double ind = getAsyncInd(); + PlayGames.getAchievementsClient(activity).incrementImmediate(arch_id, (int)steps).addOnCompleteListener(new OnCompleteListener() { @Override public void onComplete(@NonNull Task task) { + //Task error Verfication + try{task.getResult();} + catch(Exception e) + { + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_Achievements_Increment"); + RunnerJNILib.DsMapAddDouble( dsMapIndex, "ind", ind ); + RunnerJNILib.DsMapAddDouble(dsMapIndex,"success",0); + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + return; + } + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_Achievements_Increment" ); RunnerJNILib.DsMapAddString( dsMapIndex, "achievement_id", arch_id); - + RunnerJNILib.DsMapAddDouble( dsMapIndex, "ind", ind ); if (task.isSuccessful()) { task.getResult(); @@ -496,18 +437,33 @@ public void onComplete(@NonNull Task task) RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); } }); + return(ind); } - public void GooglePlayServices_Achievements_Reveal(final String arch_id) + public double GooglePlayServices_Achievements_Reveal(final String arch_id) { - Games.getAchievementsClient(activity, signedInAccount).revealImmediate(arch_id).addOnCompleteListener(new OnCompleteListener() + final double ind = getAsyncInd(); + PlayGames.getAchievementsClient(activity).revealImmediate(arch_id).addOnCompleteListener(new OnCompleteListener() { @Override public void onComplete(@NonNull Task task) { + //Task error Verfication + try{task.getResult();} + catch(Exception e) + { + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_Achievements_Reveal"); + RunnerJNILib.DsMapAddDouble( dsMapIndex, "ind", ind ); + RunnerJNILib.DsMapAddDouble(dsMapIndex,"success",0); + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + return; + } + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_Achievements_Reveal" ); RunnerJNILib.DsMapAddString( dsMapIndex, "achievement_id", arch_id); + RunnerJNILib.DsMapAddDouble( dsMapIndex, "ind", ind ); if (task.isSuccessful()) { @@ -523,18 +479,33 @@ public void onComplete(@NonNull Task task) RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); } }); + return(ind); } - public void GooglePlayServices_Achievements_SetSteps(final String arch_id,double steps) + public double GooglePlayServices_Achievements_SetSteps(final String arch_id,double steps) { - Games.getAchievementsClient(activity, signedInAccount).setStepsImmediate(arch_id, (int)steps).addOnCompleteListener(new OnCompleteListener() + final double ind = getAsyncInd(); + PlayGames.getAchievementsClient(activity).setStepsImmediate(arch_id, (int)steps).addOnCompleteListener(new OnCompleteListener() { @Override public void onComplete(@NonNull Task task) { + //Task error Verfication + try{task.getResult();} + catch(Exception e) + { + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_Achievements_SetSteps"); + RunnerJNILib.DsMapAddDouble( dsMapIndex, "ind", ind ); + RunnerJNILib.DsMapAddDouble(dsMapIndex,"success",0); + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + return; + } + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_Achievements_SetSteps" ); RunnerJNILib.DsMapAddString( dsMapIndex, "achievement_id", arch_id); + RunnerJNILib.DsMapAddDouble( dsMapIndex, "ind", ind ); if (task.isSuccessful()) { @@ -550,18 +521,34 @@ public void onComplete(@NonNull Task task) RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); } }); + return(ind); } - public void GooglePlayServices_Achievements_Unlock(final String arch_id) + public double GooglePlayServices_Achievements_Unlock(final String arch_id) { - Games.getAchievementsClient(activity, signedInAccount).unlockImmediate(arch_id).addOnCompleteListener(new OnCompleteListener() + final double ind = getAsyncInd(); + + PlayGames.getAchievementsClient(activity).unlockImmediate(arch_id).addOnCompleteListener(new OnCompleteListener() { @Override public void onComplete(@NonNull Task task) { + //Task error Verfication + try{task.getResult();} + catch(Exception e) + { + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_Achievements_Unlock"); + RunnerJNILib.DsMapAddDouble( dsMapIndex, "ind", ind ); + RunnerJNILib.DsMapAddDouble(dsMapIndex,"success",0); + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + return; + } + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_Achievements_Unlock" ); RunnerJNILib.DsMapAddString( dsMapIndex, "achievement_id", arch_id); + RunnerJNILib.DsMapAddDouble( dsMapIndex, "ind", ind ); if (task.isSuccessful()) { @@ -576,16 +563,30 @@ public void onComplete(@NonNull Task task) RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); } }); + return(ind); } - public void GooglePlayServices_Achievements_GetStatus(double force_reload) + public double GooglePlayServices_Achievements_GetStatus(double force_reload) { - Games.getAchievementsClient(activity, signedInAccount).load(force_reload >= 0.5).addOnCompleteListener(new OnCompleteListener>() + final double ind = getAsyncInd(); + PlayGames.getAchievementsClient(activity).load(force_reload >= 0.5).addOnCompleteListener(new OnCompleteListener>() { @Override public void onComplete(@NonNull Task> task) { + //Task error Verfication + try{task.getResult();} + catch(Exception e) + { + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_Achievements_GetStatus"); + RunnerJNILib.DsMapAddDouble( dsMapIndex, "ind", ind ); + RunnerJNILib.DsMapAddDouble(dsMapIndex,"success",0); + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + return; + } + AnnotatedData mAnnotated = task.getResult(); AchievementBuffer mAchievementBuffer = mAnnotated.get(); @@ -602,10 +603,12 @@ public void onComplete(@NonNull Task> task) map.put("description",achievement.getDescription()); map.put("lastUpdatedTimestamp",(double)achievement.getLastUpdatedTimestamp()); map.put("name",achievement.getName()); - map.put("revealedImage",achievement.getRevealedImageUri().toString()); + if(achievement.getRevealedImageUri() != null) + map.put("revealedImage",achievement.getRevealedImageUri().toString()); map.put("state",(double)achievement.getState()); map.put("typeAchievement",(double)achievement.getType()); - map.put("unlockedImage",achievement.getUnlockedImageUri().toString()); + if(achievement.getUnlockedImageUri() != null) + map.put("unlockedImage",achievement.getUnlockedImageUri().toString()); map.put("xpValue",(double)achievement.getXpValue()); if(achievement.getType() == Achievement.TYPE_INCREMENTAL) @@ -620,6 +623,7 @@ public void onComplete(@NonNull Task> task) } int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddDouble( dsMapIndex, "ind", ind ); RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_Achievements_GetStatus"); RunnerJNILib.DsMapAddDouble( dsMapIndex, "success", task.isSuccessful()? 1:0); RunnerJNILib.DsMapAddString( dsMapIndex, "data", list.toString()); @@ -628,44 +632,61 @@ public void onComplete(@NonNull Task> task) catch(Exception e) { int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddDouble( dsMapIndex, "ind", ind ); RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_Achievements_GetStatus"); RunnerJNILib.DsMapAddDouble( dsMapIndex, "success",0); RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); } } }); + return(ind); } - - ///////////////////////////////////////////////////////////////////////////////Learderboards + // ==================================== + // Leaderboards + // ==================================== private static final int RC_LEADERBOARD_UI = 9004; public void GooglePlayServices_Leaderboard_ShowAll() { - Games.getLeaderboardsClient(activity,signedInAccount).getAllLeaderboardsIntent().addOnSuccessListener(new OnSuccessListener() + PlayGames.getLeaderboardsClient(activity).getAllLeaderboardsIntent().addOnSuccessListener(new OnSuccessListener() { @Override public void onSuccess(Intent intent) { - activity.startActivityForResult(intent, RC_LEADERBOARD_UI); + try + { + activity.startActivityForResult(intent, RC_LEADERBOARD_UI); + } + catch(Exception e) + { + Log.e("yoyo", "ERROR GooglePlayServices_Leaderboard_ShowAll: " + e.getMessage(), e); + } } }); } public void GooglePlayServices_Leaderboard_Show(String leader_id) { - Games.getLeaderboardsClient(activity,signedInAccount).getLeaderboardIntent(leader_id).addOnSuccessListener(new OnSuccessListener() + PlayGames.getLeaderboardsClient(activity).getLeaderboardIntent(leader_id).addOnSuccessListener(new OnSuccessListener() { @Override public void onSuccess(Intent intent) { - activity.startActivityForResult(intent, RC_LEADERBOARD_UI); + try + { + activity.startActivityForResult(intent, RC_LEADERBOARD_UI); + } + catch(Exception e) + { + Log.e("yoyo", "ERROR GooglePlayServices_Leaderboard_Show: " + e.getMessage(), e); + } } }); } - static String PlayerJSON(Player mPlayer) + static JSONObject PlayerJSON(Player mPlayer) { //https://developers.google.com/android/reference/com/google/android/gms/games/Player @@ -682,8 +703,6 @@ static String PlayerJSON(Player mPlayer) map.put("hiResImageUri",mPlayer.getHiResImageUri().toString()); if(mPlayer.getIconImageUri() != null) map.put("iconImageUri",mPlayer.getIconImageUri().toString()); - //if(mPlayer.getLastPlayedWithTimestamp() != null) - map.put("lastPlayedWithTimestamp",(double)mPlayer.getLastPlayedWithTimestamp()); //if(mPlayer.getLevelInfo().getCurrentXpTotal() != null) map.put("currentXpTotal",(double)mPlayer.getLevelInfo().getCurrentXpTotal()); //if(mPlayer.getLevelInfo().getLastLevelUpTimestamp() != null) @@ -719,20 +738,34 @@ static String PlayerJSON(Player mPlayer) JSONObject obj = new JSONObject(map); - return obj.toString(); + return obj; } - public void GooglePlayServices_Leaderboard_SubmitScore(final String leader_id,final double score,final String scoreTag) + public double GooglePlayServices_Leaderboard_SubmitScore(final String leader_id,final double score,final String scoreTag) { - Games.getLeaderboardsClient(activity,signedInAccount).submitScoreImmediate(leader_id,(long) score, scoreTag).addOnCompleteListener(new OnCompleteListener() + final double ind = getAsyncInd(); + + PlayGames.getLeaderboardsClient(activity).submitScoreImmediate(leader_id,(long) score, scoreTag).addOnCompleteListener(new OnCompleteListener() { @Override public void onComplete(@NonNull Task task) { + //Task error Verfication + try{task.getResult();} + catch(Exception e) + { + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_Leaderboard_SubmitScore"); + RunnerJNILib.DsMapAddDouble( dsMapIndex, "ind", ind ); + RunnerJNILib.DsMapAddDouble(dsMapIndex,"success",0); + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + return; + } + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); RunnerJNILib.DsMapAddString(dsMapIndex, "type", "GooglePlayServices_Leaderboard_SubmitScore" ); - + RunnerJNILib.DsMapAddDouble( dsMapIndex, "ind", ind ); RunnerJNILib.DsMapAddString(dsMapIndex,"leaderboardId",leader_id); RunnerJNILib.DsMapAddDouble(dsMapIndex,"score",score); RunnerJNILib.DsMapAddString(dsMapIndex,"scoreTag",scoreTag); @@ -787,21 +820,7 @@ public void onComplete(@NonNull Task task) RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); } }); - } - - String mClientID = ""; - public void GooglePlayServices_SetClientID(String clientID) - { - mClientID = clientID; - } - - - public String GooglePlayServices_GetServerAuthCode() - { - if(signedInAccount.getServerAuthCode() == null) - return "NULL"; - - return signedInAccount.getServerAuthCode(); + return(ind); } static JSONObject LeaderboardScoreJSON(LeaderboardScore mLeaderboardScore) throws Exception @@ -848,15 +867,29 @@ static String LeaderboardJSON(Leaderboard mLeaderboard) return obj.toString(); } - public void GooglePlayServices_Leaderboard_LoadPlayerCenteredScores(String leaderboardId, double span, double leaderboardCollection, double maxResults, double forceReload) + public double GooglePlayServices_Leaderboard_LoadPlayerCenteredScores(String leaderboardId, double span, double leaderboardCollection, double maxResults, double forceReload) { - Games.getLeaderboardsClient(activity,signedInAccount) + final double ind = getAsyncInd(); + + PlayGames.getLeaderboardsClient(activity) .loadPlayerCenteredScores(leaderboardId, (int) span, (int) leaderboardCollection, (int) maxResults, forceReload >= 0.5) .addOnCompleteListener(new OnCompleteListener>() { @Override public void onComplete(@NonNull Task> task) { + //Task error Verfication + try{task.getResult();} + catch(Exception e) + { + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_Leaderboard_LoadPlayerCenteredScores"); + RunnerJNILib.DsMapAddDouble( dsMapIndex, "ind", ind ); + RunnerJNILib.DsMapAddDouble(dsMapIndex,"success",0); + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + return; + } + try { // This can thrown an extension needs to be inside the try/catch @@ -874,6 +907,9 @@ public void onComplete(@NonNull Task= 0.5) .addOnCompleteListener(new OnCompleteListener>() { @Override public void onComplete(@NonNull Task> task) { + //Task error Verfication + try{task.getResult();} + catch(Exception e) + { + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_Leaderboard_LoadTopScores"); + RunnerJNILib.DsMapAddDouble( dsMapIndex, "ind", ind ); + RunnerJNILib.DsMapAddDouble(dsMapIndex,"success",0); + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + return; + } + try { // This can thrown an extension needs to be inside the try/catch @@ -922,6 +973,7 @@ public void onComplete(@NonNull Task map = new HashMap(); - - //if(mSnapshotMetadata.getCoverImageAspectRatio() != null) - map.put("coverImageAspectRatio",(double)mSnapshotMetadata.getCoverImageAspectRatio()); - if(mSnapshotMetadata.getCoverImageUri() != null) - map.put("coverImageUri",mSnapshotMetadata.getCoverImageUri().toString()); - if(mSnapshotMetadata.getDescription() != null) - map.put("description",mSnapshotMetadata.getDescription()); - if(mSnapshotMetadata.getDeviceName() != null) - map.put("deviceName",mSnapshotMetadata.getDeviceName()); - map.put("game",gameJSON(mSnapshotMetadata.getGame())); - //if(mSnapshotMetadata.getLastModifiedTimestamp() != null) - map.put("lastModifiedTimestamp",(double)mSnapshotMetadata.getLastModifiedTimestamp()); - //if( != null) - map.put("owner",PlayerJSON(mSnapshotMetadata.getOwner())); - //if(mSnapshotMetadata.getPlayedTime() != null) - map.put("playedTime",(double)mSnapshotMetadata.getPlayedTime()); - //if(mSnapshotMetadata.getProgressValue() != null) - map.put("progressValue",(double)mSnapshotMetadata.getProgressValue()); - if(mSnapshotMetadata.getUniqueName() != null) - map.put("uniqueName",mSnapshotMetadata.getUniqueName()); - - if(mSnapshotMetadata.hasChangePending()) - map.put("hasChangePending",(double) 1.0); - else - map.put("hasChangePending",(double) 0.0); + static JSONObject GameJSON(Game game) { + JSONObject jsonObject = new JSONObject(); - JSONObject obj = new JSONObject(map); - - return obj; - } + try { + jsonObject.put("areSnapshotsEnabled", game.areSnapshotsEnabled() ? 1.0 : 0.0); + jsonObject.put("achievementTotalCount", game.getAchievementTotalCount()); + jsonObject.put("applicationId", game.getApplicationId()); + jsonObject.put("description", game.getDescription()); + jsonObject.put("developerName", game.getDeveloperName()); + String displayName = game.getDisplayName(); + if (displayName != null) { + jsonObject.put("displayName", displayName); + } + Uri featuredImageUri = game.getFeaturedImageUri(); + if (featuredImageUri != null) { + jsonObject.put("featuredImageUri", featuredImageUri.toString()); + } + + jsonObject.put("gamepadSupport", game.hasGamepadSupport() ? 1.0 : 0.0); + + Uri hiResImageUri = game.getHiResImageUri(); + if (hiResImageUri != null) { + jsonObject.put("hiResImageUri", hiResImageUri.toString()); + } + Uri iconImageUri = game.getIconImageUri(); + if (iconImageUri != null) { + jsonObject.put("iconImageUri", iconImageUri.toString()); + } + + jsonObject.put("leaderboardCount", game.getLeaderboardCount()); + jsonObject.put("primaryCategory", game.getPrimaryCategory()); + jsonObject.put("secondaryCategory", game.getSecondaryCategory()); + jsonObject.put("themeColor", game.getThemeColor()); + + } catch (Exception e) { + Log.e("yoyo", "GameJSON : failed to create Game json object - " + e.getMessage()); + } + + return jsonObject; + } + private static final int RC_SAVED_GAMES = 9009; - public void GooglePlayServices_SavedGames_ShowSavedGamesUI(String title, double button_add, double button_delete, double max) - { - try - { - boolean button_add_; - if(button_add > 0.5) - button_add_ = true; - else - button_add_ = false; - - boolean button_delete_; - if(button_delete > 0.5) - button_delete_ = true; - else - button_delete_ = false; + private double ind_ShowSavedGamesUI; + + public double GooglePlayServices_SavedGames_ShowSavedGamesUI(String title, double buttonAdd, double buttonDelete, double max) { + ind_ShowSavedGamesUI = getAsyncInd(); - mSnapshotsClient.getSelectSnapshotIntent(title, button_add_, button_delete_, (int)max).addOnSuccessListener(new OnSuccessListener() - { - @Override - public void onSuccess(Intent intent) - { + boolean showAddButton = buttonAdd > 0.5; + boolean showDeleteButton = buttonDelete > 0.5; + int maxToShow = (int) max; + + SnapshotsClient snapshotsClient = PlayGames.getSnapshotsClient(activity); + snapshotsClient.getSelectSnapshotIntent(title, showAddButton, showDeleteButton, maxToShow) + .addOnSuccessListener(intent -> { + try { activity.startActivityForResult(intent, RC_SAVED_GAMES); + } catch (Exception e) { + Log.e("yoyo", "GooglePlayServices_SavedGames_ShowSavedGamesUI: failed to show save games UI - " + e.getMessage()); } }); - } - catch(Exception e) - { - Log.e("yoyo", e.getMessage(), e); - } + + return ind_ShowSavedGamesUI; } + public double GooglePlayServices_SavedGames_CommitAndClose(final String name, final String desc, final String data, final String coverImagePath) { + final double asyncIndex = getAsyncInd(); - public void GooglePlayServices_SavedGames_CommitAndClose(String name , final String desc, final String data,final String pathConverIamge) // Snapshot snapshot,byte[] data, Bitmap coverImage - { - boolean data_Ok; - byte[] data_; - try - { - data_ = data.getBytes("UTF-8"); - data_Ok = true; - } - catch(Exception e) - { - data_Ok = false; - data_ = null; - } - - if (data_Ok) - { - Snapshot snapshot = mapSnapshot.get(name); - snapshot.getSnapshotContents().writeBytes(data_); - - SnapshotMetadataChange.Builder metadataChange_builder = new SnapshotMetadataChange.Builder(); - - String localImgPath = activity.getFilesDir() + "/" + pathConverIamge; - File imgFile = new File(localImgPath); - - if(desc != "") - metadataChange_builder.setDescription(desc); - - if(imgFile.exists()) - { - Bitmap myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath()); - if(myBitmap != null) - metadataChange_builder.setCoverImage(myBitmap); + Snapshot snapshot = mapSnapshot.get(name); + if (snapshot == null) { + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString(dsMapIndex, "type", "GooglePlayServices_SavedGames_CommitAndClose"); + RunnerJNILib.DsMapAddDouble(dsMapIndex, "ind", asyncIndex); + RunnerJNILib.DsMapAddDouble(dsMapIndex, "success", 0); + Log.i("yoyo", "GooglePlayServices_SavedGames_CommitAndClose : couldn't find snapshot with name '" + name + "'"); + + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + + } else { + + try { + byte[] dataBytes = data.getBytes("UTF_8"); + snapshot.getSnapshotContents().writeBytes(dataBytes); + } catch (Exception e) { + Log.i("yoyo", "GooglePlayServices_SavedGames_CommitAndClose: Exception while converting data to bytes - " + e.getMessage()); } - - SnapshotMetadataChange metadataChange = metadataChange_builder.build(); - - mSnapshotsClient.commitAndClose(snapshot, metadataChange).addOnCompleteListener(new OnCompleteListener() - { - @Override - public void onComplete(@NonNull Task task) + + SnapshotMetadataChange.Builder metadataChangeBuilder = new SnapshotMetadataChange.Builder(); + + if (!desc.isEmpty()) { + metadataChangeBuilder.setDescription(desc); + } + + if (!coverImagePath.isEmpty()) { + String localImgPath = activity.getFilesDir() + "/" + coverImagePath; + File imgFile = new File(localImgPath); + + if (imgFile.exists()) { + Bitmap coverImageBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath()); + if (coverImageBitmap != null) { + metadataChangeBuilder.setCoverImage(coverImageBitmap); + } + } + } + + SnapshotMetadataChange metadataChange = metadataChangeBuilder.build(); + SnapshotsClient snapshotsClient = PlayGames.getSnapshotsClient(activity); + + snapshotsClient.commitAndClose(snapshot, metadataChange).addOnCompleteListener(task -> { + + //Task error Verfication + try{task.getResult();} + catch(Exception e) { int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); - RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_SavedGames_CommitAndClose" ); - - if (task.isSuccessful()) - { - SnapshotMetadata snapshotMetadata = task.getResult(); - RunnerJNILib.DsMapAddString( dsMapIndex, "snapshotMetadata", SnapshotMetadataJSON(snapshotMetadata)); - RunnerJNILib.DsMapAddDouble( dsMapIndex, "success", 1 ); - } - else - { - Exception exception = task.getException(); - RunnerJNILib.DsMapAddDouble( dsMapIndex, "success", 0 ); - } + RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_SavedGames_CommitAndClose"); + RunnerJNILib.DsMapAddDouble( dsMapIndex, "ind", asyncIndex ); + RunnerJNILib.DsMapAddDouble(dsMapIndex,"success",0); RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + return; } + + boolean wasSuccessful = task.isSuccessful(); + + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString(dsMapIndex, "type", "GooglePlayServices_SavedGames_CommitAndClose"); + RunnerJNILib.DsMapAddDouble(dsMapIndex, "ind", asyncIndex); + RunnerJNILib.DsMapAddDouble(dsMapIndex, "success", wasSuccessful ? 1.0 : 0.0); + + if (wasSuccessful) { + SnapshotMetadata snapshotMetadata = task.getResult(); + RunnerJNILib.DsMapAddString(dsMapIndex, "snapshotMetadata", SnapshotMetadataJSON(snapshotMetadata).toString()); + mapSnapshot.remove(name); + } else { + Exception exception = task.getException(); + Log.i("yoyo", "GooglePlayServices_SavedGames_CommitAndClose: failed to commit and close the saved game - " + exception.getMessage()); + } + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); }); - + } - + + return asyncIndex; } - public void GooglePlayServices_SavedGames_CommitNew(String name, final String desc, final String data,final String pathConverIamge) // Snapshot snapshot,byte[] data, Bitmap coverImage - { + public double GooglePlayServices_SavedGames_CommitNew(final String name, final String desc, final String data, final String coverImagePath) { boolean createIfNotFound = true; double conflictPolicy = 1; - - - mSnapshotsClient.open(name,createIfNotFound,(int)conflictPolicy).addOnCompleteListener(new OnCompleteListener >() - { - @Override - public void onComplete(@NonNull Task> task) - { - boolean data_Ok; - byte[] data_; - try - { - data_ = data.getBytes("UTF-8"); - data_Ok = true; - } - catch(Exception e) - { - data_Ok = false; - data_ = null; - } - - if(task.isSuccessful() && !task.getResult().isConflict() && data_Ok) - { - DataOrConflict mDataOrConflict = task.getResult(); - Snapshot snapshot = (Snapshot)mDataOrConflict.getData(); - mapSnapshot.put(snapshot.getMetadata().getUniqueName(),snapshot); - snapshot.getSnapshotContents().writeBytes(data_); + final double asyncIndex = getAsyncInd(); - SnapshotMetadataChange.Builder metadataChange_builder = new SnapshotMetadataChange.Builder(); - metadataChange_builder.setDescription(desc); + SnapshotsClient snapshotsClient = PlayGames.getSnapshotsClient(activity); + snapshotsClient.open(name, createIfNotFound, (int) conflictPolicy).addOnCompleteListener(task -> + { - if(pathConverIamge != "") + //Task error Verfication + try{task.getResult();} + catch(Exception e) { - String localImgPath = activity.getFilesDir() + "/" + pathConverIamge; - File imgFile = new File(localImgPath); - - if(imgFile.exists()) - { - Bitmap myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath()); - if(myBitmap != null) - metadataChange_builder.setCoverImage(myBitmap); - } + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_SavedGames_CommitNew"); + RunnerJNILib.DsMapAddDouble( dsMapIndex, "ind", asyncIndex ); + RunnerJNILib.DsMapAddDouble(dsMapIndex,"success",0); + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + return; } - - SnapshotMetadataChange metadataChange = metadataChange_builder.build(); + + boolean wasSuccessful = task.isSuccessful(); - mSnapshotsClient.commitAndClose(snapshot, metadataChange).addOnCompleteListener(new OnCompleteListener() - { - @Override - public void onComplete(@NonNull Task task) - { - int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); - RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_SavedGames_CommitNew" ); - - if (task.isSuccessful()) - { - SnapshotMetadata snapshotMetadata = task.getResult(); - RunnerJNILib.DsMapAddString( dsMapIndex, "snapshotMetadata", SnapshotMetadataJSON(snapshotMetadata)); - RunnerJNILib.DsMapAddDouble( dsMapIndex, "success", 1 ); - } - else - { - Exception exception = task.getException(); - RunnerJNILib.DsMapAddDouble( dsMapIndex, "success", 0 ); - Log.i("yoyo",exception.getMessage()); + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString(dsMapIndex, "type", "GooglePlayServices_SavedGames_CommitNew"); + RunnerJNILib.DsMapAddDouble(dsMapIndex, "ind", asyncIndex); + RunnerJNILib.DsMapAddDouble(dsMapIndex, "success", wasSuccessful ? 1.0 : 0.0); + + if (wasSuccessful && !task.getResult().isConflict()) { + DataOrConflict dataOrConflict = task.getResult(); + Snapshot snapshot = dataOrConflict.getData(); + mapSnapshot.put(snapshot.getMetadata().getUniqueName(), snapshot); + + try { + byte[] dataBytes = data.getBytes("UTF-8"); + snapshot.getSnapshotContents().writeBytes(dataBytes); + } catch (Exception e) { + Log.i("yoyo", "GooglePlayServices_SavedGames_CommitNew : Failed to write snapshot data - " + e.getMessage()); + } + + SnapshotMetadataChange.Builder metadataChangeBuilder = new SnapshotMetadataChange.Builder(); + + if (!desc.isEmpty()) { + metadataChangeBuilder.setDescription(desc); + } + + if (!coverImagePath.isEmpty()) { + String localImgPath = activity.getFilesDir() + "/" + coverImagePath; + File imgFile = new File(localImgPath); + + if (imgFile.exists()) { + Bitmap coverImageBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath()); + if (coverImageBitmap != null) { + metadataChangeBuilder.setCoverImage(coverImageBitmap); + } } - RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); } - }); - } - else - { - int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); - RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_SavedGames_CommitNew" ); - - Exception exception = task.getException(); - RunnerJNILib.DsMapAddDouble( dsMapIndex, "success", 0 ); - - RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); - } - } - }); + + SnapshotMetadataChange metadataChange = metadataChangeBuilder.build(); + snapshotsClient.commitAndClose(snapshot, metadataChange) + .addOnCompleteListener(commitTask -> { + boolean commitWasSuccessful = commitTask.isSuccessful(); + + int dsMapIndexCommit = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString(dsMapIndexCommit, "type", "GooglePlayServices_SavedGames_CommitNew"); + RunnerJNILib.DsMapAddDouble(dsMapIndexCommit, "ind", asyncIndex); + RunnerJNILib.DsMapAddDouble(dsMapIndexCommit, "success", + commitWasSuccessful ? 1.0 : 0.0); + + if (commitWasSuccessful) { + SnapshotMetadata snapshotMetadata = commitTask.getResult(); + RunnerJNILib.DsMapAddString(dsMapIndexCommit, "snapshotMetadata", + SnapshotMetadataJSON(snapshotMetadata).toString()); + } else { + Exception exception = commitTask.getException(); + Log.i("yoyo", "GooglePlayServices_SavedGames_CommitNew: failed to commit and close the saved game - " + exception.getMessage()); + } + + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndexCommit, EVENT_OTHER_SOCIAL); + }); + } else { + Exception exception = task.getException(); + Log.i("yoyo", "GooglePlayServices_SavedGames_CommitNew: task failed or conflict - " + + exception.getMessage()); + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + } + }); + + return asyncIndex; } - public void GooglePlayServices_SavedGames_Load(final double forceReload) - { - boolean forceReload_ = forceReload >= 0.5; - mSnapshotsClient.load(forceReload_).addOnCompleteListener(new OnCompleteListener>() - { - @Override - public void onComplete(@NonNull Task> task) + public double GooglePlayServices_SavedGames_Load(final double forceReload) { + final double asyncIndex = getAsyncInd(); + boolean shouldForceReload = forceReload >= 0.5; + SnapshotsClient snapshotsClient = PlayGames.getSnapshotsClient(activity); + + snapshotsClient.load(shouldForceReload).addOnCompleteListener(task -> { + + //Task error Verfication + try{task.getResult();} + catch(Exception e) { int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_SavedGames_Load"); - - if(!task.isSuccessful()) - { - RunnerJNILib.DsMapAddDouble(dsMapIndex,"success",0.0); - RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); - return; - } - - RunnerJNILib.DsMapAddDouble(dsMapIndex,"success",1.0); - - AnnotatedData mAnnotatedData = task.getResult(); - SnapshotMetadataBuffer mSnapshotMetadataBuffer = (SnapshotMetadataBuffer) mAnnotatedData.get(); - - JSONArray snapshots = new JSONArray(); - for(SnapshotMetadata mSnapshotMetadata : mSnapshotMetadataBuffer) - snapshots.put(SnapshotMetadataJSONObj(mSnapshotMetadata)); - - RunnerJNILib.DsMapAddString(dsMapIndex,"snapshots", snapshots.toString()); - + RunnerJNILib.DsMapAddDouble( dsMapIndex, "ind", asyncIndex ); + RunnerJNILib.DsMapAddDouble(dsMapIndex,"success",0); RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + return; } + + boolean wasSuccessful = task.isSuccessful(); + + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString(dsMapIndex, "type", "GooglePlayServices_SavedGames_Load"); + RunnerJNILib.DsMapAddDouble(dsMapIndex, "ind", asyncIndex); + RunnerJNILib.DsMapAddDouble(dsMapIndex, "success", wasSuccessful ? 1.0 : 0.0); + + if (wasSuccessful) { + AnnotatedData annotatedData = task.getResult(); + SnapshotMetadataBuffer snapshotMetadataBuffer = annotatedData.get(); + + JSONArray snapshots = new JSONArray(); + for (SnapshotMetadata snapshotMetadata : snapshotMetadataBuffer) { + snapshots.put(SnapshotMetadataJSON(snapshotMetadata)); + } + + RunnerJNILib.DsMapAddString(dsMapIndex, "snapshots", snapshots.toString()); + } else { + Exception exception = task.getException(); + Log.i("yoyo", "GooglePlayServices_SavedGames_Load : failed to load saved games - " + exception.getMessage()); + } + + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); }); + + return asyncIndex; } - public void GooglePlayServices_SavedGames_Open(String fileName) - { - double createIfNotFound = 0; - double conflictPolicy = 1; - - boolean createIfNotFound_; - - if(createIfNotFound >= 0.5) - createIfNotFound_ = true; - else - createIfNotFound_ = false; - - mSnapshotsClient.open(fileName,createIfNotFound_,(int) conflictPolicy).addOnCompleteListener(new OnCompleteListener>() - { - @Override - public void onComplete(@NonNull Task>task) + public double GooglePlayServices_SavedGames_Open(final String name) { + final double asyncIndex = getAsyncInd(); + + boolean createIfNotFound = false; + int conflictPolicy = 1; + + PlayGames.getSnapshotsClient(activity).open(name, createIfNotFound, conflictPolicy).addOnCompleteListener(task -> { + + //Task error Verfication + try{task.getResult();} + catch(Exception e) { int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); - RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_SavedGames_Open" ); - - if(!task.isSuccessful()) - { - Exception exception = task.getException(); - Log.i("yoyo","GooglePlayServices_SavedGames_Open ERROR:" + exception.getMessage()); - RunnerJNILib.DsMapAddDouble( dsMapIndex, "success", 0 ); - return; - } - - RunnerJNILib.DsMapAddDouble( dsMapIndex, "success",1); - DataOrConflict mDataOrConflict = task.getResult(); - Snapshot mSnapshot = (Snapshot) mDataOrConflict.getData(); - mapSnapshot.put(mSnapshot.getMetadata().getUniqueName(),mSnapshot); - - RunnerJNILib.DsMapAddString( dsMapIndex, "snapshotMetadata", SnapshotMetadataJSON(mSnapshot.getMetadata())); - - try - { - SnapshotContents mSnapshotContents = mSnapshot.getSnapshotContents(); - byte[] mDataInBytes = mSnapshotContents.readFully(); - String dataString = new String(mDataInBytes, "UTF-8"); - RunnerJNILib.DsMapAddString( dsMapIndex, "data", dataString); - } - catch(Exception e) - {} - + RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_SavedGames_Open"); + RunnerJNILib.DsMapAddDouble( dsMapIndex, "ind", asyncIndex ); + RunnerJNILib.DsMapAddDouble(dsMapIndex,"success",0); RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + return; + } + + boolean wasSuccessful = task.isSuccessful(); + + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString(dsMapIndex, "type", "GooglePlayServices_SavedGames_Open"); + RunnerJNILib.DsMapAddDouble(dsMapIndex, "ind", asyncIndex); + RunnerJNILib.DsMapAddDouble(dsMapIndex, "success", wasSuccessful ? 1.0 : 0.0); + + if (wasSuccessful) { + DataOrConflict dataOrConflict = task.getResult(); + Snapshot snapshot = dataOrConflict.getData(); + mapSnapshot.put(snapshot.getMetadata().getUniqueName(), snapshot); + + SnapshotMetadata snapshotMetadata = snapshot.getMetadata(); + RunnerJNILib.DsMapAddString(dsMapIndex, "snapshotMetadata", SnapshotMetadataJSON(snapshotMetadata).toString()); + + try { + SnapshotContents snapshotContents = snapshot.getSnapshotContents(); + byte[] dataInBytes = snapshotContents.readFully(); + String dataString = new String(dataInBytes, "UTF-8"); + RunnerJNILib.DsMapAddString(dsMapIndex, "data", dataString); + } catch (Exception e) { + Log.i("yoyo", "GooglePlayServices_SavedGames_Open : Exception while reading snapshot data - " + e.getMessage()); + } + } else { + Exception exception = task.getException(); + Log.i("yoyo", "GooglePlayServices_SavedGames_Open : failed to open saved game - " + exception.getMessage()); } + + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); }); + + return asyncIndex; } - public void GooglePlayServices_SavedGames_Delete(String fileName) - { - Snapshot mSnapshot = (Snapshot) mapSnapshot.get(fileName); - SnapshotMetadata mSnapshotMetadata = mSnapshot.getMetadata(); - - mSnapshotsClient.delete(mSnapshotMetadata).addOnCompleteListener(new OnCompleteListener() - { - @Override - public void onComplete(@NonNull Tasktask) - { - int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); - RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_SavedGames_Delete" ); + public double GooglePlayServices_SavedGames_Delete(final String name) { + final double asyncIndex = getAsyncInd(); + + Snapshot snapshot = mapSnapshot.get(name); + if (snapshot == null) { + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString(dsMapIndex, "type", "GooglePlayServices_SavedGames_Delete"); + RunnerJNILib.DsMapAddDouble(dsMapIndex, "ind", asyncIndex); + RunnerJNILib.DsMapAddDouble(dsMapIndex, "success", 0); + Log.i("yoyo", "GooglePlayServices_SavedGames_Delete : couldn't find snapshot with name '" + name + "'"); + + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + + } else { + SnapshotsClient snapshotsClient = PlayGames.getSnapshotsClient(activity); + SnapshotMetadata snapshotMetadata = snapshot.getMetadata(); + + snapshotsClient.delete(snapshotMetadata).addOnCompleteListener(task -> { - if (task.isSuccessful()) + //Task error Verfication + try{task.getResult();} + catch(Exception e) { - String snapshotID = task.getResult(); - RunnerJNILib.DsMapAddDouble( dsMapIndex, "success", 1 ); - RunnerJNILib.DsMapAddString( dsMapIndex, "snapshotID.", snapshotID); + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_SavedGames_Delete"); + RunnerJNILib.DsMapAddDouble( dsMapIndex, "ind", asyncIndex ); + RunnerJNILib.DsMapAddDouble(dsMapIndex,"success",0); + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + return; } - else - { + + boolean wasSuccessful = task.isSuccessful(); + + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString(dsMapIndex, "type", "GooglePlayServices_SavedGames_Delete"); + RunnerJNILib.DsMapAddDouble(dsMapIndex, "ind", asyncIndex); + RunnerJNILib.DsMapAddDouble(dsMapIndex, "success", wasSuccessful ? 1.0 : 0.0); + + if (wasSuccessful) { + String snapshotID = task.getResult(); + RunnerJNILib.DsMapAddString(dsMapIndex, "snapshotID", snapshotID); + + } else { Exception exception = task.getException(); - RunnerJNILib.DsMapAddDouble( dsMapIndex, "success", 0 ); - Log.i("yoyo","GooglePlayServices_SavedGames_Delete FAIL: " + exception.getMessage()); + Log.i("yoyo", "GooglePlayServices_SavedGames_Delete : failed to delete saved game - " + exception.getMessage()); } - - RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); - } - }); - } + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + }); + } - public void GooglePlayServices_SavedGames_DiscardAndClose(String fileName) - { - Snapshot mSnapshot = (Snapshot) mapSnapshot.get(fileName); - mSnapshotsClient.discardAndClose(mSnapshot).addOnCompleteListener(new OnCompleteListener() - { - @Override - public void onComplete(@NonNull Tasktask) - { - int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); - RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_SavedGames_DiscardAndClose" ); - - if (task.isSuccessful()) - RunnerJNILib.DsMapAddDouble( dsMapIndex, "success", 1); - else + return asyncIndex; + } + + public double GooglePlayServices_SavedGames_DiscardAndClose(String name) { + final double asyncIndex = getAsyncInd(); + + Snapshot snapshot = mapSnapshot.get(name); + if (snapshot == null) { + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString(dsMapIndex, "type", "GooglePlayServices_SavedGames_DiscardAndClose"); + RunnerJNILib.DsMapAddDouble(dsMapIndex, "ind", asyncIndex); + RunnerJNILib.DsMapAddDouble(dsMapIndex, "success", 0); + Log.i("yoyo", "GooglePlayServices_SavedGames_DiscardAndClose : couldn't find snapshot with name '" + name + "'"); + + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + + } else { + SnapshotsClient snapshotsClient = PlayGames.getSnapshotsClient(activity); + snapshotsClient.discardAndClose(snapshot).addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { - Exception exception = task.getException(); - Log.i("yoyo","GooglePlayServices_SavedGames_DiscardAndClose FAIL: " + exception.getMessage()); - RunnerJNILib.DsMapAddDouble( dsMapIndex, "success", 0 ); + //Task error Verfication + try{task.getResult();} + catch(Exception e) + { + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_SavedGames_DiscardAndClose"); + RunnerJNILib.DsMapAddDouble( dsMapIndex, "ind", asyncIndex ); + RunnerJNILib.DsMapAddDouble(dsMapIndex,"success",0); + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + return; + } + + boolean wasSuccessful = task.isSuccessful(); + + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString(dsMapIndex, "type", "GooglePlayServices_SavedGames_DiscardAndClose"); + RunnerJNILib.DsMapAddDouble(dsMapIndex, "ind", asyncIndex); + RunnerJNILib.DsMapAddDouble(dsMapIndex, "success", wasSuccessful ? 1.0 : 0.0); + + if (!wasSuccessful) { + Exception exception = task.getException(); + Log.i("yoyo", "GooglePlayServices_SavedGames_DiscardAndClose : failed to discard and close the saved game - " + exception.getMessage()); + } + + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); } - - RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); - } - }); - } + }); + } - static String gameJSON(Game mGame) - { - HashMap map = new HashMap(); - - if(mGame.areSnapshotsEnabled()) - map.put("areSnapshotsEnabled",(double) 1); - else - map.put("areSnapshotsEnabled",(double) 0); - - map.put("achievementTotalCount",(double)mGame.getAchievementTotalCount()); - map.put("applicationId",mGame.getApplicationId()); - map.put("description",mGame.getDescription()); - map.put("developerName",mGame.getDeveloperName()); - if(mGame.getDisplayName() != null) - map.put("displayName",mGame.getDisplayName()); - if(mGame.getFeaturedImageUri() != null) - map.put("featuredImageUri",mGame.getFeaturedImageUri().toString()); - if(mGame.getHiResImageUri() != null) - map.put("hiResImageUri",mGame.getHiResImageUri().toString()); - if(mGame.getIconImageUri() != null) - map.put("iconImageUri",mGame.getIconImageUri().toString()); - map.put("leaderboardCount",mGame.getLeaderboardCount()); - map.put("primaryCategory",mGame.getPrimaryCategory()); - map.put("secondaryCategory",mGame.getSecondaryCategory()); - map.put("themeColor",mGame.getThemeColor()); - - if(mGame.hasGamepadSupport()) - map.put("gamepadSupport", 1); - else - map.put("gamepadSupport", 0); - - JSONObject obj = new JSONObject(map); - - return obj.toString(); + return asyncIndex; } + + // ==================================== + // PlayerStats + // ==================================== - - // Video Recorder + public double GooglePlayServices_PlayerStats_LoadPlayerStats(double forceReload) { + final double asyncIndex = getAsyncInd(); + boolean shouldForceReload = forceReload >= 0.5; - private static final int RC_VIDEO_OVERLAY = 9011; - public void GooglePlayServices_VideoRecording_ShowVideoOverlay() - { - Games.getVideosClient(activity, GoogleSignIn.getLastSignedInAccount(activity)).getCaptureOverlayIntent().addOnSuccessListener(new OnSuccessListener() + PlayGames.getPlayerStatsClient(activity).loadPlayerStats(shouldForceReload).addOnCompleteListener(task -> { - @Override - public void onSuccess(Intent intent) + //Task error Verfication + try{task.getResult();} + catch(Exception e) { - activity.startActivityForResult(intent, RC_VIDEO_OVERLAY); + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString( dsMapIndex, "type", "GooglePlayServices_PlayerStats_LoadPlayerStats"); + RunnerJNILib.DsMapAddDouble( dsMapIndex, "ind", asyncIndex ); + RunnerJNILib.DsMapAddDouble(dsMapIndex,"success",0); + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); + return; + } + + boolean wasSuccessful = task.isSuccessful(); + + int dsMapIndex = RunnerJNILib.jCreateDsMap(null, null, null); + RunnerJNILib.DsMapAddString(dsMapIndex, "type", "GooglePlayServices_PlayerStats_LoadPlayerStats"); + RunnerJNILib.DsMapAddDouble(dsMapIndex, "ind", asyncIndex); + RunnerJNILib.DsMapAddDouble(dsMapIndex, "success", wasSuccessful ? 1.0 : 0.0); + + if (wasSuccessful) { + AnnotatedData annotatedData = task.getResult(); + PlayerStats playerStats = annotatedData.get(); + + RunnerJNILib.DsMapAddDouble(dsMapIndex, "AverageSessionLength", playerStats.getAverageSessionLength()); + RunnerJNILib.DsMapAddDouble(dsMapIndex, "DaysSinceLastPlayed", playerStats.getDaysSinceLastPlayed()); + RunnerJNILib.DsMapAddDouble(dsMapIndex, "NumberOfPurchases", playerStats.getNumberOfPurchases()); + RunnerJNILib.DsMapAddDouble(dsMapIndex, "NumberOfSessions", playerStats.getNumberOfSessions()); + RunnerJNILib.DsMapAddDouble(dsMapIndex, "SessionPercentile", playerStats.getSessionPercentile()); + RunnerJNILib.DsMapAddDouble(dsMapIndex, "SpendPercentile", playerStats.getSpendPercentile()); + + } else { + Exception exception = task.getException(); + Log.i("yoyo", "GooglePlayServices_PlayerStats_LoadPlayerStats : failed to query player stats - " + exception.getMessage()); } + + RunnerJNILib.CreateAsynEventWithDSMap(dsMapIndex, EVENT_OTHER_SOCIAL); }); + + return asyncIndex; } + } diff --git a/extensions/GooglePlayServices/GooglePlayServices.yy b/extensions/GooglePlayServices/GooglePlayServices.yy index f7d91b27a..afc3ef73c 100644 --- a/extensions/GooglePlayServices/GooglePlayServices.yy +++ b/extensions/GooglePlayServices/GooglePlayServices.yy @@ -3,7 +3,7 @@ "%Name":"GooglePlayServices", "androidactivityinject":"", "androidclassname":"YYGooglePlayServices", - "androidcodeinjection":"\r\n${YYEXTOPT_GooglePlayServices_AppID}\r\n\r\n\r\n\r\nandroid {\r\n lintOptions {\r\n checkReleaseBuilds false\r\n abortOnError false\r\n }\r\n}\r\n\r\n//https://developers.google.com/android/guides/setup\r\ndependencies {\r\n//https://developers.google.com/android/guides/releases\r\n implementation 'com.google.android.gms:play-services-auth:20.1.0'\r\n implementation 'com.google.android.gms:play-services-games:22.0.1'\r\n}\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n", + "androidcodeinjection":"\r\n${YYEXTOPT_GooglePlayServices_AppID}\r\n\r\n\r\n\r\nandroid {\r\n lintOptions {\r\n checkReleaseBuilds false\r\n abortOnError false\r\n }\r\n}\r\n\r\n//https://developers.google.com/android/guides/setup\r\ndependencies {\r\n//https://developers.google.com/android/guides/releases\r\n implementation \"com.google.android.gms:play-services-games-v2:+\"\r\n}\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n# The native PGS library wraps the Java PGS SDK using reflection.\r\n-dontobfuscate\r\n-keeppackagenames\r\n\r\n# Needed for callbacks.\r\n-keepclasseswithmembernames,includedescriptorclasses class * {\r\n native *;\r\n}\r\n\r\n# Needed for helper libraries.\r\n-keep class com.google.example.games.juihelper.** {\r\n public protected *;\r\n}\r\n-keep class com.sample.helper.** {\r\n public protected *;\r\n}\r\n\r\n# Needed for GoogleApiClient and auth stuff.\r\n-keep class com.google.android.gms.common.api.** {\r\n public protected *;\r\n}\r\n\r\n# Keep all of the \"nearby\" library, which is needed by the native PGS library\r\n# at runtime (though deprecated).\r\n-keep class com.google.android.gms.nearby.** {\r\n public protected *;\r\n}\r\n\r\n# Keep all of the public PGS APIs.\r\n-keep class com.google.android.gms.games.** {\r\n public protected *;\r\n}\r\n", "androidinject":"\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n", "androidmanifestinject":"", "androidPermissions":[], @@ -11,10 +11,10 @@ "androidsourcedir":"", "author":"", "classname":"", - "copyToTargets":0, + "copyToTargets":8, "description":"", "exportToGame":true, - "extensionVersion":"1.1.0", + "extensionVersion":"2.1.4", "files":[ {"$GMExtensionFile":"","%Name":"GooglePlayService.ext","constants":[ {"$GMExtensionConstant":"","%Name":"Achievement_STATE_HIDDEN","hidden":false,"name":"Achievement_STATE_HIDDEN","resourceType":"GMExtensionConstant","resourceVersion":"2.0","value":"2",}, @@ -28,74 +28,61 @@ {"$GMExtensionConstant":"","%Name":"Leaderboard_COLLECTION_PUBLIC","hidden":false,"name":"Leaderboard_COLLECTION_PUBLIC","resourceType":"GMExtensionConstant","resourceVersion":"2.0","value":"0",}, {"$GMExtensionConstant":"","%Name":"Leaderboard_COLLECTION_SOCIAL","hidden":false,"name":"Leaderboard_COLLECTION_SOCIAL","resourceType":"GMExtensionConstant","resourceVersion":"2.0","value":"1",}, ],"copyToTargets":8,"filename":"GooglePlayService.ext","final":"","functions":[ - {"$GMExtensionFunction":"","%Name":"GooglePlayServices_StartSignInIntent","argCount":0,"args":[],"documentation":"","externalName":"GooglePlayServices_StartSignInIntent","help":"GooglePlayServices_StartSignInIntent()","hidden":false,"kind":4,"name":"GooglePlayServices_StartSignInIntent","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, - {"$GMExtensionFunction":"","%Name":"GooglePlayServices_IsSignedIn","argCount":0,"args":[],"documentation":"","externalName":"GooglePlayServices_IsSignedIn","help":"GooglePlayServices_IsSignedIn()","hidden":false,"kind":4,"name":"GooglePlayServices_IsSignedIn","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, - {"$GMExtensionFunction":"","%Name":"GooglePlayServices_SignOut","argCount":0,"args":[],"documentation":"","externalName":"GooglePlayServices_SignOut","help":"GooglePlayServices_SignOut()","hidden":false,"kind":4,"name":"GooglePlayServices_SignOut","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, - {"$GMExtensionFunction":"","%Name":"GooglePlayServices_Achievements_Show","argCount":0,"args":[],"documentation":"","externalName":"GooglePlayServices_Achievements_Show","help":"GooglePlayServices_Achievements_Show()","hidden":false,"kind":4,"name":"GooglePlayServices_Achievements_Show","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, - {"$GMExtensionFunction":"","%Name":"GooglePlayServices_Achievements_Increment","argCount":0,"args":[1,2,],"documentation":"","externalName":"GooglePlayServices_Achievements_Increment","help":"GooglePlayServices_Achievements_Increment(arch_id,steps)","hidden":false,"kind":4,"name":"GooglePlayServices_Achievements_Increment","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, - {"$GMExtensionFunction":"","%Name":"GooglePlayServices_Achievements_Reveal","argCount":0,"args":[1,],"documentation":"","externalName":"GooglePlayServices_Achievements_Reveal","help":"GooglePlayServices_Achievements_Reveal(id)","hidden":false,"kind":4,"name":"GooglePlayServices_Achievements_Reveal","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, - {"$GMExtensionFunction":"","%Name":"GooglePlayServices_Achievements_SetSteps","argCount":0,"args":[1,2,],"documentation":"","externalName":"GooglePlayServices_Achievements_SetSteps","help":"GooglePlayServices_Achievements_SetSteps(id,steps)","hidden":false,"kind":4,"name":"GooglePlayServices_Achievements_SetSteps","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, - {"$GMExtensionFunction":"","%Name":"GooglePlayServices_Achievements_Unlock","argCount":0,"args":[1,],"documentation":"","externalName":"GooglePlayServices_Achievements_Unlock","help":"GooglePlayServices_Achievements_Unlock(id)","hidden":false,"kind":4,"name":"GooglePlayServices_Achievements_Unlock","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, - {"$GMExtensionFunction":"","%Name":"GooglePlayServices_Leaderboard_ShowAll","argCount":0,"args":[],"documentation":"","externalName":"GooglePlayServices_Leaderboard_ShowAll","help":"GooglePlayServices_Leaderboard_ShowAll()","hidden":false,"kind":4,"name":"GooglePlayServices_Leaderboard_ShowAll","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, - {"$GMExtensionFunction":"","%Name":"GooglePlayServices_Leaderboard_Show","argCount":0,"args":[1,],"documentation":"","externalName":"GooglePlayServices_Leaderboard_Show","help":"GooglePlayServices_Leaderboard_Show(id)","hidden":false,"kind":4,"name":"GooglePlayServices_Leaderboard_Show","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, - {"$GMExtensionFunction":"","%Name":"GooglePlayServices_Leaderboard_SubmitScore","argCount":0,"args":[1,2,1,],"documentation":"","externalName":"GooglePlayServices_Leaderboard_SubmitScore","help":"GooglePlayServices_Leaderboard_SubmitScore(leader_id,score,scoreTag)","hidden":false,"kind":4,"name":"GooglePlayServices_Leaderboard_SubmitScore","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, - {"$GMExtensionFunction":"","%Name":"GooglePlayServices_GetAccount","argCount":0,"args":[],"documentation":"","externalName":"GooglePlayServices_GetAccount","help":"GooglePlayServices_GetAccount()","hidden":false,"kind":4,"name":"GooglePlayServices_GetAccount","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, - {"$GMExtensionFunction":"","%Name":"GooglePlayServices_SavedGames_ShowSavedGamesUI","argCount":0,"args":[1,2,2,2,],"documentation":"","externalName":"GooglePlayServices_SavedGames_ShowSavedGamesUI","help":"GooglePlayServices_SavedGames_ShowSavedGamesUI(tittle,buttonAdd,buttonDelete,max)","hidden":false,"kind":4,"name":"GooglePlayServices_SavedGames_ShowSavedGamesUI","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, - {"$GMExtensionFunction":"","%Name":"GooglePlayServices_SavedGames_CommitAndClose","argCount":0,"args":[1,1,1,1,],"documentation":"","externalName":"GooglePlayServices_SavedGames_CommitAndClose","help":"GooglePlayServices_SavedGames_CommitAndClose(name,descripction,data,pathImage)","hidden":false,"kind":4,"name":"GooglePlayServices_SavedGames_CommitAndClose","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, - {"$GMExtensionFunction":"","%Name":"GooglePlayServices_RevokeAccess","argCount":0,"args":[],"documentation":"","externalName":"GooglePlayServices_RevokeAccess","help":"GooglePlayServices_RevokeAccess()","hidden":false,"kind":4,"name":"GooglePlayServices_RevokeAccess","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, - {"$GMExtensionFunction":"","%Name":"GooglePlayServices_SavedGames_Load","argCount":0,"args":[2,],"documentation":"","externalName":"GooglePlayServices_SavedGames_Load","help":"GooglePlayServices_SavedGames_Load(forced)","hidden":false,"kind":4,"name":"GooglePlayServices_SavedGames_Load","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, - {"$GMExtensionFunction":"","%Name":"GooglePlayServices_SavedGames_Delete","argCount":0,"args":[1,],"documentation":"","externalName":"GooglePlayServices_SavedGames_Delete","help":"GooglePlayServices_SavedGames_Delete(name)","hidden":false,"kind":4,"name":"GooglePlayServices_SavedGames_Delete","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, - {"$GMExtensionFunction":"","%Name":"GooglePlayServices_SavedGames_DiscardAndClose","argCount":0,"args":[1,],"documentation":"","externalName":"GooglePlayServices_SavedGames_DiscardAndClose","help":"GooglePlayServices_SavedGames_DiscardAndClose(fileName)","hidden":false,"kind":4,"name":"GooglePlayServices_SavedGames_DiscardAndClose","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, - {"$GMExtensionFunction":"","%Name":"GooglePlayServices_SavedGames_Open","argCount":0,"args":[1,],"documentation":"","externalName":"GooglePlayServices_SavedGames_Open","help":"GooglePlayServices_SavedGames_Open(fileName)","hidden":false,"kind":4,"name":"GooglePlayServices_SavedGames_Open","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, - {"$GMExtensionFunction":"","%Name":"GooglePlayServices_SavedGames_ResolveConflict","argCount":0,"args":[],"documentation":"","externalName":"GooglePlayServices_SavedGames_ResolveConflict","help":"GooglePlayServices_SavedGames_ResolveConflict()","hidden":false,"kind":4,"name":"GooglePlayServices_SavedGames_ResolveConflict","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, - {"$GMExtensionFunction":"","%Name":"GooglePlayServices_SavedGames_CommitNew","argCount":0,"args":[1,1,1,1,],"documentation":"","externalName":"GooglePlayServices_SavedGames_CommitNew","help":"GooglePlayServices_SavedGames_CommitNew(name,description,data,pathImage)","hidden":false,"kind":4,"name":"GooglePlayServices_SavedGames_CommitNew","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, - {"$GMExtensionFunction":"","%Name":"GooglePlayServices_UserMessage","argCount":0,"args":[1,],"documentation":"","externalName":"GooglePlayServices_UserMessage","help":"GooglePlayServices_UserMessage(text)","hidden":false,"kind":4,"name":"GooglePlayServices_UserMessage","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, + {"$GMExtensionFunction":"","%Name":"GooglePlayServices_Achievements_Show","argCount":0,"args":[],"documentation":"","externalName":"GooglePlayServices_Achievements_Show","help":"GooglePlayServices_Achievements_Show()","hidden":false,"kind":4,"name":"GooglePlayServices_Achievements_Show","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, + {"$GMExtensionFunction":"","%Name":"GooglePlayServices_Achievements_Increment","argCount":0,"args":[1,2,],"documentation":"","externalName":"GooglePlayServices_Achievements_Increment","help":"GooglePlayServices_Achievements_Increment(arch_id,steps)","hidden":false,"kind":4,"name":"GooglePlayServices_Achievements_Increment","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, + {"$GMExtensionFunction":"","%Name":"GooglePlayServices_Achievements_Reveal","argCount":0,"args":[1,],"documentation":"","externalName":"GooglePlayServices_Achievements_Reveal","help":"GooglePlayServices_Achievements_Reveal(id)","hidden":false,"kind":4,"name":"GooglePlayServices_Achievements_Reveal","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, + {"$GMExtensionFunction":"","%Name":"GooglePlayServices_Achievements_SetSteps","argCount":0,"args":[1,2,],"documentation":"","externalName":"GooglePlayServices_Achievements_SetSteps","help":"GooglePlayServices_Achievements_SetSteps(id,steps)","hidden":false,"kind":4,"name":"GooglePlayServices_Achievements_SetSteps","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, + {"$GMExtensionFunction":"","%Name":"GooglePlayServices_Achievements_Unlock","argCount":0,"args":[1,],"documentation":"","externalName":"GooglePlayServices_Achievements_Unlock","help":"GooglePlayServices_Achievements_Unlock(id)","hidden":false,"kind":4,"name":"GooglePlayServices_Achievements_Unlock","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, + {"$GMExtensionFunction":"","%Name":"GooglePlayServices_Leaderboard_ShowAll","argCount":0,"args":[],"documentation":"","externalName":"GooglePlayServices_Leaderboard_ShowAll","help":"GooglePlayServices_Leaderboard_ShowAll()","hidden":false,"kind":4,"name":"GooglePlayServices_Leaderboard_ShowAll","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, + {"$GMExtensionFunction":"","%Name":"GooglePlayServices_Leaderboard_Show","argCount":0,"args":[1,],"documentation":"","externalName":"GooglePlayServices_Leaderboard_Show","help":"GooglePlayServices_Leaderboard_Show(id)","hidden":false,"kind":4,"name":"GooglePlayServices_Leaderboard_Show","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, + {"$GMExtensionFunction":"","%Name":"GooglePlayServices_Leaderboard_SubmitScore","argCount":0,"args":[1,2,1,],"documentation":"","externalName":"GooglePlayServices_Leaderboard_SubmitScore","help":"GooglePlayServices_Leaderboard_SubmitScore(leader_id,score,scoreTag)","hidden":false,"kind":4,"name":"GooglePlayServices_Leaderboard_SubmitScore","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, + {"$GMExtensionFunction":"","%Name":"GooglePlayServices_SavedGames_ShowSavedGamesUI","argCount":0,"args":[1,2,2,2,],"documentation":"","externalName":"GooglePlayServices_SavedGames_ShowSavedGamesUI","help":"GooglePlayServices_SavedGames_ShowSavedGamesUI(tittle,buttonAdd,buttonDelete,max)","hidden":false,"kind":4,"name":"GooglePlayServices_SavedGames_ShowSavedGamesUI","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, + {"$GMExtensionFunction":"","%Name":"GooglePlayServices_SavedGames_CommitAndClose","argCount":0,"args":[1,1,1,1,],"documentation":"","externalName":"GooglePlayServices_SavedGames_CommitAndClose","help":"GooglePlayServices_SavedGames_CommitAndClose(name,descripction,data,pathImage)","hidden":false,"kind":4,"name":"GooglePlayServices_SavedGames_CommitAndClose","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, + {"$GMExtensionFunction":"","%Name":"GooglePlayServices_SavedGames_Load","argCount":0,"args":[2,],"documentation":"","externalName":"GooglePlayServices_SavedGames_Load","help":"GooglePlayServices_SavedGames_Load(forced)","hidden":false,"kind":4,"name":"GooglePlayServices_SavedGames_Load","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, + {"$GMExtensionFunction":"","%Name":"GooglePlayServices_SavedGames_Delete","argCount":0,"args":[1,],"documentation":"","externalName":"GooglePlayServices_SavedGames_Delete","help":"GooglePlayServices_SavedGames_Delete(name)","hidden":false,"kind":4,"name":"GooglePlayServices_SavedGames_Delete","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, + {"$GMExtensionFunction":"","%Name":"GooglePlayServices_SavedGames_DiscardAndClose","argCount":0,"args":[1,],"documentation":"","externalName":"GooglePlayServices_SavedGames_DiscardAndClose","help":"GooglePlayServices_SavedGames_DiscardAndClose(fileName)","hidden":false,"kind":4,"name":"GooglePlayServices_SavedGames_DiscardAndClose","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, + {"$GMExtensionFunction":"","%Name":"GooglePlayServices_SavedGames_Open","argCount":0,"args":[1,],"documentation":"","externalName":"GooglePlayServices_SavedGames_Open","help":"GooglePlayServices_SavedGames_Open(fileName)","hidden":false,"kind":4,"name":"GooglePlayServices_SavedGames_Open","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, + {"$GMExtensionFunction":"","%Name":"GooglePlayServices_SavedGames_ResolveConflict","argCount":0,"args":[],"documentation":"","externalName":"GooglePlayServices_SavedGames_ResolveConflict","help":"GooglePlayServices_SavedGames_ResolveConflict()","hidden":false,"kind":4,"name":"GooglePlayServices_SavedGames_ResolveConflict","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, + {"$GMExtensionFunction":"","%Name":"GooglePlayServices_SavedGames_CommitNew","argCount":0,"args":[1,1,1,1,],"documentation":"","externalName":"GooglePlayServices_SavedGames_CommitNew","help":"GooglePlayServices_SavedGames_CommitNew(name,description,data,pathImage)","hidden":false,"kind":4,"name":"GooglePlayServices_SavedGames_CommitNew","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, {"$GMExtensionFunction":"","%Name":"GooglePlayServices_Player_Current","argCount":0,"args":[],"documentation":"","externalName":"GooglePlayServices_Player_Current","help":"GooglePlayServices_Player_Current()","hidden":false,"kind":4,"name":"GooglePlayServices_Player_Current","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, - {"$GMExtensionFunction":"","%Name":"GooglePlayServices_VideoRecording_ShowVideoOverlay","argCount":0,"args":[],"documentation":"","externalName":"GooglePlayServices_VideoRecording_ShowVideoOverlay","help":"GooglePlayServices_VideoRecording_ShowVideoOverlay()","hidden":false,"kind":4,"name":"GooglePlayServices_VideoRecording_ShowVideoOverlay","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, {"$GMExtensionFunction":"","%Name":"GooglePlayServices_Player_CurrentID","argCount":0,"args":[],"documentation":"","externalName":"GooglePlayServices_Player_CurrentID","help":"GooglePlayServices_Player_CurrentID()","hidden":false,"kind":4,"name":"GooglePlayServices_Player_CurrentID","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, - {"$GMExtensionFunction":"","%Name":"GooglePlayServices_SetClientID","argCount":0,"args":[1,],"documentation":"","externalName":"GooglePlayServices_SetClientID","help":"GooglePlayServices_SetClientID(string)","hidden":false,"kind":4,"name":"GooglePlayServices_SetClientID","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, - {"$GMExtensionFunction":"","%Name":"GooglePlayServices_GetServerAuthCode","argCount":0,"args":[],"documentation":"","externalName":"GooglePlayServices_GetServerAuthCode","help":"GooglePlayServices_GetServerAuthCode()","hidden":false,"kind":4,"name":"GooglePlayServices_GetServerAuthCode","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, {"$GMExtensionFunction":"","%Name":"GooglePlayServices_UriToPath","argCount":0,"args":[1,],"documentation":"","externalName":"GooglePlayServices_UriToPath","help":"GooglePlayServices_UriToPath(uri)","hidden":false,"kind":4,"name":"GooglePlayServices_UriToPath","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, {"$GMExtensionFunction":"","%Name":"GooglePlayServices_IsAvailable","argCount":0,"args":[],"documentation":"","externalName":"GooglePlayServices_IsAvailable","help":"GooglePlayServices_IsAvailable()","hidden":false,"kind":4,"name":"GooglePlayServices_IsAvailable","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, {"$GMExtensionFunction":"","%Name":"GooglePlayServices_Achievements_GetStatus","argCount":0,"args":[2,],"documentation":"","externalName":"GooglePlayServices_Achievements_GetStatus","help":"GooglePlayServices_Achievements_GetStatus(force_reload)","hidden":false,"kind":4,"name":"GooglePlayServices_Achievements_GetStatus","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, - {"$GMExtensionFunction":"","%Name":"GooglePlayServices_Leaderboard_LoadPlayerCenteredScores","argCount":0,"args":[1,2,2,2,2,],"documentation":"","externalName":"GooglePlayServices_Leaderboard_LoadPlayerCenteredScores","help":"GooglePlayServices_Leaderboard_LoadPlayerCenteredScores(leaderboardId, span, leaderboardCollection, maxResults, forceReload)","hidden":false,"kind":4,"name":"GooglePlayServices_Leaderboard_LoadPlayerCenteredScores","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, + {"$GMExtensionFunction":"","%Name":"GooglePlayServices_Leaderboard_LoadPlayerCenteredScores","argCount":0,"args":[1,2,2,2,2,],"documentation":"","externalName":"GooglePlayServices_Leaderboard_LoadPlayerCenteredScores","help":"GooglePlayServices_Leaderboard_LoadPlayerCenteredScores(leaderboardId, span, leaderboardCollection, maxResults, forceReload)","hidden":false,"kind":4,"name":"GooglePlayServices_Leaderboard_LoadPlayerCenteredScores","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, {"$GMExtensionFunction":"","%Name":"GooglePlayServices_Leaderboard_LoadTopScores","argCount":0,"args":[1,2,2,2,2,],"documentation":"","externalName":"GooglePlayServices_Leaderboard_LoadTopScores","help":"GooglePlayServices_Leaderboard_LoadTopScores(leaderboardId, span, leaderboardCollection, maxResults, forceReload)","hidden":false,"kind":4,"name":"GooglePlayServices_Leaderboard_LoadTopScores","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":1,}, + {"$GMExtensionFunction":"","%Name":"GooglePlayServices_Leaderboard_LoadTopScores","argCount":0,"args":[1,2,2,2,2,],"documentation":"","externalName":"GooglePlayServices_Leaderboard_LoadTopScores","help":"GooglePlayServices_Leaderboard_LoadTopScores(leaderboardId, span, leaderboardCollection, maxResults, forceReload)","hidden":false,"kind":4,"name":"GooglePlayServices_Leaderboard_LoadTopScores","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, + {"$GMExtensionFunction":"","%Name":"GooglePlayServices_SignIn","argCount":0,"args":[],"documentation":"","externalName":"GooglePlayServices_SignIn","help":"GooglePlayServices_SignIn()","hidden":false,"kind":4,"name":"GooglePlayServices_SignIn","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, + {"$GMExtensionFunction":"","%Name":"GooglePlayServices_IsAuthenticated","argCount":0,"args":[],"documentation":"","externalName":"GooglePlayServices_IsAuthenticated","help":"GooglePlayServices_IsAuthenticated()","hidden":false,"kind":4,"name":"GooglePlayServices_IsAuthenticated","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, + {"$GMExtensionFunction":"","%Name":"GooglePlayServices_RequestServerSideAccess","argCount":0,"args":[1,2,],"documentation":"","externalName":"GooglePlayServices_RequestServerSideAccess","help":"GooglePlayServices_RequestServerSideAccess(serverClientId,forceRefreshToken)","hidden":false,"kind":4,"name":"GooglePlayServices_RequestServerSideAccess","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, + {"$GMExtensionFunction":"","%Name":"GooglePlayServices_PlayerStats_LoadPlayerStats","argCount":0,"args":[2,],"documentation":"","externalName":"GooglePlayServices_PlayerStats_LoadPlayerStats","help":"GooglePlayServices_PlayerStats_LoadPlayerStats(forcedLoad)","hidden":false,"kind":4,"name":"GooglePlayServices_PlayerStats_LoadPlayerStats","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, ],"init":"","kind":4,"name":"GooglePlayService.ext","order":[ - {"name":"GooglePlayServices_StartSignInIntent","path":"extensions/GooglePlayServices/GooglePlayServices.yy",}, - {"name":"GooglePlayServices_IsSignedIn","path":"extensions/GooglePlayServices/GooglePlayServices.yy",}, - {"name":"GooglePlayServices_RevokeAccess","path":"extensions/GooglePlayServices/GooglePlayServices.yy",}, - {"name":"GooglePlayServices_SignOut","path":"extensions/GooglePlayServices/GooglePlayServices.yy",}, - {"name":"GooglePlayServices_SetClientID","path":"extensions/GooglePlayServices/GooglePlayServices.yy",}, - {"name":"GooglePlayServices_GetServerAuthCode","path":"extensions/GooglePlayServices/GooglePlayServices.yy",}, - {"name":"GooglePlayServices_UriToPath","path":"extensions/GooglePlayServices/GooglePlayServices.yy",}, - {"name":"GooglePlayServices_GetAccount","path":"extensions/GooglePlayServices/GooglePlayServices.yy",}, - {"name":"GooglePlayServices_UserMessage","path":"extensions/GooglePlayServices/GooglePlayServices.yy",}, - {"name":"GooglePlayServices_Player_Current","path":"extensions/GooglePlayServices/GooglePlayServices.yy",}, - {"name":"GooglePlayServices_Player_CurrentID","path":"extensions/GooglePlayServices/GooglePlayServices.yy",}, {"name":"GooglePlayServices_Achievements_Show","path":"extensions/GooglePlayServices/GooglePlayServices.yy",}, {"name":"GooglePlayServices_Achievements_Increment","path":"extensions/GooglePlayServices/GooglePlayServices.yy",}, {"name":"GooglePlayServices_Achievements_Reveal","path":"extensions/GooglePlayServices/GooglePlayServices.yy",}, {"name":"GooglePlayServices_Achievements_SetSteps","path":"extensions/GooglePlayServices/GooglePlayServices.yy",}, {"name":"GooglePlayServices_Achievements_Unlock","path":"extensions/GooglePlayServices/GooglePlayServices.yy",}, + {"name":"GooglePlayServices_Achievements_GetStatus","path":"extensions/GooglePlayServices/GooglePlayServices.yy",}, {"name":"GooglePlayServices_Leaderboard_ShowAll","path":"extensions/GooglePlayServices/GooglePlayServices.yy",}, {"name":"GooglePlayServices_Leaderboard_Show","path":"extensions/GooglePlayServices/GooglePlayServices.yy",}, {"name":"GooglePlayServices_Leaderboard_SubmitScore","path":"extensions/GooglePlayServices/GooglePlayServices.yy",}, + {"name":"GooglePlayServices_Leaderboard_LoadPlayerCenteredScores","path":"extensions/GooglePlayServices/GooglePlayServices.yy",}, + {"name":"GooglePlayServices_Leaderboard_LoadTopScores","path":"extensions/GooglePlayServices/GooglePlayServices.yy",}, {"name":"GooglePlayServices_SavedGames_ShowSavedGamesUI","path":"extensions/GooglePlayServices/GooglePlayServices.yy",}, {"name":"GooglePlayServices_SavedGames_CommitAndClose","path":"extensions/GooglePlayServices/GooglePlayServices.yy",}, + {"name":"GooglePlayServices_SavedGames_Load","path":"extensions/GooglePlayServices/GooglePlayServices.yy",}, {"name":"GooglePlayServices_SavedGames_Delete","path":"extensions/GooglePlayServices/GooglePlayServices.yy",}, {"name":"GooglePlayServices_SavedGames_DiscardAndClose","path":"extensions/GooglePlayServices/GooglePlayServices.yy",}, {"name":"GooglePlayServices_SavedGames_Open","path":"extensions/GooglePlayServices/GooglePlayServices.yy",}, - {"name":"GooglePlayServices_SavedGames_Load","path":"extensions/GooglePlayServices/GooglePlayServices.yy",}, {"name":"GooglePlayServices_SavedGames_ResolveConflict","path":"extensions/GooglePlayServices/GooglePlayServices.yy",}, {"name":"GooglePlayServices_SavedGames_CommitNew","path":"extensions/GooglePlayServices/GooglePlayServices.yy",}, - {"name":"GooglePlayServices_VideoRecording_ShowVideoOverlay","path":"extensions/GooglePlayServices/GooglePlayServices.yy",}, + {"name":"GooglePlayServices_Player_Current","path":"extensions/GooglePlayServices/GooglePlayServices.yy",}, + {"name":"GooglePlayServices_Player_CurrentID","path":"extensions/GooglePlayServices/GooglePlayServices.yy",}, + {"name":"GooglePlayServices_UriToPath","path":"extensions/GooglePlayServices/GooglePlayServices.yy",}, {"name":"GooglePlayServices_IsAvailable","path":"extensions/GooglePlayServices/GooglePlayServices.yy",}, - {"name":"GooglePlayServices_Achievements_GetStatus","path":"extensions/GooglePlayServices/GooglePlayServices.yy",}, - {"name":"GooglePlayServices_Leaderboard_LoadPlayerCenteredScores","path":"extensions/GooglePlayServices/GooglePlayServices.yy",}, - {"name":"GooglePlayServices_Leaderboard_LoadTopScores","path":"extensions/GooglePlayServices/GooglePlayServices.yy",}, ],"origname":"","ProxyFiles":[],"resourceType":"GMExtensionFile","resourceVersion":"2.0","uncompress":false,"usesRunnerInterface":false,}, ], - "gradleinject":"\r\nandroid {\r\n lintOptions {\r\n checkReleaseBuilds false\r\n abortOnError false\r\n }\r\n}\r\n\r\n//https://developers.google.com/android/guides/setup\r\ndependencies {\r\n//https://developers.google.com/android/guides/releases\r\n implementation 'com.google.android.gms:play-services-auth:20.1.0'\r\n implementation 'com.google.android.gms:play-services-games:22.0.1'\r\n}\r\n\r\n", + "gradleinject":"\r\nandroid {\r\n lintOptions {\r\n checkReleaseBuilds false\r\n abortOnError false\r\n }\r\n}\r\n\r\n//https://developers.google.com/android/guides/setup\r\ndependencies {\r\n//https://developers.google.com/android/guides/releases\r\n implementation \"com.google.android.gms:play-services-games-v2:+\"\r\n}\r\n\r\n", "hasConvertedCodeInjection":true, "helpfile":"", "HTML5CodeInjection":"", @@ -116,8 +103,18 @@ "macsourcedir":"", "name":"GooglePlayServices", "options":[ + {"$GMExtensionOption":"","%Name":"__extOptLabel","defaultValue":"APP OPTIONS:","description":"","displayName":"","exportToINI":false,"extensionId":null,"guid":"9d0b1496-d98c-4f0d-a615-f2afa4873468","hidden":false,"listItems":[],"name":"__extOptLabel","optType":5,"resourceType":"GMExtensionOption","resourceVersion":"2.0",}, {"$GMExtensionOption":"","%Name":"AppID","defaultValue":"","description":"","displayName":"","exportToINI":false,"extensionId":null,"guid":"2333e839-6686-4c10-a29b-851041b2e067","hidden":false,"listItems":[],"name":"AppID","optType":2,"resourceType":"GMExtensionOption","resourceVersion":"2.0",}, - {"$GMExtensionOption":"","%Name":"SavedGames","defaultValue":"True","description":"","displayName":"","exportToINI":true,"extensionId":null,"guid":"9a1bc5e1-1f6a-4128-bb77-f352c42a5bad","hidden":false,"listItems":[],"name":"SavedGames","optType":0,"resourceType":"GMExtensionOption","resourceVersion":"2.0",}, + {"$GMExtensionOption":"","%Name":"__extOptLabel1","defaultValue":"EXTRA OPTIONS:","description":"","displayName":"","exportToINI":false,"extensionId":null,"guid":"b8e7eb69-cec3-466b-b60e-9dfdea781aba","hidden":false,"listItems":[],"name":"__extOptLabel1","optType":5,"resourceType":"GMExtensionOption","resourceVersion":"2.0",}, + {"$GMExtensionOption":"","%Name":"logLevel","defaultValue":"1","description":"The log level to be used by the script file.\r\n0: Show only errors\r\n1: Show errors and warnings (recommended)\r\n2: Show everything (use before submitting a bug)","displayName":"Log Level","exportToINI":false,"extensionId":null,"guid":"99765f9a-ab54-45da-b2b3-e7119f9275a0","hidden":false,"listItems":[ + "0", + "1", + "2", + ],"name":"logLevel","optType":6,"resourceType":"GMExtensionOption","resourceVersion":"2.0",}, + {"$GMExtensionOption":"","%Name":"versionStable","defaultValue":"2022.9.0.0","description":"","displayName":"","exportToINI":false,"extensionId":null,"guid":"e0d1568c-d7ea-4236-956d-fb4729253091","hidden":true,"listItems":[],"name":"versionStable","optType":2,"resourceType":"GMExtensionOption","resourceVersion":"2.0",}, + {"$GMExtensionOption":"","%Name":"versionBeta","defaultValue":"2022.900.0.0","description":"","displayName":"","exportToINI":false,"extensionId":null,"guid":"ba9b6890-9864-4fa1-aaec-d65ced643b86","hidden":true,"listItems":[],"name":"versionBeta","optType":2,"resourceType":"GMExtensionOption","resourceVersion":"2.0",}, + {"$GMExtensionOption":"","%Name":"versionDev","defaultValue":"9.9.1.0","description":"","displayName":"","exportToINI":false,"extensionId":null,"guid":"6cd32340-3378-4234-bcac-ca9eb79d227a","hidden":true,"listItems":[],"name":"versionDev","optType":2,"resourceType":"GMExtensionOption","resourceVersion":"2.0",}, + {"$GMExtensionOption":"","%Name":"versionLTS","defaultValue":"2022.0.0.0","description":"","displayName":"","exportToINI":false,"extensionId":null,"guid":"3d566d80-4a40-4194-b092-6ec3f219c999","hidden":true,"listItems":[],"name":"versionLTS","optType":2,"resourceType":"GMExtensionOption","resourceVersion":"2.0",}, ], "optionsFile":"options.json", "packageId":"", diff --git a/extensions/GooglePlayServices/docs/404.html b/extensions/GooglePlayServices/docs/404.html new file mode 100644 index 000000000..5b654b239 --- /dev/null +++ b/extensions/GooglePlayServices/docs/404.html @@ -0,0 +1,142 @@ + + + + + + + + GMEXT-GooglePlayServices + + + + + + + + + + + + + + +
+ + +
+ +
+
+
    +
  • +
  • +
  • +
+
+
+
+
+ + +

404

+ +

Page not found

+ + +
+
+ +
+
+ +
+ +
+ +
+ + + + GitHub + + + + + +
+ + + + + + + + + + diff --git a/extensions/GooglePlayServices/docs/_footer.html b/extensions/GooglePlayServices/docs/_footer.html new file mode 100644 index 000000000..5494d059c --- /dev/null +++ b/extensions/GooglePlayServices/docs/_footer.html @@ -0,0 +1,147 @@ + + + + + + + + footer - GMEXT-GooglePlayServices + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+ +
+
+
+
+ +

GameMaker 2024

+ +
+
+ +
+
+ +
+ +
+ +
+ + + + GitHub + + + + + +
+ + + + + + + + + + diff --git a/extensions/GooglePlayServices/docs/_sidebar.html b/extensions/GooglePlayServices/docs/_sidebar.html new file mode 100644 index 000000000..138e42d9d --- /dev/null +++ b/extensions/GooglePlayServices/docs/_sidebar.html @@ -0,0 +1,161 @@ + + + + + + + + sidebar - GMEXT-GooglePlayServices + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+ +
+
+ + +
+
+ +
+ +
+ +
+ + + + GitHub + + + + + +
+ + + + + + + + + + diff --git a/extensions/GooglePlayServices/docs/achievements.html b/extensions/GooglePlayServices/docs/achievements.html new file mode 100644 index 000000000..387520ec5 --- /dev/null +++ b/extensions/GooglePlayServices/docs/achievements.html @@ -0,0 +1,763 @@ + + + + + + + + Achievements - GMEXT-GooglePlayServices + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+ +
+
+
+
+ +

+

Achievements

+

Achievements can be a great way to increase your users' engagement within your game. You can implement achievements in your game to encourage players to experiment with features they might not normally use, or to approach your game with entirely different play styles. Achievements can also be a fun way for players to compare their progress with each other and engage in light-hearted competition.

+

Functions

+

The following functions are provided for working with achievements:

+ +

Constants

+

The following constants are provided to be used as input arguments or output values:

+ +

Structs

+

The following structurs are used as output values from the function calls to the GooglePlayServices API:

+ +


+
+

Back To Top

+ +

GooglePlayServices_Achievements_GetStatus

+

This function requests the Google Play Services API to query the status of the achievements for the current player.

+

This function operates asynchronously, which means that it does not immediately return the requested result. Instead, upon completion of the task, it will trigger the Social Async Event.

+


+

Syntax:

+
+
GooglePlayServices_Achievements_GetStatus(forceReload)
+
+ + + + + + + + + + + + + + + +
ArgumentTypeDescription
forceReloadBooleanShould we force reload the achievements status.
+


+

Returns:

+
+

Real

+
+


+

Triggers:

+
+

Social Async Event

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeStringThe string "GooglePlayServices_Achievements_GetStatus"
indRealThe id of the request this callback refers to.
dataStringA json formatted string of an array of AchievementStatusJSON. This string can be parsed into a struct with the function json_parse.
+


+

Example:

+

GooglePlayServices_Achievements_GetStatus(achievementId);
+The code sample above will initialize the status querie for all the available achievements. The result can then be caught inside an Social Async Event. +
if(async_load[?"type"] == "GooglePlayServices_Achievements_GetStatus")
+{
+    var array = json_parse(async_load[?"data"])
+
+    array_sort(array, function(_ach1, _ach2) { return _ach1.name < _ach2.name ? -1 : 1 });
+    for(var a = 0 ; a < array_length(array) ; a++)
+    {
+        var struct = array[a];
+
+        show_debug_message(struct);
+
+        var ins = instance_create_depth(150+a*300,room_height/2-50,0,Obj_GooglePlayServices_Achievement_Entry)
+        ins.ID = struct.id
+        ins.description = struct.description
+        ins.lastUpdatedTimestamp = struct.lastUpdatedTimestamp
+        ins.name = struct.name
+        ins.revealedImage = struct.revealedImage
+        ins.state = struct.state
+        ins.typeAchievement = struct.typeAchievement
+        ins.unlockedImage = struct.unlockedImage
+        ins.xpValue = struct.xpValue
+
+        if(ins.typeAchievement == Achievement_TYPE_INCREMENTAL)
+        {
+            ins.currentSteps = struct.currentSteps
+            ins.formattedCurrentSteps = struct.formattedCurrentSteps
+            ins.formattedTotalSteps = struct.formattedTotalSteps
+            ins.totalSteps = struct.totalSteps
+        }
+    }
+}
+The code above shows a way of reading the returned data using the function json_parse. This sample is taken from the demo project check the project for more context.

+


+


+
+

Back To Top

+ +

GooglePlayServices_Achievements_Increment

+

This function requests the Google Play Services API to increment the achievement progress by a given amount of steps. Incremental achievements require a specific amount of steps before they are set as complete. You can also set the steps to a specific value using GooglePlayServices_Achievements_SetSteps.

+

This function operates asynchronously, which means that it does not immediately return the requested result. Instead, upon completion of the task, it will trigger the Social Async Event.

+


+

Syntax:

+
+
GooglePlayServices_Achievements_Increment(achievementId, steps)
+
+ + + + + + + + + + + + + + + + + + + + +
ArgumentTypeDescription
achievementIdStringThe unique identifier of the achievement
stepsRealThe amount of steps to increment by
+


+

Returns:

+
+

Real

+
+


+

Triggers:

+
+

Social Async Event

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeStringThe string "GooglePlayServices_Achievements_Increment"
indRealThe id of the request this callback refers to.
successBooleanWhether or not the function request succeeded.
achievement_idStringThe unique name of the achievement
+


+

Example:

+

GooglePlayServices_Achievements_Increment(achievementId, 1);
+The code sample above will increment the number of steps for the specified acheivement by 1. The result can be caught inside an Social Async Event as follows: +
if(async_load[?"type"] == "GooglePlayServices_Achievements_Increment")
+if(async_load[?"success"])
+{
+    //Done, let's continue
+}
+The code above checks if the task was successful. This sample is taken from the demo project check the project for more context.

+


+


+
+

Back To Top

+ +

GooglePlayServices_Achievements_Reveal

+

This function requests the Google Play Services API to change the state of a given achievement to revealed (AchievementState) for the currently signed in player.

+

This function operates asynchronously, which means that it does not immediately return the requested result. Instead, upon completion of the task, it will trigger the Social Async Event.

+


+

Syntax:

+
+
GooglePlayServices_Achievements_Reveal(achievementId)
+
+ + + + + + + + + + + + + + + +
ArgumentTypeDescription
achievementIdStringThe unique identifier of the achievement
+


+

Returns:

+
+

Real

+
+


+

Triggers:

+
+

Social Async Event

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeStringThe string "GooglePlayServices_Achievements_Reveal"
indRealThe id of the request this callback refers to.
successBooleanWhether or not the function request succeeded.
achievement_idStringThe unique name of the achievement
+


+

Example:

+

GooglePlayServices_Achievements_Reveal(achievementId);
+The code sample above will set the state of the specified acheivement to revealed. The result can be caught inside an Social Async Event as follows: +
if(async_load[?"type"] == "GooglePlayServices_Achievements_Reveal")
+if(async_load[?"success"])
+{
+    //Done, let's continue
+}
+The code above checks if the task was successful. This sample is taken from the demo project check the project for more context.

+


+


+
+

Back To Top

+ +

GooglePlayServices_Achievements_SetSteps

+

This function requests the Google Play Services API to set the achievement progress to a given amount of steps. Incremental achievements require a specific amount of steps before they are set as complete. You can also increment the steps by a given amount using GooglePlayServices_Achievements_Increment.

+

This function operates asynchronously, which means that it does not immediately return the requested result. Instead, upon completion of the task, it will trigger the Social Async Event.

+


+

Syntax:

+
+
GooglePlayServices_Achievements_SetSteps()
+
+


+

Returns:

+
+

Real

+
+


+

Triggers:

+
+

Social Async Event

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeStringThe string "GooglePlayServices_Achievements_SetSteps"
indRealThe id of the request this callback refers to.
successBooleanWhether or not the function request succeeded.
achievement_idStringThe unique name of the achievement
+


+

Example:

+

GooglePlayServices_Achievements_SetSteps(achievementId,1);
+The code sample above will set the number of steps for the specified acheivement to 1. The result can be caught inside an Social Async Event as follows: +
if(async_load[?"type"] == "GooglePlayServices_Achievements_SetSteps")
+if(async_load[?"success"])
+{
+    //Done, let's continue
+}
+The code above checks if the task was successful. This sample is taken from the demo project check the project for more context.

+


+


+
+

Back To Top

+ +

GooglePlayServices_Achievements_Show

+

This function will call the Google Play Services achievement overlay with all your achievement information.

+


+

Syntax:

+
+
GooglePlayServices_Achievements_Show()
+
+


+

Returns:

+
+

N/A

+
+


+

Example:

+

GooglePlayServices_Achievements_Show()
+The code above will trigger the achievement overlay.

+


+


+
+

Back To Top

+ +

GooglePlayServices_Achievements_Unlock

+

This function requests the Google Play Services API to unlock (AchievementState) the given achievement for the currently signed in player.

+

This function operates asynchronously, which means that it does not immediately return the requested result. Instead, upon completion of the task, it will trigger the Social Async Event.

+


+

Syntax:

+
+
GooglePlayServices_Achievements_Unlock(achievementId)
+
+ + + + + + + + + + + + + + + +
ArgumentTypeDescription
achievementIdStringThe unique identifier of the achievement
+


+

Returns:

+
+

Real

+
+


+

Triggers:

+
+

Social Async Event

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeStringThe string "GooglePlayServices_Achievements_Unlock"
indRealThe id of the request this callback refers to.
successBooleanWhether or not the function request succeeded.
achievement_idStringThe unique name of the achievement
+


+

Example:

+

GooglePlayServices_Achievements_Unlock(achievementId);
+The code sample above will set the state of the specified acheivement to unlocked. The result can be caught inside an Social Async Event as follows: +
if(async_load[?"type"] == "GooglePlayServices_Achievements_Unlock")
+if(async_load[?"success"])
+{
+    //Done, let's continue
+}
+The code above checks if the task was successful. This sample is taken from the demo project check the project for more context.

+


+


+
+

Back To Top

+ +

AchievementState

+

These constants specify the achievement state.

+

These constants are referenced by the following structs:

+ +


+ + + + + + + + + + + + + + + + + + + + + +
MemberDescription
Achievement_STATE_HIDDENIndicates a hidden achievement.
Achievement_STATE_REVEALEDIndicates a revealed achievement.
Achievement_STATE_UNLOCKEDIndicates an unlocked achievement.
+


+
+

Back To Top

+ +

AchievementType

+

These constants specify the type on an achievement.

+

These constants are referenced by the following structs:

+ +


+ + + + + + + + + + + + + + + + + +
MemberDescription
Achievement_TYPE_INCREMENTALIndicates an incremental achievement.
Achievement_TYPE_STANDARDIndicates a standard achievement.
+


+
+

Back To Top

+ +

AchievementStatusJSON

+

Represents an achievement and its associated metadata.

+


+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MemberTypeDescription
idStringThe ID of this achievement.
nameStringThe name of this achievement.
descriptionStringThe description for this achievement.
stateAchievementStateThe AchievementState of the achievement.
typeAchievementAchievementTypeThe AchievementType of the achievement.
xpValueRealThe XP value of this achievement.
lastUpdatedTimestampRealThe timestamp (in millseconds since epoch) at which this achievement was last updated.
revealedImageStringA URI string that can be used to load the achievement's revealed image icon (see GooglePlayServices_UriToPath). Not present if the achievement has no revealed image.
unlockedImageStringA URI string that can be used to load the achievement's unlocked image icon (see GooglePlayServices_UriToPath). Not present if the achievement has no revealed image.
currentStepsRealThe number of steps this user has gone toward unlocking this achievement. Only available for incremental achievement types (AchievementType).
formattedCurrentStepsStringThe number of steps this user has gone toward unlocking this achievement (formatted for the user's locale). Only available for incremental achievement types (AchievementType).
totalStepsRealThe total number of steps necessary to unlock this achievement. Only available for incremental achievement types (AchievementType).
formattedTotalStepsStringThe total number of steps necessary to unlock this achievement, formatted for the user's locale. Only available for incremental achievement types (AchievementType).
+


+ +
+
+ +
+
+ +
+ +
+ +
+ + + + GitHub + + + + « Previous + + + Next » + + +
+ + + + + + + + + + diff --git a/extensions/GooglePlayServices/docs/assets/CloudSync_AddServices.png b/extensions/GooglePlayServices/docs/assets/CloudSync_AddServices.png new file mode 100644 index 000000000..a208c2eeb Binary files /dev/null and b/extensions/GooglePlayServices/docs/assets/CloudSync_AddServices.png differ diff --git a/extensions/GooglePlayServices/docs/assets/CloudSync_GameDetails.png b/extensions/GooglePlayServices/docs/assets/CloudSync_GameDetails.png new file mode 100644 index 000000000..5e1cf5542 Binary files /dev/null and b/extensions/GooglePlayServices/docs/assets/CloudSync_GameDetails.png differ diff --git a/extensions/GooglePlayServices/docs/assets/CloudSync_GetID.png b/extensions/GooglePlayServices/docs/assets/CloudSync_GetID.png new file mode 100644 index 000000000..587de31b1 Binary files /dev/null and b/extensions/GooglePlayServices/docs/assets/CloudSync_GetID.png differ diff --git a/extensions/GooglePlayServices/docs/assets/CloudSync_SetSaving.png b/extensions/GooglePlayServices/docs/assets/CloudSync_SetSaving.png new file mode 100644 index 000000000..5b453b7aa Binary files /dev/null and b/extensions/GooglePlayServices/docs/assets/CloudSync_SetSaving.png differ diff --git a/extensions/GooglePlayServices/docs/assets/css/gmext_style.css b/extensions/GooglePlayServices/docs/assets/css/gmext_style.css new file mode 100644 index 000000000..9e2e42e83 --- /dev/null +++ b/extensions/GooglePlayServices/docs/assets/css/gmext_style.css @@ -0,0 +1,65 @@ +.wy-table-responsive table td, .wy-table-responsive th { + word-wrap: break-word; + white-space: normal; /* Allows text to wrap within cells */ +} + +.wy-table-responsive thead, +.wy-table-responsive tbody, +.wy-table-responsive th, +.wy-table-responsive tr { + width: 1000px; +} + +.wy-table-responsive th:not(:last-child), +.wy-table-responsive td:not(:last-child) { + width: 20%; /* Adjust based on the number of columns */ +} + +.wy-table-responsive img, +.wy-table-responsive iframe { + max-width: 100%; + height: auto; /* Maintain aspect ratio for images */ +} + +.wy-table-responsive pre, +.wy-table-responsive code { + overflow-x: auto; /* Allows horizontal scrolling for long unbreakable content */ + white-space: pre-wrap; /* Allows text to wrap within pre/code blocks */ + word-wrap: break-word; /* Breaks long words if necessary */ +} + +hr { + height: 2px; + background:#03759b; +} + +/* Adjust emoji size */ +.emojione { + height: 1em; /* Matches the line-height of surrounding text */ + width: 1em; /* Keeps the emoji width consistent with its height */ + vertical-align: middle; /* Aligns emoji with the middle of the text line */ +} + +.copy-code-button { + display: inline-flex; /* Use flexbox to center the icon */ + justify-content: center; /* Center content horizontally */ + align-items: center; /* Center content vertically */ + position: relative; + top: -0.5em; + right: -0.5em; + float: right; + width: 1.8em; /* Set both width */ + height: 1.8em; /* and height to make the button square */ + padding: 0; /* Adjust padding as needed */ + margin-bottom: -3em; + background-color: #007bff; /* Blue background */ + color: white; + border: none; + cursor: pointer; + border-radius: 3px; + font-size: 1em; /* Adjust the icon size as necessary */ +} + +.copy-code-button:hover { + background-color: #0056b3; +} diff --git a/extensions/GooglePlayServices/docs/assets/gps_setup_ext_options.png b/extensions/GooglePlayServices/docs/assets/gps_setup_ext_options.png new file mode 100644 index 000000000..fc451c6d2 Binary files /dev/null and b/extensions/GooglePlayServices/docs/assets/gps_setup_ext_options.png differ diff --git a/extensions/GooglePlayServices/docs/assets/js/gmext_script.js b/extensions/GooglePlayServices/docs/assets/js/gmext_script.js new file mode 100644 index 000000000..f6bf67d59 --- /dev/null +++ b/extensions/GooglePlayServices/docs/assets/js/gmext_script.js @@ -0,0 +1,49 @@ +document.addEventListener('DOMContentLoaded', function() { + + // Top left link should point ot the github page + var link = document.querySelector('a.icon.icon-home'); + var githublink = document.querySelector('a.fa.fa-github') + if (link && githublink) { + link.href = githublink.href; + } + + // Point home icon to home.html + var home_link = document.querySelector('a.icon.icon-home[aria-label="Docs"]'); + home_link.href = 'home.html' + + // Remove the editor icon + var element = document.querySelector('li.wy-breadcrumbs-aside'); + if (element) { + element.remove(); + } + + // Add copy-to-clipboard on code blocks + const codeBlocks = document.querySelectorAll('pre code'); + codeBlocks.forEach(function(codeBlock) { + const button = document.createElement('button'); + button.className = 'copy-code-button'; + button.type = 'button'; + button.innerHTML = ''; // Clipboard icon + button.addEventListener('click', function() { + navigator.clipboard.writeText(codeBlock.innerText).then(() => { + const originalInnerHTML = button.innerHTML; + button.innerHTML = ''; // Check icon + button.style.backgroundColor = "#28a745"; // Change button to green + setTimeout(() => { + button.innerHTML = originalInnerHTML; // Reset icon + button.style.backgroundColor = ""; // Reset button color + }, 2000); // Reset icon and button color after 2 seconds + }, (err) => { + console.error('Failed to copy text: ', err); + }); + }); + + const pre = codeBlock.parentNode; + if (pre.parentNode.classList.contains('highlight')) { + const highlight = pre.parentNode; + highlight.parentNode.insertBefore(button, highlight); + } else { + pre.parentNode.insertBefore(button, pre); + } + }); +}); diff --git a/extensions/GooglePlayServices/docs/css/fonts/Roboto-Slab-Bold.woff b/extensions/GooglePlayServices/docs/css/fonts/Roboto-Slab-Bold.woff new file mode 100644 index 000000000..6cb600001 Binary files /dev/null and b/extensions/GooglePlayServices/docs/css/fonts/Roboto-Slab-Bold.woff differ diff --git a/extensions/GooglePlayServices/docs/css/fonts/Roboto-Slab-Bold.woff2 b/extensions/GooglePlayServices/docs/css/fonts/Roboto-Slab-Bold.woff2 new file mode 100644 index 000000000..7059e2314 Binary files /dev/null and b/extensions/GooglePlayServices/docs/css/fonts/Roboto-Slab-Bold.woff2 differ diff --git a/extensions/GooglePlayServices/docs/css/fonts/Roboto-Slab-Regular.woff b/extensions/GooglePlayServices/docs/css/fonts/Roboto-Slab-Regular.woff new file mode 100644 index 000000000..f815f63f9 Binary files /dev/null and b/extensions/GooglePlayServices/docs/css/fonts/Roboto-Slab-Regular.woff differ diff --git a/extensions/GooglePlayServices/docs/css/fonts/Roboto-Slab-Regular.woff2 b/extensions/GooglePlayServices/docs/css/fonts/Roboto-Slab-Regular.woff2 new file mode 100644 index 000000000..f2c76e5bd Binary files /dev/null and b/extensions/GooglePlayServices/docs/css/fonts/Roboto-Slab-Regular.woff2 differ diff --git a/extensions/GooglePlayServices/docs/css/fonts/fontawesome-webfont.eot b/extensions/GooglePlayServices/docs/css/fonts/fontawesome-webfont.eot new file mode 100644 index 000000000..e9f60ca95 Binary files /dev/null and b/extensions/GooglePlayServices/docs/css/fonts/fontawesome-webfont.eot differ diff --git a/extensions/GooglePlayServices/docs/css/fonts/fontawesome-webfont.svg b/extensions/GooglePlayServices/docs/css/fonts/fontawesome-webfont.svg new file mode 100644 index 000000000..855c845e5 --- /dev/null +++ b/extensions/GooglePlayServices/docs/css/fonts/fontawesome-webfont.svg @@ -0,0 +1,2671 @@ + + + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/extensions/GooglePlayServices/docs/css/fonts/fontawesome-webfont.ttf b/extensions/GooglePlayServices/docs/css/fonts/fontawesome-webfont.ttf new file mode 100644 index 000000000..35acda2fa Binary files /dev/null and b/extensions/GooglePlayServices/docs/css/fonts/fontawesome-webfont.ttf differ diff --git a/extensions/GooglePlayServices/docs/css/fonts/fontawesome-webfont.woff b/extensions/GooglePlayServices/docs/css/fonts/fontawesome-webfont.woff new file mode 100644 index 000000000..400014a4b Binary files /dev/null and b/extensions/GooglePlayServices/docs/css/fonts/fontawesome-webfont.woff differ diff --git a/extensions/GooglePlayServices/docs/css/fonts/fontawesome-webfont.woff2 b/extensions/GooglePlayServices/docs/css/fonts/fontawesome-webfont.woff2 new file mode 100644 index 000000000..4d13fc604 Binary files /dev/null and b/extensions/GooglePlayServices/docs/css/fonts/fontawesome-webfont.woff2 differ diff --git a/extensions/GooglePlayServices/docs/css/fonts/lato-bold-italic.woff b/extensions/GooglePlayServices/docs/css/fonts/lato-bold-italic.woff new file mode 100644 index 000000000..88ad05b9f Binary files /dev/null and b/extensions/GooglePlayServices/docs/css/fonts/lato-bold-italic.woff differ diff --git a/extensions/GooglePlayServices/docs/css/fonts/lato-bold-italic.woff2 b/extensions/GooglePlayServices/docs/css/fonts/lato-bold-italic.woff2 new file mode 100644 index 000000000..c4e3d804b Binary files /dev/null and b/extensions/GooglePlayServices/docs/css/fonts/lato-bold-italic.woff2 differ diff --git a/extensions/GooglePlayServices/docs/css/fonts/lato-bold.woff b/extensions/GooglePlayServices/docs/css/fonts/lato-bold.woff new file mode 100644 index 000000000..c6dff51f0 Binary files /dev/null and b/extensions/GooglePlayServices/docs/css/fonts/lato-bold.woff differ diff --git a/extensions/GooglePlayServices/docs/css/fonts/lato-bold.woff2 b/extensions/GooglePlayServices/docs/css/fonts/lato-bold.woff2 new file mode 100644 index 000000000..bb195043c Binary files /dev/null and b/extensions/GooglePlayServices/docs/css/fonts/lato-bold.woff2 differ diff --git a/extensions/GooglePlayServices/docs/css/fonts/lato-normal-italic.woff b/extensions/GooglePlayServices/docs/css/fonts/lato-normal-italic.woff new file mode 100644 index 000000000..76114bc03 Binary files /dev/null and b/extensions/GooglePlayServices/docs/css/fonts/lato-normal-italic.woff differ diff --git a/extensions/GooglePlayServices/docs/css/fonts/lato-normal-italic.woff2 b/extensions/GooglePlayServices/docs/css/fonts/lato-normal-italic.woff2 new file mode 100644 index 000000000..3404f37e2 Binary files /dev/null and b/extensions/GooglePlayServices/docs/css/fonts/lato-normal-italic.woff2 differ diff --git a/extensions/GooglePlayServices/docs/css/fonts/lato-normal.woff b/extensions/GooglePlayServices/docs/css/fonts/lato-normal.woff new file mode 100644 index 000000000..ae1307ff5 Binary files /dev/null and b/extensions/GooglePlayServices/docs/css/fonts/lato-normal.woff differ diff --git a/extensions/GooglePlayServices/docs/css/fonts/lato-normal.woff2 b/extensions/GooglePlayServices/docs/css/fonts/lato-normal.woff2 new file mode 100644 index 000000000..3bf984332 Binary files /dev/null and b/extensions/GooglePlayServices/docs/css/fonts/lato-normal.woff2 differ diff --git a/extensions/GooglePlayServices/docs/css/theme.css b/extensions/GooglePlayServices/docs/css/theme.css new file mode 100644 index 000000000..ad773009b --- /dev/null +++ b/extensions/GooglePlayServices/docs/css/theme.css @@ -0,0 +1,13 @@ +/* + * This file is copied from the upstream ReadTheDocs Sphinx + * theme. To aid upgradability this file should *not* be edited. + * modifications we need should be included in theme_extra.css. + * + * https://github.com/readthedocs/sphinx_rtd_theme + */ + + /* sphinx_rtd_theme version 1.2.0 | MIT license */ +html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden],audio:not([controls]){display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;text-decoration:none}ins,mark{color:#000}mark{background:#ff0;font-style:italic;font-weight:700}.rst-content code,.rst-content tt,code,kbd,pre,samp{font-family:monospace,serif;_font-family:courier new,monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:after,q:before{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}dl,ol,ul{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure,form{margin:0}label{cursor:pointer}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type=button],input[type=reset],input[type=submit]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}textarea{resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:.2em 0;background:#ccc;color:#000;padding:.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none!important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{body,html,section{background:none!important}*{box-shadow:none!important;text-shadow:none!important;filter:none!important;-ms-filter:none!important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}.rst-content .toctree-wrapper>p.caption,h2,h3,p{orphans:3;widows:3}.rst-content .toctree-wrapper>p.caption,h2,h3{page-break-after:avoid}}.btn,.fa:before,.icon:before,.rst-content .admonition,.rst-content .admonition-title:before,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .code-block-caption .headerlink:before,.rst-content .danger,.rst-content .eqno .headerlink:before,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-alert,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before,input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week],select,textarea{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:FontAwesome;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713);src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix&v=4.7.0) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#fontawesomeregular) format("svg");font-weight:400;font-style:normal}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14286em;width:2.14286em;top:.14286em;text-align:center}.fa-li.fa-lg{left:-1.85714em}.fa-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa-pull-left.icon,.fa.fa-pull-left,.rst-content .code-block-caption .fa-pull-left.headerlink,.rst-content .eqno .fa-pull-left.headerlink,.rst-content .fa-pull-left.admonition-title,.rst-content code.download span.fa-pull-left:first-child,.rst-content dl dt .fa-pull-left.headerlink,.rst-content h1 .fa-pull-left.headerlink,.rst-content h2 .fa-pull-left.headerlink,.rst-content h3 .fa-pull-left.headerlink,.rst-content h4 .fa-pull-left.headerlink,.rst-content h5 .fa-pull-left.headerlink,.rst-content h6 .fa-pull-left.headerlink,.rst-content p .fa-pull-left.headerlink,.rst-content table>caption .fa-pull-left.headerlink,.rst-content tt.download span.fa-pull-left:first-child,.wy-menu-vertical li.current>a button.fa-pull-left.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-left.toctree-expand,.wy-menu-vertical li button.fa-pull-left.toctree-expand{margin-right:.3em}.fa-pull-right.icon,.fa.fa-pull-right,.rst-content .code-block-caption .fa-pull-right.headerlink,.rst-content .eqno .fa-pull-right.headerlink,.rst-content .fa-pull-right.admonition-title,.rst-content code.download span.fa-pull-right:first-child,.rst-content dl dt .fa-pull-right.headerlink,.rst-content h1 .fa-pull-right.headerlink,.rst-content h2 .fa-pull-right.headerlink,.rst-content h3 .fa-pull-right.headerlink,.rst-content h4 .fa-pull-right.headerlink,.rst-content h5 .fa-pull-right.headerlink,.rst-content h6 .fa-pull-right.headerlink,.rst-content p .fa-pull-right.headerlink,.rst-content table>caption .fa-pull-right.headerlink,.rst-content tt.download span.fa-pull-right:first-child,.wy-menu-vertical li.current>a button.fa-pull-right.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-right.toctree-expand,.wy-menu-vertical li button.fa-pull-right.toctree-expand{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.pull-left.icon,.rst-content .code-block-caption .pull-left.headerlink,.rst-content .eqno .pull-left.headerlink,.rst-content .pull-left.admonition-title,.rst-content code.download span.pull-left:first-child,.rst-content dl dt .pull-left.headerlink,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content p .pull-left.headerlink,.rst-content table>caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.wy-menu-vertical li.current>a button.pull-left.toctree-expand,.wy-menu-vertical li.on a button.pull-left.toctree-expand,.wy-menu-vertical li button.pull-left.toctree-expand{margin-right:.3em}.fa.pull-right,.pull-right.icon,.rst-content .code-block-caption .pull-right.headerlink,.rst-content .eqno .pull-right.headerlink,.rst-content .pull-right.admonition-title,.rst-content code.download span.pull-right:first-child,.rst-content dl dt .pull-right.headerlink,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content p .pull-right.headerlink,.rst-content table>caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.wy-menu-vertical li.current>a button.pull-right.toctree-expand,.wy-menu-vertical li.on a button.pull-right.toctree-expand,.wy-menu-vertical li button.pull-right.toctree-expand{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);-ms-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scaleY(-1);-ms-transform:scaleY(-1);transform:scaleY(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-close:before,.fa-remove:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-cog:before,.fa-gear:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-repeat:before,.fa-rotate-right:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-image:before,.fa-photo:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:""}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before,.rst-content .admonition-title:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before,.icon-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-exclamation-triangle:before,.fa-warning:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-cogs:before,.fa-gears:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook-f:before,.fa-facebook:before{content:""}.fa-github:before,.icon-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-feed:before,.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-floppy-o:before,.fa-save:before{content:""}.fa-square:before{content:""}.fa-bars:before,.fa-navicon:before,.fa-reorder:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.icon-caret-down:before,.wy-dropdown .caret:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-sort:before,.fa-unsorted:before{content:""}.fa-sort-desc:before,.fa-sort-down:before{content:""}.fa-sort-asc:before,.fa-sort-up:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-gavel:before,.fa-legal:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-bolt:before,.fa-flash:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-clipboard:before,.fa-paste:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-chain-broken:before,.fa-unlink:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-caret-square-o-down:before,.fa-toggle-down:before{content:""}.fa-caret-square-o-up:before,.fa-toggle-up:before{content:""}.fa-caret-square-o-right:before,.fa-toggle-right:before{content:""}.fa-eur:before,.fa-euro:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-inr:before,.fa-rupee:before{content:""}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen:before{content:""}.fa-rouble:before,.fa-rub:before,.fa-ruble:before{content:""}.fa-krw:before,.fa-won:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before,.icon-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before,.fa-gratipay:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-caret-square-o-left:before,.fa-toggle-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-try:before,.fa-turkish-lira:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li button.toctree-expand:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-bank:before,.fa-institution:before,.fa-university:before{content:""}.fa-graduation-cap:before,.fa-mortar-board:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper-pp:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-image-o:before,.fa-file-photo-o:before,.fa-file-picture-o:before{content:""}.fa-file-archive-o:before,.fa-file-zip-o:before{content:""}.fa-file-audio-o:before,.fa-file-sound-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-ring:before,.fa-life-saver:before,.fa-support:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-rebel:before,.fa-resistance:before{content:""}.fa-empire:before,.fa-ge:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-hacker-news:before,.fa-y-combinator-square:before,.fa-yc-square:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-paper-plane:before,.fa-send:before{content:""}.fa-paper-plane-o:before,.fa-send-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-futbol-o:before,.fa-soccer-ball-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-ils:before,.fa-shekel:before,.fa-sheqel:before{content:""}.fa-meanpath:before{content:""}.fa-buysellads:before{content:""}.fa-connectdevelop:before{content:""}.fa-dashcube:before{content:""}.fa-forumbee:before{content:""}.fa-leanpub:before{content:""}.fa-sellsy:before{content:""}.fa-shirtsinbulk:before{content:""}.fa-simplybuilt:before{content:""}.fa-skyatlas:before{content:""}.fa-cart-plus:before{content:""}.fa-cart-arrow-down:before{content:""}.fa-diamond:before{content:""}.fa-ship:before{content:""}.fa-user-secret:before{content:""}.fa-motorcycle:before{content:""}.fa-street-view:before{content:""}.fa-heartbeat:before{content:""}.fa-venus:before{content:""}.fa-mars:before{content:""}.fa-mercury:before{content:""}.fa-intersex:before,.fa-transgender:before{content:""}.fa-transgender-alt:before{content:""}.fa-venus-double:before{content:""}.fa-mars-double:before{content:""}.fa-venus-mars:before{content:""}.fa-mars-stroke:before{content:""}.fa-mars-stroke-v:before{content:""}.fa-mars-stroke-h:before{content:""}.fa-neuter:before{content:""}.fa-genderless:before{content:""}.fa-facebook-official:before{content:""}.fa-pinterest-p:before{content:""}.fa-whatsapp:before{content:""}.fa-server:before{content:""}.fa-user-plus:before{content:""}.fa-user-times:before{content:""}.fa-bed:before,.fa-hotel:before{content:""}.fa-viacoin:before{content:""}.fa-train:before{content:""}.fa-subway:before{content:""}.fa-medium:before{content:""}.fa-y-combinator:before,.fa-yc:before{content:""}.fa-optin-monster:before{content:""}.fa-opencart:before{content:""}.fa-expeditedssl:before{content:""}.fa-battery-4:before,.fa-battery-full:before,.fa-battery:before{content:""}.fa-battery-3:before,.fa-battery-three-quarters:before{content:""}.fa-battery-2:before,.fa-battery-half:before{content:""}.fa-battery-1:before,.fa-battery-quarter:before{content:""}.fa-battery-0:before,.fa-battery-empty:before{content:""}.fa-mouse-pointer:before{content:""}.fa-i-cursor:before{content:""}.fa-object-group:before{content:""}.fa-object-ungroup:before{content:""}.fa-sticky-note:before{content:""}.fa-sticky-note-o:before{content:""}.fa-cc-jcb:before{content:""}.fa-cc-diners-club:before{content:""}.fa-clone:before{content:""}.fa-balance-scale:before{content:""}.fa-hourglass-o:before{content:""}.fa-hourglass-1:before,.fa-hourglass-start:before{content:""}.fa-hourglass-2:before,.fa-hourglass-half:before{content:""}.fa-hourglass-3:before,.fa-hourglass-end:before{content:""}.fa-hourglass:before{content:""}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:""}.fa-hand-paper-o:before,.fa-hand-stop-o:before{content:""}.fa-hand-scissors-o:before{content:""}.fa-hand-lizard-o:before{content:""}.fa-hand-spock-o:before{content:""}.fa-hand-pointer-o:before{content:""}.fa-hand-peace-o:before{content:""}.fa-trademark:before{content:""}.fa-registered:before{content:""}.fa-creative-commons:before{content:""}.fa-gg:before{content:""}.fa-gg-circle:before{content:""}.fa-tripadvisor:before{content:""}.fa-odnoklassniki:before{content:""}.fa-odnoklassniki-square:before{content:""}.fa-get-pocket:before{content:""}.fa-wikipedia-w:before{content:""}.fa-safari:before{content:""}.fa-chrome:before{content:""}.fa-firefox:before{content:""}.fa-opera:before{content:""}.fa-internet-explorer:before{content:""}.fa-television:before,.fa-tv:before{content:""}.fa-contao:before{content:""}.fa-500px:before{content:""}.fa-amazon:before{content:""}.fa-calendar-plus-o:before{content:""}.fa-calendar-minus-o:before{content:""}.fa-calendar-times-o:before{content:""}.fa-calendar-check-o:before{content:""}.fa-industry:before{content:""}.fa-map-pin:before{content:""}.fa-map-signs:before{content:""}.fa-map-o:before{content:""}.fa-map:before{content:""}.fa-commenting:before{content:""}.fa-commenting-o:before{content:""}.fa-houzz:before{content:""}.fa-vimeo:before{content:""}.fa-black-tie:before{content:""}.fa-fonticons:before{content:""}.fa-reddit-alien:before{content:""}.fa-edge:before{content:""}.fa-credit-card-alt:before{content:""}.fa-codiepie:before{content:""}.fa-modx:before{content:""}.fa-fort-awesome:before{content:""}.fa-usb:before{content:""}.fa-product-hunt:before{content:""}.fa-mixcloud:before{content:""}.fa-scribd:before{content:""}.fa-pause-circle:before{content:""}.fa-pause-circle-o:before{content:""}.fa-stop-circle:before{content:""}.fa-stop-circle-o:before{content:""}.fa-shopping-bag:before{content:""}.fa-shopping-basket:before{content:""}.fa-hashtag:before{content:""}.fa-bluetooth:before{content:""}.fa-bluetooth-b:before{content:""}.fa-percent:before{content:""}.fa-gitlab:before,.icon-gitlab:before{content:""}.fa-wpbeginner:before{content:""}.fa-wpforms:before{content:""}.fa-envira:before{content:""}.fa-universal-access:before{content:""}.fa-wheelchair-alt:before{content:""}.fa-question-circle-o:before{content:""}.fa-blind:before{content:""}.fa-audio-description:before{content:""}.fa-volume-control-phone:before{content:""}.fa-braille:before{content:""}.fa-assistive-listening-systems:before{content:""}.fa-american-sign-language-interpreting:before,.fa-asl-interpreting:before{content:""}.fa-deaf:before,.fa-deafness:before,.fa-hard-of-hearing:before{content:""}.fa-glide:before{content:""}.fa-glide-g:before{content:""}.fa-sign-language:before,.fa-signing:before{content:""}.fa-low-vision:before{content:""}.fa-viadeo:before{content:""}.fa-viadeo-square:before{content:""}.fa-snapchat:before{content:""}.fa-snapchat-ghost:before{content:""}.fa-snapchat-square:before{content:""}.fa-pied-piper:before{content:""}.fa-first-order:before{content:""}.fa-yoast:before{content:""}.fa-themeisle:before{content:""}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:""}.fa-fa:before,.fa-font-awesome:before{content:""}.fa-handshake-o:before{content:""}.fa-envelope-open:before{content:""}.fa-envelope-open-o:before{content:""}.fa-linode:before{content:""}.fa-address-book:before{content:""}.fa-address-book-o:before{content:""}.fa-address-card:before,.fa-vcard:before{content:""}.fa-address-card-o:before,.fa-vcard-o:before{content:""}.fa-user-circle:before{content:""}.fa-user-circle-o:before{content:""}.fa-user-o:before{content:""}.fa-id-badge:before{content:""}.fa-drivers-license:before,.fa-id-card:before{content:""}.fa-drivers-license-o:before,.fa-id-card-o:before{content:""}.fa-quora:before{content:""}.fa-free-code-camp:before{content:""}.fa-telegram:before{content:""}.fa-thermometer-4:before,.fa-thermometer-full:before,.fa-thermometer:before{content:""}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:""}.fa-thermometer-2:before,.fa-thermometer-half:before{content:""}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:""}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:""}.fa-shower:before{content:""}.fa-bath:before,.fa-bathtub:before,.fa-s15:before{content:""}.fa-podcast:before{content:""}.fa-window-maximize:before{content:""}.fa-window-minimize:before{content:""}.fa-window-restore:before{content:""}.fa-times-rectangle:before,.fa-window-close:before{content:""}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:""}.fa-bandcamp:before{content:""}.fa-grav:before{content:""}.fa-etsy:before{content:""}.fa-imdb:before{content:""}.fa-ravelry:before{content:""}.fa-eercast:before{content:""}.fa-microchip:before{content:""}.fa-snowflake-o:before{content:""}.fa-superpowers:before{content:""}.fa-wpexplorer:before{content:""}.fa-meetup:before{content:""}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{font-family:inherit}.fa:before,.icon:before,.rst-content .admonition-title:before,.rst-content .code-block-caption .headerlink:before,.rst-content .eqno .headerlink:before,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before{font-family:FontAwesome;display:inline-block;font-style:normal;font-weight:400;line-height:1;text-decoration:inherit}.rst-content .code-block-caption a .headerlink,.rst-content .eqno a .headerlink,.rst-content a .admonition-title,.rst-content code.download a span:first-child,.rst-content dl dt a .headerlink,.rst-content h1 a .headerlink,.rst-content h2 a .headerlink,.rst-content h3 a .headerlink,.rst-content h4 a .headerlink,.rst-content h5 a .headerlink,.rst-content h6 a .headerlink,.rst-content p.caption a .headerlink,.rst-content p a .headerlink,.rst-content table>caption a .headerlink,.rst-content tt.download a span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li a button.toctree-expand,a .fa,a .icon,a .rst-content .admonition-title,a .rst-content .code-block-caption .headerlink,a .rst-content .eqno .headerlink,a .rst-content code.download span:first-child,a .rst-content dl dt .headerlink,a .rst-content h1 .headerlink,a .rst-content h2 .headerlink,a .rst-content h3 .headerlink,a .rst-content h4 .headerlink,a .rst-content h5 .headerlink,a .rst-content h6 .headerlink,a .rst-content p.caption .headerlink,a .rst-content p .headerlink,a .rst-content table>caption .headerlink,a .rst-content tt.download span:first-child,a .wy-menu-vertical li button.toctree-expand{display:inline-block;text-decoration:inherit}.btn .fa,.btn .icon,.btn .rst-content .admonition-title,.btn .rst-content .code-block-caption .headerlink,.btn .rst-content .eqno .headerlink,.btn .rst-content code.download span:first-child,.btn .rst-content dl dt .headerlink,.btn .rst-content h1 .headerlink,.btn .rst-content h2 .headerlink,.btn .rst-content h3 .headerlink,.btn .rst-content h4 .headerlink,.btn .rst-content h5 .headerlink,.btn .rst-content h6 .headerlink,.btn .rst-content p .headerlink,.btn .rst-content table>caption .headerlink,.btn .rst-content tt.download span:first-child,.btn .wy-menu-vertical li.current>a button.toctree-expand,.btn .wy-menu-vertical li.on a button.toctree-expand,.btn .wy-menu-vertical li button.toctree-expand,.nav .fa,.nav .icon,.nav .rst-content .admonition-title,.nav .rst-content .code-block-caption .headerlink,.nav .rst-content .eqno .headerlink,.nav .rst-content code.download span:first-child,.nav .rst-content dl dt .headerlink,.nav .rst-content h1 .headerlink,.nav .rst-content h2 .headerlink,.nav .rst-content h3 .headerlink,.nav .rst-content h4 .headerlink,.nav .rst-content h5 .headerlink,.nav .rst-content h6 .headerlink,.nav .rst-content p .headerlink,.nav .rst-content table>caption .headerlink,.nav .rst-content tt.download span:first-child,.nav .wy-menu-vertical li.current>a button.toctree-expand,.nav .wy-menu-vertical li.on a button.toctree-expand,.nav .wy-menu-vertical li button.toctree-expand,.rst-content .btn .admonition-title,.rst-content .code-block-caption .btn .headerlink,.rst-content .code-block-caption .nav .headerlink,.rst-content .eqno .btn .headerlink,.rst-content .eqno .nav .headerlink,.rst-content .nav .admonition-title,.rst-content code.download .btn span:first-child,.rst-content code.download .nav span:first-child,.rst-content dl dt .btn .headerlink,.rst-content dl dt .nav .headerlink,.rst-content h1 .btn .headerlink,.rst-content h1 .nav .headerlink,.rst-content h2 .btn .headerlink,.rst-content h2 .nav .headerlink,.rst-content h3 .btn .headerlink,.rst-content h3 .nav .headerlink,.rst-content h4 .btn .headerlink,.rst-content h4 .nav .headerlink,.rst-content h5 .btn .headerlink,.rst-content h5 .nav .headerlink,.rst-content h6 .btn .headerlink,.rst-content h6 .nav .headerlink,.rst-content p .btn .headerlink,.rst-content p .nav .headerlink,.rst-content table>caption .btn .headerlink,.rst-content table>caption .nav .headerlink,.rst-content tt.download .btn span:first-child,.rst-content tt.download .nav span:first-child,.wy-menu-vertical li .btn button.toctree-expand,.wy-menu-vertical li.current>a .btn button.toctree-expand,.wy-menu-vertical li.current>a .nav button.toctree-expand,.wy-menu-vertical li .nav button.toctree-expand,.wy-menu-vertical li.on a .btn button.toctree-expand,.wy-menu-vertical li.on a .nav button.toctree-expand{display:inline}.btn .fa-large.icon,.btn .fa.fa-large,.btn .rst-content .code-block-caption .fa-large.headerlink,.btn .rst-content .eqno .fa-large.headerlink,.btn .rst-content .fa-large.admonition-title,.btn .rst-content code.download span.fa-large:first-child,.btn .rst-content dl dt .fa-large.headerlink,.btn .rst-content h1 .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.btn .rst-content p .fa-large.headerlink,.btn .rst-content table>caption .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.btn .wy-menu-vertical li button.fa-large.toctree-expand,.nav .fa-large.icon,.nav .fa.fa-large,.nav .rst-content .code-block-caption .fa-large.headerlink,.nav .rst-content .eqno .fa-large.headerlink,.nav .rst-content .fa-large.admonition-title,.nav .rst-content code.download span.fa-large:first-child,.nav .rst-content dl dt .fa-large.headerlink,.nav .rst-content h1 .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.nav .rst-content p .fa-large.headerlink,.nav .rst-content table>caption .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.nav .wy-menu-vertical li button.fa-large.toctree-expand,.rst-content .btn .fa-large.admonition-title,.rst-content .code-block-caption .btn .fa-large.headerlink,.rst-content .code-block-caption .nav .fa-large.headerlink,.rst-content .eqno .btn .fa-large.headerlink,.rst-content .eqno .nav .fa-large.headerlink,.rst-content .nav .fa-large.admonition-title,.rst-content code.download .btn span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.rst-content dl dt .btn .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.rst-content p .btn .fa-large.headerlink,.rst-content p .nav .fa-large.headerlink,.rst-content table>caption .btn .fa-large.headerlink,.rst-content table>caption .nav .fa-large.headerlink,.rst-content tt.download .btn span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.wy-menu-vertical li .btn button.fa-large.toctree-expand,.wy-menu-vertical li .nav button.fa-large.toctree-expand{line-height:.9em}.btn .fa-spin.icon,.btn .fa.fa-spin,.btn .rst-content .code-block-caption .fa-spin.headerlink,.btn .rst-content .eqno .fa-spin.headerlink,.btn .rst-content .fa-spin.admonition-title,.btn .rst-content code.download span.fa-spin:first-child,.btn .rst-content dl dt .fa-spin.headerlink,.btn .rst-content h1 .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.btn .rst-content p .fa-spin.headerlink,.btn .rst-content table>caption .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.btn .wy-menu-vertical li button.fa-spin.toctree-expand,.nav .fa-spin.icon,.nav .fa.fa-spin,.nav .rst-content .code-block-caption .fa-spin.headerlink,.nav .rst-content .eqno .fa-spin.headerlink,.nav .rst-content .fa-spin.admonition-title,.nav .rst-content code.download span.fa-spin:first-child,.nav .rst-content dl dt .fa-spin.headerlink,.nav .rst-content h1 .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.nav .rst-content p .fa-spin.headerlink,.nav .rst-content table>caption .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.nav .wy-menu-vertical li button.fa-spin.toctree-expand,.rst-content .btn .fa-spin.admonition-title,.rst-content .code-block-caption .btn .fa-spin.headerlink,.rst-content .code-block-caption .nav .fa-spin.headerlink,.rst-content .eqno .btn .fa-spin.headerlink,.rst-content .eqno .nav .fa-spin.headerlink,.rst-content .nav .fa-spin.admonition-title,.rst-content code.download .btn span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.rst-content dl dt .btn .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.rst-content p .btn .fa-spin.headerlink,.rst-content p .nav .fa-spin.headerlink,.rst-content table>caption .btn .fa-spin.headerlink,.rst-content table>caption .nav .fa-spin.headerlink,.rst-content tt.download .btn span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.wy-menu-vertical li .btn button.fa-spin.toctree-expand,.wy-menu-vertical li .nav button.fa-spin.toctree-expand{display:inline-block}.btn.fa:before,.btn.icon:before,.rst-content .btn.admonition-title:before,.rst-content .code-block-caption .btn.headerlink:before,.rst-content .eqno .btn.headerlink:before,.rst-content code.download span.btn:first-child:before,.rst-content dl dt .btn.headerlink:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content p .btn.headerlink:before,.rst-content table>caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.wy-menu-vertical li button.btn.toctree-expand:before{opacity:.5;-webkit-transition:opacity .05s ease-in;-moz-transition:opacity .05s ease-in;transition:opacity .05s ease-in}.btn.fa:hover:before,.btn.icon:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content .code-block-caption .btn.headerlink:hover:before,.rst-content .eqno .btn.headerlink:hover:before,.rst-content code.download span.btn:first-child:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content p .btn.headerlink:hover:before,.rst-content table>caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.wy-menu-vertical li button.btn.toctree-expand:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .icon:before,.btn-mini .rst-content .admonition-title:before,.btn-mini .rst-content .code-block-caption .headerlink:before,.btn-mini .rst-content .eqno .headerlink:before,.btn-mini .rst-content code.download span:first-child:before,.btn-mini .rst-content dl dt .headerlink:before,.btn-mini .rst-content h1 .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.btn-mini .rst-content p .headerlink:before,.btn-mini .rst-content table>caption .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.btn-mini .wy-menu-vertical li button.toctree-expand:before,.rst-content .btn-mini .admonition-title:before,.rst-content .code-block-caption .btn-mini .headerlink:before,.rst-content .eqno .btn-mini .headerlink:before,.rst-content code.download .btn-mini span:first-child:before,.rst-content dl dt .btn-mini .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.rst-content p .btn-mini .headerlink:before,.rst-content table>caption .btn-mini .headerlink:before,.rst-content tt.download .btn-mini span:first-child:before,.wy-menu-vertical li .btn-mini button.toctree-expand:before{font-size:14px;vertical-align:-15%}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.wy-alert{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.rst-content .admonition-title,.wy-alert-title{font-weight:700;display:block;color:#fff;background:#6ab0de;padding:6px 12px;margin:-12px -12px 12px}.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.admonition,.rst-content .wy-alert-danger.admonition-todo,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.wy-alert.wy-alert-danger{background:#fdf3f2}.rst-content .danger .admonition-title,.rst-content .danger .wy-alert-title,.rst-content .error .admonition-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.rst-content .wy-alert-danger.admonition .admonition-title,.rst-content .wy-alert-danger.admonition .wy-alert-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.wy-alert.wy-alert-danger .wy-alert-title{background:#f29f97}.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .warning,.rst-content .wy-alert-warning.admonition,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.note,.rst-content .wy-alert-warning.seealso,.rst-content .wy-alert-warning.tip,.wy-alert.wy-alert-warning{background:#ffedcc}.rst-content .admonition-todo .admonition-title,.rst-content .admonition-todo .wy-alert-title,.rst-content .attention .admonition-title,.rst-content .attention .wy-alert-title,.rst-content .caution .admonition-title,.rst-content .caution .wy-alert-title,.rst-content .warning .admonition-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.admonition .admonition-title,.rst-content .wy-alert-warning.admonition .wy-alert-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.wy-alert.wy-alert-warning .wy-alert-title{background:#f0b37e}.rst-content .note,.rst-content .seealso,.rst-content .wy-alert-info.admonition,.rst-content .wy-alert-info.admonition-todo,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.wy-alert.wy-alert-info{background:#e7f2fa}.rst-content .note .admonition-title,.rst-content .note .wy-alert-title,.rst-content .seealso .admonition-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .admonition-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.rst-content .wy-alert-info.admonition .admonition-title,.rst-content .wy-alert-info.admonition .wy-alert-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.wy-alert.wy-alert-info .wy-alert-title{background:#6ab0de}.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.admonition,.rst-content .wy-alert-success.admonition-todo,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.warning,.wy-alert.wy-alert-success{background:#dbfaf4}.rst-content .hint .admonition-title,.rst-content .hint .wy-alert-title,.rst-content .important .admonition-title,.rst-content .important .wy-alert-title,.rst-content .tip .admonition-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .admonition-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.rst-content .wy-alert-success.admonition .admonition-title,.rst-content .wy-alert-success.admonition .wy-alert-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.wy-alert.wy-alert-success .wy-alert-title{background:#1abc9c}.rst-content .wy-alert-neutral.admonition,.rst-content .wy-alert-neutral.admonition-todo,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.wy-alert.wy-alert-neutral{background:#f3f6f6}.rst-content .wy-alert-neutral.admonition-todo .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.rst-content .wy-alert-neutral.admonition .admonition-title,.rst-content .wy-alert-neutral.admonition .wy-alert-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.wy-alert.wy-alert-neutral .wy-alert-title{color:#404040;background:#e1e4e5}.rst-content .wy-alert-neutral.admonition-todo a,.rst-content .wy-alert-neutral.admonition a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.wy-alert.wy-alert-neutral a{color:#2980b9}.rst-content .admonition-todo p:last-child,.rst-content .admonition p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .note p:last-child,.rst-content .seealso p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.wy-alert p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all .3s ease-in;-moz-transition:all .3s ease-in;transition:all .3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27ae60}.wy-tray-container li.wy-tray-item-info{background:#2980b9}.wy-tray-container li.wy-tray-item-warning{background:#e67e22}.wy-tray-container li.wy-tray-item-danger{background:#e74c3c}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width:768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px;color:#fff;border:1px solid rgba(0,0,0,.1);background-color:#27ae60;text-decoration:none;font-weight:400;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 2px -1px hsla(0,0%,100%,.5),inset 0 -2px 0 0 rgba(0,0,0,.1);outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all .1s linear;-moz-transition:all .1s linear;transition:all .1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:inset 0 -1px 0 0 rgba(0,0,0,.05),inset 0 2px 0 0 rgba(0,0,0,.1);padding:8px 12px 6px}.btn:visited{color:#fff}.btn-disabled,.btn-disabled:active,.btn-disabled:focus,.btn-disabled:hover,.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980b9!important}.btn-info:hover{background-color:#2e8ece!important}.btn-neutral{background-color:#f3f6f6!important;color:#404040!important}.btn-neutral:hover{background-color:#e5ebeb!important;color:#404040}.btn-neutral:visited{color:#404040!important}.btn-success{background-color:#27ae60!important}.btn-success:hover{background-color:#295!important}.btn-danger{background-color:#e74c3c!important}.btn-danger:hover{background-color:#ea6153!important}.btn-warning{background-color:#e67e22!important}.btn-warning:hover{background-color:#e98b39!important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f!important}.btn-link{background-color:transparent!important;color:#2980b9;box-shadow:none;border-color:transparent!important}.btn-link:active,.btn-link:hover{background-color:transparent!important;color:#409ad5!important;box-shadow:none}.btn-link:visited{color:#9b59b6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:after,.wy-btn-group:before{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:1px solid #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980b9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:1px solid #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type=search]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980b9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned .wy-help-inline,.wy-form-aligned input,.wy-form-aligned label,.wy-form-aligned select,.wy-form-aligned textarea{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{margin:0}fieldset,legend{border:0;padding:0}legend{width:100%;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label,legend{display:block}label{margin:0 0 .3125em;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;max-width:1200px;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:after,.wy-control-group:before{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#e74c3c}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full input[type=color],.wy-control-group .wy-form-full input[type=date],.wy-control-group .wy-form-full input[type=datetime-local],.wy-control-group .wy-form-full input[type=datetime],.wy-control-group .wy-form-full input[type=email],.wy-control-group .wy-form-full input[type=month],.wy-control-group .wy-form-full input[type=number],.wy-control-group .wy-form-full input[type=password],.wy-control-group .wy-form-full input[type=search],.wy-control-group .wy-form-full input[type=tel],.wy-control-group .wy-form-full input[type=text],.wy-control-group .wy-form-full input[type=time],.wy-control-group .wy-form-full input[type=url],.wy-control-group .wy-form-full input[type=week],.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves input[type=color],.wy-control-group .wy-form-halves input[type=date],.wy-control-group .wy-form-halves input[type=datetime-local],.wy-control-group .wy-form-halves input[type=datetime],.wy-control-group .wy-form-halves input[type=email],.wy-control-group .wy-form-halves input[type=month],.wy-control-group .wy-form-halves input[type=number],.wy-control-group .wy-form-halves input[type=password],.wy-control-group .wy-form-halves input[type=search],.wy-control-group .wy-form-halves input[type=tel],.wy-control-group .wy-form-halves input[type=text],.wy-control-group .wy-form-halves input[type=time],.wy-control-group .wy-form-halves input[type=url],.wy-control-group .wy-form-halves input[type=week],.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds input[type=color],.wy-control-group .wy-form-thirds input[type=date],.wy-control-group .wy-form-thirds input[type=datetime-local],.wy-control-group .wy-form-thirds input[type=datetime],.wy-control-group .wy-form-thirds input[type=email],.wy-control-group .wy-form-thirds input[type=month],.wy-control-group .wy-form-thirds input[type=number],.wy-control-group .wy-form-thirds input[type=password],.wy-control-group .wy-form-thirds input[type=search],.wy-control-group .wy-form-thirds input[type=tel],.wy-control-group .wy-form-thirds input[type=text],.wy-control-group .wy-form-thirds input[type=time],.wy-control-group .wy-form-thirds input[type=url],.wy-control-group .wy-form-thirds input[type=week],.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full{float:left;display:block;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.35765%;width:48.82117%}.wy-control-group .wy-form-halves:last-child,.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(odd){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.35765%;width:31.76157%}.wy-control-group .wy-form-thirds:last-child,.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control,.wy-control-no-input{margin:6px 0 0;font-size:90%}.wy-control-no-input{display:inline-block}.wy-control-group.fluid-input input[type=color],.wy-control-group.fluid-input input[type=date],.wy-control-group.fluid-input input[type=datetime-local],.wy-control-group.fluid-input input[type=datetime],.wy-control-group.fluid-input input[type=email],.wy-control-group.fluid-input input[type=month],.wy-control-group.fluid-input input[type=number],.wy-control-group.fluid-input input[type=password],.wy-control-group.fluid-input input[type=search],.wy-control-group.fluid-input input[type=tel],.wy-control-group.fluid-input input[type=text],.wy-control-group.fluid-input input[type=time],.wy-control-group.fluid-input input[type=url],.wy-control-group.fluid-input input[type=week]{width:100%}.wy-form-message-inline{padding-left:.3em;color:#666;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;*overflow:visible}input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}input[type=datetime-local]{padding:.34375em .625em}input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{padding:0;margin-right:.3125em;*height:13px;*width:13px}input[type=checkbox],input[type=radio],input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}input[type=color]:focus,input[type=date]:focus,input[type=datetime-local]:focus,input[type=datetime]:focus,input[type=email]:focus,input[type=month]:focus,input[type=number]:focus,input[type=password]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=time]:focus,input[type=url]:focus,input[type=week]:focus{outline:0;outline:thin dotted\9;border-color:#333}input.no-focus:focus{border-color:#ccc!important}input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus{outline:thin dotted #333;outline:1px auto #129fea}input[type=color][disabled],input[type=date][disabled],input[type=datetime-local][disabled],input[type=datetime][disabled],input[type=email][disabled],input[type=month][disabled],input[type=number][disabled],input[type=password][disabled],input[type=search][disabled],input[type=tel][disabled],input[type=text][disabled],input[type=time][disabled],input[type=url][disabled],input[type=week][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,select:focus:invalid,textarea:focus:invalid{color:#e74c3c;border:1px solid #e74c3c}input:focus:invalid:focus,select:focus:invalid:focus,textarea:focus:invalid:focus{border-color:#e74c3c}input[type=checkbox]:focus:invalid:focus,input[type=file]:focus:invalid:focus,input[type=radio]:focus:invalid:focus{outline-color:#e74c3c}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif}select,textarea{padding:.5em .625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}input[readonly],select[disabled],select[readonly],textarea[disabled],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type=checkbox][disabled],input[type=radio][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:1px solid #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{position:relative;display:block;height:24px;margin-top:12px;cursor:pointer}.wy-switch:before{left:0;top:0;width:36px;height:12px;background:#ccc}.wy-switch:after,.wy-switch:before{position:absolute;content:"";display:block;border-radius:4px;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch:after{width:18px;height:18px;background:#999;left:-3px;top:-3px}.wy-switch span{position:absolute;left:48px;display:block;font-size:12px;color:#ccc;line-height:1}.wy-switch.active:before{background:#1e8449}.wy-switch.active:after{left:24px;background:#27ae60}.wy-switch.disabled{cursor:not-allowed;opacity:.8}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#e74c3c}.wy-control-group.wy-control-group-error input[type=color],.wy-control-group.wy-control-group-error input[type=date],.wy-control-group.wy-control-group-error input[type=datetime-local],.wy-control-group.wy-control-group-error input[type=datetime],.wy-control-group.wy-control-group-error input[type=email],.wy-control-group.wy-control-group-error input[type=month],.wy-control-group.wy-control-group-error input[type=number],.wy-control-group.wy-control-group-error input[type=password],.wy-control-group.wy-control-group-error input[type=search],.wy-control-group.wy-control-group-error input[type=tel],.wy-control-group.wy-control-group-error input[type=text],.wy-control-group.wy-control-group-error input[type=time],.wy-control-group.wy-control-group-error input[type=url],.wy-control-group.wy-control-group-error input[type=week],.wy-control-group.wy-control-group-error textarea{border:1px solid #e74c3c}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:.5em .625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27ae60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#e74c3c}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#e67e22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980b9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width:480px){.wy-form button[type=submit]{margin:.7em 0 0}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=text],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week],.wy-form label{margin-bottom:.3em;display:block}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0}.wy-form-message,.wy-form-message-inline,.wy-form .wy-help-inline{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width:768px){.tablet-hide{display:none}}@media screen and (max-width:480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.rst-content table.docutils,.rst-content table.field-list,.wy-table{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.rst-content table.docutils caption,.rst-content table.field-list caption,.wy-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.rst-content table.docutils td,.rst-content table.docutils th,.rst-content table.field-list td,.rst-content table.field-list th,.wy-table td,.wy-table th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.rst-content table.docutils td:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list td:first-child,.rst-content table.field-list th:first-child,.wy-table td:first-child,.wy-table th:first-child{border-left-width:0}.rst-content table.docutils thead,.rst-content table.field-list thead,.wy-table thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.rst-content table.docutils thead th,.rst-content table.field-list thead th,.wy-table thead th{font-weight:700;border-bottom:2px solid #e1e4e5}.rst-content table.docutils td,.rst-content table.field-list td,.wy-table td{background-color:transparent;vertical-align:middle}.rst-content table.docutils td p,.rst-content table.field-list td p,.wy-table td p{line-height:18px}.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child,.wy-table td p:last-child{margin-bottom:0}.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min,.wy-table .wy-table-cell-min{width:1%;padding-right:0}.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:grey;font-size:90%}.wy-table-tertiary{color:grey;font-size:80%}.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td,.wy-table-backed,.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td{background-color:#f3f6f6}.rst-content table.docutils,.wy-table-bordered-all{border:1px solid #e1e4e5}.rst-content table.docutils td,.wy-table-bordered-all td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.rst-content table.docutils tbody>tr:last-child td,.wy-table-bordered-all tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0!important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980b9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9b59b6}html{height:100%}body,html{overflow-x:hidden}body{font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;font-weight:400;color:#404040;min-height:100%;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#e67e22!important}a.wy-text-warning:hover{color:#eb9950!important}.wy-text-info{color:#2980b9!important}a.wy-text-info:hover{color:#409ad5!important}.wy-text-success{color:#27ae60!important}a.wy-text-success:hover{color:#36d278!important}.wy-text-danger{color:#e74c3c!important}a.wy-text-danger:hover{color:#ed7669!important}.wy-text-neutral{color:#404040!important}a.wy-text-neutral:hover{color:#595959!important}.rst-content .toctree-wrapper>p.caption,h1,h2,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif}p{line-height:24px;font-size:16px;margin:0 0 24px}h1{font-size:175%}.rst-content .toctree-wrapper>p.caption,h2{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}.rst-content code,.rst-content tt,code{white-space:nowrap;max-width:100%;background:#fff;border:1px solid #e1e4e5;font-size:75%;padding:0 5px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#e74c3c;overflow-x:auto}.rst-content tt.code-large,code.code-large{font-size:90%}.rst-content .section ul,.rst-content .toctree-wrapper ul,.rst-content section ul,.wy-plain-list-disc,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.rst-content .section ul li,.rst-content .toctree-wrapper ul li,.rst-content section ul li,.wy-plain-list-disc li,article ul li{list-style:disc;margin-left:24px}.rst-content .section ul li p:last-child,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li p:last-child,.rst-content .toctree-wrapper ul li ul,.rst-content section ul li p:last-child,.rst-content section ul li ul,.wy-plain-list-disc li p:last-child,.wy-plain-list-disc li ul,article ul li p:last-child,article ul li ul{margin-bottom:0}.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,.rst-content section ul li li,.wy-plain-list-disc li li,article ul li li{list-style:circle}.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,.rst-content section ul li li li,.wy-plain-list-disc li li li,article ul li li li{list-style:square}.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,.rst-content section ul li ol li,.wy-plain-list-disc li ol li,article ul li ol li{list-style:decimal}.rst-content .section ol,.rst-content .section ol.arabic,.rst-content .toctree-wrapper ol,.rst-content .toctree-wrapper ol.arabic,.rst-content section ol,.rst-content section ol.arabic,.wy-plain-list-decimal,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.rst-content .section ol.arabic li,.rst-content .section ol li,.rst-content .toctree-wrapper ol.arabic li,.rst-content .toctree-wrapper ol li,.rst-content section ol.arabic li,.rst-content section ol li,.wy-plain-list-decimal li,article ol li{list-style:decimal;margin-left:24px}.rst-content .section ol.arabic li ul,.rst-content .section ol li p:last-child,.rst-content .section ol li ul,.rst-content .toctree-wrapper ol.arabic li ul,.rst-content .toctree-wrapper ol li p:last-child,.rst-content .toctree-wrapper ol li ul,.rst-content section ol.arabic li ul,.rst-content section ol li p:last-child,.rst-content section ol li ul,.wy-plain-list-decimal li p:last-child,.wy-plain-list-decimal li ul,article ol li p:last-child,article ol li ul{margin-bottom:0}.rst-content .section ol.arabic li ul li,.rst-content .section ol li ul li,.rst-content .toctree-wrapper ol.arabic li ul li,.rst-content .toctree-wrapper ol li ul li,.rst-content section ol.arabic li ul li,.rst-content section ol li ul li,.wy-plain-list-decimal li ul li,article ol li ul li{list-style:disc}.wy-breadcrumbs{*zoom:1}.wy-breadcrumbs:after,.wy-breadcrumbs:before{display:table;content:""}.wy-breadcrumbs:after{clear:both}.wy-breadcrumbs>li{display:inline-block;padding-top:5px}.wy-breadcrumbs>li.wy-breadcrumbs-aside{float:right}.rst-content .wy-breadcrumbs>li code,.rst-content .wy-breadcrumbs>li tt,.wy-breadcrumbs>li .rst-content tt,.wy-breadcrumbs>li code{all:inherit;color:inherit}.breadcrumb-item:before{content:"/";color:#bbb;font-size:13px;padding:0 6px 0 3px}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width:480px){.wy-breadcrumbs-extra,.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}html{font-size:16px}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:after,.wy-menu-horiz:before{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz li,.wy-menu-horiz ul{display:inline-block}.wy-menu-horiz li:hover{background:hsla(0,0%,100%,.1)}.wy-menu-horiz li.divide-left{border-left:1px solid #404040}.wy-menu-horiz li.divide-right{border-right:1px solid #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical{width:300px}.wy-menu-vertical header,.wy-menu-vertical p.caption{color:#55a5d9;height:32px;line-height:32px;padding:0 1.618em;margin:12px 0 0;display:block;font-weight:700;text-transform:uppercase;font-size:85%;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:1px solid #404040}.wy-menu-vertical li.divide-bottom{border-bottom:1px solid #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:grey;border-right:1px solid #c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.rst-content .wy-menu-vertical li tt,.wy-menu-vertical li .rst-content tt,.wy-menu-vertical li code{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li button.toctree-expand{display:block;float:left;margin-left:-1.2em;line-height:18px;color:#4d4d4d;border:none;background:none;padding:0}.wy-menu-vertical li.current>a,.wy-menu-vertical li.on a{color:#404040;font-weight:700;position:relative;background:#fcfcfc;border:none;padding:.4045em 1.618em}.wy-menu-vertical li.current>a:hover,.wy-menu-vertical li.on a:hover{background:#fcfcfc}.wy-menu-vertical li.current>a:hover button.toctree-expand,.wy-menu-vertical li.on a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand{display:block;line-height:18px;color:#333}.wy-menu-vertical li.toctree-l1.current>a{border-bottom:1px solid #c9c9c9;border-top:1px solid #c9c9c9}.wy-menu-vertical .toctree-l1.current .toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .toctree-l11>ul{display:none}.wy-menu-vertical .toctree-l1.current .current.toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .current.toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .current.toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .current.toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .current.toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .current.toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .current.toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .current.toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .current.toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .current.toctree-l11>ul{display:block}.wy-menu-vertical li.toctree-l3,.wy-menu-vertical li.toctree-l4{font-size:.9em}.wy-menu-vertical li.toctree-l2 a,.wy-menu-vertical li.toctree-l3 a,.wy-menu-vertical li.toctree-l4 a,.wy-menu-vertical li.toctree-l5 a,.wy-menu-vertical li.toctree-l6 a,.wy-menu-vertical li.toctree-l7 a,.wy-menu-vertical li.toctree-l8 a,.wy-menu-vertical li.toctree-l9 a,.wy-menu-vertical li.toctree-l10 a{color:#404040}.wy-menu-vertical li.toctree-l2 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l3 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l4 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l5 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l6 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l7 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l8 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l9 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l10 a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a,.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a,.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a,.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a,.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a,.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a,.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a,.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{display:block}.wy-menu-vertical li.toctree-l2.current>a{padding:.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{padding:.4045em 1.618em .4045em 4.045em}.wy-menu-vertical li.toctree-l3.current>a{padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{padding:.4045em 1.618em .4045em 5.663em}.wy-menu-vertical li.toctree-l4.current>a{padding:.4045em 5.663em}.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a{padding:.4045em 1.618em .4045em 7.281em}.wy-menu-vertical li.toctree-l5.current>a{padding:.4045em 7.281em}.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a{padding:.4045em 1.618em .4045em 8.899em}.wy-menu-vertical li.toctree-l6.current>a{padding:.4045em 8.899em}.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a{padding:.4045em 1.618em .4045em 10.517em}.wy-menu-vertical li.toctree-l7.current>a{padding:.4045em 10.517em}.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a{padding:.4045em 1.618em .4045em 12.135em}.wy-menu-vertical li.toctree-l8.current>a{padding:.4045em 12.135em}.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a{padding:.4045em 1.618em .4045em 13.753em}.wy-menu-vertical li.toctree-l9.current>a{padding:.4045em 13.753em}.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a{padding:.4045em 1.618em .4045em 15.371em}.wy-menu-vertical li.toctree-l10.current>a{padding:.4045em 15.371em}.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{padding:.4045em 1.618em .4045em 16.989em}.wy-menu-vertical li.toctree-l2.current>a,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{background:#c9c9c9}.wy-menu-vertical li.toctree-l2 button.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3.current>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{background:#bdbdbd}.wy-menu-vertical li.toctree-l3 button.toctree-expand{color:#969696}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical li ul li a{margin-bottom:0;color:#d9d9d9;font-weight:400}.wy-menu-vertical a{line-height:18px;padding:.4045em 1.618em;display:block;position:relative;font-size:90%;color:#d9d9d9}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover button.toctree-expand{color:#d9d9d9}.wy-menu-vertical a:active{background-color:#2980b9;cursor:pointer;color:#fff}.wy-menu-vertical a:active button.toctree-expand{color:#fff}.wy-side-nav-search{display:block;width:300px;padding:.809em;margin-bottom:.809em;z-index:200;background-color:#2980b9;text-align:center;color:#fcfcfc}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto .809em;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-side-nav-search .wy-dropdown>a,.wy-side-nav-search>a{color:#fcfcfc;font-size:100%;font-weight:700;display:inline-block;padding:4px 6px;margin-bottom:.809em;max-width:100%}.wy-side-nav-search .wy-dropdown>a:hover,.wy-side-nav-search>a:hover{background:hsla(0,0%,100%,.1)}.wy-side-nav-search .wy-dropdown>a img.logo,.wy-side-nav-search>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search .wy-dropdown>a.icon img.logo,.wy-side-nav-search>a.icon img.logo{margin-top:.85em}.wy-side-nav-search>div.version{margin-top:-.4045em;margin-bottom:.809em;font-weight:400;color:hsla(0,0%,100%,.3)}.wy-nav .wy-menu-vertical header{color:#2980b9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980b9;color:#fff}[data-menu-wrap]{-webkit-transition:all .2s ease-in;-moz-transition:all .2s ease-in;transition:all .2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:#fcfcfc}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:hidden;min-height:100%;color:#9b9b9b;background:#343131;z-index:200}.wy-side-scroll{width:320px;position:relative;overflow-x:hidden;overflow-y:scroll;height:100%}.wy-nav-top{display:none;background:#2980b9;color:#fff;padding:.4045em .809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:after,.wy-nav-top:before{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:700}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer;padding-top:inherit}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:grey}footer p{margin-bottom:12px}.rst-content footer span.commit tt,footer span.commit .rst-content tt,footer span.commit code{padding:0;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:1em;background:none;border:none;color:grey}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:after,.rst-footer-buttons:before{width:100%;display:table;content:""}.rst-footer-buttons:after{clear:both}.rst-breadcrumbs-buttons{margin-top:12px;*zoom:1}.rst-breadcrumbs-buttons:after,.rst-breadcrumbs-buttons:before{display:table;content:""}.rst-breadcrumbs-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:1px solid #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:1px solid #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:grey;font-size:90%}.genindextable li>ul{margin-left:24px}@media screen and (max-width:768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-menu.wy-menu-vertical,.wy-side-nav-search,.wy-side-scroll{width:auto}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width:1100px){.wy-nav-content-wrap{background:rgba(0,0,0,.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,.wy-nav-side,footer{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60;*zoom:1}.rst-versions .rst-current-version:after,.rst-versions .rst-current-version:before{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-content .code-block-caption .rst-versions .rst-current-version .headerlink,.rst-content .eqno .rst-versions .rst-current-version .headerlink,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-content p .rst-versions .rst-current-version .headerlink,.rst-content table>caption .rst-versions .rst-current-version .headerlink,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .icon,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-versions .rst-current-version .rst-content .code-block-caption .headerlink,.rst-versions .rst-current-version .rst-content .eqno .headerlink,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-versions .rst-current-version .rst-content p .headerlink,.rst-versions .rst-current-version .rst-content table>caption .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-versions .rst-current-version .wy-menu-vertical li button.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version button.toctree-expand{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}.rst-content .toctree-wrapper>p.caption,.rst-content h1,.rst-content h2,.rst-content h3,.rst-content h4,.rst-content h5,.rst-content h6{margin-bottom:24px}.rst-content img{max-width:100%;height:auto}.rst-content div.figure,.rst-content figure{margin-bottom:24px}.rst-content div.figure .caption-text,.rst-content figure .caption-text{font-style:italic}.rst-content div.figure p:last-child.caption,.rst-content figure p:last-child.caption{margin-bottom:0}.rst-content div.figure.align-center,.rst-content figure.align-center{text-align:center}.rst-content .section>a>img,.rst-content .section>img,.rst-content section>a>img,.rst-content section>img{margin-bottom:24px}.rst-content abbr[title]{text-decoration:none}.rst-content.style-external-links a.reference.external:after{font-family:FontAwesome;content:"\f08e";color:#b3b3b3;vertical-align:super;font-size:60%;margin:0 .2em}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content pre.literal-block{white-space:pre;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;display:block;overflow:auto}.rst-content div[class^=highlight],.rst-content pre.literal-block{border:1px solid #e1e4e5;overflow-x:auto;margin:1px 0 24px}.rst-content div[class^=highlight] div[class^=highlight],.rst-content pre.literal-block div[class^=highlight]{padding:0;border:none;margin:0}.rst-content div[class^=highlight] td.code{width:100%}.rst-content .linenodiv pre{border-right:1px solid #e6e9ea;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;user-select:none;pointer-events:none}.rst-content div[class^=highlight] pre{white-space:pre;margin:0;padding:12px;display:block;overflow:auto}.rst-content div[class^=highlight] pre .hll{display:block;margin:0 -12px;padding:0 12px}.rst-content .linenodiv pre,.rst-content div[class^=highlight] pre,.rst-content pre.literal-block{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:12px;line-height:1.4}.rst-content div.highlight .gp,.rst-content div.highlight span.linenos{user-select:none;pointer-events:none}.rst-content div.highlight span.linenos{display:inline-block;padding-left:0;padding-right:12px;margin-right:12px;border-right:1px solid #e6e9ea}.rst-content .code-block-caption{font-style:italic;font-size:85%;line-height:1;padding:1em 0;text-align:center}@media print{.rst-content .codeblock,.rst-content div[class^=highlight],.rst-content div[class^=highlight] pre{white-space:pre-wrap}}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning{clear:both}.rst-content .admonition-todo .last,.rst-content .admonition-todo>:last-child,.rst-content .admonition .last,.rst-content .admonition>:last-child,.rst-content .attention .last,.rst-content .attention>:last-child,.rst-content .caution .last,.rst-content .caution>:last-child,.rst-content .danger .last,.rst-content .danger>:last-child,.rst-content .error .last,.rst-content .error>:last-child,.rst-content .hint .last,.rst-content .hint>:last-child,.rst-content .important .last,.rst-content .important>:last-child,.rst-content .note .last,.rst-content .note>:last-child,.rst-content .seealso .last,.rst-content .seealso>:last-child,.rst-content .tip .last,.rst-content .tip>:last-child,.rst-content .warning .last,.rst-content .warning>:last-child{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent!important;border-color:rgba(0,0,0,.1)!important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha>li,.rst-content .toctree-wrapper ol.loweralpha,.rst-content .toctree-wrapper ol.loweralpha>li,.rst-content section ol.loweralpha,.rst-content section ol.loweralpha>li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha>li,.rst-content .toctree-wrapper ol.upperalpha,.rst-content .toctree-wrapper ol.upperalpha>li,.rst-content section ol.upperalpha,.rst-content section ol.upperalpha>li{list-style:upper-alpha}.rst-content .section ol li>*,.rst-content .section ul li>*,.rst-content .toctree-wrapper ol li>*,.rst-content .toctree-wrapper ul li>*,.rst-content section ol li>*,.rst-content section ul li>*{margin-top:12px;margin-bottom:12px}.rst-content .section ol li>:first-child,.rst-content .section ul li>:first-child,.rst-content .toctree-wrapper ol li>:first-child,.rst-content .toctree-wrapper ul li>:first-child,.rst-content section ol li>:first-child,.rst-content section ul li>:first-child{margin-top:0}.rst-content .section ol li>p,.rst-content .section ol li>p:last-child,.rst-content .section ul li>p,.rst-content .section ul li>p:last-child,.rst-content .toctree-wrapper ol li>p,.rst-content .toctree-wrapper ol li>p:last-child,.rst-content .toctree-wrapper ul li>p,.rst-content .toctree-wrapper ul li>p:last-child,.rst-content section ol li>p,.rst-content section ol li>p:last-child,.rst-content section ul li>p,.rst-content section ul li>p:last-child{margin-bottom:12px}.rst-content .section ol li>p:only-child,.rst-content .section ol li>p:only-child:last-child,.rst-content .section ul li>p:only-child,.rst-content .section ul li>p:only-child:last-child,.rst-content .toctree-wrapper ol li>p:only-child,.rst-content .toctree-wrapper ol li>p:only-child:last-child,.rst-content .toctree-wrapper ul li>p:only-child,.rst-content .toctree-wrapper ul li>p:only-child:last-child,.rst-content section ol li>p:only-child,.rst-content section ol li>p:only-child:last-child,.rst-content section ul li>p:only-child,.rst-content section ul li>p:only-child:last-child{margin-bottom:0}.rst-content .section ol li>ol,.rst-content .section ol li>ul,.rst-content .section ul li>ol,.rst-content .section ul li>ul,.rst-content .toctree-wrapper ol li>ol,.rst-content .toctree-wrapper ol li>ul,.rst-content .toctree-wrapper ul li>ol,.rst-content .toctree-wrapper ul li>ul,.rst-content section ol li>ol,.rst-content section ol li>ul,.rst-content section ul li>ol,.rst-content section ul li>ul{margin-bottom:12px}.rst-content .section ol.simple li>*,.rst-content .section ol.simple li ol,.rst-content .section ol.simple li ul,.rst-content .section ul.simple li>*,.rst-content .section ul.simple li ol,.rst-content .section ul.simple li ul,.rst-content .toctree-wrapper ol.simple li>*,.rst-content .toctree-wrapper ol.simple li ol,.rst-content .toctree-wrapper ol.simple li ul,.rst-content .toctree-wrapper ul.simple li>*,.rst-content .toctree-wrapper ul.simple li ol,.rst-content .toctree-wrapper ul.simple li ul,.rst-content section ol.simple li>*,.rst-content section ol.simple li ol,.rst-content section ol.simple li ul,.rst-content section ul.simple li>*,.rst-content section ul.simple li ol,.rst-content section ul.simple li ul{margin-top:0;margin-bottom:0}.rst-content .line-block{margin-left:0;margin-bottom:24px;line-height:24px}.rst-content .line-block .line-block{margin-left:24px;margin-bottom:0}.rst-content .topic-title{font-weight:700;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0 0 24px 24px}.rst-content .align-left{float:left;margin:0 24px 24px 0}.rst-content .align-center{margin:auto}.rst-content .align-center:not(table){display:block}.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink{opacity:0;font-size:14px;font-family:FontAwesome;margin-left:.5em}.rst-content .code-block-caption .headerlink:focus,.rst-content .code-block-caption:hover .headerlink,.rst-content .eqno .headerlink:focus,.rst-content .eqno:hover .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink:focus,.rst-content .toctree-wrapper>p.caption:hover .headerlink,.rst-content dl dt .headerlink:focus,.rst-content dl dt:hover .headerlink,.rst-content h1 .headerlink:focus,.rst-content h1:hover .headerlink,.rst-content h2 .headerlink:focus,.rst-content h2:hover .headerlink,.rst-content h3 .headerlink:focus,.rst-content h3:hover .headerlink,.rst-content h4 .headerlink:focus,.rst-content h4:hover .headerlink,.rst-content h5 .headerlink:focus,.rst-content h5:hover .headerlink,.rst-content h6 .headerlink:focus,.rst-content h6:hover .headerlink,.rst-content p.caption .headerlink:focus,.rst-content p.caption:hover .headerlink,.rst-content p .headerlink:focus,.rst-content p:hover .headerlink,.rst-content table>caption .headerlink:focus,.rst-content table>caption:hover .headerlink{opacity:1}.rst-content p a{overflow-wrap:anywhere}.rst-content .wy-table td p,.rst-content .wy-table td ul,.rst-content .wy-table th p,.rst-content .wy-table th ul,.rst-content table.docutils td p,.rst-content table.docutils td ul,.rst-content table.docutils th p,.rst-content table.docutils th ul,.rst-content table.field-list td p,.rst-content table.field-list td ul,.rst-content table.field-list th p,.rst-content table.field-list th ul{font-size:inherit}.rst-content .btn:focus{outline:2px solid}.rst-content table>caption .headerlink:after{font-size:12px}.rst-content .centered{text-align:center}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:1px solid #e1e4e5}.rst-content .sidebar dl,.rst-content .sidebar p,.rst-content .sidebar ul{font-size:90%}.rst-content .sidebar .last,.rst-content .sidebar>:last-child{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif;font-weight:700;background:#e1e4e5;padding:6px 12px;margin:-24px -24px 24px;font-size:100%}.rst-content .highlighted{background:#f1c40f;box-shadow:0 0 0 2px #f1c40f;display:inline;font-weight:700}.rst-content .citation-reference,.rst-content .footnote-reference{vertical-align:baseline;position:relative;top:-.4em;line-height:0;font-size:90%}.rst-content .citation-reference>span.fn-bracket,.rst-content .footnote-reference>span.fn-bracket{display:none}.rst-content .hlist{width:100%}.rst-content dl dt span.classifier:before{content:" : "}.rst-content dl dt span.classifier-delimiter{display:none!important}html.writer-html4 .rst-content table.docutils.citation,html.writer-html4 .rst-content table.docutils.footnote{background:none;border:none}html.writer-html4 .rst-content table.docutils.citation td,html.writer-html4 .rst-content table.docutils.citation tr,html.writer-html4 .rst-content table.docutils.footnote td,html.writer-html4 .rst-content table.docutils.footnote tr{border:none;background-color:transparent!important;white-space:normal}html.writer-html4 .rst-content table.docutils.citation td.label,html.writer-html4 .rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{display:grid;grid-template-columns:auto minmax(80%,95%)}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{display:inline-grid;grid-template-columns:max-content auto}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{display:grid;grid-template-columns:auto auto minmax(.65rem,auto) minmax(40%,95%)}html.writer-html5 .rst-content aside.citation>span.label,html.writer-html5 .rst-content aside.footnote>span.label,html.writer-html5 .rst-content div.citation>span.label{grid-column-start:1;grid-column-end:2}html.writer-html5 .rst-content aside.citation>span.backrefs,html.writer-html5 .rst-content aside.footnote>span.backrefs,html.writer-html5 .rst-content div.citation>span.backrefs{grid-column-start:2;grid-column-end:3;grid-row-start:1;grid-row-end:3}html.writer-html5 .rst-content aside.citation>p,html.writer-html5 .rst-content aside.footnote>p,html.writer-html5 .rst-content div.citation>p{grid-column-start:4;grid-column-end:5}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{margin-bottom:24px}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{padding-left:1rem}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dd,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dd,html.writer-html5 .rst-content dl.footnote>dt{margin-bottom:0}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{font-size:.9rem}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.footnote>dt{margin:0 .5rem .5rem 0;line-height:1.2rem;word-break:break-all;font-weight:400}html.writer-html5 .rst-content dl.citation>dt>span.brackets:before,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:before{content:"["}html.writer-html5 .rst-content dl.citation>dt>span.brackets:after,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:after{content:"]"}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a{word-break:keep-all}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a:not(:first-child):before,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.footnote>dd{margin:0 0 .5rem;line-height:1.2rem}html.writer-html5 .rst-content dl.citation>dd p,html.writer-html5 .rst-content dl.footnote>dd p{font-size:.9rem}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{padding-left:1rem;padding-right:1rem;font-size:.9rem;line-height:1.2rem}html.writer-html5 .rst-content aside.citation p,html.writer-html5 .rst-content aside.footnote p,html.writer-html5 .rst-content div.citation p{font-size:.9rem;line-height:1.2rem;margin-bottom:12px}html.writer-html5 .rst-content aside.citation span.backrefs,html.writer-html5 .rst-content aside.footnote span.backrefs,html.writer-html5 .rst-content div.citation span.backrefs{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content aside.citation span.backrefs>a,html.writer-html5 .rst-content aside.footnote span.backrefs>a,html.writer-html5 .rst-content div.citation span.backrefs>a{word-break:keep-all}html.writer-html5 .rst-content aside.citation span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content aside.footnote span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content div.citation span.backrefs>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content aside.citation span.label,html.writer-html5 .rst-content aside.footnote span.label,html.writer-html5 .rst-content div.citation span.label{line-height:1.2rem}html.writer-html5 .rst-content aside.citation-list,html.writer-html5 .rst-content aside.footnote-list,html.writer-html5 .rst-content div.citation-list{margin-bottom:24px}html.writer-html5 .rst-content dl.option-list kbd{font-size:.9rem}.rst-content table.docutils.footnote,html.writer-html4 .rst-content table.docutils.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content aside.footnote-list aside.footnote,html.writer-html5 .rst-content div.citation-list>div.citation,html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{color:grey}.rst-content table.docutils.footnote code,.rst-content table.docutils.footnote tt,html.writer-html4 .rst-content table.docutils.citation code,html.writer-html4 .rst-content table.docutils.citation tt,html.writer-html5 .rst-content aside.footnote-list aside.footnote code,html.writer-html5 .rst-content aside.footnote-list aside.footnote tt,html.writer-html5 .rst-content aside.footnote code,html.writer-html5 .rst-content aside.footnote tt,html.writer-html5 .rst-content div.citation-list>div.citation code,html.writer-html5 .rst-content div.citation-list>div.citation tt,html.writer-html5 .rst-content dl.citation code,html.writer-html5 .rst-content dl.citation tt,html.writer-html5 .rst-content dl.footnote code,html.writer-html5 .rst-content dl.footnote tt{color:#555}.rst-content .wy-table-responsive.citation,.rst-content .wy-table-responsive.footnote{margin-bottom:0}.rst-content .wy-table-responsive.citation+:not(.citation),.rst-content .wy-table-responsive.footnote+:not(.footnote){margin-top:24px}.rst-content .wy-table-responsive.citation:last-child,.rst-content .wy-table-responsive.footnote:last-child{margin-bottom:24px}.rst-content table.docutils th{border-color:#e1e4e5}html.writer-html5 .rst-content table.docutils th{border:1px solid #e1e4e5}html.writer-html5 .rst-content table.docutils td>p,html.writer-html5 .rst-content table.docutils th>p{line-height:1rem;margin-bottom:0;font-size:.9rem}.rst-content table.docutils td .last,.rst-content table.docutils td .last>:last-child{margin-bottom:0}.rst-content table.field-list,.rst-content table.field-list td{border:none}.rst-content table.field-list td p{line-height:inherit}.rst-content table.field-list td>strong{display:inline-block}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left}.rst-content code,.rst-content tt{color:#000;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;padding:2px 5px}.rst-content code big,.rst-content code em,.rst-content tt big,.rst-content tt em{font-size:100%!important;line-height:normal}.rst-content code.literal,.rst-content tt.literal{color:#e74c3c;white-space:normal}.rst-content code.xref,.rst-content tt.xref,a .rst-content code,a .rst-content tt{font-weight:700;color:#404040;overflow-wrap:normal}.rst-content kbd,.rst-content pre,.rst-content samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace}.rst-content a code,.rst-content a tt{color:#2980b9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:700;margin-bottom:12px}.rst-content dl ol,.rst-content dl p,.rst-content dl table,.rst-content dl ul{margin-bottom:12px}.rst-content dl dd{margin:0 0 12px 24px;line-height:24px}.rst-content dl dd>ol:last-child,.rst-content dl dd>p:last-child,.rst-content dl dd>table:last-child,.rst-content dl dd>ul:last-child{margin-bottom:0}html.writer-html4 .rst-content dl:not(.docutils),html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple){margin-bottom:24px}html.writer-html4 .rst-content dl:not(.docutils)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{display:table;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980b9;border-top:3px solid #6ab0de;padding:6px;position:relative}html.writer-html4 .rst-content dl:not(.docutils)>dt:before,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:before{color:#6ab0de}html.writer-html4 .rst-content dl:not(.docutils)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{margin-bottom:6px;border:none;border-left:3px solid #ccc;background:#f0f0f0;color:#555}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils)>dt:first-child,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:first-child{margin-top:0}html.writer-html4 .rst-content dl:not(.docutils) code.descclassname,html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descclassname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{background-color:transparent;border:none;padding:0;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .optional,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .property,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .property{display:inline-block;padding-right:8px;max-width:100%}html.writer-html4 .rst-content dl:not(.docutils) .k,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .k{font-style:italic}html.writer-html4 .rst-content dl:not(.docutils) .descclassname,html.writer-html4 .rst-content dl:not(.docutils) .descname,html.writer-html4 .rst-content dl:not(.docutils) .sig-name,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .sig-name{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#000}.rst-content .viewcode-back,.rst-content .viewcode-link{display:inline-block;color:#27ae60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:700}.rst-content code.download,.rst-content tt.download{background:inherit;padding:inherit;font-weight:400;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content code.download span:first-child,.rst-content tt.download span:first-child{-webkit-font-smoothing:subpixel-antialiased}.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{margin-right:4px}.rst-content .guilabel{border:1px solid #7fbbe3;background:#e7f2fa;font-size:80%;font-weight:700;border-radius:4px;padding:2.4px 6px;margin:auto 2px}.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>.kbd,.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>kbd{color:inherit;font-size:80%;background-color:#fff;border:1px solid #a6a6a6;border-radius:4px;box-shadow:0 2px grey;padding:2.4px 6px;margin:auto 0}.rst-content .versionmodified{font-style:italic}@media screen and (max-width:480px){.rst-content .sidebar{width:100%}}span[id*=MathJax-Span]{color:#404040}.math{text-align:center}@font-face{font-family:Lato;src:url(fonts/lato-normal.woff2?bd03a2cc277bbbc338d464e679fe9942) format("woff2"),url(fonts/lato-normal.woff?27bd77b9162d388cb8d4c4217c7c5e2a) format("woff");font-weight:400;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold.woff2?cccb897485813c7c256901dbca54ecf2) format("woff2"),url(fonts/lato-bold.woff?d878b6c29b10beca227e9eef4246111b) format("woff");font-weight:700;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold-italic.woff2?0b6bb6725576b072c5d0b02ecdd1900d) format("woff2"),url(fonts/lato-bold-italic.woff?9c7e4e9eb485b4a121c760e61bc3707c) format("woff");font-weight:700;font-style:italic;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-normal-italic.woff2?4eb103b4d12be57cb1d040ed5e162e9d) format("woff2"),url(fonts/lato-normal-italic.woff?f28f2d6482446544ef1ea1ccc6dd5892) format("woff");font-weight:400;font-style:italic;font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:400;src:url(fonts/Roboto-Slab-Regular.woff2?7abf5b8d04d26a2cafea937019bca958) format("woff2"),url(fonts/Roboto-Slab-Regular.woff?c1be9284088d487c5e3ff0a10a92e58c) format("woff");font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:700;src:url(fonts/Roboto-Slab-Bold.woff2?9984f4a9bda09be08e83f2506954adbe) format("woff2"),url(fonts/Roboto-Slab-Bold.woff?bed5564a116b05148e3b3bea6fb1162a) format("woff");font-display:block} diff --git a/extensions/GooglePlayServices/docs/css/theme_extra.css b/extensions/GooglePlayServices/docs/css/theme_extra.css new file mode 100644 index 000000000..9f4b063c2 --- /dev/null +++ b/extensions/GooglePlayServices/docs/css/theme_extra.css @@ -0,0 +1,191 @@ +/* + * Wrap inline code samples otherwise they shoot of the side and + * can't be read at all. + * + * https://github.com/mkdocs/mkdocs/issues/313 + * https://github.com/mkdocs/mkdocs/issues/233 + * https://github.com/mkdocs/mkdocs/issues/834 + */ +.rst-content code { + white-space: pre-wrap; + word-wrap: break-word; + padding: 2px 5px; +} + +/** + * Make code blocks display as blocks and give them the appropriate + * font size and padding. + * + * https://github.com/mkdocs/mkdocs/issues/855 + * https://github.com/mkdocs/mkdocs/issues/834 + * https://github.com/mkdocs/mkdocs/issues/233 + */ +.rst-content pre code { + white-space: pre; + word-wrap: normal; + display: block; + padding: 12px; + font-size: 12px; +} + +/** + * Fix code colors + * + * https://github.com/mkdocs/mkdocs/issues/2027 + */ +.rst-content code { + color: #E74C3C; +} + +.rst-content pre code { + color: #000; + background: #f8f8f8; +} + +/* + * Fix link colors when the link text is inline code. + * + * https://github.com/mkdocs/mkdocs/issues/718 + */ +a code { + color: #2980B9; +} +a:hover code { + color: #3091d1; +} +a:visited code { + color: #9B59B6; +} + +/* + * The CSS classes from highlight.js seem to clash with the + * ReadTheDocs theme causing some code to be incorrectly made + * bold and italic. + * + * https://github.com/mkdocs/mkdocs/issues/411 + */ +pre .cs, pre .c { + font-weight: inherit; + font-style: inherit; +} + +/* + * Fix some issues with the theme and non-highlighted code + * samples. Without and highlighting styles attached the + * formatting is broken. + * + * https://github.com/mkdocs/mkdocs/issues/319 + */ +.rst-content .no-highlight { + display: block; + padding: 0.5em; + color: #333; +} + + +/* + * Additions specific to the search functionality provided by MkDocs + */ + +.search-results { + margin-top: 23px; +} + +.search-results article { + border-top: 1px solid #E1E4E5; + padding-top: 24px; +} + +.search-results article:first-child { + border-top: none; +} + +form .search-query { + width: 100%; + border-radius: 50px; + padding: 6px 12px; /* csslint allow: box-model */ + border-color: #D1D4D5; +} + +/* + * Improve inline code blocks within admonitions. + * + * https://github.com/mkdocs/mkdocs/issues/656 + */ + .rst-content .admonition code { + color: #404040; + border: 1px solid #c7c9cb; + border: 1px solid rgba(0, 0, 0, 0.2); + background: #f8fbfd; + background: rgba(255, 255, 255, 0.7); +} + +/* + * Account for wide tables which go off the side. + * Override borders to avoid weirdness on narrow tables. + * + * https://github.com/mkdocs/mkdocs/issues/834 + * https://github.com/mkdocs/mkdocs/pull/1034 + */ +.rst-content .section .docutils { + width: 100%; + overflow: auto; + display: block; + border: none; +} + +td, th { + border: 1px solid #e1e4e5 !important; /* csslint allow: important */ + border-collapse: collapse; +} + +/* + * Without the following amendments, the navigation in the theme will be + * slightly cut off. This is due to the fact that the .wy-nav-side has a + * padding-bottom of 2em, which must not necessarily align with the font-size of + * 90 % on the .rst-current-version container, combined with the padding of 12px + * above and below. These amendments fix this in two steps: First, make sure the + * .rst-current-version container has a fixed height of 40px, achieved using + * line-height, and then applying a padding-bottom of 40px to this container. In + * a second step, the items within that container are re-aligned using flexbox. + * + * https://github.com/mkdocs/mkdocs/issues/2012 + */ + .wy-nav-side { + padding-bottom: 40px; +} + +/* + * The second step of above amendment: Here we make sure the items are aligned + * correctly within the .rst-current-version container. Using flexbox, we + * achieve it in such a way that it will look like the following: + * + * [No repo_name] + * Next >> // On the first page + * << Previous Next >> // On all subsequent pages + * + * [With repo_name] + * Next >> // On the first page + * << Previous Next >> // On all subsequent pages + * + * https://github.com/mkdocs/mkdocs/issues/2012 + */ +.rst-versions .rst-current-version { + padding: 0 12px; + display: flex; + font-size: initial; + justify-content: space-between; + align-items: center; + line-height: 40px; +} + +/* + * Please note that this amendment also involves removing certain inline-styles + * from the file ./mkdocs/themes/readthedocs/versions.html. + * + * https://github.com/mkdocs/mkdocs/issues/2012 + */ +.rst-current-version span { + flex: 1; + text-align: center; +} diff --git a/extensions/GooglePlayServices/docs/extension_setup.html b/extensions/GooglePlayServices/docs/extension_setup.html new file mode 100644 index 000000000..71556be69 --- /dev/null +++ b/extensions/GooglePlayServices/docs/extension_setup.html @@ -0,0 +1,177 @@ + + + + + + + + Extension Setup - GMEXT-GooglePlayServices + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+ +
+
+
+
+ +

Setup

+

The Google Play Services extension is to be used alongside your Google Developer account (web page). All the required personal leaderboard ids and achievement ids should be managed from there.

+
+

⚠️ IMPORTANT

+

Before using this extension make sure to correctly set up your Android application following the steps on this article. It's also important to note that the demo provided with extension is a reference demo meaning it cannot be played as is, as it would need our .keystore and our Google Services ID which cannot be included with the package. +

+
+
    +
  1. The extension setup will require the user to double click the extension asset in the asset browser and fill in the information regarding the GooglePlayServices account.
  2. +
+

+
    +
  1. +

    As the Google Developer Console layout might change in the future you can check their official guide on setting up leaderboards: Adding Leaderboards.

    +
  2. +
  3. +

    As the Google Developer Console layout might change in the future you can check their official guide on setting up achievements: Adding Achievements.

    +
  4. +
+



+
+ +
+
+ +
+
+ +
+ +
+ +
+ + + + GitHub + + + + « Previous + + + Next » + + +
+ + + + + + + + + + diff --git a/extensions/GooglePlayServices/docs/general.html b/extensions/GooglePlayServices/docs/general.html new file mode 100644 index 000000000..099f74394 --- /dev/null +++ b/extensions/GooglePlayServices/docs/general.html @@ -0,0 +1,520 @@ + + + + + + + + General - GMEXT-GooglePlayServices + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+ +
+
+
+
+ +

+

General

+

Play Games Services sign-in provides you with a player's gaming identity, which is a platform-level, gaming-specific identity for Android players. This identity helps build a relationship between your game and the player. Players are more willing to use this identity to sign in than with alternate centralized systems.

+

Functions

+

The following functions are provided for general tasks:

+ +

Structs

+

The following structures are provided as response for some GooglePlayServices API calls:

+ +


+
+

Back To Top

+ +

GooglePlayServices_IsAuthenticated

+

Queries the servers for the current authentication status.

+

This function operates asynchronously, which means that it does not immediately return the requested result. Instead, upon completion of the task, it will trigger the Social Async Event.

+


+

Syntax:

+
+
GooglePlayServices_IsAuthenticated()
+
+


+

Returns:

+
+

Real

+
+


+

Triggers:

+
+

Social Async Event

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeStringThe string "GooglePlayServices_IsAuthenticated"
successBooleanWhether or not the function request succeeded
isAuthenticatedBooleanWhether or not player is authenticated
+


+

Example:

+

GooglePlayServices_IsAuthenticated()
+The code sample above save the identifier that can be used inside an Social Async Event. +
if(async_load[? "type"] == "GooglePlayServices_IsAuthenticated")
+{
+    if(!async_load[?"success"])
+     exit
+
+    if(async_load[?"isAuthenticated"]);
+    {
+        show_debug_message("GoolePlayServices Player Authenticated")
+    }
+    else
+    {
+        GooglePlayServices_SignIn()
+    }
+}
+The code above matches the response against the correct event type and, if the player is not authenticated yet, it calls GooglePlayServices_SignIn to initiate the sign in process.

+


+


+
+

Back To Top

+ +

GooglePlayServices_IsAvailable

+

This function returns whether or not the user has GooglePlayServices installed into their devices. This is required for using any of the extension functions.

+


+

Syntax:

+
+
GooglePlayServices_IsAvailable()
+
+


+

Returns:

+
+

Boolean

+
+


+

Example:

+

if(GooglePlayServices_IsAvailable())
+{
+    show_debug_message("GooglePlayServices Available")
+    //Do something
+}
+The code sample above will check if the GooglePlayServices are installed into the device after a positive result from this call you can call any of the function from the extension.

+


+


+
+

Back To Top

+ +

GooglePlayServices_RequestServerSideAccess

+

Requests server-side access to Play Games Services for the currently signed-in player, this is necessary for 3rd party apps that need GooglePlayServices authentication.

+

When requested, an authorization code is returned that can be used by your server to exchange for an access token (and conditionally a refresh token when forceRefreshToken is true). The access token may then be used by your server to access the Play Games Services web APIs. This is commonly used to complete a sign-in flow by verifying the Play Games Services player ID.

+

If forceRefreshToken is true, when exchanging the authorization code, a refresh token will be returned in addition to the access token. The refresh token allows your server to request additional access tokens, allowing your server to continue accesses Play Games Services while the user is not actively playing your game. Refresh tokens are only generated for players that have auto sign-in setting enabled.

+

This function operates asynchronously, which means that it does not immediately return the requested result. Instead, upon completion of the task, it will trigger the Social Async Event.

+


+

Syntax:

+
+
GooglePlayServices_RequestServerSideAccess(serverClientId, forceRefreshToken)
+
+ + + + + + + + + + + + + + + + + + + + +
ArgumentTypeDescription
serverClientIdStringThe client ID of the server that will perform the authorization code flow exchange.
forceRefreshTokenBooleanIf true, when the returned authorization code is exchanged, a refresh token will be included in addition to an access token.
+


+

Returns:

+
+

Real

+
+


+

Triggers:

+
+

Social Async Event

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeStringThe string "GooglePlayServices_RequestServerSideAccess"
successBooleanWhether or not the function request succeeded.
authCodeStringThe authorization code
+


+

Example:

+

GooglePlayServices_RequestServerSideAccess()
+The code sample above requests for an authorization code that will allow server side access, the code can be caught inside an Social Async Event. +
if(async_load[? "type"] == "GooglePlayServices_RequestServerSideAccess")
+{
+    if(!async_load[?"success"])
+       exit
+
+    var authorizationCode = async_load[?"authCode"];
+    // Use the code to request a accessToken (with optional refreshToken)
+
+}
+The code above matches the response against the correct event type and in case of success caches the authorization code that can be later used on 3rd party libraries.

+


+


+
+

Back To Top

+ +

GooglePlayServices_SignIn

+

Manually requests that your game sign in with Play Games Services.

+
+

Note

+

A sign-in attempt will be made automatically when your game starts. Games will only need to manually request to sign in if the automatic sign-in attempt failed.

+
+

This function operates asynchronously, which means that it does not immediately return the requested result. Instead, upon completion of the task, it will trigger the Social Async Event.

+


+

Syntax:

+
+
GooglePlayServices_SignIn()
+
+


+

Returns:

+
+

Real

+
+


+

Triggers:

+
+

Social Async Event

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeStringThe string "GooglePlayServices_SignIn"
successBooleanWhether or not the function request succeeded
isAuthenticatedBooleanWhether or not player is authenticated
+


+

Example:

+

GooglePlayServices_SignIn()
+The code sample above save the identifier that can be used inside an Social Async Event. +
if(async_load[? "type"] == "GooglePlayServices_SignIn")
+{
+    if(!async_load[?"success"])
+       exit
+
+    if(async_load[?"isAuthenticated"]);
+    {
+        show_debug_message("GoolePlayServices Player Authenticated")
+    }
+    else
+    {
+        show_debug_message("Lets continue without GooglePlayGameServices")
+    }
+}
+The code above matches the response against the correct event type and logs the success of the task.

+


+


+
+

Back To Top

+ +

GameJSON

+

This is the GameJSON is a json formatted string representing a game and its associated metadata.

+

This struct is referenced by the following structs:

+ +


+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MemberTypeDescription
areSnapshotsEnabledBooleanWhether or not this game supports snapshots.
achievementTotalCountRealThe number of achievements registered for this game.
applicationIdStringThe application ID for this game.
descriptionStringThe description of this game.
developerNameStringThe name of the developer of this game.
displayNameStringThe display name for this game.
featuredImageUriStringAn image URI that can be used to load the game's featured (banner) image from Google Play (see GooglePlayServices_UriToPath). Not present if the game has no featured image.
hiResImageUriStringAn image URI that can be used to load the game's hi-res image (see GooglePlayServices_UriToPath). Not present if the game has no high-res image.
iconImageUriStringAn image URI that can be used to load the game's icon (see GooglePlayServices_UriToPath). Not present if the game has no icon image.
leaderboardCountRealThe number of leaderboards registered for this game.
primaryCategoryStringThe primary category of the game.
secondaryCategoryStringThe secondary category of the game.
themeColorStringThe theme color for this game.
gamepadSupportBooleanWhether or not this game is marked as supporting gamepads.
+


+ +
+
+ +
+
+ +
+ +
+ +
+ + + + GitHub + + + + « Previous + + + Next » + + +
+ + + + + + + + + + diff --git a/extensions/GooglePlayServices/docs/google_setup.html b/extensions/GooglePlayServices/docs/google_setup.html new file mode 100644 index 000000000..b040d09e5 --- /dev/null +++ b/extensions/GooglePlayServices/docs/google_setup.html @@ -0,0 +1,169 @@ + + + + + + + + Google Setup - GMEXT-GooglePlayServices + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+ +
+
+
+
+ +

Google Play Setup

+

Before you can add any cloud sync code and test it, you first have to set up an app listing on your Google Play Developer Console for the game and you will also have had to upload an APK to one of the available channels for testing - either Internal Test (recommended), Alpha or Beta is fine. Once that has been done, you will also need to set up the Game Services for the app.

+

From the Developer dashboard, click the Game Services button on the left, then click the Add New Game button:

+

+

This will then show you a screen where you have to give some details about the game, including a name and a category:

+

+

After filling in the information and pressing Continue, you will now need to go to the Linked Apps section and get the App ID and set the app as being for Android:

+

+

The App ID is shown at the top and you will need to take a note of it as we'll be using it in GameMaker later. When you click the Android button, you will then be prompted to give some information about the app you want to link the services too, and you should link it to an app that you have previously uploaded to the store.

+

Once that's done, we have one final task and that is to enable Cloud Saving for the game services. This is done from the Game Details page:

+

+

Before publishing the game publicly, you will need to complete the rest of the game details on this page, but for now, you can simply enable saving and then continue on to add the code into your project in GameMaker.

+


+ +
+
+ +
+
+ +
+ +
+ +
+ + + + GitHub + + + + « Previous + + + Next » + + +
+ + + + + + + + + + diff --git a/extensions/GooglePlayServices/docs/home.html b/extensions/GooglePlayServices/docs/home.html new file mode 100644 index 000000000..7d3859cd4 --- /dev/null +++ b/extensions/GooglePlayServices/docs/home.html @@ -0,0 +1,178 @@ + + + + + + + + Google Play Services - GMEXT-GooglePlayServices + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+ +
+
+
+
+ +

+

GooglePlayServices

+

This is the GooglePlayServices extension and it provides the developers with a set of tools for creating engaging and appealing games. Here you can find the full available API documentation and guides necessary to get you started with creating your games.

+

Guides

+

This section hosts the guides to get you up and running.

+ +

Modules

+

The following are the available modules from the GooglePlayServices API:

+ +


+
+ +
+
+ +
+
+ +
+ +
+ +
+ + + + GitHub + + + + + Next » + + +
+ + + + + + + + + + diff --git a/extensions/GooglePlayServices/docs/img/favicon.ico b/extensions/GooglePlayServices/docs/img/favicon.ico new file mode 100644 index 000000000..e85006a3c Binary files /dev/null and b/extensions/GooglePlayServices/docs/img/favicon.ico differ diff --git a/extensions/GooglePlayServices/docs/index.html b/extensions/GooglePlayServices/docs/index.html new file mode 100644 index 000000000..eae5b3243 --- /dev/null +++ b/extensions/GooglePlayServices/docs/index.html @@ -0,0 +1,166 @@ + + + + + + + + GMEXT-GooglePlayServices + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+ +
+
+
+
+ +

Welcome to MkDocs

+

For full documentation visit mkdocs.org.

+

Commands

+
    +
  • mkdocs new [dir-name] - Create a new project.
  • +
  • mkdocs serve - Start the live-reloading docs server.
  • +
  • mkdocs build - Build the documentation site.
  • +
  • mkdocs -h - Print help message and exit.
  • +
+

Project layout

+
mkdocs.yml    # The configuration file.
+docs/
+    index.md  # The documentation homepage.
+    ...       # Other markdown pages, images and other files.
+
+ +
+
+ +
+
+ +
+ +
+ +
+ + + + GitHub + + + + + +
+ + + + + + + + + + + + diff --git a/extensions/GooglePlayServices/docs/js/html5shiv.min.js b/extensions/GooglePlayServices/docs/js/html5shiv.min.js new file mode 100644 index 000000000..1a01c94ba --- /dev/null +++ b/extensions/GooglePlayServices/docs/js/html5shiv.min.js @@ -0,0 +1,4 @@ +/** +* @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed +*/ +!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document); diff --git a/extensions/GooglePlayServices/docs/js/jquery-3.6.0.min.js b/extensions/GooglePlayServices/docs/js/jquery-3.6.0.min.js new file mode 100644 index 000000000..c4c6022f2 --- /dev/null +++ b/extensions/GooglePlayServices/docs/js/jquery-3.6.0.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0"),n("table.docutils.footnote").wrap("
"),n("table.docutils.citation").wrap("
"),n(".wy-menu-vertical ul").not(".simple").siblings("a").each((function(){var t=n(this);expand=n(''),expand.on("click",(function(n){return e.toggleCurrent(t),n.stopPropagation(),!1})),t.prepend(expand)}))},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),t=e.find('[href="'+n+'"]');if(0===t.length){var i=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(t=e.find('[href="#'+i.attr("id")+'"]')).length&&(t=e.find('[href="#"]'))}if(t.length>0){$(".wy-menu-vertical .current").removeClass("current").attr("aria-expanded","false"),t.addClass("current").attr("aria-expanded","true"),t.closest("li.toctree-l1").parent().addClass("current").attr("aria-expanded","true");for(let n=1;n<=10;n++)t.closest("li.toctree-l"+n).addClass("current").attr("aria-expanded","true");t[0].scrollIntoView()}}catch(n){console.log("Error expanding nav for anchor",n)}},onScroll:function(){this.winScroll=!1;var n=this.win.scrollTop(),e=n+this.winHeight,t=this.navBar.scrollTop()+(n-this.winPosition);n<0||e>this.docHeight||(this.navBar.scrollTop(t),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",(function(){this.linkScroll=!1}))},toggleCurrent:function(n){var e=n.closest("li");e.siblings("li.current").removeClass("current").attr("aria-expanded","false"),e.siblings().find("li.current").removeClass("current").attr("aria-expanded","false");var t=e.find("> ul li");t.length&&(t.removeClass("current").attr("aria-expanded","false"),e.toggleClass("current").attr("aria-expanded",(function(n,e){return"true"==e?"false":"true"})))}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:n.exports.ThemeNav,StickyNav:n.exports.ThemeNav}),function(){for(var n=0,e=["ms","moz","webkit","o"],t=0;t + + + + + + + Leaderboards - GMEXT-GooglePlayServices + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+ +
+
+
+
+ +

+

Leaderboards

+

Leaderboards can be a fun way to drive competition among your players, both for your most hardcore fans (who will be fighting for the top spot in a public leaderboard) and for your more casual players (who will be interested in comparing their progress to their friends').

+

Functions

+

The following functions are provided for working with leaderboards:

+ +

Constants

+

The following constants are provided to be used as input arguments or output values:

+ +

Structs

+

The following structures are used as output values from the function calls to the GooglePlayServices API:

+ +


+
+

Back To Top

+ +

GooglePlayServices_Leaderboard_LoadPlayerCenteredScores

+

Asynchronously load the player-centered page of scores for a given leaderboard. If the player does not have a score on this leaderboard, this call will return the first page instead.

+

This function operates asynchronously, which means that it does not immediately return the requested result. Instead, upon completion of the task, it will trigger the Social Async Event.

+


+

Syntax:

+
+
GooglePlayServices_Leaderboard_LoadPlayerCenteredScores(leaderboardId, span, collection, maxResults, forceReload)
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ArgumentTypeDescription
leaderboardIdStringThe unique identifier of the leaderboard.
spanLeaderboardTimeSpanThe time span to retrieve data for.
collectionLeaderboardCollectionhe collection to retrieve scores for
maxResultsRealThe maximum number of scores to fetch per page. Must be between 1 and 25.
forceReloadBooleanIf true, this call will clear any locally cached data and attempt to fetch the latest data from the server. This would commonly be used for something like a user-initiated refresh. Normally, this should be set to false to gain advantages of data caching.
+


+

Returns:

+
+

Real

+
+


+

Triggers:

+
+

Social Async Event

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeStringThe string "GooglePlayServices_Leaderboard_LoadPlayerCenteredScores"
indRealThe id of the request this callback refers to.
dataStringA json formatted string of an array of LeaderboardEntryJSON. This string can be parsed into an array with the function json_parse.
+


+

Example:

+

GooglePlayServices_Leaderboard_LoadPlayerCenteredScores(Leaderboard1, Leaderboard_TIME_SPAN_ALL_TIME, Leaderboard_COLLECTION_PUBLIC, 5, true)
+The code sample above will start a query for player centered leaderboard entries. The results can be caught inside an Social Async Event. +
if(async_load[?"type"] == "GooglePlayServices_Leaderboard_LoadPlayerCenteredScores")
+{
+    var array = json_parse(async_load[?"data"])
+    for(var a = 0 ; a < array_length(array) ; a ++)
+    {
+        var struct = array[a]
+        var ins = instance_create_depth(800,200+a*75,00,Obj_GooglePlayServices_Leaderboard_Entry)
+        ins.displayRank = struct.displayRank;
+        ins.displayScore = struct.displayScore;
+        ins.rank = struct.rank;
+        ins.rawScore = struct.rawScore;
+        ins.scoreHolder = struct.scoreHolder;
+        ins.scoreHolderDisplayName = struct.scoreHolderDisplayName;
+        ins.scoreHolderHiResImageUri = struct.scoreHolderHiResImageUri;
+        ins.scoreHolderIconImageUri = struct.scoreHolderIconImageUri;
+
+        // This is an options parameter and is only present if a scoreTag was provided.
+        ins.scoreTag = struct[$ "scoreTag"];
+
+        ins.timestampMillis = struct.timestampMillis;
+    }
+}
+The code above shows a way of reading the returned data using the function json_parse. This sample is taken from the demo project check the project for more context.

+


+


+
+

Back To Top

+ +

GooglePlayServices_Leaderboard_LoadTopScores

+

Asynchronously load the top page of scores for a given leaderboard.

+

This function operates asynchronously, which means that it does not immediately return the requested result. Instead, upon completion of the task, it will trigger the Social Async Event.

+


+

Syntax:

+
+
GooglePlayServices_Leaderboard_LoadTopScores(leaderboardId, span, collection, maxResults, forceReload)
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ArgumentTypeDescription
leaderboardIdStringThe unique identifier of the leaderboard.
spanLeaderboardTimeSpanThe time span to retrieve data for.
collectionLeaderboardCollectionhe collection to retrieve scores for
maxResultsRealThe maximum number of scores to fetch per page. Must be between 1 and 25.
forceReloadBooleanIf true, this call will clear any locally cached data and attempt to fetch the latest data from the server. This would commonly be used for something like a user-initiated refresh. Normally, this should be set to false to gain advantages of data caching.
+


+

Returns:

+
+

Real

+
+


+

Triggers:

+
+

Social Async Event

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeStringThe string "GooglePlayServices_Leaderboard_LoadTopScores"
indRealThe id of the request this callback refers to.
dataStringA json formatted string of an array of LeaderboardEntryJSON. This string can be parsed into an array with the function json_parse.
+


+

Example:

+

GooglePlayServices_Leaderboard_LoadTopScores(Leaderboard1, Leaderboard_TIME_SPAN_ALL_TIME, Leaderboard_COLLECTION_PUBLIC, 5, true)
+The code sample above will start a query for top scores leaderboard entries. The results can be caught inside a Social Async Event. +
if(async_load[?"type"] == "GooglePlayServices_Leaderboard_LoadTopScores")
+{
+    var array = json_parse(async_load[?"data"])
+    for(var a = 0 ; a < array_length(array) ; a ++)
+    {
+        var struct = array[a]
+        var ins = instance_create_depth(800,200+a*75,00,Obj_GooglePlayServices_Leaderboard_Entry)
+        ins.displayRank = struct.displayRank;
+        ins.displayScore = struct.displayScore;
+        ins.rank = struct.rank;
+        ins.rawScore = struct.rawScore;
+        ins.scoreHolder = struct.scoreHolder;
+        ins.scoreHolderDisplayName = struct.scoreHolderDisplayName;
+        ins.scoreHolderHiResImageUri = struct.scoreHolderHiResImageUri;
+        ins.scoreHolderIconImageUri = struct.scoreHolderIconImageUri;
+
+        // This is an options parameter and is only present if a scoreTag was provided.
+        ins.scoreTag = struct[$ "scoreTag"];
+
+        ins.timestampMillis = struct.timestampMillis;
+    }
+}
+The code above shows a way of reading the returned data using the function json_parse. This sample is taken from the demo project check the project for more context.

+


+


+
+

Back To Top

+ +

GooglePlayServices_Leaderboard_Show

+

This function will call the Google Play Services overlay for a specific leaderboard.

+


+

Syntax:

+
+
GooglePlayServices_Leaderboard_Show(leaderboardId)
+
+ + + + + + + + + + + + + + + +
ArgumentTypeDescription
leaderboardIdStringThe unique identifier of the leaderboard.
+


+

Returns:

+
+

N/A

+
+


+

Example:

+

GooglePlayServices_Leaderboard_Show(leaderboardId);
+The code above will trigger the leaderboard overlay of the given leaderboard.

+


+


+
+

Back To Top

+ +

GooglePlayServices_Leaderboard_ShowAll

+

This function will call the general Google Play Services leaderboards overlay. Here the user will have access to all the existing leaderboards of the current application.

+


+

Syntax:

+
+
GooglePlayServices_Leaderboard_ShowAll()
+
+


+

Returns:

+
+

N/A

+
+


+

Example:

+

GooglePlayServices_Leaderboard_ShowAll()
+The code above will trigger the leaderboard overlay of all the available leaderboards for this game.

+


+


+
+

Back To Top

+ +

GooglePlayServices_Leaderboard_SubmitScore

+

This function requests the Google Play Services API to submit a score to the given leaderboard.

+

This function operates asynchronously, which means that it does not immediately return the requested result. Instead, upon completion of the task, it will trigger the Social Async Event.

+


+

Syntax:

+
+
GooglePlayServices_Leaderboard_SubmitScore(leaderboardId, score, scoreTag)
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
ArgumentTypeDescription
leaderboardIdStringThe unique identifier of the leaderboard.
scoreRealThe value to be submitted to the leaderboard (remember that only the highest score value is displayed in the leaderboard).
scoreTagStringA tag that will be added to the value being submitted to the leaderboard (note that this value is required, if you don't want to set a tag use an empty string).
+


+

Returns:

+
+

Real

+
+


+

Triggers:

+
+

Social Async Event

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeStringThe string "GooglePlayServices_Leaderboard_SubmitScore"
indRealThe id of the request this callback refers to.
successBooleanWhether or not the function request succeeded.
leaderboardIdStringThe unique name of the leaderboard.
scoreRealThe submitted score.
scoreTagStringThe tag for the current submission.
reportStringA json formatted string of LeaderboardReportJSON. This string can be parsed into a struct with the function json_parse. Only available if the task succeeds.
+


+

Example:

+

GooglePlayServices_Leaderboard_SubmitScore(leaderId, 100, "archer");
+The code sample above will submit a new score to the leaderboard with a specific tag ("archer"). The result can be caught inside a Social Async Event as follows: +
if(async_load[?"type"] == "GooglePlayServices_Leaderboard_SubmitScore")
+if(async_load[?"success")
+{
+    //Done, let's continue
+}
+The code above checks if the task was successful. This sample is taken from the demo project check the project for more context.

+


+


+
+

Back To Top

+ +

LeaderboardCollection

+

These constants represent kinds of leaderboard collections.

+

These constants are referenced by the following functions:

+ +


+ + + + + + + + + + + + + + + + + +
MemberDescription
Leaderboard_COLLECTION_SOCIALThese leaderboards contain the scores of players in the viewing player's friends list.
Leaderboard_COLLECTION_PUBLICPublic leaderboards contain the scores of players who are sharing their gameplay activity publicly.
+


+
+

Back To Top

+ +

LeaderboardTimeSpan

+

These constants represent the various types of time span that can be used.

+

These constants are referenced by the following functions:

+ +


+ + + + + + + + + + + + + + + + + + + + + +
MemberDescription
Leaderboard_TIME_SPAN_DAILYRefers to the scores of the day. Scores are reset every day. The reset occurs at 11:59PM PST.
Leaderboard_TIME_SPAN_WEEKLYRefers to the scores of the week. Scores are reset once per week. The reset occurs at 11:59PM PST on Sunday.
Leaderboard_TIME_SPAN_ALL_TIMERefers to all the scores. Scores are never reset.
+


+
+

Back To Top

+ +

LeaderboardEntryJSON

+

Represents a score and its associated metadata.

+


+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MemberTypeDescription
displayRankStringA formatted string to display for this rank. This handles appropriate localization and formatting.
displayScoreStringA formatted string to display for this score. The details of the formatting are specified by the developer in their dev console.
rankRealThe rank returned from the server for this score. Note that this may not be exact and that multiple scores can have identical ranks. Lower ranks indicate a better score, with rank 1 being the best score on the board.
rawScoreRealThe raw score value.
scoreHolderPlayerJSONA struct of PlayerJSON.
scoreHolderDisplayNameStringThe display name of the player that scored this particular score.
scoreHolderHiResImageUriStringThe URI of the hi-res image to display for the player who scored this score (you can later convert the uri to a local path using the GooglePlayServices_UriToPath).
scoreHolderIconImageUriStringThe URI of the icon image to display for the player who scored this score (you can later convert the uri to a local path using the GooglePlayServices_UriToPath).
+


+
+

Back To Top

+ +

LeaderboardReportJSON

+

Represents a leaderboard report and its associated metadata.

+


+ + + + + + + + + + + + + + + + + + + + + + + + + +
MemberTypeDescription
allTimeLeaderboardReportEntryJSONThe all time result report.
weeklyLeaderboardReportEntryJSONThe weekly result report.
dailyLeaderboardReportEntryJSONThe daily result report
+


+
+

Back To Top

+ +

LeaderboardReportEntryJSON

+

Represents a leaderboard report entry.

+

This struct is referenced by the following structs:

+ +


+ + + + + + + + + + + + + + + + + + + + + + + + + +
MemberTypeDescription
isNewBestBooleanWhether or not this score is a new best.
scoreRealThe score submitted to the server.
scoreTagStringThe tag used the submittion of the achievement.
+


+ +
+
+ +
+
+ +
+ +
+ +
+ + + + GitHub + + + + « Previous + + + Next » + + +
+ + + + + + + + + + diff --git a/extensions/GooglePlayServices/docs/player.html b/extensions/GooglePlayServices/docs/player.html new file mode 100644 index 000000000..00506b319 --- /dev/null +++ b/extensions/GooglePlayServices/docs/player.html @@ -0,0 +1,531 @@ + + + + + + + + Player - GMEXT-GooglePlayServices + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+ +
+
+
+
+ +

+

Player

+

Being able to access player information allows for a much better gaming experience. The game can be tailored to the gamer in new and creative ways. This functions will allow you to gain that kind of costumization.

+

Functions

+

The following functions are provided for working with player data:

+ +

Structs

+

The following structures are used by the API to expose data to the developer:

+ +


+
+

Back To Top

+ +

GooglePlayServices_Player_Current

+

This function queries the Google Play server for information on the current signed-in player.

+

This function operates asynchronously, which means that it does not immediately return the requested result. Instead, upon completion of the task, it will trigger the Social Async Event.

+


+

Syntax:

+
+
GooglePlayServices_Player_Current()
+
+


+

Returns:

+
+

Real

+
+


+

Triggers:

+
+

Social Async Event

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeStringThe string "GooglePlayServices_Player_Current"
indRealThe id of the request this callback refers to.
successBooleanWhether or not the function request succeeded
playerStringThe information of the player as a json formatted string of PlayerJSON. This string can be parsed into a struct with the function json_parse.
+


+

Example:

+

GooglePlayServices_Player_Current()
+The code sample above will trigger a player data fetch and the callback can be caught inside an Social Async Event. +
if(async_load[? "type"] == "GooglePlayServices_Player_Current")
+{
+    if(!async_load[?"success"])
+       exit
+
+    var playerInfo = json_parse(async_load[? "player"]);
+
+    // ### Available members #### (some are optional, check documentation)
+    // bannerImageLandscapeUri
+    // bannerImagePortraitUri
+    // displayName
+    // hiResImageUri
+    // iconImageUri
+    // currentXpTotal
+    // lastLevelUpTimestamp
+    // currentLevelNumber
+    // currentMaxXp
+    // currentMinXp
+    // nextLevelNumber
+    // nextMaxXp
+    // nextMinXp
+    // playerId
+    // retrievedTimestamp
+    // title
+
+}
+The code above matches the response against the correct event type and parses the player data string into a struct (PlayerJSON) using the function json_parse. This sample is taken from the demo project check the project for more context.

+


+


+
+

Back To Top

+ +

GooglePlayServices_Player_CurrentID

+

This function queries the Google Play server for information on the current player's unique id.

+

This function operates asynchronously, which means that it does not immediately return the requested result. Instead, upon completion of the task, it will trigger the Social Async Event.

+


+

Syntax:

+
+
GooglePlayServices_Player_CurrentID()
+
+


+

Returns:

+
+

Real

+
+


+

Triggers:

+
+

Social Async Event

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeStringThe string "GooglePlayServices_Player_CurrentID"
indRealThe id of the request this callback refers to.
successBooleanWhether or not the function request succeeded.
playerIDStringThe unique identifier of the current player.
+


+

Example:

+

GooglePlayServices_Player_CurrentID()
+The code sample above save the identifier that can be used inside an Social Async Event. +
if(async_load[? "type"] == "GooglePlayServices_Player_CurrentID")
+{
+    if(!async_load[?"success"])
+       exit
+
+    var playerId = async_load[? "playerID"];
+}
+The code above matches the response against the correct event type and cache the playerID into a variable.

+


+


+
+

Back To Top

+ +

GooglePlayServices_PlayerStats_LoadPlayerStats

+

This function queries the Google Play server for a lot of statistical values regarding the logged in player.

+

This function operates asynchronously, which means that it does not immediately return the requested result. Instead, upon completion of the task, it will trigger the Social Async Event.

+


+

Syntax:

+
+
GooglePlayServices_PlayerStats_LoadPlayerStats()
+
+


+

Returns:

+
+

Real

+
+


+

Triggers:

+
+

Social Async Event

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeStringThe string "GooglePlayServices_PlayerStats_LoadPlayerStats".
indRealThe id of the request this callback refers to.
successBooleanWhether or not the function request succeeded.
AverageSessionLengthRealThe average session length of the player in minutes.
DaysSinceLastPlayedRealThe approximate number of days since the player last played.
NumberOfPurchasesRealThe approximate number of in-app purchases for the player.
NumberOfSessionsRealThe approximate number of sessions of the player.
SessionPercentileRealThe approximation of sessions percentile for the player.
SpendPercentileRealThe approximate spend percentile of the player.
+


+

Example:

+

GooglePlayServices_PlayerStats_LoadPlayerStats()
+The code sample above save the identifier that can be used inside an Social Async Event. +
if(async_load[? "type"] == "GooglePlayServices_PlayerStats_LoadPlayerStats")
+{
+    if(!async_load[?"success"])
+       exit
+
+    // Do something with the data
+}
+The code above matches the response against the correct event type and bails out if the task was not successful.

+


+


+
+

Back To Top

+ +

PlayerJSON

+

Represents a player and its associated metadata.

+

This struct is referenced by the following structs:

+ +


+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MemberTypeDescription
bannerImageLandscapeUriStringThe URI for loading this player's landscape banner image (see GooglePlayServices_UriToPath). Not present if the player has no landscape banner image image.
bannerImagePortraitUriStringThe URI for loading this player's portrait banner image (see GooglePlayServices_UriToPath). Not present if the player has no portrait banner image.
displayNameStringThe display name for this player.
hiResImageUriStringThe URI for loading this player's hi-res profile image (see GooglePlayServices_UriToPath). Not present if the player has no high-resolution image.
iconImageUriStringThe URI for loading this player's icon-size profile image (see GooglePlayServices_UriToPath). Not present if the player has no icon image.
currentXpTotalRealThe player's current XP value.
lastLevelUpTimestampRealThe timestamp of the player's last level-up.
currentLevelNumberRealThe number for the current level.
currentMaxXpRealThe maximum XP value represented by the current level, exclusive.
currentMinXpRealThe minimum XP value needed to attain the current level, inclusive.
nextLevelNumberRealThe number for the next level. Not present if the player is already at the maximum level.
nextMaxXpRealThe maximum XP value represented by the next level, exclusive. Not present if the player is already at the maximum level.
nextMinXpRealThe minimum XP value needed to attain the next level, inclusive. Not present if the player is already at the maximum level.
playerIdStringThe ID of this player.
retrievedTimestampRealThe timestamp at which this player record was last updated locally.
titleStringThe title of the player.
hasHiResImageBooleanIndicates whether this player has a hi-res profile image to display.
hasIconImageBooleanIndicates whether this player has an icon-size profile image to display.
+


+ +
+
+ +
+
+ +
+ +
+ +
+ + + + GitHub + + + + « Previous + + + Next » + + +
+ + + + + + + + + + diff --git a/extensions/GooglePlayServices/docs/savedgames.html b/extensions/GooglePlayServices/docs/savedgames.html new file mode 100644 index 000000000..e71b523d2 --- /dev/null +++ b/extensions/GooglePlayServices/docs/savedgames.html @@ -0,0 +1,919 @@ + + + + + + + + SavedGames - GMEXT-GooglePlayServices + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+ +
+
+
+
+ +

+

SavedGames

+

The Saved Games service gives you a convenient way to save your players' game progression to Google's servers. Your game can retrieve the saved game data to allow returning players to continue a game at their last save point from any device.

+

The Saved Games service makes it possible to synchronize a player's game data across multiple devices. For example, if you have a game that runs on Android, you can use the Saved Games service to allow a player to start a game on their Android phone, and then continue playing on a tablet without losing any of their progress. This service can also be used to ensure that a player's game play continues from where it left off even if their device is lost, destroyed, or traded in for a newer model.

+

Functions

+

The following functions are provided for working with saved games:

+ +

Structs

+

The following structurs are used as output values from the function calls to the GooglePlayServices API:

+ +


+
+

Back To Top

+ +

GooglePlayServices_SavedGames_CommitAndClose

+

This function requests the Google Play Services API to commit data to a given save slot. The unique identifier of the slot needs to exist meaning that this function will only update already existing files (see GooglePlayServices_SavedGames_CommitNew for creating new ones) but the description, data and coverPath can be changed if needed.

+

This function operates asynchronously, which means that it does not immediately return the requested result. Instead, upon completion of the task, it will trigger the Social Async Event.

+


+

Syntax:

+
+
GooglePlayServices_SavedGames_CommitAndClose(name, description, data, coverPath)
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ArgumentTypeDescription
nameStringThe unique identifier of the save game slot.
descriptionStringThe description of the current save slot.
dataStringA string containing the data you want to save (note you can use json formatted string to store data).
coverPathStringThe path to the image to be used as a save slot cover image.
+


+

Returns:

+
+

Real

+
+


+

Triggers:

+
+

Social Async Event

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeStringThe string "GooglePlayServices_SavedGames_CommitAndClose"
indRealThe id of the request this callback refers to.
successBooleanWhether or not the function request succeeded.
+


+

Example:

+

GooglePlayServices_SavedGames_CommitAndClose("slot_1", "Random Description....", json_stringify(struct), coverPath);
+The code sample above save the identifier that can be used inside an Social Async Event. +
if(async_load[? "type"] == "GooglePlayServices_SavedGames_CommitAndClose")
+{
+    if(async_load[? "success"])
+      show_debug_message("Saved")
+    else
+      show_debug_message("Not saved :(")
+}
+The code above matches the response against the correct event type and logs the success of the task. For a full usage sample check the provided demo.

+


+


+
+

Back To Top

+ +

GooglePlayServices_SavedGames_CommitNew

+

This function requests the Google Play Services API to commit data to a given save slot. This function will create a new slot, if you want to update an already existing slot use the GooglePlayServices_SavedGames_CommitAndClose function.

+

This function operates asynchronously, which means that it does not immediately return the requested result. Instead, upon completion of the task, it will trigger the Social Async Event.

+


+

Syntax:

+
+
GooglePlayServices_SavedGames_CommitNew(name, description, data, coverPath)
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ArgumentTypeDescription
nameStringThe unique identifier of the save game slot.
descriptionStringThe description of the current save slot.
dataStringA string containing the data you want to save (note you can use json formatted string to store data).
coverPathStringThe path to the image to be used as a save slot cover image.
+


+

Returns:

+
+

Real

+
+


+

Triggers:

+
+

Social Async Event

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeStringThe string "GooglePlayServices_SavedGames_CommitAndClose"
indRealThe id of the request this callback refers to.
successBooleanWhether or not the function request succeeded.
snapshotMetadataStringA json formatted string of SnapshotMetadataJSON. This string can be parsed into a struct with the function json_parse. Only available if the task succeeds.
+


+

Example:

+

GooglePlayServices_SavedGames_CommitNew("slot_1", "Random Description....", json_stringify(struct), coverPath);
+The code sample above save the identifier that can be used inside an Social Async Event. +
if(async_load[? "type"] == "GooglePlayServices_SavedGames_CommitNew")
+{
+    if(async_load[? "success"])
+      show_debug_message("Created");
+
+      var snapshots = json_parse(async_load[?"snapshotMetadata"]);
+      // Do something with the snapshots
+    else
+      show_debug_message("Not created :(")
+}
+The code above matches the response against the correct event type and logs the success of the task. For a full usage sample check the provided demo.

+


+


+
+

Back To Top

+ +

GooglePlayServices_SavedGames_Delete

+

This function requests the Google Play Services API to delete a given save slot given its unique identifier.

+

This function operates asynchronously, which means that it does not immediately return the requested result. Instead, upon completion of the task, it will trigger the Social Async Event.

+


+

Syntax:

+
+
GooglePlayServices_SavedGames_Delete(name)
+
+ + + + + + + + + + + + + + + +
ArgumentTypeDescription
nameStringThe unique identifier of the save game slot.
+


+

Returns:

+
+

Real

+
+


+

Triggers:

+
+

Social Async Event

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeStringThe string "GooglePlayServices_SavedGames_Delete"
indRealThe id of the request this callback refers to.
successBooleanWhether or not the function request succeeded.
+


+

Example:

+

GooglePlayServices_SavedGames_Delete("slot_1");
+The code sample above save the identifier that can be used inside an Social Async Event. +
if(async_load[? "type"] == "GooglePlayServices_SavedGames_Delete")
+{
+    if(async_load[? "success"])
+      show_debug_message("Deleted")
+    else
+      show_debug_message("Not Deleted :(")
+}
+The code above matches the response against the correct event type and logs the success of the task. For a full usage sample check the provided demo.

+


+


+
+

Back To Top

+ +

GooglePlayServices_SavedGames_DiscardAndClose

+

This function requests the Google Play Services API to discard changes and close the currently opened save slot.

+

This function operates asynchronously, which means that it does not immediately return the requested result. Instead, upon completion of the task, it will trigger the Social Async Event.

+


+

Syntax:

+
+
GooglePlayServices_SavedGames_DiscardAndClose(name)
+
+ + + + + + + + + + + + + + + +
ArgumentTypeDescription
nameStringThe unique identifier of the save game slot.
+


+

Returns:

+
+

Real

+
+


+

Triggers:

+
+

Social Async Event

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeStringThe string "GooglePlayServices_SavedGames_DiscardAndClose"
indRealThe id of the request this callback refers to.
successBooleanWhether or not the function request succeeded.
+


+

Example:

+

GooglePlayServices_SavedGames_DiscardAndClose("slot_1")
+The code sample above save the identifier that can be used inside an Social Async Event. +
if(async_load[? "type"] == "GooglePlayServices_SavedGames_DiscardAndClose")
+{
+    if(async_load[? "success"])
+      show_debug_message("Closed (discarding)")
+    else
+      show_debug_message("Not closed :(")
+}
+The code above matches the response against the correct event type and logs the success of the task. For a full usage sample check the provided demo.

+


+


+
+

Back To Top

+ +

GooglePlayServices_SavedGames_Load

+

This function requests the Google Play Services API to query all the save slot metadata of the currently signed-in user.

+

This function operates asynchronously, which means that it does not immediately return the requested result. Instead, upon completion of the task, it will trigger the Social Async Event.

+


+

Syntax:

+
+
GooglePlayServices_SavedGames_Load(forceReload)
+
+ + + + + + + + + + + + + + + +
ArgumentTypeDescription
forceReloadBooleanWhether or not the current local cache should be cleared and a new fetch should be performed from the server.
+


+

Returns:

+
+

Real

+
+


+

Triggers:

+
+

Social Async Event

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeStringThe string "GooglePlayServices_SavedGames_Load"
indRealThe id of the request this callback refers to.
successBooleanWhether or not the function request succeeded.
snapshotsStringA json formatted string of an array of SnapshotMetadataJSON. This string can be parsed into a struct with the function json_parse. Only available if the task succeeds.
+


+

Example:

+

GooglePlayServices_SavedGames_Load(true)
+The code sample above save the identifier that can be used inside an Social Async Event. +
if(async_load[? "type"] == "GooglePlayServices_SavedGames_Load")
+{
+    if(!async_load[?"success"])
+       exit
+
+    var snapshots = json_parse(async_load[?"snapshots"]);
+    //do something with snapshots
+}
+The code above matches the response against the correct event type and logs the success of the task. For a full usage sample check the provided demo.

+


+


+
+

Back To Top

+ +

GooglePlayServices_SavedGames_Open

+

This function requests the Google Play Services API to open a given save slot given its unique name identifier.

+

This function operates asynchronously, which means that it does not immediately return the requested result. Instead, upon completion of the task, it will trigger the Social Async Event.

+


+

Syntax:

+
+
GooglePlayServices_SavedGames_Open(name)
+
+ + + + + + + + + + + + + + + +
ArgumentTypeDescription
nameStringThe unique identifier of the save game slot.
+


+

Returns:

+
+

Real

+
+


+

Triggers:

+
+

Social Async Event

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeStringThe string "GooglePlayServices_SavedGames_Open"
indRealThe id of the request this callback refers to.
successBooleanWhether or not the function request succeeded.
dataStringThe string previously saved to the Google Play Services. Only available if the task succeeds.
+


+

Example:

+

GooglePlayServices_SavedGames_Open("slot_1")
+The code sample above save the identifier that can be used inside an Social Async Event +
if(async_load[? "type"] == "GooglePlayServices_SavedGames_Open")
+if (!async_load[? "success"])
+{
+    GooglePlayServices_SavedGames_Load(true);
+
+    var data = async_load[? "data"];
+    // do something with the data
+    return;
+}
+The code above matches the response against the correct event type and logs the success of the task. For a full usage sample check the provided demo.

+


+


+
+

Back To Top

+ +

GooglePlayServices_SavedGames_ShowSavedGamesUI

+

This function requests Google Play Services API to open the saved games UI overlay, giving you the ability to see, add (optional) and delete (optional) the save slots.

+
+

Note

+

This function will open an overlay the user can interact with, during this time there are some Async Social events that can be trigger depending on the actions performed by the user. Theses events are showed in the tables below.

+
+

This function operates asynchronously, which means that it does not immediately return the requested result. Instead, upon completion of the task, it will trigger the Social Async Event.

+


+

Syntax:

+
+
GooglePlayServices_SavedGames_ShowSavedGamesUI(title, add, delete, max)
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ArgumentTypeDescription
titleStringThe text to be used as the title of the overlay.
addBooleanWhether or not the Add slot button should be displayed.
deleteBooleanWhether or not the Delete slot button should be displayed.
maxBooleanSets the maximum amount of slots allowed. This can be useful to limit the number of saves you want the player to be able to create.
+


+

Returns:

+
+

Real

+
+


+

Triggers:

+
+

Social Async Event

+
+

Triggered whenever an existing slot is selected

+ + + + + + + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeStringThe string "GooglePlayServices_SavedGames_ShowSavedGamesUI_OnOpen".
indRealThe id of the request this callback refers to.
snapshotMetadataStringA json formatted string of SnapshotMetadataJSON. This string can be parsed into a struct with the function json_parse.
+


+

Triggered whenever a new slot is created.

+ + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeStringThe string "GooglePlayServices_SavedGames_ShowSavedGamesUI_OnNew".
indRealThe id of the request this callback refers to.
+


+

Triggered when the dialog is closed.

+ + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeStringThe string "GooglePlayServices_SavedGames_ShowSavedGamesUI_OnExit".
indRealThe id of the request this callback refers to.
+


+

Example:

+

GooglePlayServices_SavedGames_ShowSavedGamesUI("Save Point", true, true, 3)
+The code above will trigger the save games overlay with options to create/delete save slots and with a maximum number of 3 slots. From now on the triggered events can be caught inside an Social Async Event, as follows: +
switch(async_load[? "type"])
+{
+    case "GooglePlayServices_SavedGames_ShowSavedGamesUI_OnNew":
+        dialog_ind = get_string_async("Description: ","Slot #0");
+        break;
+
+    case "GooglePlayServices_SavedGames_ShowSavedGamesUI_OnOpen":
+        var snapshotMeta = json_parse(async_load[? "snapshotMetadata"]);
+        var uniqueName = snapshotMeta.uniqueName;
+        GooglePlayServices_SavedGames_Open(uniqueName);
+        break;
+
+    case "GooglePlayServices_SavedGames_ShowSavedGamesUI_OnExit":
+        GooglePlayServices_SavedGames_Load(true);
+        break;
+}
+The code above matches the response against the correct event type and acts accordingly by requesting the user a description for the new slot (if a new slot was created), opens a existinf slot (using GooglePlayServices_SavedGames_Open, if the user selects an existing one) or reloads the slot data (using GooglePlayServices_SavedGames_Load, if the user closes the overaly). For a full usage sample check the provided demo.

+


+


+
+

Back To Top

+ +

SnapshotMetadataJSON

+

Is a json formatted string that represents a snapshot and its associated metadata.

+


+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MemberTypeDescription
coverImageAspectRatioRealThe aspect ratio of the cover image for this snapshot, if any.
coverImageUriStringAn image URI that can be used to load the snapshot's cover image (see GooglePlayServices_UriToPath). Not present if the metadata has no cover image.
descriptionStringThe description of this snapshot.
deviceNameRealThe name of the device that wrote this snapshot, if known.
gameGameJSONA struct of GameJSON.
lastModifiedTimestampRealThe last time this snapshot was modified, in millis since epoch.
ownerPlayerJSONA struct of PlayerJSON.
playedTimeRealThe played time of this snapshot in milliseconds.
progressValueRealThe progress value for this snapshot.
uniqueNameStringThe unique identifier of this snapshot.
hasChangePendingBooleanIndicates whether or not this snapshot has any changes pending that have not been uploaded to the server.
+


+ +
+
+ +
+
+ +
+ +
+ +
+ + + + GitHub + + + + « Previous + + + Next » + + +
+ + + + + + + + + + diff --git a/extensions/GooglePlayServices/docs/sitemap.xml b/extensions/GooglePlayServices/docs/sitemap.xml new file mode 100644 index 000000000..0f8724efd --- /dev/null +++ b/extensions/GooglePlayServices/docs/sitemap.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/extensions/GooglePlayServices/docs/sitemap.xml.gz b/extensions/GooglePlayServices/docs/sitemap.xml.gz new file mode 100644 index 000000000..e4a0753db Binary files /dev/null and b/extensions/GooglePlayServices/docs/sitemap.xml.gz differ diff --git a/extensions/GooglePlayServices/docs/utilities.html b/extensions/GooglePlayServices/docs/utilities.html new file mode 100644 index 000000000..8baddfdb8 --- /dev/null +++ b/extensions/GooglePlayServices/docs/utilities.html @@ -0,0 +1,247 @@ + + + + + + + + Utilities - GMEXT-GooglePlayServices + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+ +
+
+
+
+ +

+

Utilities

+

This modules provides the user with some utility functions.

+

Functions

+

The following functions are provided for helping with development:

+ +


+
+

Back To Top

+ +

GooglePlayServices_UriToPath

+

Some of the functions callbacks in this API return URIs (unique resource identifiers). However if you need to open these files or load them as images (using the sprite_add function) it is necessary to convert these URIs into paths. This function requests the Google Play Services API for the path to a given URI.

+

This function operates asynchronously, which means that it does not immediately return the requested result. Instead, upon completion of the task, it will trigger the Social Async Event.

+


+

Syntax:

+
+
GooglePlayServices_UriToPath(uri)
+
+ + + + + + + + + + + + + + + +
ArgumentTypeDescription
uriStringThe URI to get the path from.
+


+

Returns:

+
+

Real

+
+


+

Triggers:

+
+

Social Async Event

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyTypeDescription
typeStringThe string "GooglePlayServices_UriToPath"
successBooleanWhether or not the function request succeeded.
indRealThe id of the request this callback refers to.
pathStringThe path to the resource.
+


+

Example:

+

var request = GooglePlayServices_UriToPath(uri)
+The code sample above save the identifier that can be used inside Social Async Event. +
if(async_load[? "type"] == "GooglePlayServices_UriToPath")
+if(async_load[?"ind"] == request)
+{
+    if(!async_load[?"success"])
+       exit
+
+    sprite = sprite_add(async_load[?"path"], 0, 0, 0, 0, 0);
+}
+The code above matches the response against the correct event type and request identifier (ind) . And loads the resolved path as a sprite using the sprite_add function.

+


+


+ +
+
+ +
+
+ +
+ +
+ +
+ + + + GitHub + + + + « Previous + + + +
+ + + + + + + + + + diff --git a/extensions/GooglePlayServices/pre_build_step.bat b/extensions/GooglePlayServices/pre_build_step.bat new file mode 100644 index 000000000..57f2dbe50 --- /dev/null +++ b/extensions/GooglePlayServices/pre_build_step.bat @@ -0,0 +1,19 @@ +@echo off +set Utils="%~dp0scriptUtils.bat" + +:: ###################################################################################### +:: Script Logic + +:: Always init the script +call %Utils% scriptInit + +:: Version locks +call %Utils% optionGetValue "versionStable" RUNTIME_VERSION_STABLE +call %Utils% optionGetValue "versionBeta" RUNTIME_VERSION_BETA +call %Utils% optionGetValue "versionDev" RUNTIME_VERSION_DEV +call %Utils% optionGetValue "versionLTS" RUNTIME_VERSION_LTS + +:: Checks IDE and Runtime versions +call %Utils% versionLockCheck "%YYruntimeVersion%" %RUNTIME_VERSION_STABLE% %RUNTIME_VERSION_BETA% %RUNTIME_VERSION_DEV% %RUNTIME_VERSION_LTS% + +exit 0 \ No newline at end of file diff --git a/extensions/GooglePlayServices/pre_build_step.sh b/extensions/GooglePlayServices/pre_build_step.sh new file mode 100644 index 000000000..098dccc5e --- /dev/null +++ b/extensions/GooglePlayServices/pre_build_step.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +sed -i -e 's/\r$//' "$(dirname "$0")/scriptUtils.sh" +chmod +x "$(dirname "$0")/scriptUtils.sh" +source "$(dirname "$0")/scriptUtils.sh" + +# ###################################################################################### +# Script Functions + +# ###################################################################################### +# Script Logic + +# Always init the script +scriptInit + +# Version locks +optionGetValue "versionStable" RUNTIME_VERSION_STABLE +optionGetValue "versionBeta" RUNTIME_VERSION_BETA +optionGetValue "versionDev" RUNTIME_VERSION_DEV +optionGetValue "versionLTS" RUNTIME_VERSION_LTS + +# Checks IDE and Runtime versions +versionLockCheck "$YYruntimeVersion" $RUNTIME_VERSION_STABLE $RUNTIME_VERSION_BETA $RUNTIME_VERSION_DEV $RUNTIME_VERSION_LTS + +exit 0 diff --git a/extensions/GooglePlayServices/scriptUtils.bat b/extensions/GooglePlayServices/scriptUtils.bat new file mode 100644 index 000000000..a4ddc6703 --- /dev/null +++ b/extensions/GooglePlayServices/scriptUtils.bat @@ -0,0 +1,367 @@ +@echo off + +set SCRIPT_PATH="%~0" +shift & goto :%~1 + +:scriptInit + set "LOG_LABEL=UNSET" + set "LOG_LEVEL=-1" + + :: Get extension data + call :pathExtractBase %SCRIPT_PATH% EXTENSION_NAME + call :extensionGetVersion EXTENSION_VERSION + if not defined EXTENSION_VERSION set "EXTENSION_VERSION=0.0.0" + + :: Setup logger + call :toUpper %EXTENSION_NAME% LOG_LABEL + call :optionGetValue "logLevel" LOG_LEVEL + if not defined LOG_LEVEL set "LOG_LEVEL=0" + + :: Check if the operation succeeded + if %errorlevel% neq 0 ( + call :log "INIT" "Script initialization failed (v%EXTENSION_VERSION% :: %LOG_LEVEL%)." + ) else ( + call :log "INIT" "Script initialization succeeded (v%EXTENSION_VERSION% :: %LOG_LEVEL%)." + ) +exit /b 0 + +:extensionGetVersion result + :: Need to enabled delayed expansion + setlocal enabledelayedexpansion + + set "result=!GMEXT_%EXTENSION_NAME%_version!" + call :logInformation "Accessed extension version with value '%result%'." + + :: Need to end local (to push into main scope) + endlocal & set "%~1=%result%" +exit /b 0 + +:: Gets an extension option value +:optionGetValue str result + :: Need to enabled delayed expansion + setlocal enabledelayedexpansion + + set "result=!YYEXTOPT_%EXTENSION_NAME%_%~1!" + call :logInformation "Accessed extension option '%~1' with value '%result%'." + + :: Need to end local (to push into main scope) + endlocal & set "%~2=%result%" +exit /b 0 + +:: Converts a string to uppercase and stores it into a variable +:toUpper str result + for /f "usebackq delims=" %%i in (`powershell.exe -Command "$str = '%~1'.ToUpper(); Write-Output $str"`) do set "%~2=%%i" + call :logInformation "Converted string '%~1' to uppercase." +exit /b 0 + +:: Extracts folder path from a filepath, if a folder path is provided return it instead +:pathExtractDirectory fullpath result + set "%~2=%~dp1" + call :logInformation "Extracted directory path from '%~1'." +exit /b 0 + +:: Extracts the parent folder path from a filepath. The input 'path\to\my\file.txt' must result in 'my' +:pathExtractBase fullpath result + for %%I in ("%~dp1\.") do set "%~2=%%~nI%%~xI" + call :logInformation "Extracted base name from '%~1'." +exit /b 0 + +:: Resolves a relative path if required +:pathResolve basePath relativePath result + + :: Need to enable delayed expansion + setlocal enabledelayedexpansion + + :: Set environment variables for basePath and relativePath + set "PS_BASEPATH=%~1" + set "PS_RELATIVEPATH=%~2" + + for /f "delims=" %%i in ('powershell -Command "$basePath = $env:PS_BASEPATH; $relativePath = $env:PS_RELATIVEPATH; Push-Location $basePath; $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($relativePath); Pop-Location;"') do set "result=%%i" + + :: Clean up environment variables + set "PS_BASEPATH=" + set "PS_RELATIVEPATH=" + + call :logInformation "Resolved relative path into '%result%'." + + :: Need to end local (to push into main scope) + endlocal & set "%~3=%result%" +exit /b 0 + +:: This function resolves the path if required and stores it into a variable (displays log messages) +:pathResolveExisting basePath relativePath result + :: Resolve the path + call :pathResolve "%~1" "%~2" "%~3" + + :: Need to enabled delayed expansion + setlocal enabledelayedexpansion + + :: Check if the path exists + if not exist "!%~3%!" ( + call :logError "Path '!%~3%!' does not exist." + endlocal & exit /b 1 + ) + :: Need to end local (to push into main scope) + endlocal +exit /b 0 + +:: Copies a file or folder to the specified destination folder (displays log messages) +:itemCopyTo srcPath destFolder + + call :pathResolve "%cd%" "%~2" destination + + if not exist "%~1" ( + call :logError "Failed to copy '%~1' to '%destination%' (source doesn't exist)." + exit /b 1 + ) + + :: Set environment variables for srcPath and destination + set "PS_SRCPATH=%~1" + set "PS_DESTINATION=%destination%" + + for /f "delims=" %%a in ('dir /b /a:d "%~1" 2^>nul') do ( + if "%%~a" == "%~nx1" ( + powershell -NoLogo -NoProfile -Command "New-Item -ItemType Directory -Force -Path $env:PS_DESTINATION; Copy-Item -Path $env:PS_SRCPATH -Destination $env:PS_DESTINATION -Recurse" + ) + ) + + for /f "delims=" %%a in ('dir /b /a:-d "%~1" 2^>nul') do ( + if "%%~a" == "%~nx1" ( + powershell -NoLogo -NoProfile -Command "New-Item -ItemType Directory -Force -Path (Split-Path -Parent $env:PS_DESTINATION); Copy-Item -Path $env:PS_SRCPATH -Destination $env:PS_DESTINATION -Force" + ) + ) + + :: Clean up environment variables + set "PS_SRCPATH=" + set "PS_DESTINATION=" + + :: Check if the copy operation succeeded + if %errorlevel% neq 0 ( + call :logError "Failed to copy '%~1' to '%destination%'." + exit /b 1 + ) + + call :logInformation "Copied '%~1' to '%destination%'." +exit /b 0 + + +:: Deletes a file or folder at the specified path (displays log messages) +:itemDelete targetPath + + call :pathResolve "%cd%" "%~1" target + + if not exist "%~1" ( + call :logWarning "Path '%target%' does not exist. Skipping deletion." + exit /b 0 + ) + + :: Set environment variables for target + set "PS_TARGET=%target%" + + for /f "delims=" %%a in ('dir /b /a:d "%~1" 2^>nul') do ( + if "%%~a" == "%~nx1" ( + powershell -NoLogo -NoProfile -Command "Remove-Item -Path $env:PS_TARGET -Recurse -Force" + ) + ) + + for /f "delims=" %%a in ('dir /b /a:-d "%~1" 2^>nul') do ( + if "%%~a" == "%~nx1" ( + powershell -NoLogo -NoProfile -Command "Remove-Item -Path $env:PS_TARGET -Force" + ) + ) + + :: Clean up environment variables + set "PS_TARGET=" + + :: Check if the deletion operation succeeded + if %errorlevel% neq 0 ( + call :logError "Failed to delete '%target%'." + exit /b 1 + ) + + call :logInformation "Deleted '%target%'." +exit /b 0 + +:: Generates the SHA256 hash of a file and stores it into a variable (displays log messages) +:fileGetHash filepath result + + :: Set environment variables for target + set "PS_FILEPATH=%~1" + + for /f "usebackq delims=" %%i in (`powershell -Command "(Get-FileHash -Path $env:PS_FILEPATH -Algorithm SHA256).Hash"`) do set "%~2=%%i" + + :: Clean up environment variables + set "PS_FILEPATH=" + + call :logInformation "Generated SHA256 hash of '%~1'." +exit /b 0 + +:: Extracts the contents of a zip file to the specified destination folder (displays log messages) +:fileExtract srcFile destFolder + + :: Set environment variables for target + set "PS_SRCFILE=%~1" + set "PS_DESTFOLDER=%~2" + + powershell -Command "if (!(Test-Path $env:PS_DESTFOLDER)) { New-Item -ItemType Directory -Path $env:PS_DESTFOLDER }" + powershell -Command "$ErrorActionPreference = 'Stop'; Expand-Archive -Path $env:PS_SRCFILE -DestinationPath $env:PS_DESTFOLDER" + + :: Clean up environment variables + set "PS_SRCFILE=" + set "PS_DESTFOLDER=" + + :: Check if the extraction operation succeeded + if %errorlevel% neq 0 ( + call :logError "Failed to extract contents of '%~1' to '%~2'." + exit /b 1 + ) + + call :logInformation "Extracted contents of '%~1' to '%~2'." +exit /b 0 + +:: Compresses the contents of a folder into a zip file (displays log messages) +:folderCompress srcFolder destFile + + :: Set environment variables for target + set "PS_SRCFOLDER=%~1" + set "PS_DESTFILE=%~2" + + powershell -Command "Compress-Archive -Path $env:PS_SRCFOLDER\* -DestinationPath $env:PS_DESTFILE -Force" + + :: Check if the compression operation succeeded + if %errorlevel% neq 0 ( + call :logError "Failed to compress contents of '%~1' into '%~2'." + exit /b 1 + ) + + :: Clean up environment variables + set "PS_SRCFOLDER=" + set "PS_DESTFILE=" + + call :logInformation "Compressed contents of '%~1' into '%~2'." +exit /b 0 + +:: Extracts a specified part of a version string and stores it into a variable (displays log messages) +:versionExtract version part result + :: Use PowerShell to extract the specified part of the version string + for /f "usebackq delims=" %%i in (`powershell -Command "$version = New-Object Version '%~1'; Write-Output $version.%~2"`) do set "%~3=%%i" + + :: Need to enabled delayed expansion + setlocal enabledelayedexpansion + call :logInformation "Extracted part %~2 of version '%~1' with value '!%~3%!'." + endlocal +exit /b 0 + +:: Compares two version numbers (major.minor.build.rev) and saves result into variable +:versionCompare version1 version2 result + for /f "tokens=* usebackq" %%F in (`powershell -NoLogo -NoProfile -Command ^([System.Version]'%~1'^).compareTo^([System.Version]'%~2'^)`) do ( set "%~3=%%F" ) + call :logInformation "Compared version '%~1' with version '%~2'." +exit /b 0 + +:: Check minimum required versions for STABLE|BETA|DEV releases +:versionLockCheck version stableVersion betaVersion devVersion ltsVersion + + call :versionExtract "%~1" Major majorVersion + call :versionExtract "%~1" Minor minorVersion + + set "runnerBuild=" + + if %minorVersion% equ 0 ( + :: LTS version + set "runnerBuild=LTS" + call :assertVersionRequired "%~1" "%~5" "The %%runnerBuild%% runtime version needs to be at least v%~5." + + ) else ( + if %majorVersion% geq 2020 ( + if %minorVersion% geq 100 ( + :: Beta version + set "runnerBuild=BETA" + call :assertVersionRequired "%~1" "%~3" "The %%runnerBuild%% runtime version needs to be at least v%~3." + ) else ( + :: Stable version + set "runnerBuild=STABLE" + call :assertVersionRequired "%~1" "%~2" "The %%runnerBuild%% runtime version needs to be at least v%~2." + ) + ) else ( + :: Dev version + set "runnerBuild=DEV" + call :assertVersionRequired "%~1" "%~4" "The %%runnerBuild%% runtime version needs to be at least v%~4." + ) + ) + + call :logInformation "Version lock check passed successfully, with %%runnerBuild%% version '%~1'." +exit /b 0 + +:: ASSERTS + +:: Asserts the SHA256 hash of a file, logs an error message and throws an error if they do not match (displays log messages) +:assertFileHashEquals filepath expected message + :: Generate hash + call :fileGetHash "%~1" actualHash + + :: Compare the actual hash with the expected hash + if not "%actualHash%" == "%~2" ( + call :logError "%~3" + exit /b 1 + ) + + :: Log a message + call :logInformation "Asserted SHA256 hash of '%~1' matches expected hash." +exit /b 0 + +:: Asserts that the given version string is greater than the expected version string, logs an error message and throws an error if not (displays log messages) +:assertVersionRequired version expected message + :: Compare the two version strings using :versionCompare + set "compareResult=" + call :versionCompare "%~1" "%~2" compareResult + + :: Check the result and log an error message and throw an error if not greater + if %compareResult% lss 0 ( + call :logError "%~3" + exit /b 1 + ) + + :: Log a message + call :logInformation "Asserted that version '%~1' is greater than or equal to version '%~2'." +exit /b 0 + +:: Asserts that the given version string is equal to the expected version string, logs an error message and throws an error if not (displays log messages) +:assertVersionEquals version expected message + :: Compare the two version strings using :versionCompare + set "compareResult=" + call :versionCompare "%~1" "%~2" compareResult + + :: Check the result and log an error message and throw an error if not equal + if %compareResult% neq 0 ( + call :logError "%~3" + exit /b 1 + ) + + :: Log a message + call :logInformation "Asserted that version '%~1' equals version '%~2'." +exit /b 0 + +:: LOGGING + +:: Logs information +:logInformation message + if %LOG_LEVEL% geq 2 call :log "INFO" "%~1" +exit /b 0 + +:: Logs warning +:logWarning message + if %LOG_LEVEL% geq 1 call :log "WARN" "%~1" +exit /b 0 + +:: Logs error +:logError message + if %LOG_LEVEL% geq 0 call :log "ERROR" "%~1" + exit 1 +exit /b 0 + +:: General log function +:log tag message + echo [%LOG_LABEL%] %~1: %~2 +exit /b 0 + + diff --git a/extensions/GooglePlayServices/scriptUtils.sh b/extensions/GooglePlayServices/scriptUtils.sh new file mode 100644 index 000000000..913d6eb5b --- /dev/null +++ b/extensions/GooglePlayServices/scriptUtils.sh @@ -0,0 +1,451 @@ +#!/bin/bash + +SCRIPT_PATH="$0" + +# Auxiliar Functions + +# Script initialization +# Usage: scriptInit +scriptInit() { + LOG_LABEL="UNSET" + LOG_LEVEL=-1 + EXTENSION_NAME= + + # Get extension data + pathExtractBase $SCRIPT_PATH EXTENSION_NAME + extensionGetVersion EXTENSION_VERSION + if [ -z "$EXTENSION_VERSION" ]; then + EXTENSION_VERSION="0.0.0" + fi + + # Setup logger + toUpper $EXTENSION_NAME LOG_LABEL + optionGetValue "logLevel" LOG_LEVEL + if [ -z "$LOG_LEVEL" ]; then + LOG_LEVEL=2 + fi + + # Check if the operation succeeded + if [ "$?" -ne 0 ]; then + log "INIT" "Script initialization failed (v$EXTENSION_VERSION :: $LOG_LEVEL)." + else + log "INIT" "Script initialization succeeded (v$EXTENSION_VERSION :: $LOG_LEVEL)." + fi +} + +# Gets the extension version value +# Usage: extensionGetVersion result +extensionGetVersion() { + # Enable indirect variable reference + set -f + local var="GMEXT_${EXTENSION_NAME}_version" + local result="${!var}" + set +f + + logInformation "Accessed extension version with value '${result}'." + eval "$1=\"\$result\"" +} + +# Gets an extension option value +# Usage: optionGetValue optionName result +optionGetValue() { + + # Enable indirect variable reference + set -f + local var="YYEXTOPT_${EXTENSION_NAME}_$1" + local result="${!var}" + set +f + + logInformation "Accessed extension option '${1}' with value '${result}'." + eval "$2=\"\$result\"" +} + +# Sets a string to uppercase +toUpper() { # str result + eval "$2=$(echo $1 | tr '[:lower:]' '[:upper:]')" + logInformation "Converted string '$1' to upper case." +} + +# Extracts the full folder path from a filepath +# Usage: pathExtractDirectory fullpath result +pathExtractDirectory() { + eval "$2=\"$(dirname "$1")\"" + logInformation "Extracted directory path from '$1'." +} + +# Extracts the parent folder from a path +# Usage: pathExtractBase fullpath result +pathExtractBase() { + eval "$2=\"$(basename $(dirname "$1"))\"" + logInformation "Extracted base name from '$1'." +} + +# Resolves a relative or absolute path to an absolute path +# Usage: pathResolve basePath relativePath result +pathResolve() { + local basePath="$1" + local relativePath="$2" + local resolvedPath= + + # Ensure 'basePath' ends with a forward slash + [[ "${basePath: -1}" != "/" ]] && basePath+="/" + + # If 'relativePath' starts with "/", set 'combined_path' to 'relativePath' + if [[ "${relativePath:0:1}" == "/" ]]; then + combined_path="$relativePath" + else + # Concatenate the paths + combined_path="$basePath$relativePath" + fi + + # Split the path into an array by the character "/" + IFS="/" read -ra path_parts <<< "$combined_path" + + # Remove any entries that are "." and if an entry is "..", remove that entry and the previous one + result=() + for part in "${path_parts[@]}"; do + if [ "$part" == "." ] || [ -z "$part" ]; then + continue + elif [ "$part" == ".." ]; then + unset result[${#result[@]}-1] + else + result+=("$part") + fi + done + + # Merge the final array using "/" as a delimiter + resolvedPath="/" + for i in "${!result[@]}"; do + resolvedPath+="${result[i]}" + if [ "$i" -lt $((${#result[@]}-1)) ]; then + resolvedPath+="/" + fi + done + + # Return the merged result + logInformation "Resolved path into '$resolvedPath'." + eval "$3=\"$resolvedPath\"" +} + +# Resolves an existing relative path if required (handles errors) +# Usage: pathResolveExisting basePath relativePath result +pathResolveExisting() { + local existingPath="" + pathResolve "$1" "$2" existingPath + + # Check if the path is valid + if [ ! -e "$existingPath" ]; then + logError "Path '$existingPath' does not exist or is not accessible." + fi + + eval "$3=\"$existingPath\"" +} + +# Copies a file or folder to the specified destination folder +# Usage: itemCopyTo srcPath destFolder +itemCopyTo() { + local source="$1" + local destination="$2" + local resolved_destination="" + + # Resolve the destination folder to an absolute path + pathResolve "$PWD" "$destination" resolved_destination + + # If 'resolved_destination' ends with a "/", ensure the path exists + if [[ "${resolved_destination: -1}" == "/" ]]; then + mkdir -p "$resolved_destination" + else + # Create all parent directories up until the destination path + parent_directory=$(dirname "$resolved_destination") + mkdir -p "$parent_directory" + fi + + if [ -d "$source" ]; then + # Source is a folder + cp -rf "$source" "$resolved_destination" + elif [ -f "$source" ]; then + # Source is a file + cp -f "$source" "$resolved_destination" + else + logError "Failed to copy '$source' does not exist or is not accessible." + exit 1 + fi + + if [ $? -ne 0 ]; then + logError "Failed to copy '$source' to '$resolved_destination'." + exit 1 + fi + + logInformation "Copied '$source' to '$resolved_destination'." +} + +# Deletes a file or folder given a path +# Usage: itemDelete folderPath +itemDelete() { + target_path="$1" + + if [ -d "$target_path" ]; then + # Is a folder + rm -rf "$target_path" + elif [ -f "$target_path" ]; then + # Is a file + rm -f "$target_path" + else + logWarning "Path '$target_path' does not exist. Skipping deletion." + return 0 + fi + + if [ $? -ne 0 ]; then + logError "Failed to delete '$target_path'." + return 1 + fi + + logInformation "Deleted '$target_path'." + return 0 +} + +# Generates the SHA256 hash of a file and stores it into a variable +# Usage: fileGetHash filepath result +fileGetHash() { + local file="$1" + local hash="" + + if [ ! -f "$file" ]; then + logError "Failed to generate hash for '$file' does not exist or is not a file." + exit 1 + fi + + hash=$(shasum -a 256 "$file" | awk '{print $1}') + + if [ $? -ne 0 ]; then + logError "Failed to generate hash for '$file'." + exit 1 + fi + + toUpper "$hash" hash + + eval "$2=\"$hash\"" + logInformation "Generated SHA256 hash of '$file'." +} + +# Extracts the contents of a zip file to the specified destination folder +# Usage: fileExtract srcFile destFolder +fileExtract() { + local source="$1" + local destination="$2" + + # Create the destination folder if it doesn't exist + mkdir -p "$destination" + + # Extract the zip file to the destination folder + unzip -q "$source" -d "$destination" + + if [ $? -ne 0 ]; then + logError "Failed to extract contents of '$source' to '$destination'." + exit 1 + fi + + logInformation "Extracted contents of '$source' to '$destination'." +} + +# Compresses the contents of a folder into a zip file +# Usage: folderCompress srcFolder destFile +folderCompress() { + local source="$1" + local destination="$2" + + # Compress the contents of the folder to the destination file + zip -j -r -q "$destination" "$source" + + if [ $? -ne 0 ]; then + logError "Failed to compress contents of '$source' into '$destination'." + exit 1 + fi + + logInformation "Compressed contents of '$source' into '$destination'." +} + +# Extracts a specified part of a version string and stores it into a variable +# Usage: versionExtract version part result +versionExtract() { + local version="$1" + local part="$2" + + # Use awk to extract the specified part of the version string + local result="$(echo "$version" | awk -F '.' "{print \$$part}")" + + # Store the result in the specified variable + eval "$3=\"$result\"" + + # Display a log message + logInformation "Extracted part $part of version '$version' with value '$result'." +} + +# Compares two version numbers (w.x.y.z) and saves result into variable +# Usage: versionCompare version1 version2 result +versionCompare() { + local version1="$1" + local version2="$2" + + # Use awk to split the version numbers into components + local version1_parts=($(echo "$version1" | awk -F '.' '{print $1,$2,$3,$4}')) + local version2_parts=($(echo "$version2" | awk -F '.' '{print $1,$2,$3,$4}')) + + # Compare the components of the version numbers + for i in {0..3}; do + if [ "${version1_parts[$i]}" -lt "${version2_parts[$i]}" ]; then + result=-1 + break + elif [ "${version1_parts[$i]}" -gt "${version2_parts[$i]}" ]; then + result=1 + break + else + result=0 + fi + done + + # Store the result in the specified variable + eval "$3=\"$result\"" + + # Display a log message + logInformation "Compared version '$version1' with version '$version2'." +} + +# Check minimum required versions for STABLE|BETA|DEV releases +# Usage: versionLockCheck version stableVersion betaVersion devVersion +versionLockCheck() { + local version="$1" + local stableVersion="$2" + local betaVersion="$3" + local devVersion="$4" + local ltsVersion="$5" + + # Extract the major and minor version numbers from the given version + local runnerBuild= + local majorVersion= + local minorVersion= + versionExtract "$version" 1 majorVersion + versionExtract "$version" 2 minorVersion + + if [ "$minorVersion" -eq 0 ]; then + # LTS version + runnerBuild=LTS + assertVersionRequired "$version" "$ltsVersion" "The $runnerBuild runtime version needs to be at least v$ltsVersion." + + elif [ "$majorVersion" -ge 2020 ]; then + if [ "$minorVersion" -ge 100 ]; then + # Beta version + runnerBuild=BETA + assertVersionRequired "$version" "$betaVersion" "The $runnerBuild runtime version needs to be at least v$betaVersion." + else + # Stable version + runnerBuild=STABLE + assertVersionRequired "$version" "$stableVersion" "The $runnerBuild runtime version needs to be at least v$stableVersion." + fi + else + # Dev version + runnerBuild=DEV + assertVersionRequired "$version" "$devVersion" "The $runnerBuild runtime version needs to be at least v$devVersion." + fi + + logInformation "Version lock check passed successfully, with version '$version'." +} + +# ASSERTS + +# Asserts the SHA256 hash of a file, logs an error message and throws an error if they do not match +# Usage: assertFileHashEquals filepath expected message +assertFileHashEquals() { + local filepath="$1" + local expected="$2" + local message="$3" + + # Generate hash + local actualHash= + fileGetHash "$filepath" actualHash + + # Compare the actual hash with the expected hash + if [ "$actualHash" != "$expected" ]; then + logError "$message" + exit 1 + fi + + # Log a message + logInformation "Asserted SHA256 hash of '$filepath' matches expected hash." +} + +# Asserts that the given version string is greater than the expected version string, logs an error message and throws an error if not +# Usage: assertVersionRequired version expected message +assertVersionRequired() { + local version="$1" + local expected="$2" + local message="$3" + + # Compare the two version strings using versionCompare + local compareResult= + versionCompare "$version" "$expected" compareResult + + # Check the result and log an error message and throw an error if not greater + if [ "$compareResult" -lt 0 ]; then + logError "$message" + exit 1 + fi + + # Log a message + logInformation "Asserted that version '$version' is greater than or equal to version '$expected'." +} + +# Asserts that the given version string is equal to the expected version string, logs an error message and throws an error if not +# Usage: assertVersionEquals version expected message +assertVersionEquals() { + local version="$1" + local expected="$2" + local message="$3" + + # Compare the two version strings using versionCompare + local compareResult= + versionCompare "$version" "$expected" compareResult + + # Check the result and log an error message and throw an error if not equal + if [ "$compareResult" -ne 0 ]; then + logError "$message" + exit 1 + fi + + # Log a message + logInformation "Asserted that version '$version' equals version '$expected'." +} + +# Logging + +# Logs information +# Usage: logInformation message +logInformation() { + if [ "$LOG_LEVEL" -ge 2 ]; then + log "INFO" "$1" + fi +} + +# Logs warning +# Usage: logWarning message +logWarning() { + if [ "$LOG_LEVEL" -ge 1 ]; then + log "WARN" "$1" + fi +} + +# Logs error +# Usage: logError message +logError() { + if [ "$LOG_LEVEL" -ge 0 ]; then + log "ERROR" "$1" + fi + exit 1 +} + +# General log function +# Usage: log tag message +log() { + echo "[$LOG_LABEL] $1: $2" +} + diff --git a/extensions/Steamworks/Steamworks.so b/extensions/Steamworks/Steamworks.so index 61c30bccf..d3299d2fe 100644 Binary files a/extensions/Steamworks/Steamworks.so and b/extensions/Steamworks/Steamworks.so differ diff --git a/extensions/Steamworks/Steamworks.yy b/extensions/Steamworks/Steamworks.yy index cb97aa9fd..a6260e362 100644 --- a/extensions/Steamworks/Steamworks.yy +++ b/extensions/Steamworks/Steamworks.yy @@ -15,7 +15,7 @@ "copyToTargets":194, "description":"", "exportToGame":true, - "extensionVersion":"1.6.7", + "extensionVersion":"1.6.9", "files":[ {"$GMExtensionFile":"","%Name":"Steamworks.ext","constants":[ {"$GMExtensionConstant":"","%Name":"ov_friends","hidden":false,"name":"ov_friends","resourceType":"GMExtensionConstant","resourceVersion":"2.0","value":"0",}, @@ -253,6 +253,7 @@ {"$GMExtensionConstant":"","%Name":"steam_music_playback_playing","hidden":false,"name":"steam_music_playback_playing","resourceType":"GMExtensionConstant","resourceVersion":"2.0","value":"1",}, {"$GMExtensionConstant":"","%Name":"steam_music_playback_paused","hidden":false,"name":"steam_music_playback_paused","resourceType":"GMExtensionConstant","resourceVersion":"2.0","value":"2",}, {"$GMExtensionConstant":"","%Name":"steam_music_playback_idle","hidden":false,"name":"steam_music_playback_idle","resourceType":"GMExtensionConstant","resourceVersion":"2.0","value":"3",}, + {"$GMExtensionConstant":"","%Name":"steam_item_instance_id_invalid","hidden":false,"name":"steam_item_instance_id_invalid","resourceType":"GMExtensionConstant","resourceVersion":"2.0","value":"0xFFFFFFFFFFFFFFFF",}, ],"copyToTargets":194,"filename":"Steamworks.ext","final":"","functions":[ {"$GMExtensionFunction":"","%Name":"steam_user_owns_dlc","argCount":1,"args":[2,],"documentation":"/// @param {Int64} dlc_id The unique identifier for the DLC to be checked.\n/// @returns {Real}","externalName":"steam_user_owns_dlc","help":"steam_user_owns_dlc(dlc_id)","hidden":false,"kind":11,"name":"steam_user_owns_dlc","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, {"$GMExtensionFunction":"","%Name":"steam_user_installed_dlc","argCount":1,"args":[2,],"documentation":"/// @param {Int64} dlc_id The unique identifier for the DLC to be checked.\n/// @returns {Bool}","externalName":"steam_user_installed_dlc","help":"steam_user_installed_dlc(dlc_id)","hidden":false,"kind":11,"name":"steam_user_installed_dlc","resourceType":"GMExtensionFunction","resourceVersion":"2.0","returnType":2,}, diff --git a/extensions/Steamworks/Steamworks_x64.dll b/extensions/Steamworks/Steamworks_x64.dll index 2664f6fb8..e9ba7ca48 100644 Binary files a/extensions/Steamworks/Steamworks_x64.dll and b/extensions/Steamworks/Steamworks_x64.dll differ diff --git a/extensions/Steamworks/docs/index.html b/extensions/Steamworks/docs/index.html index 142e383a0..b7fdda4c5 100644 --- a/extensions/Steamworks/docs/index.html +++ b/extensions/Steamworks/docs/index.html @@ -194,5 +194,5 @@

Project layout

diff --git a/extensions/Steamworks/docs/inventory.html b/extensions/Steamworks/docs/inventory.html index c408a2313..02b4af6da 100644 --- a/extensions/Steamworks/docs/inventory.html +++ b/extensions/Steamworks/docs/inventory.html @@ -766,6 +766,11 @@

steam_inventory_add_promo_items

steam_inventory_exchange_items

This function grants one item in exchange for a set of other items.

+

The API currently takes an array of items to generate but at this time the size of that array must be 1 and the quantity of the new item must be 1.

+
+

Note

+

Any items that can be granted MUST have an exchange attribute in their itemdef.

+

Warning

You must call steam_inventory_result_destroy on the returned async result ID when you are done with it.

@@ -792,7 +797,7 @@

steam_inventory_exchange_items

create_arr Array of InventoryItemCreationData -An array of structs representing items to be created +An array of structs representing items to be created (must be of size 1 and the item quantity must also be 1) destroy_arr @@ -851,7 +856,6 @@

steam_inventory_exchange_items

var _arrayCreate = [ { item_def: global.holy_sword, quantity: 1 }, - { item_def: global.orange, quantity: 2 } ]; steam_inventory_exchange_items(_arrayCreate, _arrayDestroy); @@ -1278,7 +1282,8 @@

steam_inventory_submit_update_

Back To Top

steam_inventory_transfer_item_quantity

-

This function transfers items between stacks within a user's inventory.

+

Transfer items between stacks within a user's inventory.

+

This can be used to stack, split, and moving items. The source and destination items must have the same itemdef id. To move items onto a destination stack specify the source, the quantity to move, and the destination item id. To split an existing stack, pass steam_item_instance_id_invalid into dest_item_id. A new item stack will be generated with the requested quantity.

Warning

You must call steam_inventory_result_destroy on the returned async result ID when you are done with it.

@@ -1315,7 +1320,7 @@

steam_inventory_transfer_item_qu dest_item_id Int64 -The destination steam_inventory_item_id to transfer to +The destination steam_inventory_item_id to transfer to or steam_item_instance_id_invalid to create a new stack @@ -1362,8 +1367,8 @@

steam_inventory_transfer_item_qu


Example:

-

handle = steam_inventory_transfer_item_quantity(global.apple, 2, global.oranges);
-The above code will trigger a transfer between two items owned by the user the amount to be transferred in the example, the user will lose 2 apples and receive 2 oranges. For an example on how to use the Steam Async Event to read the callback response, refer to the function steam_inventory_get_all_items.

+

handle = steam_inventory_transfer_item_quantity(global.apples[0], 2, global.apples[1]);
+The above code will trigger a transfer between two item stacks owned by the user the amount to be transferred in the example, this will move 2 apples from stack 0 to stack 1. For an example on how to use the Steam Async Event to read the callback response, refer to the function steam_inventory_get_all_items.




diff --git a/extensions/Steamworks/docs/sitemap.xml.gz b/extensions/Steamworks/docs/sitemap.xml.gz index bd5a0820f..b3c04d0f5 100644 Binary files a/extensions/Steamworks/docs/sitemap.xml.gz and b/extensions/Steamworks/docs/sitemap.xml.gz differ diff --git a/extensions/Steamworks/libSteamworks.dylib b/extensions/Steamworks/libSteamworks.dylib index 4263ae310..1a982b3d9 100644 Binary files a/extensions/Steamworks/libSteamworks.dylib and b/extensions/Steamworks/libSteamworks.dylib differ diff --git a/extensions/Steamworks/steamworks_cpp/GMLSteam/steam_inventory.cpp b/extensions/Steamworks/steamworks_cpp/GMLSteam/steam_inventory.cpp index 57ae16612..94400b644 100644 --- a/extensions/Steamworks/steamworks_cpp/GMLSteam/steam_inventory.cpp +++ b/extensions/Steamworks/steamworks_cpp/GMLSteam/steam_inventory.cpp @@ -261,7 +261,7 @@ vector argToSteam_inventory_itemid_w_quantity for (int i = 0; GET_RValue(&elem, pV, NULL, i); ++i) { steam_inventory_itemid_w_quantity* _struct = new steam_inventory_itemid_w_quantity();// {0}; - _struct->item_id = static_cast(YYStructGetMember(&elem, "item_id")->val); + _struct->item_id = static_cast(YYStructGetMember(&elem, "item_id")->v64); _struct->quantity = static_cast(YYStructGetMember(&elem, "quantity")->val); items.push_back(*_struct); @@ -278,8 +278,8 @@ vector argToSteam_inventory_itemid_w_quantity YYEXPORT void /*SteamInventoryResult_t*/ steam_inventory_exchange_items(RValue& Result, CInstance* selfinst, CInstance* otherinst, int argc, RValue* arg)//(vector create, vector< steam_inventory_itemid_w_quantity> destroy) { - vector create = argToSteam_inventory_itemdef_w_quantity(arg, 0); - vector destroy = argToSteam_inventory_itemid_w_quantity(arg, 1); + const vector& create = argToSteam_inventory_itemdef_w_quantity(arg, 0); + const vector& destroy = argToSteam_inventory_itemid_w_quantity(arg, 1); vector create_defs; create_defs.resize(create.size()); vector create_quantities; create_quantities.resize(create.size()); diff --git a/extensions/Steamworks/steamworks_windows/Steamworks/Steamworks.vcxproj b/extensions/Steamworks/steamworks_windows/Steamworks/Steamworks.vcxproj deleted file mode 100644 index 9ff773605..000000000 --- a/extensions/Steamworks/steamworks_windows/Steamworks/Steamworks.vcxproj +++ /dev/null @@ -1,232 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 16.0 - Win32Proj - {52f43e45-315c-4145-a717-ced98e7302d4} - Steamworks - 10.0 - - - - DynamicLibrary - true - v143 - Unicode - - - DynamicLibrary - false - v143 - true - Unicode - - - DynamicLibrary - true - v143 - Unicode - - - DynamicLibrary - false - v143 - true - Unicode - - - - - - - - - - - - - - - - - - - - - true - $(ProjectName) - ..\..\Steamworks_gml\extensions\Steamworks\ - - - false - ..\..\Steamworks_gml\extensions\Steamworks\ - - - true - $(SolutionDir)$(Platform)\$(Configuration)\ - $(ProjectName)_x64 - - - false - $(SolutionDir)$(Platform)\$(Configuration)\ - $(ProjectName)_x64 - - - - Level3 - true - OS_Windows;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;STEAMWORKS_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - NotUsing - pch.h - ..\..\steamworks_sdk\public\steam\;.\;.\GMLSteam\;..\..\json-c-0.9 - stdcpp17 - - - Windows - true - false - ..\..\steamworks_sdk\redistributable_bin\;%(AdditionalLibraryDirectories) - steam_api.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - $(OutDir)$(TargetName)$(TargetExt) - - - - - Level3 - true - true - true - OS_Windows;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;STEAMWORKS_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - NotUsing - pch.h - stdcpp17 - ..\..\steamworks_sdk\public\steam\;.\;.\GMLSteam\;..\..\json-c-0.9 - MultiThreaded - - - Windows - true - true - true - false - ..\..\steamworks_sdk\redistributable_bin\; - steam_api.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - - - - Level3 - true - OS_Windows;_CRT_SECURE_NO_WARNINGS;_DEBUG;STEAMWORKS_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - NotUsing - pch.h - $(SolutionDir)..\..\..\..\steamworks_sdk\public\steam\;.\;$(SolutionDir)..\steamworks_cpp\;$(SolutionDir)..\steamworks_cpp\GMLSteam - stdcpp17 - - - Windows - true - false - steam_api64.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - $(SolutionDir)..\..\..\..\steamworks_sdk\redistributable_bin\win64\; - - - xcopy /Y "$(TargetPath)" "$(ProjectDir)..\..\$(TargetFileName)" - - - - - Level3 - true - true - true - OS_Windows;_CRT_SECURE_NO_WARNINGS;NDEBUG;STEAMWORKS_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - NotUsing - pch.h - $(SolutionDir)..\..\..\..\steamworks_sdk\public\steam\;.\;$(SolutionDir)..\steamworks_cpp\;$(SolutionDir)..\steamworks_cpp\GMLSteam - stdcpp17 - MultiThreaded - - - Windows - true - true - true - false - steam_api64.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - $(SolutionDir)..\..\..\..\steamworks_sdk\redistributable_bin\win64\; - - - xcopy /Y "$(TargetPath)" "$(ProjectDir)..\..\$(TargetFileName)" - - - - - - \ No newline at end of file diff --git a/extensions/Steamworks/steamworks_windows/Steamworks/Steamworks.vcxproj.filters b/extensions/Steamworks/steamworks_windows/Steamworks/Steamworks.vcxproj.filters deleted file mode 100644 index 261b09a94..000000000 --- a/extensions/Steamworks/steamworks_windows/Steamworks/Steamworks.vcxproj.filters +++ /dev/null @@ -1,135 +0,0 @@ - - - - - {406c4a65-5e89-497a-a3c0-0fabfeb2d87e} - - - {56b9c76c-a8f7-4e15-b4fd-df0c05b2f805} - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Header Files - - - Header Files - - - Header Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - \ No newline at end of file diff --git a/objects/o_asteroidsplusplusad/Draw_0.gml b/objects/o_asteroidsplusplusad/Draw_0.gml deleted file mode 100644 index b827108a9..000000000 --- a/objects/o_asteroidsplusplusad/Draw_0.gml +++ /dev/null @@ -1,3 +0,0 @@ -draw_self() -//draw_set_font(fnt_multiplayerfont) -//draw_text(x+25,y-20,"NEW GAMES IN\nDEVELOPMENT") \ No newline at end of file diff --git a/objects/o_asteroidsplusplusad/Mouse_10.gml b/objects/o_asteroidsplusplusad/Mouse_10.gml deleted file mode 100644 index c38abd095..000000000 --- a/objects/o_asteroidsplusplusad/Mouse_10.gml +++ /dev/null @@ -1 +0,0 @@ -window_set_cursor(cr_handpoint) \ No newline at end of file diff --git a/objects/o_asteroidsplusplusad/Mouse_11.gml b/objects/o_asteroidsplusplusad/Mouse_11.gml deleted file mode 100644 index 7407a6507..000000000 --- a/objects/o_asteroidsplusplusad/Mouse_11.gml +++ /dev/null @@ -1 +0,0 @@ -window_set_cursor(cr_default) \ No newline at end of file diff --git a/objects/o_asteroidsplusplusad/Mouse_4.gml b/objects/o_asteroidsplusplusad/Mouse_4.gml deleted file mode 100644 index 4f1711937..000000000 --- a/objects/o_asteroidsplusplusad/Mouse_4.gml +++ /dev/null @@ -1,11 +0,0 @@ -if instance_exists(o_progressask) { exit } - -if os_is_network_connected() { -window_set_cursor(cr_default) -var popup = instance_create(x,y,o_webask) -with popup { -url = "https://store.steampowered.com/app/2407300/Asteroids/" -} -} else { -show_message(loc(646)) -} \ No newline at end of file diff --git a/objects/o_infilandgamead/Create_0.gml b/objects/o_infilandgamead/Create_0.gml new file mode 100644 index 000000000..186f8c477 --- /dev/null +++ b/objects/o_infilandgamead/Create_0.gml @@ -0,0 +1,12 @@ +maxGames = 3 +game = irandom(maxGames)+1 +image_xscale = 0.7 +image_yscale = 0.7 +link = "" +timerRotation = 300 +timer = timerRotation +gameChanged = 0 + +if global.noadsinmenusettings = 1 { + instance_destroy() +} \ No newline at end of file diff --git a/objects/o_infilandgamead/Draw_0.gml b/objects/o_infilandgamead/Draw_0.gml new file mode 100644 index 000000000..85581da24 --- /dev/null +++ b/objects/o_infilandgamead/Draw_0.gml @@ -0,0 +1,17 @@ +image_index = game - 1 + +switch(image_index) { +default: //Asteroids ++ +link = "https://store.steampowered.com/app/2407300/Asteroids/" +break; +case(1): //Monophobia Echoes +link = "https://infiland.itch.io/monophobia-echoes" +break; +case(2): //Brik Brik +link = "https://play.google.com/store/apps/details?id=com.infiland.brikbrik" +break; +} + +draw_self() +//draw_set_font(fnt_multiplayerfont) +//draw_text(x+25,y-20,"NEW GAMES IN\nDEVELOPMENT") \ No newline at end of file diff --git a/objects/o_infilandgamead/Mouse_10.gml b/objects/o_infilandgamead/Mouse_10.gml new file mode 100644 index 000000000..6ce07c3ce --- /dev/null +++ b/objects/o_infilandgamead/Mouse_10.gml @@ -0,0 +1,3 @@ +window_set_cursor(cr_handpoint) +image_xscale = 0.72 +image_yscale = 0.72 \ No newline at end of file diff --git a/objects/o_infilandgamead/Mouse_11.gml b/objects/o_infilandgamead/Mouse_11.gml new file mode 100644 index 000000000..143e9be67 --- /dev/null +++ b/objects/o_infilandgamead/Mouse_11.gml @@ -0,0 +1,3 @@ +window_set_cursor(cr_default) +image_xscale = 0.7 +image_yscale = 0.7 \ No newline at end of file diff --git a/objects/o_monophobiaechoesad/Mouse_4.gml b/objects/o_infilandgamead/Mouse_4.gml similarity index 78% rename from objects/o_monophobiaechoesad/Mouse_4.gml rename to objects/o_infilandgamead/Mouse_4.gml index e8ca7df34..2a15ad81b 100644 --- a/objects/o_monophobiaechoesad/Mouse_4.gml +++ b/objects/o_infilandgamead/Mouse_4.gml @@ -2,9 +2,10 @@ if instance_exists(o_progressask) { exit } if os_is_network_connected() { window_set_cursor(cr_default) +var lnk = link var popup = instance_create(x,y,o_webask) with popup { -url = "https://infiland.itch.io/monophobia-echoes" +url = lnk } } else { show_message(loc(646)) diff --git a/objects/o_infilandgamead/Step_0.gml b/objects/o_infilandgamead/Step_0.gml new file mode 100644 index 000000000..0821f2133 --- /dev/null +++ b/objects/o_infilandgamead/Step_0.gml @@ -0,0 +1,24 @@ +timer -= 1 + +if timer <= 0 { + if gameChanged = 0 { + y += 5 + } else { + y -= 5 + if y < 638 { + timer = timerRotation + y = 638 + gameChanged = 0 + } + } +} + +if y > 768 { +if gameChanged = 0 { +game += 1 +if game > maxGames { + game = 0 +}} +gameChanged = 1 +} +/* diff --git a/objects/o_asteroidsplusplusad/o_asteroidsplusplusad.yy b/objects/o_infilandgamead/o_infilandgamead.yy similarity index 70% rename from objects/o_asteroidsplusplusad/o_asteroidsplusplusad.yy rename to objects/o_infilandgamead/o_infilandgamead.yy index cc087a4fc..b3f7d8d29 100644 --- a/objects/o_asteroidsplusplusad/o_asteroidsplusplusad.yy +++ b/objects/o_infilandgamead/o_infilandgamead.yy @@ -1,18 +1,20 @@ { "$GMObject":"", - "%Name":"o_asteroidsplusplusad", + "%Name":"o_infilandgamead", "eventList":[ {"$GMEvent":"","%Name":"","collisionObjectId":null,"eventNum":0,"eventType":8,"isDnD":false,"name":"","resourceType":"GMEvent","resourceVersion":"2.0",}, {"$GMEvent":"","%Name":"","collisionObjectId":null,"eventNum":10,"eventType":6,"isDnD":false,"name":"","resourceType":"GMEvent","resourceVersion":"2.0",}, {"$GMEvent":"","%Name":"","collisionObjectId":null,"eventNum":11,"eventType":6,"isDnD":false,"name":"","resourceType":"GMEvent","resourceVersion":"2.0",}, {"$GMEvent":"","%Name":"","collisionObjectId":null,"eventNum":4,"eventType":6,"isDnD":false,"name":"","resourceType":"GMEvent","resourceVersion":"2.0",}, + {"$GMEvent":"","%Name":"","collisionObjectId":null,"eventNum":0,"eventType":0,"isDnD":false,"name":"","resourceType":"GMEvent","resourceVersion":"2.0",}, + {"$GMEvent":"","%Name":"","collisionObjectId":null,"eventNum":0,"eventType":3,"isDnD":false,"name":"","resourceType":"GMEvent","resourceVersion":"2.0",}, ], "managed":true, - "name":"o_asteroidsplusplusad", + "name":"o_infilandgamead", "overriddenProperties":[], "parent":{ - "name":"New Games", - "path":"folders/Objects/Mainmenu/New Games.yy", + "name":"Mainmenu", + "path":"folders/Objects/Mainmenu.yy", }, "parentObjectId":null, "persistent":false, @@ -33,8 +35,8 @@ "resourceVersion":"2.0", "solid":false, "spriteId":{ - "name":"s_asteroidsplusplusad", - "path":"sprites/s_asteroidsplusplusad/s_asteroidsplusplusad.yy", + "name":"s_infilandgamead", + "path":"sprites/s_infilandgamead/s_infilandgamead.yy", }, "spriteMaskId":null, "visible":true, diff --git a/objects/o_monophobiaechoesad/Draw_0.gml b/objects/o_monophobiaechoesad/Draw_0.gml deleted file mode 100644 index 877c9b4f1..000000000 --- a/objects/o_monophobiaechoesad/Draw_0.gml +++ /dev/null @@ -1,3 +0,0 @@ -draw_self() -draw_set_font(fnt_multiplayerfont) -draw_text(x+25,y-20,"NEW GAMES IN DEVELOPMENT") \ No newline at end of file diff --git a/objects/o_monophobiaechoesad/Mouse_10.gml b/objects/o_monophobiaechoesad/Mouse_10.gml deleted file mode 100644 index c38abd095..000000000 --- a/objects/o_monophobiaechoesad/Mouse_10.gml +++ /dev/null @@ -1 +0,0 @@ -window_set_cursor(cr_handpoint) \ No newline at end of file diff --git a/objects/o_monophobiaechoesad/Mouse_11.gml b/objects/o_monophobiaechoesad/Mouse_11.gml deleted file mode 100644 index 7407a6507..000000000 --- a/objects/o_monophobiaechoesad/Mouse_11.gml +++ /dev/null @@ -1 +0,0 @@ -window_set_cursor(cr_default) \ No newline at end of file diff --git a/objects/o_newsbanner/Create_0.gml b/objects/o_newsbanner/Create_0.gml index 8dec7b575..ac1c40443 100644 --- a/objects/o_newsbanner/Create_0.gml +++ b/objects/o_newsbanner/Create_0.gml @@ -1,7 +1,7 @@ y = -600 image_alpha = 0 depth = -15001 -req = 18 //Change this so that news can appear +req = 19 //Change this so that news can appear newsText = string_upper(loc(618)) //text = "New Level Editor has been released! The UI was updated to make it easy for people to make levels. You can now make levels much more quickly, the UI makes more sense, and this was in development during February and March. This is still in 'Beta' so please give us feedback in the official discord server.\n\nHave fun!" @@ -19,8 +19,8 @@ newsText = string_upper(loc(618)) //text = "Release 1.1.7 is here! Added partial Czech, Portuguese and Slovenian! Improvements to Calendar! Code Refactored all of the skins, hats and items in the game! Well, you might not even know what that means but whatever!\n\nHave fun!" //text = "The FREEDOM UPDATE! The game is now open sourced! You can now help develop the game, ensuring a longlasting life of this game. I have many things to talk about, so please read the 'News' on this. If you want to contribute, click the 'Help Development' or 'Feedback' buttons to get started.\n\nThank you!" //text = "Release 1.1.8 is here! Added quests and 40 OF THEM!! You can now earn credits by completing quests, each day you have 3 random quests to beat. Along with the update come general improvements.\n\nHave fun!" -text = "Release 1.1.9 introduces the TCC Economy! You can now recieve drops by actively playing the game, then you can trade with other players and sell those items!\n\nAlso, added [rainbow][wave]SKIN MASTERIES[/] so you can truly show your bling!\n\nHave fun!" -//text = "What's better than a soundtrack? [rainbow][wave]A SUPER SOUNDTRACK![/]\n\nThe difference? It includes all .flp files so you can remix songs, it also has unused songs and sound effects!\n\nAnd finally, you get a [s_badgesmenu,15] Isn't that cute?" +//text = "Release 1.1.9 introduces the TCC Economy! You can now recieve drops by actively playing the game, then you can trade with other players and sell those items!\n\nAlso, added [rainbow][wave]SKIN MASTERIES[/] so you can truly show your bling!\n\nHave fun!" +text = "What's better than a soundtrack? [rainbow][wave]A SUPER SOUNDTRACK![/]\n\nThe difference? It includes all .flp files so you can remix songs, it also has unused songs and sound effects!\n\nAnd finally, you get a [s_badgesmenu,15] Isn't that cute?" if global.moddedGameDir != "" { text = "You are running a modded client! Save files will not be confilcted with the modded game. Have fun!\n\n[c_yellow]Mod Name: " + string(global.moddedGameDir) diff --git a/objects/o_noadsinmenusettings/Create_0.gml b/objects/o_noadsinmenusettings/Create_0.gml new file mode 100644 index 000000000..fb1f39347 --- /dev/null +++ b/objects/o_noadsinmenusettings/Create_0.gml @@ -0,0 +1 @@ +depth = -1000000000 \ No newline at end of file diff --git a/objects/o_noadsinmenusettings/Draw_73.gml b/objects/o_noadsinmenusettings/Draw_73.gml new file mode 100644 index 000000000..dfc4841f4 --- /dev/null +++ b/objects/o_noadsinmenusettings/Draw_73.gml @@ -0,0 +1 @@ +draw_self() \ No newline at end of file diff --git a/objects/o_noadsinmenusettings/Mouse_10.gml b/objects/o_noadsinmenusettings/Mouse_10.gml new file mode 100644 index 000000000..bae57f4ea --- /dev/null +++ b/objects/o_noadsinmenusettings/Mouse_10.gml @@ -0,0 +1,3 @@ +global.infosettings = 0 +image_xscale = 1.02 +image_yscale = 1.02 \ No newline at end of file diff --git a/objects/o_noadsinmenusettings/Mouse_11.gml b/objects/o_noadsinmenusettings/Mouse_11.gml new file mode 100644 index 000000000..9dcabf3b7 --- /dev/null +++ b/objects/o_noadsinmenusettings/Mouse_11.gml @@ -0,0 +1,3 @@ +image_xscale = 1 +image_yscale = 1 +global.infosettings = 0 \ No newline at end of file diff --git a/objects/o_noadsinmenusettings/Mouse_4.gml b/objects/o_noadsinmenusettings/Mouse_4.gml new file mode 100644 index 000000000..11c4acedd --- /dev/null +++ b/objects/o_noadsinmenusettings/Mouse_4.gml @@ -0,0 +1,5 @@ +if global.choosesettings != 0 { exit } + +if global.noadsinmenusettings = 1 { global.noadsinmenusettings = 0 } +else { global.noadsinmenusettings = 1 + } \ No newline at end of file diff --git a/objects/o_noadsinmenusettings/Step_0.gml b/objects/o_noadsinmenusettings/Step_0.gml new file mode 100644 index 000000000..a254f8029 --- /dev/null +++ b/objects/o_noadsinmenusettings/Step_0.gml @@ -0,0 +1,4 @@ +event_inherited() +image_index = global.noadsinmenusettings +if global.choosesettings != 0 { x = lerp(x,camera_get_view_x(view_camera[0])-256,0.2 * (60 / global.maxfps)) } +if global.choosesettings = 0 { x = lerp(x,camera_get_view_x(view_camera[0])+544,0.2 * (60 / global.maxfps)) } \ No newline at end of file diff --git a/objects/o_noadsinmenusettings/o_gunvisibilitysettings.yy b/objects/o_noadsinmenusettings/o_gunvisibilitysettings.yy new file mode 100644 index 000000000..d7451a519 --- /dev/null +++ b/objects/o_noadsinmenusettings/o_gunvisibilitysettings.yy @@ -0,0 +1,44 @@ +{ + "spriteId": { + "name": "s_gunvisibilitysettings", + "path": "sprites/s_gunvisibilitysettings/s_gunvisibilitysettings.yy", + }, + "solid": false, + "visible": true, + "spriteMaskId": null, + "persistent": false, + "parentObjectId": null, + "physicsObject": false, + "physicsSensor": false, + "physicsShape": 1, + "physicsGroup": 0, + "physicsDensity": 0.5, + "physicsRestitution": 0.1, + "physicsLinearDamping": 0.1, + "physicsAngularDamping": 0.1, + "physicsFriction": 0.2, + "physicsStartAwake": true, + "physicsKinematic": false, + "physicsShapePoints": [ + {"x":0.0,"y":0.0,}, + {"x":241.0,"y":0.0,}, + {"x":241.0,"y":50.0,}, + {"x":0.0,"y":50.0,}, + ], + "eventList": [ + {"isDnD":false,"eventNum":0,"eventType":3,"collisionObjectId":null,"parent":{"name":"o_gunvisibilitysettings","path":"objects/o_gunvisibilitysettings/o_gunvisibilitysettings.yy",},"resourceVersion":"1.0","name":"","tags":[],"resourceType":"GMEvent",}, + {"isDnD":false,"eventNum":4,"eventType":6,"collisionObjectId":null,"parent":{"name":"o_gunvisibilitysettings","path":"objects/o_gunvisibilitysettings/o_gunvisibilitysettings.yy",},"resourceVersion":"1.0","name":"","tags":[],"resourceType":"GMEvent",}, + {"isDnD":false,"eventNum":10,"eventType":6,"collisionObjectId":null,"parent":{"name":"o_gunvisibilitysettings","path":"objects/o_gunvisibilitysettings/o_gunvisibilitysettings.yy",},"resourceVersion":"1.0","name":"","tags":[],"resourceType":"GMEvent",}, + {"isDnD":false,"eventNum":11,"eventType":6,"collisionObjectId":null,"parent":{"name":"o_gunvisibilitysettings","path":"objects/o_gunvisibilitysettings/o_gunvisibilitysettings.yy",},"resourceVersion":"1.0","name":"","tags":[],"resourceType":"GMEvent",}, + ], + "properties": [], + "overriddenProperties": [], + "parent": { + "name": "Settings", + "path": "folders/Objects/Settings.yy", + }, + "resourceVersion": "1.0", + "name": "o_gunvisibilitysettings", + "tags": [], + "resourceType": "GMObject", +} \ No newline at end of file diff --git a/objects/o_noadsinmenusettings/o_maxfpssettings.yy b/objects/o_noadsinmenusettings/o_maxfpssettings.yy new file mode 100644 index 000000000..8c5801ca0 --- /dev/null +++ b/objects/o_noadsinmenusettings/o_maxfpssettings.yy @@ -0,0 +1,45 @@ +{ + "spriteId": { + "name": "s_maxfpssettings", + "path": "sprites/s_maxfpssettings/s_maxfpssettings.yy", + }, + "solid": false, + "visible": true, + "spriteMaskId": null, + "persistent": false, + "parentObjectId": null, + "physicsObject": false, + "physicsSensor": false, + "physicsShape": 1, + "physicsGroup": 0, + "physicsDensity": 0.5, + "physicsRestitution": 0.1, + "physicsLinearDamping": 0.1, + "physicsAngularDamping": 0.1, + "physicsFriction": 0.2, + "physicsStartAwake": true, + "physicsKinematic": false, + "physicsShapePoints": [ + {"x":0.0,"y":0.0,}, + {"x":241.0,"y":0.0,}, + {"x":241.0,"y":50.0,}, + {"x":0.0,"y":50.0,}, + ], + "eventList": [ + {"isDnD":false,"eventNum":0,"eventType":3,"collisionObjectId":null,"parent":{"name":"o_maxfpssettings","path":"objects/o_maxfpssettings/o_maxfpssettings.yy",},"resourceVersion":"1.0","name":"","tags":[],"resourceType":"GMEvent",}, + {"isDnD":false,"eventNum":4,"eventType":6,"collisionObjectId":null,"parent":{"name":"o_maxfpssettings","path":"objects/o_maxfpssettings/o_maxfpssettings.yy",},"resourceVersion":"1.0","name":"","tags":[],"resourceType":"GMEvent",}, + {"isDnD":false,"eventNum":10,"eventType":6,"collisionObjectId":null,"parent":{"name":"o_maxfpssettings","path":"objects/o_maxfpssettings/o_maxfpssettings.yy",},"resourceVersion":"1.0","name":"","tags":[],"resourceType":"GMEvent",}, + {"isDnD":false,"eventNum":11,"eventType":6,"collisionObjectId":null,"parent":{"name":"o_maxfpssettings","path":"objects/o_maxfpssettings/o_maxfpssettings.yy",},"resourceVersion":"1.0","name":"","tags":[],"resourceType":"GMEvent",}, + {"isDnD":false,"eventNum":0,"eventType":0,"collisionObjectId":null,"parent":{"name":"o_maxfpssettings","path":"objects/o_maxfpssettings/o_maxfpssettings.yy",},"resourceVersion":"1.0","name":"","tags":[],"resourceType":"GMEvent",}, + ], + "properties": [], + "overriddenProperties": [], + "parent": { + "name": "Settings", + "path": "folders/Objects/Settings.yy", + }, + "resourceVersion": "1.0", + "name": "o_maxfpssettings", + "tags": [], + "resourceType": "GMObject", +} \ No newline at end of file diff --git a/objects/o_monophobiaechoesad/o_monophobiaechoesad.yy b/objects/o_noadsinmenusettings/o_noadsinmenusettings.yy similarity index 55% rename from objects/o_monophobiaechoesad/o_monophobiaechoesad.yy rename to objects/o_noadsinmenusettings/o_noadsinmenusettings.yy index 00da3e0ab..16bad90cd 100644 --- a/objects/o_monophobiaechoesad/o_monophobiaechoesad.yy +++ b/objects/o_noadsinmenusettings/o_noadsinmenusettings.yy @@ -1,40 +1,50 @@ { "$GMObject":"", - "%Name":"o_monophobiaechoesad", + "%Name":"o_noadsinmenusettings", "eventList":[ - {"$GMEvent":"","%Name":"","collisionObjectId":null,"eventNum":0,"eventType":8,"isDnD":false,"name":"","resourceType":"GMEvent","resourceVersion":"2.0",}, + {"$GMEvent":"","%Name":"","collisionObjectId":null,"eventNum":0,"eventType":3,"isDnD":false,"name":"","resourceType":"GMEvent","resourceVersion":"2.0",}, + {"$GMEvent":"","%Name":"","collisionObjectId":null,"eventNum":4,"eventType":6,"isDnD":false,"name":"","resourceType":"GMEvent","resourceVersion":"2.0",}, {"$GMEvent":"","%Name":"","collisionObjectId":null,"eventNum":10,"eventType":6,"isDnD":false,"name":"","resourceType":"GMEvent","resourceVersion":"2.0",}, {"$GMEvent":"","%Name":"","collisionObjectId":null,"eventNum":11,"eventType":6,"isDnD":false,"name":"","resourceType":"GMEvent","resourceVersion":"2.0",}, - {"$GMEvent":"","%Name":"","collisionObjectId":null,"eventNum":4,"eventType":6,"isDnD":false,"name":"","resourceType":"GMEvent","resourceVersion":"2.0",}, + {"$GMEvent":"","%Name":"","collisionObjectId":null,"eventNum":0,"eventType":0,"isDnD":false,"name":"","resourceType":"GMEvent","resourceVersion":"2.0",}, + {"$GMEvent":"","%Name":"","collisionObjectId":null,"eventNum":73,"eventType":8,"isDnD":false,"name":"","resourceType":"GMEvent","resourceVersion":"2.0",}, ], "managed":true, - "name":"o_monophobiaechoesad", + "name":"o_noadsinmenusettings", "overriddenProperties":[], "parent":{ - "name":"New Games", - "path":"folders/Objects/Mainmenu/New Games.yy", + "name":"Settings", + "path":"folders/Objects/Settings.yy", + }, + "parentObjectId":{ + "name":"o_allsettings", + "path":"objects/o_allsettings/o_allsettings.yy", }, - "parentObjectId":null, "persistent":false, "physicsAngularDamping":0.1, "physicsDensity":0.5, "physicsFriction":0.2, - "physicsGroup":1, + "physicsGroup":0, "physicsKinematic":false, "physicsLinearDamping":0.1, "physicsObject":false, "physicsRestitution":0.1, "physicsSensor":false, "physicsShape":1, - "physicsShapePoints":[], + "physicsShapePoints":[ + {"x":0.0,"y":0.0,}, + {"x":241.0,"y":0.0,}, + {"x":241.0,"y":50.0,}, + {"x":0.0,"y":50.0,}, + ], "physicsStartAwake":true, "properties":[], "resourceType":"GMObject", "resourceVersion":"2.0", "solid":false, "spriteId":{ - "name":"s_monophobiaechoesad", - "path":"sprites/s_monophobiaechoesad/s_monophobiaechoesad.yy", + "name":"s_noadsinmenusettings", + "path":"sprites/s_noadsinmenusettings/s_noadsinmenusettings.yy", }, "spriteMaskId":null, "visible":true, diff --git a/objects/o_noadsinmenusettings/o_watershadersettings.yy b/objects/o_noadsinmenusettings/o_watershadersettings.yy new file mode 100644 index 000000000..22236f43a --- /dev/null +++ b/objects/o_noadsinmenusettings/o_watershadersettings.yy @@ -0,0 +1,44 @@ +{ + "spriteId": { + "name": "s_watershadersettings", + "path": "sprites/s_watershadersettings/s_watershadersettings.yy", + }, + "solid": false, + "visible": true, + "spriteMaskId": null, + "persistent": false, + "parentObjectId": null, + "physicsObject": false, + "physicsSensor": false, + "physicsShape": 1, + "physicsGroup": 0, + "physicsDensity": 0.5, + "physicsRestitution": 0.1, + "physicsLinearDamping": 0.1, + "physicsAngularDamping": 0.1, + "physicsFriction": 0.2, + "physicsStartAwake": true, + "physicsKinematic": false, + "physicsShapePoints": [ + {"x":0.0,"y":0.0,}, + {"x":241.0,"y":0.0,}, + {"x":241.0,"y":50.0,}, + {"x":0.0,"y":50.0,}, + ], + "eventList": [ + {"isDnD":false,"eventNum":0,"eventType":3,"collisionObjectId":null,"parent":{"name":"o_watershadersettings","path":"objects/o_watershadersettings/o_watershadersettings.yy",},"resourceVersion":"1.0","name":"","tags":[],"resourceType":"GMEvent",}, + {"isDnD":false,"eventNum":4,"eventType":6,"collisionObjectId":null,"parent":{"name":"o_watershadersettings","path":"objects/o_watershadersettings/o_watershadersettings.yy",},"resourceVersion":"1.0","name":"","tags":[],"resourceType":"GMEvent",}, + {"isDnD":false,"eventNum":10,"eventType":6,"collisionObjectId":null,"parent":{"name":"o_watershadersettings","path":"objects/o_watershadersettings/o_watershadersettings.yy",},"resourceVersion":"1.0","name":"","tags":[],"resourceType":"GMEvent",}, + {"isDnD":false,"eventNum":11,"eventType":6,"collisionObjectId":null,"parent":{"name":"o_watershadersettings","path":"objects/o_watershadersettings/o_watershadersettings.yy",},"resourceVersion":"1.0","name":"","tags":[],"resourceType":"GMEvent",}, + ], + "properties": [], + "overriddenProperties": [], + "parent": { + "name": "Settings", + "path": "folders/Objects/Settings.yy", + }, + "resourceVersion": "1.0", + "name": "o_watershadersettings", + "tags": [], + "resourceType": "GMObject", +} \ No newline at end of file diff --git a/objects/o_questsmenu/Draw_75.gml b/objects/o_questsmenu/Draw_75.gml index 6e277da56..70db3901a 100644 --- a/objects/o_questsmenu/Draw_75.gml +++ b/objects/o_questsmenu/Draw_75.gml @@ -21,4 +21,6 @@ random_set_seed(seed) //QUESTS drawquest(150,irandom_range(0,maxquests-1),0) //Quest 1 drawquest(310,irandom_range(0,maxquests-1),1) //Quest 2 -drawquest(470,irandom_range(0,maxquests-1),2) //Quest 3 \ No newline at end of file +drawquest(470,irandom_range(0,maxquests-1),2) //Quest 3 +draw_set_halign(fa_left) +draw_sprite_ext(s_cannotplace,0,64,80,3,3,0,c_white,1) \ No newline at end of file diff --git a/objects/o_settingspausemenu/Create_0.gml b/objects/o_settingspausemenu/Create_0.gml index 592ec1a51..753fd9a9e 100644 --- a/objects/o_settingspausemenu/Create_0.gml +++ b/objects/o_settingspausemenu/Create_0.gml @@ -28,6 +28,9 @@ instance_create(camera_get_view_x(view_camera[0])-256,camera_get_view_y(view_cam instance_create(camera_get_view_x(view_camera[0])-256,camera_get_view_y(view_camera[0])+480,o_antialiasingsettings) instance_create(camera_get_view_x(view_camera[0])-256,camera_get_view_y(view_camera[0])+544,o_vsyncsettings) instance_create(camera_get_view_x(view_camera[0])-256,camera_get_view_y(view_camera[0])+608,o_biglevelperfsettings) +instance_create(camera_get_view_x(view_camera[0])-256,camera_get_view_y(view_camera[0])+160,o_devcommentarysettings) +instance_create(camera_get_view_x(view_camera[0])-256,camera_get_view_y(view_camera[0])+224,o_customsplashessettings) +instance_create(camera_get_view_x(view_camera[0])-256,camera_get_view_y(view_camera[0])+288,o_noadsinmenusettings) //Create Visual Settings instance_create(camera_get_view_x(view_camera[0])-256,camera_get_view_y(view_camera[0])+160,o_starsettings) diff --git a/objects/o_webask/Create_0.gml b/objects/o_webask/Create_0.gml index 16636d542..5ce4a5638 100644 --- a/objects/o_webask/Create_0.gml +++ b/objects/o_webask/Create_0.gml @@ -1,5 +1,9 @@ y = -64 x = 224 + +//If there's more than 1 popup +if instance_number(o_webask) > 1 { instance_destroy() } + url = "" text = loc(678) + " (Y/N)" if gamepad_is_connected(0) { diff --git a/options/extensions/AdMob.json b/options/extensions/AdMob.json index dbfcc8c49..45fa310e4 100644 --- a/options/extensions/AdMob.json +++ b/options/extensions/AdMob.json @@ -27,11 +27,19 @@ "value": "ca-app-pub-7108130195717311/3182582404" } }, + "62068c1c-784e-47b3-b748-a59448d35292": null, "dd7deddb-f012-47ed-9802-3003899c4691": null, "538faebe-f399-430a-b961-576a73233bed": null, "83b3436e-3ee8-432e-8fce-49754e27f5aa": null, "dabd5195-9778-41db-848d-e124050792cc": null, "f6d2fbcb-0a33-4b9b-9914-1e6afbc5b0f9": null, - "6ca59a1d-8267-4f89-a230-f3402bf7ab04": null + "6ca59a1d-8267-4f89-a230-f3402bf7ab04": null, + "a59b6674-9967-4d30-b607-61b9561a9c56": null, + "46974f59-b380-4f04-ad8b-f36a0ff91891": null, + "cc2fb2da-05f1-4e87-909b-b5d19824d731": null, + "d0d19117-79cc-4668-8bed-1349ca551925": null, + "18b08591-a1fe-4892-a653-b6cd26479dec": null, + "0f61eb8d-f68c-4777-bd04-c14e94f6dc9a": null, + "ae27ca8c-4569-427f-abd9-77ae24ab3184": null } } \ No newline at end of file diff --git a/options/extensions/AdMobAppLovin.json b/options/extensions/AdMobAppLovin.json new file mode 100644 index 000000000..afe75e906 --- /dev/null +++ b/options/extensions/AdMobAppLovin.json @@ -0,0 +1,4 @@ +{ + "$GMExtensionConfigSet": "GMExtensionConfigSet", + "configurables": null +} \ No newline at end of file diff --git a/options/extensions/AdMobIronSource.json b/options/extensions/AdMobIronSource.json new file mode 100644 index 000000000..afe75e906 --- /dev/null +++ b/options/extensions/AdMobIronSource.json @@ -0,0 +1,4 @@ +{ + "$GMExtensionConfigSet": "GMExtensionConfigSet", + "configurables": null +} \ No newline at end of file diff --git a/options/extensions/AdMobMeta.json b/options/extensions/AdMobMeta.json new file mode 100644 index 000000000..afe75e906 --- /dev/null +++ b/options/extensions/AdMobMeta.json @@ -0,0 +1,4 @@ +{ + "$GMExtensionConfigSet": "GMExtensionConfigSet", + "configurables": null +} \ No newline at end of file diff --git a/options/extensions/AdMobPangle.json b/options/extensions/AdMobPangle.json new file mode 100644 index 000000000..afe75e906 --- /dev/null +++ b/options/extensions/AdMobPangle.json @@ -0,0 +1,4 @@ +{ + "$GMExtensionConfigSet": "GMExtensionConfigSet", + "configurables": null +} \ No newline at end of file diff --git a/options/extensions/AdMobUnityAds.json b/options/extensions/AdMobUnityAds.json new file mode 100644 index 000000000..afe75e906 --- /dev/null +++ b/options/extensions/AdMobUnityAds.json @@ -0,0 +1,4 @@ +{ + "$GMExtensionConfigSet": "GMExtensionConfigSet", + "configurables": null +} \ No newline at end of file diff --git a/options/extensions/GooglePlayServices.json b/options/extensions/GooglePlayServices.json index 2c00404f1..b357a781e 100644 --- a/options/extensions/GooglePlayServices.json +++ b/options/extensions/GooglePlayServices.json @@ -1,11 +1,17 @@ { "$GMExtensionConfigSet": "GMExtensionConfigSet", "configurables": { + "9d0b1496-d98c-4f0d-a615-f2afa4873468": null, "2333e839-6686-4c10-a29b-851041b2e067": { "Default": { "value": "580119712223" } }, - "9a1bc5e1-1f6a-4128-bb77-f352c42a5bad": null + "b8e7eb69-cec3-466b-b60e-9dfdea781aba": null, + "99765f9a-ab54-45da-b2b3-e7119f9275a0": null, + "e0d1568c-d7ea-4236-956d-fb4729253091": null, + "ba9b6890-9864-4fa1-aaec-d65ced643b86": null, + "6cd32340-3378-4234-bcac-ca9eb79d227a": null, + "3d566d80-4a40-4194-b092-6ec3f219c999": null } } \ No newline at end of file diff --git a/options/windows/options_windows.yy b/options/windows/options_windows.yy index 7b28d9ec8..6e785b9ab 100644 --- a/options/windows/options_windows.yy +++ b/options/windows/options_windows.yy @@ -29,7 +29,7 @@ "option_windows_steam_use_alternative_launcher":true, "option_windows_texture_page":"2048x2048", "option_windows_use_splash":false, - "option_windows_version":"1.1.9.1", + "option_windows_version":"1.1.9.3", "option_windows_vsync":false, "resourceType":"GMWindowsOptions", "resourceVersion":"2.0", diff --git a/rooms/r_mainmenu/r_mainmenu.yy b/rooms/r_mainmenu/r_mainmenu.yy index 4f575b2ea..41e046aec 100644 --- a/rooms/r_mainmenu/r_mainmenu.yy +++ b/rooms/r_mainmenu/r_mainmenu.yy @@ -24,16 +24,16 @@ {"name":"inst_19B2581C","path":"rooms/r_mainmenu/r_mainmenu.yy",}, {"name":"inst_2B77151C","path":"rooms/r_mainmenu/r_mainmenu.yy",}, {"name":"inst_396C61B5","path":"rooms/r_mainmenu/r_mainmenu.yy",}, - {"name":"inst_6833CFF7","path":"rooms/r_mainmenu/r_mainmenu.yy",}, {"name":"inst_42AC446A","path":"rooms/r_mainmenu/r_mainmenu.yy",}, - {"name":"inst_27094760","path":"rooms/r_mainmenu/r_mainmenu.yy",}, {"name":"inst_7B5BAE47","path":"rooms/r_mainmenu/r_mainmenu.yy",}, {"name":"inst_14D2530E","path":"rooms/r_mainmenu/r_mainmenu.yy",}, {"name":"inst_77CE7589","path":"rooms/r_mainmenu/r_mainmenu.yy",}, {"name":"inst_3240DB1B","path":"rooms/r_mainmenu/r_mainmenu.yy",}, + {"name":"inst_726BD1A1","path":"rooms/r_mainmenu/r_mainmenu.yy",}, ], "isDnd":false, "layers":[ + {"$GMRAssetLayer":"","%Name":"Assets_1","assets":[],"depth":-100,"effectEnabled":true,"effectType":null,"gridX":32,"gridY":32,"hierarchyFrozen":false,"inheritLayerDepth":false,"inheritLayerSettings":false,"inheritSubLayers":true,"inheritVisibility":true,"layers":[],"name":"Assets_1","properties":[],"resourceType":"GMRAssetLayer","resourceVersion":"2.0","userdefinedDepth":false,"visible":true,}, {"$GMRInstanceLayer":"","%Name":"Compatibility_Instances_Depth_0","depth":0,"effectEnabled":true,"effectType":null,"gridX":32,"gridY":32,"hierarchyFrozen":false,"inheritLayerDepth":false,"inheritLayerSettings":false,"inheritSubLayers":true,"inheritVisibility":true,"instances":[ {"$GMRInstance":"","%Name":"inst_CF281530","colour":4294967295,"frozen":false,"hasCreationCode":false,"ignore":false,"imageIndex":0,"imageSpeed":1.0,"inheritCode":false,"inheritedItemId":null,"inheritItemSettings":false,"isDnd":false,"name":"inst_CF281530","objectId":{"name":"o_title","path":"objects/o_title/o_title.yy",},"properties":[],"resourceType":"GMRInstance","resourceVersion":"2.0","rotation":0.0,"scaleX":1.0,"scaleY":1.0,"x":390.0,"y":152.0,}, {"$GMRInstance":"","%Name":"inst_28433160","colour":4294967295,"frozen":false,"hasCreationCode":false,"ignore":false,"imageIndex":0,"imageSpeed":1.0,"inheritCode":false,"inheritedItemId":null,"inheritItemSettings":false,"isDnd":false,"name":"inst_28433160","objectId":{"name":"o_version","path":"objects/o_version/o_version.yy",},"properties":[],"resourceType":"GMRInstance","resourceVersion":"2.0","rotation":0.0,"scaleX":1.0,"scaleY":1.0,"x":32.0,"y":0.0,}, @@ -53,13 +53,12 @@ {"$GMRInstance":"","%Name":"inst_19B2581C","colour":4294967295,"frozen":false,"hasCreationCode":true,"ignore":false,"imageIndex":0,"imageSpeed":1.0,"inheritCode":false,"inheritedItemId":null,"inheritItemSettings":false,"isDnd":false,"name":"inst_19B2581C","objectId":{"name":"o_fullversiongame","path":"objects/o_fullversiongame/o_fullversiongame.yy",},"properties":[],"resourceType":"GMRInstance","resourceVersion":"2.0","rotation":0.0,"scaleX":38.520008,"scaleY":18.599987,"x":64.0,"y":602.60016,}, {"$GMRInstance":"","%Name":"inst_2B77151C","colour":4294967295,"frozen":false,"hasCreationCode":false,"ignore":false,"imageIndex":0,"imageSpeed":1.0,"inheritCode":false,"inheritedItemId":null,"inheritItemSettings":false,"isDnd":false,"name":"inst_2B77151C","objectId":{"name":"o_news","path":"objects/o_news/o_news.yy",},"properties":[],"resourceType":"GMRInstance","resourceVersion":"2.0","rotation":0.0,"scaleX":41.2,"scaleY":5.912266,"x":798.0,"y":681.0,}, {"$GMRInstance":"","%Name":"inst_396C61B5","colour":4294967295,"frozen":false,"hasCreationCode":false,"ignore":false,"imageIndex":0,"imageSpeed":1.0,"inheritCode":false,"inheritedItemId":null,"inheritItemSettings":false,"isDnd":false,"name":"inst_396C61B5","objectId":{"name":"o_esc","path":"objects/o_esc/o_esc.yy",},"properties":[],"resourceType":"GMRInstance","resourceVersion":"2.0","rotation":0.0,"scaleX":1.0,"scaleY":1.0,"x":0.0,"y":0.0,}, - {"$GMRInstance":"","%Name":"inst_6833CFF7","colour":4294967295,"frozen":false,"hasCreationCode":false,"ignore":false,"imageIndex":0,"imageSpeed":1.0,"inheritCode":false,"inheritedItemId":null,"inheritItemSettings":false,"isDnd":false,"name":"inst_6833CFF7","objectId":{"name":"o_asteroidsplusplusad","path":"objects/o_asteroidsplusplusad/o_asteroidsplusplusad.yy",},"properties":[],"resourceType":"GMRInstance","resourceVersion":"2.0","rotation":0.0,"scaleX":0.625731,"scaleY":0.5733333,"x":640.0,"y":672.0,}, {"$GMRInstance":"","%Name":"inst_42AC446A","colour":4294967295,"frozen":false,"hasCreationCode":false,"ignore":false,"imageIndex":0,"imageSpeed":1.0,"inheritCode":false,"inheritedItemId":null,"inheritItemSettings":false,"isDnd":false,"name":"inst_42AC446A","objectId":{"name":"o_newsbanner","path":"objects/o_newsbanner/o_newsbanner.yy",},"properties":[],"resourceType":"GMRInstance","resourceVersion":"2.0","rotation":0.0,"scaleX":1.0,"scaleY":1.0,"x":112.0,"y":-534.0,}, - {"$GMRInstance":"","%Name":"inst_27094760","colour":4294967295,"frozen":false,"hasCreationCode":false,"ignore":false,"imageIndex":0,"imageSpeed":1.0,"inheritCode":false,"inheritedItemId":null,"inheritItemSettings":false,"isDnd":false,"name":"inst_27094760","objectId":{"name":"o_monophobiaechoesad","path":"objects/o_monophobiaechoesad/o_monophobiaechoesad.yy",},"properties":[],"resourceType":"GMRInstance","resourceVersion":"2.0","rotation":0.0,"scaleX":0.50999993,"scaleY":0.50999993,"x":560.0,"y":672.0,}, {"$GMRInstance":"","%Name":"inst_7B5BAE47","colour":4294967295,"frozen":false,"hasCreationCode":false,"ignore":false,"imageIndex":0,"imageSpeed":1.0,"inheritCode":false,"inheritedItemId":null,"inheritItemSettings":false,"isDnd":false,"name":"inst_7B5BAE47","objectId":{"name":"o_controllertutormenu","path":"objects/o_controllertutormenu/o_controllertutormenu.yy",},"properties":[],"resourceType":"GMRInstance","resourceVersion":"2.0","rotation":0.0,"scaleX":1.0,"scaleY":1.0,"x":672.0,"y":160.0,}, {"$GMRInstance":"","%Name":"inst_14D2530E","colour":4294967295,"frozen":false,"hasCreationCode":true,"ignore":false,"imageIndex":0,"imageSpeed":1.0,"inheritCode":false,"inheritedItemId":null,"inheritItemSettings":false,"isDnd":false,"name":"inst_14D2530E","objectId":{"name":"o_githubbutton","path":"objects/o_githubbutton/o_githubbutton.yy",},"properties":[],"resourceType":"GMRInstance","resourceVersion":"2.0","rotation":0.0,"scaleX":41.2,"scaleY":5.912266,"x":798.0,"y":718.0,}, {"$GMRInstance":"","%Name":"inst_77CE7589","colour":4294967295,"frozen":false,"hasCreationCode":false,"ignore":false,"imageIndex":0,"imageSpeed":1.0,"inheritCode":false,"inheritedItemId":null,"inheritItemSettings":false,"isDnd":false,"name":"inst_77CE7589","objectId":{"name":"o_questsbutton","path":"objects/o_questsbutton/o_questsbutton.yy",},"properties":[],"resourceType":"GMRInstance","resourceVersion":"2.0","rotation":0.0,"scaleX":1.0,"scaleY":1.0,"x":32.0,"y":320.0,}, {"$GMRInstance":"","%Name":"inst_3240DB1B","colour":4294967295,"frozen":false,"hasCreationCode":false,"ignore":false,"imageIndex":0,"imageSpeed":1.0,"inheritCode":false,"inheritedItemId":null,"inheritItemSettings":false,"isDnd":false,"name":"inst_3240DB1B","objectId":{"name":"o_github","path":"objects/o_github/o_github.yy",},"properties":[],"resourceType":"GMRInstance","resourceVersion":"2.0","rotation":0.0,"scaleX":0.45312497,"scaleY":0.45312497,"x":897.0,"y":469.0,}, + {"$GMRInstance":"","%Name":"inst_726BD1A1","colour":4294967295,"frozen":false,"hasCreationCode":false,"ignore":false,"imageIndex":0,"imageSpeed":1.0,"inheritCode":false,"inheritedItemId":null,"inheritItemSettings":false,"isDnd":false,"name":"inst_726BD1A1","objectId":{"name":"o_infilandgamead","path":"objects/o_infilandgamead/o_infilandgamead.yy",},"properties":[],"resourceType":"GMRInstance","resourceVersion":"2.0","rotation":0.0,"scaleX":1.0,"scaleY":1.0,"x":608.0,"y":640.0,}, ],"layers":[],"name":"Compatibility_Instances_Depth_0","properties":[],"resourceType":"GMRInstanceLayer","resourceVersion":"2.0","userdefinedDepth":true,"visible":true,}, {"$GMRBackgroundLayer":"","%Name":"Compatibility_Colour","animationFPS":30.0,"animationSpeedType":0,"colour":4278190080,"depth":2147483600,"effectEnabled":true,"effectType":null,"gridX":32,"gridY":32,"hierarchyFrozen":false,"hspeed":0.2,"htiled":true,"inheritLayerDepth":false,"inheritLayerSettings":false,"inheritSubLayers":true,"inheritVisibility":true,"layers":[],"name":"Compatibility_Colour","properties":[],"resourceType":"GMRBackgroundLayer","resourceVersion":"2.0","spriteId":null,"stretch":false,"userdefinedAnimFPS":false,"userdefinedDepth":true,"visible":true,"vspeed":0.2,"vtiled":true,"x":0,"y":0,}, ], diff --git a/rooms/r_settings/r_settings.yy b/rooms/r_settings/r_settings.yy index 9c69041c4..f14529d71 100644 --- a/rooms/r_settings/r_settings.yy +++ b/rooms/r_settings/r_settings.yy @@ -87,6 +87,7 @@ {"name":"inst_55AF6E27","path":"rooms/r_settings/r_settings.yy",}, {"name":"inst_3F278810","path":"rooms/r_settings/r_settings.yy",}, {"name":"inst_1E289F89","path":"rooms/r_settings/r_settings.yy",}, + {"name":"inst_7A77809","path":"rooms/r_settings/r_settings.yy",}, ], "isDnd":false, "layers":[ @@ -110,6 +111,7 @@ {"$GMRInstance":"","%Name":"inst_55AF6E27","colour":4294967295,"frozen":false,"hasCreationCode":false,"ignore":false,"imageIndex":0,"imageSpeed":1.0,"inheritCode":false,"inheritedItemId":null,"inheritItemSettings":false,"isDnd":false,"name":"inst_55AF6E27","objectId":{"name":"o_controllertutormenu","path":"objects/o_controllertutormenu/o_controllertutormenu.yy",},"properties":[],"resourceType":"GMRInstance","resourceVersion":"2.0","rotation":0.0,"scaleX":1.0,"scaleY":1.0,"x":800.0,"y":576.0,}, {"$GMRInstance":"","%Name":"inst_3F278810","colour":4294967295,"frozen":false,"hasCreationCode":true,"ignore":false,"imageIndex":0,"imageSpeed":1.0,"inheritCode":false,"inheritedItemId":null,"inheritItemSettings":false,"isDnd":false,"name":"inst_3F278810","objectId":{"name":"o_changelanguagesettings","path":"objects/o_changelanguagesettings/o_changelanguagesettings.yy",},"properties":[],"resourceType":"GMRInstance","resourceVersion":"2.0","rotation":0.0,"scaleX":37.7,"scaleY":10.0,"x":-640.0,"y":160.0,}, {"$GMRInstance":"","%Name":"inst_1E289F89","colour":4294967295,"frozen":false,"hasCreationCode":true,"ignore":false,"imageIndex":0,"imageSpeed":1.0,"inheritCode":false,"inheritedItemId":null,"inheritItemSettings":false,"isDnd":false,"name":"inst_1E289F89","objectId":{"name":"o_changelanguagesettings","path":"objects/o_changelanguagesettings/o_changelanguagesettings.yy",},"properties":[],"resourceType":"GMRInstance","resourceVersion":"2.0","rotation":0.0,"scaleX":37.7,"scaleY":10.0,"x":-640.0,"y":224.0,}, + {"$GMRInstance":"","%Name":"inst_7A77809","colour":4294967295,"frozen":false,"hasCreationCode":false,"ignore":false,"imageIndex":0,"imageSpeed":1.0,"inheritCode":false,"inheritedItemId":null,"inheritItemSettings":false,"isDnd":false,"name":"inst_7A77809","objectId":{"name":"o_noadsinmenusettings","path":"objects/o_noadsinmenusettings/o_noadsinmenusettings.yy",},"properties":[],"resourceType":"GMRInstance","resourceVersion":"2.0","rotation":0.0,"scaleX":1.0,"scaleY":1.0,"x":544.0,"y":288.0,}, ],"layers":[],"name":"Languages","properties":[],"resourceType":"GMRInstanceLayer","resourceVersion":"2.0","userdefinedDepth":false,"visible":true,}, {"$GMRInstanceLayer":"","%Name":"Instances","depth":100,"effectEnabled":true,"effectType":null,"gridX":32,"gridY":32,"hierarchyFrozen":false,"inheritLayerDepth":false,"inheritLayerSettings":false,"inheritSubLayers":true,"inheritVisibility":true,"instances":[ {"$GMRInstance":"","%Name":"inst_3BA07805","colour":4294967295,"frozen":false,"hasCreationCode":true,"ignore":false,"imageIndex":0,"imageSpeed":1.0,"inheritCode":false,"inheritedItemId":null,"inheritItemSettings":false,"isDnd":false,"name":"inst_3BA07805","objectId":{"name":"o_esc","path":"objects/o_esc/o_esc.yy",},"properties":[],"resourceType":"GMRInstance","resourceVersion":"2.0","rotation":0.0,"scaleX":1.0,"scaleY":1.0,"x":0.0,"y":0.0,}, diff --git a/scripts/drawquest/drawquest.gml b/scripts/drawquest/drawquest.gml index c72341e8b..885c7f03b 100644 --- a/scripts/drawquest/drawquest.gml +++ b/scripts/drawquest/drawquest.gml @@ -3,8 +3,8 @@ function drawquest(yy,quest=0,qid=0){ draw_set_halign(fa_center) //Variables -var title = str[quest][0] -var description = str[quest][1] +var title = str[quest][0] //Title +var description = str[quest][1] //Quest Description var current = variable_global_get(str[quest][2]) //Current Progress var needed = str[quest][3] //Required var reward = str[quest][4] //Credits Reward diff --git a/scripts/scr_loadsettings/scr_loadsettings.gml b/scripts/scr_loadsettings/scr_loadsettings.gml index 5649b37a9..4fd392757 100644 --- a/scripts/scr_loadsettings/scr_loadsettings.gml +++ b/scripts/scr_loadsettings/scr_loadsettings.gml @@ -26,6 +26,7 @@ function scr_loadsettings() { global.watershadersettings = ini_read_real("Settings","Water Shader",1); global.gunvisibilitysettings = ini_read_real("Settings","Gun Visibility",1); global.fullscreen = ini_read_real("Settings","Fullscreen",0); + global.noadsinmenusettings = ini_read_real("Settings","No Ads in Menu",0); //global.maxfps = ini_read_real("Settings","Max FPS",60); global.skiplevelholdsettings = ini_read_real("Settings","Skip Level Hold",1); global.oldGSsettings = ini_read_real("Settings","Old GS",0); diff --git a/scripts/scr_savesettings/scr_savesettings.gml b/scripts/scr_savesettings/scr_savesettings.gml index 3e750c659..2b79eff51 100644 --- a/scripts/scr_savesettings/scr_savesettings.gml +++ b/scripts/scr_savesettings/scr_savesettings.gml @@ -37,6 +37,7 @@ function scr_savesettings() { ini_write_real("Settings","Custom Splashes",global.customsplashessettings) ini_write_real("Settings","Hats Autoscale",global.customhatautoscale) ini_write_real("Settings","Fullscreen",global.fullscreen); + ini_write_real("Settings","No Ads in Menu",global.noadsinmenusettings) //Controls Config ini_write_string("Controls","Restart",global.controlsrestart); ini_write_string("Controls","Skip Level",global.controlsskiplevel); diff --git a/sprites/s_monophobiaechoesad/c8dac2e7-3ba2-4e82-98a0-af629b638069.png b/sprites/s_infilandgamead/0f940122-b228-4776-8fb2-ede497dd0dca.png similarity index 93% rename from sprites/s_monophobiaechoesad/c8dac2e7-3ba2-4e82-98a0-af629b638069.png rename to sprites/s_infilandgamead/0f940122-b228-4776-8fb2-ede497dd0dca.png index 9f5210f41..50ecfa98d 100644 Binary files a/sprites/s_monophobiaechoesad/c8dac2e7-3ba2-4e82-98a0-af629b638069.png and b/sprites/s_infilandgamead/0f940122-b228-4776-8fb2-ede497dd0dca.png differ diff --git a/sprites/s_asteroidsplusplusad/6a353215-5fb7-401e-9a58-b16978052c7c.png b/sprites/s_infilandgamead/ac3660d6-97a3-4fab-99fe-c758a535e664.png similarity index 98% rename from sprites/s_asteroidsplusplusad/6a353215-5fb7-401e-9a58-b16978052c7c.png rename to sprites/s_infilandgamead/ac3660d6-97a3-4fab-99fe-c758a535e664.png index b35984e33..adaf13473 100644 Binary files a/sprites/s_asteroidsplusplusad/6a353215-5fb7-401e-9a58-b16978052c7c.png and b/sprites/s_infilandgamead/ac3660d6-97a3-4fab-99fe-c758a535e664.png differ diff --git a/sprites/s_infilandgamead/c36f7d95-02d1-4036-b443-961d061a8d58.png b/sprites/s_infilandgamead/c36f7d95-02d1-4036-b443-961d061a8d58.png new file mode 100644 index 000000000..3833febca Binary files /dev/null and b/sprites/s_infilandgamead/c36f7d95-02d1-4036-b443-961d061a8d58.png differ diff --git a/sprites/s_monophobiaechoesad/layers/c8dac2e7-3ba2-4e82-98a0-af629b638069/a8451542-6815-4569-adec-08923aa587ce.png b/sprites/s_infilandgamead/layers/0f940122-b228-4776-8fb2-ede497dd0dca/785fc54f-6c96-4165-bb93-176cbef781fc.png similarity index 93% rename from sprites/s_monophobiaechoesad/layers/c8dac2e7-3ba2-4e82-98a0-af629b638069/a8451542-6815-4569-adec-08923aa587ce.png rename to sprites/s_infilandgamead/layers/0f940122-b228-4776-8fb2-ede497dd0dca/785fc54f-6c96-4165-bb93-176cbef781fc.png index 9f5210f41..50ecfa98d 100644 Binary files a/sprites/s_monophobiaechoesad/layers/c8dac2e7-3ba2-4e82-98a0-af629b638069/a8451542-6815-4569-adec-08923aa587ce.png and b/sprites/s_infilandgamead/layers/0f940122-b228-4776-8fb2-ede497dd0dca/785fc54f-6c96-4165-bb93-176cbef781fc.png differ diff --git a/sprites/s_asteroidsplusplusad/layers/6a353215-5fb7-401e-9a58-b16978052c7c/c33f47bf-69d3-4303-a50a-2632a6f6a571.png b/sprites/s_infilandgamead/layers/ac3660d6-97a3-4fab-99fe-c758a535e664/785fc54f-6c96-4165-bb93-176cbef781fc.png similarity index 98% rename from sprites/s_asteroidsplusplusad/layers/6a353215-5fb7-401e-9a58-b16978052c7c/c33f47bf-69d3-4303-a50a-2632a6f6a571.png rename to sprites/s_infilandgamead/layers/ac3660d6-97a3-4fab-99fe-c758a535e664/785fc54f-6c96-4165-bb93-176cbef781fc.png index b35984e33..adaf13473 100644 Binary files a/sprites/s_asteroidsplusplusad/layers/6a353215-5fb7-401e-9a58-b16978052c7c/c33f47bf-69d3-4303-a50a-2632a6f6a571.png and b/sprites/s_infilandgamead/layers/ac3660d6-97a3-4fab-99fe-c758a535e664/785fc54f-6c96-4165-bb93-176cbef781fc.png differ diff --git a/sprites/s_infilandgamead/layers/c36f7d95-02d1-4036-b443-961d061a8d58/785fc54f-6c96-4165-bb93-176cbef781fc.png b/sprites/s_infilandgamead/layers/c36f7d95-02d1-4036-b443-961d061a8d58/785fc54f-6c96-4165-bb93-176cbef781fc.png new file mode 100644 index 000000000..3833febca Binary files /dev/null and b/sprites/s_infilandgamead/layers/c36f7d95-02d1-4036-b443-961d061a8d58/785fc54f-6c96-4165-bb93-176cbef781fc.png differ diff --git a/sprites/s_monophobiaechoesad/s_monophobiaechoesad.yy b/sprites/s_infilandgamead/s_infilandgamead.yy similarity index 50% rename from sprites/s_monophobiaechoesad/s_monophobiaechoesad.yy rename to sprites/s_infilandgamead/s_infilandgamead.yy index d7ab8362a..86783b34c 100644 --- a/sprites/s_monophobiaechoesad/s_monophobiaechoesad.yy +++ b/sprites/s_infilandgamead/s_infilandgamead.yy @@ -1,6 +1,6 @@ { "$GMSprite":"", - "%Name":"s_monophobiaechoesad", + "%Name":"s_infilandgamead", "bboxMode":0, "bbox_bottom":149, "bbox_left":0, @@ -12,16 +12,18 @@ "edgeFiltering":false, "For3D":false, "frames":[ - {"$GMSpriteFrame":"","%Name":"c8dac2e7-3ba2-4e82-98a0-af629b638069","name":"c8dac2e7-3ba2-4e82-98a0-af629b638069","resourceType":"GMSpriteFrame","resourceVersion":"2.0",}, + {"$GMSpriteFrame":"","%Name":"ac3660d6-97a3-4fab-99fe-c758a535e664","name":"ac3660d6-97a3-4fab-99fe-c758a535e664","resourceType":"GMSpriteFrame","resourceVersion":"2.0",}, + {"$GMSpriteFrame":"","%Name":"0f940122-b228-4776-8fb2-ede497dd0dca","name":"0f940122-b228-4776-8fb2-ede497dd0dca","resourceType":"GMSpriteFrame","resourceVersion":"2.0",}, + {"$GMSpriteFrame":"","%Name":"c36f7d95-02d1-4036-b443-961d061a8d58","name":"c36f7d95-02d1-4036-b443-961d061a8d58","resourceType":"GMSpriteFrame","resourceVersion":"2.0",}, ], "gridX":0, "gridY":0, "height":150, "HTile":false, "layers":[ - {"$GMImageLayer":"","%Name":"a8451542-6815-4569-adec-08923aa587ce","blendMode":0,"displayName":"default","isLocked":false,"name":"a8451542-6815-4569-adec-08923aa587ce","opacity":100.0,"resourceType":"GMImageLayer","resourceVersion":"2.0","visible":true,}, + {"$GMImageLayer":"","%Name":"785fc54f-6c96-4165-bb93-176cbef781fc","blendMode":0,"displayName":"default","isLocked":false,"name":"785fc54f-6c96-4165-bb93-176cbef781fc","opacity":100.0,"resourceType":"GMImageLayer","resourceVersion":"2.0","visible":true,}, ], - "name":"s_monophobiaechoesad", + "name":"s_infilandgamead", "nineSlice":null, "origin":0, "parent":{ @@ -33,7 +35,7 @@ "resourceVersion":"2.0", "sequence":{ "$GMSequence":"", - "%Name":"s_monophobiaechoesad", + "%Name":"s_infilandgamead", "autoRecord":true, "backdropHeight":768, "backdropImageOpacity":0.5, @@ -49,7 +51,7 @@ }, "eventStubScript":null, "eventToFunction":{}, - "length":1.0, + "length":3.0, "lockOrigin":false, "moments":{ "$KeyframeStore":"", @@ -57,7 +59,7 @@ "resourceType":"KeyframeStore", "resourceVersion":"2.0", }, - "name":"s_monophobiaechoesad", + "name":"s_infilandgamead", "playback":1, "playbackSpeed":30.0, "playbackSpeedType":0, @@ -69,8 +71,14 @@ "tracks":[ {"$GMSpriteFramesTrack":"","builtinName":0,"events":[],"inheritsTrackColour":true,"interpolation":1,"isCreationTrack":false,"keyframes":{"$KeyframeStore":"","Keyframes":[ {"$Keyframe":"","Channels":{ - "0":{"$SpriteFrameKeyframe":"","Id":{"name":"c8dac2e7-3ba2-4e82-98a0-af629b638069","path":"sprites/s_monophobiaechoesad/s_monophobiaechoesad.yy",},"resourceType":"SpriteFrameKeyframe","resourceVersion":"2.0",}, - },"Disabled":false,"id":"d78e9ced-34e0-43a7-ae7d-fd6ccd1bd682","IsCreationKey":false,"Key":0.0,"Length":1.0,"resourceType":"Keyframe","resourceVersion":"2.0","Stretch":false,}, + "0":{"$SpriteFrameKeyframe":"","Id":{"name":"ac3660d6-97a3-4fab-99fe-c758a535e664","path":"sprites/s_infilandgamead/s_infilandgamead.yy",},"resourceType":"SpriteFrameKeyframe","resourceVersion":"2.0",}, + },"Disabled":false,"id":"e68323a3-d632-40a0-8b00-325f81d07b20","IsCreationKey":false,"Key":0.0,"Length":1.0,"resourceType":"Keyframe","resourceVersion":"2.0","Stretch":false,}, + {"$Keyframe":"","Channels":{ + "0":{"$SpriteFrameKeyframe":"","Id":{"name":"0f940122-b228-4776-8fb2-ede497dd0dca","path":"sprites/s_infilandgamead/s_infilandgamead.yy",},"resourceType":"SpriteFrameKeyframe","resourceVersion":"2.0",}, + },"Disabled":false,"id":"0c7a55a1-ddd4-47fd-86c6-845310705780","IsCreationKey":false,"Key":1.0,"Length":1.0,"resourceType":"Keyframe","resourceVersion":"2.0","Stretch":false,}, + {"$Keyframe":"","Channels":{ + "0":{"$SpriteFrameKeyframe":"","Id":{"name":"c36f7d95-02d1-4036-b443-961d061a8d58","path":"sprites/s_infilandgamead/s_infilandgamead.yy",},"resourceType":"SpriteFrameKeyframe","resourceVersion":"2.0",}, + },"Disabled":false,"id":"df80afe2-29c1-463c-8d15-d5a6dd47fe6a","IsCreationKey":false,"Key":2.0,"Length":1.0,"resourceType":"Keyframe","resourceVersion":"2.0","Stretch":false,}, ],"resourceType":"KeyframeStore","resourceVersion":"2.0",},"modifiers":[],"name":"frames","resourceType":"GMSpriteFramesTrack","resourceVersion":"2.0","spriteId":null,"trackColour":0,"tracks":[],"traits":0,}, ], "visibleRange":null, @@ -79,10 +87,10 @@ "yorigin":0, }, "swatchColours":null, - "swfPrecision":2.525, + "swfPrecision":0.5, "textureGroupId":{ - "name":"Buttons", - "path":"texturegroups/Buttons", + "name":"Default", + "path":"texturegroups/Default", }, "type":0, "VTile":false, diff --git a/sprites/s_newsbanner/1f783dd4-df1a-42d9-8827-cd3e4463d249.png b/sprites/s_newsbanner/1f783dd4-df1a-42d9-8827-cd3e4463d249.png new file mode 100644 index 000000000..549428ebb Binary files /dev/null and b/sprites/s_newsbanner/1f783dd4-df1a-42d9-8827-cd3e4463d249.png differ diff --git a/sprites/s_newsbanner/8ae2cc1c-6a07-4db0-81b6-507e2810eaca.png b/sprites/s_newsbanner/8ae2cc1c-6a07-4db0-81b6-507e2810eaca.png deleted file mode 100644 index 766fdb5b0..000000000 Binary files a/sprites/s_newsbanner/8ae2cc1c-6a07-4db0-81b6-507e2810eaca.png and /dev/null differ diff --git a/sprites/s_newsbanner/layers/1f783dd4-df1a-42d9-8827-cd3e4463d249/23692a75-605b-4f4c-a751-47d023a863a5.png b/sprites/s_newsbanner/layers/1f783dd4-df1a-42d9-8827-cd3e4463d249/23692a75-605b-4f4c-a751-47d023a863a5.png new file mode 100644 index 000000000..549428ebb Binary files /dev/null and b/sprites/s_newsbanner/layers/1f783dd4-df1a-42d9-8827-cd3e4463d249/23692a75-605b-4f4c-a751-47d023a863a5.png differ diff --git a/sprites/s_newsbanner/layers/8ae2cc1c-6a07-4db0-81b6-507e2810eaca/30ea032a-9bc7-4c9e-903b-3d16d2772b08.png b/sprites/s_newsbanner/layers/8ae2cc1c-6a07-4db0-81b6-507e2810eaca/30ea032a-9bc7-4c9e-903b-3d16d2772b08.png deleted file mode 100644 index 766fdb5b0..000000000 Binary files a/sprites/s_newsbanner/layers/8ae2cc1c-6a07-4db0-81b6-507e2810eaca/30ea032a-9bc7-4c9e-903b-3d16d2772b08.png and /dev/null differ diff --git a/sprites/s_newsbanner/s_newsbanner.yy b/sprites/s_newsbanner/s_newsbanner.yy index 669e67d3e..a56cc3f78 100644 --- a/sprites/s_newsbanner/s_newsbanner.yy +++ b/sprites/s_newsbanner/s_newsbanner.yy @@ -12,14 +12,14 @@ "edgeFiltering":false, "For3D":false, "frames":[ - {"$GMSpriteFrame":"","%Name":"8ae2cc1c-6a07-4db0-81b6-507e2810eaca","name":"8ae2cc1c-6a07-4db0-81b6-507e2810eaca","resourceType":"GMSpriteFrame","resourceVersion":"2.0",}, + {"$GMSpriteFrame":"","%Name":"1f783dd4-df1a-42d9-8827-cd3e4463d249","name":"1f783dd4-df1a-42d9-8827-cd3e4463d249","resourceType":"GMSpriteFrame","resourceVersion":"2.0",}, ], "gridX":0, "gridY":0, "height":450, "HTile":false, "layers":[ - {"$GMImageLayer":"","%Name":"30ea032a-9bc7-4c9e-903b-3d16d2772b08","blendMode":0,"displayName":"default","isLocked":false,"name":"30ea032a-9bc7-4c9e-903b-3d16d2772b08","opacity":100.0,"resourceType":"GMImageLayer","resourceVersion":"2.0","visible":true,}, + {"$GMImageLayer":"","%Name":"23692a75-605b-4f4c-a751-47d023a863a5","blendMode":0,"displayName":"default","isLocked":false,"name":"23692a75-605b-4f4c-a751-47d023a863a5","opacity":100.0,"resourceType":"GMImageLayer","resourceVersion":"2.0","visible":true,}, ], "name":"s_newsbanner", "nineSlice":null, @@ -69,8 +69,8 @@ "tracks":[ {"$GMSpriteFramesTrack":"","builtinName":0,"events":[],"inheritsTrackColour":true,"interpolation":1,"isCreationTrack":false,"keyframes":{"$KeyframeStore":"","Keyframes":[ {"$Keyframe":"","Channels":{ - "0":{"$SpriteFrameKeyframe":"","Id":{"name":"8ae2cc1c-6a07-4db0-81b6-507e2810eaca","path":"sprites/s_newsbanner/s_newsbanner.yy",},"resourceType":"SpriteFrameKeyframe","resourceVersion":"2.0",}, - },"Disabled":false,"id":"b2f7f94e-f3a8-436a-a694-b9ed1a91dcf8","IsCreationKey":false,"Key":0.0,"Length":1.0,"resourceType":"Keyframe","resourceVersion":"2.0","Stretch":false,}, + "0":{"$SpriteFrameKeyframe":"","Id":{"name":"1f783dd4-df1a-42d9-8827-cd3e4463d249","path":"sprites/s_newsbanner/s_newsbanner.yy",},"resourceType":"SpriteFrameKeyframe","resourceVersion":"2.0",}, + },"Disabled":false,"id":"ccc56441-eabf-411e-b353-8e9edfc27361","IsCreationKey":false,"Key":0.0,"Length":1.0,"resourceType":"Keyframe","resourceVersion":"2.0","Stretch":false,}, ],"resourceType":"KeyframeStore","resourceVersion":"2.0",},"modifiers":[],"name":"frames","resourceType":"GMSpriteFramesTrack","resourceVersion":"2.0","spriteId":null,"trackColour":0,"tracks":[],"traits":0,}, ], "visibleRange":null, diff --git a/sprites/s_noadsinmenusettings/5d101196-2670-4048-9ff2-33bc2f77d2ba.png b/sprites/s_noadsinmenusettings/5d101196-2670-4048-9ff2-33bc2f77d2ba.png new file mode 100644 index 000000000..71bf204be Binary files /dev/null and b/sprites/s_noadsinmenusettings/5d101196-2670-4048-9ff2-33bc2f77d2ba.png differ diff --git a/sprites/s_noadsinmenusettings/e0edf731-3082-4afa-996a-ca96a1683e0a.png b/sprites/s_noadsinmenusettings/e0edf731-3082-4afa-996a-ca96a1683e0a.png new file mode 100644 index 000000000..fc223ec55 Binary files /dev/null and b/sprites/s_noadsinmenusettings/e0edf731-3082-4afa-996a-ca96a1683e0a.png differ diff --git a/sprites/s_noadsinmenusettings/layers/5d101196-2670-4048-9ff2-33bc2f77d2ba/ee1459dd-2c7d-4fea-8173-0c18f0330150.png b/sprites/s_noadsinmenusettings/layers/5d101196-2670-4048-9ff2-33bc2f77d2ba/ee1459dd-2c7d-4fea-8173-0c18f0330150.png new file mode 100644 index 000000000..71bf204be Binary files /dev/null and b/sprites/s_noadsinmenusettings/layers/5d101196-2670-4048-9ff2-33bc2f77d2ba/ee1459dd-2c7d-4fea-8173-0c18f0330150.png differ diff --git a/sprites/s_noadsinmenusettings/layers/e0edf731-3082-4afa-996a-ca96a1683e0a/ee1459dd-2c7d-4fea-8173-0c18f0330150.png b/sprites/s_noadsinmenusettings/layers/e0edf731-3082-4afa-996a-ca96a1683e0a/ee1459dd-2c7d-4fea-8173-0c18f0330150.png new file mode 100644 index 000000000..fc223ec55 Binary files /dev/null and b/sprites/s_noadsinmenusettings/layers/e0edf731-3082-4afa-996a-ca96a1683e0a/ee1459dd-2c7d-4fea-8173-0c18f0330150.png differ diff --git a/sprites/s_asteroidsplusplusad/s_asteroidsplusplusad.yy b/sprites/s_noadsinmenusettings/s_noadsinmenusettings.yy similarity index 57% rename from sprites/s_asteroidsplusplusad/s_asteroidsplusplusad.yy rename to sprites/s_noadsinmenusettings/s_noadsinmenusettings.yy index 841c2213e..939914da7 100644 --- a/sprites/s_asteroidsplusplusad/s_asteroidsplusplusad.yy +++ b/sprites/s_noadsinmenusettings/s_noadsinmenusettings.yy @@ -1,39 +1,40 @@ { "$GMSprite":"", - "%Name":"s_asteroidsplusplusad", + "%Name":"s_noadsinmenusettings", "bboxMode":0, - "bbox_bottom":140, - "bbox_left":3, - "bbox_right":146, - "bbox_top":13, + "bbox_bottom":49, + "bbox_left":0, + "bbox_right":240, + "bbox_top":0, "collisionKind":1, "collisionTolerance":0, "DynamicTexturePage":false, "edgeFiltering":false, "For3D":false, "frames":[ - {"$GMSpriteFrame":"","%Name":"6a353215-5fb7-401e-9a58-b16978052c7c","name":"6a353215-5fb7-401e-9a58-b16978052c7c","resourceType":"GMSpriteFrame","resourceVersion":"2.0",}, + {"$GMSpriteFrame":"","%Name":"5d101196-2670-4048-9ff2-33bc2f77d2ba","name":"5d101196-2670-4048-9ff2-33bc2f77d2ba","resourceType":"GMSpriteFrame","resourceVersion":"2.0",}, + {"$GMSpriteFrame":"","%Name":"e0edf731-3082-4afa-996a-ca96a1683e0a","name":"e0edf731-3082-4afa-996a-ca96a1683e0a","resourceType":"GMSpriteFrame","resourceVersion":"2.0",}, ], "gridX":0, "gridY":0, - "height":150, + "height":50, "HTile":false, "layers":[ - {"$GMImageLayer":"","%Name":"c33f47bf-69d3-4303-a50a-2632a6f6a571","blendMode":0,"displayName":"default","isLocked":false,"name":"c33f47bf-69d3-4303-a50a-2632a6f6a571","opacity":100.0,"resourceType":"GMImageLayer","resourceVersion":"2.0","visible":true,}, + {"$GMImageLayer":"","%Name":"ee1459dd-2c7d-4fea-8173-0c18f0330150","blendMode":0,"displayName":"default","isLocked":false,"name":"ee1459dd-2c7d-4fea-8173-0c18f0330150","opacity":100.0,"resourceType":"GMImageLayer","resourceVersion":"2.0","visible":true,}, ], - "name":"s_asteroidsplusplusad", + "name":"s_noadsinmenusettings", "nineSlice":null, "origin":0, "parent":{ - "name":"Sprites", - "path":"folders/Sprites.yy", + "name":"Settings", + "path":"folders/Sprites/Settings.yy", }, "preMultiplyAlpha":false, "resourceType":"GMSprite", "resourceVersion":"2.0", "sequence":{ "$GMSequence":"", - "%Name":"s_asteroidsplusplusad", + "%Name":"s_noadsinmenusettings", "autoRecord":true, "backdropHeight":768, "backdropImageOpacity":0.5, @@ -49,7 +50,7 @@ }, "eventStubScript":null, "eventToFunction":{}, - "length":1.0, + "length":2.0, "lockOrigin":false, "moments":{ "$KeyframeStore":"", @@ -57,7 +58,7 @@ "resourceType":"KeyframeStore", "resourceVersion":"2.0", }, - "name":"s_asteroidsplusplusad", + "name":"s_noadsinmenusettings", "playback":1, "playbackSpeed":30.0, "playbackSpeedType":0, @@ -69,8 +70,11 @@ "tracks":[ {"$GMSpriteFramesTrack":"","builtinName":0,"events":[],"inheritsTrackColour":true,"interpolation":1,"isCreationTrack":false,"keyframes":{"$KeyframeStore":"","Keyframes":[ {"$Keyframe":"","Channels":{ - "0":{"$SpriteFrameKeyframe":"","Id":{"name":"6a353215-5fb7-401e-9a58-b16978052c7c","path":"sprites/s_asteroidsplusplusad/s_asteroidsplusplusad.yy",},"resourceType":"SpriteFrameKeyframe","resourceVersion":"2.0",}, - },"Disabled":false,"id":"ca8b2478-c7ba-49fa-a6e6-fd8a6805f89d","IsCreationKey":false,"Key":0.0,"Length":1.0,"resourceType":"Keyframe","resourceVersion":"2.0","Stretch":false,}, + "0":{"$SpriteFrameKeyframe":"","Id":{"name":"5d101196-2670-4048-9ff2-33bc2f77d2ba","path":"sprites/s_noadsinmenusettings/s_noadsinmenusettings.yy",},"resourceType":"SpriteFrameKeyframe","resourceVersion":"2.0",}, + },"Disabled":false,"id":"18412685-07c1-4da0-be8d-2044aaeac603","IsCreationKey":false,"Key":0.0,"Length":1.0,"resourceType":"Keyframe","resourceVersion":"2.0","Stretch":false,}, + {"$Keyframe":"","Channels":{ + "0":{"$SpriteFrameKeyframe":"","Id":{"name":"e0edf731-3082-4afa-996a-ca96a1683e0a","path":"sprites/s_noadsinmenusettings/s_noadsinmenusettings.yy",},"resourceType":"SpriteFrameKeyframe","resourceVersion":"2.0",}, + },"Disabled":false,"id":"33f88ee3-3a96-4ee8-a931-ff6e602c2c67","IsCreationKey":false,"Key":1.0,"Length":1.0,"resourceType":"Keyframe","resourceVersion":"2.0","Stretch":false,}, ],"resourceType":"KeyframeStore","resourceVersion":"2.0",},"modifiers":[],"name":"frames","resourceType":"GMSpriteFramesTrack","resourceVersion":"2.0","spriteId":null,"trackColour":0,"tracks":[],"traits":0,}, ], "visibleRange":null, @@ -79,12 +83,12 @@ "yorigin":0, }, "swatchColours":null, - "swfPrecision":2.525, + "swfPrecision":0.5, "textureGroupId":{ "name":"Buttons", "path":"texturegroups/Buttons", }, "type":0, "VTile":false, - "width":150, + "width":241, } \ No newline at end of file