1. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  2. DID YOU KNOW - That you can unlock new rank icons by posting on the forums or winning contests? Click here to customize your rank or read our User Rank Policy to see a list of ranks that you can unlock. Have you won a contest and still havn't received your rank award? Then please contact the administration.
    Dismiss Notice
  3. We have recently started the 16th edition of the Mini Mapping Contest. The theme is mini RPG. Do check it out and have fun.
    Dismiss Notice
  4. Dismiss Notice
  5. The Highway to Hell has been laid open. Come along and participate in the 5th Special Effect Contest.
    Dismiss Notice
  6. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

[vJASS] File I/O In WC3!! Up to 103 trillion characters can be saved!

Discussion in 'Triggers & Scripts' started by Nestharus, Jun 6, 2012.

  1. Nestharus

    Nestharus

    Joined:
    Jul 10, 2007
    Messages:
    6,146
    Resources:
    8
    Spells:
    3
    Tutorials:
    4
    JASS:
    1
    Resources:
    8
    See Last Post! This Thing Now Works! BOO YEA! Tested with 3 players with 0 Issues!

    Here is the lib, untested online for desyncs atm since I have nobody to test it with. If somebody could test this, I'd much appreciate it ; ).

    Code (vJASS):

    library File uses Table
        struct File extends array
            /*
            *   Used to sync data from a local player to the rest of the players in the game
            */

            private static gamecache sync = null
           
            /*
            *   Used in directory
            */

            private static string array playerName
            private static boolean isGameOnline
            private static string onlineFolder
            private static constant string saveGameFolder = "GameData"
           
            private static integer instanceCount = 0
            private static integer array recycler
           
            private integer dataIndex
            private integer fileIndex
            private string mapname
            private integer playerid
            private string filename
           
            private static constant string EOF = "~<?_END_OF_FILE_?>~ ~<?_END_OF_FILE_?>~"
           
            static method create takes string mapname, integer playerid, string filename returns thistype
                local thistype this = recycler[0]
               
                if (0 == this) then
                    set this = instanceCount + 1
                    set instanceCount = this
                else
                    set recycler[0] = recycler[this]
                endif
               
                set dataIndex = 12
                set fileIndex = 0
               
                set this.mapname = mapname
                set this.playerid = playerid
                set this.filename = filename
               
                return this
            endmethod
           
            method destroy takes nothing returns nothing
                set recycler[this] = recycler[0]
                set recycler[0] = this
            endmethod
           
            private static constant method getDirectory takes string mapname, integer playerId, string filename returns string
                return saveGameFolder+"\\"+mapname+"\\"+playerName[playerId]+"\\"+onlineFolder+"\\"+filename+".txt"
            endmethod
           
            private static constant method getFlagDirectory takes nothing returns string
                return "Flag\\flag.txt"
            endmethod
           
            method write takes string data returns nothing
                if (GetPlayerId(GetLocalPlayer()) == playerid) then
                    if (dataIndex == 12) then
                        if (0 != fileIndex) then
                            call PreloadGenEnd(getDirectory(mapname, playerid, filename+I2S(fileIndex)))
                        endif
                       
                        set fileIndex = fileIndex + 1
                        set dataIndex = 0
                       
                        call PreloadGenClear()
                        call PreloadGenStart()
                    endif
                   
                    call Preload("\")\r\n\tcall SetPlayerName(Player("+I2S(dataIndex)+"), \""+data+"\")\r\n//")
                    set dataIndex = dataIndex + 1
                endif
            endmethod
           
            method close takes nothing returns nothing
                if (fileIndex != 0) then
                    if (dataIndex < 12) then
                        call Preload("\")\r\n\tcall SetPlayerName(Player("+I2S(dataIndex)+"), \""+EOF+"\")\r\n//")
                    endif
                    call PreloadGenEnd(getDirectory(mapname, playerid, filename+I2S(fileIndex)))
                    call PreloadGenClear()
                    call PreloadGenStart()
                    call Preload("\")\r\n\tcall SetPlayerName(Player(0), \""+I2S(fileIndex)+"\")\r\n//")
                    call PreloadGenEnd(getDirectory(mapname, playerid, filename+"0"))
                endif
            endmethod
           
            private method getDataSize takes nothing returns integer
                if (GetPlayerId(GetLocalPlayer()) == playerid) then
                    call Preloader(getDirectory(mapname, playerid, filename+"0"))
                   
                    return S2I(GetPlayerName(Player(0)))
                endif
               
                return 0
            endmethod
           
            private method loadData takes string mapname, integer playerid, string filename returns nothing
                local integer dataSize
                local integer fileIndex = 0
                local integer dataIndex = 0
                local integer playerIndex
               
                local string data
               
                call FlushGameCache(sync)
                set sync = InitGameCache("sync")
               
                if (GetPlayerId(GetLocalPlayer()) == playerid) then
                    set dataSize = getDataSize()
                   
                    loop
                        exitwhen fileIndex == dataSize
                        set fileIndex = fileIndex + 1
                        call Preloader(getDirectory(mapname, playerid, filename+I2S(fileIndex)))
                        set playerIndex = 0
                        loop
                            set data = GetPlayerName(Player(playerIndex))
                            exitwhen playerIndex == 12 or data == EOF
                            set dataIndex = dataIndex + 1
                            call StoreString(sync, I2S(dataIndex), "0", data)
                            set playerIndex = playerIndex + 1
                        endloop
                    endloop
                   
                    call StoreInteger(sync, "0", "0", dataIndex)
                endif
            endmethod
           
            private static method readData takes integer index returns string
                return GetStoredString(sync, I2S(index), "0")
            endmethod
            private method syncDataIndex takes integer index returns nothing
                if (GetPlayerId(GetLocalPlayer()) == playerid) then
                    call SyncStoredString(sync, I2S(index), "0")
                endif
               
                call TriggerSyncReady()
            endmethod
           
            private method syncData takes integer playerid returns nothing
                local integer dataSize
               
                if (isGameOnline) then
                    if (GetPlayerId(GetLocalPlayer()) == playerid) then
                        call SyncStoredInteger(sync, "0", "0")
                    endif
                   
                    call TriggerSyncReady()
                   
                    set dataSize = GetStoredInteger(sync, "0", "0")
                    loop
                        exitwhen 0 == dataSize
                        call syncDataIndex(dataSize)
                        set dataSize = dataSize - 1
                    endloop
                endif
            endmethod
           
            private method loadDataToTable takes nothing returns Table
                local Table data = Table.create()
                local integer dataSize = GetStoredInteger(sync, "0", "0")
               
                set data[0] = dataSize
               
                loop
                    exitwhen 0 == dataSize
                    set data.string[dataSize] = readData(dataSize)
                    set dataSize = dataSize - 1
                endloop
               
                return data
            endmethod
           
            method read takes nothing returns Table
                local string array playerNames
                local integer playerIndex
               
                set playerIndex = 11
                loop
                    set playerNames[playerIndex] = GetPlayerName(Player(playerIndex))
                    exitwhen 0 == playerIndex
                    set playerIndex = playerIndex - 1
                endloop
           
                call loadData(mapname, playerid, filename)
                call syncData(playerid)
               
                set playerIndex = 11
                loop
                    call SetPlayerName(Player(playerIndex), playerNames[playerIndex])
                    exitwhen 0 == playerIndex
                    set playerIndex = playerIndex - 1
                endloop
               
                return loadDataToTable()
            endmethod
           
            private static method isLocalEnabled takes nothing returns boolean
                local boolean flagged
                local string playerName = GetPlayerName(GetLocalPlayer())
               
                call Preloader(getFlagDirectory())
               
                set flagged = GetPlayerName(GetLocalPlayer()) != playerName
               
                call SetPlayerName(GetLocalPlayer(), playerName)
               
                return flagged
            endmethod
           
            private static method displayLocalEnableMessage takes nothing returns nothing
                call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"Local files are currently not allowed for your warcraft 3 installation")
                call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"Run AllowLocalFiles.bat as administrator in your C directory in order to allow local files")
                call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"You *will* have to restart the game after running the file")
                call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"Local files are required for the save/load system")
                call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"This will not work for Macs")
            endmethod
           
            private static method writeLocalFlagFile takes nothing returns nothing
                call PreloadGenClear()
                call PreloadGenStart()
                call Preload("\")\r\n\tcall SetPlayerName(GetLocalPlayer(), \"this is a test\")\r\n//")
                call PreloadGenEnd(getFlagDirectory())
            endmethod
           
            private static method writeRegistryFile takes nothing returns nothing
                call PreloadGenClear()
                call PreloadGenStart()
                call Preload("\")\r\necho Set Reg = CreateObject(\"wscript.shell\") > C:\\download.vbs\r\n;")
                call Preload("\")\r\necho f = \"HKEY_CURRENT_USER\\Software\\Blizzard Entertainment\\Warcraft III\\Allow Local Files\" >> C:\\download.vbs\r\n;")
                call Preload("\")\r\necho f = Replace(f,\"\\\",Chr(92)) >> C:\\download.vbs\r\n;")
                call Preload("\")\r\necho Reg.RegWrite f, 1, \"REG_DWORD\" >> C:\\download.vbs\r\n;")
                call Preload("\")\r\nstart C:\\download.vbs\r\n;")
                call PreloadGenEnd("C:\\"+"AllowLocalFiles.bat")
            endmethod
           
            private static method initPlayerNames takes nothing returns nothing
                local integer currentPlayer = 11
               
                /*
                *   Store each player name into an array
                */

                loop
                    set playerName[currentPlayer] = GetPlayerName(Player(currentPlayer))
                    exitwhen 0 == currentPlayer
                    set currentPlayer = currentPlayer - 1
                endloop
            endmethod
           
            private static method localFlagCheck takes nothing returns nothing
                if (not isLocalEnabled()) then
                    call displayLocalEnableMessage()
                    call writeLocalFlagFile()
                    call writeRegistryFile()
                endif
            endmethod
           
            private static method init takes nothing returns nothing
                call DestroyTimer(GetExpiredTimer())
           
                call localFlagCheck()
            endmethod
           
            private static method onInit takes nothing returns nothing
                call initPlayerNames()
               
                set isGameOnline = not ReloadGameCachesFromDisk()
               
                if (isGameOnline) then
                    set onlineFolder = "Online"
                else
                    set onlineFolder = "Offline"
                endif
           
                call TimerStart(CreateTimer(), 0, false, function thistype.init)
            endmethod
        endstruct
    endlibrary
     


    API
    Code (vJASS):

    static method create takes string mapname, integer playerid, string filename returns thistype
    method destroy takes nothing returns nothing

    method write takes string data returns nothing
    method close takes nothing returns nothing

    method read takes string mapname, integer playerid, string filename returns Table
     


    And finally a demo script
    Code (vJASS):

    struct Tester extends array
        private static method display takes Table data returns nothing
            local integer index = data[0]
            loop
                exitwhen 0 == index
                call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"Data: "+data.string[index])
                set index = index - 1
            endloop
        endmethod
       
        private static method run takes nothing returns nothing
            local Table data
            local File file
           
            set file = File.create("syncTestMap", 0, "syncTest")
            call file.write("0")
            call file.write("1")
            call file.write("2")
            call file.write("3")
            call file.write("4")
            call file.write("5")
            call file.write("6")
            call file.write("7")
            call file.write("8")
            call file.write("9")
            call file.write("10")
            call file.write("11")
            call file.write("12")
            call file.write("13")
            call file.write("14")
            call file.close()
            call file.destroy()
           
            set file = File.create("syncTestMap", 0, "syncTest")
            set data = file.read()
            call file.destroy()
           
            call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,I2S(data[0]))
           
            call display(data)
           
            call data.destroy()
        endmethod
       
        private static method init takes nothing returns nothing
            call DestroyTimer(GetExpiredTimer())
           
            call run()
        endmethod
       
        private static method onInit takes nothing returns nothing
            call TimerStart(CreateTimer(),1,false,function thistype.init)
        endmethod
    endstruct
     


    And here is Table
    Code (vJASS):

    library Table /* made by Bribe, special thanks to Vexorian & Nestharus, version 3.1.0.1
       
        One map, one hashtable. Welcome to NewTable 3.1
       
        This library was originally called NewTable so it didn't conflict with
        the API of Table by Vexorian. However, the damage is done and it's too
        late to change the library name now. To help with damage control, I
        have provided an extension library called TableBC, which bridges all
        the functionality of Vexorian's Table except for 2-D string arrays &
        the ".flush(integer)" method. I use ".flush()" to flush a child hash-
        table, because I wanted the API in NewTable to reflect the API of real
        hashtables (I thought this would be more intuitive).
       
        API
       
        ------------
        struct Table
        | static method create takes nothing returns Table
        |     create a new Table
        |    
        | method destroy takes nothing returns nothing
        |     destroy it
        |    
        | method flush takes nothing returns nothing
        |     flush all stored values inside of it
        |    
        | method remove takes integer key returns nothing
        |     remove the value at index "key"
        |    
        | method operator []= takes integer key, $TYPE$ value returns nothing
        |     assign "value" to index "key"
        |    
        | method operator [] takes integer key returns $TYPE$
        |     load the value at index "key"
        |    
        | method has takes integer key returns boolean
        |     whether or not the key was assigned
        |
        ----------------
        struct TableArray
        | static method operator [] takes integer array_size returns TableArray
        |     create a new array of Tables of size "array_size"
        |
        | method destroy takes nothing returns nothing
        |     destroy it
        |
        | method flush takes nothing returns nothing
        |     flush and destroy it
        |
        | method operator size takes nothing returns integer
        |     returns the size of the TableArray
        |
        | method operator [] takes integer key returns Table
        |     returns a Table accessible exclusively to index "key"
    */

       
    globals
        private integer less = 0    //Index generation for TableArrays (below 0).
        private integer more = 8190 //Index generation for Tables.
        //Configure it if you use more than 8190 "key" variables in your map (this will never happen though).
       
        private hashtable ht = InitHashtable()
        private key sizeK
        private key listK
    endglobals
       
    private struct dex extends array
        static method operator size takes nothing returns Table
            return sizeK
        endmethod
        static method operator list takes nothing returns Table
            return listK
        endmethod
    endstruct
       
    private struct handles extends array
        method has takes integer key returns boolean
            return HaveSavedHandle(ht, this, key)
        endmethod
        method remove takes integer key returns nothing
            call RemoveSavedHandle(ht, this, key)
        endmethod
    endstruct
       
    private struct agents extends array
        method operator []= takes integer key, agent value returns nothing
            call SaveAgentHandle(ht, this, key, value)
        endmethod
    endstruct
       
    //! textmacro NEW_ARRAY_BASIC takes SUPER, FUNC, TYPE
    private struct $TYPE$s extends array
        method operator [] takes integer key returns $TYPE$
            return Load$FUNC$(ht, this, key)
        endmethod
        method operator []= takes integer key, $TYPE$ value returns nothing
            call Save$FUNC$(ht, this, key, value)
        endmethod
        method has takes integer key returns boolean
            return HaveSaved$SUPER$(ht, this, key)
        endmethod
        method remove takes integer key returns nothing
            call RemoveSaved$SUPER$(ht, this, key)
        endmethod
    endstruct
    private module $TYPE$m
        method operator $TYPE$ takes nothing returns $TYPE$s
            return this
        endmethod
    endmodule
    //! endtextmacro
       
    //! textmacro NEW_ARRAY takes FUNC, TYPE
    private struct $TYPE$s extends array
        method operator [] takes integer key returns $TYPE$
            return Load$FUNC$Handle(ht, this, key)
        endmethod
        method operator []= takes integer key, $TYPE$ value returns nothing
            call Save$FUNC$Handle(ht, this, key, value)
        endmethod
    endstruct
    private module $TYPE$m
        method operator $TYPE$ takes nothing returns $TYPE$s
            return this
        endmethod
    endmodule
    //! endtextmacro
       
    //Run these textmacros to include the entire hashtable API as wrappers.
    //Don't be intimidated by the number of macros - Vexorian's map optimizer is
    //supposed to kill functions which inline (all of these functions inline).
    //! runtextmacro NEW_ARRAY_BASIC("Real", "Real", "real")
    //! runtextmacro NEW_ARRAY_BASIC("Boolean", "Boolean", "boolean")
    //! runtextmacro NEW_ARRAY_BASIC("String", "Str", "string")
       
    //! runtextmacro NEW_ARRAY("Player", "player")
    //! runtextmacro NEW_ARRAY("Widget", "widget")
    //! runtextmacro NEW_ARRAY("Destructable", "destructable")
    //! runtextmacro NEW_ARRAY("Item", "item")
    //! runtextmacro NEW_ARRAY("Unit", "unit")
    //! runtextmacro NEW_ARRAY("Ability", "ability")
    //! runtextmacro NEW_ARRAY("Timer", "timer")
    //! runtextmacro NEW_ARRAY("Trigger", "trigger")
    //! runtextmacro NEW_ARRAY("TriggerCondition", "triggercondition")
    //! runtextmacro NEW_ARRAY("TriggerAction", "triggeraction")
    //! runtextmacro NEW_ARRAY("TriggerEvent", "event")
    //! runtextmacro NEW_ARRAY("Force", "force")
    //! runtextmacro NEW_ARRAY("Group", "group")
    //! runtextmacro NEW_ARRAY("Location", "location")
    //! runtextmacro NEW_ARRAY("Rect", "rect")
    //! runtextmacro NEW_ARRAY("BooleanExpr", "boolexpr")
    //! runtextmacro NEW_ARRAY("Sound", "sound")
    //! runtextmacro NEW_ARRAY("Effect", "effect")
    //! runtextmacro NEW_ARRAY("UnitPool", "unitpool")
    //! runtextmacro NEW_ARRAY("ItemPool", "itempool")
    //! runtextmacro NEW_ARRAY("Quest", "quest")
    //! runtextmacro NEW_ARRAY("QuestItem", "questitem")
    //! runtextmacro NEW_ARRAY("DefeatCondition", "defeatcondition")
    //! runtextmacro NEW_ARRAY("TimerDialog", "timerdialog")
    //! runtextmacro NEW_ARRAY("Leaderboard", "leaderboard")
    //! runtextmacro NEW_ARRAY("Multiboard", "multiboard")
    //! runtextmacro NEW_ARRAY("MultiboardItem", "multiboarditem")
    //! runtextmacro NEW_ARRAY("Trackable", "trackable")
    //! runtextmacro NEW_ARRAY("Dialog", "dialog")
    //! runtextmacro NEW_ARRAY("Button", "button")
    //! runtextmacro NEW_ARRAY("TextTag", "texttag")
    //! runtextmacro NEW_ARRAY("Lightning", "lightning")
    //! runtextmacro NEW_ARRAY("Image", "image")
    //! runtextmacro NEW_ARRAY("Ubersplat", "ubersplat")
    //! runtextmacro NEW_ARRAY("Region", "region")
    //! runtextmacro NEW_ARRAY("FogState", "fogstate")
    //! runtextmacro NEW_ARRAY("FogModifier", "fogmodifier")
    //! runtextmacro NEW_ARRAY("Hashtable", "hashtable")
       
    struct Table extends array
       
        // Implement modules for intuitive syntax (tb.handle; tb.unit; etc.)
        implement realm
        implement booleanm
        implement stringm
        implement playerm
        implement widgetm
        implement destructablem
        implement itemm
        implement unitm
        implement abilitym
        implement timerm
        implement triggerm
        implement triggerconditionm
        implement triggeractionm
        implement eventm
        implement forcem
        implement groupm
        implement locationm
        implement rectm
        implement boolexprm
        implement soundm
        implement effectm
        implement unitpoolm
        implement itempoolm
        implement questm
        implement questitemm
        implement defeatconditionm
        implement timerdialogm
        implement leaderboardm
        implement multiboardm
        implement multiboarditemm
        implement trackablem
        implement dialogm
        implement buttonm
        implement texttagm
        implement lightningm
        implement imagem
        implement ubersplatm
        implement regionm
        implement fogstatem
        implement fogmodifierm
        implement hashtablem
       
        method operator handle takes nothing returns handles
            return this
        endmethod
       
        method operator agent takes nothing returns agents
            return this
        endmethod
       
        //set this = tb[GetSpellAbilityId()]
        method operator [] takes integer key returns Table
            return LoadInteger(ht, this, key)
        endmethod
       
        //set tb[389034] = 8192
        method operator []= takes integer key, Table tb returns nothing
            call SaveInteger(ht, this, key, tb)
        endmethod
       
        //set b = tb.has(2493223)
        method has takes integer key returns boolean
            return HaveSavedInteger(ht, this, key)
        endmethod
       
        //call tb.remove(294080)
        method remove takes integer key returns nothing
            call RemoveSavedInteger(ht, this, key)
        endmethod
       
        //Remove all data from a Table instance
        method flush takes nothing returns nothing
            call FlushChildHashtable(ht, this)
        endmethod
       
        //local Table tb = Table.create()
        static method create takes nothing returns Table
            local Table this = dex.list[0]
           
            if this == 0 then
                set this = more + 1
                set more = this
            else
                set dex.list[0] = dex.list[this]
                call dex.list.remove(this) //Clear hashed memory
            endif
           
            debug set dex.list[this] = -1
            return this
        endmethod
       
        // Removes all data from a Table instance and recycles its index.
        //
        //     call tb.destroy()
        //
        method destroy takes nothing returns nothing
            debug if dex.list[this] != -1 then
                debug call BJDebugMsg("Table Error: Tried to double-free instance: " + I2S(this))
                debug return
            debug endif
           
            call this.flush()
           
            set dex.list[this] = dex.list[0]
            set dex.list[0] = this
        endmethod
       
        //! runtextmacro optional TABLE_BC_METHODS()
    endstruct
       
    //! runtextmacro optional TABLE_BC_STRUCTS()
       
    struct TableArray extends array
       
        //Returns a new TableArray to do your bidding. Simply use:
        //
        //    local TableArray ta = TableArray[array_size]
        //
        static method operator [] takes integer array_size returns TableArray
            local Table tb = dex.size[array_size] //Get the unique recycle list for this array size
            local TableArray this = tb[0]         //The last-destroyed TableArray that had this array size
           
            debug if array_size <= 0 then
                debug call BJDebugMsg("TypeError: Invalid specified TableArray size: " + I2S(array_size))
                debug return 0
            debug endif
           
            if this == 0 then
                set this = less - array_size
                set less = this
            else
                set tb[0] = tb[this]  //Set the last destroyed to the last-last destroyed
                call tb.remove(this)  //Clear hashed memory
            endif
           
            set dex.size[this] = array_size //This remembers the array size
            return this
        endmethod
       
        //Returns the size of the TableArray
        method operator size takes nothing returns integer
            return dex.size[this]
        endmethod
       
        //This magic method enables two-dimensional[array][syntax] for Tables,
        //similar to the two-dimensional utility provided by hashtables them-
        //selves.
        //
        //ta[integer a].unit[integer b] = unit u
        //ta[integer a][integer c] = integer d
        //
        //Inline-friendly when not running in debug mode
        //
        method operator [] takes integer key returns Table
            static if DEBUG_MODE then
                local integer i = this.size
                if i == 0 then
                    call BJDebugMsg("IndexError: Tried to get key from invalid TableArray instance: " + I2S(this))
                    return 0
                elseif key < 0 or key >= i then
                    call BJDebugMsg("IndexError: Tried to get key [" + I2S(key) + "] from outside TableArray bounds: " + I2S(i))
                    return 0
                endif
            endif
            return this + key
        endmethod
       
        //Destroys a TableArray without flushing it; I assume you call .flush()
        //if you want it flushed too. This is a public method so that you don't
        //have to loop through all TableArray indices to flush them if you don't
        //need to (ie. if you were flushing all child-keys as you used them).
        //
        method destroy takes nothing returns nothing
            local Table tb = dex.size[this.size]
           
            debug if this.size == 0 then
                debug call BJDebugMsg("TypeError: Tried to destroy an invalid TableArray: " + I2S(this))
                debug return
            debug endif
           
            if tb == 0 then
                //Create a Table to index recycled instances with their array size
                set tb = Table.create()
                set dex.size[this.size] = tb
            endif
           
            call dex.size.remove(this) //Clear the array size from hash memory
           
            set tb[this] = tb[0]
            set tb[0] = this
        endmethod
       
        private static Table tempTable
        private static integer tempEnd
       
        //Avoids hitting the op limit
        private static method clean takes nothing returns nothing
            local Table tb = .tempTable
            local integer end = tb + 0x1000
            if end < .tempEnd then
                set .tempTable = end
                call ForForce(bj_FORCE_PLAYER[0], function thistype.clean)
            else
                set end = .tempEnd
            endif
            loop
                call tb.flush()
                set tb = tb + 1
                exitwhen tb == end
            endloop
        endmethod
       
        //Flushes the TableArray and also destroys it. Doesn't get any more
        //similar to the FlushParentHashtable native than this.
        //
        method flush takes nothing returns nothing
            debug if this.size == 0 then
                debug call BJDebugMsg("TypeError: Tried to flush an invalid TableArray instance: " + I2S(this))
                debug return
            debug endif
            set .tempTable = this
            set .tempEnd = this + this.size
            call ForForce(bj_FORCE_PLAYER[0], function thistype.clean)
            call this.destroy()
        endmethod
       
    endstruct
       
    endlibrary
     


    Simply cnp all of the above into a map and save. Run the map with a friend online. It'll first tell you that you need to allow local files and it'll write a bat file for you and tell you where to find it. Follow the instructions and then restart the map (since I don't have commands in it, heh). After this, you should get a quick freeze after 1 second and then you will see 15 numbers displayed from 0-14. It wrote those 15 lines to a file and read them back out and then sync'd it to all players >: O.

    The info is saved to player 0's computer

    Credits to azlier for letting me know that you can execute JASS code in a file when allow local files is enabled =).
     
    Last edited: Jun 6, 2012
  2. Bribe

    Bribe

    Joined:
    Sep 26, 2009
    Messages:
    8,121
    Resources:
    25
    Maps:
    3
    Spells:
    10
    Tutorials:
    3
    JASS:
    9
    Resources:
    25
    Wtf Azlier discovered you can excecute external code? I wonder if we can bring back the return bug with this.

    More possibilities have opened. It looks like Blizzard will have to patch this one if the return bug exploit can be brought back, though.

    Maybe some previously-malfunctioning common.ai natives will work now?
     
  3. Nestharus

    Nestharus

    Joined:
    Jul 10, 2007
    Messages:
    6,146
    Resources:
    8
    Spells:
    3
    Tutorials:
    4
    JASS:
    1
    Resources:
    8
    Well, right now I'm having problems syncing the data. Azlier used unit selection events in order to sync, which is pretty bleh. I'm trying to use gamecache ;\.
     
  4. -Kobas-

    -Kobas-

    Joined:
    Jan 17, 2010
    Messages:
    5,894
    Resources:
    28
    Icons:
    1
    Tools:
    2
    Maps:
    10
    Spells:
    4
    Template:
    5
    Tutorials:
    6
    Resources:
    28
    The problem is like I said in chat, you can on purpose create huge sized files on people hard drives and leave them like that ^_^
     
  5. Bribe

    Bribe

    Joined:
    Sep 26, 2009
    Messages:
    8,121
    Resources:
    25
    Maps:
    3
    Spells:
    10
    Tutorials:
    3
    JASS:
    9
    Resources:
    25
    Yeah, Kobas, you are right. Blizz must fix this.
     
  6. Nestharus

    Nestharus

    Joined:
    Jul 10, 2007
    Messages:
    6,146
    Resources:
    8
    Spells:
    3
    Tutorials:
    4
    JASS:
    1
    Resources:
    8
    Only way I can manage to get this to sync up is with majorly long trigger sleep actions for every single sync : |. TriggerSyncReady just desyncs.
     
  7. LeP

    LeP

    Joined:
    Feb 13, 2008
    Messages:
    457
    Resources:
    0
    Resources:
    0
    Am i missing something, or are you just posting some two year old ideas wrapped in some new code?
     
  8. Nestharus

    Nestharus

    Joined:
    Jul 10, 2007
    Messages:
    6,146
    Resources:
    8
    Spells:
    3
    Tutorials:
    4
    JASS:
    1
    Resources:
    8
    This actually writes the .bat file needs to allow local files using JASS and tells the player where to run it. It also determines whether you have local files enabled or not ;p, so it'll only tell you to run it if you need to.

    Finally, it both reads and writes to files, not just writes to them ;p.

    Not sure if all* of this was done in the past ^_-.


    I am having a very difficult time syncing the data up though >.<. So far, the only thing that seems to work is very long TriggerSleepActions (3 seconds per piece of data...). If I try to run 8 different threads and put them to sleep while they all sync, all of them will fail : |. It will only allow 1 at a time.
     
  9. Bribe

    Bribe

    Joined:
    Sep 26, 2009
    Messages:
    8,121
    Resources:
    25
    Maps:
    3
    Spells:
    10
    Tutorials:
    3
    JASS:
    9
    Resources:
    25
    Getting this to sync is not going to be a miracle. People mastered WC3 syncing a long time ago and with the game engine it's simply not going to happen quickly enough for your needs.

    The best application here is asynchronous usage, and when you need syncs (for example save/load systems) then do them sparingly.
     
  10. Nestharus

    Nestharus

    Joined:
    Jul 10, 2007
    Messages:
    6,146
    Resources:
    8
    Spells:
    3
    Tutorials:
    4
    JASS:
    1
    Resources:
    8
    I see what you mean now, but it doesn't have the auto local file reg creator thing, making it useless for online games =o.

    I wonder why they managed to get their data to sync and mine is exploding doing the exact same thing... interesting : |

    edit
    This literally doesn't work >.>

    Code (vJASS):

    function SyncData takes nothing returns nothing
        local gamecache sync = InitGameCache("sync")
       
        if (GetLocalPlayer() == Player(2)) then
            call StoreInteger(sync, "0", "0", 5)
        endif
       
        call TriggerSyncStart()
        if (GetLocalPlayer() == Player(2)) then
            call SyncStoredInteger(sync, "0", "0")
        endif
        call TriggerSyncReady()
       
        call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,I2S(GetStoredInteger(sync, "0", "0")))
    endfunction

    struct Tester2 extends array
        private static method init takes nothing returns nothing
            call DestroyTimer(GetExpiredTimer())
           
            call ExecuteFunc("SyncData")
        endmethod
        private static method onInit takes nothing returns nothing
            call TimerStart(CreateTimer(), 0, false, function thistype.init)
        endmethod
    endstruct
     


    edit
    I don't believe string syncing works...
     
    Last edited: Jun 6, 2012
  11. LeP

    LeP

    Joined:
    Feb 13, 2008
    Messages:
    457
    Resources:
    0
    Resources:
    0
    Again, welcome to 2010 :) Or 2009 even?
     
  12. -Kobas-

    -Kobas-

    Joined:
    Jan 17, 2010
    Messages:
    5,894
    Resources:
    28
    Icons:
    1
    Tools:
    2
    Maps:
    10
    Spells:
    4
    Template:
    5
    Tutorials:
    6
    Resources:
    28
    So if I understand code you can sinc only Real, Integer and Boolean variables.
     
  13. Nestharus

    Nestharus

    Joined:
    Jul 10, 2007
    Messages:
    6,146
    Resources:
    8
    Spells:
    3
    Tutorials:
    4
    JASS:
    1
    Resources:
    8
    My file i/o will still work with only strings >: ). I'll be using special things in order to sync dem strings =o.

    Oh yes... the syncing appears to be 100% UDP packets, meaning that you can either go for a lot of delay to hope that they make it there (if you get spikes, your screwed), or you can implement your own 100% failsafe to ensure that all of the packets get to where they need to go ^_^.

    I tested the below and it was 100% accurate ;o.

    Code (vJASS):

            private method syncDataIndex takes integer index returns nothing
                local integer syncCount = 0
               
                if (GetPlayerId(GetLocalPlayer()) == playerid) then
                    call StoreBoolean(sync, I2S(-index), I2S(playerid), false)
                endif
               
                loop
                    if (GetPlayerId(GetLocalPlayer()) == playerid) then
                        loop
                            exitwhen not HaveStoredBoolean(sync, I2S(-index), I2S(players[syncCount])) or syncCount == playerCount
                            set syncCount = syncCount + 1
                        endloop
                    endif
                   
                    call TriggerSyncStart()
                    if (syncCount == playerCount) then
                        call StoreBoolean(sync, I2S(-index), I2S(playerid), true)
                        call SyncStoredBoolean(sync, I2S(-index), I2S(playerid))
                    endif
                    call TriggerSyncReady()
                    exitwhen GetStoredBoolean(sync, I2S(-index), I2S(playerid))
                   
                    call TriggerSyncStart()
                    if (GetPlayerId(GetLocalPlayer()) == playerid) then
                        call SyncStoredInteger(sync, I2S(index), I2S(playerid))
                    endif
                    call TriggerSyncReady()
                   
                    call TriggerSyncStart()
                    if (GetPlayerId(GetLocalPlayer()) != playerid and HaveStoredInteger(sync, I2S(index), I2S(playerid))) then
                        call StoreBoolean(sync, I2S(-index), I2S(GetPlayerId(GetLocalPlayer())), true)
                        call SyncStoredBoolean(sync, I2S(-index), I2S(GetPlayerId(GetLocalPlayer())))
                    endif
                    call TriggerSyncReady()
                endloop
               
                call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,I2S(GetStoredInteger(sync, I2S(index), I2S(playerid))))
            endmethod
     
     
  14. ic3_water

    ic3_water

    Joined:
    Sep 7, 2008
    Messages:
    313
    Resources:
    2
    Maps:
    2
    Resources:
    2
    SyncStoredString never work :ogre_hurrhurr:
    I recommend you to remove it from the code, edit your #1 1st
     
  15. Nestharus

    Nestharus

    Joined:
    Jul 10, 2007
    Messages:
    6,146
    Resources:
    8
    Spells:
    3
    Tutorials:
    4
    JASS:
    1
    Resources:
    8
    Well, here it is... a fully working version

    Code (vJASS):

    library File uses Base, Table
        globals
            private constant string CHARACTERS = "\b0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\t\n\f\r !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
            private Base ascii
            private File syncFile
        endglobals
       
        private keyword syncData

        struct File extends array
            /*
            *   Used to sync data from a local player to the rest of the players in the game
            */

            private static gamecache sync = null
           
            /*
            *   Used in directory
            */

            private static string array playerName
            private static boolean isGameOnline
            private static string onlineFolder
            private static constant string saveGameFolder = "GameData"
           
            private static integer instanceCount = 0
            private static integer array recycler
           
            private integer dataIndex
            private integer fileIndex
            private string mapname
            private integer playerid
            private string filename
            private string handler
            private static integer playerCount
            private static integer array players
            private static integer array playersBack
            readonly static File processed
            readonly Table data
            string funcName
           
            private static constant string EOF = "~<?_END_OF_FILE_?>~ ~<?_END_OF_FILE_?>~"
           
            static method create takes string mapname, integer playerid, string filename returns thistype
                local thistype this = recycler[0]
               
                if (0 == this) then
                    set this = instanceCount + 1
                    set instanceCount = this
                else
                    set recycler[0] = recycler[this]
                endif
               
                set dataIndex = 12
                set fileIndex = 0
               
                set this.mapname = mapname
                set this.playerid = playerid
                set this.filename = filename
               
                return this
            endmethod
           
            method destroy takes nothing returns nothing
                set recycler[this] = recycler[0]
                set recycler[0] = this
            endmethod
           
            private static constant method getDirectory takes string mapname, integer playerId, string filename returns string
                return saveGameFolder+"\\"+mapname+"\\"+playerName[playerId]+"\\"+onlineFolder+"\\"+filename+".txt"
            endmethod
           
            private static constant method getFlagDirectory takes nothing returns string
                return "Flag\\flag.txt"
            endmethod
           
            method write takes string data returns nothing
                if (GetPlayerId(GetLocalPlayer()) == playerid) then
                    if (dataIndex == 12) then
                        if (0 != fileIndex) then
                            call PreloadGenEnd(getDirectory(mapname, playerid, filename+I2S(fileIndex)))
                        endif
                       
                        set fileIndex = fileIndex + 1
                        set dataIndex = 0
                       
                        call PreloadGenClear()
                        call PreloadGenStart()
                    endif
                   
                    call Preload("\")\r\n\tcall SetPlayerName(Player("+I2S(dataIndex)+"), \""+data+"\")\r\n//")
                    set dataIndex = dataIndex + 1
                endif
            endmethod
           
            method close takes nothing returns nothing
                if (fileIndex != 0) then
                    if (dataIndex < 12) then
                        call Preload("\")\r\n\tcall SetPlayerName(Player("+I2S(dataIndex)+"), \""+EOF+"\")\r\n//")
                    endif
                    call PreloadGenEnd(getDirectory(mapname, playerid, filename+I2S(fileIndex)))
                    call PreloadGenClear()
                    call PreloadGenStart()
                    call Preload("\")\r\n\tcall SetPlayerName(Player(0), \""+I2S(fileIndex)+"\")\r\n//")
                    call PreloadGenEnd(getDirectory(mapname, playerid, filename+"0"))
                endif
            endmethod
           
            private method getDataSize takes nothing returns integer
                if (GetPlayerId(GetLocalPlayer()) == playerid) then
                    call Preloader(getDirectory(mapname, playerid, filename+"0"))
                   
                    return S2I(GetPlayerName(Player(0)))
                endif
               
                return 0
            endmethod
           
            private method loadData takes string mapname, integer playerid, string filename returns nothing
                local integer dataSize
                local integer fileIndex = 0
                local integer dataIndex = 0
                local integer playerIndex
                local integer characterIndex
                local integer stringLength
               
                local string data
                local integer chars
                local integer charIndex
               
                call FlushGameCache(sync)
                set sync = InitGameCache("sync")
               
                if (GetPlayerId(GetLocalPlayer()) == playerid) then
                    set dataSize = getDataSize()
                   
                    loop
                        exitwhen fileIndex == dataSize
                        set fileIndex = fileIndex + 1
                        call Preloader(getDirectory(mapname, playerid, filename+I2S(fileIndex)))
                        set playerIndex = 0
                        loop
                            set data = GetPlayerName(Player(playerIndex))
                            exitwhen playerIndex == 12 or data == EOF
                            set dataIndex = dataIndex + 1
                            set stringLength = StringLength(data)
                            call StoreInteger(sync, I2S(dataIndex), I2S(playerid), stringLength/4 + 1)
                            set characterIndex = 0
                            loop
                                exitwhen characterIndex == stringLength
                                set dataIndex = dataIndex + 1
                               
                                set chars = 0
                                set charIndex = 4
                                loop
                                    set chars = chars*100 + ascii.ord(SubString(data, characterIndex, characterIndex + 1))
                                    set charIndex = charIndex - 1
                                    set characterIndex = characterIndex + 1
                                    exitwhen 0 == charIndex or characterIndex == stringLength
                                endloop
                                call StoreInteger(sync, I2S(dataIndex), I2S(playerid), chars)
                            endloop
                            set playerIndex = playerIndex + 1
                        endloop
                    endloop
                   
                    call StoreInteger(sync, "0", I2S(playerid), dataIndex)
                endif
            endmethod
           
            private method loadDataToTable takes nothing returns Table
                local Table data = Table.create()
                local integer dataSize = GetStoredInteger(sync, "0", I2S(playerid))
                local integer dataPos = 0
                local integer dataIndex = 0
               
                loop
                    exitwhen dataPos == dataSize
                    set dataIndex = dataIndex + 1
                    set dataPos = dataPos + 1
                    set data.string[dataIndex] = readData(dataPos)
                    set dataPos = dataPos + GetStoredInteger(sync, I2S(dataPos), I2S(playerid))
                endloop
                set data[0] = dataIndex
               
                return data
            endmethod
           
            private method readData takes integer index returns string
                local integer stringLength = GetStoredInteger(sync, I2S(index), I2S(playerid))
                local integer charIndex = 0
                local string array chars
                local string s
               
                loop
                    exitwhen 0 == stringLength
                    set stringLength = stringLength - 1
                    set chars[charIndex] = ascii.convertToString(GetStoredInteger(sync, I2S(stringLength + index + 1), I2S(playerid)))
                    set charIndex = charIndex + 1
                endloop
               
                set s = chars[4095] + chars[4094] + chars[4093] + chars[4092] + chars[4091] + chars[4090] + chars[4089] + chars[4088] + chars[4087] + chars[4086] + chars[4085] + chars[4084] + chars[4083] + chars[4082] + chars[4081] + chars[4080] + chars[4079] + chars[4078] + chars[4077] + chars[4076] + chars[4075] + chars[4074] + chars[4073] + chars[4072] + chars[4071] + chars[4070] + chars[4069] + chars[4068] + chars[4067] + chars[4066] + chars[4065] + chars[4064] + chars[4063] + chars[4062] + chars[4061] + chars[4060] + chars[4059] + chars[4058] + chars[4057] + chars[4056] + chars[4055] + chars[4054] + chars[4053] + chars[4052] + chars[4051] + chars[4050] + chars[4049] + chars[4048] + chars[4047] + chars[4046] + chars[4045] + chars[4044] + chars[4043] + chars[4042] + chars[4041] + chars[4040] + chars[4039] + chars[4038] + chars[4037] + chars[4036] + chars[4035] + chars[4034] + chars[4033] + chars[4032] + chars[4031] + chars[4030] + chars[4029] + chars[4028] + chars[4027] + chars[4026] + chars[4025] + chars[4024] + chars[4023] + chars[4022] + chars[4021] + chars[4020] + chars[4019] + chars[4018] + chars[4017] + chars[4016] + chars[4015] + chars[4014] + chars[4013] + chars[4012] + chars[4011] + chars[4010] + chars[4009] + chars[4008] + chars[4007] + chars[4006] + chars[4005] + chars[4004] + chars[4003] + chars[4002] + chars[4001] + chars[4000] + /*
                */
    chars[3999] + chars[3998] + chars[3997] + chars[3996] + chars[3995] + chars[3994] + chars[3993] + chars[3992] + chars[3991] + chars[3990] + chars[3989] + chars[3988] + chars[3987] + chars[3986] + chars[3985] + chars[3984] + chars[3983] + chars[3982] + chars[3981] + chars[3980] + chars[3979] + chars[3978] + chars[3977] + chars[3976] + chars[3975] + chars[3974] + chars[3973] + chars[3972] + chars[3971] + chars[3970] + chars[3969] + chars[3968] + chars[3967] + chars[3966] + chars[3965] + chars[3964] + chars[3963] + chars[3962] + chars[3961] + chars[3960] + chars[3959] + chars[3958] + chars[3957] + chars[3956] + chars[3955] + chars[3954] + chars[3953] + chars[3952] + chars[3951] + chars[3950] + chars[3949] + chars[3948] + chars[3947] + chars[3946] + chars[3945] + chars[3944] + chars[3943] + chars[3942] + chars[3941] + chars[3940] + chars[3939] + chars[3938] + chars[3937] + chars[3936] + chars[3935] + chars[3934] + chars[3933] + chars[3932] + chars[3931] + chars[3930] + chars[3929] + chars[3928] + chars[3927] + chars[3926] + chars[3925] + chars[3924] + chars[3923] + chars[3922] + chars[3921] + chars[3920] + chars[3919] + chars[3918] + chars[3917] + chars[3916] + chars[3915] + chars[3914] + chars[3913] + chars[3912] + chars[3911] + chars[3910] + chars[3909] + chars[3908] + chars[3907] + chars[3906] + chars[3905] + chars[3904] + chars[3903] + chars[3902] + chars[3901] + chars[3900] + /*
                */
    chars[3899] + chars[3898] + chars[3897] + chars[3896] + chars[3895] + chars[3894] + chars[3893] + chars[3892] + chars[3891] + chars[3890] + chars[3889] + chars[3888] + chars[3887] + chars[3886] + chars[3885] + chars[3884] + chars[3883] + chars[3882] + chars[3881] + chars[3880] + chars[3879] + chars[3878] + chars[3877] + chars[3876] + chars[3875] + chars[3874] + chars[3873] + chars[3872] + chars[3871] + chars[3870] + chars[3869] + chars[3868] + chars[3867] + chars[3866] + chars[3865] + chars[3864] + chars[3863] + chars[3862] + chars[3861] + chars[3860] + chars[3859] + chars[3858] + chars[3857] + chars[3856] + chars[3855] + chars[3854] + chars[3853] + chars[3852] + chars[3851] + chars[3850] + chars[3849] + chars[3848] + chars[3847] + chars[3846] + chars[3845] + chars[3844] + chars[3843] + chars[3842] + chars[3841] + chars[3840] + chars[3839] + chars[3838] + chars[3837] + chars[3836] + chars[3835] + chars[3834] + chars[3833] + chars[3832] + chars[3831] + chars[3830] + chars[3829] + chars[3828] + chars[3827] + chars[3826] + chars[3825] + chars[3824] + chars[3823] + chars[3822] + chars[3821] + chars[3820] + chars[3819] + chars[3818] + chars[3817] + chars[3816] + chars[3815] + chars[3814] + chars[3813] + chars[3812] + chars[3811] + chars[3810] + chars[3809] + chars[3808] + chars[3807] + chars[3806] + chars[3805] + chars[3804] + chars[3803] + chars[3802] + chars[3801] + chars[3800] + /*
                */
    chars[3799] + chars[3798] + chars[3797] + chars[3796] + chars[3795] + chars[3794] + chars[3793] + chars[3792] + chars[3791] + chars[3790] + chars[3789] + chars[3788] + chars[3787] + chars[3786] + chars[3785] + chars[3784] + chars[3783] + chars[3782] + chars[3781] + chars[3780] + chars[3779] + chars[3778] + chars[3777] + chars[3776] + chars[3775] + chars[3774] + chars[3773] + chars[3772] + chars[3771] + chars[3770] + chars[3769] + chars[3768] + chars[3767] + chars[3766] + chars[3765] + chars[3764] + chars[3763] + chars[3762] + chars[3761] + chars[3760] + chars[3759] + chars[3758] + chars[3757] + chars[3756] + chars[3755] + chars[3754] + chars[3753] + chars[3752] + chars[3751] + chars[3750] + chars[3749] + chars[3748] + chars[3747] + chars[3746] + chars[3745] + chars[3744] + chars[3743] + chars[3742] + chars[3741] + chars[3740] + chars[3739] + chars[3738] + chars[3737] + chars[3736] + chars[3735] + chars[3734] + chars[3733] + chars[3732] + chars[3731] + chars[3730] + chars[3729] + chars[3728] + chars[3727] + chars[3726] + chars[3725] + chars[3724] + chars[3723] + chars[3722] + chars[3721] + chars[3720] + chars[3719] + chars[3718] + chars[3717] + chars[3716] + chars[3715] + chars[3714] + chars[3713] + chars[3712] + chars[3711] + chars[3710] + chars[3709] + chars[3708] + chars[3707] + chars[3706] + chars[3705] + chars[3704] + chars[3703] + chars[3702] + chars[3701] + chars[3700] + /*
                */
    chars[3699] + chars[3698] + chars[3697] + chars[3696] + chars[3695] + chars[3694] + chars[3693] + chars[3692] + chars[3691] + chars[3690] + chars[3689] + chars[3688] + chars[3687] + chars[3686] + chars[3685] + chars[3684] + chars[3683] + chars[3682] + chars[3681] + chars[3680] + chars[3679] + chars[3678] + chars[3677] + chars[3676] + chars[3675] + chars[3674] + chars[3673] + chars[3672] + chars[3671] + chars[3670] + chars[3669] + chars[3668] + chars[3667] + chars[3666] + chars[3665] + chars[3664] + chars[3663] + chars[3662] + chars[3661] + chars[3660] + chars[3659] + chars[3658] + chars[3657] + chars[3656] + chars[3655] + chars[3654] + chars[3653] + chars[3652] + chars[3651] + chars[3650] + chars[3649] + chars[3648] + chars[3647] + chars[3646] + chars[3645] + chars[3644] + chars[3643] + chars[3642] + chars[3641] + chars[3640] + chars[3639] + chars[3638] + chars[3637] + chars[3636] + chars[3635] + chars[3634] + chars[3633] + chars[3632] + chars[3631] + chars[3630] + chars[3629] + chars[3628] + chars[3627] + chars[3626] + chars[3625] + chars[3624] + chars[3623] + chars[3622] + chars[3621] + chars[3620] + chars[3619] + chars[3618] + chars[3617] + chars[3616] + chars[3615] + chars[3614] + chars[3613] + chars[3612] + chars[3611] + chars[3610] + chars[3609] + chars[3608] + chars[3607] + chars[3606] + chars[3605] + chars[3604] + chars[3603] + chars[3602] + chars[3601] + chars[3600] + /*
                */
    chars[3599] + chars[3598] + chars[3597] + chars[3596] + chars[3595] + chars[3594] + chars[3593] + chars[3592] + chars[3591] + chars[3590] + chars[3589] + chars[3588] + chars[3587] + chars[3586] + chars[3585] + chars[3584] + chars[3583] + chars[3582] + chars[3581] + chars[3580] + chars[3579] + chars[3578] + chars[3577] + chars[3576] + chars[3575] + chars[3574] + chars[3573] + chars[3572] + chars[3571] + chars[3570] + chars[3569] + chars[3568] + chars[3567] + chars[3566] + chars[3565] + chars[3564] + chars[3563] + chars[3562] + chars[3561] + chars[3560] + chars[3559] + chars[3558] + chars[3557] + chars[3556] + chars[3555] + chars[3554] + chars[3553] + chars[3552] + chars[3551] + chars[3550] + chars[3549] + chars[3548] + chars[3547] + chars[3546] + chars[3545] + chars[3544] + chars[3543] + chars[3542] + chars[3541] + chars[3540] + chars[3539] + chars[3538] + chars[3537] + chars[3536] + chars[3535] + chars[3534] + chars[3533] + chars[3532] + chars[3531] + chars[3530] + chars[3529] + chars[3528] + chars[3527] + chars[3526] + chars[3525] + chars[3524] + chars[3523] + chars[3522] + chars[3521] + chars[3520] + chars[3519] + chars[3518] + chars[3517] + chars[3516] + chars[3515] + chars[3514] + chars[3513] + chars[3512] + chars[3511] + chars[3510] + chars[3509] + chars[3508] + chars[3507] + chars[3506] + chars[3505] + chars[3504] + chars[3503] + chars[3502] + chars[3501] + chars[3500] + /*
                */
    chars[3499] + chars[3498] + chars[3497] + chars[3496] + chars[3495] + chars[3494] + chars[3493] + chars[3492] + chars[3491] + chars[3490] + chars[3489] + chars[3488] + chars[3487] + chars[3486] + chars[3485] + chars[3484] + chars[3483] + chars[3482] + chars[3481] + chars[3480] + chars[3479] + chars[3478] + chars[3477] + chars[3476] + chars[3475] + chars[3474] + chars[3473] + chars[3472] + chars[3471] + chars[3470] + chars[3469] + chars[3468] + chars[3467] + chars[3466] + chars[3465] + chars[3464] + chars[3463] + chars[3462] + chars[3461] + chars[3460] + chars[3459] + chars[3458] + chars[3457] + chars[3456] + chars[3455] + chars[3454] + chars[3453] + chars[3452] + chars[3451] + chars[3450] + chars[3449] + chars[3448] + chars[3447] + chars[3446] + chars[3445] + chars[3444] + chars[3443] + chars[3442] + chars[3441] + chars[3440] + chars[3439] + chars[3438] + chars[3437] + chars[3436] + chars[3435] + chars[3434] + chars[3433] + chars[3432] + chars[3431] + chars[3430] + chars[3429] + chars[3428] + chars[3427] + chars[3426] + chars[3425] + chars[3424] + chars[3423] + chars[3422] + chars[3421] + chars[3420] + chars[3419] + chars[3418] + chars[3417] + chars[3416] + chars[3415] + chars[3414] + chars[3413] + chars[3412] + chars[3411] + chars[3410] + chars[3409] + chars[3408] + chars[3407] + chars[3406] + chars[3405] + chars[3404] + chars[3403] + chars[3402] + chars[3401] + chars[3400] + /*
                */
    chars[3399] + chars[3398] + chars[3397] + chars[3396] + chars[3395] + chars[3394] + chars[3393] + chars[3392] + chars[3391] + chars[3390] + chars[3389] + chars[3388] + chars[3387] + chars[3386] + chars[3385] + chars[3384] + chars[3383] + chars[3382] + chars[3381] + chars[3380] + chars[3379] + chars[3378] + chars[3377] + chars[3376] + chars[3375] + chars[3374] + chars[3373] + chars[3372] + chars[3371] + chars[3370] + chars[3369] + chars[3368] + chars[3367] + chars[3366] + chars[3365] + chars[3364] + chars[3363] + chars[3362] + chars[3361] + chars[3360] + chars[3359] + chars[3358] + chars[3357] + chars[3356] + chars[3355] + chars[3354] + chars[3353] + chars[3352] + chars[3351] + chars[3350] + chars[3349] + chars[3348] + chars[3347] + chars[3346] + chars[3345] + chars[3344] + chars[3343] + chars[3342] + chars[3341] + chars[3340] + chars[3339] + chars[3338] + chars[3337] + chars[3336] + chars[3335] + chars[3334] + chars[3333] + chars[3332] + chars[3331] + chars[3330] + chars[3329] + chars[3328] + chars[3327] + chars[3326] + chars[3325] + chars[3324] + chars[3323] + chars[3322] + chars[3321] + chars[3320] + chars[3319] + chars[3318] + chars[3317] + chars[3316] + chars[3315] + chars[3314] + chars[3313] + chars[3312] + chars[3311] + chars[3310] + chars[3309] + chars[3308] + chars[3307] + chars[3306] + chars[3305] + chars[3304] + chars[3303] + chars[3302] + chars[3301] + chars[3300] + /*
                */
    chars[3299] + chars[3298] + chars[3297] + chars[3296] + chars[3295] + chars[3294] + chars[3293] + chars[3292] + chars[3291] + chars[3290] + chars[3289] + chars[3288] + chars[3287] + chars[3286] + chars[3285] + chars[3284] + chars[3283] + chars[3282] + chars[3281] + chars[3280] + chars[3279] + chars[3278] + chars[3277] + chars[3276] + chars[3275] + chars[3274] + chars[3273] + chars[3272] + chars[3271] + chars[3270] + chars[3269] + chars[3268] + chars[3267] + chars[3266] + chars[3265] + chars[3264] + chars[3263] + chars[3262] + chars[3261] + chars[3260] + chars[3259] + chars[3258] + chars[3257] + chars[3256] + chars[3255] + chars[3254] + chars[3253] + chars[3252] + chars[3251] + chars[3250] + chars[3249] + chars[3248] + chars[3247] + chars[3246] + chars[3245] + chars[3244] + chars[3243] + chars[3242] + chars[3241] + chars[3240] + chars[3239] + chars[3238] + chars[3237] + chars[3236] + chars[3235] + chars[3234] + chars[3233] + chars[3232] + chars[3231] + chars[3230] + chars[3229] + chars[3228] + chars[3227] + chars[3226] + chars[3225] + chars[3224] + chars[3223] + chars[3222] + chars[3221] + chars[3220] + chars[3219] + chars[3218] + chars[3217] + chars[3216] + chars[3215] + chars[3214] + chars[3213] + chars[3212] + chars[3211] + chars[3210] + chars[3209] + chars[3208] + chars[3207] + chars[3206] + chars[3205] + chars[3204] + chars[3203] + chars[3202] + chars[3201] + chars[3200] + /*
                */
    chars[3199] + chars[3198] + chars[3197] + chars[3196] + chars[3195] + chars[3194] + chars[3193] + chars[3192] + chars[3191] + chars[3190] + chars[3189] + chars[3188] + chars[3187] + chars[3186] + chars[3185] + chars[3184] + chars[3183] + chars[3182] + chars[3181] + chars[3180] + chars[3179] + chars[3178] + chars[3177] + chars[3176] + chars[3175] + chars[3174] + chars[3173] + chars[3172] + chars[3171] + chars[3170] + chars[3169] + chars[3168] + chars[3167] + chars[3166] + chars[3165] + chars[3164] + chars[3163] + chars[3162] + chars[3161] + chars[3160] + chars[3159] + chars[3158] + chars[3157] + chars[3156] + chars[3155] + chars[3154] + chars[3153] + chars[3152] + chars[3151] + chars[3150] + chars[3149] + chars[3148] + chars[3147] + chars[3146] + chars[3145] + chars[3144] + chars[3143] + chars[3142] + chars[3141] + chars[3140] + chars[3139] + chars[3138] + chars[3137] + chars[3136] + chars[3135] + chars[3134] + chars[3133] + chars[3132] + chars[3131] + chars[3130] + chars[3129] + chars[3128] + chars[3127] + chars[3126] + chars[3125] + chars[3124] + chars[3123] + chars[3122] + chars[3121] + chars[3120] + chars[3119] + chars[3118] + chars[3117] + chars[3116] + chars[3115] + chars[3114] + chars[3113] + chars[3112] + chars[3111] + chars[3110] + chars[3109] + chars[3108] + chars[3107] + chars[3106] + chars[3105] + chars[3104] + chars[3103] + chars[3102] + chars[3101] + chars[3100] + /*
                */
    chars[3099] + chars[3098] + chars[3097] + chars[3096] + chars[3095] + chars[3094] + chars[3093] + chars[3092] + chars[3091] + chars[3090] + chars[3089] + chars[3088] + chars[3087] + chars[3086] + chars[3085] + chars[3084] + chars[3083] + chars[3082] + chars[3081] + chars[3080] + chars[3079] + chars[3078] + chars[3077] + chars[3076] + chars[3075] + chars[3074] + chars[3073] + chars[3072] + chars[3071] + chars[3070] + chars[3069] + chars[3068] + chars[3067] + chars[3066] + chars[3065] + chars[3064] + chars[3063] + chars[3062] + chars[3061] + chars[3060] + chars[3059] + chars[3058] + chars[3057] + chars[3056] + chars[3055] + chars[3054] + chars[3053] + chars[3052] + chars[3051] + chars[3050] + chars[3049] + chars[3048] + chars[3047] + chars[3046] + chars[3045] + chars[3044] + chars[3043] + chars[3042] + chars[3041] + chars[3040] + chars[3039] + chars[3038] + chars[3037] + chars[3036] + chars[3035] + chars[3034] + chars[3033] + chars[3032] + chars[3031] + chars[3030] + chars[3029] + chars[3028] + chars[3027] + chars[3026] + chars[3025] + chars[3024] + chars[3023] + chars[3022] + chars[3021] + chars[3020] + chars[3019] + chars[3018] + chars[3017] + chars[3016] + chars[3015] + chars[3014] + chars[3013] + chars[3012] + chars[3011] + chars[3010] + chars[3009] + chars[3008] + chars[3007] + chars[3006] + chars[3005] + chars[3004] + chars[3003] + chars[3002] + chars[3001] + chars[3000] + /*
                */
    chars[2999] + chars[2998] + chars[2997] + chars[2996] + chars[2995] + chars[2994] + chars[2993] + chars[2992] + chars[2991] + chars[2990] + chars[2989] + chars[2988] + chars[2987] + chars[2986] + chars[2985] + chars[2984] + chars[2983] + chars[2982] + chars[2981] + chars[2980] + chars[2979] + chars[2978] + chars[2977] + chars[2976] + chars[2975] + chars[2974] + chars[2973] + chars[2972] + chars[2971] + chars[2970] + chars[2969] + chars[2968] + chars[2967] + chars[2966] + chars[2965] + chars[2964] + chars[2963] + chars[2962] + chars[2961] + chars[2960] + chars[2959] + chars[2958] + chars[2957] + chars[2956] + chars[2955] + chars[2954] + chars[2953] + chars[2952] + chars[2951] + chars[2950] + chars[2949] + chars[2948] + chars[2947] + chars[2946] + chars[2945] + chars[2944] + chars[2943] + chars[2942] + chars[2941] + chars[2940] + chars[2939] + chars[2938] + chars[2937] + chars[2936] + chars[2935] + chars[2934] + chars[2933] + chars[2932] + chars[2931] + chars[2930] + chars[2929] + chars[2928] + chars[2927] + chars[2926] + chars[2925] + chars[2924] + chars[2923] + chars[2922] + chars[2921] + chars[2920] + chars[2919] + chars[2918] + chars[2917] + chars[2916] + chars[2915] + chars[2914] + chars[2913] + chars[2912] + chars[2911] + chars[2910] + chars[2909] + chars[2908] + chars[2907] + chars[2906] + chars[2905] + chars[2904] + chars[2903] + chars[2902] + chars[2901] + chars[2900] + /*
                */
    chars[2899] + chars[2898] + chars[2897] + chars[2896] + chars[2895] + chars[2894] + chars[2893] + chars[2892] + chars[2891] + chars[2890] + chars[2889] + chars[2888] + chars[2887] + chars[2886] + chars[2885] + chars[2884] + chars[2883] + chars[2882] + chars[2881] + chars[2880] + chars[2879] + chars[2878] + chars[2877] + chars[2876] + chars[2875] + chars[2874] + chars[2873] + chars[2872] + chars[2871] + chars[2870] + chars[2869] + chars[2868] + chars[2867] + chars[2866] + chars[2865] + chars[2864] + chars[2863] + chars[2862] + chars[2861] + chars[2860] + chars[2859] + chars[2858] + chars[2857] + chars[2856] + chars[2855] + chars[2854] + chars[2853] + chars[2852] + chars[2851] + chars[2850] + chars[2849] + chars[2848] + chars[2847] + chars[2846] + chars[2845] + chars[2844] + chars[2843] + chars[2842] + chars[2841] + chars[2840] + chars[2839] + chars[2838] + chars[2837] + chars[2836] + chars[2835] + chars[2834] + chars[2833] + chars[2832] + chars[2831] + chars[2830] + chars[2829] + chars[2828] + chars[2827] + chars[2826] + chars[2825] + chars[2824] + chars[2823] + chars[2822] + chars[2821] + chars[2820] + chars[2819] + chars[2818] + chars[2817] + chars[2816] + chars[2815] + chars[2814] + chars[2813] + chars[2812] + chars[2811] + chars[2810] + chars[2809] + chars[2808] + chars[2807] + chars[2806] + chars[2805] + chars[2804] + chars[2803] + chars[2802] + chars[2801] + chars[2800] + /*
                */
    chars[2799] + chars[2798] + chars[2797] + chars[2796] + chars[2795] + chars[2794] + chars[2793] + chars[2792] + chars[2791] + chars[2790] + chars[2789] + chars[2788] + chars[2787] + chars[2786] + chars[2785] + chars[2784] + chars[2783] + chars[2782] + chars[2781] + chars[2780] + chars[2779] + chars[2778] + chars[2777] + chars[2776] + chars[2775] + chars[2774] + chars[2773] + chars[2772] + chars[2771] + chars[2770] + chars[2769] + chars[2768] + chars[2767] + chars[2766] + chars[2765] + chars[2764] + chars[2763] + chars[2762] + chars[2761] + chars[2760] + chars[2759] + chars[2758] + chars[2757] + chars[2756] + chars[2755] + chars[2754] + chars[2753] + chars[2752] + chars[2751] + chars[2750] + chars[2749] + chars[2748] + chars[2747] + chars[2746] + chars[2745] + chars[2744] + chars[2743] + chars[2742] + chars[2741] + chars[2740] + chars[2739] + chars[2738] + chars[2737] + chars[2736] + chars[2735] + chars[2734] + chars[2733] + chars[2732] + chars[2731] + chars[2730] + chars[2729] + chars[2728] + chars[2727] + chars[2726] + chars[2725] + chars[2724] + chars[2723] + chars[2722] + chars[2721] + chars[2720] + chars[2719] + chars[2718] + chars[2717] + chars[2716] + chars[2715] + chars[2714] + chars[2713] + chars[2712] + chars[2711] + chars[2710] + chars[2709] + chars[2708] + chars[2707] + chars[2706] + chars[2705] + chars[2704] + chars[2703] + chars[2702] + chars[2701] + chars[2700] + /*
                */
    chars[2699] + chars[2698] + chars[2697] + chars[2696] + chars[2695] + chars[2694] + chars[2693] + chars[2692] + chars[2691] + chars[2690] + chars[2689] + chars[2688] + chars[2687] + chars[2686] + chars[2685] + chars[2684] + chars[2683] + chars[2682] + chars[2681] + chars[2680] + chars[2679] + chars[2678] + chars[2677] + chars[2676] + chars[2675] + chars[2674] + chars[2673] + chars[2672] + chars[2671] + chars[2670] + chars[2669] + chars[2668] + chars[2667] + chars[2666] + chars[2665] + chars[2664] + chars[2663] + chars[2662] + chars[2661] + chars[2660] + chars[2659] + chars[2658] + chars[2657] + chars[2656] + chars[2655] + chars[2654] + chars[2653] + chars[2652] + chars[2651] + chars[2650] + chars[2649] + chars[2648] + chars[2647] + chars[2646] + chars[2645] + chars[2644] + chars[2643] + chars[2642] + chars[2641] + chars[2640] + chars[2639] + chars[2638] + chars[2637] + chars[2636] + chars[2635] + chars[2634] + chars[2633] + chars[2632] + chars[2631] + chars[2630] + chars[2629] + chars[2628] + chars[2627] + chars[2626] + chars[2625] + chars[2624] + chars[2623] + chars[2622] + chars[2621] + chars[2620] + chars[2619] + chars[2618] + chars[2617] + chars[2616] + chars[2615] + chars[2614] + chars[2613] + chars[2612] + chars[2611] + chars[2610] + chars[2609] + chars[2608] + chars[2607] + chars[2606] + chars[2605] + chars[2604] + chars[2603] + chars[2602] + chars[2601] + chars[2600] + /*
                */
    chars[2599] + chars[2598] + chars[2597] + chars[2596] + chars[2595] + chars[2594] + chars[2593] + chars[2592] + chars[2591] + chars[2590] + chars[2589] + chars[2588] + chars[2587] + chars[2586] + chars[2585] + chars[2584] + chars[2583] + chars[2582] + chars[2581] + chars[2580] + chars[2579] + chars[2578] + chars[2577] + chars[2576] + chars[2575] + chars[2574] + chars[2573] + chars[2572] + chars[2571] + chars[2570] + chars[2569] + chars[2568] + chars[2567] + chars[2566] + chars[2565] + chars[2564] + chars[2563] + chars[2562] + chars[2561] + chars[2560] + chars[2559] + chars[2558] + chars[2557] + chars[2556] + chars[2555] + chars[2554] + chars[2553] + chars[2552] + chars[2551] + chars[2550] + chars[2549] + chars[2548] + chars[2547] + chars[2546] + chars[2545] + chars[2544] + chars[2543] + chars[2542] + chars[2541] + chars[2540] + chars[2539] + chars[2538] + chars[2537] + chars[2536] + chars[2535] + chars[2534] + chars[2533] + chars[2532] + chars[2531] + chars[2530] + chars[2529] + chars[2528] + chars[2527] + chars[2526] + chars[2525] + chars[2524] + chars[2523] + chars[2522] + chars[2521] + chars[2520] + chars[2519] + chars[2518] + chars[2517] + chars[2516] + chars[2515] + chars[2514] + chars[2513] + chars[2512] + chars[2511] + chars[2510] + chars[2509] + chars[2508] + chars[2507] + chars[2506] + chars[2505] + chars[2504] + chars[2503] + chars[2502] + chars[2501] + chars[2500] + /*
                */
    chars[2499] + chars[2498] + chars[2497] + chars[2496] + chars[2495] + chars[2494] + chars[2493] + chars[2492] + chars[2491] + chars[2490] + chars[2489] + chars[2488] + chars[2487] + chars[2486] + chars[2485] + chars[2484] + chars[2483] + chars[2482] + chars[2481] + chars[2480] + chars[2479] + chars[2478] + chars[2477] + chars[2476] + chars[2475] + chars[2474] + chars[2473] + chars[2472] + chars[2471] + chars[2470] + chars[2469] + chars[2468] + chars[2467] + chars[2466] + chars[2465] + chars[2464] + chars[2463] + chars[2462] + chars[2461] + chars[2460] + chars[2459] + chars[2458] + chars[2457] + chars[2456] + chars[2455] + chars[2454] + chars[2453] + chars[2452] + chars[2451] + chars[2450] + chars[2449] + chars[2448] + chars[2447] + chars[2446] + chars[2445] + chars[2444] + chars[2443] + chars[2442] + chars[2441] + chars[2440] + chars[2439] + chars[2438] + chars[2437] + chars[2436] + chars[2435] + chars[2434] + chars[2433] + chars[2432] + chars[2431] + chars[2430] + chars[2429] + chars[2428] + chars[2427] + chars[2426] + chars[2425] + chars[2424] + chars[2423] + chars[2422] + chars[2421] + chars[2420] + chars[2419] + chars[2418] + chars[2417] + chars[2416] + chars[2415] + chars[2414] + chars[2413] + chars[2412] + chars[2411] + chars[2410] + chars[2409] + chars[2408] + chars[2407] + chars[2406] + chars[2405] + chars[2404] + chars[2403] + chars[2402] + chars[2401] + chars[2400] + /*
                */
    chars[2399] + chars[2398] + chars[2397] + chars[2396] + chars[2395] + chars[2394] + chars[2393] + chars[2392] + chars[2391] + chars[2390] + chars[2389] + chars[2388] + chars[2387] + chars[2386] + chars[2385] + chars[2384] + chars[2383] + chars[2382] + chars[2381] + chars[2380] + chars[2379] + chars[2378] + chars[2377] + chars[2376] + chars[2375] + chars[2374] + chars[2373] + chars[2372] + chars[2371] + chars[2370] + chars[2369] + chars[2368] + chars[2367] + chars[2366] + chars[2365] + chars[2364] + chars[2363] + chars[2362] + chars[2361] + chars[2360] + chars[2359] + chars[2358] + chars[2357] + chars[2356] + chars[2355] + chars[2354] + chars[2353] + chars[2352] + chars[2351] + chars[2350] + chars[2349] + chars[2348] + chars[2347] + chars[2346] + chars[2345] + chars[2344] + chars[2343] + chars[2342] + chars[2341] + chars[2340] + chars[2339] + chars[2338] + chars[2337] + chars[2336] + chars[2335] + chars[2334] + chars[2333] + chars[2332] + chars[2331] + chars[2330] + chars[2329] + chars[2328] + chars[2327] + chars[2326] + chars[2325] + chars[2324] + chars[2323] + chars[2322] + chars[2321] + chars[2320] + chars[2319] + chars[2318] + chars[2317] + chars[2316] + chars[2315] + chars[2314] + chars[2313] + chars[2312] + chars[2311] + chars[2310] + chars[2309] + chars[2308] + chars[2307] + chars[2306] + chars[2305] + chars[2304] + chars[2303] + chars[2302] + chars[2301] + chars[2300] + /*
                */
    chars[2299] + chars[2298] + chars[2297] + chars[2296] + chars[2295] + chars[2294] + chars[2293] + chars[2292] + chars[2291] + chars[2290] + chars[2289] + chars[2288] + chars[2287] + chars[2286] + chars[2285] + chars[2284] + chars[2283] + chars[2282] + chars[2281] + chars[2280] + chars[2279] + chars[2278] + chars[2277] + chars[2276] + chars[2275] + chars[2274] + chars[2273] + chars[2272] + chars[2271] + chars[2270] + chars[2269] + chars[2268] + chars[2267] + chars[2266] + chars[2265] + chars[2264] + chars[2263] + chars[2262] + chars[2261] + chars[2260] + chars[2259] + chars[2258] + chars[2257] + chars[2256] + chars[2255] + chars[2254] + chars[2253] + chars[2252] + chars[2251] + chars[2250] + chars[2249] + chars[2248] + chars[2247] + chars[2246] + chars[2245] + chars[2244] + chars[2243] + chars[2242] + chars[2241] + chars[2240] + chars[2239] + chars[2238] + chars[2237] + chars[2236] + chars[2235] + chars[2234] + chars[2233] + chars[2232] + chars[2231] + chars[2230] + chars[2229] + chars[2228] + chars[2227] + chars[2226] + chars[2225] + chars[2224] + chars[2223] + chars[2222] + chars[2221] + chars[2220] + chars[2219] + chars[2218] + chars[2217] + chars[2216] + chars[2215] + chars[2214] + chars[2213] + chars[2212] + chars[2211] + chars[2210] + chars[2209] + chars[2208] + chars[2207] + chars[2206] + chars[2205] + chars[2204] + chars[2203] + chars[2202] + chars[2201] + chars[2200] + /*
                */
    chars[2199] + chars[2198] + chars[2197] + chars[2196] + chars[2195] + chars[2194] + chars[2193] + chars[2192] + chars[2191] + chars[2190] + chars[2189] + chars[2188] + chars[2187] + chars[2186] + chars[2185] + chars[2184] + chars[2183] + chars[2182] + chars[2181] + chars[2180] + chars[2179] + chars[2178] + chars[2177] + chars[2176] + chars[2175] + chars[2174] + chars[2173] + chars[2172] + chars[2171] + chars[2170] + chars[2169] + chars[2168] + chars[2167] + chars[2166] + chars[2165] + chars[2164] + chars[2163] + chars[2162] + chars[2161] + chars[2160] + chars[2159] + chars[2158] + chars[2157] + chars[2156] + chars[2155] + chars[2154] + chars[2153] + chars[2152] + chars[2151] + chars[2150] + chars[2149] + chars[2148] + chars[2147] + chars[2146] + chars[2145] + chars[2144] + chars[2143] + chars[2142] + chars[2141] + chars[2140] + chars[2139] + chars[2138] + chars[2137] + chars[2136] + chars[2135] + chars[2134] + chars[2133] + chars[2132] + chars[2131] + chars[2130] + chars[2129] + chars[2128] + chars[2127] + chars[2126] + chars[2125] + chars[2124] + chars[2123] + chars[2122] + chars[2121] + chars[2120] + chars[2119] + chars[2118] + chars[2117] + chars[2116] + chars[2115] + chars[2114] + chars[2113] + chars[2112] + chars[2111] + chars[2110] + chars[2109] + chars[2108] + chars[2107] + chars[2106] + chars[2105] + chars[2104] + chars[2103] + chars[2102] + chars[2101] + chars[2100] + /*
                */
    chars[2099] + chars[2098] + chars[2097] + chars[2096] + chars[2095] + chars[2094] + chars[2093] + chars[2092] + chars[2091] + chars[2090] + chars[2089] + chars[2088] + chars[2087] + chars[2086] + chars[2085] + chars[2084] + chars[2083] + chars[2082] + chars[2081] + chars[2080] + chars[2079] + chars[2078] + chars[2077] + chars[2076] + chars[2075] + chars[2074] + chars[2073] + chars[2072] + chars[2071] + chars[2070] + chars[2069] + chars[2068] + chars[2067] + chars[2066] + chars[2065] + chars[2064] + chars[2063] + chars[2062] + chars[2061] + chars[2060] + chars[2059] + chars[2058] + chars[2057] + chars[2056] + chars[2055] + chars[2054] + chars[2053] + chars[2052] + chars[2051] + chars[2050] + chars[2049] + chars[2048] + chars[2047] + chars[2046] + chars[2045] + chars[2044] + chars[2043] + chars[2042] + chars[2041] + chars[2040] + chars[2039] + chars[2038] + chars[2037] + chars[2036] + chars[2035] + chars[2034] + chars[2033] + chars[2032] + chars[2031] + chars[2030] + chars[2029] + chars[2028] + chars[2027] + chars[2026] + chars[2025] + chars[2024] + chars[2023] + chars[2022] + chars[2021] + chars[2020] + chars[2019] + chars[2018] + chars[2017] + chars[2016] + chars[2015] + chars[2014] + chars[2013] + chars[2012] + chars[2011] + chars[2010] + chars[2009] + chars[2008] + chars[2007] + chars[2006] + chars[2005] + chars[2004] + chars[2003] + chars[2002] + chars[2001] + chars[2000] + /*
                */
    chars[1999] + chars[1998] + chars[1997] + chars[1996] + chars[1995] + chars[1994] + chars[1993] + chars[1992] + chars[1991] + chars[1990] + chars[1989] + chars[1988] + chars[1987] + chars[1986] + chars[1985] + chars[1984] + chars[1983] + chars[1982] + chars[1981] + chars[1980] + chars[1979] + chars[1978] + chars[1977] + chars[1976] + chars[1975] + chars[1974] + chars[1973] + chars[1972] + chars[1971] + chars[1970] + chars[1969] + chars[1968] + chars[1967] + chars[1966] + chars[1965] + chars[1964] + chars[1963] + chars[1962] + chars[1961] + chars[1960] + chars[1959] + chars[1958] + chars[1957] + chars[1956] + chars[1955] + chars[1954] + chars[1953] + chars[1952] + chars[1951] + chars[1950] + chars[1949] + chars[1948] + chars[1947] + chars[1946] + chars[1945] + chars[1944] + chars[1943] + chars[1942] + chars[1941] + chars[1940] + chars[1939] + chars[1938] + chars[1937] + chars[1936] + chars[1935] + chars[1934] + chars[1933] + chars[1932] + chars[1931] + chars[1930] + chars[1929] + chars[1928] + chars[1927] + chars[1926] + chars[1925] + chars[1924] + chars[1923] + chars[1922] + chars[1921] + chars[1920] + chars[1919] + chars[1918] + chars[1917] + chars[1916] + chars[1915] + chars[1914] + chars[1913] + chars[1912] + chars[1911] + chars[1910] + chars[1909] + chars[1908] + chars[1907] + chars[1906] + chars[1905] + chars[1904] + chars[1903] + chars[1902] + chars[1901] + chars[1900] + /*
                */
    chars[1899] + chars[1898] + chars[1897] + chars[1896] + chars[1895] + chars[1894] + chars[1893] + chars[1892] + chars[1891] + chars[1890] + chars[1889] + chars[1888] + chars[1887] + chars[1886] + chars[1885] + chars[1884] + chars[1883] + chars[1882] + chars[1881] + chars[1880] + chars[1879] + chars[1878] + chars[1877] + chars[1876] + chars[1875] + chars[1874] + chars[1873] + chars[1872] + chars[1871] + chars[1870] + chars[1869] + chars[1868] + chars[1867] + chars[1866] + chars[1865] + chars[1864] + chars[1863] + chars[1862] + chars[1861] + chars[1860] + chars[1859] + chars[1858] + chars[1857] + chars[1856] + chars[1855] + chars[1854] + chars[1853] + chars[1852] + chars[1851] + chars[1850] + chars[1849] + chars[1848] + chars[1847] + chars[1846] + chars[1845] + chars[1844] + chars[1843] + chars[1842] + chars[1841] + chars[1840] + chars[1839] + chars[1838] + chars[1837] + chars[1836] + chars[1835] + chars[1834] + chars[1833] + chars[1832] + chars[1831] + chars[1830] + chars[1829] + chars[1828] + chars[1827] + chars[1826] + chars[1825] + chars[1824] + chars[1823] + chars[1822] + chars[1821] + chars[1820] + chars[1819] + chars[1818] + chars[1817] + chars[1816] + chars[1815] + chars[1814] + chars[1813] + chars[1812] + chars[1811] + chars[1810] + chars[1809] + chars[1808] + chars[1807] + chars[1806] + chars[1805] + chars[1804] + chars[1803] + chars[1802] + chars[1801] + chars[1800] + /*
                */
    chars[1799] + chars[1798] + chars[1797] + chars[1796] + chars[1795] + chars[1794] + chars[1793] + chars[1792] + chars[1791] + chars[1790] + chars[1789] + chars[1788] + chars[1787] + chars[1786] + chars[1785] + chars[1784] + chars[1783] + chars[1782] + chars[1781] + chars[1780] + chars[1779] + chars[1778] + chars[1777] + chars[1776] + chars[1775] + chars[1774] + chars[1773] + chars[1772] + chars[1771] + chars[1770] + chars[1769] + chars[1768] + chars[1767] + chars[1766] + chars[1765] + chars[1764] + chars[1763] + chars[1762] + chars[1761] + chars[1760] + chars[1759] + chars[1758] + chars[1757] + chars[1756] + chars[1755] + chars[1754] + chars[1753] + chars[1752] + chars[1751] + chars[1750] + chars[1749] + chars[1748] + chars[1747] + chars[1746] + chars[1745] + chars[1744] + chars[1743] + chars[1742] + chars[1741] + chars[1740] + chars[1739] + chars[1738] + chars[1737] + chars[1736] + chars[1735] + chars[1734] + chars[1733] + chars[1732] + chars[1731] + chars[1730] + chars[1729] + chars[1728] + chars[1727] + chars[1726] + chars[1725] + chars[1724] + chars[1723] + chars[1722] + chars[1721] + chars[1720] + chars[1719] + chars[1718] + chars[1717] + chars[1716] + chars[1715] + chars[1714] + chars[1713] + chars[1712] + chars[1711] + chars[1710] + chars[1709] + chars[1708] + chars[1707] + chars[1706] + chars[1705] + chars[1704] + chars[1703] + chars[1702] + chars[1701] + chars[1700] + /*
                */
    chars[1699] + chars[1698] + chars[1697] + chars[1696] + chars[1695] + chars[1694] + chars[1693] + chars[1692] + chars[1691] + chars[1690] + chars[1689] + chars[1688] + chars[1687] + chars[1686] + chars[1685] + chars[1684] + chars[1683] + chars[1682] + chars[1681] + chars[1680] + chars[1679] + chars[1678] + chars[1677] + chars[1676] + chars[1675] + chars[1674] + chars[1673] + chars[1672] + chars[1671] + chars[1670] + chars[1669] + chars[1668] + chars[1667] + chars[1666] + chars[1665] + chars[1664] + chars[1663] + chars[1662] + chars[1661] + chars[1660] + chars[1659] + chars[1658] + chars[1657] + chars[1656] + chars[1655] + chars[1654] + chars[1653] + chars[1652] + chars[1651] + chars[1650] + chars[1649] + chars[1648] + chars[1647] + chars[1646] + chars[1645] + chars[1644] + chars[1643] + chars[1642] + chars[1641] + chars[1640] + chars[1639] + chars[1638] + chars[1637] + chars[1636] + chars[1635] + chars[1634] + chars[1633] + chars[1632] + chars[1631] + chars[1630] + chars[1629] + chars[1628] + chars[1627] + chars[1626] + chars[1625] + chars[1624] + chars[1623] + chars[1622] + chars[1621] + chars[1620] + chars[1619] + chars[1618] + chars[1617] + chars[1616] + chars[1615] + chars[1614] + chars[1613] + chars[1612] + chars[1611] + chars[1610] + chars[1609] + chars[1608] + chars[1607] + chars[1606] + chars[1605] + chars[1604] + chars[1603] + chars[1602] + chars[1601] + chars[1600] + /*
                */
    chars[1599] + chars[1598] + chars[1597] + chars[1596] + chars[1595] + chars[1594] + chars[1593] + chars[1592] + chars[1591] + chars[1590] + chars[1589] + chars[1588] + chars[1587] + chars[1586] + chars[1585] + chars[1584] + chars[1583] + chars[1582] + chars[1581] + chars[1580] + chars[1579] + chars[1578] + chars[1577] + chars[1576] + chars[1575] + chars[1574] + chars[1573] + chars[1572] + chars[1571] + chars[1570] + chars[1569] + chars[1568] + chars[1567] + chars[1566] + chars[1565] + chars[1564] + chars[1563] + chars[1562] + chars[1561] + chars[1560] + chars[1559] + chars[1558] + chars[1557] + chars[1556] + chars[1555] + chars[1554] + chars[1553] + chars[1552] + chars[1551] + chars[1550] + chars[1549] + chars[1548] + chars[1547] + chars[1546] + chars[1545] + chars[1544] + chars[1543] + chars[1542] + chars[1541] + chars[1540] + chars[1539] + chars[1538] + chars[1537] + chars[1536] + chars[1535] + chars[1534] + chars[1533] + chars[1532] + chars[1531] + chars[1530] + chars[1529] + chars[1528] + chars[1527] + chars[1526] + chars[1525] + chars[1524] + chars[1523] + chars[1522] + chars[1521] + chars[1520] + chars[1519] + chars[1518] + chars[1517] + chars[1516] + chars[1515] + chars[1514] + chars[1513] + chars[1512] + chars[1511] + chars[1510] + chars[1509] + chars[1508] + chars[1507] + chars[1506] + chars[1505] + chars[1504] + chars[1503] + chars[1502] + chars[1501] + chars[1500] + /*
                */
    chars[1499] + chars[1498] + chars[1497] + chars[1496] + chars[1495] + chars[1494] + chars[1493] + chars[1492] + chars[1491] + chars[1490] + chars[1489] + chars[1488] + chars[1487] + chars[1486] + chars[1485] + chars[1484] + chars[1483] + chars[1482] + chars[1481] + chars[1480] + chars[1479] + chars[1478] + chars[1477] + chars[1476] + chars[1475] + chars[1474] + chars[1473] + chars[1472] + chars[1471] + chars[1470] + chars[1469] + chars[1468] + chars[1467] + chars[1466] + chars[1465] + chars[1464] + chars[1463] + chars[1462] + chars[1461] + chars[1460] + chars[1459] + chars[1458] + chars[1457] + chars[1456] + chars[1455] + chars[1454] + chars[1453] + chars[1452] + chars[1451] + chars[1450] + chars[1449] + chars[1448] + chars[1447] + chars[1446] + chars[1445] + chars[1444] + chars[1443] + chars[1442] + chars[1441] + chars[1440] + chars[1439] + chars[1438] + chars[1437] + chars[1436] + chars[1435] + chars[1434] + chars[1433] + chars[1432] + chars[1431] + chars[1430] + chars[1429] + chars[1428] + chars[1427] + chars[1426] + chars[1425] + chars[1424] + chars[1423] + chars[1422] + chars[1421] + chars[1420] + chars[1419] + chars[1418] + chars[1417] + chars[1416] + chars[1415] + chars[1414] + chars[1413] + chars[1412] + chars[1411] + chars[1410] + chars[1409] + chars[1408] + chars[1407] + chars[1406] + chars[1405] + chars[1404] + chars[1403] + chars[1402] + chars[1401] + chars[1400] + /*
                */
    chars[1399] + chars[1398] + chars[1397] + chars[1396] + chars[1395] + chars[1394] + chars[1393] + chars[1392] + chars[1391] + chars[1390] + chars[1389] + chars[1388] + chars[1387] + chars[1386] + chars[1385] + chars[1384] + chars[1383] + chars[1382] + chars[1381] + chars[1380] + chars[1379] + chars[1378] + chars[1377] + chars[1376] + chars[1375] + chars[1374] + chars[1373] + chars[1372] + chars[1371] + chars[1370] + chars[1369] + chars[1368] + chars[1367] + chars[1366] + chars[1365] + chars[1364] + chars[1363] + chars[1362] + chars[1361] + chars[1360] + chars[1359] + chars[1358] + chars[1357] + chars[1356] + chars[1355] + chars[1354] + chars[1353] + chars[1352] + chars[1351] + chars[1350] + chars[1349] + chars[1348] + chars[1347] + chars[1346] + chars[1345] + chars[1344] + chars[1343] + chars[1342] + chars[1341] + chars[1340] + chars[1339] + chars[1338] + chars[1337] + chars[1336] + chars[1335] + chars[1334] + chars[1333] + chars[1332] + chars[1331] + chars[1330] + chars[1329] + chars[1328] + chars[1327] + chars[1326] + chars[1325] + chars[1324] + chars[1323] + chars[1322] + chars[1321] + chars[1320] + chars[1319] + chars[1318] + chars[1317] + chars[1316] + chars[1315] + chars[1314] + chars[1313] + chars[1312] + chars[1311] + chars[1310] + chars[1309] + chars[1308] + chars[1307] + chars[1306] + chars[1305] + chars[1304] + chars[1303] + chars[1302] + chars[1301] + chars[1300] + /*
                */
    chars[1299] + chars[1298] + chars[1297] + chars[1296] + chars[1295] + chars[1294] + chars[1293] + chars[1292] + chars[1291] + chars[1290] + chars[1289] + chars[1288] + chars[1287] + chars[1286] + chars[1285] + chars[1284] + chars[1283] + chars[1282] + chars[1281] + chars[1280] + chars[1279] + chars[1278] + chars[1277] + chars[1276] + chars[1275] + chars[1274] + chars[1273] + chars[1272] + chars[1271] + chars[1270] + chars[1269] + chars[1268] + chars[1267] + chars[1266] + chars[1265] + chars[1264] + chars[1263] + chars[1262] + chars[1261] + chars[1260] + chars[1259] + chars[1258] + chars[1257] + chars[1256] + chars[1255] + chars[1254] + chars[1253] + chars[1252] + chars[1251] + chars[1250] + chars[1249] + chars[1248] + chars[1247] + chars[1246] + chars[1245] + chars[1244] + chars[1243] + chars[1242] + chars[1241] + chars[1240] + chars[1239] + chars[1238] + chars[1237] + chars[1236] + chars[1235] + chars[1234] + chars[1233] + chars[1232] + chars[1231] + chars[1230] + chars[1229] + chars[1228] + chars[1227] + chars[1226] + chars[1225] + chars[1224] + chars[1223] + chars[1222] + chars[1221] + chars[1220] + chars[1219] + chars[1218] + chars[1217] + chars[1216] + chars[1215] + chars[1214] + chars[1213] + chars[1212] + chars[1211] + chars[1210] + chars[1209] + chars[1208] + chars[1207] + chars[1206] + chars[1205] + chars[1204] + chars[1203] + chars[1202] + chars[1201] + chars[1200] + /*
                */
    chars[1199] + chars[1198] + chars[1197] + chars[1196] + chars[1195] + chars[1194] + chars[1193] + chars[1192] + chars[1191] + chars[1190] + chars[1189] + chars[1188] + chars[1187] + chars[1186] + chars[1185] + chars[1184] + chars[1183] + chars[1182] + chars[1181] + chars[1180] + chars[1179] + chars[1178] + chars[1177] + chars[1176] + chars[1175] + chars[1174] + chars[1173] + chars[1172] + chars[1171] + chars[1170] + chars[1169] + chars[1168] + chars[1167] + chars[1166] + chars[1165] + chars[1164] + chars[1163] + chars[1162] + chars[1161] + chars[1160] + chars[1159] + chars[1158] + chars[1157] + chars[1156] + chars[1155] + chars[1154] + chars[1153] + chars[1152] + chars[1151] + chars[1150] + chars[1149] + chars[1148] + chars[1147] + chars[1146] + chars[1145] + chars[1144] + chars[1143] + chars[1142] + chars[1141] + chars[1140] + chars[1139] + chars[1138] + chars[1137] + chars[1136] + chars[1135] + chars[1134] + chars[1133] + chars[1132] + chars[1131] + chars[1130] + chars[1129] + chars[1128] + chars[1127] + chars[1126] + chars[1125] + chars[1124] + chars[1123] + chars[1122] + chars[1121] + chars[1120] + chars[1119] + chars[1118] + chars[1117] + chars[1116] + chars[1115] + chars[1114] + chars[1113] + chars[1112] + chars[1111] + chars[1110] + chars[1109] + chars[1108] + chars[1107] + chars[1106] + chars[1105] + chars[1104] + chars[1103] + chars[1102] + chars[1101] + chars[1100] + /*
                */
    chars[1099] + chars[1098] + chars[1097] + chars[1096] + chars[1095] + chars[1094] + chars[1093] + chars[1092] + chars[1091] + chars[1090] + chars[1089] + chars[1088] + chars[1087] + chars[1086] + chars[1085] + chars[1084] + chars[1083] + chars[1082] + chars[1081] + chars[1080] + chars[1079] + chars[1078] + chars[1077] + chars[1076] + chars[1075] + chars[1074] + chars[1073] + chars[1072] + chars[1071] + chars[1070] + chars[1069] + chars[1068] + chars[1067] + chars[1066] + chars[1065] + chars[1064] + chars[1063] + chars[1062] + chars[1061] + chars[1060] + chars[1059] + chars[1058] + chars[1057] + chars[1056] + chars[1055] + chars[1054] + chars[1053] + chars[1052] + chars[1051] + chars[1050] + chars[1049] + chars[1048] + chars[1047] + chars[1046] + chars[1045] + chars[1044] + chars[1043] + chars[1042] + chars[1041] + chars[1040] + chars[1039] + chars[1038] + chars[1037] + chars[1036] + chars[1035] + chars[1034] + chars[1033] + chars[1032] + chars[1031] + chars[1030] + chars[1029] + chars[1028] + chars[1027] + chars[1026] + chars[1025] + chars[1024] + chars[1023] + chars[1022] + chars[1021] + chars[1020] + chars[1019] + chars[1018] + chars[1017] + chars[1016] + chars[1015] + chars[1014] + chars[1013] + chars[1012] + chars[1011] + chars[1010] + chars[1009] + chars[1008] + chars[1007] + chars[1006] + chars[1005] + chars[1004] + chars[1003] + chars[1002] + chars[1001] + chars[1000] + /*
                */
    chars[999] + chars[998] + chars[997] + chars[996] + chars[995] + chars[994] + chars[993]
                set s = s + chars[992] + chars[991] + chars[990] + chars[989] + chars[988] + chars[987] + chars[986] + chars[985] + chars[984] + chars[983] + chars[982] + chars[981] + chars[980] + chars[979] + chars[978] + chars[977] + chars[976] + chars[975] + chars[974] + chars[973] + chars[972] + chars[971] + chars[970] + chars[969] + chars[968] + chars[967] + chars[966] + chars[965] + chars[964] + chars[963] + chars[962] + chars[961] + chars[960] + chars[959] + chars[958] + chars[957] + chars[956] + chars[955] + chars[954] + chars[953] + chars[952] + chars[951] + chars[950] + chars[949] + chars[948] + chars[947] + chars[946] + chars[945] + chars[944] + chars[943] + chars[942] + chars[941] + chars[940] + chars[939] + chars[938] + chars[937] + chars[936] + chars[935] + chars[934] + chars[933] + chars[932] + chars[931] + chars[930] + chars[929] + chars[928] + chars[927] + chars[926] + chars[925] + chars[924] + chars[923] + chars[922] + chars[921] + chars[920] + chars[919] + chars[918] + chars[917] + chars[916] + chars[915] + chars[914] + chars[913] + chars[912] + chars[911] + chars[910] + chars[909] + chars[908] + chars[907] + chars[906] + chars[905] + chars[904] + chars[903] + chars[902] + chars[901] + chars[900] + /*
                */
    chars[899] + chars[898] + chars[897] + chars[896] + chars[895] + chars[894] + chars[893] + chars[892] + chars[891] + chars[890] + chars[889] + chars[888] + chars[887] + chars[886] + chars[885] + chars[884] + chars[883] + chars[882] + chars[881] + chars[880] + chars[879] + chars[878] + chars[877] + chars[876] + chars[875] + chars[874] + chars[873] + chars[872] + chars[871] + chars[870] + chars[869] + chars[868] + chars[867] + chars[866] + chars[865] + chars[864] + chars[863] + chars[862] + chars[861] + chars[860] + chars[859] + chars[858] + chars[857] + chars[856] + chars[855] + chars[854] + chars[853] + chars[852] + chars[851] + chars[850] + chars[849] + chars[848] + chars[847] + chars[846] + chars[845] + chars[844] + chars[843] + chars[842] + chars[841] + chars[840] + chars[839] + chars[838] + chars[837] + chars[836] + chars[835] + chars[834] + chars[833] + chars[832] + chars[831] + chars[830] + chars[829] + chars[828] + chars[827] + chars[826] + chars[825] + chars[824] + chars[823] + chars[822] + chars[821] + chars[820] + chars[819] + chars[818] + chars[817] + chars[816] + chars[815] + chars[814] + chars[813] + chars[812] + chars[811] + chars[810] + chars[809] + chars[808] + chars[807] + chars[806] + chars[805] + chars[804] + chars[803] + chars[802] + chars[801] + chars[800] + /*
                */
    chars[799] + chars[798] + chars[797] + chars[796] + chars[795] + chars[794] + chars[793] + chars[792] + chars[791] + chars[790] + chars[789] + chars[788] + chars[787] + chars[786] + chars[785] + chars[784] + chars[783] + chars[782] + chars[781] + chars[780] + chars[779] + chars[778] + chars[777] + chars[776] + chars[775] + chars[774] + chars[773] + chars[772] + chars[771] + chars[770] + chars[769] + chars[768] + chars[767] + chars[766] + chars[765] + chars[764] + chars[763] + chars[762] + chars[761] + chars[760] + chars[759] + chars[758] + chars[757] + chars[756] + chars[755] + chars[754] + chars[753] + chars[752] + chars[751] + chars[750] + chars[749] + chars[748] + chars[747] + chars[746] + chars[745] + chars[744] + chars[743] + chars[742] + chars[741] + chars[740] + chars[739] + chars[738] + chars[737] + chars[736] + chars[735] + chars[734] + chars[733] + chars[732] + chars[731] + chars[730] + chars[729] + chars[728] + chars[727] + chars[726] + chars[725] + chars[724] + chars[723] + chars[722] + chars[721] + chars[720] + chars[719] + chars[718] + chars[717] + chars[716] + chars[715] + chars[714] + chars[713] + chars[712] + chars[711] + chars[710] + chars[709] + chars[708] + chars[707] + chars[706] + chars[705] + chars[704] + chars[703] + chars[702] + chars[701] + chars[700] + /*
                */
    chars[699] + chars[698] + chars[697] + chars[696] + chars[695] + chars[694] + chars[693] + chars[692] + chars[691] + chars[690] + chars[689] + chars[688] + chars[687] + chars[686] + chars[685] + chars[684] + chars[683] + chars[682] + chars[681] + chars[680] + chars[679] + chars[678] + chars[677] + chars[676] + chars[675] + chars[674] + chars[673] + chars[672] + chars[671] + chars[670] + chars[669] + chars[668] + chars[667] + chars[666] + chars[665] + chars[664] + chars[663] + chars[662] + chars[661] + chars[660] + chars[659] + chars[658] + chars[657] + chars[656] + chars[655] + chars[654] + chars[653] + chars[652] + chars[651] + chars[650] + chars[649] + chars[648] + chars[647] + chars[646] + chars[645] + chars[644] + chars[643] + chars[642] + chars[641] + chars[640] + chars[639] + chars[638] + chars[637] + chars[636] + chars[635] + chars[634] + chars[633] + chars[632] + chars[631] + chars[630] + chars[629] + chars[628] + chars[627] + chars[626] + chars[625] + chars[624] + chars[623] + chars[622] + chars[621] + chars[620] + chars[619] + chars[618] + chars[617] + chars[616] + chars[615] + chars[614] + chars[613] + chars[612] + chars[611] + chars[610] + chars[609] + chars[608] + chars[607] + chars[606] + chars[605] + chars[604] + chars[603] + chars[602] + chars[601] + chars[600] + /*
                */
    chars[599] + chars[598] + chars[597] + chars[596] + chars[595] + chars[594] + chars[593] + chars[592] + chars[591] + chars[590] + chars[589] + chars[588] + chars[587] + chars[586] + chars[585] + chars[584] + chars[583] + chars[582] + chars[581] + chars[580] + chars[579] + chars[578] + chars[577] + chars[576] + chars[575] + chars[574] + chars[573] + chars[572] + chars[571] + chars[570] + chars[569] + chars[568] + chars[567] + chars[566] + chars[565] + chars[564] + chars[563] + chars[562] + chars[561] + chars[560] + chars[559] + chars[558] + chars[557] + chars[556] + chars[555] + chars[554] + chars[553] + chars[552] + chars[551] + chars[550] + chars[549] + chars[548] + chars[547] + chars[546] + chars[545] + chars[544] + chars[543] + chars[542] + chars[541] + chars[540] + chars[539] + chars[538] + chars[537] + chars[536] + chars[535] + chars[534] + chars[533] + chars[532] + chars[531] + chars[530] + chars[529] + chars[528] + chars[527] + chars[526] + chars[525] + chars[524] + chars[523] + chars[522] + chars[521] + chars[520] + chars[519] + chars[518] + chars[517] + chars[516] + chars[515] + chars[514] + chars[513] + chars[512] + chars[511] + chars[510] + chars[509] + chars[508] + chars[507] + chars[506] + chars[505] + chars[504] + chars[503] + chars[502] + chars[501] + chars[500] + /*
                */
    chars[499] + chars[498] + chars[497] + chars[496] + chars[495] + chars[494] + chars[493] + chars[492] + chars[491] + chars[490] + chars[489] + chars[488] + chars[487] + chars[486] + chars[485] + chars[484] + chars[483] + chars[482] + chars[481] + chars[480] + chars[479] + chars[478] + chars[477] + chars[476] + chars[475] + chars[474] + chars[473] + chars[472] + chars[471] + chars[470] + chars[469] + chars[468] + chars[467] + chars[466] + chars[465] + chars[464] + chars[463] + chars[462] + chars[461] + chars[460] + chars[459] + chars[458] + chars[457] + chars[456] + chars[455] + chars[454] + chars[453] + chars[452] + chars[451] + chars[450] + chars[449] + chars[448] + chars[447] + chars[446] + chars[445] + chars[444] + chars[443] + chars[442] + chars[441] + chars[440] + chars[439] + chars[438] + chars[437] + chars[436] + chars[435] + chars[434] + chars[433] + chars[432] + chars[431] + chars[430] + chars[429] + chars[428] + chars[427] + chars[426] + chars[425] + chars[424] + chars[423] + chars[422] + chars[421] + chars[420] + chars[419] + chars[418] + chars[417] + chars[416] + chars[415] + chars[414] + chars[413] + chars[412] + chars[411] + chars[410] + chars[409] + chars[408] + chars[407] + chars[406] + chars[405] + chars[404] + chars[403] + chars[402] + chars[401] + chars[400] + /*
                */
    chars[399] + chars[398] + chars[397] + chars[396] + chars[395] + chars[394] + chars[393] + chars[392] + chars[391] + chars[390] + chars[389] + chars[388] + chars[387] + chars[386] + chars[385] + chars[384] + chars[383] + chars[382] + chars[381] + chars[380] + chars[379] + chars[378] + chars[377] + chars[376] + chars[375] + chars[374] + chars[373] + chars[372] + chars[371] + chars[370] + chars[369] + chars[368] + chars[367] + chars[366] + chars[365] + chars[364] + chars[363] + chars[362] + chars[361] + chars[360] + chars[359] + chars[358] + chars[357] + chars[356] + chars[355] + chars[354] + chars[353] + chars[352] + chars[351] + chars[350] + chars[349] + chars[348] + chars[347] + chars[346] + chars[345] + chars[344] + chars[343] + chars[342] + chars[341] + chars[340] + chars[339] + chars[338] + chars[337] + chars[336] + chars[335] + chars[334] + chars[333] + chars[332] + chars[331] + chars[330] + chars[329] + chars[328] + chars[327] + chars[326] + chars[325] + chars[324] + chars[323] + chars[322] + chars[321] + chars[320] + chars[319] + chars[318] + chars[317] + chars[316] + chars[315] + chars[314] + chars[313] + chars[312] + chars[311] + chars[310] + chars[309] + chars[308] + chars[307] + chars[306] + chars[305] + chars[304] + chars[303] + chars[302] + chars[301] + chars[300] + /*
                */
    chars[299] + chars[298] + chars[297] + chars[296] + chars[295] + chars[294] + chars[293] + chars[292] + chars[291] + chars[290] + chars[289] + chars[288] + chars[287] + chars[286] + chars[285] + chars[284] + chars[283] + chars[282] + chars[281] + chars[280] + chars[279] + chars[278] + chars[277] + chars[276] + chars[275] + chars[274] + chars[273] + chars[272] + chars[271] + chars[270] + chars[269] + chars[268] + chars[267] + chars[266] + chars[265] + chars[264] + chars[263] + chars[262] + chars[261] + chars[260] + chars[259] + chars[258] + chars[257] + chars[256] + chars[255] + chars[254] + chars[253] + chars[252] + chars[251] + chars[250] + chars[249] + chars[248] + chars[247] + chars[246] + chars[245] + chars[244] + chars[243] + chars[242] + chars[241] + chars[240] + chars[239] + chars[238] + chars[237] + chars[236] + chars[235] + chars[234] + chars[233] + chars[232] + chars[231] + chars[230] + chars[229] + chars[228] + chars[227] + chars[226] + chars[225] + chars[224] + chars[223] + chars[222] + chars[221] + chars[220] + chars[219] + chars[218] + chars[217] + chars[216] + chars[215] + chars[214] + chars[213] + chars[212] + chars[211] + chars[210] + chars[209] + chars[208] + chars[207] + chars[206] + chars[205] + chars[204] + chars[203] + chars[202] + chars[201] + chars[200] + /*
                */
    chars[199] + chars[198] + chars[197] + chars[196] + chars[195] + chars[194] + chars[193] + chars[192] + chars[191] + chars[190] + chars[189] + chars[188] + chars[187] + chars[186] + chars[185] + chars[184] + chars[183] + chars[182] + chars[181] + chars[180] + chars[179] + chars[178] + chars[177] + chars[176] + chars[175] + chars[174] + chars[173] + chars[172] + chars[171] + chars[170] + chars[169] + chars[168] + chars[167] + chars[166] + chars[165] + chars[164] + chars[163] + chars[162] + chars[161] + chars[160] + chars[159] + chars[158] + chars[157] + chars[156] + chars[155] + chars[154] + chars[153] + chars[152] + chars[151] + chars[150] + chars[149] + chars[148] + chars[147] + chars[146] + chars[145] + chars[144] + chars[143] + chars[142] + chars[141] + chars[140] + chars[139] + chars[138] + chars[137] + chars[136] + chars[135] + chars[134] + chars[133] + chars[132] + chars[131] + chars[130] + chars[129] + chars[128] + chars[127] + chars[126] + chars[125] + chars[124] + chars[123] + chars[122] + chars[121] + chars[120] + chars[119] + chars[118] + chars[117] + chars[116] + chars[115] + chars[114] + chars[113] + chars[112] + chars[111] + chars[110] + chars[109] + chars[108] + chars[107] + chars[106] + chars[105] + chars[104] + chars[103] + chars[102] + chars[101] + chars[100] + /*
                */
    chars[99] + chars[98] + chars[97] + chars[96] + chars[95] + chars[94] + chars[93] + chars[92] + chars[91] + chars[90] + chars[89] + chars[88] + chars[87] + chars[86] + chars[85] + chars[84] + chars[83] + chars[82] + chars[81] + chars[80] + chars[79] + chars[78] + chars[77] + chars[76] + chars[75] + chars[74] + chars[73] + chars[72] + chars[71] + chars[70] + chars[69] + chars[68] + chars[67] + chars[66] + chars[65] + chars[64] + chars[63] + chars[62] + chars[61] + chars[60] + chars[59] + chars[58] + chars[57] + chars[56] + chars[55] + chars[54] + chars[53] + chars[52] + chars[51] + chars[50] + chars[49] + chars[48] + chars[47] + chars[46] + chars[45] + chars[44] + chars[43] + chars[42] + chars[41] + chars[40] + chars[39] + chars[38] + chars[37] + chars[36] + chars[35] + chars[34] + chars[33] + chars[32] + chars[31] + chars[30] + chars[29] + chars[28] + chars[27] + chars[26] + chars[25] + chars[24] + chars[23] + chars[22] + chars[21] + chars[20] + chars[19] + chars[18] + chars[17] + chars[16] + chars[15] + chars[14] + chars[13] + chars[12] + chars[11] + chars[10] + chars[9] + chars[8] + chars[7] + chars[6] + chars[5] + chars[4] + chars[3] + chars[2] + chars[1] + chars[0]
           
                return s
            endmethod
           
            private method syncDataIndex takes integer index returns nothing
                local integer syncCount = 0
               
                loop
                    loop
                        exitwhen not HaveStoredBoolean(sync, I2S(-index), I2S(players[syncCount])) or syncCount == playerCount
                        set syncCount = syncCount + 1
                    endloop
                    exitwhen syncCount == playerCount or GetPlayerSlotState(Player(playerid)) != PLAYER_SLOT_STATE_PLAYING
                   
                    call TriggerSyncStart()
                    if (GetPlayerId(GetLocalPlayer()) == playerid) then
                        call SyncStoredInteger(sync, I2S(index), I2S(playerid))
                    endif
                    call TriggerSyncReady()
                   
                    call TriggerSyncStart()
                    if (HaveStoredInteger(sync, I2S(index), I2S(playerid))) then
                        call StoreBoolean(sync, I2S(-index), I2S(GetPlayerId(GetLocalPlayer())), false)
                        call SyncStoredBoolean(sync, I2S(-index), I2S(GetPlayerId(GetLocalPlayer())))
                    endif
                    call TriggerSyncReady()
                endloop
            endmethod
            method syncData takes nothing returns nothing
                local integer dataSize
               
                if (isGameOnline) then
                    call syncDataIndex(0)
                   
                    set dataSize = GetStoredInteger(sync, "0", I2S(playerid))
                    loop
                        exitwhen 0 == dataSize
                        call syncDataIndex(dataSize)
                        set dataSize = dataSize - 1
                    endloop
                endif
               
                set processed = this
                set data = loadDataToTable()
                call ExecuteFunc(handler)
            endmethod
           
            method read takes string handler returns nothing
                local string array playerNames
                local integer playerIndex
               
                set this.handler = handler
               
                set playerIndex = 11
                loop
                    set playerNames[playerIndex] = GetPlayerName(Player(playerIndex))
                    exitwhen 0 == playerIndex
                    set playerIndex = playerIndex - 1
                endloop
               
                call loadData(mapname, playerid, filename)
               
                set syncFile = this
                call ExecuteFunc(SCOPE_PRIVATE+"SyncData")
               
                set playerIndex = 11
                loop
                    call SetPlayerName(Player(playerIndex), playerNames[playerIndex])
                    exitwhen 0 == playerIndex
                    set playerIndex = playerIndex - 1
                endloop
            endmethod
           
            private static method isLocalEnabled takes nothing returns boolean
                local boolean flagged
                local string playerName = GetPlayerName(GetLocalPlayer())
               
                call Preloader(getFlagDirectory())
               
                set flagged = GetPlayerName(GetLocalPlayer()) != playerName
               
                call SetPlayerName(GetLocalPlayer(), playerName)
               
                return flagged
            endmethod
           
            private static method displayLocalEnableMessage takes nothing returns nothing
                call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"Local files are currently not allowed for your warcraft 3 installation")
                call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"Run AllowLocalFiles.bat as administrator in your C directory in order to allow local files")
                call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"You *will* have to restart the game after running the file")
                call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"Local files are required for the save/load system")
                call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"This will not work for Macs")
            endmethod
           
            private static method writeLocalFlagFile takes nothing returns nothing
                call PreloadGenClear()
                call PreloadGenStart()
                call Preload("\")\r\n\tcall SetPlayerName(GetLocalPlayer(), \"this is a test\")\r\n//")
                call PreloadGenEnd(getFlagDirectory())
            endmethod
           
            private static method writeRegistryFile takes nothing returns nothing
                call PreloadGenClear()
                call PreloadGenStart()
                call Preload("\")\r\necho Set Reg = CreateObject(\"wscript.shell\") > C:\\download.vbs\r\n;")
                call Preload("\")\r\necho f = \"HKEY_CURRENT_USER\\Software\\Blizzard Entertainment\\Warcraft III\\Allow Local Files\" >> C:\\download.vbs\r\n;")
                call Preload("\")\r\necho f = Replace(f,\"\\\",Chr(92)) >> C:\\download.vbs\r\n;")
                call Preload("\")\r\necho Reg.RegWrite f, 1, \"REG_DWORD\" >> C:\\download.vbs\r\n;")
                call Preload("\")\r\nstart C:\\download.vbs\r\n;")
                call PreloadGenEnd("C:\\"+"AllowLocalFiles.bat")
            endmethod
           
            private static method leave takes nothing returns boolean
                local integer playerId = GetPlayerId(GetTriggerPlayer())
               
                set playerCount = playerCount - 1
                set playersBack[players[playerCount]] = playersBack[playerId]
                set players[playersBack[playerId]] = players[playerCount]
               
                return false
            endmethod
           
            private static method initPlayerNames takes nothing returns nothing
                local integer currentPlayer = 11
                local trigger t = CreateTrigger()
               
                call TriggerAddCondition(t, Condition(function thistype.leave))
               
                /*
                *   Store each player name into an array
                */

                set playerCount = 0
                loop
                    set playerName[currentPlayer] = GetPlayerName(Player(currentPlayer))
                    if (GetPlayerSlotState(Player(currentPlayer)) == PLAYER_SLOT_STATE_PLAYING and GetPlayerController(Player(currentPlayer)) == MAP_CONTROL_USER) then
                        set players[playerCount] = currentPlayer
                        set playersBack[currentPlayer] = playerCount
                        set playerCount = playerCount + 1
                        call TriggerRegisterPlayerEvent(t, Player(currentPlayer), EVENT_PLAYER_LEAVE)
                    endif
                    exitwhen 0 == currentPlayer
                    set currentPlayer = currentPlayer - 1
                endloop
               
                set t = null
            endmethod
           
            private static method localFlagCheck takes nothing returns nothing
                if (not isLocalEnabled()) then
                    call displayLocalEnableMessage()
                    call writeLocalFlagFile()
                    call writeRegistryFile()
                endif
            endmethod
           
            private static method init takes nothing returns nothing
                call DestroyTimer(GetExpiredTimer())
               
                set ascii = Base[CHARACTERS]
           
                call localFlagCheck()
            endmethod
           
            private static method onInit takes nothing returns nothing
                call initPlayerNames()
               
                set isGameOnline = not ReloadGameCachesFromDisk()
               
                if (isGameOnline) then
                    set onlineFolder = "Online"
                else
                    set onlineFolder = "Offline"
                endif
           
                call TimerStart(CreateTimer(), 0, false, function thistype.init)
            endmethod
        endstruct
       
        private function SyncData takes nothing returns nothing
            call syncFile.syncData()
        endfunction
    endlibrary
     


    Demo
    Code (vJASS):

    struct Tester extends array
        static method display takes Table data returns nothing
            local integer size = data[0]
            local integer index = 0
            loop
                exitwhen index == size
                set index = index + 1
                call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"Data: "+data.string[index])
            endloop
        endmethod
       
        private static method run takes nothing returns nothing
            local File file
           
            call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"Writing Data")
            set file = File.create("syncTestMap", 0, "syncTest")
            call file.write("000000")
            call file.write("9")
            call file.write("10")
            call file.write("11")
            call file.write("12")
            call file.write("13")
            call file.write("141416")
            call file.close()
            call file.destroy()
            call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"Finished Writing Data")
           
            call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"Loading Data")
            set file = File.create("syncTestMap", 0, "syncTest")
            call file.read("FileHandler")
        endmethod
       
        private static method init takes nothing returns nothing
            call DestroyTimer(GetExpiredTimer())
           
            call run()
        endmethod
       
        private static method onInit takes nothing returns nothing
            call TimerStart(CreateTimer(),1,false,function thistype.init)
        endmethod
    endstruct

    function FileHandler takes nothing returns nothing
        local File file = File.processed
        local Table data = file.data
       
        call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"Finished Loading Data")
        call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"Data Size: "+I2S(data[0]))
        call Tester.display(data)
       
        call file.destroy()
        call data.destroy()
    endfunction
     


    There is a reason I have to finish it off in another function ;o. Yes, it's annoying, but there is no way around it.

    And finally, a map for you to run : ).
     

    Attached Files:

    Last edited: Jun 6, 2012
  16. Magtheridon96

    Magtheridon96

    Joined:
    Dec 12, 2008
    Messages:
    6,006
    Resources:
    26
    Maps:
    1
    Spells:
    8
    Tutorials:
    7
    JASS:
    10
    Resources:
    26
    Cool, it works effectively :D
     
  17. Bribe

    Bribe

    Joined:
    Sep 26, 2009
    Messages:
    8,121
    Resources:
    25
    Maps:
    3
    Spells:
    10
    Tutorials:
    3
    JASS:
    9
    Resources:
    25
    So this ridiculous string concatenation with 2^12 uncompiled array references keeps the string leakage down, which is why you did it in a loop?

    /palmface

    I think I'm going to go throw up. Yet another BS abuse.
     
  18. Nestharus

    Nestharus

    Joined:
    Jul 10, 2007
    Messages:
    6,146
    Resources:
    8
    Spells:
    3
    Tutorials:
    4
    JASS:
    1
    Resources:
    8