In this article I show you a way to automatically tweet your #100DaysOfCode Challenge progress. This saves you some extra time to focus on the coding. Isn’t that all what matters?

This is day 007 of our 100 Days of Code challenge. You can follow along by forking our repo.

Getting ready

You need pytz, tweepy and requests. You can pip install -r requirements.txt if you cloned our repo (after cd-ing in 007). We recommend using virtualenv to isolate environments.

As explained in a previous article you need to get a Consumer Key/Secret and Access Token (Secret) from Twitter. I added those to my .bashrc which I load in via os.environ in config.py. There I also started a logging handler I use to log outgoing tweets and any exceptions that may occur.

The main script

See here and below what I learned:

  • As per PEP8 we import stdlib, followed by external modules and own project modules:

    import datetime
    import os
    import re
    import sys
    
    import requests
    import pytz
    
    from config import logging, api
    
  • My server (see deployment below) runs on MT tz and I wanted to talk EMEA times. Pytz (World Timezone Definitions for Python) to the rescue: it made working with timezones very easy:

    tz = pytz.timezone('Europe/Amsterdam')
    now = datetime.datetime.now(tz)
    start = datetime.datetime(2017, 3, 29, tzinfo=tz)  # = PyBites 100 days :)
    
  • I define some constants in all capital letters with underscores separating words (PEP8). I start to like datetime: calculating dates is easy:

    CURRENT_CHALLENGE_DAY = str((now - start).days).zfill(3)
    LOG = 'https://raw.githubusercontent.com/pybites/100DaysOfCode/master/LOG.md'
    LOG_ENTRY = re.compile(r'\[(?P.*?)\]\((?P<day>\d+)\)')
    REPO_URL = 'https://github.com/pybites/100DaysOfCode/tree/master/'
    TWEET_LEN = 140
    TWEET_LINK_LEN = 23
    </code></pre>
    </li>
    <li>
    <p>Where would we be without requests? Here I get the LOG.md file from <a href="https://github.com/pybites/100DaysOfCode">our repo</a>, just a single line of code:</p>
    <pre class="wp-block-code"><code>def get_log():
        return requests.get(LOG).text.split('\n')
    </code></pre>
    </li>
    <li>
    <p>I get the script title and day string from the line in LOG.md that matches the exact day string (today = ‘007’):</p>
    <pre class="wp-block-code"><code>def get_day_progress(html):
        lines = [line.strip()
                for line in html
                if line.strip()]
    
        for line in lines:
            day_entry = line.strip('|').split('|')[0].strip()
            if day_entry == CURRENT_CHALLENGE_DAY:
                return LOG_ENTRY.search(line).groupdict()
    </code></pre>
    </li>
    <li>
    <p>I create the tweet. I added some code to shorten the script title if the total tweet size is too long:</p>
    <pre class="wp-block-code"><code>def create_tweet(m):
        ht1, ht2 = '#100DaysOfCode', '#Python'
        title = m['title']
        day = m['day']
        url = REPO_URL + day
        allowed_len = TWEET_LEN + len(url) - TWEET_LINK_LEN
    
        fmt = '{} - Day {}: {} {} {}'
        tweet = fmt.format(ht1, day, title, url, ht2)
        surplus = len(tweet) - allowed_len
    
        if surplus > 0:
            new_title = title[:-(surplus + 4)] + '...'
            tweet = tweet.replace(title, new_title)
        return tweet
    </code></pre>
    </li>
    <li>
    <p>tweet_status() sends the tweet. We use the imported api object (from config.py) to send the tweet and we log an info if success, or error if any exception:</p>
    <pre class="wp-block-code"><code>def tweet_status(tweet):
        try:
            api.update_status(tweet)
            logging.info('Posted to Twitter')
        except Exception as exc:
            logging.error('Error posting to Twitter: {}'.format(exc))
    </code></pre>
    </li>
    <li>
    <p>We drive the script under main (= if script is run directly/standalone, not imported by another module). I set up some variables to allow for testing / dry runs:</p>
    <pre class="wp-block-code"><code>if __name__ == '__main__':
        import socket
        local = 'MacBook' in socket.gethostname()
        test = local or 'dry' in sys.argv[1:]
    </code></pre>
    </li>
    <li>
    <p>If test I use my local LOG file:</p>
    <pre class="wp-block-code"><code>    if test:
            log = os.path.basename(LOG)
            with open(log) as f:
                html = f.readlines()
        else:
            html = get_log()
    </code></pre>
    </li>
    <li>
    <p>If for some reason I don’t get a valid return from get_day_progress() I abort the script, logging the error:</p>
    <pre class="wp-block-code"><code>    m = get_day_progress(html)
        if not m:
            logging.error('Error getting day progress from log')
            sys.exit(1)
    </code></pre>
    </li>
    <li>
    <p>I create the tweet. If dry run, I just log it, else it tweets automatically:</p>
    <pre class="wp-block-code"><code>    tweet = create_tweet(m)
        if test:
            logging.info('Test: tweet to send: {}'.format(tweet))
        else:
            tweet_status(tweet)
    </code></pre>
    </li>
    </ul>
    <h2>Deployment</h2>
    <p>On my server I had to do some magic to get it all working: source .bashrc to load in the ENV vars, export PYTHONPATH, and specify the full path to python3. <a href="http://unix.stackexchange.com/a/27291">As explained here</a>: “Cron knows nothing about your shell; it is started by the system, so it has a minimal environment.”</p>
    <pre class="wp-block-code"><code>$ crontab -l
    ...
    34 14 * * * source $HOME/.bashrc && export PYTHONPATH=$HOME/bin/python3/lib/python3.5/site-packages && cd $HOME/code/100days/007 && $HOME/bin/python3/bin/python3.5 100day_autotweet.py
    </code></pre>
    <h2>Result</h2>
    <p>What a coincidence: as I write this our <a href="https://twitter.com/pybites/status/849721815538712576">today’s progress tweet just went out</a> 🙂</p>
    <p><img decoding="async" loading="lazy" alt="my automated tweet" src="https://pybit.es/wp-content/uploads/2021/05/auto-tweet.png" class="aligncenter"></p>
    <h2>Logging</h2>
    <p>The cool thing about the logging module is that you get the external packages’ logging for free. When I look at the log I see a lot more than my script’s logging:</p>
    <pre class="wp-block-code"><code>$ vi 100day_autotweet.log
    ...
    ...
    14:34:02 tweepy.binder INFO     PARAMS: {'status': b'#100DaysOfCode - Day 007: script to automatically tweet 100DayOfCode progress tweet https://github.com/pybites/100DaysOfCode/tree/master/007 #Python'}
    ...
    many more log entries ...
    ...
    14:34:02 requests.packages.urllib3.connectionpool DEBUG    https://api.twitter.com:443 "POST /1.1/statuses/update.json?status=%23100DaysOfCode+-+Day+007%3A+script+to+automatically+tweet+100DayOfCode+progress+tweet+https%3A%2F%2Fgithub.com%2Fpybites%2F100DaysOfCode%2Ftree%2Fmaster%2F007+%23Python HTTP/1.1" 200 2693
    14:34:02 root         INFO     Posted to Twitter ==> my message
    </code></pre>
    <p>Of course you can mute these by raising the log level (INFO or higher) in logging.basicConfig (<a href="https://github.com/pybites/100DaysOfCode/blob/master/007/config.py">config.py</a>). See <a href="https://docs.python.org/3/library/logging.html">the docs</a> for more info.</p>
    <hr>
    <p>I hope this taught you a bite of Python and it inspired you to automate your 100DaysOfCode and/or other tweets. Let us know how it goes … Happy coding!</p>
    <p>Keep Calm and Code in Python!</p>
    <p>— Bob</p>
    </div></article>
    </main>
    
    
    <footer class="site-footer wp-block-template-part">
    <div class="wp-block-group alignfull has-base-color has-main-background-color has-text-color has-background has-link-color wp-elements-bb9b062ee50e0daa6c6fcd115a5627d3 has-global-padding is-layout-constrained wp-container-core-group-is-layout-640d399d wp-block-group-is-layout-constrained" style="min-height:px;margin-top:0;padding-top:var(--wp--preset--spacing--x-large);padding-right:var(--wp--preset--spacing--medium);padding-bottom:var(--wp--preset--spacing--medium);padding-left:var(--wp--preset--spacing--medium)">
    <div class="wp-block-outermost-icon-block alignwide"><div class="icon-container has-icon-color has-base-color" style="color:#fff;width:8rem;transform:rotate(0deg) scaleX(1) scaleY(1)"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1045 243"><g><path d="M456.911,202.611C454.473,208.95 451.75,214.599 448.743,219.556C445.736,224.514 442.16,228.74 438.015,232.235C433.87,235.729 428.994,238.371 423.386,240.159C417.778,241.947 411.155,242.841 403.515,242.841C399.777,242.841 395.916,242.597 391.934,242.109C387.952,241.622 384.498,240.971 381.572,240.159L385.96,206.512C387.911,207.162 390.065,207.69 392.422,208.097C394.779,208.503 396.932,208.706 398.883,208.706C405.059,208.706 409.529,207.284 412.293,204.44C415.056,201.595 417.413,197.572 419.363,192.371L423.264,182.374L372.551,62.904L416.925,62.904L443.989,140.926L444.72,140.926L468.858,62.904L511.282,62.904L456.911,202.611Z"></path><g><path d="M52.687,109.917C52.687,107.009 50.326,104.648 47.418,104.648L26.326,104.648C11.796,104.648 0,116.444 0,130.974L0,237.572C0,240.48 2.361,242.841 5.269,242.841L26.384,242.841C40.901,242.841 52.687,231.055 52.687,216.538L52.687,109.917Z"></path><path d="M118.545,63.853C118.545,60.945 116.184,58.584 113.277,58.584L92.185,58.584C77.655,58.584 65.858,70.38 65.858,84.91L65.858,191.508C65.858,194.416 68.219,196.776 71.127,196.776L92.243,196.776C106.76,196.776 118.545,184.991 118.545,170.474L118.545,63.853Z"></path><path d="M134.266,27.537C132.636,30.957 131.721,34.783 131.717,38.821L131.717,145.444C131.717,148.351 134.078,150.712 136.986,150.712L158.101,150.712C172.618,150.712 184.404,138.927 184.404,124.41L184.404,52.57L186.603,51.032C198.518,42.698 201.425,26.26 193.092,14.346L188.562,7.87C182.729,-0.47 171.222,-2.505 162.882,3.328L142.959,17.262C139.082,19.974 136.159,23.544 134.266,27.537ZM160.468,27.979C162.848,31.383 162.018,36.08 158.614,38.461C155.21,40.842 150.513,40.011 148.132,36.607C145.751,33.203 146.582,28.506 149.986,26.125C153.39,23.744 158.087,24.575 160.468,27.979Z"></path></g><path d="M1023.05,98.745C1019.8,95.657 1015.98,93.056 1011.59,90.943C1007.2,88.83 1002.57,87.774 997.694,87.774C993.956,87.774 990.502,88.505 987.332,89.968C984.163,91.431 982.578,93.95 982.578,97.526C982.578,100.94 984.325,103.378 987.82,104.841C991.315,106.304 996.963,107.929 1004.76,109.717C1009.32,110.692 1013.91,112.074 1018.54,113.862C1023.17,115.65 1027.36,118.007 1031.1,120.933C1034.84,123.858 1037.84,127.434 1040.12,131.661C1042.39,135.887 1043.53,140.926 1043.53,146.777C1043.53,154.417 1041.99,160.878 1038.9,166.161C1035.81,171.443 1031.79,175.71 1026.83,178.961C1021.87,182.212 1016.31,184.569 1010.13,186.031C1003.95,187.494 997.776,188.226 991.599,188.226C981.684,188.226 971.972,186.641 962.463,183.471C952.954,180.302 945.03,175.629 938.691,169.452L961.122,145.802C964.698,149.703 969.087,152.954 974.288,155.555C979.49,158.155 985.016,159.456 990.868,159.456C994.119,159.456 997.329,158.683 1000.5,157.139C1003.67,155.595 1005.25,152.873 1005.25,148.971C1005.25,145.233 1003.3,142.47 999.401,140.682C995.5,138.894 989.405,137.025 981.115,135.074C976.889,134.099 972.663,132.798 968.437,131.173C964.21,129.547 960.431,127.353 957.099,124.59C953.767,121.827 951.044,118.413 948.931,114.35C946.818,110.286 945.762,105.41 945.762,99.721C945.762,92.406 947.306,86.189 950.394,81.069C953.483,75.949 957.465,71.763 962.341,68.512C967.217,65.261 972.622,62.864 978.555,61.32C984.488,59.776 990.38,59.003 996.232,59.003C1005.33,59.003 1014.23,60.426 1022.93,63.27C1031.63,66.115 1038.98,70.382 1045,76.071L1023.05,98.745Z"></path><path d="M778.504,92.894L778.504,139.219C778.504,144.908 779.601,149.175 781.796,152.019C783.99,154.864 787.932,156.286 793.621,156.286C795.571,156.286 797.644,156.123 799.838,155.798C802.032,155.473 803.861,154.986 805.324,154.335L805.811,183.593C803.048,184.569 799.553,185.422 795.327,186.153C791.101,186.885 786.875,187.251 782.649,187.251C774.522,187.251 767.695,186.235 762.168,184.203C756.642,182.171 752.213,179.245 748.88,175.426C745.548,171.606 743.151,167.054 741.688,161.772C740.225,156.489 739.493,150.597 739.493,144.095L739.493,92.894L719.988,92.894L719.988,62.904L739.25,62.904L739.25,30.965L778.504,30.965L778.504,62.904L807.03,62.904L807.03,92.894L778.504,92.894Z"></path><rect x="665.861" y="62.904" width="39.986" height="121.42"></rect><path d="M377.915,123.127C377.915,131.579 376.614,139.706 374.014,147.509C371.413,155.311 367.634,162.178 362.676,168.111C357.718,174.044 351.664,178.798 344.512,182.374C337.36,185.95 329.233,187.738 320.13,187.738C312.653,187.738 305.583,186.235 298.918,183.228C292.254,180.221 287.053,176.116 283.314,170.915L282.826,170.915L282.826,242.841L242.841,242.841L242.841,62.904L280.876,62.904L280.876,77.777L281.607,77.777C285.346,72.901 290.507,68.634 297.09,64.977C303.673,61.32 311.434,59.491 320.374,59.491C329.151,59.491 337.116,61.198 344.268,64.611C351.42,68.025 357.475,72.657 362.432,78.509C367.39,84.36 371.21,91.146 373.892,98.867C376.574,106.588 377.915,114.675 377.915,123.127ZM339.148,123.127C339.148,119.226 338.538,115.406 337.319,111.668C336.1,107.929 334.312,104.638 331.955,101.793C329.598,98.949 326.632,96.632 323.056,94.844C319.48,93.056 315.335,92.162 310.621,92.162C306.07,92.162 302.007,93.056 298.431,94.844C294.855,96.632 291.807,98.989 289.288,101.915C286.768,104.841 284.818,108.173 283.436,111.911C282.054,115.65 281.363,119.47 281.363,123.371C281.363,127.272 282.054,131.092 283.436,134.83C284.818,138.569 286.768,141.901 289.288,144.827C291.807,147.752 294.855,150.109 298.431,151.897C302.007,153.685 306.07,154.579 310.621,154.579C315.335,154.579 319.48,153.685 323.056,151.897C326.632,150.109 329.598,147.752 331.955,144.827C334.312,141.901 336.1,138.528 337.319,134.708C338.538,130.888 339.148,127.028 339.148,123.127Z"></path><path d="M652.207,123.127C652.207,131.579 650.907,139.706 648.306,147.509C645.706,155.311 641.927,162.178 636.969,168.111C632.011,174.044 625.957,178.798 618.805,182.374C611.653,185.95 603.526,187.738 594.423,187.738C586.296,187.738 578.616,186.072 571.382,182.74C564.149,179.408 558.582,174.653 554.681,168.477L554.193,168.477L554.193,184.325L517.377,184.325L517.377,0L557.363,0L557.363,75.827L557.851,75.827C561.264,71.763 566.059,68.025 572.236,64.611C578.412,61.198 585.971,59.491 594.911,59.491C603.688,59.491 611.612,61.198 618.683,64.611C625.753,68.025 631.768,72.657 636.725,78.509C641.683,84.36 645.502,91.146 648.184,98.867C650.866,106.588 652.207,114.675 652.207,123.127ZM613.685,123.127C613.685,119.226 613.075,115.406 611.856,111.668C610.637,107.929 608.808,104.638 606.37,101.793C603.932,98.949 600.925,96.632 597.349,94.844C593.773,93.056 589.628,92.162 584.914,92.162C580.363,92.162 576.299,93.056 572.723,94.844C569.147,96.632 566.1,98.989 563.58,101.915C561.061,104.841 559.11,108.173 557.729,111.911C556.347,115.65 555.656,119.47 555.656,123.371C555.656,127.272 556.347,131.092 557.729,134.83C559.11,138.569 561.061,141.901 563.58,144.827C566.1,147.752 569.147,150.109 572.723,151.897C576.299,153.685 580.363,154.579 584.914,154.579C589.628,154.579 593.773,153.685 597.349,151.897C600.925,150.109 603.932,147.752 606.37,144.827C608.808,141.901 610.637,138.528 611.856,134.708C613.075,130.888 613.685,127.028 613.685,123.127Z"></path><path d="M938.935,125.078L938.935,129.954C938.935,131.579 938.854,133.123 938.691,134.586L850.674,134.586C850.999,138 852.015,141.088 853.721,143.851C855.428,146.615 857.622,149.012 860.304,151.044C862.986,153.076 865.993,154.661 869.325,155.798C872.658,156.936 876.112,157.505 879.688,157.505C886.027,157.505 891.391,156.327 895.779,153.97C900.168,151.613 903.744,148.565 906.507,144.827L934.302,162.381C928.613,170.671 921.096,177.051 911.749,181.521C902.403,185.991 891.553,188.226 879.2,188.226C870.098,188.226 861.483,186.804 853.355,183.959C845.228,181.115 838.117,176.97 832.022,171.524C825.926,166.079 821.131,159.374 817.636,151.41C814.142,143.445 812.394,134.343 812.394,124.102C812.394,114.187 814.101,105.207 817.515,97.161C820.928,89.115 825.56,82.288 831.412,76.68C837.264,71.072 844.172,66.724 852.136,63.636C860.101,60.548 868.716,59.003 877.981,59.003C886.921,59.003 895.129,60.507 902.606,63.514C910.083,66.521 916.504,70.869 921.868,76.558C927.232,82.247 931.417,89.155 934.424,97.283C937.431,105.41 938.935,114.675 938.935,125.078ZM902.119,109.717C902.119,103.378 900.128,97.933 896.145,93.381C892.163,88.83 886.189,86.555 878.225,86.555C874.324,86.555 870.748,87.164 867.497,88.383C864.246,89.602 861.401,91.268 858.963,93.381C856.525,95.495 854.575,97.973 853.112,100.818C851.649,103.662 850.836,106.629 850.674,109.717L902.119,109.717Z"></path><path d="M708.773,24.138C708.773,27.226 708.163,30.111 706.944,32.793C705.725,35.475 704.1,37.791 702.068,39.742C700.036,41.693 697.598,43.237 694.753,44.374C691.909,45.512 688.942,46.081 685.854,46.081C679.352,46.081 673.907,43.927 669.518,39.62C665.13,35.313 662.935,30.152 662.935,24.138C662.935,21.212 663.504,18.408 664.642,15.726C665.78,13.044 667.405,10.728 669.518,8.777C671.631,6.827 674.07,5.242 676.833,4.023C679.596,2.804 682.603,2.194 685.854,2.194C688.942,2.194 691.909,2.763 694.753,3.901C697.598,5.039 700.036,6.583 702.068,8.534C704.1,10.484 705.725,12.8 706.944,15.482C708.163,18.164 708.773,21.049 708.773,24.138Z"></path></g></svg></div></div>
    
    
    
    <div class="wp-block-columns alignwide is-layout-flex wp-container-core-columns-is-layout-f619a8c7 wp-block-columns-is-layout-flex">
    <div class="wp-block-column is-layout-flow wp-container-core-column-is-layout-c7b3064f wp-block-column-is-layout-flow">
    <p style="font-style:normal;font-weight:600">Training</p>
    
    
    
    <div class="wp-block-group has-small-font-size has-global-padding is-layout-constrained wp-container-core-group-is-layout-f5f3bcb8 wp-block-group-is-layout-constrained">
    <p><a href="https://pybit.es/courses/" data-type="page" data-id="26">Courses</a></p>
    
    
    
    <p><a href="https://pybit.es/code-platform/" data-type="page" data-id="14">Code Platform</a></p>
    
    
    
    <p><a href="https://pybit.es/python-certification/" data-type="page" data-id="36">Python Certification</a></p>
    </div>
    </div>
    
    
    
    <div class="wp-block-column is-layout-flow wp-container-core-column-is-layout-c7b3064f wp-block-column-is-layout-flow">
    <p style="font-style:normal;font-weight:600">Solutions</p>
    
    
    
    <div class="wp-block-group has-small-font-size has-global-padding is-layout-constrained wp-container-core-group-is-layout-f5f3bcb8 wp-block-group-is-layout-constrained">
    <p><a href="https://pybit.es/for-organizations/" data-type="page" data-id="32">For Organizations</a></p>
    
    
    
    <p><a href="https://pybit.es/for-educators/" data-type="page" data-id="28">For Educators</a></p>
    
    
    
    <p><a href="https://pybit.es/for-veterans/" data-type="page" data-id="16726">For Veterans</a></p>
    </div>
    </div>
    
    
    
    <div class="wp-block-column is-layout-flow wp-container-core-column-is-layout-c7b3064f wp-block-column-is-layout-flow">
    <p style="font-style:normal;font-weight:600">Resources</p>
    
    
    
    <div class="wp-block-group has-small-font-size has-global-padding is-layout-constrained wp-container-core-group-is-layout-f5f3bcb8 wp-block-group-is-layout-constrained">
    <p><a href="https://pybit.es/articles/" data-type="page" data-id="9">Articles</a></p>
    
    
    
    <p><a href="https://pybit.es/community/" data-type="page" data-id="16">Community</a></p>
    
    
    
    <p><a href="https://pybit.es/student-projects/" data-type="page" data-id="49">Student Projects</a></p>
    
    
    
    <p><a href="https://pybit.es/podcast/" data-type="page" data-id="34">Podcast</a></p>
    
    
    
    <p><a href="https://github.com/PyBites-Open-Source">Github</a></p>
    </div>
    </div>
    
    
    
    <div class="wp-block-column is-layout-flow wp-container-core-column-is-layout-c7b3064f wp-block-column-is-layout-flow">
    <p style="font-style:normal;font-weight:600">Company</p>
    
    
    
    <div class="wp-block-group has-small-font-size has-global-padding is-layout-constrained wp-container-core-group-is-layout-f5f3bcb8 wp-block-group-is-layout-constrained">
    <p><a href="https://pybit.es/about/" data-type="page" data-id="11">About Us</a></p>
    
    
    
    <p><a href="https://pybit.es/contact/" data-type="page" data-id="21">Contact</a></p>
    </div>
    </div>
    
    
    
    <div class="wp-block-column has-border-light-color has-text-color has-link-color wp-elements-e0060dd084f2371ec8d2c00fe58fcfc4 is-layout-flow wp-container-core-column-is-layout-c7b3064f wp-block-column-is-layout-flow">
    <p style="font-style:normal;font-weight:600">Follow</p>
    
    
    
    <div class="wp-block-group has-small-font-size has-global-padding is-layout-constrained wp-container-core-group-is-layout-f5f3bcb8 wp-block-group-is-layout-constrained">
    <p><a href="https://pybit.es/about/" data-type="page" data-id="11"></a><a href="https://facebook.com/pybites">Facebook</a></p>
    
    
    
    <p><a href="https://pybit.es/contact/" data-type="page" data-id="21"></a><a href="https://www.linkedin.com/company/pybites/">LinkedIn</a></p>
    
    
    
    <p><a href="/feed/">RSS</a></p>
    
    
    
    <p><a href="https://pybit.es/privacy-policy/" data-type="page" data-id="3"></a><a href="https://www.x.com/pybites">X</a></p>
    
    
    
    <p><a href="https://www.youtube.com/channel/UCBn-uKDGsRBfcB0lQeOB_gA">YouTube</a></p>
    </div>
    </div>
    </div>
    
    
    
    <div class="wp-block-group alignwide has-border-light-color has-text-color has-link-color wp-elements-878ad92586730ead5961492caf70d8c8 is-layout-flex wp-container-core-group-is-layout-516594b6 wp-block-group-is-layout-flex" style="margin-top:var(--wp--preset--spacing--xxx-large)">
    <p class="has-x-small-font-size">Copyright © 2026 Pybites</p>
    
    
    
    <div class="wp-block-buttons is-layout-flex wp-block-buttons-is-layout-flex">
    <div class="wp-block-button is-style-link open-cookiefox"><button type="button" class="wp-block-button__link has-x-small-font-size has-custom-font-size wp-element-button" style="padding-top:0;padding-right:0;padding-bottom:0;padding-left:0">Cookie Preferences</button></div>
    </div>
    
    
    
    <p class="has-x-small-font-size"><a href="https://pybit.es/privacy-policy/" data-type="page" data-id="3">Privacy Policy</a></p>
    </div>
    </div>
    </footer></div>
    <script type="speculationrules">
    {"prefetch":[{"source":"document","where":{"and":[{"href_matches":"/*"},{"not":{"href_matches":["/wp-*.php","/wp-admin/*","/wp-content/uploads/*","/wp-content/*","/wp-content/plugins/*","/wp-content/themes/ollie/*","/*\\?(.+)"]}},{"not":{"selector_matches":"a[rel~=\"nofollow\"]"}},{"not":{"selector_matches":".no-prefetch, .no-prefetch a"}}]},"eagerness":"conservative"}]}
    </script>
    <script type="module" src="https://pybit.es/wp-includes/js/dist/script-modules/block-library/navigation/view.min.js?ver=b0f909c3ec791c383210" id="@wordpress/block-library/navigation/view-js-module" fetchpriority="low" data-wp-router-options="{"loadOnClientNavigation":true}"></script>
    		<script>
    			var cookiefox = {data: {"consent_type":"category","cookie_notice_enabled":"on","cookie_notice_hide_on_privacy_page":"on","notice_display":"modal","notice_delay":0,"notice_title":"Cookie Preferences","notice_text":"We use cookies that are necessary to run this site, plus optional cookies to load embedded external content. You can choose what to allow.","notice_button_accept":"Accept all","notice_button_save":"Save","notice_button_manage":"View details","notice_button_decline_type":"button","notice_button_decline":"Decline all","block_embeds":"on","font":"theme","button_style":"rounded","color_background":"#ffffff","color_text_primary":"#000000","color_text_secondary":"#767676","color_text_tertiary":"#d8d8d8","color_button_primary":"#3D854F","color_button_secondary":"#767676","cookie_name":"cookie_consent","cookie_expiration":180,"stylesheet":"none","javascript":"modern","privacy_type":"basic","disabled_on_privacy_page":false,"api_base":"https:\/\/pybit.es\/wp-json\/","lang":"en","notice_button_back":"Back","notice_button_cookie_information":"Cookie information","notice_text_name":"Name","notice_text_vendor":"Vendor","notice_text_purpose":"Purpose","notice_text_privacy_policy":"Privacy Policy","notice_text_cookies":"Cookies","notice_text_duration":"Duration","notice_text_hosts":"Hosts"}};
    		</script>
    		<div id="cookiefox" data-nosnippet></div>
    		
    		<script id="wp-block-template-skip-link-js-after">
    	( function() {
    		var skipLinkTarget = document.querySelector( 'main' ),
    			sibling,
    			skipLinkTargetID,
    			skipLink;
    
    		// Early exit if a skip-link target can't be located.
    		if ( ! skipLinkTarget ) {
    			return;
    		}
    
    		/*
    		 * Get the site wrapper.
    		 * The skip-link will be injected in the beginning of it.
    		 */
    		sibling = document.querySelector( '.wp-site-blocks' );
    
    		// Early exit if the root element was not found.
    		if ( ! sibling ) {
    			return;
    		}
    
    		// Get the skip-link target's ID, and generate one if it doesn't exist.
    		skipLinkTargetID = skipLinkTarget.id;
    		if ( ! skipLinkTargetID ) {
    			skipLinkTargetID = 'wp--skip-link--target';
    			skipLinkTarget.id = skipLinkTargetID;
    		}
    
    		// Create the skip link.
    		skipLink = document.createElement( 'a' );
    		skipLink.classList.add( 'skip-link', 'screen-reader-text' );
    		skipLink.id = 'wp-skip-link';
    		skipLink.href = '#' + skipLinkTargetID;
    		skipLink.innerText = 'Skip to content';
    
    		// Inject the skip link.
    		sibling.parentElement.insertBefore( skipLink, sibling );
    	}() );
    	
    //# sourceURL=wp-block-template-skip-link-js-after
    </script>
    <script id="nfd-performance-lazy-loader-js-before">
    window.nfdPerformance = window.nfdPerformance || {};
            window.nfdPerformance.imageOptimization = window.nfdPerformance.imageOptimization || {};
            window.nfdPerformance.imageOptimization.lazyLoading = {"classes":["nfd-performance-not-lazy","a3-notlazy","disable-lazyload","no-lazy","no-lazyload","skip-lazy"],"attributes":["data-lazy-src","data-crazy-lazy=\"exclude\"","data-no-lazy","data-no-lazy=\"1\""]};
    //# sourceURL=nfd-performance-lazy-loader-js-before
    </script>
    <script src="https://pybit.es/wp-content/plugins/bluehost-wordpress-plugin/vendor/newfold-labs/wp-module-performance/build/assets/image-lazy-loader.min.js?ver=1776885463" id="nfd-performance-lazy-loader-js"></script>
    <script id="linkprefetcher-js-before">
    window.LP_CONFIG = {"activeOnDesktop":true,"behavior":"mouseHover","hoverDelay":60,"instantClick":false,"activeOnMobile":true,"mobileBehavior":"touchstart","ignoreKeywords":"#,?","isMobile":false}
    //# sourceURL=linkprefetcher-js-before
    </script>
    <script src="https://pybit.es/wp-content/plugins/bluehost-wordpress-plugin/vendor/newfold-labs/wp-module-performance/build/assets/link-prefetch.min.js?ver=4.15.1" id="linkprefetcher-js" defer></script>
    <script src="https://pybit.es/wp-content/plugins/cookiefox/assets/frontend/js/main.js?ver=1773218114" id="cookiefox-js"></script>
    <script id="wp-emoji-settings" type="application/json">
    {"baseUrl":"https://s.w.org/images/core/emoji/17.0.2/72x72/","ext":".png","svgUrl":"https://s.w.org/images/core/emoji/17.0.2/svg/","svgExt":".svg","source":{"concatemoji":"https://pybit.es/wp-includes/js/wp-emoji-release.min.js?ver=6.9.4"}}
    </script>
    <script type="module">
    /*! This file is auto-generated */
    const a=JSON.parse(document.getElementById("wp-emoji-settings").textContent),o=(window._wpemojiSettings=a,"wpEmojiSettingsSupports"),s=["flag","emoji"];function i(e){try{var t={supportTests:e,timestamp:(new Date).valueOf()};sessionStorage.setItem(o,JSON.stringify(t))}catch(e){}}function c(e,t,n){e.clearRect(0,0,e.canvas.width,e.canvas.height),e.fillText(t,0,0);t=new Uint32Array(e.getImageData(0,0,e.canvas.width,e.canvas.height).data);e.clearRect(0,0,e.canvas.width,e.canvas.height),e.fillText(n,0,0);const a=new Uint32Array(e.getImageData(0,0,e.canvas.width,e.canvas.height).data);return t.every((e,t)=>e===a[t])}function p(e,t){e.clearRect(0,0,e.canvas.width,e.canvas.height),e.fillText(t,0,0);var n=e.getImageData(16,16,1,1);for(let e=0;e<n.data.length;e++)if(0!==n.data[e])return!1;return!0}function u(e,t,n,a){switch(t){case"flag":return n(e,"\ud83c\udff3\ufe0f\u200d\u26a7\ufe0f","\ud83c\udff3\ufe0f\u200b\u26a7\ufe0f")?!1:!n(e,"\ud83c\udde8\ud83c\uddf6","\ud83c\udde8\u200b\ud83c\uddf6")&&!n(e,"\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc65\udb40\udc6e\udb40\udc67\udb40\udc7f","\ud83c\udff4\u200b\udb40\udc67\u200b\udb40\udc62\u200b\udb40\udc65\u200b\udb40\udc6e\u200b\udb40\udc67\u200b\udb40\udc7f");case"emoji":return!a(e,"\ud83e\u1fac8")}return!1}function f(e,t,n,a){let r;const o=(r="undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?new OffscreenCanvas(300,150):document.createElement("canvas")).getContext("2d",{willReadFrequently:!0}),s=(o.textBaseline="top",o.font="600 32px Arial",{});return e.forEach(e=>{s[e]=t(o,e,n,a)}),s}function r(e){var t=document.createElement("script");t.src=e,t.defer=!0,document.head.appendChild(t)}a.supports={everything:!0,everythingExceptFlag:!0},new Promise(t=>{let n=function(){try{var e=JSON.parse(sessionStorage.getItem(o));if("object"==typeof e&&"number"==typeof e.timestamp&&(new Date).valueOf()<e.timestamp+604800&&"object"==typeof e.supportTests)return e.supportTests}catch(e){}return null}();if(!n){if("undefined"!=typeof Worker&&"undefined"!=typeof OffscreenCanvas&&"undefined"!=typeof URL&&URL.createObjectURL&&"undefined"!=typeof Blob)try{var e="postMessage("+f.toString()+"("+[JSON.stringify(s),u.toString(),c.toString(),p.toString()].join(",")+"));",a=new Blob([e],{type:"text/javascript"});const r=new Worker(URL.createObjectURL(a),{name:"wpTestEmojiSupports"});return void(r.onmessage=e=>{i(n=e.data),r.terminate(),t(n)})}catch(e){}i(n=f(s,u,c,p))}t(n)}).then(e=>{for(const n in e)a.supports[n]=e[n],a.supports.everything=a.supports.everything&&a.supports[n],"flag"!==n&&(a.supports.everythingExceptFlag=a.supports.everythingExceptFlag&&a.supports[n]);var t;a.supports.everythingExceptFlag=a.supports.everythingExceptFlag&&!a.supports.flag,a.supports.everything||((t=a.source||{}).concatemoji?r(t.concatemoji):t.wpemoji&&t.twemoji&&(r(t.twemoji),r(t.wpemoji)))});
    //# sourceURL=https://pybit.es/wp-includes/js/wp-emoji-loader.min.js
    </script>
    </body>
    </html>
    <script>(function(){function c(){var b=a.contentDocument||a.contentWindow.document;if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'9f11985beb895b65',t:'MTc3Njk5Njg3Mw=='};var a=document.createElement('script');a.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js';document.getElementsByTagName('head')[0].appendChild(a);";b.getElementsByTagName('head')[0].appendChild(d)}}if(document.body){var a=document.createElement('iframe');a.height=1;a.width=1;a.style.position='absolute';a.style.top=0;a.style.left=0;a.style.border='none';a.style.visibility='hidden';document.body.appendChild(a);if('loading'!==document.readyState)c();else if(window.addEventListener)document.addEventListener('DOMContentLoaded',c);else{var e=document.onreadystatechange||function(){};document.onreadystatechange=function(b){e(b);'loading'!==document.readyState&&(document.onreadystatechange=e,c())}}}})();</script>