<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Python &#8211; Blog of Kliment Andreev &#8211; A place so I won&#039;t forget things</title>
	<atom:link href="https://blog.andreev.it/category/programming/python/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.andreev.it</link>
	<description></description>
	<lastBuildDate>Fri, 22 Nov 2024 16:36:12 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	
	<item>
		<title>FreeBSD: OpenVPN server in a LAN (local network) environment</title>
		<link>https://blog.andreev.it/2024/11/freebsd-openvpn-server-in-a-lan-local-network-environment/</link>
					<comments>https://blog.andreev.it/2024/11/freebsd-openvpn-server-in-a-lan-local-network-environment/#respond</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Fri, 22 Nov 2024 16:36:12 +0000</pubDate>
				<category><![CDATA[FreeBSD]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[freebsd]]></category>
		<category><![CDATA[LAN]]></category>
		<category><![CDATA[OpenVPN]]></category>
		<category><![CDATA[pf]]></category>
		<category><![CDATA[VPN]]></category>
		<guid isPermaLink="false">https://blog.andreev.it/?p=10074</guid>

					<description><![CDATA[In this post I&#8217;ll describe a use case that I am currently using. I&#8230;]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>In this post I&#8217;ll describe a use case that I am currently using. I have a standard Internet connection that goes to my Eero mesh router and behind that I have a homelab on 192.168.1.0/24 network as shown in the diagram. I have a port forwarding configured on the router so I can access one of my Linux servers, but if I want to access other servers, I have to either port forward SSH on some other-than-22/tcp port or use the Linux server as a jump-box. None of this is good, so I decided to create an OpenVPN server. Anytime I VPN to this server I can ssh/rdp to any of the internal servers. The OpenVPN server requires one nic.<br />
<strong>NOTE</strong>: This post is very FreeBSD specific so if you want to use some Linux server as OpenVPN server, this guide won&#8217;t help you at all.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2024/11/P177-01.png"><img fetchpriority="high" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2024/11/P177-01.png" alt="" width="721" height="491" class="aligncenter size-full wp-image-10078" srcset="https://blog.andreev.it/wp-content/uploads/2024/11/P177-01.png 721w, https://blog.andreev.it/wp-content/uploads/2024/11/P177-01-300x204.png 300w, https://blog.andreev.it/wp-content/uploads/2024/11/P177-01-585x398.png 585w" sizes="(max-width: 721px) 100vw, 721px" /></a><br />
<strong>IMPORTANT</strong>: On your home router port-forward port 1194/udp to your OpenVPN server.</p>
<h1>OpenVPN server</h1>
<p>Let&#8217;s install OpenVPN server first.</p>
<pre class="brush: bash; title: ; notranslate">
pkg install openvpn
</pre>
<p>Make sure it starts on boot and enable the NAT.</p>
<pre class="brush: bash; title: ; notranslate">
sysrc openvpn_enable=YES
sysrc gateway_enable=YES
</pre>
<p>Next, we need a directory where we&#8217;ll store our config files and the PKI.</p>
<pre class="brush: bash; title: ; notranslate">
mkdir /usr/local/etc/openvpn
cd /usr/local/etc/openvpn
</pre>
<p>Create the PKI structure.</p>
<pre class="brush: bash; title: ; notranslate">
easyrsa init-pki
</pre>
<p>Go to the newly created <em>pki </em>directory and make a copy of the <em>vars.example</em> file.</p>
<pre class="brush: bash; title: ; notranslate">
cd pki
cp vars.example vars
</pre>
<p>Now edit this file and uncomment the following lines and change to match your needs. It&#8217;s optional and you can keep everything-as-is.</p>
<pre class="brush: bash; title: ; notranslate">
set_var EASYRSA_REQ_COUNTRY     &quot;US&quot;
set_var EASYRSA_REQ_PROVINCE    &quot;NJ&quot;
set_var EASYRSA_REQ_CITY        &quot;Allentown&quot;
set_var EASYRSA_REQ_ORG         &quot;iAndreev&quot;
set_var EASYRSA_REQ_EMAIL       &quot;mail@somemail.com&quot;
set_var EASYRSA_REQ_OU          &quot;iAndreev&quot;
set_var EASYRSA_CA_EXPIRE       3650
set_var EASYRSA_CERT_EXPIRE     825
</pre>
<p>Now create the Certificate Authority based on these values.</p>
<pre class="brush: bash; title: ; notranslate">
cd /usr/local/etc/openvpn
easyrsa build-ca
</pre>
<p>This command will prompt you to create a password that you will you to sign the certificates for the server and the clients.<br />
Then create the DH parameters. It might take 30+ seconds.</p>
<pre class="brush: bash; title: ; notranslate">
easyrsa gen-dh
</pre>
<p>Create the server request and sign it.</p>
<pre class="brush: bash; title: ; notranslate">
easyrsa build-server-full server nopass
</pre>
<p>You have to type <em>yes </em>to confirm and then use the password that you created above to sign the cert.<br />
The command will create some files under the <em>pki </em>directory and we&#8217;ll need those later.<br />
Next, we&#8217;ll create the same for the client. In my case it&#8217;s a Dell laptop, so I use the word dell, but you can use client, client1, something-whatever&#8230;</p>
<pre class="brush: bash; title: ; notranslate">
easyrsa build-client-full dell nopass
</pre>
<p>Same thing, answer <em>yes </em>and then use the password to sign the certs.<br />
Copy the OpenVPN config example file that comes with the package.</p>
<pre class="brush: bash; title: ; notranslate">
cp /usr/local/share/examples/openvpn/sample-config-files/server.conf /usr/local/etc/openvpn/openvpn.conf
</pre>
<p>Edit<em> openvpn.conf</em> and make sure these values are changed and match the certs you created earlier.</p>
<pre class="brush: bash; title: ; notranslate">
ca /usr/local/etc/openvpn/pki/ca.crt
cert /usr/local/etc/openvpn/pki/issued/server.crt
key /usr/local/etc/openvpn/pki/private/server.key

dh /usr/local/etc/openvpn/pki/dh.pem
</pre>
<p>In addition to that, find the line that says push route and create a new one that matches your internal subnet. In my case it looks like this.</p>
<pre class="brush: bash; title: ; notranslate">
push &quot;route 192.168.1.0 255.255.255.0&quot;
</pre>
<p>If you have internal DNS and you want to send that as well, uncomment the following line and change to match your DNS IP.</p>
<pre class="brush: bash; title: ; notranslate">
push &quot;dhcp-option DNS 208.67.222.222&quot;
</pre>
<p>Now, you can start the OpenVPN server. Make sure you check the syslog for any errors.</p>
<pre class="brush: bash; title: ; notranslate">
service openvpn start
tail /var/log/messages
</pre>
<h1>OpenVPN client</h1>
<p>On your laptop that you want to use as a VPN client, download the OpenVPN client from <a href="https://openvpn.net/community-downloads/" target="_blank">here</a>. When you install the client, you&#8217;ll have a generic config file under <em>C:\Program Files\OpenVPN\sample-config</em> folder. Copy that file under <em>c:\users\[your_username]\OpenVPN\config</em>.<br />
Then, edit the file and change the following lines.</p>
<pre class="brush: bash; title: ; notranslate">
remote public-ip-or-hostname-of-your-router 1194
ca ca.crt
cert dell.crt
key dell.key
</pre>
<p>NOTE: Make sure you copy <em>ca.crt</em> from <em>/usr/local/etc/openvpn/pki</em>, <em>dell.crt</em> or client.crt or whatever.crt from <em>/usr/local/etc/openvpn/pki/issued</em> and<em> dell.key</em> or client.key or whatever.key from <em>/usr/local/etc/openvpn/pki/private</em> directories to the same <em>c:\users\[your-user-name]\OpenVPN\config</em> folder. There should be 4 files there. The config file, the CA certificate, the client certificate and the private key for the client.<br />
Start the OpenVPN client and connect. You shouldn&#8217;t have any problems and you&#8217;ll get 10.8.0.2 IP assigned to your laptop. If you try to ping 10.8.0.1 you&#8217;ll get a response. Do route print and you&#8217;ll see that the routes for 192.168.1.0 are going over 10.8.0.1. But, if you try to ping some server internally, e.g. 192.168.1.21, you won&#8217;t get any response. That&#8217;s because that server doesn&#8217;t know the route back. You can easily add the route to each server but it&#8217;s not practical. Let&#8217;s make one more change to the server.</p>
<h1>OpenVPN server</h1>
<p>Add these two lines to <em>/etc/rc.conf</em>. That&#8217;s the FreeBSD pf firewall.</p>
<pre class="brush: bash; title: ; notranslate">
pf_enable=&quot;YES&quot;
pf_rules=&quot;/etc/pf.conf&quot;
</pre>
<p>Now, create this config file in <em>/etc/pf.conf</em>. Many thanks to <a href="https://gundersen.net/openvpn-server-on-freebsd-with-pf-firewall/" target="_blank">this </a>guy. </p>
<pre class="brush: bash; title: ; notranslate">
vpnclients = &quot;10.8.0.0/24&quot;
# The name of your NIC. I am using a VM on ESXi and vmx0 is my NIC.
wanint = &quot;vmx0&quot;
# put your tunnel interface here, it is usually tun0
vpnint = &quot;tun0&quot;
# OpenVPN by default runs on udp port 1194
udpopen = &quot;{1194}&quot;
# Open the SSH port.
tcpopen = &quot;{22}&quot;
icmptypes = &quot;{echoreq, unreach}&quot;

set skip on lo
# the essential line
nat on $wanint inet from $vpnclients to any -&gt; $wanint

block in
pass in on $wanint proto udp from any to $wanint port $udpopen
pass in on $wanint proto tcp from any to $wanint port $tcpopen
# the following two lines could be made stricter if you don&#039;t trust the clients
pass out quick
pass in on $vpnint from any to any
pass in inet proto icmp all icmp-type $icmptypes
</pre>
<p>Reboot the OpenVPN server and if you reconnect from the client, you can use the internal IPs directly to connect.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2024/11/freebsd-openvpn-server-in-a-lan-local-network-environment/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>AWS: Snapshot Clean Up script in Lambda</title>
		<link>https://blog.andreev.it/2019/02/148-aws-lambda-snapshot-clean-up-script/</link>
					<comments>https://blog.andreev.it/2019/02/148-aws-lambda-snapshot-clean-up-script/#respond</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Wed, 13 Feb 2019 20:02:05 +0000</pubDate>
				<category><![CDATA[AWS]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[AMI]]></category>
		<category><![CDATA[Lambda]]></category>
		<category><![CDATA[Snapshot]]></category>
		<guid isPermaLink="false">https://blog.andreev.it/?p=4467</guid>

					<description><![CDATA[I have several scripts that I use to do some maintenance on my servers&#8230;]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>I have several scripts that I use to do some maintenance on my servers (snapshots, backups, cleanups etc) and they are all scattered on different servers. I&#8217;ve decided to consolidate them and use AWS Lambda to do the scheduling and execution for me. So, in this post I&#8217;ll explain how to create simple snapshot clean up script that deletes some old AWS snapshots and runs once a day. In addition, I&#8217;ll do the same Lambda script, but this time using the <a href="https://serverless.com" target="_blank" rel="noopener noreferrer">serverless</a> framework.</p>
<div style="border: 1px solid red; padding: 16px;">
<p style="text-align: center;"><strong><span style="color: #800000;">NOTE ABOUT SNAPSHOTS</span> </strong><br />
<i>The Lambda function deletes snapshots only. If the snapshot is associated with an AMI, you&#8217;ll get a message that the snapshot is in use.</i></p>
</div>
<p>The setup below requires Full Access to AWS.</p>
<h1>SNS</h1>
<p>First, let&#8217;s configure SNS that we&#8217;ll use to send us the notifications from the script. Go to <strong>SNS </strong>and click on <strong>Create topic</strong>.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2019/02/P125-01.png"><img decoding="async" src="https://blog.andreev.it/wp-content/uploads/2019/02/P125-01.png" alt="" width="411" height="315" class="aligncenter size-full wp-image-8445" srcset="https://blog.andreev.it/wp-content/uploads/2019/02/P125-01.png 411w, https://blog.andreev.it/wp-content/uploads/2019/02/P125-01-300x230.png 300w" sizes="(max-width: 411px) 100vw, 411px" /></a><br />
Name your topic and click on <strong>Create topic</strong>.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2019/02/P125-02.png"><img decoding="async" src="https://blog.andreev.it/wp-content/uploads/2019/02/P125-02.png" alt="" width="419" height="313" class="aligncenter size-full wp-image-8446" srcset="https://blog.andreev.it/wp-content/uploads/2019/02/P125-02.png 419w, https://blog.andreev.it/wp-content/uploads/2019/02/P125-02-300x224.png 300w" sizes="(max-width: 419px) 100vw, 419px" /></a><br />
Once there, click on <strong>Create subscription</strong>.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2019/02/P125-03.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2019/02/P125-03.png" alt="" width="276" height="208" class="aligncenter size-full wp-image-8447" /></a><br />
In my case, I want to receive an e-mail. Click on <strong>Create subscription</strong>.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2019/02/P125-04.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2019/02/P125-04.png" alt="" width="865" height="339" class="aligncenter size-full wp-image-8448" srcset="https://blog.andreev.it/wp-content/uploads/2019/02/P125-04.png 865w, https://blog.andreev.it/wp-content/uploads/2019/02/P125-04-300x118.png 300w, https://blog.andreev.it/wp-content/uploads/2019/02/P125-04-768x301.png 768w, https://blog.andreev.it/wp-content/uploads/2019/02/P125-04-585x229.png 585w" sizes="(max-width: 865px) 100vw, 865px" /></a><br />
If you check your e-mail, you&#8217;ll see that you have to confirm the subscription. Click on <strong>Confirm subscription</strong> in the e-mail and you are done with this part.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2019/02/P125-05.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2019/02/P125-05.png" alt="" width="490" height="324" class="aligncenter size-full wp-image-8449" srcset="https://blog.andreev.it/wp-content/uploads/2019/02/P125-05.png 490w, https://blog.andreev.it/wp-content/uploads/2019/02/P125-05-300x198.png 300w, https://blog.andreev.it/wp-content/uploads/2019/02/P125-05-263x175.png 263w" sizes="(max-width: 490px) 100vw, 490px" /></a></p>
<h1>Lambda function</h1>
<p>We are ready to deploy the script now. Go to <strong>Lambda </strong>and click on <strong>Create a function</strong>. Fill out the form so it looks like this.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2019/02/P125-06.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2019/02/P125-06.png" alt="" width="1123" height="678" class="aligncenter size-full wp-image-8450" srcset="https://blog.andreev.it/wp-content/uploads/2019/02/P125-06.png 1123w, https://blog.andreev.it/wp-content/uploads/2019/02/P125-06-300x181.png 300w, https://blog.andreev.it/wp-content/uploads/2019/02/P125-06-1024x618.png 1024w, https://blog.andreev.it/wp-content/uploads/2019/02/P125-06-768x464.png 768w, https://blog.andreev.it/wp-content/uploads/2019/02/P125-06-585x353.png 585w" sizes="(max-width: 1123px) 100vw, 1123px" /></a><br />
Once you select <strong>Create a custom role</strong> a new window will pop up.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2019/02/P125-07.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2019/02/P125-07.png" alt="" width="509" height="294" class="aligncenter size-full wp-image-8451" srcset="https://blog.andreev.it/wp-content/uploads/2019/02/P125-07.png 509w, https://blog.andreev.it/wp-content/uploads/2019/02/P125-07-300x173.png 300w" sizes="(max-width: 509px) 100vw, 509px" /></a><br />
Click <strong>Allow </strong>and the window will close. You&#8217;ll be back to the initial screen. Click <strong>Create function</strong> here.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2019/02/P125-08.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2019/02/P125-08.png" alt="" width="1119" height="303" class="aligncenter size-full wp-image-8452" srcset="https://blog.andreev.it/wp-content/uploads/2019/02/P125-08.png 1119w, https://blog.andreev.it/wp-content/uploads/2019/02/P125-08-300x81.png 300w, https://blog.andreev.it/wp-content/uploads/2019/02/P125-08-1024x277.png 1024w, https://blog.andreev.it/wp-content/uploads/2019/02/P125-08-768x208.png 768w, https://blog.andreev.it/wp-content/uploads/2019/02/P125-08-585x158.png 585w" sizes="(max-width: 1119px) 100vw, 1119px" /></a><br />
If you scroll down a bit, you&#8217;ll see a placeholder for a Python code. I already have my function ready, so I&#8217;ll just delete what&#8217;s in there and paste my script. Make sure you change the values in line numbers 8 and 10. Line number 8 is your AWS account and line number 10 is the amount of days that you want your snapshots to be kept. Also, if you have any snapshots that you want to keep no matter how many days they are old, you can specify their IDs in line 6. They&#8217;ll be skipped. Anything older than <em>diff_time</em> days will be deleted. Also, if your SNS topic was named differently, change the line number 53.</p>
<pre class="brush: python; title: ; notranslate">
import json, boto3, datetime

def lambda_handler(event, context):

    # Do not delete these snaps
    snap_ignore = &#x5B;'snap-12718f7046cc2add6','snap-0e738d4c47b2d6e14']    
    # Enter the AWS account number here
    accountId = '123456789012'
    # Delete snapshots older than diff_time days   
    diff_time = 30
    # Constant string
    no_snap = 'No snaps were found for clean up.'  
    # Constant string
    skip_str = 'was skipped because it is in use.'
    # Leave it empty
    mail_body = ''

    
    ec2 = boto3.resource('ec2')
    sns = boto3.client('sns')

    # Get all the snaps from the account
    snaps = ec2.snapshots.filter(OwnerIds=&#x5B;accountId])
    # Get the current time
    now_time = datetime.datetime.now().date()
    # Iterate through the snaps
    for snap in snaps:
        # Check for protected snaps, e.g the ones that we have to skip and ignore
        if (snap.id in snap_ignore): 
            continue
        # Get the creation time of the snap
        snap_time = snap.start_time.date()
        # Get the current time
        now_time = datetime.datetime.now().date()
        # Calculate the difference
        snapage_time = (now_time - snap_time).days
        # If the creation time is older than the required difference
        if(snapage_time &gt; diff_time):
            try:
                # Delete the snap
                snap.delete(snap.id)
                # Print the snap that will be deleted
                print(snap.id,'created on',snap_time,'was deleted')
                mail_body = mail_body + snap.id + ' created on ' + str(snap_time) + ' was deleted.\n'
            # Catch an exception if the snap is in use
            except:
                print(snap.id, skip_str)
                mail_body = mail_body + snap.id + ' ' + skip_str + '\n'
                continue
    if (mail_body == ''):
        mail_body = no_snap
    response = sns.publish(
        TopicArn = 'arn:aws:sns:us-east-1:' + accountId + ':topSnapCleanUp',
        Message = mail_body,
        Subject = 'Snapshot Clean up ' + str(now_time)
    )
</pre>
<p>Click <strong>Save </strong>in the upper right corner and click <strong>Test</strong>. Enter something for the Event name and click <strong>Create</strong>. Click <strong>Test </strong>again. You&#8217;ll get an error at the top of the screen.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2019/02/P125-09.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2019/02/P125-09.png" alt="" width="1083" height="423" class="aligncenter size-full wp-image-8453" srcset="https://blog.andreev.it/wp-content/uploads/2019/02/P125-09.png 1083w, https://blog.andreev.it/wp-content/uploads/2019/02/P125-09-300x117.png 300w, https://blog.andreev.it/wp-content/uploads/2019/02/P125-09-1024x400.png 1024w, https://blog.andreev.it/wp-content/uploads/2019/02/P125-09-768x300.png 768w, https://blog.andreev.it/wp-content/uploads/2019/02/P125-09-585x228.png 585w" sizes="(max-width: 1083px) 100vw, 1083px" /></a><br />
The error means that we don&#8217;t have rights. So, we have to add a policy to our role that we created earlier.</p>
<h1>IAM Roles and Policies</h1>
<p>If you go to the IAM service and search for the role that you&#8217;ve created, you&#8217;ll see that it&#8217;s there and that there is a simple Lambda policy attached.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2019/02/P125-10.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2019/02/P125-10.png" alt="" width="696" height="522" class="aligncenter size-full wp-image-8454" srcset="https://blog.andreev.it/wp-content/uploads/2019/02/P125-10.png 696w, https://blog.andreev.it/wp-content/uploads/2019/02/P125-10-300x225.png 300w, https://blog.andreev.it/wp-content/uploads/2019/02/P125-10-585x439.png 585w" sizes="(max-width: 696px) 100vw, 696px" /></a><br />
If you look at the policy, you&#8217;ll see that this policy gives access to CloudWatch logs. What we need in the policy is access to snapshots and SNS. Click on <strong>Edit policy</strong> and copy and paste this one. Replace your account number in line 16.</p>
<pre class="brush: bash; title: ; notranslate">
{
    &quot;Version&quot;: &quot;2012-10-17&quot;,
    &quot;Statement&quot;: &#x5B;
        {
            &quot;Effect&quot;: &quot;Allow&quot;,
            &quot;Action&quot;: &#x5B;
                &quot;ec2:DeleteSnapshot&quot;,
                &quot;ec2:DescribeVolumes&quot;,
                &quot;ec2:DescribeSnapshots&quot;
            ],
            &quot;Resource&quot;: &quot;*&quot;
        },
        {
            &quot;Effect&quot;: &quot;Allow&quot;,
            &quot;Action&quot;: &quot;sns:Publish&quot;,
            &quot;Resource&quot;: &quot;arn:aws:sns:us-east-1:123456789012:topSnapCleanUp&quot;
        }
    ]
}
</pre>
<p>If you save the policy and run the Lambda function, you&#8217;ll see that everything works as expected. But, we want to go a step further and automate the execution of the script.</p>
<h1>CloudWatch</h1>
<p>First, we need to decide when we want this script to start. In my case, I want the script to run at 1AM in the morning. Go to <strong>CloudWatch</strong>, click on <strong>Rules </strong>on the left side and click on <strong>Create rule</strong> button.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2019/02/P125-11.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2019/02/P125-11.png" alt="" width="425" height="321" class="aligncenter size-full wp-image-8455" srcset="https://blog.andreev.it/wp-content/uploads/2019/02/P125-11.png 425w, https://blog.andreev.it/wp-content/uploads/2019/02/P125-11-300x227.png 300w" sizes="(max-width: 425px) 100vw, 425px" /></a><br />
Click on <strong>Cron expression</strong> and enter <em>0 1 * * ? *</em>. If you don&#8217;t know what this means, it&#8217;s a cron syntax. Google it and you&#8217;ll figure it out. It&#8217;s easy. On the right side, under <strong>Targets</strong>, choose our Lambda function from the drop-down. Then click <strong>Configure details</strong>.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2019/02/P125-12.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2019/02/P125-12.png" alt="" width="1060" height="653" class="aligncenter size-full wp-image-8456" srcset="https://blog.andreev.it/wp-content/uploads/2019/02/P125-12.png 1060w, https://blog.andreev.it/wp-content/uploads/2019/02/P125-12-300x185.png 300w, https://blog.andreev.it/wp-content/uploads/2019/02/P125-12-1024x631.png 1024w, https://blog.andreev.it/wp-content/uploads/2019/02/P125-12-768x473.png 768w, https://blog.andreev.it/wp-content/uploads/2019/02/P125-12-585x360.png 585w" sizes="(max-width: 1060px) 100vw, 1060px" /></a><br />
Under Step 2, enter the rule name, description and click on <strong>Create rule</strong>.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2019/02/P125-13.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2019/02/P125-13.png" alt="" width="1058" height="361" class="aligncenter size-full wp-image-8457" srcset="https://blog.andreev.it/wp-content/uploads/2019/02/P125-13.png 1058w, https://blog.andreev.it/wp-content/uploads/2019/02/P125-13-300x102.png 300w, https://blog.andreev.it/wp-content/uploads/2019/02/P125-13-1024x349.png 1024w, https://blog.andreev.it/wp-content/uploads/2019/02/P125-13-768x262.png 768w, https://blog.andreev.it/wp-content/uploads/2019/02/P125-13-585x200.png 585w" sizes="(max-width: 1058px) 100vw, 1058px" /></a><br />
In case your function times out because you have way too many snapshots, you can increase the time-out settings for the function from the main Lambda screen.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2019/02/P125-14.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2019/02/P125-14.png" alt="" width="417" height="347" class="aligncenter size-full wp-image-8458" srcset="https://blog.andreev.it/wp-content/uploads/2019/02/P125-14.png 417w, https://blog.andreev.it/wp-content/uploads/2019/02/P125-14-300x250.png 300w" sizes="(max-width: 417px) 100vw, 417px" /></a><br />
You are all set.</p>
<h1>Serverless</h1>
<p>You can deploy the same solution without even logging to the console. All you need is the <a href="https://serverless.com/" target="_blank" rel="noopener noreferrer">serverless </a>framework. I won&#8217;t explain how to install and configure serverless, so once you are done, let&#8217;s create our first serverless project.</p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
sls create -t aws-python3 -p SnapCleanUp
Serverless: Generating boilerplate...
Serverless: Generating boilerplate in &quot;/home/klimenta/SnapCleanUp&quot;
 _______                             __
|   _   .-----.----.--.--.-----.----|  .-----.-----.-----.
|   |___|  -__|   _|  |  |  -__|   _|  |  -__|__ --|__ --|
|____   |_____|__|  \___/|_____|__| |__|_____|_____|_____|
|   |   |             The Serverless Application Framework
|       |                           serverless.com, v1.37.1
 -------'

Serverless: Successfully generated boilerplate for template: &quot;aws-python3&quot;
</pre>
<p>Serverless will generate the skeleton code and YAML config file for you. If you go to that directory, you&#8217;ll see two files: <strong>handler.py</strong> which is our Python function and <strong>serverless.yml</strong> which is the AWS config written in YAML. You can take a look at the generic files to see what&#8217;s going on. In our case we&#8217;ll replace these two files with ours. So, here is the <strong>handler.py</strong> file. As you can see it&#8217;s pretty much the same as the Python file that we used initially.</p>
<pre class="brush: python; title: ; notranslate">
import json, boto3, datetime

def snapcleanup(event, context):

    # Do not delete these snaps
    snap_ignore = &#x5B;'snap-12718f7046cc2add6','snap-0e738d4c47b2d6e14']
    # Enter the AWS account number here
    accountId = '123456789012'
    # Delete snapshots older than diff_time days
    diff_time = 30
    # Constant string
    no_snap = 'No snaps were found for clean up.'
    # Constant string
    skip_str = 'was skipped because it is in use.'
    # Leave it empty
    mail_body = ''

    ec2 = boto3.resource('ec2')
    sns = boto3.client('sns')

    # Get all the snaps from the account
    snaps = ec2.snapshots.filter(OwnerIds=&#x5B;accountId])
    # Get the current time
    now_time = datetime.datetime.now().date()
    # Iterate through the snaps
    for snap in snaps:
        # Check for protected snaps, e.g the ones that we have to skip and ignore
        if (snap.id in snap_ignore):
            continue
        # Get the creation time of the snap
        snap_time = snap.start_time.date()
        # Get the current time
        now_time = datetime.datetime.now().date()
        # Calculate the difference
        snapage_time = (now_time - snap_time).days
        # If the creation time is older than the required difference
        if(snapage_time &gt; diff_time):
            try:
                # Delete the snap
                snap.delete(snap.id)
                # Print the snap that will be deleted
                print(snap.id,'created on',snap_time,'was deleted')
                mail_body = mail_body + snap.id + ' created on ' + str(snap_time) + ' was deleted.\n'
            # Catch an exception if the snap is in use
            except:
                print(snap.id, skip_str)
                mail_body = mail_body + snap.id + ' ' + skip_str + '\n'
                continue
    if (mail_body == ''):
        mail_body = no_snap
    response = sns.publish(
        TopicArn = 'arn:aws:sns:us-east-1:' + accountId + ':topSnapCleanUp',
        Message = mail_body,
        Subject = 'Snapshot Clean up ' + str(now_time)
    )
</pre>
<p>And here is the YAML file that does the heavy lifting of creating and gluing everything for you.</p>
<pre class="brush: xml; title: ; notranslate">
service: SnapCleanUp

provider:
  name: aws
  runtime: python3.7
  timeout: 10
  stage: prod
  region: us-east-1
  iamRoleStatements:
    - Effect: &quot;Allow&quot;
      Action:
      - ec2:DeleteSnapshot
      - ec2:DescribeVolumes
      - ec2:DescribeSnapshots
      Resource: &quot;*&quot;
    - Effect: Allow
      Action: sns:Publish
      Resource: {&quot;Ref&quot; : &quot;SNSTopic&quot;}

functions:
  snapcleanup:
    handler: handler.snapcleanup
    description: Deletes snaps older than XX days
    events:
      - schedule: cron(* 1 * * ? *)
        enabled: true
resources:
  Resources:
    SNSTopic:
      Type: AWS::SNS::Topic
      Properties:
        DisplayName: 'Snap Clean'
        TopicName: topSnapCleanUp

    SNSSubscription:
      Type: AWS::SNS::Subscription
      Properties:
        Endpoint: klimenta@iandreev.com
        Protocol: email
        TopicArn: {&quot;Ref&quot; : &quot;SNSTopic&quot;}
</pre>
<p>Here is a brief description. In the <strong>provider </strong>section you specify that you&#8217;ll use Python 3, the timeout for the execution will be 10 seconds and the region is us-east-1. We also have the role defined here. If you look the initial JSON script for the role, well, this is the same, except it&#8217;s in YAML. You can use any online converter to translate JSON to YAML. The <strong>function </strong>section is where I specify the name of the function and I also create the CloudWatch rule so the script runs at 1AM every day. Finally in the <strong>resources </strong>section I create the SNS topic and the subscription. For more information about the syntax, see the docs on the serverless site.<br />
Anyway, we can deploy the function now.</p>
<pre class="brush: bash; title: ; notranslate">
sls deploy -v
</pre>
<p>It takes about a minute for all resources to be completed. Once deployed, check your e-mail and look for the confirmation e-mail. You have to confirm your subscription. And pretty much that&#8217;s it. If you take a look at the console (Lambda, IAM roles, CLoudWatch rules and logs), you&#8217;ll see that pretty much every AWS resource looks the same as our first manual try.</p>
<h1>Helpful tips</h1>
<p>If you have to make a change in the function (handler.py), you don&#8217;t have to redeploy the whole solution. You can just deploy the function itself.</p>
<pre class="brush: bash; title: ; notranslate">
sls deploy function -f snapcleanup
</pre>
<p>Also, we have a scheduled that runs the function at a specified interval, but you can run the script manually.</p>
<pre class="brush: bash; title: ; notranslate">
sls invoke -f snapcleanup -l
</pre>
<p>Check the logs of the function in real-time.</p>
<pre class="brush: bash; title: ; notranslate">
sls logs -f snapcleanup -t
</pre>
<p>If you want to remove all resources and delete the function, use the remove parameter.</p>
<pre class="brush: bash; title: ; notranslate">
sls remove
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2019/02/148-aws-lambda-snapshot-clean-up-script/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>python: Tetris clone in python and pygame</title>
		<link>https://blog.andreev.it/2015/11/python-pygame-tetris-variant/</link>
					<comments>https://blog.andreev.it/2015/11/python-pygame-tetris-variant/#respond</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Sun, 08 Nov 2015 15:34:28 +0000</pubDate>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[pygame]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[Tetris]]></category>
		<guid isPermaLink="false">http://blog.iandreev.com/?p=2042</guid>

					<description><![CDATA[I was playing with python and pygame and decided to make a variant of&#8230;]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>I was playing with python and pygame and decided to make a variant of the Tetris game (called KAtrix). This one is a little easier because the shapes do not fall automatically from the top. You have to move them with the left, right and down cursor keys and confirm the position with the space key.<br />
Here is the screenshot and the source.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2015/11/P057-01.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2015/11/P057-01.png" alt="" width="647" height="508" class="aligncenter size-full wp-image-7389" srcset="https://blog.andreev.it/wp-content/uploads/2015/11/P057-01.png 647w, https://blog.andreev.it/wp-content/uploads/2015/11/P057-01-300x236.png 300w, https://blog.andreev.it/wp-content/uploads/2015/11/P057-01-585x459.png 585w" sizes="(max-width: 647px) 100vw, 647px" /></a></p>
<pre class="brush: plain; title: ; notranslate">
git clone https://github.com/klimenta/KAtrix
</pre>
<p>Not well documented, but it gives an idea what&#8217;s going on.</p>
<pre class="brush: python; collapse: true; light: false; title: ; toolbar: true; notranslate">
__author__ = 'Kliment Andreev'
__version__ = '20151108 15:48'

# Imports
import random
import time
import pygame
import sys
from pygame.locals import *

# Constants and dictionaries
# Frames per second
FPS = 25
# The top left column where the falling shape is positioned initially
START_COL = 4
# Represent a box or empty space for a shape
EMPTY_BOX = '-'
FULL_BOX = 'X'
# Window dimensions
WINDOW_WIDTH = 640
WINDOW_HEIGHT = 480
# Matrix dimensions, including 4 borders (left, right, top, bottom)
MATRIX_WIDTH = 12
MATRIX_HEIGHT = 22
# Fill the matrix with zeros
MATRIX = &#x5B;&#x5B;0 for x in range(MATRIX_WIDTH)] for x in range(MATRIX_HEIGHT)]
#Box width in pixels. Each shape is composed of boxes.
BOX_SIZE = 20
# Define 16 web colors
BLACK = (0x00, 0x00, 0x00)
YELLOW = (0xff, 0xff, 0x00)
WHITE = (0xff, 0xff, 0xff)
SILVER = (0xc0, 0xc0, 0xc0)
GRAY = (0x80, 0x80, 0x80)
RED = (0xff, 0x00, 0x00)
MAROON = (0x80, 0x00, 0x00)
OLIVE = (0x80, 0x80, 0x00)
LIME = (0x00, 0xff, 0x00)
GREEN = (0x00, 0x80, 0x00)
AQUA = (0x00, 0xff, 0xff)
TEAL = (0x00, 0x80, 0x80)
BLUE = (0x00, 0x00, 0xff)
NAVY = (0x00, 0x00, 0x80)
FUCHSIA = (0xff, 0x00, 0xff)
PURPLE = (0x80, 0x00, 0x80)
# Top left coordinates of the matrix
TOP_X = 199
TOP_Y = 19
# Top left coordinates of the the box at (0,0)
# This is the top left coordinate of the top-left shape can be
TOP_BOX_X = TOP_X + BOX_SIZE
TOP_BOX_Y = TOP_Y + BOX_SIZE
# These are the shapes
# Each line represent an original position
# and three possible rotations
SHAPE_I = ((&quot;----&quot;), (&quot;XXXX&quot;), (&quot;----&quot;), (&quot;----&quot;)), \
          ((&quot;-X--&quot;), (&quot;-X--&quot;), (&quot;-X--&quot;), (&quot;-X--&quot;)), \
          ((&quot;----&quot;), (&quot;XXXX&quot;), (&quot;----&quot;), (&quot;----&quot;)), \
          ((&quot;-X--&quot;), (&quot;-X--&quot;), (&quot;-X--&quot;), (&quot;-X--&quot;))
SHAPE_J = ((&quot;--X-&quot;), (&quot;--X-&quot;), (&quot;-XX-&quot;), (&quot;----&quot;)), \
          ((&quot;-X--&quot;), (&quot;-XXX&quot;), (&quot;----&quot;), (&quot;----&quot;)), \
          ((&quot;-XX-&quot;), (&quot;-X--&quot;), (&quot;-X--&quot;), (&quot;----&quot;)), \
          ((&quot;-XXX&quot;), (&quot;---X&quot;), (&quot;----&quot;), (&quot;----&quot;))
SHAPE_L = ((&quot;-X--&quot;), (&quot;-X--&quot;), (&quot;-XX-&quot;), (&quot;----&quot;)), \
          ((&quot;XXX-&quot;), (&quot;X---&quot;), (&quot;----&quot;), (&quot;----&quot;)), \
          ((&quot;-XX-&quot;), (&quot;--X-&quot;), (&quot;--X-&quot;), (&quot;----&quot;)), \
          ((&quot;--X-&quot;), (&quot;XXX-&quot;), (&quot;----&quot;), (&quot;----&quot;))
SHAPE_O = ((&quot;-XX-&quot;), (&quot;-XX-&quot;), (&quot;----&quot;), (&quot;----&quot;)), \
          ((&quot;-XX-&quot;), (&quot;-XX-&quot;), (&quot;----&quot;), (&quot;----&quot;)), \
          ((&quot;-XX-&quot;), (&quot;-XX-&quot;), (&quot;----&quot;), (&quot;----&quot;)), \
          ((&quot;-XX-&quot;), (&quot;-XX-&quot;), (&quot;----&quot;), (&quot;----&quot;))
SHAPE_S = ((&quot;----&quot;), (&quot;-XX-&quot;), (&quot;XX--&quot;), (&quot;----&quot;)), \
          ((&quot;-X--&quot;), (&quot;-XX-&quot;), (&quot;--X-&quot;), (&quot;----&quot;)), \
          ((&quot;----&quot;), (&quot;-XX-&quot;), (&quot;XX--&quot;), (&quot;----&quot;)), \
          ((&quot;-X--&quot;), (&quot;-XX-&quot;), (&quot;--X-&quot;), (&quot;----&quot;))
SHAPE_T = ((&quot;XXX-&quot;), (&quot;-X--&quot;), (&quot;----&quot;), (&quot;----&quot;)), \
          ((&quot;--X-&quot;), (&quot;-XX-&quot;), (&quot;--X-&quot;), (&quot;----&quot;)), \
          ((&quot;-X--&quot;), (&quot;XXX-&quot;), (&quot;----&quot;), (&quot;----&quot;)), \
          ((&quot;X---&quot;), (&quot;XX--&quot;), (&quot;X---&quot;), (&quot;----&quot;))
SHAPE_Z = ((&quot;----&quot;), (&quot;-XX-&quot;), (&quot;--XX&quot;), (&quot;----&quot;)), \
          ((&quot;--X-&quot;), (&quot;-XX-&quot;), (&quot;-X--&quot;), (&quot;----&quot;)), \
          ((&quot;----&quot;), (&quot;-XX-&quot;), (&quot;--XX&quot;), (&quot;----&quot;)), \
          ((&quot;--X-&quot;), (&quot;-XX-&quot;), (&quot;-X--&quot;), (&quot;----&quot;))
# List of shapes
SHAPES = (SHAPE_I, SHAPE_J, SHAPE_L, SHAPE_O, SHAPE_S, SHAPE_T, SHAPE_Z)
# Shape Colors - Dictionary
SHAPE_COLOR = {SHAPE_I: BLUE,
               SHAPE_J: PURPLE,
               SHAPE_L: RED,
               SHAPE_O: GREEN,
               SHAPE_S: WHITE,
               SHAPE_T: FUCHSIA,
               SHAPE_Z: AQUA}
# Colors, web colors - dictionary
COLOR_COLOR = {BLACK: 0,
               YELLOW: 1,
               BLUE: 2,
               PURPLE: 3,
               RED: 4,
               GREEN: 5,
               WHITE: 6,
               FUCHSIA: 7,
               AQUA: 8}
# This is a reverse dictionary finder
find_color = dict(&#x5B;&#x5B;value, key] for key, value in COLOR_COLOR.items()])
# All possible combinations of rotations
ROTATE_0_DEGREES = 0
ROTATE_90_DEGREES = 1
ROTATE_180_DEGREES = 2
ROTATE_270_DEGREES = 3
# This is the size of one shape, 4 x 4
SHAPE_SIZE = 4


class Shape(object):
    &quot;&quot;&quot;A class for shapes&quot;&quot;&quot;
    def __init__(self, name, rotation, pos_y, pos_x):
        self.name = name            # Name of the shape, e.g. SHAPE_T
        self.rotation = rotation    # Rotation index of the shape
        self.pos_x = pos_x          # X position of the shape, it can be from 1 to 10
        self.pos_y = pos_y          # Y position of the shape, it can be from 1 to 20

    def drawShapeOnScreen(self):
        &quot;&quot;&quot;
        This method draws all boxes that form a shape on the screen
        and outline each box with a black edge line
        &quot;&quot;&quot;
        piece = self.name&#x5B;self.rotation]
        for x in range(SHAPE_SIZE):
            for y in range(SHAPE_SIZE):
                if piece&#x5B;y]&#x5B;x] != EMPTY_BOX:
                    # This line draws all the squares on the screen
                    pygame.draw.rect(DISPLAY_SURFACE, SHAPE_COLOR&#x5B;self.name],
                                     (x * BOX_SIZE + TOP_X + BOX_SIZE * self.pos_x,
                                      y * BOX_SIZE + TOP_Y + BOX_SIZE * self.pos_y,
                                      BOX_SIZE,
                                      BOX_SIZE))
                    # The following lines outline each square with 1 pixel black line
                    # Top vertical
                    pygame.draw.line(DISPLAY_SURFACE, BLACK,
                                     (x * BOX_SIZE + TOP_X + BOX_SIZE * self.pos_x,
                                      y * BOX_SIZE + TOP_Y + BOX_SIZE * self.pos_y),
                                     (x * BOX_SIZE + TOP_X + BOX_SIZE * self.pos_x + BOX_SIZE,
                                      y * BOX_SIZE + TOP_Y + BOX_SIZE * self.pos_y), 1)
                    # Right horizontal
                    pygame.draw.line(DISPLAY_SURFACE, BLACK,
                                     (x * BOX_SIZE + TOP_X + BOX_SIZE * self.pos_x + BOX_SIZE,
                                      y * BOX_SIZE + TOP_Y + BOX_SIZE * self.pos_y),
                                     (x * BOX_SIZE + TOP_X + BOX_SIZE * self.pos_x + BOX_SIZE,
                                      y * BOX_SIZE + TOP_Y + BOX_SIZE * self.pos_y + BOX_SIZE),
                                     1)
                    # Left horizontal
                    pygame.draw.line(DISPLAY_SURFACE, BLACK,
                                     (x * BOX_SIZE + TOP_X + BOX_SIZE * self.pos_x,
                                      y * BOX_SIZE + TOP_Y + BOX_SIZE * self.pos_y),
                                     (x * BOX_SIZE + TOP_X + BOX_SIZE * self.pos_x,
                                      y * BOX_SIZE + TOP_Y + BOX_SIZE * self.pos_y + BOX_SIZE),
                                     1)
                    # Bottom vertical
                    pygame.draw.line(DISPLAY_SURFACE, BLACK,
                                     (x * BOX_SIZE + TOP_X + BOX_SIZE * self.pos_x,
                                      y * BOX_SIZE + TOP_Y + BOX_SIZE * self.pos_y + BOX_SIZE),
                                     (x * BOX_SIZE + TOP_X + BOX_SIZE * self.pos_x + BOX_SIZE,
                                      y * BOX_SIZE + TOP_Y + BOX_SIZE * self.pos_y + BOX_SIZE),
                                     1)

    def deleteShapeFromScreen(self):
        &quot;&quot;&quot;
        This method deletes the shape from the screen
        &quot;&quot;&quot;
        piece = self.name&#x5B;self.rotation]
        for x in range(SHAPE_SIZE):
            for y in range(SHAPE_SIZE):
                if piece&#x5B;y]&#x5B;x] != EMPTY_BOX:
                    # This line erases all the squares
                    pygame.draw.rect(DISPLAY_SURFACE, BLACK,
                                     (x * BOX_SIZE + TOP_X + BOX_SIZE * self.pos_x,
                                      y * BOX_SIZE + TOP_Y + BOX_SIZE * self.pos_y,
                                      BOX_SIZE, BOX_SIZE))


    def deleteShapeFromMatrix(self):
        &quot;&quot;&quot;
        This method deletes the shape from the matrix
        &quot;&quot;&quot;
        piece = self.name&#x5B;self.rotation]
        for x in range(SHAPE_SIZE):
            for y in range(SHAPE_SIZE):
                if x + self.pos_x &lt; (MATRIX_WIDTH - 1) \
                        and y + self.pos_y &lt; (MATRIX_HEIGHT -1) \
                        and piece&#x5B;y]&#x5B;x] == FULL_BOX:
                    MATRIX&#x5B;y + self.pos_y]&#x5B;x + self.pos_x] = COLOR_COLOR&#x5B;BLACK]
        resetMatrix()

    def returnMaxWidth(self):
        &quot;&quot;&quot;
        Each shape is 4 x 4, but the actual width is different
        for each shape, e.g. horizontal &quot;I&quot; shape is 4 boxes in width
        but the same vertical shape is 2 boxes in width
        This method returns the width from the left. See the shape definition above
        &quot;&quot;&quot;
        max_x = 0
        piece = self.name&#x5B;self.rotation]
        for x in range(SHAPE_SIZE):
            for y in range(SHAPE_SIZE):
                if piece&#x5B;x]&#x5B;y] == FULL_BOX and y &gt; max_x :
                    max_x = y
        return max_x

    def returnMinWidth(self):
        &quot;&quot;&quot;
        Each shape is 4 x 4, but the actual width is different
        for each shape, e.g. horizontal &quot;I&quot; shape is 4 boxes in width
        but the same vertical shape is 2 boxes in width
        This method returns the width from right. See the shape definition above
        &quot;&quot;&quot;
        min_x = SHAPE_SIZE
        piece = self.name&#x5B;self.rotation]
        for x in range(SHAPE_SIZE):
            for y in range(SHAPE_SIZE):
                if piece&#x5B;x]&#x5B;y] == FULL_BOX and y &lt; min_x :
                    min_x = y
        return min_x

    def returnMaxHeight(self):
        &quot;&quot;&quot;
        Each shape is 4 x 4, but the actual height is different
        for each shape, e.g. horizontal &quot;I&quot; shape is 2 boxes in width
        but the same vertical shape is 4 boxes in height
        This method returns the height. See the shape definition above
        &quot;&quot;&quot;
        max_y = 0
        piece = self.name&#x5B;self.rotation]
        for x in range(SHAPE_SIZE):
            for y in range(SHAPE_SIZE):
                if piece&#x5B;x]&#x5B;y] == FULL_BOX and x &gt; max_y :
                    max_y = x
        return max_y

    def returnMaxHeightPerColumn(self, column):
        &quot;&quot;&quot;
        Each shape is 4 x 4, but the actual height is different per column
        for each shape, e.g. horizontal &quot;T&quot; shape can be 1 boxes or 3 boxes in height
        This method return the max height and that's the box that's the lowest in a shape
        &quot;&quot;&quot;
        max_y = 0
        piece = self.name&#x5B;self.rotation]
        for y in range(SHAPE_SIZE):
            if piece&#x5B;y]&#x5B;column] == FULL_BOX and y &gt; max_y:
                max_y = y
        return max_y

    def moveLeft(self):
        &quot;&quot;&quot;
        Move the shape left if possible
        &quot;&quot;&quot;
        if isAvailableLeft(self):
            self.deleteShapeFromMatrix()
            self.deleteShapeFromScreen()
            self.pos_x -= 1
            updateShapeInMatrix(self)
            self.drawShapeOnScreen()

    def moveRight(self):
        &quot;&quot;&quot;
        Move the shape right if possible
        &quot;&quot;&quot;
        if isAvailableRight(self):
            self.deleteShapeFromMatrix()
            self.deleteShapeFromScreen()
            self.pos_x += 1
            updateShapeInMatrix(self)
            self.drawShapeOnScreen()

    def moveDown(self):
        &quot;&quot;&quot;
        Move the shape down if possible
        &quot;&quot;&quot;
        if isAvailableDown(self):
            self.deleteShapeFromMatrix()
            self.deleteShapeFromScreen()
            self.pos_y += 1
            updateShapeInMatrix(self)
            self.drawShapeOnScreen()

    def moveRotate(self):
        &quot;&quot;&quot;
        Rotate the shape if possible
        &quot;&quot;&quot;
        if isAvailableRotate(self):
            self.deleteShapeFromMatrix()
            self.deleteShapeFromScreen()
            self.rotation += 1
            if self.rotation == 4:
                self.rotation = 0
            updateShapeInMatrix(self)
            self.drawShapeOnScreen()

def resetMatrix():
    &quot;&quot;&quot;
    Updates the edges of the matrix in memory, that's the YELLOW borders
    &quot;&quot;&quot;
    for x in range(0, MATRIX_HEIGHT):
        MATRIX&#x5B;x]&#x5B;0] = COLOR_COLOR&#x5B;YELLOW]
        MATRIX&#x5B;x]&#x5B;MATRIX_WIDTH - 1] = COLOR_COLOR&#x5B;YELLOW]
    for y in range(0, MATRIX_WIDTH):
        MATRIX&#x5B;0]&#x5B;y] = COLOR_COLOR&#x5B;YELLOW]
        MATRIX&#x5B;MATRIX_HEIGHT - 1]&#x5B;y] = COLOR_COLOR&#x5B;YELLOW]

def isAvailable(Shape):
    &quot;&quot;&quot;
    Is the shape available to be moved in the matrix
    Checks the new position initially when dropping it for the first time
    &quot;&quot;&quot;
    allowed = True
    piece = Shape.name&#x5B;Shape.rotation]
    for x in range(SHAPE_SIZE):
        for y in range(SHAPE_SIZE):
            if piece&#x5B;y]&#x5B;x] == FULL_BOX and \
                            MATRIX&#x5B;y + Shape.pos_y]&#x5B;x + Shape.pos_x] &gt;= COLOR_COLOR&#x5B;YELLOW]:
                allowed = False
                break
    return allowed

def isAvailableLeft(Shape):
    &quot;&quot;&quot;
    Is the shape available to be moved left in the matrix
    &quot;&quot;&quot;
    allowed = True
    piece = Shape.name&#x5B;Shape.rotation]
    for y in range(SHAPE_SIZE):
        if piece&#x5B;y]&#x5B;Shape.returnMinWidth()] == FULL_BOX \
                and MATRIX&#x5B;y + Shape.pos_y]&#x5B;Shape.pos_x +Shape.returnMinWidth() - 1] &gt;= COLOR_COLOR&#x5B;YELLOW] :
            allowed = False
            break
    return allowed

def isAvailableRight(Shape):
    &quot;&quot;&quot;
    Is the shape available to be moved right in the matrix
    &quot;&quot;&quot;
    allowed = True
    piece = Shape.name&#x5B;Shape.rotation]
    for y in range(SHAPE_SIZE):
        if piece&#x5B;y]&#x5B;Shape.returnMaxWidth()] == FULL_BOX \
                and MATRIX&#x5B;y + Shape.pos_y]&#x5B;Shape.pos_x + Shape.returnMaxWidth() + 1] &gt;= COLOR_COLOR&#x5B;YELLOW]:
            allowed = False
            break
    return allowed

def isAvailableRotate(Shape):
    &quot;&quot;&quot;
    Is the shape available to be moved rotated in the matrix
    &quot;&quot;&quot;
    allowed = True
    oldMaxWidth= Shape.returnMaxWidth()
    oldMinWidth = Shape. returnMinWidth()
    oldMaxHeight = Shape.returnMaxHeight()
    oldRotation = Shape.rotation
    Shape.rotation += 1
    if Shape.rotation == 4:
        Shape.rotation = 0
    newMaxWidth = Shape.returnMaxWidth()
    newMinWidth = Shape.returnMinWidth()
    newMaxHeight = Shape.returnMaxHeight()
    if (newMinWidth - oldMinWidth) + Shape.pos_x &lt; 0 \
            or (newMaxWidth - oldMaxWidth) + Shape.pos_x &gt;= (MATRIX_WIDTH - 2):
        allowed = False
    if (newMaxHeight - oldMaxHeight) + Shape.pos_y &gt;= (MATRIX_HEIGHT -2):
        allowed = False
    Shape.rotation = oldRotation
    return allowed

def isAvailableDown(Shape):
    &quot;&quot;&quot;
    Is the shape available to be moved down in the matrix
    &quot;&quot;&quot;
    allowed = True
    piece = Shape.name&#x5B;Shape.rotation]
    for x in range(SHAPE_SIZE):
        if piece&#x5B;Shape.returnMaxHeightPerColumn(x)]&#x5B;x] == FULL_BOX and \
                        MATRIX&#x5B;Shape.pos_y + Shape.returnMaxHeightPerColumn(x) + 1]&#x5B;x + Shape.pos_x] &gt;= COLOR_COLOR&#x5B;YELLOW] :
            allowed = False
            break
    return allowed

def updateShapeInMatrix(Shape):
    &quot;&quot;&quot;
    Updates the matrix with the moved shape
    &quot;&quot;&quot;
    piece = Shape.name&#x5B;Shape.rotation]
    for x in range(SHAPE_SIZE):
        for y in range(SHAPE_SIZE):
            if piece&#x5B;y]&#x5B;x] == &quot;X&quot; and (y + Shape.pos_y) in range (1, MATRIX_HEIGHT - 1) \
                    and (x + Shape.pos_x) in range(1, MATRIX_WIDTH - 1) \
                    and MATRIX&#x5B;y + Shape.pos_y]&#x5B;x + Shape.pos_x] == COLOR_COLOR&#x5B;BLACK]:
                MATRIX&#x5B;y + Shape.pos_y]&#x5B;x + Shape.pos_x] = COLOR_COLOR&#x5B;SHAPE_COLOR&#x5B;Shape.name]]
    resetMatrix()

def drawMatrixOnScreen():
    &quot;&quot;&quot;
    Draws four bars where the game occurs
    &quot;&quot;&quot;
    # Left bar
    pygame.draw.rect(DISPLAY_SURFACE, YELLOW, (TOP_X,
                                               TOP_Y,
                                               BOX_SIZE,
                                               MATRIX_HEIGHT * BOX_SIZE + 1))
    # Right bar
    pygame.draw.rect(DISPLAY_SURFACE, YELLOW, (TOP_X + (MATRIX_WIDTH - 1) * BOX_SIZE + 1,
                                               TOP_Y,
                                               BOX_SIZE,
                                               MATRIX_HEIGHT * BOX_SIZE + 1))
    # Bottom bar
    pygame.draw.rect(DISPLAY_SURFACE, YELLOW, (TOP_X + BOX_SIZE,
                                               TOP_Y + (MATRIX_HEIGHT - 1) * BOX_SIZE + 1,
                                               (MATRIX_WIDTH - 2) * BOX_SIZE + 1,
                                               BOX_SIZE))
    # Top bar
    pygame.draw.rect(DISPLAY_SURFACE, YELLOW, (TOP_X + BOX_SIZE,
                                               TOP_Y,
                                               (MATRIX_WIDTH - 2) * BOX_SIZE + 1,
                                               BOX_SIZE))

def checkFullLine():
    &quot;&quot;&quot;
    Check if there is a full horizontal line in the matrix.
    &quot;&quot;&quot;
    for x in range(MATRIX_HEIGHT - 2, 0, - 1):
        if 0 not in MATRIX&#x5B;x]:
            return x

def printText(msg, FONT, x_cor, y_cor, b_color, f_color):
    &quot;&quot;&quot;
    Writes Text on the screen
    &quot;&quot;&quot;
    text = FONT.render(msg, True, b_color, f_color)
    textRect = text.get_rect()
    textRect.centerx = x_cor
    textRect.centery = y_cor
    DISPLAY_SURFACE.blit(text, textRect)

def drawRectangle(x_cor, y_cor, width, height, color):
    &quot;&quot;&quot;
    Draws rectangle on the screen
    &quot;&quot;&quot;
    pygame.draw.rect(DISPLAY_SURFACE, color, (x_cor, y_cor, width, height))

def printScore(score):
    &quot;&quot;&quot;
    Prints score on the screen
    &quot;&quot;&quot;
    printText('SCORE:', FONT_SMALL, 490, 240, WHITE, BLACK)
    printText(str(score), FONT_SMALL, 580, 240, WHITE, BLACK)

def shiftShapesOnScreen(row):
    &quot;&quot;&quot;
    Shift shapes down on the screen when one line is full and collapses
    &quot;&quot;&quot;
    for col in range(1, MATRIX_WIDTH -1):
        pygame.draw.rect(DISPLAY_SURFACE,
                         find_color&#x5B;MATRIX&#x5B;row]&#x5B;col]],
                         (TOP_X + BOX_SIZE * col,
                          TOP_Y + BOX_SIZE * row,
                          BOX_SIZE,
                          BOX_SIZE))

        # This line outlines each square with 1 pixel black line
        # Top vertical
        pygame.draw.line(DISPLAY_SURFACE, BLACK,
            (TOP_X + BOX_SIZE * col,
            TOP_Y + BOX_SIZE * row),
            (TOP_X + BOX_SIZE * col + BOX_SIZE,
            TOP_Y + BOX_SIZE * row), 1)
        # Right horizontal
        pygame.draw.line(DISPLAY_SURFACE, BLACK,
            (TOP_X + BOX_SIZE * col + BOX_SIZE,
            TOP_Y + BOX_SIZE * row),
            (TOP_X + BOX_SIZE * col + BOX_SIZE,
            TOP_Y + BOX_SIZE * row + BOX_SIZE),
            1)
        # Left horizontal
        pygame.draw.line(DISPLAY_SURFACE, BLACK,
            (TOP_X + BOX_SIZE * col,
            TOP_Y + BOX_SIZE * row),
            (TOP_X + BOX_SIZE * col,
            TOP_Y + BOX_SIZE * row + BOX_SIZE),
            1)
        # Bottom vertical
        pygame.draw.line(DISPLAY_SURFACE, BLACK,
            (TOP_X + BOX_SIZE * col,
            TOP_Y + BOX_SIZE * row + BOX_SIZE),
            (TOP_X + BOX_SIZE * col + BOX_SIZE,
            TOP_Y + BOX_SIZE * row + BOX_SIZE),
            1)

def shiftShapesInMatrix(row):
    &quot;&quot;&quot;
    Shift shapes down in the matrix when one line is full and collapses
    &quot;&quot;&quot;
    while row &gt; 1:
        for xx in range(1, MATRIX_WIDTH):
            MATRIX&#x5B;row]&#x5B;xx] = MATRIX&#x5B;row - 1]&#x5B;xx]
        shiftShapesOnScreen(row)
        row -= 1

def main():
    global FPS_CLOCK, DISPLAY_SURFACE, FONT_BIG, FONT_SMALL, FONT_SUPER_SMALL, SCORE
    pygame.init()
    FPS_CLOCK = pygame.time.Clock()
    DISPLAY_SURFACE = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
    pygame.display.set_caption('KAtrix')
    FONT_BIG = pygame.font.SysFont(None, 44)
    FONT_SMALL = pygame.font.SysFont(None, 24)
    FONT_SUPER_SMALL = pygame.font.SysFont(None, 12)
    DISPLAY_SURFACE.fill(BLACK)
    resetMatrix()
    drawMatrixOnScreen()
    SCORE = 0
    printScore(SCORE)
    printText('Program by: Kliment ANDREEV, 2015', FONT_SUPER_SMALL, 320, 470, SILVER, BLACK)
    # MAIN GAME LOOP
    while True:
        new_shape = Shape(SHAPES&#x5B;random.randint(0, len(SHAPES) - 1)], ROTATE_0_DEGREES, 1, START_COL)
        NewPiece = True
        if isAvailable(new_shape):
            Shape.drawShapeOnScreen(new_shape)
            updateShapeInMatrix(new_shape)
        else:
            NewPiece=False
            Shape.drawShapeOnScreen(new_shape)
            drawRectangle(TOP_X, WINDOW_HEIGHT / 2 - 50, 241, 160, BLUE)
            printText(&quot;G A M E  O V E R&quot;, FONT_BIG, WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2 + 30, YELLOW, BLUE)
            pygame.display.update()
            pygame.time.delay(3000)
            pygame.quit()
            sys.exit()
        while NewPiece:
            for event in pygame.event.get():
                if event.type == QUIT:
                    pygame.quit()
                    sys.exit()
                if event.type == KEYDOWN:
                    if (event.key == K_LEFT):
                        Shape.moveLeft(new_shape)
                    elif (event.key == K_RIGHT):
                        Shape.moveRight(new_shape)
                    elif (event.key == K_UP):
                        Shape.moveRotate(new_shape)
                    elif (event.key == K_DOWN):
                        Shape.moveDown(new_shape)
                    elif (event.key == K_SPACE):
                        while isAvailableDown(new_shape):
                            Shape.moveDown(new_shape)
                        NewPiece = False
                        while checkFullLine() &gt; 0:
                            SCORE += 10
                            printScore(SCORE)
                            shiftShapesInMatrix(checkFullLine())
            pygame.display.update()
            FPS_CLOCK.tick(FPS)

if __name__ == '__main__':
    main()
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2015/11/python-pygame-tetris-variant/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Programming: Tips &#038; Tricks (Part I)</title>
		<link>https://blog.andreev.it/2011/12/passing-variables-by-reference-between-two-forms-in-visual-c/</link>
					<comments>https://blog.andreev.it/2011/12/passing-variables-by-reference-between-two-forms-in-visual-c/#comments</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Tue, 27 Dec 2011 19:31:08 +0000</pubDate>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[HTML/CSS]]></category>
		<category><![CDATA[JavaScript/TypeScript]]></category>
		<category><![CDATA[PowerShell]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Unix shell]]></category>
		<category><![CDATA[Tips]]></category>
		<guid isPermaLink="false">http://blog.iandreev.com/?p=194</guid>

					<description><![CDATA[pass variables between two forms in Visual C++ This example will show you how&#8230;]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><h1>pass variables between two forms in Visual C++</h1>
<p>This example will show you how to pass variables between two forms in Visual C++. We’ll create two forms, drop a button and a text box on the first form and a label box on the second form. When we start the program, we can type something in the text box. Once we click the button, the second form will show up with the label containing the text from the text box that’s on the first form.<br />
First, let’s create a project in VC++ 2008. Click <strong>File | New</strong>, then <strong>Visual C++</strong> and then <strong>Windows Forms Application</strong>. From the <strong>Toolbox</strong>, drag and drop, a button and a text box. Next, from the <strong>Solution Explorer</strong> on the right, right-click the name of your project, choose <strong>Add</strong>, <strong>New Item</strong> and then <strong>Windows Form</strong>. When the second form appears, drag and drop a label on the form. Save all files. Open the source for the first form (probably <strong>Form1.h</strong>) and right after the <strong>#pragma</strong> statement insert:</p>
<pre class="brush: cpp; title: ; notranslate">
#include &quot;Form2.h&quot;
// Make sure that the source file name is correct
</pre>
<p>Then, switch to the design mode for the first form, double-click the button control and put the following lines between the brackets. This is an event-handler that runs when the button is clicked.</p>
<pre class="brush: cpp; title: ; notranslate">
Form2^ newform = gcnew Form2;
newform -&gt; strSomething = textBox1-&gt;Text
if (newform-&gt;ShowDialog(this) == ::DialogResult::OK) delete newform;
</pre>
<p>Switch to the source of the second form and define the string <strong>strSomething</strong> as shown. That’s the variable that we are using to pass values.</p>
<pre class="brush: cpp; title: ; notranslate">
public:
		Form2(void)
		{
			InitializeComponent();
			//
			//TODO: Add the constructor code here
			//
		}    

		        String^ strSomething;

	protected:
		///
</pre>
<p>Now, switch to the desing mode of the second form, double-click anywhere on the form to invoke the event-handler that runs when the form is loaded. Here, insert the following statement.</p>
<pre class="brush: cpp; title: ; notranslate">
label1-&gt;Text = strSomething;
</pre>
<p>As you can probably see, we created the second form with an extra parameter of string type. When we created this form within the source of the first form, we passed the value of <strong>textBox1</strong> to that parameter and then in the second form, we take that value and assign it to the label. We can’t use something like this:</p>
<pre class="brush: cpp; title: ; notranslate">
newform-&gt;label1-&gt;Text = textBox1-&gt;Text;
</pre>
<p>That’s because <strong>label1</strong> is a private member of the<strong> Form2</strong> class and <strong>strSomething</strong> is a public member.</p>
<h1>System uptime &#8211; Visual C++ utility</h1>
<p>It’s been a while when I was programming in C, maybe more than 15 years. I decided to refresh my memory and create a small console application that will give me the system uptime and the date and time when the OS was installed. This small app should work on all platforms after Windows 2000.</p>
<p>I used Visual C++ 2008 and this program compiles without any errors or warnings. While I was browsing for the solutions implemented in this program, I found that some of the proposed solutions won’t compile on VC 2008. </p>
<p>Start VC2008, choose <strong>File | New | Project</strong>. For <strong>Project Types</strong> choose <strong>Win32 </strong>and then <strong>Win32 Console Application</strong>. You can copy and paste the whole source below. This is a simple console application and there are no extra header files or any resource files. You can also, download the executable that’s attached.</p>
<pre class="brush: cpp; collapse: true; light: false; title: ; toolbar: true; notranslate">
#include &quot;stdafx.h&quot;
#include &lt;windows.h&gt;       

char* GetUptime()
{
   int tickCount, nTime&#x5B;5];
   static char szUptime &#x5B;1000];
   tickCount = GetTickCount();
   nTime&#x5B;0] = tickCount / 1000 % 60; // Seconds
   nTime&#x5B;1] = tickCount / 1000 / 60 % 60; // Minutes
   nTime&#x5B;2] = tickCount / 1000 / 60 / 60 % 24; // Hours
   nTime&#x5B;3] = tickCount / 1000 / 60 / 60 / 24 % 7; // Days
   nTime&#x5B;4] = tickCount / 1000 / 60 / 60 / 24 / 7 % 52; // Weeks
   memset(szUptime, 0, sizeof(szUptime));       

   for(int i = 4; i &gt;= 0; i--)
   {
      char* szLabel;
      char tmpUptime&#x5B;3];       

      if (i == 4) (nTime&#x5B;4] &gt; 1 || nTime&#x5B;4] == 0) ? szLabel = &quot; Weeks, &quot; : szLabel = &quot; Week, &quot;;
      else if (i == 3) (nTime&#x5B;3] &gt; 1 || nTime&#x5B;3] == 0) ? szLabel = &quot; Days, &quot; : szLabel = &quot; Day, &quot;;
      else if (i == 2) (nTime&#x5B;2] &gt; 1 || nTime&#x5B;2] == 0) ? szLabel = &quot; Hours, &quot; : szLabel = &quot; Hour, &quot;;
      else if (i == 1) (nTime&#x5B;1] &gt; 1 || nTime&#x5B;1] == 0) ? szLabel = &quot; Minutes, &quot; : szLabel = &quot; Minute, &quot;;
      else if (i == 0) (nTime&#x5B;0] &gt; 1 || nTime&#x5B;0] == 0) ? szLabel = &quot; Seconds&quot; : szLabel = &quot; Second&quot;;
      memset(tmpUptime, 0, sizeof(tmpUptime));
      _itoa_s(nTime&#x5B;i], tmpUptime, 3, 10);
      strcat_s(szUptime, 1000, tmpUptime);
      strcat_s(szUptime, 1000, szLabel);
      }       

   return szUptime;
}       

char* GetInstalled()
{
   HANDLE hFile;
   WIN32_FIND_DATA FileInformation;
   SYSTEMTIME st;
   char tmpChar&#x5B;12];
   char* month = &quot;&quot;;
   char* comma = &quot;, &quot;;
   char* space = &quot; &quot;;
   char* colon = &quot;:&quot;;
   TCHAR winDir&#x5B;MAX_PATH];
   static char szInstalled&#x5B;1000];
   GetWindowsDirectory(winDir, MAX_PATH);
   hFile = ::FindFirstFile(winDir, &amp;FileInformation);
   FileTimeToSystemTime(&amp;FileInformation.ftCreationTime, &amp;st);
   switch (st.wMonth)
   {
      case 1:
      month = &quot;January &quot;;
      break;
      case 2:
      month =&quot;February &quot;;
      break;
      case 3:
      month = &quot;March &quot;;
      break;
      case 4:
      month =&quot;April &quot;;
      break;
      case 5:
      month = &quot;May &quot;;
      break;
      case 6:
      month =&quot;June &quot;;
      break;
      case 7:
      month = &quot;July &quot;;
      break;
      case 8:
      month =&quot;August &quot;;
      break;
      case 9:
      month = &quot;September &quot;;
      break;
      case 10:
      month =&quot;October &quot;;
      break;
      case 11:
      month = &quot;November &quot;;
      break;
      case 12:
      month =&quot;December &quot;;
      break;
      default:
      break;
   }       

   strcat_s(szInstalled, 1000, month);
   _itoa_s(st.wDay, tmpChar, 12, 10);
   strcat_s(szInstalled, 1000, tmpChar);
   strcat_s(szInstalled, 1000, comma);
   _itoa_s(st.wYear, tmpChar, 12, 10);
   strcat_s(szInstalled, 1000, tmpChar);
   strcat_s(szInstalled, 1000, space);
   _itoa_s(st.wHour, tmpChar, 12, 10);
   strcat_s(szInstalled, 1000, tmpChar);
   strcat_s(szInstalled, 1000, colon);
   _itoa_s(st.wMinute, tmpChar, 12, 10);
   strcat_s(szInstalled, 1000, tmpChar);
   strcat_s(szInstalled, 1000, colon);
   _itoa_s(st.wSecond, tmpChar, 12, 10);
   strcat_s(szInstalled, 1000, tmpChar);
   return szInstalled;
}
int _tmain(int argc, _TCHAR* argv&#x5B;])
{
      char* upTime;
      char* installed;
      printf(&quot;%s\n&quot;, &quot;-----------------------------------------------------------------&quot;);
      printf(&quot;%s\n&quot;, &quot;KInfo v0.1 -- Program by Kliment Andreev -- Public Domain -- 2009&quot;);
      printf(&quot;%s\n&quot;, &quot;-----------------------------------------------------------------&quot;);
      upTime = GetUptime();
      printf(&quot;%s%s&quot;,&quot; System Uptime: &quot;, upTime);
      installed = GetInstalled();
      printf(&quot;\n%s%s\n&quot;,&quot;System Installed: &quot;, installed);
      return 0;
}
</pre>
<p><a href='http://blog.andreev.it/wp-content/uploads/2012/01/kinfo2.zip'>kinfo2</a></p>
<h1>Enumerating files and folders in Visual C++</h1>
<p>This is a program that will enumerate all files, folders and sub-folders under a given folder. Folders with no access will be skipped and an *ERROR* message will be recorded on the console. Attached is the executable file (link at the bottom).</p>
<pre class="brush: cpp; collapse: true; light: false; title: ; toolbar: true; notranslate">
#include &quot;stdafx.h&quot;    

using namespace System;
using namespace System::Collections;
using namespace System::IO;    

int main(array ^args)
{
	array^ strSubFolders = gcnew array(20);
	array^ strFiles = gcnew array(20);
	Stack^ objFolders = gcnew Stack;
	Object^ objItem;
	String^ strSourceFolder;
	String^ strCurrentFolder;
	String^ strEachFile;
	String^ strEachFolder;
	String^ strArgs;
	int ArgsCounter=0,
		FileCounter=0,
		FolderCounter=0,
		ErrorCounter=0;    

	for each (strArgs in args) ArgsCounter++;    

	if (ArgsCounter==0) {
		Console::WriteLine(&quot;Usage: eff , enumerates all files and folders under &quot;);
		Console::WriteLine(&quot;Public domain - Program by Kliment Andreev, 2009&quot;);
		return 0;
	}    

	strSourceFolder = args&#x5B;0];    

	if (!System::IO::Directory::Exists(strSourceFolder)) {
		Console::WriteLine(&quot;Folder doesn&#039;t exist!&quot;);
		return 0;
	}    

	objFolders-&gt;Push(strSourceFolder);	    

	while (objFolders-&gt;Count &gt; 0) {
		objItem = objFolders-&gt;Pop();
		strCurrentFolder = safe_cast(objItem);
		Console::WriteLine(&quot;{0}&quot;,strCurrentFolder);    

		try {
			strSubFolders = Directory::GetDirectories(strCurrentFolder);
			strFiles = Directory::GetFiles(strCurrentFolder);    

			for each (strEachFile in strFiles){
				FileInfo^ fi = gcnew FileInfo(strEachFile);
				Console::WriteLine(&quot;{0}\\{1} &quot;,fi-&amp;gt;DirectoryName,fi-&gt;Name);
				FileCounter++;
			}    

			for each (strEachFolder in strSubFolders) {
				objFolders-&gt;Push(strEachFolder);
				FolderCounter++;
			}    

		}    

		catch(System::Exception ^ex) {
			Console::WriteLine(&quot;*ERROR* {0}&quot;,ex-&gt;Message);
			ErrorCounter++;
		}
	}    

	Console::WriteLine(&quot;\nTotal: {0} files, {1} folders and {2} errors.&quot;, \ 
FileCounter, FolderCounter, ErrorCounter);    

    return 0;
}
</pre>
<p><a href="https://blog.andreev.it/wp-content/uploads/2012/01/eff.zip">eff</a></div>
<h1>C#: Recreate directory structure</h1>
<p>I made this small utility to help me recreate a directory structure for a project that I was working on. For example, you want to create the same directory structure as C:\Windows but under the D:\ drive. In order to do that, you have to export the directory structure to a file (<strong>dirstruct -r c:\windows > file.txt</strong>) and then create the directory structure using <strong>dirstruct -w file.txt d:\</strong>. Expand for the source.</p>
<pre class="brush: cpp; collapse: true; light: false; title: ; toolbar: true; notranslate">
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;

namespace dirstruct
{
    class Program
    {
        static void Main(string&#x5B;] args)
        {
            void PrintUsage()
            {
                string strDash = new String(&#039;-&#039;, 98);
                Console.WriteLine(strDash);
                Console.WriteLine(&quot;dirstruct -r &lt;directory&gt;        - Lists all directories and subdirectories.&quot;);
                Console.WriteLine(&quot;                                  If no &lt;directory&gt; is given, uses the current directory.&quot;);
                Console.WriteLine(&quot;dirstruct -w &lt;file&gt; &lt;directory&gt; - Recreates the directory structure under the specified directory.&quot;);
                Console.WriteLine(&quot;                                  If no &lt;directory&gt; is given, uses the current directory.&quot;);
                Console.WriteLine(strDash);
                Console.WriteLine(&quot;Examples:  dirstruct -r C:\\users &gt; mydirs.txt&quot;);
                Console.WriteLine(&quot;           dirstruct -w mydirs.txt D:\\&quot;);
                Console.WriteLine(&quot;           Recreates the structure C:\\users under D:\\&quot;);
                Console.WriteLine(&quot;           You&#039;ll get D:\\users structure same as C:\\users&quot;);
                Console.WriteLine(strDash);
                Console.WriteLine(&quot;dirstruct : Kliment Andreev - 2020 - Simplified BSD License&quot;);
            }

            void CreateDirectories(string strFN, string strEP)
            {
                string strLine;
                System.IO.StreamReader file = new System.IO.StreamReader(@strFN);
                while ((strLine = file.ReadLine()) != null)
                {
                    string strDirectoryName = strEP + strLine.Substring(2);
                    try
                    {
                        DirectoryInfo di = Directory.CreateDirectory(strDirectoryName);
                        Console.WriteLine(strDirectoryName);
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(&quot;The process failed: {0}&quot;, e.ToString());
                    }
                }
                file.Close();
            }

            string strEntryPath = @&quot;&quot;;
            string strFileName = @&quot;&quot;;
            string strOperation = &quot;&quot;;
            int intErr = 0;
            if (args.Length == 0)
            {
                PrintUsage();
                intErr = 0;
                Environment.Exit(intErr);
            }
            if (args.Length &gt; 3)
            {
                PrintUsage();
                intErr = 1;
                Environment.Exit(intErr);
            }
            if (args&#x5B;0].Length != 2)
            {
                PrintUsage();
                intErr = 1;
                Environment.Exit(intErr);
            }
            switch (args&#x5B;0].Substring(0, 2))
            {
                case &quot;-r&quot;:
                    if (args.Length == 1)
                    {
                        strEntryPath = Directory.GetCurrentDirectory();
                    }
                    if (args.Length == 2)
                    {
                        strEntryPath = args&#x5B;1];
                    }
                    if (args.Length == 3)
                    {
                        Console.WriteLine(&quot;Too many arguments.&quot;);
                        intErr = 1;
                    }
                    strOperation = &quot;R&quot;;
                    break;
                case &quot;-w&quot;:
                    if (args.Length == 1)
                    {
                        intErr = 1;
                        Console.WriteLine(&quot;File name missing.&quot;);
                    }
                    if (args.Length == 2)
                    {
                        strFileName = args&#x5B;1];                        
                    }
                    if (args.Length == 3)
                    {
                        strFileName = args&#x5B;1];
                        strEntryPath = args&#x5B;2];
                    }
                    strOperation = &quot;W&quot;;
                    break;
                case &quot;-h&quot;:
                    PrintUsage();
                    break;
                default:
                    Console.WriteLine(&quot;Unknown argument.&quot;);
                    intErr = 1;
                    break;
            }
            if (intErr == 1) Environment.Exit(intErr);
            if ((!Directory.Exists(@strEntryPath)) &amp; (strEntryPath !=&quot;&quot;))
            {
                Console.WriteLine(@strEntryPath + &quot; does not exists or incorrect.&quot;);
                intErr = 1;
            }
            if ((!File.Exists(@strFileName)) &amp; (strOperation == &quot;W&quot;))
            {
                Console.WriteLine(@strFileName + &quot; does not exists or incorrect.&quot;);
                intErr = 1;
            }
            if (intErr == 1) Environment.Exit(intErr);
            if (strOperation == &quot;R&quot;)
            {
                List&lt;string&gt; listDirs = ListDirectories.GetDirectories(@strEntryPath);
                foreach (string strDirectory in listDirs)
                {
                    Console.WriteLine(strDirectory);
                }
            }
            if ((strOperation == &quot;W&quot;) &amp;&amp; (args.Length == 2))
            {
                Console.WriteLine(&quot;You will create a directory structure in the current directory.&quot;);
                Console.WriteLine(&quot;Are you sure you want to continue (Y/N)?&quot;);
                string strYN = Console.ReadLine().ToUpper();
                if (strYN == &quot;Y&quot;)
                {
                    strEntryPath = Directory.GetCurrentDirectory();
                    CreateDirectories(strFileName, strEntryPath);
                }
                else
                {
                    Console.WriteLine(&quot;Exiting. No changes were made.&quot;);
                    Environment.Exit(0);
                }
            }
            if ((strOperation == &quot;W&quot;) &amp;&amp; (args.Length == 3))
            {
                Console.WriteLine(&quot;You will create a directory structure under &quot; + strEntryPath);
                Console.WriteLine(&quot;Are you sure you want to continue (Y/N)?&quot;);
                string strYN = Console.ReadLine().ToUpper();                
                if (strYN == &quot;Y&quot;)
                {
                    CreateDirectories(strFileName, strEntryPath);
                }
                else
                {
                    Console.WriteLine(&quot;Exiting. No changes were made.&quot;);
                    Environment.Exit(0);
                }
            }

        }
    }
    public class ListDirectories
    {
        public static List&lt;string&gt; GetDirectories(string strPath, string strSearchPattern = &quot;*&quot;,
            SearchOption searchOption = SearchOption.AllDirectories)
        {
            if (searchOption == SearchOption.TopDirectoryOnly)
                return Directory.GetDirectories(strPath, strSearchPattern).ToList();

            List&lt;string&gt; listDirectories = new List&lt;string&gt;(GetDirectories(strPath, strSearchPattern));

            for (var i = 0; i &lt; listDirectories.Count; i++)
                listDirectories.AddRange(GetDirectories(listDirectories&#x5B;i], strSearchPattern));

            return listDirectories;
            
        }

        private static List&lt;string&gt; GetDirectories(string strPath, string searchPattern)
        {
            try
            {
                return Directory.GetDirectories(strPath, searchPattern).ToList();
            }
            catch (UnauthorizedAccessException)
            {
                return new List&lt;string&gt;();
            }
        }
    }
}
</pre>
<h1>Dockerize a Node.js application</h1>
<p>My Node.js app has <strong>index.html, server.js</strong> and <strong>styles.css</strong> files. First, initialize the app and enter the values for the app.</p>
<pre class="brush: bash; title: ; notranslate">
npm init
</pre>
<p>Install all the dependent modules for the app.</p>
<pre class="brush: bash; title: ; notranslate">
npm install express socket.io --save
</pre>
<p>Create the <strong>Dockerfile</strong>. </p>
<pre class="brush: bash; highlight: [1,11,18]; title: ; notranslate">
FROM node:18

# Create app directory
WORKDIR /usr/src/app

# Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
# where available (npm@5+)
COPY package*.json ./

RUN npm install
# If you are building your code for production
# RUN npm ci --only=production

# Bundle app source
COPY . .

EXPOSE 3000
CMD &#x5B; &quot;node&quot;, &quot;server.js&quot; ]
</pre>
<p>Create a .dockerignore file to omit some of the files that are not necessary.</p>
<pre class="brush: bash; title: ; notranslate">
cat &lt;&lt;EOF &gt; .dockerignore
node_modules
npm-debug.log
EOF
</pre>
<p>Build the image.</p>
<pre class="brush: bash; title: ; notranslate">
docker build . -t &lt;your username&gt;/node-web-app
</pre>
<p>Check the image.</p>
<pre class="brush: bash; title: ; notranslate">
docker images
</pre>
<p>Test the image.</p>
<pre class="brush: bash; title: ; notranslate">
docker run -p 3000:3000 -d &lt;your username&gt;/node-web-app
</pre>
<p>Is the container running?</p>
<pre class="brush: bash; title: ; notranslate">
docker ps
</pre>
<p>Check the logs for the container.</p>
<pre class="brush: bash; title: ; notranslate">
docker logs &lt;container id&gt;
</pre>
<p>If needed, attach to the shell of the running container.</p>
<pre class="brush: bash; title: ; notranslate">
docker exec -it &lt;container id&gt; /bin/bash
</pre>
<h1>HTML/CSS/JavaSccript boilerplate</h1>
<p><strong>index.html</strong></p>
<pre class="brush: xml; title: ; notranslate">
&lt;!DOCTYPE html&gt;
&lt;html&gt;
  &lt;head&gt;
    &lt;title&gt;HTML 5 Boilerplate&lt;/title&gt;
    &lt;link rel=&quot;stylesheet&quot; href=&quot;style.css&quot; /&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;p&gt;HTML&lt;/p&gt;
    &lt;script src=&quot;script.js&quot;&gt;&lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;
</pre>
<p><strong>style.css</strong></p>
<pre class="brush: css; title: ; notranslate">
p {
  background-color: yellow;
}
</pre>
<p><strong>script.js</strong></p>
<pre class="brush: jscript; title: ; notranslate">
&#039;use strict&#039;;

console.log(&#039;JavaScript&#039;);
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2011/12/passing-variables-by-reference-between-two-forms-in-visual-c/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
	</channel>
</rss>
