diff --git a/.sass-cache/385470f2e7b7b1c936f1d148ac5e1cada845610d/_base.scssc b/.sass-cache/385470f2e7b7b1c936f1d148ac5e1cada845610d/_base.scssc new file mode 100644 index 0000000..419302d Binary files /dev/null and b/.sass-cache/385470f2e7b7b1c936f1d148ac5e1cada845610d/_base.scssc differ diff --git a/.sass-cache/385470f2e7b7b1c936f1d148ac5e1cada845610d/_layout.scssc b/.sass-cache/385470f2e7b7b1c936f1d148ac5e1cada845610d/_layout.scssc new file mode 100644 index 0000000..ee917d3 Binary files /dev/null and b/.sass-cache/385470f2e7b7b1c936f1d148ac5e1cada845610d/_layout.scssc differ diff --git a/.sass-cache/385470f2e7b7b1c936f1d148ac5e1cada845610d/_syntax-highlighting.scssc b/.sass-cache/385470f2e7b7b1c936f1d148ac5e1cada845610d/_syntax-highlighting.scssc new file mode 100644 index 0000000..3d29704 Binary files /dev/null and b/.sass-cache/385470f2e7b7b1c936f1d148ac5e1cada845610d/_syntax-highlighting.scssc differ diff --git a/.sass-cache/e8ae1ce5ba6e352254d624bec721194fc954ae58/_base.scssc b/.sass-cache/e8ae1ce5ba6e352254d624bec721194fc954ae58/_base.scssc new file mode 100644 index 0000000..7208e49 Binary files /dev/null and b/.sass-cache/e8ae1ce5ba6e352254d624bec721194fc954ae58/_base.scssc differ diff --git a/.sass-cache/e8ae1ce5ba6e352254d624bec721194fc954ae58/_layout.scssc b/.sass-cache/e8ae1ce5ba6e352254d624bec721194fc954ae58/_layout.scssc new file mode 100644 index 0000000..3ec6cda Binary files /dev/null and b/.sass-cache/e8ae1ce5ba6e352254d624bec721194fc954ae58/_layout.scssc differ diff --git a/.sass-cache/e8ae1ce5ba6e352254d624bec721194fc954ae58/_syntax-highlighting.scssc b/.sass-cache/e8ae1ce5ba6e352254d624bec721194fc954ae58/_syntax-highlighting.scssc new file mode 100644 index 0000000..53fcb32 Binary files /dev/null and b/.sass-cache/e8ae1ce5ba6e352254d624bec721194fc954ae58/_syntax-highlighting.scssc differ diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..376a84e --- /dev/null +++ b/Gemfile @@ -0,0 +1,3 @@ +source "https://rubygems.org" +gem "jekyll" +gem "jekyll-redirect-from" diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..5e06c35 --- /dev/null +++ b/Readme.md @@ -0,0 +1,6 @@ +# Homepage and Blog + +##### Made using Jekyll + + +[Link to Website](http://nihal111.github.io/) \ No newline at end of file diff --git a/_config.yml b/_config.yml new file mode 100644 index 0000000..66316f1 --- /dev/null +++ b/_config.yml @@ -0,0 +1,69 @@ +# Site Settings + + +# Name of your site (displayed in the header) +myname: Nihal Singh +alias: nihal111 +# Short bio or description (displayed in the header) +byline: I like to know things + +# URL of your avatar or profile pic (you could use your GitHub profile pic) +avatar: https://avatars1.githubusercontent.com/u/13916513?v=2&s=460 + + +# Includes an icon in the footer for each username you enter +footer-links: + dribbble: + email: + facebook: + flickr: + github: nihal111 + instagram: + linkedin: nihal111 + pinterest: + rss: # just type anything here for a working RSS icon + twitter: + stackoverflow: # your stackoverflow profile, e.g. "users/50476/bart-kiers" + youtube: # channel/ or user/ + googleplus: # anything in your profile username that comes after plus.google.com/ + + +# Enter your Disqus shortname (not your username) to enable commenting on posts +# You can find your shortname on the Settings page of your Disqus account +disqus: nihal111 + +# Enter your Google Analytics web tracking code (e.g. UA-2110908-2) to activate tracking +google_analytics: + +# Your website URL (e.g. http://barryclark.github.io or http://www.barryclark.co) +# Used for Sitemap.xml and your RSS feed +url: "http://nihal111.github.io" + +# If you're hosting your site at a Project repository on GitHub pages +# (http://yourusername.github.io/repository-name) +# and NOT your User repository (http://yourusername.github.io) +# then add in the baseurl here, like this: "/repository-name" +baseurl: "" + + +title: Nihal Singh +email: nihaliter@gmail.com +description: > + Nihal Singh's personal blog. + +github_username: nihal111 +facebook_username: Nihal Singh +linkedin_username: Nihal Singh +facebook_id: nihal111 +linkedin_id: nihal111 +address: Indian Institue of Technology, Bombay Mumbai-400076, India +# Build Settings +sass: + sass_dir: _sass +include: ['_pages'] +kramdown: + input: GFM +plugins: + - jekyll-redirect-from +whitelist: + - jekyll-redirect-from diff --git a/_includes/footer.html b/_includes/footer.html new file mode 100644 index 0000000..1417891 --- /dev/null +++ b/_includes/footer.html @@ -0,0 +1,49 @@ +
+ +
+ + + + + +
+ +
diff --git a/_includes/head.html b/_includes/head.html new file mode 100644 index 0000000..95987e5 --- /dev/null +++ b/_includes/head.html @@ -0,0 +1,26 @@ + + + + + + {% if page.title %}{{ site.title }} - {{page.title }}{% else %}{{ site.title }}{% endif %} + + + + + + + + + + + + + + diff --git a/_includes/header.html b/_includes/header.html new file mode 100644 index 0000000..5116796 --- /dev/null +++ b/_includes/header.html @@ -0,0 +1,29 @@ + \ No newline at end of file diff --git a/_includes/icon-facebook.html b/_includes/icon-facebook.html new file mode 100644 index 0000000..07e43bf --- /dev/null +++ b/_includes/icon-facebook.html @@ -0,0 +1 @@ +{{ include.username }} diff --git a/_includes/icon-facebook.svg b/_includes/icon-facebook.svg new file mode 100644 index 0000000..e4b641e --- /dev/null +++ b/_includes/icon-facebook.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/_includes/icon-facebook.svg~ b/_includes/icon-facebook.svg~ new file mode 100644 index 0000000..29a0050 --- /dev/null +++ b/_includes/icon-facebook.svg~ @@ -0,0 +1 @@ + diff --git a/_includes/icon-github.html b/_includes/icon-github.html new file mode 100644 index 0000000..e501a16 --- /dev/null +++ b/_includes/icon-github.html @@ -0,0 +1 @@ +{% include icon-github.svg %}{{ include.username }} diff --git a/_includes/icon-github.svg b/_includes/icon-github.svg new file mode 100644 index 0000000..4422c4f --- /dev/null +++ b/_includes/icon-github.svg @@ -0,0 +1 @@ + diff --git a/_includes/icon-linkedin.html b/_includes/icon-linkedin.html new file mode 100644 index 0000000..cddb2e0 --- /dev/null +++ b/_includes/icon-linkedin.html @@ -0,0 +1 @@ +{% include icon-linkedin.svg %}{{ include.username }} diff --git a/_includes/icon-linkedin.svg b/_includes/icon-linkedin.svg new file mode 100644 index 0000000..1c7b0c3 --- /dev/null +++ b/_includes/icon-linkedin.svg @@ -0,0 +1,9 @@ + + + + + diff --git a/_includes/landing_social.html b/_includes/landing_social.html new file mode 100644 index 0000000..e1e8ca1 --- /dev/null +++ b/_includes/landing_social.html @@ -0,0 +1,26 @@ + \ No newline at end of file diff --git a/_includes/masthead.html b/_includes/masthead.html new file mode 100644 index 0000000..be9fd7f --- /dev/null +++ b/_includes/masthead.html @@ -0,0 +1,17 @@ +
+
+
+ + +
+

{{ site.myname }}

+

{{ site.byline }}

+
+ + + +
+
+
diff --git a/_includes/post-tags.html b/_includes/post-tags.html new file mode 100644 index 0000000..3433ef9 --- /dev/null +++ b/_includes/post-tags.html @@ -0,0 +1,10 @@ + \ No newline at end of file diff --git a/_includes/social.html b/_includes/social.html new file mode 100644 index 0000000..aec6d69 --- /dev/null +++ b/_includes/social.html @@ -0,0 +1,16 @@ + + +GitHub + + + + + + + + +LinkedIn + + \ No newline at end of file diff --git a/_layouts/default.html b/_layouts/default.html new file mode 100644 index 0000000..de45fac --- /dev/null +++ b/_layouts/default.html @@ -0,0 +1,17 @@ + + +{% include head.html %} + + + {% include header.html %} + {% include masthead.html %} +
+
+ {{ content }} +
+ +
+ {% include footer.html %} + + + diff --git a/_layouts/landing.html b/_layouts/landing.html new file mode 100644 index 0000000..282d715 --- /dev/null +++ b/_layouts/landing.html @@ -0,0 +1,8 @@ + + + {% include head.html %} + + {% include header.html %} + {{ content }} + + \ No newline at end of file diff --git a/_layouts/page.html b/_layouts/page.html new file mode 100644 index 0000000..6f47304 --- /dev/null +++ b/_layouts/page.html @@ -0,0 +1,7 @@ +--- +layout: default +--- + +

{{page.title }}

+ + {{ content }} diff --git a/_layouts/post.html b/_layouts/post.html new file mode 100644 index 0000000..ab7aed3 --- /dev/null +++ b/_layouts/post.html @@ -0,0 +1,40 @@ +--- +layout: default +--- + +
+

{{ page.title }}

+ +

+{% include post-tags.html %} +
+ + +{{ content }} + + + +{% if page.comments %} +
+ + +{% endif %} + + + + diff --git a/_pages/about.md b/_pages/about.md new file mode 100644 index 0000000..527d35b --- /dev/null +++ b/_pages/about.md @@ -0,0 +1,40 @@ +--- +layout: page +title: About +header: True +permalink: /about/ +--- + +I am a senior undergraduate student at the Indian Institute of Technology, Bombay. I'm pursuing my a Bachelor's degree at IIT Bombay with my major in Civil Engineering and minor in Computer Science. + +Coding has been a serious hobby since long. I have enjoyed programming ever since I knew what it meant. I continue to learn, develop and build new things every day. + +I'm interested in Natural Language Processing and Machine Learning as applied to speech and text processing. At present, I'm working with [Prof. Preethi Jyothi][pjyothi] at [CSALT][csalt] on the task of synthetic generation and language modeling of code-switched Hindi-English text. + +I actively participate in hackathons. In my freshman year, along with two of my friends, Akash and Arpan, I formed the Ferozepurwale hackathon team. Together we have won several prizes (full list [here][hackathons]). + +I am an Open Source enthusiast and I strongly believe in the FOSS philosophy. I'm a contributor and organization member at [MovingBlocks- Terasology]. I also completed my Google Summer of Code (GSoC) with Terasology in the summer of 2017. I have been a mentor with MovingBlocks for Google Code-In (high school level GSoC) since our first GCI participation in 2016. In 2018, I was one of the GSoC mentors and was chosen to represent MovingBlocks at the GSoC mentor summit at Google HQ, Sunnyvale, CA. + +The Web and Coding Club of IIT Bombay is like my family away from home. In my junior year (2017-18), I managed the club, leading a team of 22 sophomores to carry out activities which help people learn and build an interest in programming. + +I like to listen to rock music, specifically progressive rock, post-rock, djent and heavy metal. I enjoy watching science fiction and thrillers. I'm a football fan. Even though it's been a while since I stopped following the premier league, I play whenever I get the chance. I used to be an avid gamer but I play only occasionally now. Huge Assassins Creed and Call of Duty fan. + +Over the period of my stay at IIT, I have learnt a lot. I have successfully 'completed' and contributed to a few [projects]. + +For a detailed list of my projects and achievements, check out my [CV][CV]. + +I write infrequently, check out my [blog]. + +[MovingBlocks- Terasology]: https://github.com/MovingBlocks/Terasology +[Terasology]: http://terasology.org/ +[completed my Google Summer of Code]: /2017/08/15/GSoC-wrap-up.html +[wiki]: https://wncc-iitb.org/wiki +[new website]: http://wncc-iitb.org/ +[a YouTube Channel]: https://www.youtube.com/channel/UCs3x_XxwScIAzDUfN1lbbGw +[internship portal]: https://portals.wncc-iitb.org/internships/login/ +[projects]: /projects +[hackathons]: /projects#hackathons +[CV]: /cv +[blog]: /blog +[pjyothi]: https://www.cse.iitb.ac.in/~pjyothi/ +[csalt]: https://www.cse.iitb.ac.in/~pjyothi/csalt/ diff --git a/_pages/cv.md b/_pages/cv.md new file mode 100644 index 0000000..fd49684 --- /dev/null +++ b/_pages/cv.md @@ -0,0 +1,9 @@ +--- +layout: page +title: CV +permalink: /cv/ +redirect_from: + - /CV +redirect_to: + - /docs/CV.pdf +--- \ No newline at end of file diff --git a/_pages/projects.md b/_pages/projects.md new file mode 100644 index 0000000..e8b1538 --- /dev/null +++ b/_pages/projects.md @@ -0,0 +1,89 @@ +--- +layout: page +title: Projects +header: True +permalink: /projects/ +--- + +Projects are good things. Perhaps the best of things and no good project ever gets completed. +Here is the list of projects I own or have contributed to: + +* [**Google Summer of Code**][Google Summer of Code]- I completed my GSoC in 2017 under [MovingBlocks- Terasology][MovingBlocks- Terasology]. The broad goal was to introduce content systems and gameplay connections to support a new template with solid replayability. I developed a new survival gameplay mode called [Lost][Lost] involving puzzles, traps and exploration based content packed in a new world with a backing lore. Dealt with the game’s physics, multiplayer and Entity Component System. Created new modules like [AdvancedBehaviors][AdvancedBehaviors] (for event driven behavior switching), [AdventureAssets][AdventureAssets] (for traps and puzzle elements). Made several accompanying API changes to the engine. Created and added [WildAnimals] to the game. + +### Hackathons + +* [**Flood League**][Flood League]: Designed and developed an endless runner game using Unity3D. Superheroes have to drive past the obstacles while rescuing the drowning civilians as their boat rushes past the flood-stricken city. Extensively worked on level design and implemented functionality such as continuous scoring, heat vision, super stretch arms, superpower cooldown among others. **First prize winner in Ubisoft GameJam 2017**. + +* [**Run**][Run]: The Run app was born at the Yahoo! hackathon and ended up **winning the “most creative and fun hack” award**. Our team built a multi-player treasure hunt Android game supported by a Django server. Players look for and click a picture of an object around them as shown in the clue received on their phones to get the next clue. The first to finish the trail and decipher the clues wins. Used histogram equalization and scale invariant feature transform (SIFT) for rudimentary image matching. + +* [**Lend-It**][Lend-It]: Designed a Django-based web application that serves as a platform to bridge the gap between lenders and borrowers. Through Lend-It one can find people nearby who wish to lend and borrow books or other shareable commodities and perform a safe exchange. Implemented a backend using Django for the Lend-It website, which allows user interaction, sending notifications, searching and lending books, maintaining a user profile among other features Hosted temporarily online [here](http://pacific-dawn-55810.herokuapp.com/). **Third prize winner in Microsoft code.fun.do** November '16. + +* [**RPG**][RPG]: A real time RPG game in which players assume roles of characters lost on a island. Players are each given a backstory and an objective. Players can interact and communicate with each other using video chat. The story progresses and you have to convince the other player to join your objective and let you live. Made using Kandy API. **Third prize winner in Kandy Hackathon 2016**. + +* [**AssistANT**][AssistANT]: Help the ant find sugar for its family. Built a puzzle game using Unity similar to the classic Bulldozer game. Guide the ant to push the sugar cubes down the ant holes. Dealt with basic 2-D physics and box colliders. Made custom sprites and worked largely on level design. Created using Unity 2D. **Second prize winner for Lenovo GameJam '15**. + +* [**alCHEMy**][alCHEMy]: A game which completes chemical reactions, much like the classical Alchemy. Microsoft code.fun.do submission in January '16. + +### Open Source + +* [**WnCC Website**][WnCC Website]: The official Web and Coding Club, IIT Bombay website. Created, managed and maintained largely by me. The entire website is static and runs on Jekyll. Mainly serves as a portal for the Seasons Of Code (SOC) program. If you want to mentor a SOC project or have any ideas to make it look better, send a PR [here][WnCCRepo]. + +* [**Bashortcuts**][Bashortcuts]: 'bashortcuts' or bash-shortcuts is a skinny python script that helps build a personalized inputrc, which is a customized configuration of GNU Readline, the input related library used by bash and most other shells. Additionally, it makes it easy to define macros that can be used to tie shell_commands and functions to key sequences. + +* [**Terasology**][Terasology]: Terasology is an open source renedition of Minecraft and is a platform to develop gameplay settings in the voxel world. I've been contributing to this project since October '16. The community is very active and enthusiastic, and I've had a great time with them. + +### Course Projects and Research Work + +* **Synthetic generation and Language Modeling of Code-Switched Hindi-English Text**: Working on the generation of code-mixed Hindi-English text using linguistic theories and several strategies by leveraging parse-trees. Using the synthetic code-mixed data to improve performance of a language model. + +* [**Pommerman**][pommerman-blog]: Explored different strategies for training learning agents in a multi-agent scenario as part of the NeurIPS 2018 Pommerman Challenge. Read more [here][pommerman-blog]. + +* [**Voice Conversion**][voice-conversion-blog]: Built a pipelined approach to convert one person’s voice into another person’s voice. Proposed a deep learning approach to convert source waveform to phonemes and further phonemes to target waveform. Read more [here][voice-conversion-blog]. + +* [**CFS Visualizer**][CFS-visualizer-blog]: Created a visualization tool to see the Completely Fair Scheduler in action. CFS is a widely used process scheduler present in Linux kernels. Read more [here][CFS-visualizer-blog]. + +* [**SAFE Quiz App**][SAFE Quiz App]: Worked for the development of the SAFE Android application that facilitates online paperless tests in educational institutes. Multiple devices concurrently connect to a Wireless Access Point to fetch test data with action-logging happening in real time at the invigilator’s console. Worked on fetching and displaying of performance history and correct/incorrect answer visuals on the app. I worked on this as a part of my R & D Project in Fall '16. + +* [**Steganography Tool**][Steganography Tool]: Implemented a steganography tool using MATLAB with custom terminal GUI. Implemented variations of encryption algorithms using Least Significant Bit to encrypt/decrypt text within an image with a custom passphrase. This was done as a part of my Digital Image Processing course project in Fall '17. + +### Hobby Projects + +* [**MooDLD**][MooDLD]: A python application that automates the download of course material from [moodle.iitb.ac.in](moodle.iitb.ac.in). It has a Tkinter based GUI and uses Mechanize for scraping. Made independently for Windows, it consists of a setup which installs MooDLD with all dependencies. Developed further as an android app that lets you download all the courses with the click of a button. [***UPDATE***: **Was officially launched by the UG Academics Council at IIT Bombay in Aug '16**. However, project has been ***dicontinued*** due to the recent Moodle version bump to support the official Moodle Mobile app.] + +* [**EVENTual**][EVENTual]: No more painstakingly filling or remembering event details. Save events to your default calendar with one tap. Fill out the details and get a sharable link and QR code. Use the [EVENTual android app] to directly add that. Created a platform for creating and sharing events easily, automating the task of filling details in the calendar by generating shareable links and QR Codes. Made a Django based web application to facilitate creation and searching of events. Developed an Android app which would pick up sharable links and scan QR Codes, to automatically add the event to calendar. + +* [**J.A.R.V.I.S.**][J.A.R.V.I.S.]: An attempt to make a very simple, Personal Assistant that understands speech as well as text input and is capable of performing tasks other than conversing. This project is based on AIML 1.0 and uses pyaiml for using the AIML interpreter in python. AIML, is based on pattern matching and this project does not implement any sort of machine learning or language processing. + +* [**IITB login extension for Chrome**][IITB login extension for Chrome]: This extension automatically logs in to [internet.iitb.ac.in](internet.iitb.ac.in) page whenever Chrome browser is opened. Added integration for [moodle](moodle.iitb.ac.in) and [gpo](gpo.iitb.ac.in). + +* **Kibo**: In the summer of 2016, I worked on [Project Awaaz][Project Awaaz], a non-profit initiative to create an audiobook repository for the blind. Anybody can record text by reading out uploaded content and the recordings would be compiled, stitched and distributed. Built the backend for Project Awaaz and the Kibo website using the Django framework- Python/Django/Apache/MySQL. Designed responsive websites. Worked extensively on the Android application for Project Awaaz and handled server side integration. + + +[Project Awaaz]: http://projectawaaz.org/ +[Flood League]: https://github.com/Ferozepurwale/Flood-League/ +[Lost]: https://github.com/Terasology/Lost/ +[AdvancedBehaviors]: https://github.com/Terasology/AdvancedBehaviors/ +[AdventureAssets]: https://github.com/Terasology/AdventureAssets +[WildAnimals]: https://github.com/Terasology/WildAnimals +[Google Summer of Code]: /2017/08/15/GSoC-wrap-up.html +[MovingBlocks- Terasology]: https://github.com/MovingBlocks/Terasology +[J.A.R.V.I.S.]:https://github.com/nihal111/J.A.R.V.I.S +[Terasology]: https://github.com/MovingBlocks/Terasology +[EVENTual android app]: https://play.google.com/store/apps/details?id=co.eventual.ferozepurvale.eventual +[EVENTual]: https://github.com/Ferozepurwale/EVENTual +[WnCCRepo]: https://github.com/nihal111/WnCC +[WnCC Website]: http://wncc-iitb.org/ +[Lend-It]: http://pacific-dawn-55810.herokuapp.com +[MooDLD]: https://github.com/nihal111/MooDLD +[IITB login extension for Chrome]: https://github.com/nihal111/IITB-login-extension-Chrome +[AssistANT]: https://github.com/nihal111/nihal111.github.io/releases/download/v0.1/AssistANT.zip +[RPG]: https://github.com/nihal111/RPG +[alCHEMy]: https://github.com/nihal111/alCHEMy +[Run]: https://github.com/CodeMaxx/Run-App +[Bashortcuts]: https://github.com/nihal111/bashortcuts +[SAFE Quiz App]: http://safe.cse.iitb.ac.in/ +[Voice Conversion]: https://github.com/nihal111/voice-conversion +[Steganography Tool]: https://github.com/nihal111/steganography +[voice-conversion-blog]: https://nihal111.github.io/2018/04/30/voice-conversion.html +[pommerman-blog]: https://nihal111.github.io/2018/11/25/pommerman-rl.html +[CFS-visualizer-blog]: https://nihal111.github.io/2017/11/15/cfs-visualizer.html \ No newline at end of file diff --git a/_pages/resume.md b/_pages/resume.md new file mode 100644 index 0000000..cf6114c --- /dev/null +++ b/_pages/resume.md @@ -0,0 +1,9 @@ +--- +layout: page +title: Résumé +permalink: /resume/ +redirect_from: + - /Resume +redirect_to: + - /docs/resume.pdf +--- \ No newline at end of file diff --git a/_posts/2015-09-20-assistant-lenovo.markdown b/_posts/2015-09-20-assistant-lenovo.markdown new file mode 100644 index 0000000..df1735f --- /dev/null +++ b/_posts/2015-09-20-assistant-lenovo.markdown @@ -0,0 +1,59 @@ +--- +layout: post +title: "Lenovo GameJam- First Hackathon Experience" +date: 2015-09-20 +comments: true +tags: +- Unity +- Hackathon +- GameJam +--- + +**Note**: *The events in this article antedate the creation of this blog. This post is written at a later point in time than dated.* + +It was early September, and the rain gods had started to show some clemency. We made our way out of the mess area, towards the notice boards. + +{: .center} +![lenovoposter]({{ site.baseurl }}/img/lenovoposter.jpg "Poster"){:style="max-height: 500px;"} + +### The Poster +We had come across this poster before; it described the rules of a GameJam and boasted a **prize worth INR 1,00,000** sponsored by **Lenovo**. We had brushed-off the idea of participating earlier, claiming it to be ridiculously far-fetched for us to complete building a game in 72 hours, let alone vying with experienced seniors. We were new here, unfledged. Somehow Arpan convinced me that we should give it a shot. It had barely been a month since we got admitted and we were already floundering in our attempt to absorb the spectrum of activities that take place in the institute. We had our finger in every pie that looked tasty. + +### Briefing +Fast forward to **September 15, 8 PM**. We had reached early and found seats in the FC Kohli Auditorium. We saw the room fill up and cross a count of 150. There was a host who had come from Lenovo and an Android game developer who spoke for a while. General instructions and rules followed. The host named a few game engines that we could use. Arpan and I exchanged glances; we hadn't the faintest of clues. + +### Theme +If making a game wasn't already challenging enough for the two of us, the host decided to spice it up by allotting **random themes** to each team. Most teams had 4 members (with 4 being the cap), but I was reluctant to take anyone else in. Arpan and I were schoolmates and had collaborated earlier. An additional teammate could likely hamper the existing coordination. We advanced to the bowl and drew a chit; it read- **Insect World**. We found it arbitrarily absurd at first, but within a minute, ideas started flowing in. + +### Clock's Ticking +The 72-hour countdown was to start as soon as the clock hit **00:00 on September 16**. As advised, we spent a good fraction of time deciding what game to build. I came up with Bug on a Wire, the [Miniclip game](https://www.miniclip.com/games/bug-on-a-wire/en/) where the player controls a bug which has to jump past crows on a telephone wire in an endless runner. Arpan came up with other ideas. After a while, we decided that owing to our lack of knowledge and experience; we'd stick to 2D and choose a game idea that has incremental difficulty to build. We wanted to keep the first milestone in near sight. + +A little past midnight, we reconciled to the idea of a [classic bulldozer game](https://www.microsoft.com/en-us/store/p/bulldozer-classic/9nblgggzm5sm), where, in a puzzle setting a bulldozer has to push boulders to targets. Just that, the bulldozers are ants, the boulders are sugar cubes, and the targets are holes. Almost instantly, we came up with a name for it- **AssistANT**. The player has to assist an ant in order to send food to its family. + +### OK, now what? +We had done a bit of C++ in school but barely knew anything about building games. '**Unity**' stuck with us from the briefing and within a few minutes, we were already installing Unity while simultaneously watching tutorial videos. We decided to pair-program on Arpan's new laptop. Mine was a junk box, back then. Most of the initial stuff was pretty intuitive and we were soon fiddling around with an ant sprite on screen, experimenting with friction, gravity and all sorts of Physics stuff that came out of the box. + +It was 3 AM, and we decided to sleep and rendezvous at the morning 8:30 AM lecture. We couldn't concentrate in class and spent the entire time going through tutorial videos and docs. We rushed back to the room and spent the entire day building our first level. We had baked up a quick, basic map on MS Paint. Soon, we were playing around with Box Colliders and other 2D Physics stuff, writing code in C#. By around midnight, Level 1 was ready, but it was quirky, almost unplayable. I had a date the next day and I needed a time out. + +{: .center} +![lenovoposterAssistANTLevel1]({{ site.baseurl }}/img/AssistANTLevel1.jpg "Level 1"){:style="max-height: 500px;"} + +### 72 to 48 +Around early evening, having nicely cleared my other appointments, I called up Arpan only to find out that he's left for home and won't be back by next morning. I decided not to waste more time and started designing levels in MS Paint based on raw ideas from the previous day. I finished the day with 4 levels ready. + +{: .center} +![lenovoposterAssistANTNewLevel]({{ site.baseurl }}/img/AssistANTNewLevel.jpg "New level"){:style="max-height: 500px;"} + +### The Last Mile +Our game's still quirky. We work in shifts. One person integrates the new maps into the game, creating new levels while the other goes through more tutorials, docs to find solutions to the bugs. By evening we have all isolated levels working somewhat decently. Gauging we still have time, we thread together all the levels and add a nice scoring function that exponentially decays with time. An hour before midnight, we were ready for submission. + +Satisfied with our effort and pleased with the outcome, we submit and go to bed. We still had no hopes of winning; our game was amateurish at best. + +### Result Day +The results took a long time to arrive. I received a call from Pradyot, the then WnCC manager. He invited me to attend the prize distribution ceremony. The venue had been changed to the [Tinkerers' Lab](http://tinkerers-lab.org/). We expected a consolation prize or perhaps the best freshmen game prize. These existed in addition to the top 3 primary cash prizes (breakup- 50k, 30k, 20k). The distribution started from the bottom and as names went by, we realised we had made a podium finish. + +We ended up **winning the 2nd prize with a cash prize of 30,000 INR**. Our happiness knew no bounds and the prize money was a cherry on top. + +**The game can be downloaded from [here](https://github.com/nihal111/nihal111.github.io/releases/download/v0.1/AssistANT.zip).** The zip file contains an executable with instruction on how to run. Unfortunately, the source code didn't survive since we didn't know any version control back then. + +**Note from the future**: *I believe that this one event sparked a butterfly effect. I feel it has had a considerable impact on my life choices pertaining towards WnCC, shaping my interests and pursuing coding as a hobby. I look back to this with a vivid memory and great pleasure.* \ No newline at end of file diff --git a/_posts/2016-05-04-blog-init.markdown b/_posts/2016-05-04-blog-init.markdown new file mode 100644 index 0000000..0a95acd --- /dev/null +++ b/_posts/2016-05-04-blog-init.markdown @@ -0,0 +1,23 @@ +--- +layout: post +title: "Blog init" +date: 2016-05-04 +comments: true +tags: +- firstpost +- jekyll +--- +Hi, there! You've stumbled upon my first [blog](http://webanalyticshub.com/) post. + +It's been a while since I first thought of creating my github homepage and blog. And I can't believe I finally made it. + +Also, this is the first time I've used [Jekyll](https://jekyllrb.com/) to create a website. Apart from a few impediments in CSS, the journey to completion was smooth. The markdown to HTML conversion is awesome and blog maintenance is easy as well. You could [fork](https://github.com/nihal111/nihal111.github.io/fork) this [repo](https://github.com/nihal111/nihal111.github.io) and play around with it. + +I've made a [projects](/projects) section which I'll keep updating with my latest developments and contributions. I plan to use this blog to write about my experiences and other interesting stuff I come across. + +It's been a long night. I should go to bed before sunrise! + +{% highlight bash %} +blog init +echo "Hello World!" +{% endhighlight %} \ No newline at end of file diff --git a/_posts/2016-05-08-playing-with-aliases.markdown b/_posts/2016-05-08-playing-with-aliases.markdown new file mode 100644 index 0000000..2b6bdb1 --- /dev/null +++ b/_posts/2016-05-08-playing-with-aliases.markdown @@ -0,0 +1,119 @@ +--- +layout: post +title: "Playing with aliases" +date: 2016-05-08 +comments: true +tags: +- bash +- tutorial +--- + +Since I can't do without my games, I can't do without Windows, and I have to dualboot. This means that most of my data is stored on a disk shared between both the operating systems. The path to the directory where I keep my projects thus becomes rather long. And I like to keep an alias for it. + +{% highlight bash %} +alias code='cd /media/Nihal/Code' +{% endhighlight %} + +What this would do is create an alias by the name of 'code' which would exist till the time you killed the terminal. Rather I have created a permanent alias for it, which is stored by copying the above line into the **`.bash_aliases`** file in the home directory (if it doesn't exist, you should really create one). I wanted to create a few more permanent aliases as and when needed and the process to do so felt tedious. Alas! I wrote another alias for it. Let's talk about the **`.bashrc`** and **`.bash_aliases`** file before getting there. + +### The ***`.bashrc`*** file +In the home directory there also exists a `.bashrc` file which shall contain a lot of oher things. The `.bashrc` file is a script which executes evereytime a terminal is started in the **interactive mode**. It contains a set of configurations for the terminal. The `.bashrc` file provides a space to set up variables, functions, aliases etc that you may want to use. The `.bashrc` is then run every time you open up a new terminal. Be careful, that any error or change you make in the `.bashrc` file will be reflected in all subsequent terminal windows launced. Also if you have a terminal window running, and you make changes to the `.bashrc` file thereafter, you will obviously have no effect on the running terminal and you may want to restart it. + +### Loading the ***`.bash_aliases`*** file +The `.bashrc` file does a fine job of loading the `.bash_aliases` file like so: + +{% highlight bash %} +if [ -f ~/.bash_aliases ]; then + . ~/.bash_aliases +fi +{% endhighlight %} + +This essentially allows `.bashrc` to load the '.bash_aliases' file within itself, preventing you from meddling with it and managing the list of aliases neatly. + +### Creating a Permanent Alias +Creating a permanent alias is easy. Just open up ~/.bash_aliases and append the following line to it. + +{% highlight bash %} +alias foo='bar' +{% endhighlight %} + +Whenever you type in "foo", "bar" will be passed as an input to the terminal.
+**Note:** You can do this with ~/.bashrc as well but it is neater not to. + +A perhaps better way to do this would be to automate the task and save yourself the hassle of opening a the fine and appending to it manually. And what better way to create aliases by using another alias? I wanted to have a way to create a permanent alias by just typing in a 'p' before alias like so: + +{% highlight bash %} +palias foo='bar' +{% endhighlight %} + +To do this, I opened up `~/.bash_aliases` and created a function called permanent_alias and called it every time I entered "palias" on the terminal: + +{% highlight bash %} +permanent_alias(){ + KEY=$(echo $1 | cut -d"=" -f 1) + VALUE=$(echo $1 | cut -d"=" -f 2-) + echo -e "\nalias $KEY='$VALUE'" >> /home/nihal/.bash_aliases + echo "New permanent bash alias set: alias $KEY='$VALUE'" + if [ -f ~/.bash_aliases ]; then + . ~/.bash_aliases + fi +} + +#Create alias for function call +alias palias='permanent_alias' +{% endhighlight %} + +#### Explanation ++ $1 is a **positional parameter** that returns the first argument passed. Since "palias" is an alias to a function call, it returns the first word after the word "palias", without the inverted commas. `palias foo='bar'` will return foo=bar as $1.
+Interestingly, $0 returns the address of the script or shell running. In this case /bin/bash ++ **$KEY** and **$VALUE** variables are defined by splitting the string in $1 at the first "=". The string **$1** is passed to cut and with delimiter (**-d**) as "**=**", fields (**-f**) **1** and **2-** are selected +{% highlight bash %}echo "foo='bar'" | cut -d"=" -f 1 +#returns "foo" +echo "foo='bar'" | cut -d"=" -f 2 +#returns "bar" +{% endhighlight %} +**Note:** `echo "foo='bar'" | cut -d"=" -f 1` has the same effect as `echo "foo='bar'" | cut --delimiter="=" --fields 1 `
+**Note:** `echo "foo='bar==car'" | cut -d"=" -f 2-` fetches 'bar==car' while `echo "foo='bar==car'" | cut -d"=" -f 2` fetches 'bar + ++ Once KEY and VALUE are abstracted, they are appended to the `.bash_aliases` file using {% highlight bash %}echo -e "\nalias $KEY='$VALUE'" >> /home/user/.bash_aliases{% endhighlight %} +**Note:** The -e flag is for enabling interpretation of backslash escapes like "\n" (newline). `echo "string" >> file` is used to append "string" at the end of file. + ++ The `if [ -f ~/.bash_aliases ]; then . ~/.bash_aliases fi` allows you to use your newly declared permanent alias in the running terminal too, by loading the bash_aliases file again. Not doing this, would result in restarting of terminal for changes to take effect. (Thanks Vinayak for pointing out) + +#### Usage ++ For single word aliases, scrapping the inverted commas would do. +{% highlight bash %} +palias foo='bar' +and +palias foo=bar +would have same effect as we manually add inverted commas later. +{% endhighlight %} + However, +{% highlight bash %} +palias foo='cd /home' +#$1 = "foo=cd /home" +and +palias foo=cd /home +#$1 = "foo=cd" +would not have the same effect. +{% endhighlight %} + ++ For special characters like " ( , ) , @" etc, scrapping the inverted commas would not work +{% highlight bash %} +palias foo='permanent_alias()' +and +palias foo=permanent_alias() +would not have same effect as "(" would be an unexpected token. +{% endhighlight %} + ++ Garbage after the first space won't matter. +{% highlight bash %} +palias foo='bar' +and +palias foo='bar' this is an amazing blog +would have same effect. +{% endhighlight %} + ++ Spaces around the "=" in `palias foo = 'bar'` wouldn't work. They wouldn't work with regular alias either, for that matter. + +If you're still reading, I hope you found it useful. Till next time! :) \ No newline at end of file diff --git a/_posts/2016-05-16-J.A.R.V.I.S..markdown b/_posts/2016-05-16-J.A.R.V.I.S..markdown new file mode 100644 index 0000000..d101e92 --- /dev/null +++ b/_posts/2016-05-16-J.A.R.V.I.S..markdown @@ -0,0 +1,182 @@ +--- +layout: post +title: "J.A.R.V.I.S." +date: 2016-05-16 +comments: true +tags: +- AI +- python +--- + +{: .center .w100} +![J.A.R.V.I.S.]({{ site.baseurl }}/img/jarvis.jpg "J.A.R.V.I.S.") + +Almost a week ago, I attempted to create [my own version](https://github.com/nihal111/J.A.R.V.I.S) of Iron Man's J.A.R.V.I.S. which would perform a few tasks and have chatbot like abilities. After a bit of research I found out about [AIML](http://www.alicebot.org/aiml.html) and its [interpreter for python](https://pypi.python.org/pypi/PyAIML). I also found ways to convert text to speech and speech to to text using python libraries like [pyttsx](https://pypi.python.org/pypi/pyttsx) and [SpeechRecognition](https://pypi.python.org/pypi/SpeechRecognition/3.4.3). I soon ended up making a J.A.R.V.I.S. which understood some of the things I said and performed a few fun actions. + +## Configuring voice input and output: + +### Text to Speech: + +With pyttsx installed through `pip install pyttsx` or otherwise, + +{% highlight python %} +import pyttsx +def speak(jarvis_speech): + engine = pyttsx.init() + engine.say(jarvis_speech) + engine.runAndWait() + +speak("Hello world") +{% endhighlight %} + +This should produce an audio output of "Hello World" in a slightly mechanical voice. + +### Speech-to-Text: + +With SpeechRecognition installed through `pip install SpeechRecognition` or otherwise, + +{% highlight python %} + +import speech_recognition as sr +def listen(): + r = sr.Recognizer() + with sr.Microphone() as source: + print("Talk to J.A.R.V.I.S: ") + audio = r.listen(source) + try: + print r.recognize_google(audio) + return r.recognize_google(audio) + except sr.UnknownValueError: + offline_speak("I couldn't understand what you said! Would you like to repeat?") + return(listen()) + except sr.RequestError as e: + print("Could not request results from Google Speech Recognition service; {0}".format(e)) + +listen() +{% endhighlight %} + +This should listen to an audio input once from the microphone. However this can produce a series of warnings and errors. Resolution for some errors can be found in the Troubleshooting section of [this page](https://pypi.python.org/pypi/SpeechRecognition/3.4.3). + +## Working with AIML: + +AIML stands for Artificial Intelligence Markup Language. AIML is XML based markup language meant to create artificial intelligent application to create human interface. Using AIML, the implementation remains easy to program and highly maintainable. However, the development for AIML has become rather stagnant and AIML 1.0 (the one which has a python interpreter) has a documentation dating back to 2005, making it quite obsolete. Nevertheless, AIML is easy to learn and fun to use. At the very basic level, AIML recognizes patterns and gives responses as programmed. The patterns are called categories and responses are called templates. A very basic AIML code looks like this: + +{% highlight XML %} + + + HELLO + + + +{% endhighlight %} + +This small piece of code allows J.A.R.V.I.S. to reply with "Well, hello!" for every "HELLO" it gets as input. + +Such a code can then be customised to give a random output from a list of templates, redirect to a already defined pattern, use a part or whole of the user's input, run shell scripts etc. Out of all these running a shell script makes AIML, or atleast J.A.R.V.I.S. very powerful. + +All one has to do to create a chatbot using AIML, is to make up a list of `.aiml` files containing categories like the one defined above and use the aiml library for python to import them into a kernel using a `startup.xml` file which looks like this: + +{% highlight XML %} + + + LOAD AIML + + + +{% endhighlight %} + +This should allow one to load up all the aiml files present in the working directory to the created kernel. A simple python script to do is: + +{% highlight python %} +import aiml + +kernel = aiml.Kernel() +kernel.learn("startup.xml") +kernel.respond("load aiml") + +while True: + print kernel.respond(raw_input("Talk to J.A.R.V.I.S: ")) +{% endhighlight %} + +A good guide to get started with AIML using the python interpreter can be found [here](http://www.devdungeon.com/content/ai-chat-bot-python-aiml). + +## Using the \ tag: + +The system tag in AIML is a very powerful tag. It allows the script to run a shell command and use its output. A very simple example of this is: + +{% highlight XML %} + + WHAT TIME IS IT + + +{% endhighlight %} + +Running `date "+%l:%M %P"` in shell returns the current time in a 12 hour format like "6:12 PM". This can be used as a template output for the question "What time is it?". + +Using the \ tag one can achieve a lot of functionalities like opening applications, killing running processes, changing volume levels, adjusting brightness, changing wallpapers etc. And J.A.R.V.I.S. does quite a few of them. + +## Integrating Python scripts + +Since it is easy enough to use shell commands through AIML. It is equally easy to use the shell to run python scripts and perform tasks using their output. A really fun example and perhaps the best feature of J.A.R.V.I.S. is the following. + +### Finding and playing a song on youtube +With the following python script, to find the link for first result for a given `query`: + +{% highlight python %} +import urllib +import urllib2 +from bs4 import BeautifulSoup +import sys + +flag = 0 +query = sys.argv[1].strip("\"").replace(" ","+") +url = "https://www.youtube.com/results?search_query=" + query +response = urllib2.urlopen(url) +html = response.read() +soup = BeautifulSoup(html,"lxml") +for vid in soup.findAll(attrs={'class':'yt-uix-tile-link'}): + if ('https://www.youtube.com' + vid['href']).startswith("https://www.youtube.com/watch?v="): + flag = 1 + print 'https://www.youtube.com' + vid['href'] +if flag == 0: + print "https://www.youtube.com" +{% endhighlight %} + +and this AIML file which opens the link provided by the above script in chromium-browser: + +{% highlight XML %} + + PLAY SONG * + + +{% endhighlight %} + +the following output can be achieved: + +**Talk to J.A.R.V.I.S :** play song Killswitch Engage This Fire Burns
+**J.A.R.V.I.S:** Sure thing! Created new window in existing browser session. + +With this [song](https://www.youtube.com/watch?v=OPpJ7xyUapc) opened in a new chromium-browser tab.
+I have improved the above AIML code to produce this output: + +**Talk to J.A.R.V.I.S :** play me a song
+**J.A.R.V.I.S :** What song, sir?
+**Talk to J.A.R.V.I.S :** Killswitch Engage This Fire Burns
+**J.A.R.V.I.S :** On it! Created new window in existing browser session. + +The repository for J.A.R.V.I.S. lies [here](https://github.com/nihal111/J.A.R.V.I.S). Feel free to [fork](https://github.com/nihal111/J.A.R.V.I.S/fork) it and customise it. Create a PR if you feel you have an interesting feature that could be added. + +Happy coding! \ No newline at end of file diff --git a/_posts/2016-05-18-auto-deploy.markdown b/_posts/2016-05-18-auto-deploy.markdown new file mode 100644 index 0000000..d036689 --- /dev/null +++ b/_posts/2016-05-18-auto-deploy.markdown @@ -0,0 +1,47 @@ +--- +layout: post +title: "Auto Deploy on Server" +date: 2016-05-18 +comments: true +tags: +- git +- ruby +--- +It had been a while since I had been using a server to host the [website for WnCC](http://www.wncc-iitb.org). With a lot of development happening around, updating and testing changes on the server, had become a requirement. Having built the site in Jekyll, I required to shift the contents of `_site` from my local machine to `/var/www/html` on the server, after every build. I had been following the simple, standard method of using scp, for a long time. Copying all the content from `_site` to `/var/www/html` was now becoming inefficient (as I copied all the files in the folder all over again), took a lot of time as the site started expanding with more multimedia content, and required a long terminal command too. I could have used a probably more efficient way of SSHing into the server, pulling from the git repository and copying the contents of the `_site` folder into `/var/www/html`. But this would have been tedious too, and probably could have been made easier with a script. Nevertheless, it would have required me to SSH into the server, and atleast a couple of terminal commands. + +### Discovering [Github Webhooks](https://developer.github.com/webhooks/) +Enter webhooks. [Webhooks](https://developer.github.com/webhooks/) allow one to set up an integration with their github repository to listen for one or more events. Whenever such an event occurs, Github sends a HTTP POST payload to the webhook's configured URL. An event can occur with the creation of an issue, a push to the server or be triggered whenever a repository is starred, forked etc. Webhooks can be used to do a lot of things. I have used a webhook, in this example for the quite general purpose of setting up an auto-deplow on my server. + +Github provides a quite [comprehensive guide](https://developer.github.com/webhooks/configuring/) about how to set up a webhook to the local host which is connected to the web using [ngrok](https://ngrok.com/download). I followed the guide and replicated similar steps on my server to get my webhook configured to send a HTTP POST payload to the server. + +### Using [Sinatra](http://www.sinatrarb.com/) +I used Sintara to create a simple web framework which would receive a HTTP POST made to the configured server URL, and run a small shell command. Having written this small piece of code, I could now reflect all changes made in the repository on the website, everytime a push is made to the repository. The following code renames the `html` folder inside `/var/www/` to `_site` and performs a git pull inside `/var/www` and later renames it back to `html`. This is done as the built site lies inside the `_site` folder of the repository. I + +{% highlight ruby %} +# hook.rb +require 'sinatra' +require 'json' + +set :bind, '0.0.0.0' + +post '/payload' do + #push = JSON.parse(request.body.read) + #puts "I got some JSON: #{push.inspect}" + output = `mv html _site ; git pull origin master; mv _site html` + p output +end +{% endhighlight %} + +Running a `ruby hook.rb -o 0.0.0.0` will give a message like `Sinatra/1.4.4 has taken the stage on 4567...`. Making a POST request on http://IP:4567/payload, will now trigger the shell command in the above script. (`-o 0.0.0.0` and `set :bind, '0.0.0.0'` allows access from networks other than localhost) + +**Note:** You may have to enable the port if you are using a firewall on your server. A simple `sudo ufw allow 4567` should do it. + +However this session of Sinatra will close as soon as you CTRL+C out of it or logout. To keep such an instance running even after logout you could try + +`nohup sudo ruby hook.rb -o 0.0.0.0 &` + +This would put the Sinatra process in background and keep it running even after you have logged out. + +I did not know about github webhooks earlier and this was an interesting find. The above was a quick setup for automation. If you know a way in which I could improve it, do let me know in the comments. + +Till next time! \ No newline at end of file diff --git a/_posts/2016-06-03-Mozilla-Quarter-of-Contribution.markdown b/_posts/2016-06-03-Mozilla-Quarter-of-Contribution.markdown new file mode 100644 index 0000000..a0dc317 --- /dev/null +++ b/_posts/2016-06-03-Mozilla-Quarter-of-Contribution.markdown @@ -0,0 +1,28 @@ +--- +layout: post +title: "Mozilla: Quarter of Contribution" +date: 2016-06-03 +comments: true +tags: +- open source +- mozilla +--- +I have decided to dive into open source development this summer. Under the WnCC Seasons of Code programme, I have chosen to take part in the Mozilla Quarter of Contribution project mentored by Kalpesh Krishna ([martiansideofthemoon](https://github.com/martiansideofthemoon)). The [WnCC Seasons of Code](http://wncc-iitb.org/soc/) is an initiative by the Web and Coding Club of IIT Bombay, much akin to the Google Summer Of Code but without any monetary incentive. + +### Mozilla: Quarter of Contribution +The [Mozilla: Quarter of Contribution](https://wiki.mozilla.org/Auto-tools/New_Contributor/Quarter_of_Contribution) is an opportunity to work on a large project for a couple of months. Current projects for Summer 2016 are: + +- Web Platform Tests - Results Viewer Refactoring (:jgraham, :martianwars) +- Perfherder (:wlach, :jmaher) +- Talos (:jmaher, :rwood) + +I have made a few bug fixes and have merged PRs on Web Platform Tests as well as Perfherder. I have decided to work on wptview under [:jgraham](https://github.com/jgraham) and [:martianwars](https://mozillians.org/en-US/u/martianwars/) as a part of Mozilla QoC. + +### wptview +[Wptview](https://github.com/mozilla/wptview) is a web platform test viewer. The Web Platform Tests (WPT) are a set of cross browser validation tests designed to validate common functionality on the web between browsers. Wptview is used for viewing the results of web-platform-tests and for easy visual comparison between different tests results. One can add the test data available as mozlog files and all the tests along with their results will be loaded in the form of a table. These results can be studied further by adding filters and sorting by status. + +The [agenda for the QoC](https://wiki.mozilla.org/Auto-tools/New_Contributor/Quarter_of_Contribution/WPTViewer_Refactor) is a UI revamp, addition of unit testing as well as adding visualizations to be accompanied by test results. I would like to work on all these fratures. + +I have fixed a few basic bugs due to which I know a little about the codebase. I am a beginner in AngularJS and plan to learn as I go on contributing to this project. + +In conclusion, I plan to learn a lot contributing to this project. This is my first hand at open source as well, so I hope it turns out to be an exciting learning experience. \ No newline at end of file diff --git a/_posts/2016-11-22-Terasology-Getting-started.markdown b/_posts/2016-11-22-Terasology-Getting-started.markdown new file mode 100644 index 0000000..acb71a9 --- /dev/null +++ b/_posts/2016-11-22-Terasology-Getting-started.markdown @@ -0,0 +1,246 @@ +--- +layout: post +title: "Terasology: Getting Started" +date: 2016-11-22 +comments: true +tags: +- open source +- MovingBlocks +- Terasology +- GCI +--- + + + + + +{: .center} +![Terasology]({{ site.baseurl }}/img/Terasology.jpg "Terasology") + +This is a comprehensive guide for getting started with your first contribution to the Terasology project. If you've stumbled here and don't know what Terasology is, check out the [github repository][Repo]. + +The [Quick Start guide][wiki] on the github wiki of the repository is pretty complete, but it can get a little confusing if this is your first time. If not and you want to get cracking as soon as possible, do head over there. + +Without any further ado, let's get started. + +# Run from source +This is probably the first and most important step you need to do before you can do anything else. Also, the first question you'll be asked on IRC when you're in doubt, is whether you're able to "run from source". + +## 1. Get Java + +{: .center} +![Java]({{ site.baseurl }}/img/java.png "Java") + +Java 8 SDK is a requirement for the game to run. You can download this from [here](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html) by choosing your OS. + +## 2. Get Git + +{: .center} +![Git]({{ site.baseurl }}/img/git.png "Git") + +If you don't have git setup, you need to do so before going any further. You'll need git to collaborate and contribute to this project. +
+
+ What is git?
+
+ Git is a free and open source distributed version control system designed to handle everything from small to very large projects with speed and efficiency. + Version control is a system that records changes to a file or set of files over time so that you can recall specific versions later. +
+ Git allows the users working on a project to mirror and save all changes they make on the central server as well as keep a copy in their own system. +
+
+ +#### For Linux: +If you’re on Fedora, you can use yum: +{% highlight bash %} +$ sudo yum install git-all +{% endhighlight %} +If you’re on a Debian-based distribution like Ubuntu, try apt-get: +{% highlight bash %} +$ sudo apt-get install git-all +{% endhighlight %} + +#### For Windows: +Download git for windows [here](https://git-scm.com/download/win). + +#### Configuration: +Once you have git installed, open bash (terminal) in Linux or git bash (from Programs) in Windows and get it configured. +git config --global user.name "Your Name" +git config --global user.email "your_email@whatever.com" + +## 3. Fork + +{: .center} +![Fork]({{ site.baseurl }}/img/fork.png "Fork") + +
+
+ What is a fork?
+
+A fork is a copy of a repository. Forking a repository allows you to freely experiment with changes without affecting the original project. Forking the MovingBlocks/Terasology repository would create a copy of it at www.github.com/your_github_username/Terasology. +
+
+Click *[here][fork]* to fork the *[Terasology github repository][Repo].* Doing so will create a repository named "Terasology" under your github account and take you to it. From now you can access your copy of the repository here: www.github.com/your_github_username/Terasology + +## 4. Clone +
+
+ What is cloning?
+
+Cloning downloads or "clones" a repository into a newly created directory by the name of the repository. Cloning www.github.com/your_github_username/Terasology on your machine would create a folder named Teraslogy and download all the content inside it. Use cd to move in and out of directories when inside bash/git-bash. +
+
+ +Open up bash (Linux) or git-bash (Windows), go to the directory where you want to clone the repository: +{% highlight bash %} +cd path/to/directory/ +git clone www.github.com/your_github_username/Terasology +cd Terasology/ +{% endhighlight %} + +## 5. Run the game +You now have the repository cloned and can run the game using gradlew. + +Open bash or git-bash, cd in to the Terasology directory and type in: +{% highlight bash %} +./gradlew game +{% endhighlight %} + +
+
+ What is gradlew?
+
+The gradlew is a script which downloads a version of the Gradle through which most of the automation happens. The initial gradlew execution will download all project dependencies and could take a while. So, be patient.
+
+ +This should show a build log, and launch the game. If this worked you're able to run from source. If it didn't you should get back to IRC and ask for help in debugging. However, any problem encountered at this point is usually from Java not being configured right, such as having an older version as your default Java. See [Common Issues](https://github.com/MovingBlocks/Terasology/wiki/Common-Issues) for more. + +Ask in the Support Forum if issues remain, or come join us on #terasology on Freenode IRC. See [Using IRC](https://github.com/MovingBlocks/Terasology/wiki/Using-IRC) and please be patient! IRC isn't necessarily instant communication and it may take a while to get a reply. + + +## 6. Use an IDE + +With this large a project, you could easily get lost and 'grep'ing would be inefficient. We have a series of customizations that prepare run configurations, Git integration, and so on for the project, specifically for IntelliJ. Eclipse has fewer of these but is still entirely usable, as is NetBeans, but you'll need to figure out some details there yourself. I personally recommend the use of Intelij IDEA. + +{: .center} +![Intellij]({{ site.baseurl }}/img/intellij.jpeg "Intellij") + +#### Install Intellij IDEA on Linux: + +{% highlight bash %} +sudo apt-add-repository ppa:mmk2410/intellij-idea-community +sudo apt-get update +sudo apt-get install intellij-idea-community +{% endhighlight %} + +#### Install Intellij IDEA on Windows: + +Download and install the setup from [here](https://www.jetbrains.com/idea/download/). + +Open bash or git-bash and type: +{% highlight bash %} +./gradlew idea +{% endhighlight %} +This would prepare project files for Intellij. Open the resulting Terasology.ipr as an existing project in IntelliJ - do not create a new project or attempt to import the project via Gradle. + +## 7. Find a Bug + +Once you are able to run from source and preferably have an IDE set up, you should get started with working on your first bug. The complete list of issues can be found [here](https://github.com/MovingBlocks/Terasology/issues). However, you should look for issus with the tag `Bite-size`. All bite-sized issues can be found [here](https://github.com/MovingBlocks/Terasology/issues?q=is%3Aissue+is%3Aopen+label%3ABite-size). + +## 8. Code, code and code + +By default you would be on the develop branch. Before you start making changes to the code, remember to create a new branch. This can be skipped, however it is the best practice, especially when working on multiple issues. Also, if you don't create a new branch, a Pull Request for your second bug fix will also contain a fix for the first bug, if the first PR isn't merged till then. + +
+
+ What is a branch?
+
+Within a repository you have branches, which are effectively forks within your own repository. Your branches will have an ancestor commit in your repository, and will diverge from that commit with your changes. You can later merge your branch changes. Branches let you work on multiple disparate features at once. +
+
+ +### Creating a new branch +Open bash or git-bash and type: +{% highlight bash %} +git checkout -b new_branch_name +{% endhighlight %} + +Get cracking on a solution. Ask on IRC when in doubt. + +## 9. Make your first contribution + +Once you've come up with a fix, it's time to commit those changes and create a pull request. + +### Commit your changes +Open bash or git-bash and type: +{% highlight bash %} +git add -A +# to add all files to staging. You could select individual files too +git commit -m "Fix for #1234" +# to commit changes with a relevant commit message. +git push origin new_branch_name +# Push to the newly created branch on your fork +{% endhighlight %} + +
+
+ What is a commit?
+
+Whenever you commit in git, you take a screenshot of your working directory or your repository. You could come back to this state of your repository later at any point or publish these changes to your fork of the repository. +
+
+ +
+
+ What is pushing?
+
+In git, when you push, you bring the changes on your local repository come into effect in the remote repository. In this case changes to the branch "new_branch_name" are published on the remote ("origin") repository www.github.com/your_github_username/Terasology. +
+
+ +Once you've pushed successfully, open up your fork (www.github.com/your_github_username/Terasology). This should show something like: + +{: .center} +![PR]({{ site.baseurl }}/img/terasologyPR.png "PR") + +Clicking on "Compare & pull request" opens a page for you to describe your bug and solution. The pull request compares (head) your_github_username/Terasology/new_branch_name with (base) MovingBlocks/Terasology/develop. Fill in everything and hit "Create Pull Request". + +Once done, let the mentors have a look at your PR. If they want changes, you should make the required changes, test locally and then, create a new commit in the same branch and finally push. + +## 10. Goto 7 + +Don't stop now. Go find another bug to fix! :D + +[wiki]: https://github.com/MovingBlocks/Terasology/wiki/Dev-Setup +[fork]: https://github.com/MovingBlocks/Terasology/fork +[Repo]: https://github.com/MovingBlocks/Terasology \ No newline at end of file diff --git a/_posts/2017-02-18-MovingBlocks-GCI-Wrap-Up.markdown b/_posts/2017-02-18-MovingBlocks-GCI-Wrap-Up.markdown new file mode 100644 index 0000000..ea6454b --- /dev/null +++ b/_posts/2017-02-18-MovingBlocks-GCI-Wrap-Up.markdown @@ -0,0 +1,75 @@ +--- +layout: post +title: "MovingBlocks- GCI Wrap Up" +date: 2017-02-18 +comments: true +tags: +- open source +- MovingBlocks +- Terasology +- GCI +--- + +{: .center} +![GSoC]({{ site.baseurl }}/img/GSoC.png "GSoC") + +After an exciting and productive summer that saw huge commitment, dedication and interest from students and mentors alike in MovingBlock's first ever Google Summer of Code participation, it was time to gear up for some new beginnings. + +## Google Code-In + +{: .center} +![GCI]({{ site.baseurl }}/img/GCI.png "GCI") + +Google Code-in is a contest that introduces pre-university students (ages 13-17) to open source software development. Students claim tasks from a pre-selected pool of problems from varying genres and difficulty-levels, work on them one at a time, have them approved by the mentors and repeat. At the end, students are awarded with t-shirts, hoodies and a certificate. The top two winners from each organisation get to go on a trip to Google's Mountain View office in California, along with a mentor. This year, that is the winter of 2016-17, saw **1,340 students from 62 countries** completing an impressive 6,418 tasks. + +MovingBlocks having become a veteran org in GSoC, was eligible to participate in this edition of GCI. By mid November, we had gathered a team of mentors who were actively creating bite-sized tasks ranging in complexity and theme. These tasks were assorted as **Code, Documentation/Training, Outreach/Research, Quality Assurance, User Interface** etc. **November 28th** marked the start of student activity that would last till **January 18th**. + +## Winter Has Come + +{: .center} +![Winter Has Come]({{ site.baseurl }}/img/winterhascome.jpg "Winter Has Come") + +With the winter winds came gusts of excited students ready to dive into the pool of tasks that we had created. We had for long discussed how the first week (called the "hell week") is usually the most intense and oh boy, it did get hectic and overwhelming at times. We saw the pile of tasks deplete faster than we could imagine, and students kept sending in work faster than we could review it. At times it became really helpful to have mentors dispersed over the globe so that we spanned all time-zones. At other times, caffeine was our only reliable salvation. + +IRC exploded with curious students asking for assistance, Github notifications set new records and we began running out of tasks before we could even wipe the sweat off our foreheads. But the entire mentor team pulled up their socks, converted half-baked ideas into well written task desciptions, added more research, design and documentation related tasks, allowed for existing issued on Github to count as tasks and did lots more. Luckily, Terasology had huge potential for multi-instance tasks in creating equipments, food items, recipes and even new plants inside the game. Some of the best works by students were the splendid World Generators they created. More often than not, most of these tasks were in chains containing sequential tasks, such that each bite-sized task provided an introduction to a topic and had a follow up tasks which ensured a gradual increase in complexity and provided direcion to students. + +The Alpha 6 release event happened midway through GCI and went great with several students checking out our event server, which didn't even crash once in over 60 hours. + +## Hell Week is just one week? + +The "hell week" concept which we had just heard about prior to our participation in GCI, became so much more familiar that we realised how it missed an 's' at the end. The hell week had lasted for an entire three weeks with only slight variation in activity, before it took a stark downfall for Christmas. The majority of the "Create Content" tasks had gone into making new items for Cooking, Potions, Equipment, SimpleFarming and we had loads of new things to test out. Task piles were depleting as always and mentors had to stay on their toes to review work that came in like a storm. + +## Crossing the Finish Line + +{: .center} +![Finish Line]({{ site.baseurl }}/img/finishflag.png "Finish Line") + +On 18th January, the closing whistle for this edition of Google Code-In was blown. At the end we had- **606 tasks completed by 138 students**, with a total of 222 starting or otherwise getting in touch with us. The **highest** was from a student who had **42 tasks** completed. Out of the 17 organisations that had participated, we came out as the **third highest org** (with respect to number of tasks completed) which was impressive for a first-timer. + +Once again with the end of winter, we saw amazing work by so many students around the globe. A huge thank you to all the students who participated, for all their contributions. Keep up the entusiasm and foster the love for open source. Most of all, hats off to all of the 11 other overworked mentors (excluding myself)- **Cervator, Skaldarnar, rzats, oniatus, flo, xtariq, SkySom, manu3d, anthodeus, avalancs, josharias**. Lastly, thanks to Google for provinding us a platform once again to reach out to students and developers across the globe. + +## Who's the Winner? + +With GCI closing, there was one more task left, but this time for the mentors. But this was no 'bite-sized' task. The mentors were required to select the winners, from the top 11 students by quantity of tasks completed (we had a three way tie at the bottom of the top 10 so it became a top 11). This was extremely difficult as all the students in the list had done great and it was just a numbers game for us to select only 5 winners. + +{: .center} +![GCI Winners]({{ site.baseurl }}/img/GCIwinners.png "GCI Winners") + +Here are two articles that have our top 2 winners featured- [Isaac Ong](http://www.straitstimes.com/singapore/education/third-time-lucky-for-student-in-googles-coding-competition) and [Scott M. Sunarto](http://www.thejakartapost.com/life/2017/02/04/three-indonesian-students-win-google-open-source-competition.html). + +To all the students who didn't make it to the list, do not get disheartened, you had done amazing work. I'd highly encourage all students who'd be eligible next year to participate once again, as it'll again be a great learning experience. To those who would not be eligible, try GSoC. + +The real winner, I believe was MovingBlocks, as we witnessed a load of talented students connect with us and deliver amazing work. Some of these have grown to care about the project and our community has grown. + +## Student Reviews + +We ended GCI with a [recap thread](http://forum.terasology.org/threads/google-code-in-2016-recap-thread.1752/) to discuss students' experiences with Terasology. We even went ahead and made it a finishing task which students could claim. + +The interests in various parts of the game varied and the we received valuable input on how we could improve on our tasks next year. Overall we received compliments on areas such as interaction, assistance, availability and speedy reviews. General feedback about mentors and our review system was very flattering. Some students described us as the "most accommodating org" and our response rates as "phenonmenal". One student descibed our tasks as much more fun to do (having advantage of being a game) while another talks about the second family nature of our IRC. + +{: .center} +![Terasology]({{ site.baseurl }}/img/terasologylogo.png "Terasology") + +All in all, it was a huge learning experience, both for the students and for the Terasology community. We now know a lot many ways in which we can improve the next year. Till then it is time to prepare for GSoC '17. + + diff --git a/_posts/2017-05-04-Google-Summer-of-Code.markdown b/_posts/2017-05-04-Google-Summer-of-Code.markdown new file mode 100644 index 0000000..8b1894e --- /dev/null +++ b/_posts/2017-05-04-Google-Summer-of-Code.markdown @@ -0,0 +1,43 @@ +--- +layout: post +title: "Google Summer of Code Selection" +date: 2017-05-04 +comments: true +tags: +- open source +- MovingBlocks +- Terasology +- GSoC +--- + +Summer has kicked off with great news. My proposal for the Google Summer of Code with MovingBlocks- Terasology has been selected. + +## What is the Google Summer of Code? + +{: .center} +![GSoC]({{ site.baseurl }}/img/GSoC.png "GSoC") + +To the uninitiated, Google Summer of Code is a global program targeted at bringing university students into open source. Students work with an open source organization on a 3 month programming project during their summer break. Google first selects around 200 organisations and funds their open source projects. It's a win-win. The students get an awesome learning experience and a huge stipend. The organisations get a lot of work done from the dedicated students. Well, Google just plays the nice guy being a good Samaritan. + +This would be MovingBlocks' second GSoC selection as a mentoring organisation, which makes it a veteran org already. With a total of 10 slots this year, way more than last year's 3, this summer might prove to be the immensely productive for MovingBlocks. + +## What is MovingBlocks- Terasology? + +{: .center} +![Gooey]({{ site.baseurl }}/img/gooey.jpg "Gooey") + +[Moving Blocks- Terasology](https://github.com/MovingBlocks/Terasology) is a minecraft-like open source game built in a voxel world. A [voxel](https://en.wikipedia.org/wiki/Voxel) world is essentially a 3-D world made up from blocks. Terasology is still in it's Alpha stage, but what makes it really special is it's modularity. With a huge, diverse set of modules already developed/in-development, Terasology offers amazing possibilities. It has a very basic minimal engine, where even core features like health, inventory, combat etc can be added on top or removed as plug-in modules. + +## What am I doing? + +My [project](https://summerofcode.withgoogle.com/projects/#6685506025816064) is titled as **Exploration World- Improved Gameplay** (proposal [here](https://drive.google.com/file/d/0B3HM64I0M4DmYnVWUUpyQkZ2b1k/view)). In a gist, I plan to add WildAnimals, Puzzles, Exploration and other content to create a new gameplay module. The new gameplay module would pack together the best of whatever is created yet, to create a new gameplay setting that would add meaning and purpose for the end user. + +My primary mentor would be [Skylar 'skysom' Sommers](http://forum.terasology.org/members/skysom.1621/) and secondary mentors would be- [Florian 'flo' Köberle](http://forum.terasology.org/members/florian.1335/), [Xavier 'xtariq' Tariq](http://forum.terasology.org/members/xtariq.1697/) and [Isaac 'iojw' Ong](http://forum.terasology.org/members/isaac.1943/). + +## When am I doing this? + +Since my college reopens mid-July, I've already started work on the Project. Officially May is meant to be a Community-Bonding period for most and the Coding phase only starts in July. However I plan to finish my GSoC early and I've already started off with the coding phase. + +## Blog for updates + +I plan to use this blog to keep updating my progress. This blog will also be an attempt to document the work that I'll be doing. This is gonna be an exciting summer! \ No newline at end of file diff --git a/_posts/2017-05-08-GSoC-week1-2.markdown b/_posts/2017-05-08-GSoC-week1-2.markdown new file mode 100644 index 0000000..ff3395c --- /dev/null +++ b/_posts/2017-05-08-GSoC-week1-2.markdown @@ -0,0 +1,194 @@ +--- +layout: post +title: "GSoC Week 1 and 2: Wild Animals Behavior System" +date: 2017-05-08 +comments: true +tags: +- open source +- MovingBlocks +- Terasology +- GSoC +--- + + + + + + +The start to GSoC has been smooth. Currently as I write this wrap up post for week one and two, my work has already crossed the week 3 mark according to my proposal. + +# What have I been up to? +I've been adding new features to the [WildAnimals](https://github.com/Terasology/WildAnimals) module. The module only had a deer that idly moved around and did nothing else. When hit it would lose health and ultimately just disappear as a glitch when it's health reached 0. + +A lot has happened since and at this point there are 4 variants of the deer that exhibit very different behaviors- `deer`, `insensitiveDeer`, `aggressiveDeer` and `hostileDeer`. + +
+ +
+ +
+ +Before we get into details of how these were built, let's have a look at a few preview videos: + +
+ +
+
+
+ +
+ +### Importing an animal in game +First an animal model is made in blender. After an artist finishes up a model, gets it rigged, UV Mapped and adds animations, it is pushed to the [Meta repository](https://github.com/MetaTerasology/WildAnimals/) that holds all the blender files for creature models. There is a comprehensive guide on how to add creatures in game [here](https://github.com/Terasology/TutorialAssetSystem/wiki/Add-a-creature) that I've written. Also there is one written by flo, [here](https://github.com/MovingBlocks/TeraMisc/blob/master/blender_addons/io_md5_exporter/tutorial/Tutorial.md). Thanks to [quaternius](https://github.com/quaternius), I've been getting some help with animal models. + +### Working with the animal in game +Each animal has a prefab file located [here](https://github.com/Terasology/WildAnimals/tree/master/assets/prefabs/animals) that details the characterstics of the animal as components. To know more about components and the Entity system architecture, go [here](https://github.com/MovingBlocks/Terasology/wiki/Entity-System-Architecture). +Once an animal prefab is made, it can be spawned in game by typing `spawnPrefab prefabName` in the console. + +# Event driven Behavior System + +
+ +The four different deer I mentioned really have the same animal model, animations and texture. They only vary in behavior. This behavior handling forms the crux of the WildAnimals module. Let's dive into a little more detail. + +The Behavior System built in the engine allows something known as behavior trees, to define a certain behavior. + +
+
+ What is a behavior tree?
+
+ A behavior tree is used to define conditional or sequential behavior for an entity. A behavior tree essentially has a set of nodes, each node executes some logic and has a condition set for when it would return a status of FAILURE, SUCCESS or simply keep RUNNING. An involved behavior tree can switch among different nodes based on the previous or child node's status. +
+ This forum post and youtube video would really give you a feel for behavior trees. +
+
+ +These behavior trees are central to the event driven behavior system. Each behavior tree defines a particular type of behavior that can be applied to an entity, for eg- + ++ A "**stray**" behavior can have a deer idly roam around, walk and stand for a while. ++ A "**flee**" behavior can have the deer run away from the player until it's at a safe (defined minimum) distance. ++ A "**hostile**" behavior can have the deer close in on the player and then inflict damage. + +The "stray" behavior tree that exists in the [Pathfinding module](https://github.com/Terasology/Pathfinding) module looks like this: + +{: .center} +![stray]({{ site.baseurl }}/img/strayBT.jpg "stray BT") + +Each of these behavior trees can be applied to the entity by simply defining it in the entity's prefab under the BehaviorComponent. But what's needed for the animals, is a behavior system that controls what behavior the animal has at any point in time. A system that controls when the behavior needs to switch, what should trigger such a switch and which behavior takes a higher precedence. Enter Event Driven Behavior System. + +
+
+ What is an event?
+
+ An event is an action that propagates through all systems in the game to trigger a change or execute some logic. An event is sent to exactly one entity. An event can be received by event handlers, which can add filters for selecting only entities having a certain set of components. Different event handlers can receive the same event in an order of precedence, by specifying a priority. +
+ This wiki page describes in detail how events work. +
+
+ +The WildAnimals module has different packages for different behaviors like "FleeOnHit", "AttackOnHit", "AttackInProximity", "StrayIfIdle", etc. Each of these packages consists of a system and a component. If such a component is attached to an entity, the respective system takes care of handling the behavior changes associated with that package. + +
+
+ How does it work?
+
+ The component from the package whose behavior is to be implemented in an entity, is added to the entity's prefab. Whenever an action/event happens in the game that could trigger a change in the behavior of an entity, an UpdateBehaviorEvent (a consumable event) is sent to the entity. This event is received by event handlers present in any such package's system. These event handlers receive the event based on a priority and trigger the behavior switch by changing the entity's behavior tree inside it's BehaviorComponent. +

+ Let's take the example of the "FleeOnHit" and "StrayIfIdle" package, the first such packages.
+
    +
  • + The FleeOnHit package has a FleeOnHitComponent, which when attached to any wild animal entity would let it exhibit the "flee" behavior when it is hit.
    +
  • +
  • + The StrayIfIdle package has a StrayIfIdleComponent, which when attached to any wild animal entity would let it exhibit the stray behavior when it is idle and has no other behavior that could get triggered.
    +
  • +
  • + For the deer, by default it has a behavior of "stray" defined in it's prefab.
    +
  • +
  • + The FleeOnHitSystem watches for the OnDamageEvent to happen to an entity which has the WildAnimalComponent and FleeOnHitComponent. It saves the event instigator (damage inflictor) to the FleeOnHitComponent and then sends an UpdateBehaviorEvent to the entity to trigger a change if it's needed. +
  • +
  • + The UpdateBehaviorEvent is received by the FleeOnHitSystem. It checks for the instigator inside "FleeOnHit" to be non-null, triggers the behavior switch to "flee" and consumes the UpdateBehaviorEvent.
    +
  • +
  • + The StrayIfIdleSystem also receives the UpdateBehaviorSystem, but with a lower priority. +
  • +
  • + When the deer reaches a safe (defined minimum) distance from the player, the instigator in the FleeOnHitComponent is set to null and another UpdateBehaviorEvent is fired from the CheckFleeStopNode (a part of the "flee" Behavior Tree).
    +
  • +
  • + This event is not consumed by the FleeOnHitSystem event handler as the instigator in FleeOnHitComponent is null. It then is received by the StrayIfIdleSystem event handler, which triggers a behavior switch to "stray" and consumes the event. +
  • +
+
+ The behavior switches simply happen based on the different priorities the event handlers in the different packages have. +
+
+ +### Advantages of the Event Driven Behavior System +There are quite a few advantages of using this approach for dealing with complex and multiple behaviors. + ++ **Easily Extendable and Reusable**: A package consisting of a particular conditional behavior can be used for multiple animals/entities. For eg- the "FleeOnHit" package made for the deer can easily be added to other animals like cows, dogs etc. Adding a behavior is as simple as attaching a component. ++ **Efficient**: There are no constant checks and running loops. The behavior switch is instant. ++ **Simple Behavior Trees**: The behavior trees remain bare-bones and minimal, as they have to deal with only one behavior and not worry about switching behavior. ++ **Neat Prefabs**: The prefab for the animal now gives a good picture of what all behaviors it exhibits. A simple deer's prefab would just have the "FleeOnHit" and "StrayIfIdle" components. A deer's prefab could look like this: +``` +"FleesOnHit": { +"minDistance": 15.0 +}, +"EatsFromBlockIfHungry": { + "block": "grass", + "maxWalkDistance": 4 +}, +"AttractedByHoldItems": { + "items": ["apple", "nut"] +} +``` ++ **Clear order of precedence**: Different behaviors can be given different weights as per priority. A hungry deer when hurt would run for it's life instead of looking for food. A priority list of behaviors could look like this: + ``` + ensure safety (flee if recently damaged) + ensure not hungry + ensure not thirsty + ensure not tired + ensure not curious (has not watched player / player action / player item recently) + ``` ++ **Easy development**: With this system, someone who's making the "EatIfHungry" package does not have to worry about what will happen if the animal is hit when it's hungry. All he has to do is assign the event handler for the "EatIfHungry" package a lesser priority than the "FleeOnHit" package's event handler. + +The post went longer than I had expected it to. The next post would contain details of the deer that have been implemented and maybe new creatures! Most deer at this point are just placeholders for other animals whose models aren't ready yet. Thanks to [flo](http://forum.terasology.org/members/florian.1335/) for all his help lately. The whole event driven behavior system idea was born out of a discussion with him. He's been really helpful in getting my PRs reviewed and merged too. + +In other news, I was away for 3 days (10th to 12th May) for the [Microsoft code.fun.do SHOWCASE event](https://www.acadaccelerator.com/Home/CFDShowCase) that was held in Hyderabad. The trip was fun with sponsored flight trips and hotel stay. Have to catch up with lost time on GSoC though. \ No newline at end of file diff --git a/_posts/2017-05-21-GSoC-week3.markdown b/_posts/2017-05-21-GSoC-week3.markdown new file mode 100644 index 0000000..73a0bef --- /dev/null +++ b/_posts/2017-05-21-GSoC-week3.markdown @@ -0,0 +1,183 @@ +--- +layout: post +title: "GSoC Week 3: Advanced Behaviors and Taming" +date: 2017-05-21 +comments: true +tags: +- open source +- MovingBlocks +- Terasology +- GSoC +--- + + + + + + +The past week has been lighter compared to the previous two, involving a lot more of packing and moving, research and documentation. + +# What have I been up to? + +## More behaviors + +Adding to the 4 deer (`deer`, `insensitiveDeer`, `aggressiveDeer` and `hostileDeer`) from last time two new behaviors have been added namely- `scared` and `friendly`. Again these are just placeholders for actual animals that would display such behavior like a chicken (timid) and a dog (friendly). Here are two new videos that would give a quick preview. + +
+ +
+ +
+ +
+
+
+ +
+
+ +
+ +
+ +
+ +Also, the flee behavior is now improved such that the animal would always run in a direction away from the player as compared to randomly moving about like last time. + +
+ +
+ +In addition, last year's GCI saw a lot of students write up formal descriptions about AI for animals and their behavior. This can be found [here](http://forum.terasology.org/search/2685474/?q=Formal+Description&o=date) and is possibly a good reference for future. + +## Packing and Moving- AdvancedBehaviors + +It was felt that the behavior work that I had been up to, should not really be restricted to the WildAnimals module. It had great potential outside for other NPCs like monsters, zombies, aliens.. you name it. One particular requirement was that of the GooeysQuests' skeleton which would try its best to kill you in the dungeons. Currently the skeleton just has a hostile behavior, which means that it does nothing at all until a player comes close to it. After which, it would follow the player in an attempt to kill. When the player dies or escapes the skelton would return to doing nothing (standing still) where ever it had reached. The `hostileInProximity` behavior that I had implemented for the hostileDeer is probably a better alternative, where in the deer switches from hostile to stray behavior. Further the behavior switching systems could be used to add a **guard behavior** that would allow the skeleton to return to a specific location that it guards (a tressure, a secret door, who knows?). + +All this just meant one thing, that the core behavior systems should not be kept restricted to the [WildAnimals](https://github.com/Terasology/WildAnimals) module as they would have great use even in other modules. With this need was born the [AdvancedBehaviors](https://github.com/Terasology/AdvancedBehaviors) module which would just be a library module having logic and systems that are required by other modules as dependencies, but no content of its own. All the behavior systems and behavior components were packaged and moved to this new module. + +
+ +
+ +## Optional Dependencies and Library/API modules + +[AdvancedBehaviors](https://github.com/Terasology/AdvancedBehaviors) would be my second module in the game, the first being the [WorldlyTooltipAPI](https://github.com/Terasology/WorldlyTooltipAPI) module which too has no content of its own, but just serves as an API module for [WorldlyTooltip](https://github.com/Terasology/WorldlyTooltip). This was decided to be a better alternative to optional dependencies. + +
+
+ What is a Library module?
+
+ A library module is one that does not have any features or content of its own. It only provides systems that are used by other modules. An example of such a module is the Pathfinding module. Also the newly created, AdvancedBehaviors module would just be a library module. +
+
+ +Modules like WildAnimals that use events from the WorldlyTooltip module should not have a dependency on it as it doesn't need to be necessarily activated. A user should be able to enjoy the WildAnimals module without having to activate the WorldlyTooltip module. One possible way to solve this is using optional dependencies. + +
+
+ What is an optional dependency?
+
+ An optional dependency allows the user to activate modules that depend on other modules without activating the other module. The features that rely on the other module would just be enabled when the other module is activated. +
+ Lets take the WildAnimals and WorldlyTooltip module as an example. If the WildAnimals module is made to have an optional dependency on the WorldlyTooltip module, it's core features would be accessible even when the WorldlyTooltip module is inactive. Activating the WorldlyTooltip module just would enable the features that rely on it. +
+
+ +
+
+ What are the problems with optional dependencies?
+
+ Optional dependencies make sure that the user doesn't have to forcefully download a module that serves as an optional dependency. But for a developer, the module would not compile unless the developer manually downloads all the optional dependencies. Also there is a chance that with some changes happening in Java, this feature might not be available later. +
+
+ +The other way to do this is using what are called API modules. + +
+
+ What is an API module?
+
+ An API module is one that allows for modules to use on a feature that is present in an external module without having a direct dependency on it. In short it is an alternative to optional dependencies. It can be thought of as an interface to a class. If a module X relies on some classes in Y for a feature, the classes can be moved to Z. Both X and Y can now have dependency on Z and everything would work naturally. This means that Y does not necessarily need to be activated for the user to enjoy the core features of X. +

+ For example, the WildAnimals module uses the events from the WorldlyTooltip module for the tooltip feature. To enable this, the events were moved to the API module called WorldlyTooltipAPI. Both WildAnimals and WorldlyTooltip had a dependency on the WorldlyTooltipAPI module. WildAnimals module could now be activated without activating the WorldlyTooltip functionality (even though the dependency WorldlyTooltipAPI got activated). +
+
+
+ +
+ +
+ +
+ +--- +## Taming animals +With behaviors being defined for animals, it would be fun to turn a hostile or aggressive animal into a friendly one. Having a horse that you can ride, a donkey that carries around some load, a dog that guards an entrance, a cow that gives milk, all sound like a fun idea to have in game. Here are some thoughts on how taming can work in game. + +Animals can be broadly and vaguely grouped into friendly and unfriendly, with different animals falling at different levels in this classification. Generally, the friendlier the animal, the easier it would be to tame it. + +### How would taming work? +Possibly there could be a taming progress bar that gives the player an idea of how long should he continue the efforts on taming. There might be more than one ways to tame an animal, some more effective than the others. The more effective ones would increase the progress bar quicker allowing for speedy taming. + +### Taming Methods +1. **Petting**- Some very friendly animals like dogs might just be tamed after a while of petting. +2. **Feeding**- Every animal would have a preferred food item (or rather a list of food items it eats with an order of preference). Feeding an animal with its favorite food item would increase the taming progress quicker than with other foods. +3. **Sedating or Tranquilising**- Animals can be fed poisonous berries or some other substances to intoxicate them. These would leave them vulnerable and make them easier to tame. Such an approach would be useful for more unfriendly or aggressive animals. +4. **Tranquiliser darts**- For animals that are hostile and would attack when in proximity of the player, tranquiliser darts could be used to intoxicate and subdue the animal, leaving it in a vulnerable state where it can be fed and tamed easily. +5. **Trap**- Animals that are timid or hostile would either run away from the player or chase the player. A good idea is to trap the animals and then approach them when they are not in a position to run away or attack. An animal trapped in such a manner would have the feed option available now (which wouldn't have been available earlier). +6. **Knocking out**- The animals can be knocked out by fighting off with different equipment. When an animal reaches a low health the player can choose to knock it out. If the player continues to attack it and makes it health reach 0, the animal simply dies as it now does. Knocking out would have a similar effect like tranquilising, it would leave the animal in a vulnerable state where it can be fed and tamed easily. + +These options of **Feed**, **Pet**, **Knock Out**, **Poison** (selectively enabled) can be displayed in a radial menu that appears on `E` click on an animal. The radial menu can have a circular progressbar outside that also shows the taming progress. + +Since methods like knocking out or hurting an animal before attempting to tame it seems odd. It can be made possible that the animal remembers only the player which hurt it. This would allow any other player (or even the same player in disguise) to befriend or tame the animal. Such an approach would be necessary only for hostile and aggressive animals and might also bring into picture multiplayer taming. + +### Animal Utilities +1. **Mount for travel**- Some animals can be chosen as a mount to ride on and for fast travel. Animals would have different speeds, jump heights, stamina etc. Some animals would be suitable for short distance while others for long commutes. Some animals would be stronger than others making them a safer choice of travel. Additionally, some animals may be faster in the day and some faster at night. +2. **Carry load and inventory**- Most animals would have an inventory of their own that can be used for carrying goods around. +3. **Mining**- Animals can dig through (with various speeds and capacities) and collect ores and minerals present inside the crust. +4. **Food supply**- Animals can give eggs or milk that can be used as food. +5. **Wood and stone gatherers**- Some animals could fell trees and collect wood from their barks. Others could simply go around collecting stone, making construction easier. +6. **Specialised gatherers**- Some animals could be gatherers for specific items like berries, a specific fruit etc. +7. **Organic Polymer Producer** - Some animals can be tamed (or killed) to obtain fibre. +8. **Food hunter**- Tamed carnivores can be trusted to hunt other animals and bring meat. Tamed herbivores can be used to get raw products from trees. +9. **Guard animals**- Animals can be instructed to guard a location and attack all other players/animals that try to enter. +10. **Combat**- Different animals can have different special combat abilities that protect the player from attackers. +11. **Sea creatures**- Sea creatures can be used as a mount to cross oceans or for fishing. Some sea creatures can share their reserve of oxygen increasing the player's breathing capacity. Some sea creatures could be used to collect resources at the bottom of the sea like oil. +12. **Companion**- An animal that simply follows you around so that you never feel lonely. + +A nice forum post by [Vaibhav Bajaj](http://forum.terasology.org/members/vaibhav-bajaj.1985/), last year's GCI student, talks about creating a Pets module and talks about taming at great detail [here](http://forum.terasology.org/threads/new-module-pets.1742/). +Implementing taming in game is still a bonus item, probably something I'd get back to after I've checked off the main items. Next week should involve a start to all the puzzle work and making of the new gameplay module. \ No newline at end of file diff --git a/_posts/2017-05-30-GSoC-week4.markdown b/_posts/2017-05-30-GSoC-week4.markdown new file mode 100644 index 0000000..fbccf81 --- /dev/null +++ b/_posts/2017-05-30-GSoC-week4.markdown @@ -0,0 +1,128 @@ +--- +layout: post +title: "GSoC Week 4: Integrating Journal" +date: 2017-05-30 +comments: true +tags: +- open source +- MovingBlocks +- Terasology +- GSoC +--- + + + + + + +The past week involved creating the new module for my exploration world and getting sarted with it. + +# What have I been up to? + +## Creating the Lost module + +The Lost module is the new gameplay module that I have created and would be working on for the next two months. I'm still working on writing some logs but the general idea for the [lore](https://docs.google.com/document/d/1GVmJEV2KKjqgxjtVR-_Lh7QsvRzQbfxg9qeHjimIbPg/edit?usp=sharing) is complete. In short the story is centered around an intergalactic explorer who while exploring the vast world of Terasology, gets stranded. The wormhole creator that allows him to travel through space becomes dysfunctional. Fornlorn with no way to return to his home planet, he starts exploring the planet, trying to survive on what may become the last planet he would ever set his foot on. + +## Integrating Journal +A key part of the new explorationn world would be a journal that links several things. The main purpose of the Journal would be to serve as a secondary memory for the player. I plan to use the Journal in several ways- + +1. Exploration logs that would be generated as time passes or when an event occurs. Like when the player first spots a deer or finds a treasure. +2. New recipes would show up when the player pick a new item. Like picking up a stone would create an entry with the recipe for hammer. +3. The journal would be integrated with books. Whenever you open an important book, the key parts of the book would be stored in the journal. +4. Integrations with content modules like WoodCrafting, StoneCrafting (earlier WoodAndStone), CopperAndBronze, Alchemy, EquipmentSmithing, Equipment, Cooking and SimpleFarming. These would essentially be tutorials to help the player. Essentially recipes that show up, guides about more involved process like different quality of ingredients resulting in different final products. + +As of now the Journal has only been integrated with item pick up events and an initial on-spawn event that sends the first journal entry. + +## Improvements in Journal + +The [Journal module](https://github.com/Terasology/Journal) was left pretty much untouched since [MarcinSc](https://github.com/MarcinSc) had created. The Journal module looks like so- + +{: .center} +![WoodAndStone Journal]({{ site.baseurl }}/img/WaSJournal.jpg "WoodAndStone Journal") + +It has a left panel for different chapters and each chapter has its own entries. This handles categorisation pretty well, making it easier for the user to access specific entries and saving a long scroll. + +I've added another enhancement which now makes the Journal more interactive. Earlier there was just a notification that would pop up when a new Journal Entry was added. However, it wouldn't be highlighted in any way in the Journal. With the [latest PR](https://github.com/Terasology/Journal/pull/3/) merged, now the unread Journal entries appear highlightedin yellow, until the chapter they belong to gets opened once. + +{: .center} +![Unread Journal]({{ site.baseurl }}/img/UnreadJournal.jpg "Unread Journal") + +In the image above, Exploration Log #111 is a "read" entry while Exploration Log #112 is a new/"unread" entry. + +
+ +
+ +***Roadblock:*** There was a problem with the Journal module though, the first journal entry that was required to be sent only once when the player was spawned was resent every time the player respawned. This happened because the `onPlayerSpawnedEvent` was sent to the Player entity even on respawn. +A bigger problem was that whatever entries that the player had in his journal would all disappear when the player respawned. This happened because the player entity in the game was completely destroyed when the player died. In the process all components attached to the player were stripped and destroyed too. + +This was what I dealt with for the larger part of last week. + +## Saving the player entity from destruction +All existing systems relied on the player entity to be totally destroyed (and stripped of all components) when the player dies in game. This however wasn't a nice approach, as the player entity carried a lot of data that potentially could be preserved or dealt with a better way even on death. + +I felt this problem for the first time when I realised that my player would lose all it's journal entries on death. However there are many other cases which require the player entity and it's components to not be totally destroyed. + +#### The need +1. A player's inventory is always lost on death. It just disappears. With the player entity now being preserved, the player simply gets to keep its inventory after respawn. However, if needed a system can easily be added to allow items from inventory to drop when a player dies (even probabilistically). +2. Many other components would be better off having persisted than being destroyed at death. For eg. the EventualSkills module makes learning and gaining skills possible. All the skills a player has just would disappear if the player entity is completely destroyed, which might be undesirable. +3. There was no separate event that would be sent upon respawning. Now there is an additional `onPlayerRespawnedEvent` that can be used for this purpose. The `onPlayerSpawnedEvent` is simply an event that only gets fired once when the player enters a world for the first time. + +[This PR](https://github.com/MovingBlocks/Terasology/pull/2958) makes the said change. It adds the **OnPlayerRespawnedEvent, PlayerDeathEvent, AliveCharacterComponent, PlayerCharacterComponent.** + +
+ +#### What happens now + +A character lives. It has the AliveComponent. +It dies. +A `BeforeDestroyEvent` handler receives all entities having `AliveCharacterComponent` + ++ If the entity also has a `PlayerCharacterComponent`, the event is consumed to prevent destruction. The `AliveCharacterComponent` is stripped off adn a `PlayerDeathEvent` sent along with `DeathEvent` ++ Else just a `DeathEvent` sent and the `AliveCharacterComponent` stripped off. +DeathScreen launches on `PlayerDeathEvent` and sends the `RespawnRequestEvent`. +`RespawnRequestEvent` is received by the `PlayerSystem`. +`PlayerSystem` then respawns player, sets the location for `clientEntity` to spawn location. Sends `OnPlayerRespawnedEvent`. + +Components that need to be removed on death are removed by receiving the `PlayerDeathEvent`. +Components that need to be reset are done by receiving the `OnPlayerRespawnedEvent`. + + +Next week would see more work on the exploration module. I need to experiment with Structural Templates and see what's the best way to spawn structures in different places. \ No newline at end of file diff --git a/_posts/2017-06-06-GSoC-week5.markdown b/_posts/2017-06-06-GSoC-week5.markdown new file mode 100644 index 0000000..788c624 --- /dev/null +++ b/_posts/2017-06-06-GSoC-week5.markdown @@ -0,0 +1,152 @@ +--- +layout: post +title: "GSoC Week 5: The Swing King" +date: 2017-06-06 +comments: true +tags: +- open source +- MovingBlocks +- Terasology +- GSoC +--- + + + + + + +Last week involved a lot of discussions. The plan for the next two months is now a lot clearer. Here's a quick fun video that should explain the title of this blog post. + +
+ +
+ +# What have I been upto? + +## WoodAndStoneCraftingJournal +With last week's journal improvements, it was time to put the journal to some good use. A good technique to do this is to use the main Gamplay module for all story/lore related journal entries. However for most of the content related entries like crafting tutorials or cooking recipes, the best way to go is to create Journal extension modules. These extension modules would connect each content module to the Journal module. Essentially, the Journal extension module would house the Journal entries related to that content module which can easily be reused by multiple gameplay modules. + +I went ahead and created the first Journal Extension module as a proof of concept with only about 8 entries to demonstrate how it would work. The [WoodAndStoneCraftingJournal](https://github.com/Terasology/WoodAndStoneCraftingJournal/) has a dependency on [WoodCrafting](https://github.com/Terasology/WoodCrafting), [StoneCrafting](https://github.com/Terasology/StoneCrafting) and [Journal](https://github.com/Terasology/Journal). It contains the journal entries pertaining to both WoodCrafting and StoneCrafting (since both are a little related). + +## Where are the puzzles? +A major chunk of my last two month work consists of making Puzzles and adding them to my exploration centered gameplay module. +After some discussion with flo about cata's project on scenarios, I realised that it would be redundant to spend time working on mechanisms for action/event triggered changes. Since the Scenarios project would be focused on dealing with this, it would be a better idea that I aim towards making puzzle elements like traps, portals and other dangerous pieces. + +### Adventure Assets +With this new direction to work on, I've created a [list of potential items](https://docs.google.com/document/d/1Go425IJSUEI2baXX0PkSamLIHZf7qYOA7emu6qH7PvE/edit?usp=sharing) that I could work on. Also a new module called [AdventureAssets](https://github.com/Terasology/AdventureAssets/) has been created to house such elements. + +The idea now, is that I would create various puzzle elements and combine them together in a few different settings. I would create structure templates for these puzzles akin to the dungeons in GooeysQuests. This would allow me to place these puzzles in my exploration world manually by using a structure spawner. I plan to place these puzzles in the world manually and share the saved file which could be played with. + +
+
+ Why do I want to use Structure Templates?
+
+ Structure Templates allows me to create a puzzle setting or essentially a puzzle map, as a prefab. I can arrange the elements in the manner I want and also edit the map later. In theory, I could create the puzzles by hand in the saved world that I plan to share, without using Structure Templates at all. However using Structure Templates allows me to concentrate on making the puzzles one by one without worrying about how I would place them in the world. Once I have the Structure Templates for the puzzles ready I can place them however I want in the world. Also, this allows the same created puzzle to be reused multiple times. An existing puzzle can be extended or modified slightly to create a new one. Further, if a puzzle consists of multiple rooms of the same type, a single room created using ST can be easily reused to create more. +
+
+ +## The Swinging Blade + +
+ +The first item I decided to work on was the Swinging Blade. The setup consists of a huge blade that swings to and fro from one edge of the room to the other. This would serve as on obstacle and coming in contact with the blade would deal damage to the player. + +I started working with a crude swinging blade model made by flo. + +{: .center} +![crudeSB]({{ site.baseurl }}/img/crudeSB.png "crude SB"){:style="max-height: 400px;"} + +### Animating the blade +I tried to make the blade move by linearly varying the `pitch` (as in rotation's `yaw, pitch and roll`) of the entity. The GIF below shows this linear movement. This motion was later changed to an angular harmonic function, which factors in a time period (in seconds), an amplitude (in radians) and an offset/phase difference (in radians) which altogether looks like `theta = Acos((2*pi/T)*t + phi)`. + +{: .center} +![crudeSB]({{ site.baseurl }}/img/crudeSwingingBlade.gif "crude SB") + +### Alignment and orientation +The swinging blade was misaligned and I wanted it to rotate in a direction purpendicular to it's current rotation. Soon I realised that I had no control on the orientaion of the Swinging Blade entity that was being spawned by the Structure Template. I could choose the position but I couldn't change the orientation and rotation. This is because the Structure Template module allows you to spawn the structure anywhere in the world, regardless of the orientation in which they were created. Meaning, a structure that faced North could be spawned in a manner that it now faces East. All contents of the structure should undergo a similar change in their orientation too. But the entities didn't. Till now, it wasn't a problem as the only things being spawned were the GooeysQuests' skeletons. Their orientation didn't matter as they were live entities that would come running after you for your life. + +
+ +[This PR](https://github.com/Terasology/StructureTemplates/pull/15) adds the rotational control to spawning entities while using the `SpawnPrefabsComponent` in the Structure Templates module. + +
+
+ Dealing with Quaternions (Quat4f)
+
+ I hadn't dealt with quaternions before and the above fix in the PR wasn't as straightforward to me as it looks like. I didn't really want to spend too much time learning how Quaternions work to make a simple change. I knew how the yaw, pitch and roll system worked and all I needed was to change the yaw value by a mutiple of 90 degree depending on the orientation in which the room was spawned. After a few attempts of Googling and ending up on wikipedia pages that deal with rigorous math to show how Quaternions work I was almost ready to give up. It was then that I bumped into this blog post that made me understand and appreciate Quaternions. Soon after I found a forum answer that gave me a good idea on how to solve my problem. +
+
+ +### New model and texture + +Soon after I asked Quaternius to make a better model for the swinging blade and one thing led to another. Not before long, we had a full nice looking model ready with texture. + +{: .center} +**Inspiration** +![SB1]({{ site.baseurl }}/img/SB1.jpeg "SB1"){:style="width: 70%;"} + +{: .center} +**Model imported** +![SB2]({{ site.baseurl }}/img/SB2.jpg "SB2"){:style="width: 70%;"} + +{: .center} +**Texture mapped** +![SB3]({{ site.baseurl }}/img/SB3.png "SB3"){:style="width: 70%; max-height: 500px;"} + +{: .center} +**Final model imported** +![SB4]({{ site.baseurl }}/img/SB4.jpg "SB4"){:style="width: 70%;"} + +### Making it hurt + +I had a fine looking swinging blade, but it didn't hurt yet. I could pass through it like silk. +#### Adding Colliders +First step was to make the entity a rigid body and add box shape colliders. Since the shape of the entity was not so simple, I had to create two different entities- one for the blade and one for the rod. +#### Adding the DoDamageEvent +Since the blade was the part which would hurt, a `DamagePlayerComponent` was added to the blade to detect collisions with the player and trigger a `DoDamageEvent`. However, simply sending a `DoDamageEvent` would kill the player in no time as however small the damage being sent, being in contact with the blade even for a second would trigger the `OnCollide` method several times to result in death. +#### Sending a CharacterImpulse +The solution to this was sending a `CharacterImpulseEvent` to the player as well, in a direction outward from the blade. This sends the player to a relatively safer zone while also dealing some damage. + +### Multiplayer ready? + +The swinging blade is not yet multiplayer ready. There are quite a few issues on dealing with the Swinging Blade in multiplayer. The movement prediction on the server side deals with the `CharacterImpulseEvent` which makes the damaging systems function very differently even if there is a little lag. Often the player experiences too many impulses in a short time frame that end up killing him alone, even without the `DoDamageEvent` being sent. + +The PR which deals with the entire work on the swinging blade is [here](https://github.com/Terasology/AdventureAssets/pull/2/). It is still in progress with only the task of making it work in multiplayer remaining outstanding. + + +Up for next week should be more work on puzzles, a few more interesting traps and hopefully multiplayer fixes. \ No newline at end of file diff --git a/_posts/2017-06-12-GSoC-week6.markdown b/_posts/2017-06-12-GSoC-week6.markdown new file mode 100644 index 0000000..68e3f50 --- /dev/null +++ b/_posts/2017-06-12-GSoC-week6.markdown @@ -0,0 +1,152 @@ +--- +layout: post +title: "GSoC Week 6: Setting the trap" +date: 2017-06-12 +comments: true +tags: +- open source +- MovingBlocks +- Terasology +- GSoC +--- + + + + + + +With the swinging blade almost ready last week, this week involved a lot of focused efforts on making traps easy and intuitive to set up. + +# What have I been upto? + +## The Swinging Blade +Here's some more detail about the swinging blade I made last week. + +The Swinging Blade arrangement looks like this: + +{: .center} +![SBentities]({{ site.baseurl }}/img/swingingbladeentities.png "Swinging Blade Entities"){:style="max-height: 700px;"} + +There are 4 entities- A **root** entity, the **rod**, the **blade** and the **mesh** entity. The root entity **owns** all the other entities and has the **network component** which replicates it across all clients. Creation of the root entity triggers the creation of the other three entites. The rod and blade entity only exist on the server side and are loaded by the `SwingingBladeServerSystem` that is registered as `AUTHORITY`. The mesh entity exists only on the client side and is loaded by the `SwingingBladeClientSystem` that is registered as `CLIENT`. The rod and blade entities are simply rigid bodies. The blade, in addition has a `DamageComponent` that sends an impulse and deals damage to character entities. The mesh entity has the mesh and material which basically is the model exported from blender. The root entity is the one on which the rotation animations are made. The other entities have their location attached to the root entity, which makes them go through the rotations too. + + +## The Blade Runner +After I had made the swinging blade last week, I couldn't stop myself from creating a room full of swinging blades in series. I arranged the swinging blades in such a manner that there would be only one (or two) safe way past. The player has to time his sprint perfectly such that he gets past each blade safely. Interestingly, with the setup I had made manually, there was no safe way back. + +
+ +
+ +This brought me to the question, how can I generate such puzzles in which the swinging blades are so set that there are only few safe ways past. I had control over three parameters- the **amplitude** (maximum angle), the **time period** (time for one two and fro motion) and the **phase difference** (an angle to generate an offset). + +The motion of the swinging blade was much akin to that of a simple pendulum, following the equation- + +`theta = A * cos (w*t + phi)` +{: .center} +Where, +`theta:` is the angle, the rod makes with the vertical +`w:` is the angular velocity (`w = 2 * pi / timePeriod`) +`t:` is the game time at the given instant +`phi:` is the phase difference or offset + +{: .center} +![SBmath]({{ site.baseurl }}/img/SBmath.png "Swinging Blade Math"){:style="max-height: 500px;"} + +## Setting the trap- Creative Mode + +After the first trap- the Swinging Blade had been made, a major concern was how to make it easy and intuitive to set up traps in game. At the same time creating puzzles had to be made easy using Structure Templates. Also the editing of the trap settings, or removal of the trap had to be limited so that every player could not disble a trap and move past it. + +### The Trap Placeholder and Trap Configuration Tool +The first approach I had taken was to use a trap placeholder. This would be similar to the Structure Template Placeholder that is used to allow spawning of a new structure template when it is placed inside a structure template. This approach basically consisted of a trap placeholder that would allow for spawning any trap by selecting a trap in the dropdown menu of a UI Screen. After a trap is selected, it is automatically spawned. Mining the placeholder block would remove the trap from the world. + +The trap configuration tool is essentially an item that lets you edit the properties of a trap by aiming at the trap and interacting with the item (right-clicking). The trap configuration tool loads up a UI Screen populated with the properties of the targetted trap. The properties can then be edited and saved changes are immediately reflected in the world. + +Integrating this with Structural Templates meant that the trap placeholder blocks won't show up when the traps are spawned using a structure spawner. This would essentially be a way to prevent editing or even removal of traps by any player in game who doesn't have the trap configuration tool. + +Here are a few videos of how that looked like: + +
+ +
+
+
+ +
+ +There were several problems with this approach: + +1. Aiming might not work well in multiplayer. Since the targetted entity was usually the mesh, that existed only on the client side. +2. Multiple steps are necessary to place a trap. You first have to place the placeholder and then activate it and then select the trap then close that dialog select the tool for configuring it and use it to select the details. This makes setting up traps difficult for a layman. +3. Traps can’t be replaced as there is no item that remembers the trap settings when the trap is mined. Destroying a trap placeholder doesn't save the previously configured settings. +4. Requires Trap Configuration Tool for editing trap properties and removal. Difficult removal of traps if structure is mistakenly spawned a little off. +5. Inconsistent design. Some traps (spawned by structure spawners) don't have an associated trap placeholder block, while others do. + +### The Root Block- a better approach + +
+ +The root block approach basically meant that each and every trap would have a unique origin block. For traps that are block based, for e.g. for a block with retracting blades that pop out of it, the origin block would be the trap itself. This block would be the owner to the root entity that has the Trap component. Here are a few features about the root block approach- + +1. Root block can have a unique look for each trap- different shape and block tiles. +2. Root block is the owner of the entity that controls the trap. +3. Root block upon interaction creates a UI screen that allows for modification of trap properties. +4. Mining a root block would destroy the trap and create a root block item. Placing the root block item again in the world would spawn the trap with the same properties before destruction. +5. With Structure Templates, the root blocks would still exist and would be dealt in a similar way as chests. This would make the traps appear consistent. + +The problem with this approach is that the root block might be unreachable or at distances that cannot be reached without cheats (`ghost`) like inside walls or up in the air. To allow for easier property changes, the entire mesh of the trap can be made a collider that the player can interact with. +One more problem is that the editing and removal of the trap (basically, interacting with the root block) has to be limited in some way so that player's in normal gameplay cannot make changes. These will be implemented soon. + +This is a huge step forward and it will make setting up traps easy and intuitive, even for a layman. The whole thing in game, looks like this: + +
+ +
+ +## Wipe-out +The next trap I'm trying to build is a bit complicated. The idea is to create a horizontal platform attached at the end of a rod that moves in circles. There would exist a pit of lava underneath. The objective of the player would be to time his jump to hop onto the platform and jump past to dodge obstacles that come in the way, to reach the other side. Fall, and the player would be incinerated in the lava pool. + +It would look something like this: + +{: .center} +![wipeout]({{ site.baseurl }}/img/wipeout.jpg "Wipe Out"){:style="max-width: 700px;"} + +Achieving this would be a challenge and I'll need to get started with the physics engine. + +Next week should involve a lot more tinkering with the Physics Engine and trying to make new puzzles since the base architecture is now decided. diff --git a/_posts/2017-06-20-GSoC-week7.markdown b/_posts/2017-06-20-GSoC-week7.markdown new file mode 100644 index 0000000..d2db023 --- /dev/null +++ b/_posts/2017-06-20-GSoC-week7.markdown @@ -0,0 +1,119 @@ +--- +layout: post +title: "GSoC Week 7: The Wipe Out and the Fireball Launcher" +date: 2017-06-20 +comments: true +tags: +- open source +- MovingBlocks +- Terasology +- GSoC +--- + + + + + + +After having set up the base to create traps last week, this week involved creation of two new traps. + +# What have I been upto? + +## The Wipe Out + +
+ +This trap is inspired from the shows Takeshi's Castle and Wipe Out. The setup consists of a platform attached to a rod pivoted at a root block and rotated around in horizontal circles. The trap can be configured by adjusting these parameters: + +**Time Period**: The time taken to complete a whole circle. +**Offset**: Two add a phase difference between two otherwise identical wipe out traps. +**Sense**: Sense of rotation. (clockwise or anti-clockwise) +**Rotation**: The wipe out is conventionally meant to be rotated horizontally, but the pitch can be changed to give it a different look. + +Here's a video showing how the Wipe Out looks and how it's properties can be altered: +
+ +
+ +The wipe out has a very similar architecture as the swinging blade: +There are 4 entities- A **root** entity, the **rod**, the **surfboard** and the **mesh** entity. The root entity **owns** all the other entities and has the **network component** which replicates it across all clients. Creation of the root entity triggers the creation of the other three entites. The rod and surfboard entity only exist on the server side and are loaded by the `WipeOutServerSystem` that is registered as `AUTHORITY`. The mesh entity exists only on the client side and is loaded by the `WipeOutClientSystem` that is registered as `CLIENT`. The rod and surfboard entities are simply rigid bodies. The mesh entity has the mesh and material which basically is the model exported from blender. The root entity is the one on which the rotation animations are made. The other entities have their location attached to the root entity, which makes them go through the rotations too. + + +## The Wipe Out Lava Room +After I completed the trap, I went ahead and created a room consisting of two wipe outs with a pit of lava underneath and a treasure chest on the far end of the room. I arranged the wipe outs in such a manner that there would be one moment when they would align, allowing the player to jump from one to the next. The player has to time his jump perfectly such that he gets onto each surfboard, or else the player would fall into the pit of lava. + +
+ +
+ +The motion of the wipe out is pretty straight forward and follows the equation- + +`theta = ((t + offset) % timePeriod)*(2 * Math.PI / timePeriod)* direction` +{: .center} +Where, +`theta:` is the angle, the rod makes with the vertical +`timePeriod:` is the time taken for one rotation +`direction:` +1 (anti-clockwise) or -1 (clockwise) + +{: .center} +![WipeOutMath]({{ site.baseurl }}/img/wipeOutMath.PNG "Wipe Out Math"){:style="max-height: 500px;"} + +## The Fireball Launcher + +
+ +The Fireball Launcher was the next trap I worked on. With some help from [niksoc](https://github.com/niksoc/), I was able to restructure the Projectile module. This made shooting fireballs as easy as sending a `FireProjectileEvent` on the created fireball entity. + +The fireball launcher trap also has a few properties that allow for custom configurations: + +**Time Period**: Time interval between two consecutive fireball shots. +**Offset**: Time offset between two fireball launchers that have the same time period. +**Max Distance**: Maximum distance after which the fireball dies. +**Damage Amount**: Total collective damage the fireball can inflict. Acts as *health* for the fireball. The fireball is destroyed after it has inflicted a total damage equal to its health, or unitl it comes across an indestructible entity. +**Direction**: Direction in vector form (x, y and z) towards which the fireball is launched. + +
+ +Here is a video showing how the fireball launcher works: +
+ +
+ +The next item I'm working on is the revival stone which is an artifact that when activated, allows the player to respawn at its location. Also I'm going to get started with using some particle effects. That would come in handy for the revival stone and the fireball. diff --git a/_posts/2017-06-27-GSoC-week8.markdown b/_posts/2017-06-27-GSoC-week8.markdown new file mode 100644 index 0000000..9874502 --- /dev/null +++ b/_posts/2017-06-27-GSoC-week8.markdown @@ -0,0 +1,164 @@ +--- +layout: post +title: "GSoC Week 8: The Revival stone and the Password Door" +date: 2017-06-27 +comments: true +tags: +- open source +- MovingBlocks +- Terasology +- GSoC +--- + + + + + + +Week 8 has come to an end and quite a few of the proposal targets have been met. The last two months have been phenomenal, to say the least. Since I had started work around 1 month in advance, I would be completing two months by the time the first evaluation completes in a few days. + +# What have I been upto? +This week saw more work on traps, two items in particular- the **Revival Stone** (to be named the **Altar of Resurrection**) and a **Password locked door** . + +## Revival Stone + +
+ +### Concept +With all the previous traps created (swinging blade, wipe out over lava, fireball launcher) being dangerous in nature, there was a definite need for a checkpoint that allows the player to respawn just before the trap. The revival stone does exactly this. A statue of an angel serves as a checkpoint that can be activated by the player. Upon activation, the angel statue lights up and the orb held by the angel starts glowing. At a time, a player can have only one checkpoint activated. Upon death, the player respawns at the last and only activated checkpoint. + +### Model +The idea for the design of the model was very intricate. Unable to catch [quaternius](https://github.com/quaternius) online, I went forward with a placeholder model for the time being, which looked like this- + +{: .center} +![angelOld]({{ site.baseurl }}/img/angelOld.jpg "Old Angel Model"){:tyle="max-height: 500px;"} + +Soon after, [quaternius](https://github.com/quaternius) was back and ready to do some Blender magic. This was also probably the most elegant and beautiful work of his that has been added to the game. + +{: .center} +![angelNew]({{ site.baseurl }}/img/angelNew.jpg "New Angel Model"){:style="max-height: 500px;"} + +The initial model he made was a flat one (left), but it was soon changed to a smooth version (right) which looked better. + +{: .center} +![angelFlatAndSmooth]({{ site.baseurl }}/img/angelFlatAndSmooth.jpg "Angel Flat And Smooth"){:style="max-height: 500px;"} + +The model is completely static and has no built-in animations. The same model is intelligently used for both the active and inactive states of the angel statue using just a texture change. + +
+
+ How does the texture change happen?
+
+Every model is added to the game by first exporting the model to a .obj file and then creating an associated prefab for it. The associated prefab needs to have a MeshComponent that describes the mesh and the material. The mesh points to the .obj file exported using Blender. The material, on the other hand, is the texture (png image) that is UV mapped to the model. +
+The two states of the revival stone model only differ in texture. This is implemented using a simple material (texture) switch when the player interacts with the statue to activate it. As far as I know, this is the first usage of such a material switch in the game and it can definitely be used for more models to depict a change in state. +
+
+ +The two different textures being used only differ slightly- the texture for the active state has a brighter color for the angel's statue and an orange color for the orb to make it appear lit. + +{: .center} +![angelActiveAndInactive]({{ site.baseurl }}/img/angelActiveAndInactive.jpg "angelActiveAndInactive"){:style="max-height: 500px;"} + +### Respawn mechanism +After a player dies a Death Screen is displayed. Upon clicking the "Respawn" button a `RespawnRequestEvent` is sent and the spawn location is found using the World Generator information and the player respawn happens. This whole process was broken down using [this Engine PR](https://github.com/MovingBlocks/Terasology/pull/2983) allowing other systems to alter a player's respawn location. + +
+
+ How is the respawn mechanism implemented?
+
+The RespawnRequestEvent that is sent when the "Respawn" button is clicked on the Death Screen was being used to modify the LocationComponent of the player entity and line it up for respawn. +
+This process has now been broken into multiple parts. A method receives the RespawnRequestEvent with a "CRITICAL" priority and sets the respawn location as per the World Generator information. Another method in the PlayerSystem receives the RespawnRequestEvent with a "TRIVIAL" priority and initiates the whole respawn process for the player entity. +
+Any other system present in any module can receive the RespawnRequestEvent with a priority between TRIVIAL and CRITICAL (both exclusive) and make a change to the LocationComponent of the player entity to allow for a custom respawn location. +
+
+ +### Particle Effects +This was the first time I fiddled around with any particle effects of my own. The particle effects consisted of a bunch of blue mystical particles that rise from the base of the statue towards the top, upon activation. I also reused the smoke explosion particle effect from the core module along with it, to give an added effect. The whole thing in action looks like this- + +{: .center} +![angelParticleEffects]({{ site.baseurl }}/img/angelParticleEffects.gif "angelParticleEffects"){:style="max-height: 500px;"} + +
+
+ How to create such particle effects?
+
+To create the above kind of particle effects I had to create a prefab for the particle effects and then build and spawn this as an entity. The linked gist has a lot of parameters as components that allow me precise and specific control over the particles. +
+For instance- the positionRangeGenerator allows me to ensure that all particles spawn at the bottom of the statue and the velocityRangeGenerator allows me to make all the particles ascend upwards. +
+
+ +Upon deactivation, only the smoke effect is played. + +### Lighting +In addition to the texture change, there was a need to add lighting for the orb to appear as glowing. This is done by creating a simple orb entity which spawns near the location of the orb and has a `LightComponent` attached. Using the light component the two states of the revival stone appear as such at night- + +{: .center} +![angelLightAndDark]({{ site.baseurl }}/img/angelLightAndDark.jpg "angelLightAndDark"){:style="max-height: 500px;"} + +The PR for the revival stone is not complete yet, as some fixes are still required to make it multiplayer compatible. [This PR](https://github.com/Terasology/AdventureAssets/pull/11) contains all the progress so far. A working video with the placeholder model completely functioning in Single Player follows- + +
+ +
+ +## Password Locked Door + +
+ +There already existed a door in the Core module that allows for simple opening and closing with player interactions. It has a nice system that takes care of placing the two blocks long door in the world, with a nice texture and cool sound effects. I decided to reuse all of this to create a door that would require a password to unlock. + +The password door essentially extends the door from the core module. It uses the existing systems in Core for the basic features and simply overrides over the functionality that needs to change by receiving the respective events with a higher priority. For instance, the ActivateEvent handler in the `PasswordDoorSystem` receives (and consumes) the ActivateEvent with a higher priority than Core's `DoorSystem`. This allows the display of a UI Screen that lets the player enter the password to unlock the door. + +### Features: +- The passwordDoor on placement opens a UI Screen for the player to enter the details for it. It takes input for a **Title**, **Message** and the **Password**. Upon entering all the fields and hitting "Ok", the door is placed in the world. +- Upon interacting with an open door, the door close. +- Upon interacting with a closed door, a UI Screen is displayed, showing the Title and Message, which can serve as a clue for the password. An empty text box exists for the user to input the password. If the entered password is wrong, a "Invalid Password!" text appears in red just above the text box. Entering the correct password closes the UI Screen and opens the door. +- The password door can be mined to get the password door as an item. This can be placed again in the world, cycling to the top step. + +Note: A password door can be made indestructible in an area, for the purpose of being used in traps and puzzles. + +Here's a full video showing the Password Door in action: +
+ +
+ +# What's next? +For next week, I would spend most of my time working on trying to make most of the created traps compatible in Multiplayer mode so that they can be tested out in the Multiplayer play-test scheduled to happen this Saturday- the first of July. \ No newline at end of file diff --git a/_posts/2017-07-04-GSoC-week9.markdown b/_posts/2017-07-04-GSoC-week9.markdown new file mode 100644 index 0000000..d8fb2f1 --- /dev/null +++ b/_posts/2017-07-04-GSoC-week9.markdown @@ -0,0 +1,171 @@ +--- +layout: post +title: "GSoC Week 9: A fair share of Multiplayer" +date: 2017-07-04 +comments: true +tags: +- open source +- MovingBlocks +- Terasology +- GSoC +--- + + + + + + +# What have I been upto? +The Revival Stone created last week has been polished and is now renamed as the Altar Of Resurrection. All the existing traps and adventure items- Swinging Blade, Wipe Out, Fireball Launcher, Altar of Resurrection and Password Door have been made multiplayer ready. + +## Altar of Resurrection + +
+ +With most of the work been done last week, this week simply saw a finishing touch and some other minor additions. + +### Floating Text +Instead of sending a chat message to describe the state of the Altar of Resurrection, a better idea was to have a floating text that appears when the angel statue is targeted. The floating text now looks like- + +{: .center} +![angelFloatingText]({{ site.baseurl }}/img/angelFloatingText.jpg "Floating Text"){:style="max-height: 500px;"} + +### New Particle Effects + +The blue opaque Particle Effects have been switched to transparent orange ones, that match with the theme of the angel. The orange color goes along with the color of the orb. + +{: .center} +![angelNewPE]({{ site.baseurl }}/img/angelNewPE.jpg "New Particle Effects"){:style="max-height: 500px;"} + +
+
+ How to create transparent particle effects?
+
+Transparent particled effects only require the texture file for the effect to have the required transparecy. To make such a texture file I used the software Paint.NET. A simple way to do this is- +
    +
  • Open a new file in Paint.NET.
  • +
  • Resize the canvas to the desired size (e.g. 32x32).
  • +
  • Select all (Ctrl + A) and delete. This would leave you with a empty transparent canvas.
  • +
  • Select the Shapes tool and select Ellipse.
  • +
  • In the shape styles menu select "Draw Filled Shape".
  • +
  • Select the desired color for fill.
  • +
  • From the color toolbar, select "More >>" and adjust the "Opacity- Alpha" value to make the color transparent. For e.g. if you need 50% transparency, set Opacity to 128.
  • +
  • Drag the cursor to draw the ellipse on the canvas. The image can be then resized and adjusted. The color can also be adjusted later to see a live preview.
  • +
+The above should give you an image like this. +
+
+ +After all this, the final Alar of Resurrection looks like this- + +
+ +
+ +## Multiplayer Fixes + +
+ +
+ +
+ +
+ +
+ +A large amount of last week went into making the already created traps functional in multiplayer. Here is a brief collection of the issues I faced and how I solved them. Please read through the wiki page for [Entities, Components and Events on the Network](https://github.com/MovingBlocks/Terasology/wiki/Entities%2C-Components-and-Events-on-the-Network) if you already haven't. + +### Entities on the network +An entity on the network (one that has a Network Component) exists both on the server and the client. This poses a problem if you are depending on a component addition/activation event to perform an activity. For eg- For the wipe out trap, the mesh for the model was to be created only on the client side. This was supposed to happen on the OnActivatedComponent event for the `components = {WipeOutComponent, BlockComponent}` which would trigger when the WipeOutRoot block is placed in the world. However, this event gets triggered twice, on the Client System once for the server entity and once for the client side entity. This creates two meshes- one that stays stationary and the other that rotates as expected. Note that the Authority/Server system only has the event handled once since it gets triggered only for the server entity. + +As a workaround to fix this, I received the event on the Authority system with a higher priority. The Authority system event handler would then make changes to the server entity's WipeOutComponent (add the rod and surfboard collider entities to the childrenEntities list). I would then receive the event on the Client system and recognize the server entity by these changes that have been made. The client entity would not have the changes made by the Authority system (the childrenEntities list would be empty). The Client System event handler for the OnComponentActivated event would now run only for the server entity and the extra static mesh would no longer be created. + +The [Server System event handler](https://github.com/Terasology/AdventureAssets/blob/master/src/main/java/org/terasology/adventureassets/traps/wipeout/WipeOutServerSystem.java#L114-L134) looks like- +{% highlight java %} +@ReceiveEvent(priority = EventPriority.PRIORITY_HIGH, components = {WipeOutComponent.class, BlockComponent.class}) +public void onWipeOutActivated(OnActivatedComponent event, EntityRef entity, WipeOutComponent wipeOutComponent) { +// Create server entities for rod and surfboard +wipeOutComponent.childrenEntities.add(rod); +wipeOutComponent.childrenEntities.add(surfboard); +} +{% endhighlight %} + +The [Client System event handler](https://github.com/Terasology/AdventureAssets/blob/master/src/main/java/org/terasology/adventureassets/traps/wipeout/WipeOutClientSystem.java#L66-L80) looks like- +{% highlight java %} +@ReceiveEvent(components = {WipeOutComponent.class, BlockComponent.class}) +public void onWipeOutActivated(OnActivatedComponent event, EntityRef entity, WipeOutComponent wipeOutComponent) { +// So that only the relevant server entity is operated on. +if (!wipeOutComponent.childrenEntities.isEmpty()) { +// Create mesh entity on client side +} +} +{% endhighlight %} + +### Saving Component of an Entity +Before going into the specifics of the issue I faced, let's discuss how the **@Replicate** annotation works. + +Straight from the wiki- +> `@Replicate` is an annotation used to mark types or fields to indicate that these types or fields should be replicated between the server and the client. In other words, when changes are made to these types or fields on the server, these changes will be reflected in the clients as well. + +By default, the FieldReplicate type is set to `SERVER_TO_CLIENT`. This basically means that whatever the state of the entity on the server, such will be replicated to the entity on the client side. Changing a component on the client entity would not be reflected on the server entity. + +Since all of the traps I made were on the network (possessed a NetworkComponent and had entities on both the client side and the server side), altering their settings required a change in one of the components. For instance, let's consider the Fireball Launcher. On interaction with the Fireball Launcher block, the player sees a Settings screen where he can alter the properties for that Fireball Launcher. On hitting "Ok" on the Settings window, the component change happens from the FireballSettingsScreen class which is launched on the client side and instantiated with the client side Fireball Launcher Root entity. The component change thus happens only on the client entity and isn't taken into account by the server entity. + +To solve this, I created a new event- `SetFireballLauncherEvent`. This event basically carries all the new values that need to be applied to the `FireballLauncherComponent`. The event is then received on the Authority/Server system which then makes the change on the server side Fireball Launcher entity. This change is then reflected on the client side Fireball Launcher entities as they replicate the changes made to the server entity. The event can however not be sent to the FireballLauncherRoot entity from the FireballSettingsScreen class. This is because the FireballLauncherRoot entity that the player interacts with, is the client side entity. Making the change on the client side entity would not make the change register on the associated server entity. Instead, the event can be sent to the local player's character or client entity with the FireballLauncherRoot entity as a parameter. + +### How does the chest work? +All these issues I faced, made me wonder how the chest entity works. The chest opens an Inventory screen on interaction. It has an InventoryComponent and any change made by one client is reflected on any other client. + +The chest entity has the network component and has **@Replicate** on all relevant component fields to ensure that the state is replicated from **SERVER_TO_CLIENT**. Again, whatever the state of the server entity, so will be replicated on the client. +Since the entity has a Network Component, it exists on both the client side and the server side. +Consider a client opening the chest (by interaction) and adding a sand block to it (the inventory of the chest). This action is performed on the local entity (the one on that client's side). So simply saving the new InventoryComponent (with an added sand block) on the client side in the client system won't work since all client chest entities replicate the state of the server entity, which remains unaltered. +To deal with this, the component change must happen on the server entity which can be accessed only at the Authority system. This can be made possible by sending an event that is received and handled by the Authority/Server system. +Note that the event cannot be sent to the client side chest entity (since the player interacts with the client side chest entity, not the one that exists on the server). However, this event can be sent to the player's character entity with the chest entity as a parameter of the event. The event can then be received and the server side chest entity can be saved with the new InventoryComponent. + +**Note:** Making a change to the client side entity can be done to register the change on the associated server entity. But this requires the entity to be owned by the player and the `FieldReplicateType` to be set to `OWNER_TO_SERVER_TO_CLIENT`. + +Citing from code- +`InventoryClientSystem` sends an event on the local player's client entity [here](https://github.com/MovingBlocks/Terasology/blob/43f05baf94be707d5e3743300759fb530cf67e0f/modules/Core/src/main/java/org/terasology/logic/inventory/InventoryClientSystem.java#L258-L258). +`InventoryAuthoritySystem` receives the event and does its thing [here](https://github.com/MovingBlocks/Terasology/blob/80702ce7751699d93467cc843dd4ac682edcf21b/modules/Core/src/main/java/org/terasology/logic/inventory/InventoryAuthoritySystem.java#L250-L250). + +Note that some of my approaches might be incorrect. I'm not a hundred percent sure about whether the above is the right way to deal with the issues. However, having had a glance at how the Inventory stuff is handled for the chest entity, I'm more or less convinced that it is the right way. + +# What's next? +Maybe a few more traps like a pressure plate and some more triggers like buttons and levers. The major part that's really left is to integrate all of what's made into a world and package it into the Lost module with the supporting Lore. \ No newline at end of file diff --git a/_posts/2017-07-05-github-jquery.markdown b/_posts/2017-07-05-github-jquery.markdown new file mode 100644 index 0000000..993299d --- /dev/null +++ b/_posts/2017-07-05-github-jquery.markdown @@ -0,0 +1,78 @@ +--- +layout: post +title: "Github Button jQuery Plugin" +date: 2017-07-05 +comments: true +tags: +- jQuery +- CSS +- HTML +--- + + + +Lately, I've created a lot of blog posts in which I've felt the need to link a Github Pull Request or an Issue. Creating a vanilla link in markdown is easy but not aesthetically appealing. I wanted a ribbon sort-of thing that would distinguish between issues and PRs. Unable to find something good online, I went ahead and created my own jQuery plugin. + +## How does it look? +Without further ado, this is how it looks like: + +This is an un-merged open PR. + +
+ +This is a merged PR. + +
+ +This is an open issue. + +
+ +This is a closed issue. + +
+ + +## How does it work? +Generating such a button only requires creating a div with the appropriate URL and it is super simple. Here's how the HTML for one button looks like- + +{% highlight html %} +
+{% endhighlight %} + +The plugin uses the [Github API](https://api.github.com/) to fetch details of the PR or the issue, like the date, status and the repository. +The color and the icon of the right side icon is changed depending on the state. The hyperlinks to the issue/PR and associated repository are created. +The icons that have been included belong to the [Github Octicon](https://octicons.github.com/) pack. The stylesheet for the icons is loaded directly by the plugin from [CDN](https://cdnjs.cloudflare.com/ajax/libs/octicons/4.4.0/font/octicons.css) and does not need to be included separately. + +This plugin is very minimal and can be easily customised to make it look different. The jQuery code resides in one file, while the CSS code lies in another file. + +### Responsive +Since, the plugin is tailor-made to fit my needs, I rely on a single [media query](https://www.w3schools.com/css/css_rwd_mediaqueries.asp) to adjust the font and width of the elements to suit a mobile device. This is a screenshot of how it looks on my phone- + +{: .center} +![githubButtonResponsive]({{ site.baseurl }}/img/githubButtonResponsive.jpg "Github Button Responsive"){:style="max-height: 800px;"} + +## Usage + +Here is the [FIDDLE](https://jsfiddle.net/2r10thcb/). +
+ +
+ +The fiddle consists of the CSS and the Javascript (jQuery) code. It only has jQuery added as an external library. Simply download the CSS code into `github-buttons.css` and jQuery code into `github-buttons.js` and include it as shown- + +{% highlight html %} + + + +{% endhighlight %} + +### For Jekyll: +This depends on the kind of setup you have. If you have a setup like [mine](https://github.com/nihal111/nihal111.github.io), you might have to create a `github-buttons.scss` file instead of the `github-buttons.css` file with the same CSS code. Place the scss file inside the `_sass` directory. The `main.css` file then needs to be updated with + +{% highlight css %} +@import + "github-buttons" +{% endhighlight %} + +That's all for now. Feel free to use and share this plugin. Cheers! \ No newline at end of file diff --git a/_posts/2017-07-31-GSoC-week10-11-12.markdown b/_posts/2017-07-31-GSoC-week10-11-12.markdown new file mode 100644 index 0000000..1bd6ea9 --- /dev/null +++ b/_posts/2017-07-31-GSoC-week10-11-12.markdown @@ -0,0 +1,285 @@ +--- +layout: post +title: "GSoC Week 10, 11 and 12: Lost" +date: 2017-07-31 +comments: true +tags: +- open source +- MovingBlocks +- Terasology +- GSoC +--- + + + + + + +This post breaks a long silence. Most of the work in the last three weeks has been discreet and low-key. Since all the elements were made ready, it was time to put it all together and package everything under one roof. A lot of work went into putting together the lore and making a good amount of riddles for a kind of treasure hunt in-game. Most of the reason for the confidentiality was to keep the spoilers at bay. I wanted folks from the community to try out the game without having any idea of what lies ahead. + +Before you proceed any further, I'd like to make it bold and clear that there lie **SPOILERS AHEAD**. I would highly recommend you give a shot to the game, as instructed below, before you move any further. + +## Instructions to run Lost: +1. Download [this](https://slack-files.com/T03G8SB1X-F6N474GS0-867f5f5289) Omega. +2. Extract the Omega. +3. Move the save folder called "Lost" inside `omega796/saves` to the save directory- +- in Windows, C:/Users/name/Saved Games/Terasology/ +- in Linux, /home/name/.local/share/terasology/saves/ + ***Alternatively***, you can run the game with the `-homedir` flag. +- in Windows, run the game from cmd using a command like: `Terasology.x64.exe -homedir` + or add the `-homedir` flag to the target field of the shortcut to the exe file. +- in Linux, modify the run_linux.sh script so that it has a `-homedir` flag at the end, like so: + `java -Xms128m -Xmx1536m -jar libs/Terasology.jar -homedir` +4. Launch the game using the script or the .exe file. +5. Select Singleplayer -> Lost and load the saved game. + +# What have I been upto? + +There's a good amount of stuff that happened in the three weeks, from making tricky riddles interspersed with lore to making new blocks and items along with crafting a new world. I'll try to narrate things in the order of occurence, although my hazy memory might make a few things non-linear. + +## Packaging the save game + +After a bit of discussion, it was clear that it would not be possible to deal with the accurate spawning of the puzzles and other structures I want in game at world generation time, at least within the time and scope of my GSoC project. An alternative idea that was proposed was to let the world gen take care of the terrain, flora and fauna, while the other tricky elements be added (or rather placed) in-game manually. After everything gets placed, the player is moved back to the spawn location with all things like Health, Hunger and Thirst reset. This results in a base save game, that acts as a gameplay template and can be loaded instead of creating a new game. This would also serve as a final product of my GSoC project, something that is easily playable and showcases almost everything I've worked on. + +## Lore and Plot + +After spending a good amount of time on thinking about the story and the character progress, I was able to come up with something. Here's what the overall plot looks like- + +{% highlight text %} +The player ends up on a desolate planet devoid of other intelligent beings. He opens up his journal to find that this was meant to be just another exploration survey of one of the potential life-supporting planets in the neighbouring galaxy. However, the wormhole that he created to get here has malfunctioned and closed, leaving him stranded with no communication whatsoever. The situation seems grim and his forlorn attempts to fire up the wormhole again fail terribly. Left with no option, he wanders around to have a look at the planet that might be the last he ever set foot on. Born a survivor, he's able to hunt for food, and build basic tools to keep himself alive. Soon after he starts exploring, the player finds structures that clearly represent signs of existence of intelligent life forms. He becomes careful. Fearing his own death by the hands of the natives, he builds a few tools to defend himself. Underneath one of the structures, he discovers a secret passage. Gathering courage he goes through it. He finds a puzzle that needs to be solved to reach a treasure which seems to be concealed from the unworthy. He finds a book in the treasure chests which reveals a few secrets but creates even more mysteries.. +".. before the machines tear us apart, it's crucial to save the technology we've created for the survivors to grow and fight back, to take back what's theirs. Most of our defences have been destroyed, our houses burned and whatever we've created is lost, but knowledge is something that doesn't die easily. If you've survived and found this book, what follows are the blueprints of the revolutionary technologies that we’ve created. To build some of these, you might require some artifacts scattered around the entire world..." +Soon he solves a few more and realises that he can actually find a way back home by using the early civilization's technology to create what is known as a catapult portal that throws you across in space time. He sets on a journey to find and solve all puzzles to find the necessary artifacts and manuscripts to build the portal so that he can travel back home. +{% endhighlight %} + +You can find the full Lore document [here](https://docs.google.com/document/d/1GVmJEV2KKjqgxjtVR-_Lh7QsvRzQbfxg9qeHjimIbPg/edit?usp=sharing). The document also contains the whole list of riddles that need to be solved to access locked areas in game. Needless to say, **SPOILER ALERT**. + +## Making items and blocks + +With all the lore ready in a Google Doc, it was time to bring everything in-game. + +### Making the Books- +Most of the game revolves around the usage of books and the journal to convey and progress the story. There are a total of 6 books that were made. Three of these books can be found in treasure chests serving as instructions on usage of specific ingredients (kept alongside in the treasure chest) to make the catapult portal. The most crucial book is the book that carries all the secrets, mainly directions to puzzles and treasures. There is one book inside the hut that hints the player to look in the well for the Book of Secrets. There is another book that lies in a chest located inside the crash site where the player spawns. This book simply has stories on space exploration, serves as light reading. The list of books is as follows- + +1. Space Exploration Stories (Editable) +2. The Hut Book (Read-Only) +3. Book of Secrets (Read-Only) +4. Treasure Chest 1- Shattered Plasma Book (Read-Only) +5. Treasure Chest 2- Arkenstone and obsidian Torch Book (Read-Only) +6. Treasure Chest 3- Facade of Truth Book (Read-Only) + +### Antrum Sabre- + +{: .center} +![antrumSabre]({{ site.baseurl }}/img/antrumSabre.jpg "antrumSabre"){:style="max-height: 100px;"} + +The word "antrum" is latin for cave or hole. The antrum sabre is an item that the player uses to make a wormhole (a connection in space-time), to travel huge distances in a few seconds. This tool however becomes dysfunctional when the player arrives at the new planet. + +### Arkenstone- + +{: .center} +![arkenstone]({{ site.baseurl }}/img/arkenstone.jpg "Arkenstone"){:style="max-height: 100px;"} + +The arkenstone is the central part of the catapult portal. Preserved since the dawn of the ancient ages, this stone serves as the key to the Portal. The kestone must be activated by tapping on it with the obsidian torch to fire up and ignite the portal. + + +### Obsidian Torch- + +{: .center} +![obsidianTorch]({{ site.baseurl }}/img/obsidianTorch.jpg "obsidianTorch"){:style="max-height: 100px;"} + +The obsidian torch discovered by the natives in the West, was a remnant found inside the largest volcano. With an ever-glowing flame, it also has other mystical usages. Knocking on the arkenstone with the obsidian torch would light up the portal and activate it. + +### Shattered Plasma- + +{: .center} +![shatteredPlasma]({{ site.baseurl }}/img/shatteredPlasma.jpg "Shattered Plasma"){:style="max-height: 100px;"} + +The shattered plasma is a green looking block made up from forging together sand, glass and grass of Spero in the Kiln of Tudal. This forms the base or the foundation for the catapult portal. + +### Facade of Truth- + +{: .center} +![facadeOfTruth]({{ site.baseurl }}/img/facadeOfTruth.jpg "Facade Of Truth"){:style="max-height: 100px;"} + +The Facade of Truth is made up of blocks of a special type of Basalt. These blocks need to be piled up to create a 3x3 frame with a 1x2 hole for the tunnel in between. +With the Shattered Plasma foundation laid, the Facade of Truth built on top, the arkenstone needs to be placed at the front of the foundation and tapped with the Obsidian Torch to activate and light up the portal. + +### The Final Portal + +The final catapult portal when put together from all the above blocks, looks like this- + +{: .center} +![portal]({{ site.baseurl }}/img/portal.jpg "Portal"){:style="max-height: 400px;"} + + +## Making Structures +The puzzle rooms were already made, complete with deadly and lethal traps. It was time to wrap these rooms around with some special structures to hide them from plain sight. There were three puzzle rooms that I hade made. To wrap around and hide these puzzle rooms, I made three additional structures- the pyramid, the stonehenge and an underground temple. In addition to these, there were two more structures that I made, the hut and the well, that exist near the spawn location which serve as a starting point for the player. + +### Making the Pyramid- + +{: .center} +![pyramidActual]({{ site.baseurl }}/img/pyramidActual.jpg "Pyramid of Giza"){:style="max-height: 400px;"} + +A good looking square pyramid made from blocks must have square layers stacked one on top of the other. For a neat looking pyramid that has a pointed top (of one block size), it is required to have each square layer have an odd length, i.e. the top layer would be 1x1, followed by layers having dimensions 3x3, 5x5, 7x7 and so on. For a pyramid having a length `l`, the bottom-most layer has dimensions- `(2l - 1)x(2l - 1)`. + +I decided to start by making a structural template for the pyramid, the pyramid would then have the puzzle room inside, at its heart, just like the tomb inside the Egyptian pyramids. To do this I required a very large pyramid which would have been extremely tedious to build manually. So, I went ahead and made a small pyramid with a height of 3 and studied the generated structure template. The structure template for a pyramid of height 3 and base of 5x5 looks like this: + +{% highlight json %} +{ "blockType": "core:Sand", "region": { "min": [-2 ,1, 1], "size": [5 , 1, 5]}}, +{ "blockType": "core:Sand", "region": { "min": [-1 ,2, 2], "size": [3 , 1, 3]}}, +{ "blockType": "core:Sand", "region": { "min": [0 ,3, 3], "size": [1 , 1, 1]}}, + +... air blocks ... +{% endhighlight %} + +Apart from the air blocks, the sand block followed a nice pattern. So, I went ahead and made a python script to make the generation of square pyramids easy. Here's the script I wrote- + +{% highlight python %} +l = int(raw_input("Enter length of base of square pyramid (odd number)")) +a = -1*(l-1)/2 +b = 1 +s = "" +for i in range (a,1): + s += '{ "blockType": "core:Sand", "region": { "min": [' + str(i) + ' ,' + str(b) + ', ' + str(b) + '], "size": ['+ str(l) +' , 1, ' + str(l) + ']}},\n' + l = l-2 + b = b+1 +print s +{% endhighlight %} + +Note that the generated output would not account for the surrounding air blocks. It is advisable to place the structure (generated from the script) in the world using a spawner and then create another structure template by making a box size region that encompasses the whole pyramid. This ensures that no other block (like parts of a nearby tree) remains floating above the pyramid. + +{: .center} +![pyramid]({{ site.baseurl }}/img/pyramid.jpg "Pyramid"){:style="max-height: 400px;"} + +### Making the Stonehenge- + +{: .center} +![stonehengeActual]({{ site.baseurl }}/img/stonehengeActual.jpg "Stonehenge Actual"){:style="max-height: 400px;"} + +Another one such structure to conceal the puzzle room is the stone henge. The stone henge much like the real world stone henge comprises of gaping tall pillars. + +Creating the stonehenge was relatively easy. I made long pillars of cobblestone by entering the ghost mode. Some pillars were broader than the others and some were connected to a neighboring pillar at the top. + +{: .center} +![stonehengePillar]({{ site.baseurl }}/img/stonehengePillar.jpg "stonehengePillar"){:style="max-width: 400px; max-height: 400px;"} +![stonehengeTwoPillar]({{ site.baseurl }}/img/stonehengeTwoPillar.jpg "stonehengeTwoPillar"){:style="max-width: 400px; max-height: 400px;"} + +The pillars together were arranged in a circular fashion. Inside the circle lay the puzzle room. + +{: .center} +![stonehenge]({{ site.baseurl }}/img/stonehenge.jpg "Stonehenge"){:style="max-height: 400px;"} + +### Making the Temple- + +{: .center} +![templeActual]({{ site.baseurl }}/img/templeActual.jpg "Temple Actual"){:style="max-height: 400px;"} + +The third and last structure is an underground temple. The puzzle room is hidden underground in a cave like hollow. The entrance to the cave is marked as a large "T" on the ground made by dirt blocks. Breaking the dirt blocks brings out the hidden staircase that leads to the underground cave. The cave is lit up with torches and directly makes way for the puzzle room. + +{: .center} +![temple]({{ site.baseurl }}/img/temple.jpg "Temple"){:style="max-height: 400px;"} + +### Making the Hut and the Well- + +{: .center} +![well]({{ site.baseurl }}/img/well.jpg "Well"){:style="max-height: 400px;"} + +The hut and the well are the nearest structures to the spawn location. They are pivotal to the plot. The well has a hidden treasure chest underground that contains the Book of Secrets. The Book of Secrets hides inside it the directions for the three structures that conceal the different pieces of the catapult portal. + +{: .center} +![hut]({{ site.baseurl }}/img/hut.jpg "Hut"){:style="max-height: 400px;"} + +The hut also has a treasure chest consisting of a Pickaxe and some other blocks. It also contains that book which points towards the well. + +## Protecting Regions + +
+ +
+ +Most of the traps had a settings screen that was produced upon interaction. This behavior was to be prevented for the traps inside the puzzle rooms atleast. In addition the password doors could be broken down easily by attacking. These needed to be protected too. + +To protect the regions, I decided to take help of the Scenarios module (being developed in another GSoC project). I've added features like Region Resizing and marking regions Protected in the Regions section of Scenarios. Regions can be created, and their properties altered using the Scenario:HubTool. + +A protected region now has the following functionalities- +- No block addition +- No block attack/removal/mining +- No interaction with entities having the `NoInteractionWhenProtected` component + +## Journal Integration + +Finally, the Journal that's been out there dust-laden has finally been put to some good use. Lost makes immense use of the Journal. In addition to adding Journal posts related to WoodAndStoneCrafting (see [WoodAndStoneCraftingJournal](https://github.com/Terasology/WoodAndStoneCraftingJournal)), Lost adds its own section in the journal. There are multiple Journal articles that get added upon events like- killing a deer, finding a new treasure chest, finding the book of secrets etc. + +## The Angel of Resurrection + +Near every trap or puzzle room, in close proximity an Angel of Resurrection is placed that could be activated to enable respawning near it, essentially acting as a checkpoint. The checkpoint is vital since death caused by the lethal traps would send the player to respawn back at the original spawn point (0, 0, 0). This causes the player to travel a huge distance to get back to the puzzle room. This has some serious chunk loading issues as well. + +{: .center} +![pyramidAngel]({{ site.baseurl }}/img/pyramidAngel.jpg "pyramidAngel"){:style="max-width: 250px; max-height: 400px;"} +![stonehengeAngel]({{ site.baseurl }}/img/stonehengeAngel.jpg "stonehengeAngel"){:style="max-width: 250px; max-height: 400px;"} +![templeAngel]({{ site.baseurl }}/img/templeAngel.jpg "templeAngel"){:style="max-width: 250px; max-height: 400px;"} + +## MCQ Button Door +The Password door allows the player to unlock the door only if the player enters the exact passphrase. The MCQ Button door is less cruel, it provides a set of options to choose from. However, it is dangerous and it kills the player instantly if they press the wrong button. + +
+ +
+ +## Set Custom Spawn Location + +The world generator is used to set the spawn position at every RespawnRequest. For world generators like PolyWorld this can be troublesome, since there is no static spawn location and the generator finds a suitable spot in an area covered by a specified search radius. + +To allow more control over spawning, I added a new command- `setSpawnLocation` that sets the spawn location to the character's current location. + +
+ +## Putting it all together + +The individual components were all ready as structures and items. What was left was placing everything together in a world to create the base save file. Piece by piece, I placed everything together. I had to take care of a few things like the directions for the structures as indicated in the Book of Secrets and subtleties like the fact that a mammoth sized pyramid of sand cannot lie on top of grassy meadows. + +The whole world is packed in the **Island World generator** from [PolyWorld](https://github.com/Terasology/PolyWorld) that has nice little islands to help contain all the features and prevent the player from wandering too far. + +Here is the background image for the Lost module- + +{: .center} +![lostBackground]({{ site.baseurl }}/img/lostBackground.jpg "Lost"){:style="max-height: 500px;"} + +I'll be making a wrap up post soon to cover all my contributions over the summer with a few stats. Plus, I might make a teaser video for the Lost module. \ No newline at end of file diff --git a/_posts/2017-08-15-GSoC-wrap-up.markdown b/_posts/2017-08-15-GSoC-wrap-up.markdown new file mode 100644 index 0000000..f5a94f6 --- /dev/null +++ b/_posts/2017-08-15-GSoC-wrap-up.markdown @@ -0,0 +1,228 @@ +--- +layout: post +title: "GSoC Wrap Up" +date: 2017-08-15 +comments: true +tags: +- open source +- MovingBlocks +- Terasology +- GSoC +--- + + + + + + +Finally it is time for wrapping up my GSoC project and along with it a highly eventful summer. It has been an amazing experience. I've learned a lot over the summer, spending countless days and nights in a row to add new things to this game. The community has been more than helpful. I couldn't have asked for more. + +This wrap up post links to all the work done over the summer. There have been a total of **72 PRs** and quite a few independent commits in the new modules I've created. With over **19,000 lines of code**, this summer has boosted my Github stats to a whole new level. + +{: .center} +![GSoCStreak]({{ site.baseurl }}/img/GSoCStreak.png "GSoCStreak"){:style="max-height: 500px;"} + +## Final Product +The final product out of my GSoC is a whole new gameplay setting in the world of Terasology. It is a single player gameplay mode called **Lost**. You take up the role of a player that ends up stranded on a planet with no way left to get back home. Set on an expedition to find signs of life in neighbouring galaxies, you come across several intriguing things that confirm the existence of intelligent life outside your planet. *Are you truly lost? Will you ever return home?* + +{: .center} +![lostBackground]({{ site.baseurl }}/img/lostBackground.jpg "Lost"){:style="max-height: 500px;"} + +To test it out simply follow the below instructions- + +#### Instructions to run Lost: +1. Download [this](https://slack-files.com/T03G8SB1X-F6N474GS0-867f5f5289) Omega. +2. Extract the Omega. +3. Move the save folder called "Lost" inside `omega796/saves` to the save directory- +- in Windows, C:/Users/name/Saved Games/Terasology/ +- in Linux, /home/name/.local/share/terasology/saves/ + ***Alternatively***, you can run the game with the `-homedir` flag. +- in Windows, run the game from cmd using a command like: `Terasology.x64.exe -homedir` + or add the `-homedir` flag to the target field of the shortcut to the exe file. +- in Linux, modify the run_linux.sh script so that it has a `-homedir` flag at the end, like so: + `java -Xms128m -Xmx1536m -jar libs/Terasology.jar -homedir` +4. Launch the game using the script or the .exe file. +5. Select Singleplayer -> Lost and load the saved game. + +### List of new modules created- + +- [Terasology/AdvancedBehaviors](https://github.com/Terasology/AdvancedBehaviors) +- [Terasology/WorldlyTooltipAPI](https://github.com/Terasology/WorldlyTooltipAPI) +- [Terasology/WoodAndStoneCraftingJournal](https://github.com/Terasology/WoodAndStoneCraftingJournal) +- [Terasology/AdventureAssets](https://github.com/Terasology/AdventureAssets) +- [Terasology/Lost](https://github.com/Terasology/Lost) + +{: .center} +![newModules]({{ site.baseurl }}/img/newModules.png "newModules"){:style="max-height: 500px;"} + +### List of repositories contributed to- + +- [Engine- MovingBlocks/Terasology](https://github.com/MovingBlocks/Terasology) + +{: .center} +![engine]({{ site.baseurl }}/img/engine.png "engine"){:style="max-height: 500px;"} + +- [Terasology/WildAnimals](https://github.com/Terasology/WildAnimals) +- [Terasology/StructureTemplates](https://github.com/Terasology/StructureTemplates) +- [Terasology/Books](https://github.com/Terasology/Books) +- [Terasology/WorldlyTooltip](https://github.com/Terasology/WorldlyTooltip) +- [Terasology/Projectile](https://github.com/Terasology/Projectile) +- [Terasology/Pathfinding](https://github.com/Terasology/Pathfinding) +- [Terasology/Journal](https://github.com/Terasology/Journal) +- [Terasology/Scenario](https://github.com/Terasology/Scenario) +- [Terasology/Thirst](https://github.com/Terasology/Thirst) +- [Terasology/Hunger](https://github.com/Terasology/Hunger) + +{: .center} +![oldModules]({{ site.baseurl }}/img/oldModules.jpg "oldModules"){:style="max-height: 700px;"} + +### List of Pull Requests- + +Here is a [list of pull requests](https://github.com/pulls?utf8=%E2%9C%93&q=is%3Apr+is%3Amerged+author%3Anihal111+created%3A2017-05-04..2017-08-15+) from the start of GSoC up until now. + +
+
+ Click here to view all PRs?
+
+MovingBlocks/Terasology Added setSpawnLocation command
+Terasology/AdventureAssets Added MCQ Button Door
+MovingBlocks/Terasology Added removeAllWidgets method API UI
+MovingBlocks/Terasology Dead players alive-d on join
+Terasology/StructureTemplates Consumes AttackEvent for BlockRegions
+MovingBlocks/Terasology PlayerDeath event should be sent to character entity
+Terasology/Hunger Fix for Hunger related Alive/Death handling
+Terasology/Thirst Fix for Thirst related Alive/Death handling
+Terasology/AdventureAssets Added NoInteraction component
+MovingBlocks/Terasology Checking isHeadless from DisplayDevice
+MovingBlocks/Terasology Change ActivationPredicted to consumable event
+Terasology/StructureTemplates Consuming ActivationPredicted event
+Terasology/Scenario Added Protected Regions and Resizing functionality
+Terasology/Projectile MaxDistance check during displacement calculation
+Terasology/AdventureAssets Structure Template Integration fixes
+Terasology/Books Multiplayer + newline fix
+Terasology/AdventureAssets Swinging Blade is multiplayer ready
+Terasology/AdventureAssets WipeOut is multiplayer ready
+Terasology/AdventureAssets Fixed Fireball Launcher for multiplayer
+Terasology/AdventureAssets Door works in multiplayer
+Terasology/AdventureAssets Password Door is now multiplayer ready
+MovingBlocks/Terasology Added door related events
+MovingBlocks/Terasology FloatingTextRenderer accepts multiple \n separated lines
+MovingBlocks/Terasology Multiline UIText, enter produces newline
+MovingBlocks/Terasology Store DoorRegion prefab as component parameter
+Terasology/AdventureAssets Added a UI Screen Password locked Door
+MovingBlocks/Terasology Separated spawnLocation calculation from respawnPlayer method
+Terasology/AdventureAssets Add the Revival Stone
+Terasology/AdventureAssets Moved duplicate methods to utility class
+Terasology/AdventureAssets Remember rotation after mining of trap blocks
+Terasology/Projectile Revert to old constructor
+Terasology/AdventureAssets Added more parameters for Fireball with Structure Template integration
+Terasology/Projectile Changed CollisionGroup filter to ALL
+Terasology/Projectile Added new event constructor for configurable maxDistance
+Terasology/DamagingBlocks Reverted the AliveCharacter check
+Terasology/AdventureAssets Added Fireball Launcher
+MovingBlocks/Terasology Prevents player entity from being destroyed after death onDamage
+Terasology/DamagingBlocks Added Alive Character check
+Terasology/AdventureAssets Added Wipeout
+Terasology/AdventureAssets Changed trap placement approach to root block
+Terasology/AdventureAssets Changed trapPlaceholder block shape and fixed readme
+Terasology/StructureTemplates Moved rotation logic
+MovingBlocks/Terasology Fixes dumpEntities console command
+Terasology/AdventureAssets Added SwingingBlade
+Terasology/StructureTemplates Added rotation logic for spawning entities
+Terasology/AdventureAssets Add module.txt and gitignore
+Terasology/AdvancedBehaviors Added alive character check
+Terasology/Pathfinding Added alive character check
+Terasology/WildAnimals Added alive character component
+Terasology/GooeysQuests Added alive character component
+Terasology/Journal Added Recipe and Image paragraph
+Terasology/WoodCrafting Moved generators to NeoTTA
+Terasology/NeoTTA Moved generators from WoodCrafting
+MovingBlocks/Terasology Fixed eye height movement debug command
+Terasology/PhysicalStats Fixes missing save component bugs
+MovingBlocks/Terasology Do not destroy player entity completely on death
+Terasology/Journal Adds different colored entries for Unread Journal entries
+Terasology/Pathfinding Fixed intelligent flee
+Terasology/AdvancedBehaviors Added intelligent flee
+Terasology/Pathfinding Added intelligent flee
+Terasology/AdvancedBehaviors Refactor
+Terasology/AdvancedBehaviors Added the fleeInProximity package
+Terasology/WildAnimals Added a scaredDeer
+Terasology/AdvancedBehaviors Added followInProximity package
+Terasology/WildAnimals Added a friendlyDeer
+Terasology/WildAnimals Moved packages to AdvancedBehaviors** module
+Terasology/AdvancedBehaviors Moved packages from WildAnimals** module
+Terasology/WildAnimals AttackInProximity- adds hostile-stray behavior switching
+Terasology/FunnyBlocks Portals work in multiplayer
+Terasology/WildAnimals Added aggressiveDeer
+Terasology/WorldlyTooltip Configured with WorldlyTooltipAPI module
+MovingBlocks/Terasology Fixes the blocker #2913
+Terasology/WorldlyTooltip Added character entity support
+MovingBlocks/Terasology BehaviorSystem- use cachedInterpreters
+MovingBlocks/Terasology Worldly tooltip addition for character entities
+Terasology/WildAnimals Worldly tooltip Integration +
+
+ +### What more to look at? + +There have been a whole lot of videos I've made over the summer. You can have a look at them at [my channel](https://www.youtube.com/channel/UCVDrDJDt7sI8A9Ww1FekUMQ). + +I have also written a set of blog posts marking the progress I made through the summers. A list of all these can be found under the #GSoC tag [here](http://nihal111.github.io/tags/#GSoC). + +### What's next? + +Although I have checked off most of my primary targets from the proposal. There are quite a few things that need work on- +1. Some of the traps like the Swinging Blade work well only in Single Player. This is because the Movement Prediction works quite differently on the server side. The `CharacterImpulseEvent` triggers differently even with a little lag. +2. Traps like the Wipe Out, require the player to move constantly along with the surfboard. There have also been instances when a collision is not detected between the player and the surfboard. Again something to deal with the Movement Prediction and Physics engine. +3. On the Gameplay side, I've attempted to make interesting short riddles for the three treasure locations, however they get boring very fast. The player might feel it is too much effort to solve a text based riddle. It can be difficult to strike the right chord while making riddles and clues that are both short, engaging and require the player to think. +4. The Portal upon construction does nothing yet. Well, it is supposed to take you back to your home planet. But I guess we could display a "Game Over" dialog or somehow bring up the Credits screen. + +Some of these might be fixed by a long overdue movement refactoring. With Tyler Thompson's Scenario module developed alongside in [another GSoC project](https://thompsontyler.github.io/gsoc/2017/08/25/scenario-gsoc.html), the Lost module serves as an example of how a gameplay scenario can be made. +With the completion of this GSoC project making adventure assets like locked doors, traps, resurrection statues etc are now a lot more easier. Creation of more such things can probably serve as one of the tougher GCI tasks later. + +### Wrapping it up + +Once again, I would like to thank all my mentors. My primary mentor, [Skylar 'skysom' Sommers](http://forum.terasology.org/members/skysom.1621/), for replying always within a splitsecond (save for the times when he forgets to hit the Send button :P). [Florian ‘flo’ Köberle](http://forum.terasology.org/members/florian.1335/), who was my secondary but went out of his way and functioned effectively as my primary. I got to learn a lot from flo regarding various aspects about the game. It would have been impossible to complete my project without his aid. [Xavier ‘xtariq’ Tariq](http://forum.terasology.org/members/xtariq.1697/), who was also my secondary mentor, helped me whenever I needed him. I'd like to specially thank [Rasmus 'cervator' Praestholm](http://forum.terasology.org/members/cervator.2/) here. Had he not been there that night in October, welcoming me on IRC and helping me set up my codebase, maybe I would have given up, moved on and never have done GSoC in the first place. + +All in all, it has been a thrilling summer. By this time I am familiar with a good part of the game's codebase. I would love to continue contributing, albeit in different capacities. Let's hope real life doesn't get in the way too much. Also, GCI is almost here and another storm's coming! + +Here's a snap from one of the many exciting multiplayer play test sessions- + +{: .center} +![multiplayerPlayTest]({{ site.baseurl }}/img/multiplayerPlayTest.jpg "multiplayerPlayTest"){:style="max-height: 500px;"} \ No newline at end of file diff --git a/_posts/2017-11-15-cfs-visualizer.markdown b/_posts/2017-11-15-cfs-visualizer.markdown new file mode 100644 index 0000000..b1f5ee7 --- /dev/null +++ b/_posts/2017-11-15-cfs-visualizer.markdown @@ -0,0 +1,29 @@ +--- +layout: post +title: "CFS Visualizer- Operating Systems Project" +date: 2017-11-15 +comments: true +tags: +- Machine Learning +- Reinforcement Learning +--- + + +As the course project for CS 347 - Operating Systems, Fall 2017, I teamed up with Arpan Banerjee and Srivatsan Sridhar to work on building a visulizer for the Completely Fair Scheduler that's widely present in all Linux systems as the default scheduler. + +The visualizer is available at- [https://nihal111.github.io/CFS-visualizer/](https://nihal111.github.io/CFS-visualizer/). + +### Schedulers + +Linux is a multitasking operating system, and therefore, it has a scheduler to manage the processes. The Linux scheduler has evolved over time. With the Linux Kernerl 2.6, the O(1) scheduler came in. It relies on active and expired arrays of processes to achieve constant scheduling time. Each process is given a fixed time quantum, after which it is preempted and moved to the expired array. Once all the tasks from the active array have exhausted their time quantum and have been moved to the expired array, an array switch takes place. This switch makes the active array the new empty expired array, while the expired array becomes the active array. The main issue with this algorithm is the complex heuristics used to mark a task as interactive or non-interactive. + +### The Completely Fair Scheduler + +The Completely Fair Scheduler is a process scheduler that handles CPU resource allocation for executing processes and aims to maximize overall CPU utilization while also maximizing interactive performance. This was merged into the 2.6.23 (October 2007) release of the Linux kernel and is the default scheduler. + +By "Completely Fair", the CFS Scheduler means to allocate the CPU resources equally and fairly among all the queued processes depending on their nice values. + +The Completely Fair Scheduler uses a Red-Black tree to keep track of all the queued processes and handles switching with a nano second granularity. The fair queuing CFS scheduler has a scheduling complexity of `O(log N)`, where `N` is the number of tasks in the runqueue. Choosing a task can be done in constant time, but reinserting a task after it has run requires `O(log N)` operations, because the runqueue is implemented as a red-black tree. +The Visualizer + +The [CFS visualizer](https://nihal111.github.io/CFS-visualizer/) allows one to look at the process queue and the populated dynamic red-black tree while the scheduler is in action. The time scale has been magnified so that one can slow down and visualize the scheduler with nano-second granularity work in real time. \ No newline at end of file diff --git a/_posts/2018-03-30-ntp-update-time.markdown b/_posts/2018-03-30-ntp-update-time.markdown new file mode 100644 index 0000000..b8998be --- /dev/null +++ b/_posts/2018-03-30-ntp-update-time.markdown @@ -0,0 +1,236 @@ +--- +layout: post +title: "Update time on Windows with IIT Bombay NTP server" +date: 2018-03-30 +comments: true +tags: +- python +- windows +--- + +*The following blog post discusses two solutions to updating time through an external/local NTP server on a Windows machine.* + + +# Problem +**Windows would not update time using the standard NTP servers since they are blocked on the network.** + +The system time often gets messed up when **switching between different operating systems on a multi-boot machine** (solution to this specific problem in [appendix](#appendix)). This problem arises when you are on a network (like the IIT Bombay network) that blocks outside NTP servers. IIT Bombay has its own NTP server- ntp.iitb.ac.in. All other standard NTP servers (like time.windows.com, time.nist.gov, pool.ntp.org) are blocked. + +This problem can be [easily solved](https://askubuntu.com/questions/14558/how-do-i-setup-a-local-ntp-server) on linux machines by simply adding the NTP server to `/etc/ntp.conf`. However, in Windows, the control panel settings would not allow you to add an external NTP server (in our case ntp.iitb.ac.in). + +{: .center} +![ntp_no_option]({{ site.baseurl }}/img/ntp_no_option.png "No Option"){:style="max-height: 500px;"} + +Trying to force an update through a pre-defined NTP server (like time.nist.gov) results in a time out, as shown- + +{: .center} +![ntp_timeout]({{ site.baseurl }}/img/ntp_timeout.png "Timeout"){:style="max-height: 500px;"} + +### Checking if an NTP server is accessible- +On windows you can check if an NTP server is accessible by running the following command in command prompt- + +``` +w32tm /stripchart /computer:ntp.iitb.ac.in /dataonly /samples:3 +``` +(Replace ntp.iitb.ac.in with your NTP server address) + +This command is analogous to running `ntpdate -q ntp.iitb.ac.in` on a linux machine. + +Testing the above command on IIT-B network, reveals this- + +{: .center} +![cmd_check_ntp_server]({{ site.baseurl }}/img/cmd_check_ntp_server.png "cmd check ntp server"){:style="max-height: 500px;"} + +time.nist.gov is inaccessible while ntp.iitb.ac.in is accessible. + +--- + +# Solution 1: Python Script with Windows Task Scheduler + +### Description: +Make a list of NTP servers, and send a request to each until a response is received. Use socket to send a request to the NTP server on port 123. (Reference: [Simon Foster's recipe](http://code.activestate.com/recipes/117211-simple-very-sntp-client/)). Use win32api to update system time. + +### Step 1: Install Dependencies +All dependencies are standard libraries apart from win32api (a.k.a. pywin32). + +Install `pywin32` from [here](https://sourceforge.net/projects/pywin32/) or simply do a `pip install pywin32`. +To install pip for Windows, refer [this](https://stackoverflow.com/questions/4750806/how-do-i-install-pip-on-windows). + +### Step 2: Download the script +The script can be found in [this gist](https://gist.github.com/nihal111/23faa51c3f88a281b676dcbac77ce015). +Find Raw file [here](https://gist.githubusercontent.com/nihal111/23faa51c3f88a281b676dcbac77ce015/raw/fc1e5009837ab7920cd34acc8113c2451618e6f5/ntp_update_time.py). + +This script is tested with Python 2 and 3. + +{% highlight python %} +import socket +import struct +import sys +import time +import datetime +import win32api + +# List of servers in order of attempt of fetching +server_list = ['ntp.iitb.ac.in', 'time.nist.gov', 'time.windows.com', 'pool.ntp.org'] + +''' +Returns the epoch time fetched from the NTP server passed as argument. +Returns none if the request is timed out (5 seconds). +''' +def gettime_ntp(addr='time.nist.gov'): + # http://code.activestate.com/recipes/117211-simple-very-sntp-client/ + TIME1970 = 2208988800 # Thanks to F.Lundh + client = socket.socket( socket.AF_INET, socket.SOCK_DGRAM ) + data = '\x1b' + 47 * '\0' + try: + # Timing out the connection after 5 seconds, if no response received + client.settimeout(5.0) + client.sendto( data, (addr, 123)) + data, address = client.recvfrom( 1024 ) + if data: + epoch_time = struct.unpack( '!12I', data )[10] + epoch_time -= TIME1970 + return epoch_time + except socket.timeout: + return None + +if __name__ == "__main__": + # Iterates over every server in the list until it finds time from any one. + for server in server_list: + epoch_time = gettime_ntp(server) + if epoch_time is not None: + # SetSystemTime takes time as argument in UTC time. UTC time is obtained using utcfromtimestamp() + utcTime = datetime.datetime.utcfromtimestamp(epoch_time) + win32api.SetSystemTime(utcTime.year, utcTime.month, utcTime.weekday(), utcTime.day, utcTime.hour, utcTime.minute, utcTime.second, 0) + # Local time is obtained using fromtimestamp() + localTime = datetime.datetime.fromtimestamp(epoch_time) + print("Time updated to: " + localTime.strftime("%Y-%m-%d %H:%M") + " from " + server) + break + else: + print("Could not find time from " + server) + +{% endhighlight %} + +Download the file and save it at a location you'll remember. +For the purpose of this demonstration, I'll be saving it inside- `C:\Python27\ntp_update_time.py` with my Python installation directory as `C:\Python27`. + +### Step 3: Test the script +Open Command Prompt with admin privileges- Hit key combo `Windows` + `X`, and click on `Command Prompt (Admin)`. + +Type: +``` +cd C:\Python27 +python ntp_update_time.py +``` + +If you were on IIT-B network and everything worked well, it should say- `Time updated to: 2018-03-30 19:04 from ntp.iitb.ac.in` + +### Step 4: Schedule a Task +Similar to a cronjob in Unix, you can create a task to run periodically using Windows Task Scheduler. + +- Search for "Task Scheduler" from the start menu and open it. + +- Create a basic task from the Actions menu at the right + +{: .center} +![ntp_ts_1]({{ site.baseurl }}/img/ntp_ts_1.png "ntp_ts_1"){:style="max-height: 500px;"} + +- Under the General tab, give a name and description to the task. Check the "Run with highest privileges" checkbox. + +{: .center} +![ntp_ts_2]({{ site.baseurl }}/img/ntp_ts_2.png "ntp_ts_2"){:style="max-height: 500px;"} + +- Under the Triggers tab, click on New, and set "Begin the task:" to "On workstation unlock". Leave everything as is, and hit Ok. + +{: .center} +![ntp_ts_3]({{ site.baseurl }}/img/ntp_ts_3.png "ntp_ts_3"){:style="max-height: 500px;"} + +- Under the Actions tab, set Program/Script to your python path (`C:\Python27\python.exe`) and set "Add arguments (optional)" to the script path (`C:\Python27\ntp_update_time.py`). + +{: .center} +![ntp_ts_4]({{ site.baseurl }}/img/ntp_ts_4.png "ntp_ts_4"){:style="max-height: 500px;"} + +- Under the Conditions tab, uncheck the checkbox under Power which says "Start the task only if the computer is on AC power". + +{: .center} +![ntp_ts_5]({{ site.baseurl }}/img/ntp_ts_5.png "ntp_ts_5"){:style="max-height: 500px;"} + +- Hit Ok and save the Task. Return to the Task Scheduler window, double click on "Task Scheduler Library" on the left navigation drawer. Select the task you made from the list and click on it. Hit "Run" from the right hand actions menu. (Make sure to screw up your system time before running. If it gets fixed after you run the task, everything is set up to work.) + +{: .center} +![ntp_ts_6]({{ site.baseurl }}/img/ntp_ts_6.png "ntp_ts_6"){:style="max-height: 500px;"} + +The task would be scheduled to run every time you unlock your machine. This makes sense since mostly the time gets messed up when switching between two different Operating Systems on a multi-boot machine. + +--- + +# Solution 2: Use Windows Time Service tools to query local NTP server + +This solution uses the Windows Time Service tool to add an external/local NTP server. + +1. Open Command Prompt with admin privileges- Hit key combo `Windows` + `X`, and click on `Command Prompt (Admin)`. +2. Stop the time service- `net stop w32time` +3. Type in `w32tm /config /syncfromflags:manual /manualpeerlist:"ntp.iitb.ac.in,pool.ntp.org"` to manually set the list of external/local NTP servers. +4. Force set the connection as reliable- `w32tm /config /reliable:yes` +5. Start the time service- `net start w32time` +6. Check if the configuration has been written successfully- `w32tm /query /configuration` and `w32tm /query /status`. You should see "NtpServer: ntp.iitb.ac.in,pool.ntp.org (Local)". +7. Do a `w32tm /resync` to force an update. (Make sure your system time is messed up to see if it gets corrected). + +--- + +# Solution 3: No NTP server reachable, update using HTTPS +In case you are unable to reach any NTP server, you can use the following script to update the time by scraping duration since epoch time from www.unixtimestamp.com. + +The script can be found in [this gist](https://gist.github.com/nihal111/7d95fa52fb91bf3298947cd36b700ce8). +Find Raw file [here](https://gist.githubusercontent.com/nihal111/7d95fa52fb91bf3298947cd36b700ce8/raw/b65d8c187329d85ac971efc23291c06eff4d433b/update_time.py). + +{% highlight python %} +import requests +import datetime +import win32api + +page = requests.get('https://www.unixtimestamp.com/', headers={'Cache-Control': 'no-cache'}) +text = page.text + + +for line in text.split("\n"): + match_text = "

" + suffix = " seconds since Jan 01 1970. (UTC)

" + if match_text in line: + line = line.replace('<',' ').replace('>',' ') + epoch_time = [int(s) for s in line.split() if s.isdigit()][0] + break + +utcTime = datetime.datetime.utcfromtimestamp(epoch_time) + +try: + # SetSystemTime takes time as argument in UTC time + win32api.SetSystemTime(utcTime.year, utcTime.month, utcTime.weekday(), utcTime.day, utcTime.hour, utcTime.minute, utcTime.second, 0) + localTime = datetime.datetime.fromtimestamp(epoch_time) + print("Time updated to: " + localTime.strftime("%Y-%m-%d %H:%M")) +except: + print("Could not update time") + +{% endhighlight %} + +1. Install requests- `pip install requests`. +To install pip for Windows, refer [this](https://stackoverflow.com/questions/4750806/how-do-i-install-pip-on-windows). +2. Follow Step 3 and Step 4 from Solution 1, using the script above. + +--- + + +### Appendix + +Specifically pertaining to the problem of the system time going haywire when dual booting across Windows and Linux, the [Official Ubuntu documentation explains](https://help.ubuntu.com/community/UbuntuTime#Multiple_Boot_Systems_Time_Conflicts) what causes this. + +In essence, Linux/Unix systems store UTC as the time on the hardware clock and with good reason, since this saves unnecessary changes to the hardware clock when moving between timezones. On the other hand, Windows stores the local time as the time on the hardware clock. This ends up messing with the system time since both OS deal with the hardware clock differently. + +The [Official Ubuntu Docs](https://help.ubuntu.com/community/UbuntuTime#Multiple_Boot_Systems_Time_Conflicts) list down a step by step solution to avoid this from happening. + +--- + +That should save you from manually setting time again. + +Till next 'time'.. +Cheers! \ No newline at end of file diff --git a/_posts/2018-04-30-voice-conversion.markdown b/_posts/2018-04-30-voice-conversion.markdown new file mode 100644 index 0000000..6b22190 --- /dev/null +++ b/_posts/2018-04-30-voice-conversion.markdown @@ -0,0 +1,32 @@ +--- +layout: post +title: "Voice Conversion- Machine Learning Project" +date: 2018-04-30 +comments: true +tags: +- Machine Learning +- Reinforcement Learning +--- + + +As the course project for CS 419 - Introducing to Machine Learning, Spring 2018, I teamed up with Arpan Banerjee and Srivatsan Sridhar to work on the task of Voice Conversion. + +We built a pipelined approach to convert one person’s voice into another person’s voice. We proposed a deep learning approach to convert source waveform to phonemes and further phonemes to target waveform. This approach consisted of two neural networks. +The first network was used to convert the source speaker's waveforms to phonemes. + +{: .center} +![Net1]({{ site.baseurl }}/img/voice-conversion/net1.png "Net1"){:style="max-height: 500px;"} + +While the second network involved converting the obtained phonemes to the target speaker's waveforms. + +{: .center} +![Net2]({{ site.baseurl }}/img/voice-conversion/net2.png "Net2"){:style="max-height: 500px;"} + +We used the TIMIT (different sources) and CMU ARCTIC (single target) corpus respectively for training our network. As part of our project, we performed extensive experimentation with bi-directional Recurrent Neural Networks using LSTM and GRU cells. + +We’ve used the multitask approach to train the network as per both the mel spectral coefficients (as an intermediate representation) and magnitude spectrum which forms the final output while using a pyramidal network architecture. + +{: .center} +![multitask]({{ site.baseurl }}/img/voice-conversion/multitask.png "multitask"){:style="max-height: 500px;"} + +Our experiments and approaches are detailed here- [Report]({{ site.baseurl }}/docs/voice_conversion_report.pdf) diff --git a/_posts/2018-05-20-flying-dji-mavic.markdown b/_posts/2018-05-20-flying-dji-mavic.markdown new file mode 100644 index 0000000..10bd998 --- /dev/null +++ b/_posts/2018-05-20-flying-dji-mavic.markdown @@ -0,0 +1,46 @@ +--- +layout: post +title: "Flying a DJI Mavic" +date: 2018-05-20 +comments: true +tags: +- drone +--- + +On yet another Summer weekend, I drove to the NRI Complex in Seawoods. It was a sunny day, and we were to fly a drone that evening. + +### The Lake + +Just adjacent to the NRI Estate is a lake where a raft of flamingoes with almost a dozen other species visit during the summer. During the season, the lake also becomes a hive for photographers from all over Navi Mumbai. +During winter, this lake also becomes home to thousands of migratory aquatic birds including ducks, herons, and kingfishers. There's also an interesting [story](https://www.thebetterindia.com/120843/shruti-agarwal-sunil-agarwal-seawoods-lake-mumbai/) behind the lake's preservation and it's battle against being converted to a golf course. + +{: .center} +![Lake]({{ site.baseurl }}/img/lake.jpg "Lake"){:style="max-height: 500px;"} + +### The Drone + +The drone belonged to Vaibhav. It was a DJI Mavic, the one listed [here](https://www.dji.com/mavic). A small transmitter hooks on to a phone, and the drone relays a clear view to the phone's screen, saving higher quality footage to the SD card. There were four of us flying that evening, each reluctantly passing on the transmitter to the other. + +{: .center} +![drone1]({{ site.baseurl }}/img/drone1.jpg "drone1"){:style="max-height: 500px;"} + +The drone is pretty smart and packed with features including collision avoidance, wind monitoring, constant battery monitoring for safe return and a fantastic return-to-home option that brings the drone back to the take-off point with centimeter accuracy. + +The software side from DJI is pretty amazing too. In addition to providing the above-listed features in a clean interface, it does a great job at pre-processing too- threading together an entire video from the shots taken during flight and overlaying music with one button tap. The videos attached below are created automagically by the DJI app. + +
+ +
+ +After Saturday's exciting flight session, Arpan and I couldn't get enough and ended up exhorting Vaibhav for another flying session on Sunday. + +{: .center} +![drone2]({{ site.baseurl }}/img/drone2.jpg "drone2"){:style="max-height: 500px;"} + +This time we took off from Vaibhav's roof (14 storeys high) getting an aerial perspective and a larger field of view to maneuver the drone. We flew past the lake again and also took cinematic landscape shots of the NRI colony. + +
+ +
+ +Overall, it was a weekend well spent. Also, this happens to be my last weekend here in Mumbai as I fly to Tokyo this Saturday for my internship. diff --git a/_posts/2018-05-28-flew-to-japan.markdown b/_posts/2018-05-28-flew-to-japan.markdown new file mode 100644 index 0000000..6ea2f55 --- /dev/null +++ b/_posts/2018-05-28-flew-to-japan.markdown @@ -0,0 +1,33 @@ +--- +layout: post +title: "I just flew to Japan" +date: 2018-05-28 +comments: true +tags: +- Japan +--- +Wifi or SkyTV, I needed at least one. The UEFA Champions League Final was on at night, and I was flying the ANA to Tokyo. + +I was travelling from Mumbai to Tokyo for my summer internship at Mercari. I left for the airport at 4 PM. My plane was to depart at 8:15 PM. The traffic was unusually high for a non-working Saturday afternoon; I ended up reaching the airport at 5:45 PM. The airport stuff didn't take long, and I was near the boarding gates by 6:30. I decided to wait in the lounge. **PROTIP**: always try to carry a [MasterCard](https://www1.mastercard.com/content/mc/campaign-exchange/moments/india/en/local-campaigns/exclusive-airport-lounge-access.html) to the lounge, you get free food and drinks. + +{: .center} +![Lounge]({{ site.baseurl }}/img/lounge.jpg "Lounge"){:style="max-height: 250px;"} + +As soon as I boarded the flight, I checked the entertainment system. SkyTV was disabled. I accepted my fate of missing the finals and decided to watch a movie- The Butterfly Effect. My flight's departure got delayed by an hour. After the flight took off, I realised that SkyTV started working. With my plans of sleeping destroyed, I braced myself for the match. The match was disappointing (save for Bale's bicycle), thanks to Sergio Ramos' [love for clean play](https://www.youtube.com/watch?v=UxCcZe_q1iI). + +Barely able to sleep at night, I arrived in Japan with numb legs. I found Emily-san from Fourth Valley Concierge waiting to pick me up. The other interns had already reached. We took a bus to the Ginza station and then a train to the Tameikei Sanno station. Our apartment was located somewhere in Roppongi. We picked up the keys to our apartments and went in to freshen up. Seeing the apartment for the first time was a delight, and I really couldn't wish for better. + +{: .center} +![Home]({{ site.baseurl }}/img/homeJapan.jpeg "Home"){:style="max-height: 300px;"} + +Emily-san and Tanaka-san took us out for lunch and showed us around. I started falling in love with Tokyo. I spent most of the afternoon unpacking and getting used to my new home. I had a hard time trying to figure out a few things since almost everything was documented in Japanese, from the toilet seat temperature controls to the TV remote. The waste segregation was pretty complicated too, and I pushed it off for later. + +{: .center} +![View]({{ site.baseurl }}/img/viewJapan.jpeg "View"){:style="max-height: 400px;"} + +I called over Prateek in the evening, who lives only an hour away. He was doing his research internship at the University of Tokyo. We went out and explored the locality, hopped across a few convenience stores and got a few ready to cook items for dinner. + +{: .center} +![dinnerJapan]({{ site.baseurl }}/img/dinnerJapan.jpeg "Dinner"){:style="max-height: 250px;"} + +I retired to bed early, super excited for my first day at work. \ No newline at end of file diff --git a/_posts/2018-07-09-japan-lookback.markdown b/_posts/2018-07-09-japan-lookback.markdown new file mode 100644 index 0000000..376af2e --- /dev/null +++ b/_posts/2018-07-09-japan-lookback.markdown @@ -0,0 +1,55 @@ +--- +layout: post +title: "Adventures in Japan" +date: 2018-07-09 +comments: true +tags: +- Japan +--- +My time in Japan comes to a close as I enter the last week of my stay here. The experience so far has been nothing short of crazy. + +I was fortunate to spend the summer of '18 in Tokyo doing my internship at Mercari, an e-commerce unicorn. I spent most of my working days writing Android code for the main Japanese marketplace app-[Mercari](https://play.google.com/store/apps/details?id=com.kouzoh.mercari). My weekends were well spent touring around Japan. This is an attempt to lookback and document some of my adventures in Japan. Most of the following adventures were made with a varying subset of the 8 co-interns I was lucky to be in company of. + +### Week 1: Tokyo Disney Sea +We were planning to get the 2 day Disney Land + Disney Sea pass, but better judgement prevailed and we went ahead with only getting the Disney Sea tickets. +This was my first Disney experience and it was the best theme park experience I had so far. The landscapes were beyond amazing. Being a weekend, it was super crowded. But with our strong fast pass game, we managed to ride through to most of the attractions with great efficiency. The evening fireworks show- Fantasmic was true to its name. I walked over 15k steps that day and returned home with tired legs. + +{: .center} +![Lounge]({{ site.baseurl }}/img/tokyo/disneysea.jpg "DisneySea"){:style="max-height: 500px;"} + +### Week 2: Akihbara- the electric town +With our first attempt at making a booking for FujiQ online having failed, we were left with an empty weekend. I decided to make the most of it by going shopping. +I went to Akihabara, the electric town of Japan, filled with electronic stores of all sizes and interspersed with Anime cafes and Manga stores of all sorts. I explored the world's largest electronics store- the Yodobashi Camera. I bought a few things from BIC Camera and also a lot of handy items from small stores around. I went to Gachapon store and got a few capsule toys. I roamed around and went to a few other interesting stores as well... + +{: .center} +![Lounge]({{ site.baseurl }}/img/tokyo/akihabara.jpg "Akihabara"){:style="max-height: 500px;"} + +### Week 3: Exploring Kyoto +How can you come to Japan and not go to the ancient capital to witness true Japanese tradition? +We took the Shinkansen to Kyoto on our third weekend. We left early Saturday morning and reached there by 10 AM. We had planned an efficient route that would get us to a lot of good spots without having to travel a lot. We started off with **Nijo Castle**, which was home to the shoguns from the Edo period. Next up, we went to the **Imperial Palace** and then to **Kinkakuji**, the golden shrine. We paused for lunch and then continued to **Ryōan-ji**, a Zen temple with a rock garden. We then headed to the **Fushimi-inari** shrine. The climb to the top was tiring, but the view from the top was spectacular. After sundown, we made our way to the Ryokan we had booked for the night. It was a small place, but we had a fun night sleeping in traditional Japanese rooms. The next day, we went to the **Arashiyama** bamboo forest and enjoyed boating in the Hozugawa river. Later, we went to the Arashiyama monkey park to watch some macaque from real close. We returned in time to catch one of the last Shinkansen back to Tokyo. + +{: .center} +![Lounge]({{ site.baseurl }}/img/tokyo/kyoto.jpg "Kyoto"){:style="max-height: 500px;"} + +### Week 4: FujiQ, roller coaster madness +We really got lucky with this one. With most weekends having heavy rainfall forecast, we had almost given up on our roller coaster hopes. Until one Saturday we made an instant plan and went ahead since the next day showed very little rainfall. +We took the Q-Pack which includes the to and fro ride from Shinjuku and the day pass to the park. To make the most out of our lucky chance, we further bought express passes to three of the crowded roller coasters. There are a total of four popular roller coasters- Fujiyama, Eejanaika, Takabisha and Do-Dodonpa. Fujiyama surprisingly had smaller queues and we ended up going for Fujiyama twice despite not having a fast pass for it. With the express passes, we were able to get done with the popular rides in less time and had enough time on our hands to try out most of the other attractions as well. Overall, I enjoyed a lot. Some of the roller coasters are world record holders and it was a completely thrilling experience to ride them. + +{: .center} +![Lounge]({{ site.baseurl }}/img/tokyo/fujiq.jpg "FujiQ"){:style="max-height: 500px;"} + +### Week 5: Oshima- an island escapade +This was definitely one of the best weekends spent in Japan. Izu Oshima is the largest of the Izu islands that fall under the administeration of Tokyo. It has a population of around 2500 people but for long stretches, we barely saw any people when we went cycling around the island. +We took the overnight ferry from Tokyo to Oshima, that docked at early Saturday morning. We quickly went ahead and rented out cycles to begin our expedition. The island's perimeter has a nice circuit made for cycling. Cycling along the oceanline with a constant ocean breeze and through the mountains was definitely my best cycling experience so far. We cycled for a good 30+ km and headed back to our hotel. It was a small nice place called the Book Tea Bed. We went to the Hama-no-yu onsen next to have a hot water bath to relax our tired muscles whilst watching the sun set on the horizon as we sat at the edge of the island surrounded by the ocean. What followed was a good night's sleep and another cycle journey to head to the Okata port where we went snorkeling. Snorkeling was fun and we saw a lot of fish. Bringing a GoPro to record the underwater sights and the cycle journeys was one of my better decisions. We had to rush back to Motomachi port for our ship back to Tokyo. The ship had some of the coolest vending machines, ones with built in microwave for warm food and hot water dispensers for cup noodles. + +{: .center} +![Lounge]({{ site.baseurl }}/img/tokyo/oshima.jpg "Oshima"){:style="max-height: 500px;"} + +### Week 6: Conquering Mt. Fuji +This was probably the stupidest, albeit the most adventurous thing I did in Japan. The proper and recommended way to climb Mt. Fuji and witness the literally 'breath-taking' sunrise involves making a climb during day, and resting in a hut for the night, waking up energized and making to the top just in time for the sunrise. We weren't able to book a hut, thanks to our last moment planning and we decided to do it the hard way- rush to the top, see the sunrise and come back. +We made it to the 5th station at around 16:00 and started the climb at 19:30. The Yoshida trail is the easiest way to the top and that's the one we took. With frequent stops, we took it slow and made it to the top at 04:00 just in time to see the sunrise. The view was nothing short of spectacular, but it was freezing cold at the summit. The temperature touched zero degree Celcius and there were super strong chilly winds blowing. Altitude sickness and asphixiation had started taking a toll on me. It was a super cloudy day and the crater was completely shielded with fog. The sun was hidden behind the clouds intermittently too. Somehow, I survived and started descending. The descent was torturous with steep curved paths that have slippery gravel for extremely long stretches. With an extreme body ache and a severe headache, I took the bus to take me home. + +{: .center} +![Lounge]({{ site.baseurl }}/img/tokyo/mtfuji.jpg "Mt. Fuji"){:style="max-height: 500px;"} + +There were a few mini adventures on weekdays, but the bulk of my expeditions in Japan have been recorded above. Woo! \ No newline at end of file diff --git a/_posts/2018-07-16-mercari-internship.markdown b/_posts/2018-07-16-mercari-internship.markdown new file mode 100644 index 0000000..6ab8fdf --- /dev/null +++ b/_posts/2018-07-16-mercari-internship.markdown @@ -0,0 +1,70 @@ +--- +layout: post +title: "Internship at Mercari" +date: 2018-07-09 +comments: true +tags: +- Japan +- Mercari +- internship +--- +I'm back in Mumbai as I write this recap blog post describing my summer spent in the heart of Tokyo, during my internship at Mercari. This blog post is going to be specific to my internship. I've written about my travelling experiences in a [different post](https://nihal111.github.io/2018/07/09/japan-lookback.html). + +## About Mercari + +Mercari is a CtoC marketplace startup that was founded in 2013. Their main product is the Mercari CtoC marketplace app. In just 5 years, the company has skyrocketed to become Japan's largest community-driven marketplace. The company also gained the pre-IPO unicorn status, being a privately held company valued over $1 billion. This was before the company went public this June on the Toyko Stock Exchange’s Mothers Market, during my stay there. + +## The Office + +{: .center} +![Office View]({{ site.baseurl }}/img/mercari/officeview.jpg "Office View"){:style="max-height: 500px;"} + +The Mercari office is located on the 18th floor of Mori Tower, the 6th tallest building in Tokyo. The view from the office is fantastic and the breeze on the top, at the observation deck is better. There is a giant spider outside the office, that should remind you of [Enemy](http://silverscreensnobs.com/spiders-doppelgangers-secrets-enemy-expained/) if you're into sci-fi. + +{: .center} +![Mori Tower]({{ site.baseurl }}/img/mercari/moritower.jpg "Mori Tower"){:style="max-height: 500px;"} +![spider]({{ site.baseurl }}/img/mercari/spider.jpg "Spider"){:style="max-height: 500px;"} + +## The Honeymoon Phase +The first week was nothing short of overwhelming. Even for the honeymoon phase, things seemed too good to be true. The onboarding and orientation were smooth, and we were given our gear. We got company phones, portable wifi and the $2000 MacBook Pro amongst other goodies. + +{: .center} +![Gear]({{ site.baseurl }}/img/mercari/gear.jpg "Gear"){:style="max-height: 500px;"} + +We were assigned to our teams but were supposed to go through a week of orientation before beginning any work. The Global Operations Team took special effort to make us feel at home. They organised the multiple onboarding sessions and even took us out for a complete Tokyo tour on a weekday. + +{: .center} +![Tokyo Tour]({{ site.baseurl }}/img/mercari/tokyotour.jpg "Tokyo Tour"){:style="max-height: 500px;"} + +By week two, we were on our desks at our respective teams with the welcome balloons we received. + +{: .center} +![Balloons]({{ site.baseurl }}/img/mercari/balloons.jpg "Balloons"){:style="max-height: 500px;"} + +## The Android Team +I had the pleasure to work with the JP Android Team, the team working on the main marketplace app- [Mercari](https://play.google.com/store/apps/details?id=com.kouzoh.mercari) for Japan. It was a medium sized team with just over 10 people. The bulk of my task for the summer was to implement client facing feature on the Android app. I also worked on a few isolated issues all over the codebase and took the initiative to improve the code quality in the codebase which was very well received by the team. + +{: .center} +![Android Team]({{ site.baseurl }}/img/mercari/androidteam.jpg "Android Team"){:style="max-height: 500px;"} + +My team was largely global, consisting of a large number of Gaijins (Japanese for foreigners). I benefited hugely from this and learned how to work in a multi-cultural team. I learned the flow for how a spec moves to feature that gets shipped and how each detail in the middle matters. + +On the technical side, for the first time I **implemented a software architecture**, **wrote Kotlin code**, **wrote Unit tests using Mockito and Robolectric** and **created an automation task using CI**. I'm glad to have been able to achieve this in a small period of just over a month. + +{: .center} +![Desk]({{ site.baseurl }}/img/mercari/desk.jpg "Desk"){:style="max-height: 500px;"} + +My team was great in many ways, apart from the mentor lunches that all of us interns were entitled to, the Android team had a weekly team lunch. My team even put together a special farewell dinner for me, after which we ended up going to Karaoke. There was also this beautiful parting gift I received from my team- + +{: .center} +![rum]({{ site.baseurl }}/img/mercari/rum.jpg "rum"){:style="max-height: 500px;"} + +## Experience + +All in all, the whole experience over the course of my internship was more than I could have asked for. Mercari was great to me, and it was a crazy time to be there. Amidst the whole IPO frenzy and the company celebrating its 5th anniversary, I was lucky to go to all the parties. + +I learned how to work efficiently in a team, picked up on a few technical things, got to meet a whole bunch of great people, got exposed to a whole new culture and travelled as much as I could (more about that [here](https://nihal111.github.io/2018/07/09/japan-lookback.html)). + +--- + +Summer of '18 was one of the best summers I've had so far. Being home feels warm but itchy. \ No newline at end of file diff --git a/_posts/2018-09-27-us-visa-b1.markdown b/_posts/2018-09-27-us-visa-b1.markdown new file mode 100644 index 0000000..50abcf9 --- /dev/null +++ b/_posts/2018-09-27-us-visa-b1.markdown @@ -0,0 +1,109 @@ +--- +layout: post +title: "To hell and back again, US B1 Visa" +date: 2018-09-27 +comments: true +tags: +- Visa +--- + +Having been selected as one of the representatives from MovingBlocks, I was all excited about being able to attend the GSoC Mentor Summit for 2018. It would be the first time I would be travelling to the States. The timeline worked out well, and I was also able to fit Github Universe in my schedule. In little time, I had my flight tickets booked and reserved a room at the hotel provided by Google. Everything was in order and only acquiring the Visa remained. + +## The Visa Process +I started my Visa process around mid-August, filled out my DS160, made the 160$ payment and booked dates for the VAC (Biometrics) and VI (Consular Interview). The earliest date that I could find for the interview was 24th September. + +## Nearly there but oh, well +I reached just in time for my 10 AM appointment at the Mumbai consulate, owing to the deplorable peak-hour traffic. I had barely done any reading up about what the interview is like, apart from some tips shared on the GSoC mailing list and a few stories from friends. + +I had read about a good number of cases on the mailing thread, where fellow mentors had their Visa denied, and there was absolutely nothing that could be done after that. I had a word with the person standing next to me in the queue, who mentioned that it was his second attempt. The last time he had appeared, the interview lasted for 10 seconds. As soon as he said he was an IT professional, the Consular officer handed him the rejection letter saying- "I cannot approve your Visa this time". + +With these stories in my head, I was partly nervous but still convinced that my purpose of travelling was entirely legitimate. I had an invitation letter from Google, and I had to complete my undergraduate studies, which meant that I was bound to return. + +After a long wait, and slowly moving through the serpentine queue my turn arrived. While I was waiting at the counter, the person ahead of me had his Visa denied. As I walked up to the counter, I could see that the consular officer was unhappy. + +--- + +**Me:** Good morning +**Officer:** May I have your passport? +(I pass my passport) +**O:** Why would you be travelling to the United States? +**M:** To attend a conference. +(I kept my answers brief and answered only what I was asked. I had read this tip somewhere, and I was extra cautious to not annoy the officer further.) +**O:** What conference is this? +**M:** It's a conference about open source software. It's called the Google Summer of Code mentor summit. +(He starts looking at the screen and typing in something.) +**O:** Who would be paying for your trip? +**M:** Google would be paying. They would be paying 1100$ for every attendee, and if that falls short, my organisation can cover the rest. +(More typing and looking at the screen) +**O:** Are you pursuing your undergraduate studies? +**M:** Yes. I am a fourth-year student. +**O:** Do you have your old passports. May I see them? +(I pass my older passports) +**O:** What does your father do? +**M:** He is an engineer. He works at X. +**O:** Who pays for your education? +**M:** My father does. +(More typing. Longer this time.) +**O:** Your Visa application has been denied. The reason is written in this paper. You may apply again. + +--- + +Profoundly disappointed and dissatisfied with how the interview went, I left. I had carried a file with all the documents I could think of, and the interviewer didn't ask for even a single document. The paper given to me cited Section 214 (b) as the ground for denial, which essentially means I couldn't prove strong ties to my home country. Baseless in my case, since I needed to come back to finish my undergrad. + +My plans had come to an end. There was no way I could apply again. It took me more than a month to get my first appointment. I barely had 2 weeks before my flight, this time. + +## The Gamble +I heard from a friend ([Yashvardhan Didwania](https://mozillians.org/en-US/u/ydidwania/), thanks again) that it isn't all that impossible to get an appointment on a date before the expected waiting period. He had pulled it off in the past by continually refreshing the webpage and checking for available dates. When someone cancels or reschedules, an earlier date becomes available for a short while. That's when you grab it. + +The gamble was that I would have to pay 160$ before I become able to book an appointment. To get the Visa on my passport in time, I needed to get an interview date on or before October 8. There was a good chance that I would not get such a date but I decided to play the odds. + +I had to wait for the next day to start a new application since the website still showed my present-day appointment (24 September) as active. I filled out the DS-160 in the meantime and spent the entire day reading stories about Visa rejections and searching for ways to overcome them. I woke up on 25th September and at 10:21 AM, on my way to class, I made the MRV payment of 160$ again. I remember it took around 1-2 hours for my receipt to get activated and reflect on the website, last time. However, I kept checking during class, and the receipt was activated at sharp 11:00 AM. The earliest available date was 19 October at the Mumbai Consulate, as I had expected. Chennai had an earlier date of 3 October available, but I dropped that thought. Better judgement prevailed, and I kept refreshing the page hoping for a miracle to happen. At 11:21 AM, I made my last refresh, and to my surprise, the website now showed the earliest available date as 27th September. Within what were an intense 15 seconds, I had managed to secure my second interview on the 27th of September. It was unbelievable, and I was happy beyond my wits. + +## Turning my luck upside down + +Fast forward to 27th September. Again, I saw rejections all over the place and people returning with their passports. I saw three applicants have their Visa denied by the very same officer who had denied my Visa last time. I kept my head clear, and I approached the counter. + +--- + +**Me:** Good morning ma'am. +**Officer:** Good morning. May I have your passport? +*(I pass my passport along with the 4 most essential supporting documents)* +**O:** Why would you be travelling? +**M:** I am invited to attend a conference. The conference is called the Google Summer of Code Mentor Summit. It's a conference where mentors from different open source organisations come together to discuss how the Google Summer of Code program can be made better and how the open source community can improve as a whole. +**O:** I'm sorry, can you explain what the conference is about again? +**M:** Alright, so Google has a program called the Google Summer of Code wherein students participate by contributing to open source organisations. I am a student myself, and I participated in the summer of 2017 by contributing to an organisation called MovingBlocks. In 2018, I became a mentor. Each organisation is supposed to send two representatives to the Mentor Summit, to come together and discuss how the program can be improved. I would be representing MovingBlocks this time. +*(Looks at the screen, types a little)* +**O:** Who would be paying for your trip? +**M:** My expenses would be covered directly by my organisation. Google, in turn, would fund each organisation by paying 1100$ for each representative and also arranging for a hotel during the period of the conference. +*(She scrolls through the documents I forwarded)* +**O:** I see you have travelled to Japan recently. What was that for? +**M:** I was doing an internship in Japan in the past summer. *//Explain a little more* +**O:** Is there any other country you have travelled to? +**M:** Yes, *// Explain* +*(She starts typing and continues for a long time)* +*(I see her look up at the clock and press key combinations this time, she then keeps my passport on the side.)* +**O:** Your Visa application has been approved. Have a nice trip. +**M:** Thank you so much. + +--- + +I come to realise that I've pulled it off. The gamble had paid off perfectly well, and all plans were back on track. + +### Tips: + +The following are a few tips from my personal experience. I do not claim that these would generalize across different consulates and the following should not be considered in any way as formal/legal advice. + +1. Be confident. If you deserve the Visa, act like you already have it. +2. Always explain in great depth. Give no excuse to the officer to think that you're making things up. If the officer enjoys brevity, they will ask you to stop or shoot another question. +3. Push your papers forward initially. If they are returned, make further attempts to show them relevant papers whenever a document supports something you're saying. Remember, the burden of proof is on the applicant. +4. Hope for the best, expect the worst. In my opinion, the process is semi-arbitrary, and you may be unlucky to have a short interview or a grumpy interviewer. Be prepared for this and leave no effort in making sure you deliver all the information you can. +5. A denial is only temporary, and it can be turned easily if you have all the right reasons. Advice on forums echoed with- "Don't apply immediately after a rejection. Wait till your circumstances change". While this may be true, if you feel there was no real reason for your application to be rejected, applying again immediately may work in your favour. Here is a timeline of how I flipped my rejection in 4 days. + +***24th September - (VI appointment) Interview. Visa Denied*** +***25th September - Paid for next appointment.*** +***26th September - (VAC appointment) Biometrics*** +***27th September - (VI appointment) Interview. Visa approved.*** + +--- + +I'm delighted that my gamble worked out well and excited more than ever to fly to California. diff --git a/_posts/2018-11-25-pommerman-rl.markdown b/_posts/2018-11-25-pommerman-rl.markdown new file mode 100644 index 0000000..c0fe035 --- /dev/null +++ b/_posts/2018-11-25-pommerman-rl.markdown @@ -0,0 +1,29 @@ +--- +layout: post +title: "Pommerman- Reinforcement Learning Project" +date: 2018-11-25 +comments: true +tags: +- Machine Learning +- Reinforcement Learning +--- + + +As the course project for CS 747 - Foundations of Intelligent & Learning Agents, Fall 2018, I teamed up with Chinmay Talegaonkar and Dhruv Shah to take on the [Pommerman Challenge](https://www.pommerman.com/). + + +{: .center} +![Pommerman]({{ site.baseurl }}/img/pommerman.gif "Pommerman"){:style="max-height: 500px;"} + +The Pommerman Challenge essentially serves as a test bed for multi-agent learning algorithms. It is essentially a clone of the popular Bomberman game, providing a constantly changing environment with bombs going off, power-ups to be collected and other agents to be eliminated. There are mainly two modes to the game, **FFA**- where each of the four agents battle against each other and the last one to survive wins, **Team**- where there are two teams of two agents which compete against each other. + +We took on the FFA challenge, trying a few different approaches. After facing a few hurdles, we found that the DQfD agent performed remarkably well as against our other approaches. + +Our experiments and approaches are detailed here- [Report]({{ site.baseurl }}/docs/pommerman_report.pdf) + +To see our agent in action, watch the video below- + + + + + diff --git a/_sass/_base.scss b/_sass/_base.scss new file mode 100644 index 0000000..63428ca --- /dev/null +++ b/_sass/_base.scss @@ -0,0 +1,102 @@ +$content-width: 800px; +$main: #19CCAA; +$font-style: 'Open Sans', sans-serif; +$font-color: #262626; +$link-color: #425469; +$link-hover-color: $main; +$heading-font: 'Muli', sans-serif; +$heading-font-color: #425469; +$light: #E7EDF4; +$header: #1D1425; + +$blue: #4183C4; +$black: #000; +$darkerGray: #222; +$darkGray: #333; +$gray: #666; +$lightGray: #eee; +$white: #fff; + +$grey-color: #828282; +$grey-color-light: lighten($grey-color, 40%); +$grey-color-dark: darken($grey-color, 25%); + +$spacing-unit: 30px; +$on-palm: 600px; +$on-laptop: 800px; + +$helvetica: Helvetica, Arial, sans-serif; +$helveticaNeue: 'Helvetica Neue', Helvetica, Arial, sans-serif; +$georgia: Georgia, serif; + +*, +*::before, +*::after { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +// Mobile breakpoints +@mixin mobile { + @media screen and (max-width: 640px) { + @content; + } +} + +@mixin media-query($device) { + @media screen and (max-width: $device) { + @content; + } +} + + + +/** + * Wrapper + */ +.wrapper { + max-width: -webkit-calc(#{$content-width} - (#{$spacing-unit} * 2)); + max-width: calc(#{$content-width} - (#{$spacing-unit} * 2)); + margin-right: auto; + margin-left: auto; + @extend %clearfix; + + @include media-query($on-laptop) { + max-width: -webkit-calc(#{$content-width} - (#{$spacing-unit})); + max-width: calc(#{$content-width} - (#{$spacing-unit})); + } +} + + + +/** + * Clearfix + */ +%clearfix { + + &:after { + content: ""; + display: table; + clear: both; + } +} + + + +/** + * Icons + */ +.icon { + + > svg { + display: inline-block; + width: 16px; + height: 16px; + vertical-align: middle; + + path { + fill: $grey-color; + } + } +} diff --git a/_sass/_github-buttons.scss b/_sass/_github-buttons.scss new file mode 100644 index 0000000..822d490 --- /dev/null +++ b/_sass/_github-buttons.scss @@ -0,0 +1,192 @@ +*, +*:before, +*:after { + box-sizing: border-box; +} + +.github-button { + display: block; + position: relative; + padding: .75em 5em .75em 1em; + border-radius: .25em; + margin-bottom: .5em; + background: #fff; +} + +.open-PR-button { + box-shadow: + 0 .0625em .125em rgba(0, 0, 0, .125), + inset 0 -.25em 0 -.125em rgba(0, 0, 0, .125), + inset 7.5em 0 0 -.7em rgba(20, 160, 0, .8), + inset -4em 0 0 -.3em rgba(20, 160, 0, .8); +} + +.merged-PR-button { + box-shadow: + 0 .0625em .125em rgba(0, 0, 0, .125), + inset 0 -.25em 0 -.125em rgba(0, 0, 0, .125), + inset 7.5em 0 0 -.7em rgba(30, 144, 255, .5), + inset -4em 0 0 -.3em rgba(30, 144, 255, .5); +} + +.open-issue-button { + box-shadow: + 0 .0625em .125em rgba(0, 0, 0, .125), + inset 0 -.25em 0 -.125em rgba(0, 0, 0, .125), + inset 7.5em 0 0 -.7em rgba(20, 160, 0, .5), + inset -4em 0 0 -.3em rgba(20, 160, 0, .5); +} + +.closed-issue-button { + box-shadow: + 0 .0625em .125em rgba(0, 0, 0, .125), + inset 0 -.25em 0 -.125em rgba(0, 0, 0, .125), + inset 7.5em 0 0 -.7em rgba(178, 34, 34, .8), + inset -4em 0 0 -.3em rgba(178, 34, 34, .8); +} + +.number { + position: absolute; + font-family: "Lucida Console", Monaco, monospace; + font-size: 24pt; + height: 4em; + width: 3.6em; + overflow: hidden; + text-overflow: ellipsis; + text-align: center; + left: .125em; + top: 0.5em; + color: #000; +} + +.number:hover { + font-weight: bold; + color: #000; +} + +.title { + margin-left: 6em; + display: block; + font-size: 14pt; + font-weight: bold; + color: #000; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; +} + +.title:after { + content: ''; + display: block; + height: 0; + width: 100%; +} + +.meta { + display: block; + margin-left: 7em; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + font-size: 12pt; + line-height: 2; /* 16 "px" */ + font-weight: bold; + color: #2f4f4f; +} + +.repo { + font-weight: bold; + color: #2f4f4f; +} + +.date { + font-weight: bold; + color: #2f4f4f; +} + +.date:before { + content: ' '; + font-weight: normal; +} + +.octicon-clock { + display: inline-block; + margin-left: .333em; +} + +.right-icon { + display: block; + position: absolute; + right: 0.5em; + top: 50%; + margin-top: -.6em; +} + +@media screen and (max-width: 600px) { + .github-button { + padding: .75em 5em .75em 1em; + border-radius: .25em; + margin-bottom: .5em; + } + + .open-PR-button { + box-shadow: + 0 .0625em .125em rgba(0, 0, 0, .125), + inset 0 -.25em 0 -.125em rgba(0, 0, 0, .125), + inset 4em 0 0 -.7em rgba(20, 160, 0, .8), + inset -3em 0 0 -.3em rgba(20, 160, 0, .8); + } + + .merged-PR-button { + box-shadow: + 0 .0625em .125em rgba(0, 0, 0, .125), + inset 0 -.25em 0 -.125em rgba(0, 0, 0, .125), + inset 4em 0 0 -.7em rgba(30, 144, 255, .5), + inset -3em 0 0 -.3em rgba(30, 144, 255, .5); + } + + .open-issue-button { + box-shadow: + 0 .0625em .125em rgba(0, 0, 0, .125), + inset 0 -.25em 0 -.125em rgba(0, 0, 0, .125), + inset 4em 0 0 -.7em rgba(20, 160, 0, .5), + inset -3em 0 0 -.3em rgba(20, 160, 0, .5); + } + + .closed-issue-button { + box-shadow: + 0 .0625em .125em rgba(0, 0, 0, .125), + inset 0 -.25em 0 -.125em rgba(0, 0, 0, .125), + inset 4em 0 0 -.7em rgba(178, 34, 34, .8), + inset -3em 0 0 -.3em rgba(178, 34, 34, .8); + } + + .number { + font-size: 13pt; + height: 4em; + width: 3em; + left: 0.125em; + top: 1.25em; + } + + .title { + margin-left: 3.5em; + font-size: 10pt; + } + + .meta { + margin-left: 4.25em; + font-size: 8pt; + line-height: 2; /* 16 "px" */ + } + + .octicon-clock { + margin-left: .333em; + } + + .right-icon { + right: 0.25em; + top: 50%; + margin-top: -.6em; + } +} \ No newline at end of file diff --git a/_sass/_icons.scss b/_sass/_icons.scss new file mode 100644 index 0000000..cdf52c9 --- /dev/null +++ b/_sass/_icons.scss @@ -0,0 +1,527 @@ +@font-face { + font-family:"nihal111"; + src:url("../fonts/nihal111.ttf?cgaqog") format("truetype"),url("../fonts/nihal111.woff?cgaqog") format("woff"),url("../fonts/nihal111.svg?cgaqog#nihal111") format("svg"); + font-weight:normal; + font-style:normal +} +.icon { + font-family:"nihal111" !important; + speak:none; + font-style:normal; + font-weight:normal; + font-variant:normal; + text-transform:none; + line-height:1; + -webkit-font-smoothing:antialiased; + -moz-osx-font-smoothing:grayscale +} +.icon-home:before { + content:"" +} +.icon-pencil:before { + content:"" +} +.icon-image:before { + content:"" +} +.icon-images:before { + content:"" +} +.icon-camera:before { + content:"" +} +.icon-headphones:before { + content:"" +} +.icon-music:before { + content:"" +} +.icon-play:before { + content:"" +} +.icon-price-tag:before { + content:"" +} +.icon-price-tags:before { + content:"" +} +.icon-barcode:before { + content:"" +} +.icon-qrcode:before { + content:"" +} +.icon-cart:before { + content:"" +} +.icon-phone:before { + content:"" +} +.icon-phone-hang-up:before { + content:"" +} +.icon-address-book:before { + content:"" +} +.icon-envelop:before { + content:"" +} +.icon-location:before { + content:"" +} +.icon-location2:before { + content:"" +} +.icon-calendar:before { + content:"" +} +.icon-keyboard:before { + content:"" +} +.icon-display:before { + content:"" +} +.icon-laptop:before { + content:"" +} +.icon-mobile:before { + content:"" +} +.icon-mobile2:before { + content:"" +} +.icon-drawer:before { + content:"" +} +.icon-drawer2:before { + content:"" +} +.icon-floppy-disk:before { + content:"" +} +.icon-undo:before { + content:"" +} +.icon-redo:before { + content:"" +} +.icon-undo2:before { + content:"" +} +.icon-redo2:before { + content:"" +} +.icon-bubble:before { + content:"" +} +.icon-bubbles2:before { + content:"" +} +.icon-bubble2:before { + content:"" +} +.icon-bubbles4:before { + content:"" +} +.icon-user:before { + content:"" +} +.icon-users:before { + content:"" +} +.icon-user-tie:before { + content:"" +} +.icon-quotes-left:before { + content:"" +} +.icon-quotes-right:before { + content:"" +} +.icon-spinner2:before { + content:"" +} +.icon-spinner5:before { + content:"" +} +.icon-spinner8:before { + content:"" +} +.icon-spinner11:before { + content:"" +} +.icon-search:before { + content:"" +} +.icon-zoom-in:before { + content:"" +} +.icon-zoom-out:before { + content:"" +} +.icon-enlarge:before { + content:"" +} +.icon-shrink:before { + content:"" +} +.icon-enlarge2:before { + content:"" +} +.icon-shrink2:before { + content:"" +} +.icon-lock:before { + content:"" +} +.icon-unlocked:before { + content:"" +} +.icon-wrench:before { + content:"" +} +.icon-equalizer2:before { + content:"" +} +.icon-cog:before { + content:"" +} +.icon-cogs:before { + content:"" +} +.icon-bug:before { + content:"" +} +.icon-pie-chart:before { + content:"" +} +.icon-stats-dots:before { + content:"" +} +.icon-stats-bars:before { + content:"" +} +.icon-mug:before { + content:"" +} +.icon-bin:before { + content:"" +} +.icon-briefcase:before { + content:"" +} +.icon-airplane:before { + content:"" +} +.icon-truck:before { + content:"" +} +.icon-switch:before { + content:"" +} +.icon-power-cord:before { + content:"" +} +.icon-clipboard:before { + content:"" +} +.icon-menu:before { + content:"" +} +.icon-menu2:before { + content:"" +} +.icon-menu3:before { + content:"" +} +.icon-menu4:before { + content:"" +} +.icon-cloud:before { + content:"" +} +.icon-cloud-download:before { + content:"" +} +.icon-cloud-upload:before { + content:"" +} +.icon-cloud-check:before { + content:"" +} +.icon-earth:before { + content:"" +} +.icon-link:before { + content:"" +} +.icon-attachment:before { + content:"" +} +.icon-eye:before { + content:"" +} +.icon-eye-blocked:before { + content:"" +} +.icon-star-empty:before { + content:"" +} +.icon-star-half:before { + content:"" +} +.icon-star-full:before { + content:"" +} +.icon-heart:before { + content:"" +} +.icon-man:before { + content:"" +} +.icon-woman:before { + content:"" +} +.icon-man-woman:before { + content:"" +} +.icon-warning:before { + content:"" +} +.icon-notification:before { + content:"" +} +.icon-question:before { + content:"" +} +.icon-plus:before { + content:"" +} +.icon-minus:before { + content:"" +} +.icon-info:before { + content:"" +} +.icon-cancel-circle:before { + content:"" +} +.icon-blocked:before { + content:"" +} +.icon-cross:before { + content:"" +} +.icon-checkmark:before { + content:"" +} +.icon-checkmark2:before { + content:"" +} +.icon-loop2:before { + content:"" +} +.icon-infinite:before { + content:"" +} +.icon-shuffle:before { + content:"" +} +.icon-arrow-right2:before { + content:"" +} +.icon-arrow-left2:before { + content:"" +} +.icon-circle-up:before { + content:"" +} +.icon-circle-right:before { + content:"" +} +.icon-circle-down:before { + content:"" +} +.icon-circle-left:before { + content:"" +} +.icon-shift:before { + content:"" +} +.icon-ctrl:before { + content:"" +} +.icon-checkbox-checked:before { + content:"" +} +.icon-checkbox-unchecked:before { + content:"" +} +.icon-radio-checked:before { + content:"" +} +.icon-radio-unchecked:before { + content:"" +} +.icon-filter:before { + content:"" +} +.icon-share:before { + content:"" +} +.icon-new-tab:before { + content:"" +} +.icon-embed:before { + content:"" +} +.icon-embed2:before { + content:"" +} +.icon-terminal:before { + content:"" +} +.icon-share2:before { + content:"" +} +.icon-mail:before { + content:"" +} +.icon-mail2:before { + content:"" +} +.icon-mail3:before { + content:"" +} +.icon-mail4:before { + content:"" +} +.icon-google3:before { + content:"" +} +.icon-google-plus:before { + content:"" +} +.icon-google-plus2:before { + content:"" +} +.icon-google-plus3:before { + content:"" +} +.icon-hangouts:before { + content:"" +} +.icon-google-drive:before { + content:"" +} +.icon-facebook:before { + content:"" +} +.icon-facebook2:before { + content:"" +} +.icon-instagram:before { + content:"" +} +.icon-whatsapp:before { + content:"" +} +.icon-spotify:before { + content:"" +} +.icon-telegram:before { + content:"" +} +.icon-twitter:before { + content:"" +} +.icon-rss:before { + content:"" +} +.icon-rss2:before { + content:"" +} +.icon-youtube:before { + content:"" +} +.icon-vimeo:before { + content:"" +} +.icon-flickr2:before { + content:"" +} +.icon-dribbble:before { + content:"" +} +.icon-behance:before { + content:"" +} +.icon-behance2:before { + content:"" +} +.icon-dropbox:before { + content:"" +} +.icon-github:before { + content:"" +} +.icon-trello:before { + content:"" +} +.icon-wordpress:before { + content:"" +} +.icon-joomla:before { + content:"" +} +.icon-tux:before { + content:"" +} +.icon-appleinc:before { + content:"" +} +.icon-finder:before { + content:"" +} +.icon-android:before { + content:"" +} +.icon-skype:before { + content:"" +} +.icon-linkedin:before { + content:"" +} +.icon-linkedin2:before { + content:"" +} +.icon-chrome:before { + content:"" +} +.icon-firefox:before { + content:"" +} +.icon-IE:before { + content:"" +} +.icon-edge:before { + content:"" +} +.icon-safari:before { + content:"" +} +.icon-opera:before { + content:"" +} +.icon-html-five:before { + content:"" +} +.icon-html-five2:before { + content:"" +} +.icon-css3:before { + content:"" +} +.icon-git:before { + content:"" +} \ No newline at end of file diff --git a/_sass/_layout.scss b/_sass/_layout.scss new file mode 100644 index 0000000..2deab32 --- /dev/null +++ b/_sass/_layout.scss @@ -0,0 +1,628 @@ +body { + margin: 0; + color: $font-color; + font-family: $font-style; + font-size: 1.1em; + line-height: 1.6; + -webkit-font-smoothing: antialiased; +} + +h1, h2, h3, h4, h5, h6 { + font-family: $helveticaNeue; + color: $darkerGray; + font-weight: bold; + + line-height: 1.7; + margin: 1em 0 15px; + padding: 0; + + @include mobile { + line-height: 1.4; + } +} + +h1 { + font-size: 30px; + a { + color: inherit; + } +} + +h2 { + font-size: 24px; +} + +h4 { + font-size: 18px; + color: $gray; +} + +a { + color: $blue; + text-decoration: none; + cursor: pointer; + &:hover, &:active { + color: $blue; + } +} + + +main { + padding: 0 15px; + max-width: $content-width; + margin: 0 auto; +} +time { + color: #898989; +} + +.container { + margin: 0 auto; + max-width: 740px; + padding: 0 10px; + width: 100%; +} + +/* Aside */ + +aside { + position: fixed; + top: 0; + left: 0; + background: #fff; + width: 100%; + z-index: 2; + border-bottom: 1px solid lighten($light, 30%); + box-shadow: 0px 1px 1px RGBA(4, 25, 54, .1); + nav { + float: left; + max-width: 800px; + margin: 0 auto; + ul { + margin: 0; + padding: 0; + list-style: none; + li { + float: left; + position: relative; + a { + text-decoration: none; + display: block; + padding: 15px; + font-family: 'Muli', sans-serif; + line-height: 20px; + margin-bottom: -1px; + box-shadow: 0; + &:hover, + &:active { + background: $header; + text-decoration: none; + color: $main; + } + } + } + } + &:after { + content: ''; + display: table; + clear: both; + } + } +} + +.wrapper-masthead { + margin-top: 50px; + margin-bottom: 50px; +} + +.masthead { + padding: 20px 0; + border-bottom: 1px solid ; + + @include mobile { + text-align: center; + } +} + +.clearfix:before, +.clearfix:after { + content: " "; + display: table; +} + +.clearfix:after { + clear: both; +} + + +.site-avatar { + + + @include mobile { + float: none; + display: block; + margin: 0 auto; + } + + img { + float: left; + width: 70px; + height: 70px; + margin-right: 15px; + border-radius: 5px; + } +} + +.site-info { + float: left; + + @include mobile { + float: none; + display: block; + margin: 0 auto; + } +} + +.site-name { + margin: 0; + color: $darkGray; + cursor: pointer; + font-family: $helveticaNeue; + font-weight: 300; + font-size: 28px; + letter-spacing: 1px; +} + +.site-description { + margin: -5px 0 0 0; + color: $gray; + font-size: 16px; + + @include mobile { + margin: 3px 0; + } +} + + +.darken { + transition: all .2s ease; + opacity: .5; + margin: 0; + box-shadow: none; + &:hover { + opacity: .9; + } +} + +nav { + float: right; + margin-top: 23px; // @TODO: Vertically middle align + font-family: $helveticaNeue; + font-size: 18px; + + @include mobile { + float: none; + margin-top: 9px; + display: block; + font-size: 16px; + } + + a { + margin-left: 20px; + color: $darkGray; + text-align: right; + font-weight: 300; + letter-spacing: 1px; + + @include mobile { + margin: 0 10px; + } + } +} + + + +.site-title { + font-weight:300; + line-height:56px; + margin-bottom:-1px; + float:left; + color: #111; + letter-spacing: 1px; + text-decoration: none; + display: block; + padding: 0 15px; + font-family: 'Muli', sans-serif; + box-shadow: 0; + &:hover, + &:active { + background: $header; + text-decoration: none; + color: $main; + } + + @include mobile { + margin: 0 10px; + } +} +.site-nav { float: right; line-height: 56px; } +.site-nav .menu-icon { display: none; } +.site-nav .page-link { color: #111; line-height: 1.5; } +.site-nav .page-link:not(:last-child) { margin-right: 20px; } +@include mobile { + .site-nav { position: absolute; top: 9px; right: 15px; background-color: #fdfdfd; border: 1px solid #e8e8e8; border-radius: 5px; text-align: right; } + .site-nav .menu-icon { display: block; float: right; width: 36px; height: 26px; line-height: 0; padding-top: 10px; text-align: center; } + .site-nav ul { margin: 0; + padding: 0; + max-width: 120px;} + .site-nav .menu-icon > svg { width: 18px; height: 10px; } + .site-nav .menu-icon > svg path { fill: #424242; } + .site-nav .trigger { clear: both; display: none; } + .site-nav:hover .trigger { display: block; padding-bottom: 5px; } + .site-nav .page-link { display: block; padding: 5px 10px; margin-left: 20px; } + .site-nav .page-link:not(:last-child) { margin-right: 0; } +} + + +/** + * Site footer + */ +.site-footer { + border-top: 1px solid $grey-color-light; + padding: $spacing-unit 0; +} + +.footer-heading { + font-size: 18px; + display: block; + font-weight: 400; + margin: 0px; + padding: 0px; + margin-bottom: $spacing-unit / 2; +} + +.contact-list, +.social-media-list { + list-style: none; + margin-left: 0; + padding : 0; + .name{ + font-size: 20px; + color : $font-color; + font-family : $georgia; + } +} + +.abode { + font-size: 20px; + color : $font-color; + font-family : $georgia; + margin-top: 10px; + margin-bottom: 0; +} + +.footer-col-wrapper { + font-size: 15px; + color: $grey-color; + margin: auto; + @extend %clearfix; +} + +.footer-col { + float: left; + margin-bottom: $spacing-unit / 2; + padding-left: $spacing-unit / 2; + max-width: 350px; +} + +.footer-col-1 { + width: -webkit-calc(35% - (#{$spacing-unit} / 2)); + width: calc(35% - (#{$spacing-unit} / 2)); +} + +.footer-col-2 { + width: -webkit-calc(30% - (#{$spacing-unit} / 2)); + width: calc(30% - (#{$spacing-unit} / 2)); +} + +.footer-filler{ + width: -webkit-calc(15% - (#{$spacing-unit} / 2)); + width: calc(15% - (#{$spacing-unit} / 2)); +} +.footer-col-3 { + width: -webkit-calc(20% - (#{$spacing-unit} / 2)); + width: calc(20% - (#{$spacing-unit} / 2)); +} + + + +@include media-query($on-laptop) { + .footer-col-1, + .footer-col-2 { + width: -webkit-calc(50% - (#{$spacing-unit} / 2)); + width: calc(50% - (#{$spacing-unit} / 2)); + } + + .footer-col-3 { + width: -webkit-calc(100% - (#{$spacing-unit} / 2)); + width: calc(100% - (#{$spacing-unit} / 2)); + } +} + +@include media-query($on-palm) { + .footer-col { + float: none; + width: -webkit-calc(100% - (#{$spacing-unit} / 2)); + width: calc(100% - (#{$spacing-unit} / 2)); + } +} + +// for tag cloud and archives +.tag-cloud { + list-style: none; + padding: 0; + text-align: justify; + font-size: 16px; + li { + display: inline-block; + margin: 0 12px 12px 0; + } +} +#archives { + padding: 5px; +} +.archive-group { + margin: 5px; + border-top: 1px solid #ddd; +} +.archive-item { + margin-left: 5px; +} + +.tag { + padding: 0px 6px; + border-radius: 3px; + font-size: 1.1rem; + background: #ededed; + color: #666; + letter-spacing: 1px; + margin: 0 0.5rem; + text-decoration: none; +} + +.tag-date { + position: relative; + top: 2px; + margin: 0; + width: 25%; + float: right; + font-weight: 300; + color: #FFF; + text-align: right; + font-size: 1.2rem; +} + +.tag-link { + :hover{ + color: $blue; + } +} + + +/* For images */ +.center { + text-align: center; +} +.center img { + max-width: 100%; +} +.w10 img { + width: 10%; +} +.w20 img { + width: 20%; +} +.w25 img { + width: 25%; +} +.w30 img { + width: 30%; +} +.w40 img { + width: 40%; +} +.w50 img { + width: 50%; +} +.w60 img { + width: 60%; +} +.w70 img { + width: 70%; +} +.w75 img { + width: 70%; +} +.w80 img { + width: 80%; +} +.w90 img { + width: 90%; +} +.w100 img { + width: 100%; +} + +/* For iframe videos */ +.videowrapper { + float: none; + clear: both; + width: 100%; + position: relative; + padding-bottom: 56.25%; + padding-top: 25px; + height: 0; +} +.videowrapper iframe { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; +} + + +/* For new home/landing page */ + +.hero { + display:table; + margin-top: 150px; + width:100%; + height:100%; +} +.hero-inner { + width:100%; + display:table-cell; + vertical-align:middle; + text-align:center; +} +.hero-inner .dot { + padding:5px; + border:1px solid #dedede; +} +.hero-inner h1,.hero-inner h3 { + max-width:760px; + display:block; +} +.hero-inner h1 { + margin-top:.7em; + font-size:2.5rem; + margin:0 auto; +} +.hero-inner h3 { + font-size:1.25rem; + margin:.8em auto 1.2em; +} +.hero-inner h3,.hero-inner em { + font-weight:300; +} +.hero-inner em { + color:#337ab7; +} +.hero-inner strong { + font-weight:700; +} +.dot { + max-height: 200px; + border-radius:50%; +} + +.hero-container { + max-width:420px; + margin-left:auto; + margin-right:auto; + padding-left:1.5em; + padding-right:1.5em; +} +@media screen and (min-width: 768px) { + .hero-container { + max-width:768px; + } +} +@media screen and (min-width: 1240px) { + .hero-container { + max-width:960px; + } +} +button,input[type="button"],input[type="reset"],input[type="submit"],.button,.toggle-navbar-button { + appearance:none; + background-color:#337ab7; + border:0; + border-radius:6px; + color:#fff; + cursor:pointer; + display:inline-block; + font-family:inherit; + font-size:inherit; + -webkit-font-smoothing:antialiased; + font-weight:700; + line-height:1; + padding:.75em 1.5em; + text-decoration:none; + transition:background-color .3s ease-in-out; + user-select:none; + vertical-align:middle; + white-space:nowrap; +} +button:hover,input[type="button"]:hover,input[type="reset"]:hover,input[type="submit"]:hover,.button:hover,.toggle-navbar-button:hover,button:focus,input[type="button"]:focus,input[type="reset"]:focus,input[type="submit"]:focus,.button:focus,.toggle-navbar-button:focus { + background-color:#296292; +} +button.disabled,input.disabled[type="button"],input.disabled[type="reset"],input.disabled[type="submit"],.disabled.button,.disabled.toggle-navbar-button,button:disabled,input[type="button"]:disabled,input[type="reset"]:disabled,input[type="submit"]:disabled,.button:disabled,.toggle-navbar-button:disabled { + color:inherit; + cursor:not-allowed; + box-shadow:none; + opacity:.65; +} +button.disabled:hover,input.disabled[type="button"]:hover,input.disabled[type="reset"]:hover,input.disabled[type="submit"]:hover,.disabled.button:hover,.disabled.toggle-navbar-button:hover,button.disabled:focus,input.disabled[type="button"]:focus,input.disabled[type="reset"]:focus,input.disabled[type="submit"]:focus,.disabled.button:focus,.disabled.toggle-navbar-button:focus,button:disabled:hover,input[type="button"]:disabled:hover,input[type="reset"]:disabled:hover,input[type="submit"]:disabled:hover,.button:disabled:hover,.toggle-navbar-button:disabled:hover,button:disabled:focus,input[type="button"]:disabled:focus,input[type="reset"]:disabled:focus,input[type="submit"]:disabled:focus,.button:disabled:focus,.toggle-navbar-button:disabled:focus { + color:inherit; + background:none transparent; +} + +.button-ghost { + background-color:transparent; + border:2px solid #337ab7; + color:#337ab7; + margin-bottom:2px; +} +.button-ghost:hover,.button-ghost:focus { + color:#fff; +} + + +.social { + padding:1.5em 0; +} +.social li { + display:inline-block; + padding:0 .6em; +} +.social a { + color:#9a9a9a; +} +.social a:hover,.social a:active,.social a:focus { + color:#337ab7; +} +.social i { + font-size:1.6em; +} + + + +/* Blog list page each element*/ +.blog_ele { + display: block; + margin: 0 0 50px 0; +} + +.blog_ele time { + float:right; + position: relative; + top: 2px; + margin: 0; + width: 35%; + float: right; + font-size: 1.1em; + color: #898989; + text-align: right; +} + +.blog_ele h3 { + margin: 0; + width: 75%; + color: #4183C4; +} +@media screen and (min-width: 400px) { + .blog_ele { + margin: 20px 0; + } +} \ No newline at end of file diff --git a/_sass/_syntax-highlighting.scss b/_sass/_syntax-highlighting.scss new file mode 100644 index 0000000..567a5d2 --- /dev/null +++ b/_sass/_syntax-highlighting.scss @@ -0,0 +1,78 @@ +/** + * Syntax highlighting styles + */ +.highlight { + background: #fff; + + .c { color: #998; font-style: italic } // Comment + .err { color: #a61717; background-color: #e3d2d2 } // Error + .k { font-weight: bold } // Keyword + .o { font-weight: bold } // Operator + .cm { color: #998; font-style: italic } // Comment.Multiline + .cp { color: #999; font-weight: bold } // Comment.Preproc + .c1 { color: #998; font-style: italic } // Comment.Single + .cs { color: #999; font-weight: bold; font-style: italic } // Comment.Special + .gd { color: #000; background-color: #fdd } // Generic.Deleted + .gd .x { color: #000; background-color: #faa } // Generic.Deleted.Specific + .ge { font-style: italic } // Generic.Emph + .gr { color: #a00 } // Generic.Error + .gh { color: #999 } // Generic.Heading + .gi { color: #000; background-color: #dfd } // Generic.Inserted + .gi .x { color: #000; background-color: #afa } // Generic.Inserted.Specific + .go { color: #888 } // Generic.Output + .gp { color: #555 } // Generic.Prompt + .gs { font-weight: bold } // Generic.Strong + .gu { color: #aaa } // Generic.Subheading + .gt { color: #a00 } // Generic.Traceback + .kc { font-weight: bold } // Keyword.Constant + .kd { font-weight: bold } // Keyword.Declaration + .kp { font-weight: bold } // Keyword.Pseudo + .kr { font-weight: bold } // Keyword.Reserved + .kt { color: #458; font-weight: bold } // Keyword.Type + .m { color: #099 } // Literal.Number + .s { color: #d14 } // Literal.String + .na { color: #008080 } // Name.Attribute + .nb { color: #0086B3 } // Name.Builtin + .nc { color: #458; font-weight: bold } // Name.Class + .no { color: #008080 } // Name.Constant + .ni { color: #800080 } // Name.Entity + .ne { color: #900; font-weight: bold } // Name.Exception + .nf { color: #900; font-weight: bold } // Name.Function + .nn { color: #555 } // Name.Namespace + .nt { color: #000080 } // Name.Tag + .nv { color: #008080 } // Name.Variable + .ow { font-weight: bold } // Operator.Word + .w { color: #bbb } // Text.Whitespace + .mf { color: #099 } // Literal.Number.Float + .mh { color: #099 } // Literal.Number.Hex + .mi { color: #099 } // Literal.Number.Integer + .mo { color: #099 } // Literal.Number.Oct + .sb { color: #d14 } // Literal.String.Backtick + .sc { color: #d14 } // Literal.String.Char + .sd { color: #d14 } // Literal.String.Doc + .s2 { color: #d14 } // Literal.String.Double + .se { color: #d14 } // Literal.String.Escape + .sh { color: #d14 } // Literal.String.Heredoc + .si { color: #d14 } // Literal.String.Interpol + .sx { color: #d14 } // Literal.String.Other + .sr { color: #009926 } // Literal.String.Regex + .s1 { color: #d14 } // Literal.String.Single + .ss { color: #990073 } // Literal.String.Symbol + .bp { color: #999 } // Name.Builtin.Pseudo + .vc { color: #008080 } // Name.Variable.Class + .vg { color: #008080 } // Name.Variable.Global + .vi { color: #008080 } // Name.Variable.Instance + .il { color: #099 } // Literal.Number.Integer.Long +} + +pre { + white-space: pre-wrap; /* css-3 */ + white-space: -moz-pre-wrap; /* Mozilla, since 1999 */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + word-wrap: break-word; /* Internet Explorer 5.5+ */ +} + +code.highlighter-rouge { + background-color: #d3d3d3; +} \ No newline at end of file diff --git a/_site/blog/index.html b/_site/blog/index.html new file mode 100644 index 0000000..5a7111f --- /dev/null +++ b/_site/blog/index.html @@ -0,0 +1,435 @@ + + + + + + + + Nihal Singh + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+

Nihal Singh

+

I like to know things

+
+ + + +
+
+
+ +
+
+

Blog

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + diff --git a/_site/css/main.css b/_site/css/main.css new file mode 100644 index 0000000..1a7b2ac --- /dev/null +++ b/_site/css/main.css @@ -0,0 +1,898 @@ +*, +*::before, +*::after { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; } + +/** + * Wrapper + */ +.wrapper { + max-width: -webkit-calc(800px - (30px * 2)); + max-width: calc(800px - (30px * 2)); + margin-right: auto; + margin-left: auto; } + @media screen and (max-width: 800px) { + .wrapper { + max-width: -webkit-calc(800px - (30px)); + max-width: calc(800px - (30px)); } } + +/** + * Clearfix + */ +.wrapper:after, .footer-col-wrapper:after { + content: ""; + display: table; + clear: both; } + +/** + * Icons + */ +.icon > svg { + display: inline-block; + width: 16px; + height: 16px; + vertical-align: middle; } + .icon > svg path { + fill: #828282; } + +body { + margin: 0; + color: #262626; + font-family: "Open Sans", sans-serif; + font-size: 1.1em; + line-height: 1.6; + -webkit-font-smoothing: antialiased; } + +h1, h2, h3, h4, h5, h6 { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + color: #222; + font-weight: bold; + line-height: 1.7; + margin: 1em 0 15px; + padding: 0; } + @media screen and (max-width: 640px) { + h1, h2, h3, h4, h5, h6 { + line-height: 1.4; } } + +h1 { + font-size: 30px; } + h1 a { + color: inherit; } + +h2 { + font-size: 24px; } + +h4 { + font-size: 18px; + color: #666; } + +a { + color: #4183C4; + text-decoration: none; + cursor: pointer; } + a:hover, a:active { + color: #4183C4; } + +main { + padding: 0 15px; + max-width: 800px; + margin: 0 auto; } + +time { + color: #898989; } + +.container { + margin: 0 auto; + max-width: 740px; + padding: 0 10px; + width: 100%; } + +/* Aside */ +aside { + position: fixed; + top: 0; + left: 0; + background: #fff; + width: 100%; + z-index: 2; + border-bottom: 1px solid white; + box-shadow: 0px 1px 1px RGBA(4, 25, 54, 0.1); } + aside nav { + float: left; + max-width: 800px; + margin: 0 auto; } + aside nav ul { + margin: 0; + padding: 0; + list-style: none; } + aside nav ul li { + float: left; + position: relative; } + aside nav ul li a { + text-decoration: none; + display: block; + padding: 15px; + font-family: 'Muli', sans-serif; + line-height: 20px; + margin-bottom: -1px; + box-shadow: 0; } + aside nav ul li a:hover, aside nav ul li a:active { + background: #1D1425; + text-decoration: none; + color: #19CCAA; } + aside nav:after { + content: ''; + display: table; + clear: both; } + +.wrapper-masthead { + margin-top: 50px; + margin-bottom: 50px; } + +.masthead { + padding: 20px 0; + border-bottom: 1px solid; } + @media screen and (max-width: 640px) { + .masthead { + text-align: center; } } + +.clearfix:before, +.clearfix:after { + content: " "; + display: table; } + +.clearfix:after { + clear: both; } + +@media screen and (max-width: 640px) { + .site-avatar { + float: none; + display: block; + margin: 0 auto; } } +.site-avatar img { + float: left; + width: 70px; + height: 70px; + margin-right: 15px; + border-radius: 5px; } + +.site-info { + float: left; } + @media screen and (max-width: 640px) { + .site-info { + float: none; + display: block; + margin: 0 auto; } } + +.site-name { + margin: 0; + color: #333; + cursor: pointer; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-weight: 300; + font-size: 28px; + letter-spacing: 1px; } + +.site-description { + margin: -5px 0 0 0; + color: #666; + font-size: 16px; } + @media screen and (max-width: 640px) { + .site-description { + margin: 3px 0; } } + +.darken { + transition: all .2s ease; + opacity: .5; + margin: 0; + box-shadow: none; } + .darken:hover { + opacity: .9; } + +nav { + float: right; + margin-top: 23px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 18px; } + @media screen and (max-width: 640px) { + nav { + float: none; + margin-top: 9px; + display: block; + font-size: 16px; } } + nav a { + margin-left: 20px; + color: #333; + text-align: right; + font-weight: 300; + letter-spacing: 1px; } + @media screen and (max-width: 640px) { + nav a { + margin: 0 10px; } } + +.site-title { + font-weight: 300; + line-height: 56px; + margin-bottom: -1px; + float: left; + color: #111; + letter-spacing: 1px; + text-decoration: none; + display: block; + padding: 0 15px; + font-family: 'Muli', sans-serif; + box-shadow: 0; } + .site-title:hover, .site-title:active { + background: #1D1425; + text-decoration: none; + color: #19CCAA; } + @media screen and (max-width: 640px) { + .site-title { + margin: 0 10px; } } + +.site-nav { + float: right; + line-height: 56px; } + +.site-nav .menu-icon { + display: none; } + +.site-nav .page-link { + color: #111; + line-height: 1.5; } + +.site-nav .page-link:not(:last-child) { + margin-right: 20px; } + +@media screen and (max-width: 640px) { + .site-nav { + position: absolute; + top: 9px; + right: 15px; + background-color: #fdfdfd; + border: 1px solid #e8e8e8; + border-radius: 5px; + text-align: right; } + + .site-nav .menu-icon { + display: block; + float: right; + width: 36px; + height: 26px; + line-height: 0; + padding-top: 10px; + text-align: center; } + + .site-nav ul { + margin: 0; + padding: 0; + max-width: 120px; } + + .site-nav .menu-icon > svg { + width: 18px; + height: 10px; } + + .site-nav .menu-icon > svg path { + fill: #424242; } + + .site-nav .trigger { + clear: both; + display: none; } + + .site-nav:hover .trigger { + display: block; + padding-bottom: 5px; } + + .site-nav .page-link { + display: block; + padding: 5px 10px; + margin-left: 20px; } + + .site-nav .page-link:not(:last-child) { + margin-right: 0; } } +/** + * Site footer + */ +.site-footer { + border-top: 1px solid #e8e8e8; + padding: 30px 0; } + +.footer-heading { + font-size: 18px; + display: block; + font-weight: 400; + margin: 0px; + padding: 0px; + margin-bottom: 15px; } + +.contact-list, +.social-media-list { + list-style: none; + margin-left: 0; + padding: 0; } + .contact-list .name, + .social-media-list .name { + font-size: 20px; + color: #262626; + font-family: Georgia, serif; } + +.abode { + font-size: 20px; + color: #262626; + font-family: Georgia, serif; + margin-top: 10px; + margin-bottom: 0; } + +.footer-col-wrapper { + font-size: 15px; + color: #828282; + margin: auto; } + +.footer-col { + float: left; + margin-bottom: 15px; + padding-left: 15px; + max-width: 350px; } + +.footer-col-1 { + width: -webkit-calc(35% - (30px / 2)); + width: calc(35% - (30px / 2)); } + +.footer-col-2 { + width: -webkit-calc(30% - (30px / 2)); + width: calc(30% - (30px / 2)); } + +.footer-filler { + width: -webkit-calc(15% - (30px / 2)); + width: calc(15% - (30px / 2)); } + +.footer-col-3 { + width: -webkit-calc(20% - (30px / 2)); + width: calc(20% - (30px / 2)); } + +@media screen and (max-width: 800px) { + .footer-col-1, + .footer-col-2 { + width: -webkit-calc(50% - (30px / 2)); + width: calc(50% - (30px / 2)); } + + .footer-col-3 { + width: -webkit-calc(100% - (30px / 2)); + width: calc(100% - (30px / 2)); } } +@media screen and (max-width: 600px) { + .footer-col { + float: none; + width: -webkit-calc(100% - (30px / 2)); + width: calc(100% - (30px / 2)); } } +.tag-cloud { + list-style: none; + padding: 0; + text-align: justify; + font-size: 16px; } + .tag-cloud li { + display: inline-block; + margin: 0 12px 12px 0; } + +#archives { + padding: 5px; } + +.archive-group { + margin: 5px; + border-top: 1px solid #ddd; } + +.archive-item { + margin-left: 5px; } + +.tag { + padding: 0px 6px; + border-radius: 3px; + font-size: 1.1rem; + background: #ededed; + color: #666; + letter-spacing: 1px; + margin: 0 0.5rem; + text-decoration: none; } + +.tag-date { + position: relative; + top: 2px; + margin: 0; + width: 25%; + float: right; + font-weight: 300; + color: #FFF; + text-align: right; + font-size: 1.2rem; } + +.tag-link :hover { + color: #4183C4; } + +/* For images */ +.center { + text-align: center; } + +.center img { + max-width: 100%; } + +.w10 img { + width: 10%; } + +.w20 img { + width: 20%; } + +.w25 img { + width: 25%; } + +.w30 img { + width: 30%; } + +.w40 img { + width: 40%; } + +.w50 img { + width: 50%; } + +.w60 img { + width: 60%; } + +.w70 img { + width: 70%; } + +.w75 img { + width: 70%; } + +.w80 img { + width: 80%; } + +.w90 img { + width: 90%; } + +.w100 img { + width: 100%; } + +/* For iframe videos */ +.videowrapper { + float: none; + clear: both; + width: 100%; + position: relative; + padding-bottom: 56.25%; + padding-top: 25px; + height: 0; } + +.videowrapper iframe { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; } + +/* For new home/landing page */ +.hero { + display: table; + margin-top: 150px; + width: 100%; + height: 100%; } + +.hero-inner { + width: 100%; + display: table-cell; + vertical-align: middle; + text-align: center; } + +.hero-inner .dot { + padding: 5px; + border: 1px solid #dedede; } + +.hero-inner h1, .hero-inner h3 { + max-width: 760px; + display: block; } + +.hero-inner h1 { + margin-top: .7em; + font-size: 2.5rem; + margin: 0 auto; } + +.hero-inner h3 { + font-size: 1.25rem; + margin: .8em auto 1.2em; } + +.hero-inner h3, .hero-inner em { + font-weight: 300; } + +.hero-inner em { + color: #337ab7; } + +.hero-inner strong { + font-weight: 700; } + +.dot { + max-height: 200px; + border-radius: 50%; } + +.hero-container { + max-width: 420px; + margin-left: auto; + margin-right: auto; + padding-left: 1.5em; + padding-right: 1.5em; } + +@media screen and (min-width: 768px) { + .hero-container { + max-width: 768px; } } +@media screen and (min-width: 1240px) { + .hero-container { + max-width: 960px; } } +button, input[type="button"], input[type="reset"], input[type="submit"], .button, .toggle-navbar-button { + appearance: none; + background-color: #337ab7; + border: 0; + border-radius: 6px; + color: #fff; + cursor: pointer; + display: inline-block; + font-family: inherit; + font-size: inherit; + -webkit-font-smoothing: antialiased; + font-weight: 700; + line-height: 1; + padding: .75em 1.5em; + text-decoration: none; + transition: background-color .3s ease-in-out; + user-select: none; + vertical-align: middle; + white-space: nowrap; } + +button:hover, input[type="button"]:hover, input[type="reset"]:hover, input[type="submit"]:hover, .button:hover, .toggle-navbar-button:hover, button:focus, input[type="button"]:focus, input[type="reset"]:focus, input[type="submit"]:focus, .button:focus, .toggle-navbar-button:focus { + background-color: #296292; } + +button.disabled, input.disabled[type="button"], input.disabled[type="reset"], input.disabled[type="submit"], .disabled.button, .disabled.toggle-navbar-button, button:disabled, input[type="button"]:disabled, input[type="reset"]:disabled, input[type="submit"]:disabled, .button:disabled, .toggle-navbar-button:disabled { + color: inherit; + cursor: not-allowed; + box-shadow: none; + opacity: .65; } + +button.disabled:hover, input.disabled[type="button"]:hover, input.disabled[type="reset"]:hover, input.disabled[type="submit"]:hover, .disabled.button:hover, .disabled.toggle-navbar-button:hover, button.disabled:focus, input.disabled[type="button"]:focus, input.disabled[type="reset"]:focus, input.disabled[type="submit"]:focus, .disabled.button:focus, .disabled.toggle-navbar-button:focus, button:disabled:hover, input[type="button"]:disabled:hover, input[type="reset"]:disabled:hover, input[type="submit"]:disabled:hover, .button:disabled:hover, .toggle-navbar-button:disabled:hover, button:disabled:focus, input[type="button"]:disabled:focus, input[type="reset"]:disabled:focus, input[type="submit"]:disabled:focus, .button:disabled:focus, .toggle-navbar-button:disabled:focus { + color: inherit; + background: none transparent; } + +.button-ghost { + background-color: transparent; + border: 2px solid #337ab7; + color: #337ab7; + margin-bottom: 2px; } + +.button-ghost:hover, .button-ghost:focus { + color: #fff; } + +.social { + padding: 1.5em 0; } + +.social li { + display: inline-block; + padding: 0 .6em; } + +.social a { + color: #9a9a9a; } + +.social a:hover, .social a:active, .social a:focus { + color: #337ab7; } + +.social i { + font-size: 1.6em; } + +/* Blog list page each element*/ +.blog_ele { + display: block; + margin: 0 0 50px 0; } + +.blog_ele time { + float: right; + position: relative; + top: 2px; + margin: 0; + width: 35%; + float: right; + font-size: 1.1em; + color: #898989; + text-align: right; } + +.blog_ele h3 { + margin: 0; + width: 75%; + color: #4183C4; } + +@media screen and (min-width: 400px) { + .blog_ele { + margin: 20px 0; } } +/** + * Syntax highlighting styles + */ +.highlight { + background: #fff; } + .highlight .c { + color: #998; + font-style: italic; } + .highlight .err { + color: #a61717; + background-color: #e3d2d2; } + .highlight .k { + font-weight: bold; } + .highlight .o { + font-weight: bold; } + .highlight .cm { + color: #998; + font-style: italic; } + .highlight .cp { + color: #999; + font-weight: bold; } + .highlight .c1 { + color: #998; + font-style: italic; } + .highlight .cs { + color: #999; + font-weight: bold; + font-style: italic; } + .highlight .gd { + color: #000; + background-color: #fdd; } + .highlight .gd .x { + color: #000; + background-color: #faa; } + .highlight .ge { + font-style: italic; } + .highlight .gr { + color: #a00; } + .highlight .gh { + color: #999; } + .highlight .gi { + color: #000; + background-color: #dfd; } + .highlight .gi .x { + color: #000; + background-color: #afa; } + .highlight .go { + color: #888; } + .highlight .gp { + color: #555; } + .highlight .gs { + font-weight: bold; } + .highlight .gu { + color: #aaa; } + .highlight .gt { + color: #a00; } + .highlight .kc { + font-weight: bold; } + .highlight .kd { + font-weight: bold; } + .highlight .kp { + font-weight: bold; } + .highlight .kr { + font-weight: bold; } + .highlight .kt { + color: #458; + font-weight: bold; } + .highlight .m { + color: #099; } + .highlight .s { + color: #d14; } + .highlight .na { + color: #008080; } + .highlight .nb { + color: #0086B3; } + .highlight .nc { + color: #458; + font-weight: bold; } + .highlight .no { + color: #008080; } + .highlight .ni { + color: #800080; } + .highlight .ne { + color: #900; + font-weight: bold; } + .highlight .nf { + color: #900; + font-weight: bold; } + .highlight .nn { + color: #555; } + .highlight .nt { + color: #000080; } + .highlight .nv { + color: #008080; } + .highlight .ow { + font-weight: bold; } + .highlight .w { + color: #bbb; } + .highlight .mf { + color: #099; } + .highlight .mh { + color: #099; } + .highlight .mi { + color: #099; } + .highlight .mo { + color: #099; } + .highlight .sb { + color: #d14; } + .highlight .sc { + color: #d14; } + .highlight .sd { + color: #d14; } + .highlight .s2 { + color: #d14; } + .highlight .se { + color: #d14; } + .highlight .sh { + color: #d14; } + .highlight .si { + color: #d14; } + .highlight .sx { + color: #d14; } + .highlight .sr { + color: #009926; } + .highlight .s1 { + color: #d14; } + .highlight .ss { + color: #990073; } + .highlight .bp { + color: #999; } + .highlight .vc { + color: #008080; } + .highlight .vg { + color: #008080; } + .highlight .vi { + color: #008080; } + .highlight .il { + color: #099; } + +pre { + white-space: pre-wrap; + /* css-3 */ + white-space: -moz-pre-wrap; + /* Mozilla, since 1999 */ + white-space: -pre-wrap; + /* Opera 4-6 */ + white-space: -o-pre-wrap; + /* Opera 7 */ + word-wrap: break-word; + /* Internet Explorer 5.5+ */ } + +code.highlighter-rouge { + background-color: #d3d3d3; } + +*, +*:before, +*:after { + box-sizing: border-box; } + +.github-button { + display: block; + position: relative; + padding: .75em 5em .75em 1em; + border-radius: .25em; + margin-bottom: .5em; + background: #fff; } + +.open-PR-button { + box-shadow: 0 0.0625em 0.125em rgba(0, 0, 0, 0.125), inset 0 -0.25em 0 -0.125em rgba(0, 0, 0, 0.125), inset 7.5em 0 0 -0.7em rgba(20, 160, 0, 0.8), inset -4em 0 0 -0.3em rgba(20, 160, 0, 0.8); } + +.merged-PR-button { + box-shadow: 0 0.0625em 0.125em rgba(0, 0, 0, 0.125), inset 0 -0.25em 0 -0.125em rgba(0, 0, 0, 0.125), inset 7.5em 0 0 -0.7em rgba(30, 144, 255, 0.5), inset -4em 0 0 -0.3em rgba(30, 144, 255, 0.5); } + +.open-issue-button { + box-shadow: 0 0.0625em 0.125em rgba(0, 0, 0, 0.125), inset 0 -0.25em 0 -0.125em rgba(0, 0, 0, 0.125), inset 7.5em 0 0 -0.7em rgba(20, 160, 0, 0.5), inset -4em 0 0 -0.3em rgba(20, 160, 0, 0.5); } + +.closed-issue-button { + box-shadow: 0 0.0625em 0.125em rgba(0, 0, 0, 0.125), inset 0 -0.25em 0 -0.125em rgba(0, 0, 0, 0.125), inset 7.5em 0 0 -0.7em rgba(178, 34, 34, 0.8), inset -4em 0 0 -0.3em rgba(178, 34, 34, 0.8); } + +.number { + position: absolute; + font-family: "Lucida Console", Monaco, monospace; + font-size: 24pt; + height: 4em; + width: 3.6em; + overflow: hidden; + text-overflow: ellipsis; + text-align: center; + left: .125em; + top: 0.5em; + color: #000; } + +.number:hover { + font-weight: bold; + color: #000; } + +.title { + margin-left: 6em; + display: block; + font-size: 14pt; + font-weight: bold; + color: #000; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; } + +.title:after { + content: ''; + display: block; + height: 0; + width: 100%; } + +.meta { + display: block; + margin-left: 7em; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + font-size: 12pt; + line-height: 2; + /* 16 "px" */ + font-weight: bold; + color: #2f4f4f; } + +.repo { + font-weight: bold; + color: #2f4f4f; } + +.date { + font-weight: bold; + color: #2f4f4f; } + +.date:before { + content: ' '; + font-weight: normal; } + +.octicon-clock { + display: inline-block; + margin-left: .333em; } + +.right-icon { + display: block; + position: absolute; + right: 0.5em; + top: 50%; + margin-top: -.6em; } + +@media screen and (max-width: 600px) { + .github-button { + padding: .75em 5em .75em 1em; + border-radius: .25em; + margin-bottom: .5em; } + + .open-PR-button { + box-shadow: 0 0.0625em 0.125em rgba(0, 0, 0, 0.125), inset 0 -0.25em 0 -0.125em rgba(0, 0, 0, 0.125), inset 4em 0 0 -0.7em rgba(20, 160, 0, 0.8), inset -3em 0 0 -0.3em rgba(20, 160, 0, 0.8); } + + .merged-PR-button { + box-shadow: 0 0.0625em 0.125em rgba(0, 0, 0, 0.125), inset 0 -0.25em 0 -0.125em rgba(0, 0, 0, 0.125), inset 4em 0 0 -0.7em rgba(30, 144, 255, 0.5), inset -3em 0 0 -0.3em rgba(30, 144, 255, 0.5); } + + .open-issue-button { + box-shadow: 0 0.0625em 0.125em rgba(0, 0, 0, 0.125), inset 0 -0.25em 0 -0.125em rgba(0, 0, 0, 0.125), inset 4em 0 0 -0.7em rgba(20, 160, 0, 0.5), inset -3em 0 0 -0.3em rgba(20, 160, 0, 0.5); } + + .closed-issue-button { + box-shadow: 0 0.0625em 0.125em rgba(0, 0, 0, 0.125), inset 0 -0.25em 0 -0.125em rgba(0, 0, 0, 0.125), inset 4em 0 0 -0.7em rgba(178, 34, 34, 0.8), inset -3em 0 0 -0.3em rgba(178, 34, 34, 0.8); } + + .number { + font-size: 13pt; + height: 4em; + width: 3em; + left: 0.125em; + top: 1.25em; } + + .title { + margin-left: 3.5em; + font-size: 10pt; } + + .meta { + margin-left: 4.25em; + font-size: 8pt; + line-height: 2; + /* 16 "px" */ } + + .octicon-clock { + margin-left: .333em; } + + .right-icon { + right: 0.25em; + top: 50%; + margin-top: -.6em; } } diff --git a/_site/feed.xml b/_site/feed.xml new file mode 100644 index 0000000..da94b20 --- /dev/null +++ b/_site/feed.xml @@ -0,0 +1,904 @@ + + + + Nihal Singh + Nihal Singh's personal blog. + + http://localhost:4000/ + + Wed, 12 Dec 2018 15:32:48 +0530 + Wed, 12 Dec 2018 15:32:48 +0530 + Jekyll v3.8.1 + + + Pommerman- Reinforcement Learning Project + <p>As the course project for CS 747 - Foundations of Intelligent &amp; Learning Agents, Fall 2018, I teamed up with Chinmay Talegaonkar and Dhruv Shah to take on the <a href="https://www.pommerman.com/">Pommerman Challenge</a>.</p> + +<p class="center"><img src="/img/pommerman.gif" alt="Pommerman" title="Pommerman" style="max-height: 500px;" /></p> + +<p>The Pommerman Challenge essentially serves as a test bed for multi-agent learning algorithms. It is essentially a clone of the popular Bomberman game, providing a constantly changing environment with bombs going off, power-ups to be collected and other agents to be eliminated. There are mainly two modes to the game, <strong>FFA</strong>- where each of the four agents battle against each other and the last one to survive wins, <strong>Team</strong>- where there are two teams of two agents which compete against each other.</p> + +<p>We took on the FFA challenge, trying a few different approaches. After facing a few hurdles, we found that the DQfD agent performed remarkably well as against our other approaches.</p> + +<p>Our experiments and approaches are detailed here- <a href="/docs/pommerman_report.pdf">Report</a></p> + +<p>To see our agent in action, watch the video below-</p> + +<iframe width="100%" height="400px" src="https://www.youtube.com/embed/DtiyIrMZ69A" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe> + + + Sun, 25 Nov 2018 00:00:00 +0530 + http://localhost:4000/2018/11/25/pommerman-rl.html + http://localhost:4000/2018/11/25/pommerman-rl.html + + Machine Learning + + Reinforcement Learning + + + + + + To hell and back again, US B1 Visa + <p>Having been selected as one of the representatives from MovingBlocks, I was all excited about being able to attend the GSoC Mentor Summit for 2018. It would be the first time I would be travelling to the States. The timeline worked out well, and I was also able to fit Github Universe in my schedule. In little time, I had my flight tickets booked and reserved a room at the hotel provided by Google. Everything was in order and only acquiring the Visa remained.</p> + +<h2 id="the-visa-process">The Visa Process</h2> +<p>I started my Visa process around mid-August, filled out my DS160, made the 160$ payment and booked dates for the VAC (Biometrics) and VI (Consular Interview). The earliest date that I could find for the interview was 24th September.</p> + +<h2 id="nearly-there-but-oh-well">Nearly there but oh, well</h2> +<p>I reached just in time for my 10 AM appointment at the Mumbai consulate, owing to the deplorable peak-hour traffic. I had barely done any reading up about what the interview is like, apart from some tips shared on the GSoC mailing list and a few stories from friends.</p> + +<p>I had read about a good number of cases on the mailing thread, where fellow mentors had their Visa denied, and there was absolutely nothing that could be done after that. I had a word with the person standing next to me in the queue, who mentioned that it was his second attempt. The last time he had appeared, the interview lasted for 10 seconds. As soon as he said he was an IT professional, the Consular officer handed him the rejection letter saying- “I cannot approve your Visa this time”.</p> + +<p>With these stories in my head, I was partly nervous but still convinced that my purpose of travelling was entirely legitimate. I had an invitation letter from Google, and I had to complete my undergraduate studies, which meant that I was bound to return.</p> + +<p>After a long wait, and slowly moving through the serpentine queue my turn arrived. While I was waiting at the counter, the person ahead of me had his Visa denied. As I walked up to the counter, I could see that the consular officer was unhappy.</p> + +<hr /> + +<p><strong>Me:</strong> Good morning<br /> +<strong>Officer:</strong> May I have your passport? <br /> +(I pass my passport) <br /> +<strong>O:</strong> Why would you be travelling to the United States? <br /> +<strong>M:</strong> To attend a conference. <br /> +(I kept my answers brief and answered only what I was asked. I had read this tip somewhere, and I was extra cautious to not annoy the officer further.) <br /> +<strong>O:</strong> What conference is this? <br /> +<strong>M:</strong> It’s a conference about open source software. It’s called the Google Summer of Code mentor summit. <br /> +(He starts looking at the screen and typing in something.) <br /> +<strong>O:</strong> Who would be paying for your trip? <br /> +<strong>M:</strong> Google would be paying. They would be paying 1100$ for every attendee, and if that falls short, my organisation can cover the rest. +(More typing and looking at the screen) <br /> +<strong>O:</strong> Are you pursuing your undergraduate studies? <br /> +<strong>M:</strong> Yes. I am a fourth-year student. <br /> +<strong>O:</strong> Do you have your old passports. May I see them? <br /> +(I pass my older passports) <br /> +<strong>O:</strong> What does your father do? <br /> +<strong>M:</strong> He is an engineer. He works at X. <br /> +<strong>O:</strong> Who pays for your education? <br /> +<strong>M:</strong> My father does. <br /> +(More typing. Longer this time.) <br /> +<strong>O:</strong> Your Visa application has been denied. The reason is written in this paper. You may apply again.</p> + +<hr /> + +<p>Profoundly disappointed and dissatisfied with how the interview went, I left. I had carried a file with all the documents I could think of, and the interviewer didn’t ask for even a single document. The paper given to me cited Section 214 (b) as the ground for denial, which essentially means I couldn’t prove strong ties to my home country. Baseless in my case, since I needed to come back to finish my undergrad.</p> + +<p>My plans had come to an end. There was no way I could apply again. It took me more than a month to get my first appointment. I barely had 2 weeks before my flight, this time.</p> + +<h2 id="the-gamble">The Gamble</h2> +<p>I heard from a friend (<a href="https://mozillians.org/en-US/u/ydidwania/">Yashvardhan Didwania</a>, thanks again) that it isn’t all that impossible to get an appointment on a date before the expected waiting period. He had pulled it off in the past by continually refreshing the webpage and checking for available dates. When someone cancels or reschedules, an earlier date becomes available for a short while. That’s when you grab it.</p> + +<p>The gamble was that I would have to pay 160$ before I become able to book an appointment. To get the Visa on my passport in time, I needed to get an interview date on or before October 8. There was a good chance that I would not get such a date but I decided to play the odds.</p> + +<p>I had to wait for the next day to start a new application since the website still showed my present-day appointment (24 September) as active. I filled out the DS-160 in the meantime and spent the entire day reading stories about Visa rejections and searching for ways to overcome them. I woke up on 25th September and at 10:21 AM, on my way to class, I made the MRV payment of 160$ again. I remember it took around 1-2 hours for my receipt to get activated and reflect on the website, last time. However, I kept checking during class, and the receipt was activated at sharp 11:00 AM. The earliest available date was 19 October at the Mumbai Consulate, as I had expected. Chennai had an earlier date of 3 October available, but I dropped that thought. Better judgement prevailed, and I kept refreshing the page hoping for a miracle to happen. At 11:21 AM, I made my last refresh, and to my surprise, the website now showed the earliest available date as 27th September. Within what were an intense 15 seconds, I had managed to secure my second interview on the 27th of September. It was unbelievable, and I was happy beyond my wits.</p> + +<h2 id="turning-my-luck-upside-down">Turning my luck upside down</h2> + +<p>Fast forward to 27th September. Again, I saw rejections all over the place and people returning with their passports. I saw three applicants have their Visa denied by the very same officer who had denied my Visa last time. I kept my head clear, and I approached the counter.</p> + +<hr /> + +<p><strong>Me:</strong> Good morning ma’am. <br /> +<strong>Officer:</strong> Good morning. May I have your passport? <br /> +<em>(I pass my passport along with the 4 most essential supporting documents)</em> <br /> +<strong>O:</strong> Why would you be travelling? <br /> +<strong>M:</strong> I am invited to attend a conference. The conference is called the Google Summer of Code Mentor Summit. It’s a conference where mentors from different open source organisations come together to discuss how the Google Summer of Code program can be made better and how the open source community can improve as a whole.<br /> +<strong>O:</strong> I’m sorry, can you explain what the conference is about again? <br /> +<strong>M:</strong> Alright, so Google has a program called the Google Summer of Code wherein students participate by contributing to open source organisations. I am a student myself, and I participated in the summer of 2017 by contributing to an organisation called MovingBlocks. In 2018, I became a mentor. Each organisation is supposed to send two representatives to the Mentor Summit, to come together and discuss how the program can be improved. I would be representing MovingBlocks this time.<br /> +<em>(Looks at the screen, types a little)</em><br /> +<strong>O:</strong> Who would be paying for your trip? <br /> +<strong>M:</strong> My expenses would be covered directly by my organisation. Google, in turn, would fund each organisation by paying 1100$ for each representative and also arranging for a hotel during the period of the conference.<br /> +<em>(She scrolls through the documents I forwarded)</em><br /> +<strong>O:</strong> I see you have travelled to Japan recently. What was that for? <br /> +<strong>M:</strong> I was doing an internship in Japan in the past summer. <em>//Explain a little more</em> <br /> +<strong>O:</strong> Is there any other country you have travelled to? <br /> +<strong>M:</strong> Yes, <em>// Explain</em><br /> +<em>(She starts typing and continues for a long time)</em><br /> +<em>(I see her look up at the clock and press key combinations this time, she then keeps my passport on the side.)</em><br /> +<strong>O:</strong> Your Visa application has been approved. Have a nice trip. <br /> +<strong>M:</strong> Thank you so much.</p> + +<hr /> + +<p>I come to realise that I’ve pulled it off. The gamble had paid off perfectly well, and all plans were back on track.</p> + +<h3 id="tips">Tips:</h3> + +<p>The following are a few tips from my personal experience. I do not claim that these would generalize across different consulates and the following should not be considered in any way as formal/legal advice.</p> + +<ol> + <li>Be confident. If you deserve the Visa, act like you already have it.</li> + <li>Always explain in great depth. Give no excuse to the officer to think that you’re making things up. If the officer enjoys brevity, they will ask you to stop or shoot another question.</li> + <li>Push your papers forward initially. If they are returned, make further attempts to show them relevant papers whenever a document supports something you’re saying. Remember, the burden of proof is on the applicant.</li> + <li>Hope for the best, expect the worst. In my opinion, the process is semi-arbitrary, and you may be unlucky to have a short interview or a grumpy interviewer. Be prepared for this and leave no effort in making sure you deliver all the information you can.</li> + <li>A denial is only temporary, and it can be turned easily if you have all the right reasons. Advice on forums echoed with- “Don’t apply immediately after a rejection. Wait till your circumstances change”. While this may be true, if you feel there was no real reason for your application to be rejected, applying again immediately may work in your favour. Here is a timeline of how I flipped my rejection in 4 days.</li> +</ol> + +<p><strong><em>24th September - (VI appointment) Interview. Visa Denied</em></strong><br /> +<strong><em>25th September - Paid for next appointment.</em></strong><br /> +<strong><em>26th September - (VAC appointment) Biometrics</em></strong> <br /> +<strong><em>27th September - (VI appointment) Interview. Visa approved.</em></strong></p> + +<hr /> + +<p>I’m delighted that my gamble worked out well and excited more than ever to fly to California.</p> + + Thu, 27 Sep 2018 00:00:00 +0530 + http://localhost:4000/2018/09/27/us-visa-b1.html + http://localhost:4000/2018/09/27/us-visa-b1.html + + Visa + + + + + + Internship at Mercari + <p>I’m back in Mumbai as I write this recap blog post describing my summer spent in the heart of Tokyo, during my internship at Mercari. This blog post is going to be specific to my internship. I’ve written about my travelling experiences in a <a href="https://nihal111.github.io/2018/07/09/japan-lookback.html">different post</a>.</p> + +<h2 id="about-mercari">About Mercari</h2> + +<p>Mercari is a CtoC marketplace startup that was founded in 2013. Their main product is the Mercari CtoC marketplace app. In just 5 years, the company has skyrocketed to become Japan’s largest community-driven marketplace. The company also gained the pre-IPO unicorn status, being a privately held company valued over $1 billion. This was before the company went public this June on the Toyko Stock Exchange’s Mothers Market, during my stay there.</p> + +<h2 id="the-office">The Office</h2> + +<p class="center"><img src="/img/mercari/officeview.jpg" alt="Office View" title="Office View" style="max-height: 500px;" /></p> + +<p>The Mercari office is located on the 18th floor of Mori Tower, the 6th tallest building in Tokyo. The view from the office is fantastic and the breeze on the top, at the observation deck is better. There is a giant spider outside the office, that should remind you of <a href="http://silverscreensnobs.com/spiders-doppelgangers-secrets-enemy-expained/">Enemy</a> if you’re into sci-fi.</p> + +<p class="center"><img src="/img/mercari/moritower.jpg" alt="Mori Tower" title="Mori Tower" style="max-height: 500px;" /> +<img src="/img/mercari/spider.jpg" alt="spider" title="Spider" style="max-height: 500px;" /></p> + +<h2 id="the-honeymoon-phase">The Honeymoon Phase</h2> +<p>The first week was nothing short of overwhelming. Even for the honeymoon phase, things seemed too good to be true. The onboarding and orientation were smooth, and we were given our gear. We got company phones, portable wifi and the $2000 MacBook Pro amongst other goodies.</p> + +<p class="center"><img src="/img/mercari/gear.jpg" alt="Gear" title="Gear" style="max-height: 500px;" /></p> + +<p>We were assigned to our teams but were supposed to go through a week of orientation before beginning any work. The Global Operations Team took special effort to make us feel at home. They organised the multiple onboarding sessions and even took us out for a complete Tokyo tour on a weekday.</p> + +<p class="center"><img src="/img/mercari/tokyotour.jpg" alt="Tokyo Tour" title="Tokyo Tour" style="max-height: 500px;" /></p> + +<p>By week two, we were on our desks at our respective teams with the welcome balloons we received.</p> + +<p class="center"><img src="/img/mercari/balloons.jpg" alt="Balloons" title="Balloons" style="max-height: 500px;" /></p> + +<h2 id="the-android-team">The Android Team</h2> +<p>I had the pleasure to work with the JP Android Team, the team working on the main marketplace app- <a href="https://play.google.com/store/apps/details?id=com.kouzoh.mercari">Mercari</a> for Japan. It was a medium sized team with just over 10 people. The bulk of my task for the summer was to implement client facing feature on the Android app. I also worked on a few isolated issues all over the codebase and took the initiative to improve the code quality in the codebase which was very well received by the team.</p> + +<p class="center"><img src="/img/mercari/androidteam.jpg" alt="Android Team" title="Android Team" style="max-height: 500px;" /></p> + +<p>My team was largely global, consisting of a large number of Gaijins (Japanese for foreigners). I benefited hugely from this and learned how to work in a multi-cultural team. I learned the flow for how a spec moves to feature that gets shipped and how each detail in the middle matters.</p> + +<p>On the technical side, for the first time I <strong>implemented a software architecture</strong>, <strong>wrote Kotlin code</strong>, <strong>wrote Unit tests using Mockito and Robolectric</strong> and <strong>created an automation task using CI</strong>. I’m glad to have been able to achieve this in a small period of just over a month.</p> + +<p class="center"><img src="/img/mercari/desk.jpg" alt="Desk" title="Desk" style="max-height: 500px;" /></p> + +<p>My team was great in many ways, apart from the mentor lunches that all of us interns were entitled to, the Android team had a weekly team lunch. My team even put together a special farewell dinner for me, after which we ended up going to Karaoke. There was also this beautiful parting gift I received from my team-</p> + +<p class="center"><img src="/img/mercari/rum.jpg" alt="rum" title="rum" style="max-height: 500px;" /></p> + +<h2 id="experience">Experience</h2> + +<p>All in all, the whole experience over the course of my internship was more than I could have asked for. Mercari was great to me, and it was a crazy time to be there. Amidst the whole IPO frenzy and the company celebrating its 5th anniversary, I was lucky to go to all the parties.</p> + +<p>I learned how to work efficiently in a team, picked up on a few technical things, got to meet a whole bunch of great people, got exposed to a whole new culture and travelled as much as I could (more about that <a href="https://nihal111.github.io/2018/07/09/japan-lookback.html">here</a>).</p> + +<hr /> + +<p>Summer of ‘18 was one of the best summers I’ve had so far. Being home feels warm but itchy.</p> + + Mon, 09 Jul 2018 00:00:00 +0530 + http://localhost:4000/2018/07/09/mercari-internship.html + http://localhost:4000/2018/07/09/mercari-internship.html + + Japan + + Mercari + + internship + + + + + + Adventures in Japan + <p>My time in Japan comes to a close as I enter the last week of my stay here. The experience so far has been nothing short of crazy.</p> + +<p>I was fortunate to spend the summer of ‘18 in Tokyo doing my internship at Mercari, an e-commerce unicorn. I spent most of my working days writing Android code for the main Japanese marketplace app-<a href="https://play.google.com/store/apps/details?id=com.kouzoh.mercari">Mercari</a>. My weekends were well spent touring around Japan. This is an attempt to lookback and document some of my adventures in Japan. Most of the following adventures were made with a varying subset of the 8 co-interns I was lucky to be in company of.</p> + +<h3 id="week-1-tokyo-disney-sea">Week 1: Tokyo Disney Sea</h3> +<p>We were planning to get the 2 day Disney Land + Disney Sea pass, but better judgement prevailed and we went ahead with only getting the Disney Sea tickets.<br /> +This was my first Disney experience and it was the best theme park experience I had so far. The landscapes were beyond amazing. Being a weekend, it was super crowded. But with our strong fast pass game, we managed to ride through to most of the attractions with great efficiency. The evening fireworks show- Fantasmic was true to its name. I walked over 15k steps that day and returned home with tired legs.</p> + +<p class="center"><img src="/img/tokyo/disneysea.jpg" alt="Lounge" title="DisneySea" style="max-height: 500px;" /></p> + +<h3 id="week-2-akihbara--the-electric-town">Week 2: Akihbara- the electric town</h3> +<p>With our first attempt at making a booking for FujiQ online having failed, we were left with an empty weekend. I decided to make the most of it by going shopping.<br /> +I went to Akihabara, the electric town of Japan, filled with electronic stores of all sizes and interspersed with Anime cafes and Manga stores of all sorts. I explored the world’s largest electronics store- the Yodobashi Camera. I bought a few things from BIC Camera and also a lot of handy items from small stores around. I went to Gachapon store and got a few capsule toys. I roamed around and went to a few other interesting stores as well…</p> + +<p class="center"><img src="/img/tokyo/akihabara.jpg" alt="Lounge" title="Akihabara" style="max-height: 500px;" /></p> + +<h3 id="week-3-exploring-kyoto">Week 3: Exploring Kyoto</h3> +<p>How can you come to Japan and not go to the ancient capital to witness true Japanese tradition?<br /> +We took the Shinkansen to Kyoto on our third weekend. We left early Saturday morning and reached there by 10 AM. We had planned an efficient route that would get us to a lot of good spots without having to travel a lot. We started off with <strong>Nijo Castle</strong>, which was home to the shoguns from the Edo period. Next up, we went to the <strong>Imperial Palace</strong> and then to <strong>Kinkakuji</strong>, the golden shrine. We paused for lunch and then continued to <strong>Ryōan-ji</strong>, a Zen temple with a rock garden. We then headed to the <strong>Fushimi-inari</strong> shrine. The climb to the top was tiring, but the view from the top was spectacular. After sundown, we made our way to the Ryokan we had booked for the night. It was a small place, but we had a fun night sleeping in traditional Japanese rooms. The next day, we went to the <strong>Arashiyama</strong> bamboo forest and enjoyed boating in the Hozugawa river. Later, we went to the Arashiyama monkey park to watch some macaque from real close. We returned in time to catch one of the last Shinkansen back to Tokyo.</p> + +<p class="center"><img src="/img/tokyo/kyoto.jpg" alt="Lounge" title="Kyoto" style="max-height: 500px;" /></p> + +<h3 id="week-4-fujiq-roller-coaster-madness">Week 4: FujiQ, roller coaster madness</h3> +<p>We really got lucky with this one. With most weekends having heavy rainfall forecast, we had almost given up on our roller coaster hopes. Until one Saturday we made an instant plan and went ahead since the next day showed very little rainfall.<br /> +We took the Q-Pack which includes the to and fro ride from Shinjuku and the day pass to the park. To make the most out of our lucky chance, we further bought express passes to three of the crowded roller coasters. There are a total of four popular roller coasters- Fujiyama, Eejanaika, Takabisha and Do-Dodonpa. Fujiyama surprisingly had smaller queues and we ended up going for Fujiyama twice despite not having a fast pass for it. With the express passes, we were able to get done with the popular rides in less time and had enough time on our hands to try out most of the other attractions as well. Overall, I enjoyed a lot. Some of the roller coasters are world record holders and it was a completely thrilling experience to ride them.</p> + +<p class="center"><img src="/img/tokyo/fujiq.jpg" alt="Lounge" title="FujiQ" style="max-height: 500px;" /></p> + +<h3 id="week-5-oshima--an-island-escapade">Week 5: Oshima- an island escapade</h3> +<p>This was definitely one of the best weekends spent in Japan. Izu Oshima is the largest of the Izu islands that fall under the administeration of Tokyo. It has a population of around 2500 people but for long stretches, we barely saw any people when we went cycling around the island.<br /> +We took the overnight ferry from Tokyo to Oshima, that docked at early Saturday morning. We quickly went ahead and rented out cycles to begin our expedition. The island’s perimeter has a nice circuit made for cycling. Cycling along the oceanline with a constant ocean breeze and through the mountains was definitely my best cycling experience so far. We cycled for a good 30+ km and headed back to our hotel. It was a small nice place called the Book Tea Bed. We went to the Hama-no-yu onsen next to have a hot water bath to relax our tired muscles whilst watching the sun set on the horizon as we sat at the edge of the island surrounded by the ocean. What followed was a good night’s sleep and another cycle journey to head to the Okata port where we went snorkeling. Snorkeling was fun and we saw a lot of fish. Bringing a GoPro to record the underwater sights and the cycle journeys was one of my better decisions. We had to rush back to Motomachi port for our ship back to Tokyo. The ship had some of the coolest vending machines, ones with built in microwave for warm food and hot water dispensers for cup noodles.</p> + +<p class="center"><img src="/img/tokyo/oshima.jpg" alt="Lounge" title="Oshima" style="max-height: 500px;" /></p> + +<h3 id="week-6-conquering-mt-fuji">Week 6: Conquering Mt. Fuji</h3> +<p>This was probably the stupidest, albeit the most adventurous thing I did in Japan. The proper and recommended way to climb Mt. Fuji and witness the literally ‘breath-taking’ sunrise involves making a climb during day, and resting in a hut for the night, waking up energized and making to the top just in time for the sunrise. We weren’t able to book a hut, thanks to our last moment planning and we decided to do it the hard way- rush to the top, see the sunrise and come back.<br /> +We made it to the 5th station at around 16:00 and started the climb at 19:30. The Yoshida trail is the easiest way to the top and that’s the one we took. With frequent stops, we took it slow and made it to the top at 04:00 just in time to see the sunrise. The view was nothing short of spectacular, but it was freezing cold at the summit. The temperature touched zero degree Celcius and there were super strong chilly winds blowing. Altitude sickness and asphixiation had started taking a toll on me. It was a super cloudy day and the crater was completely shielded with fog. The sun was hidden behind the clouds intermittently too. Somehow, I survived and started descending. The descent was torturous with steep curved paths that have slippery gravel for extremely long stretches. With an extreme body ache and a severe headache, I took the bus to take me home.</p> + +<p class="center"><img src="/img/tokyo/mtfuji.jpg" alt="Lounge" title="Mt. Fuji" style="max-height: 500px;" /></p> + +<p>There were a few mini adventures on weekdays, but the bulk of my expeditions in Japan have been recorded above. Woo!</p> + + Mon, 09 Jul 2018 00:00:00 +0530 + http://localhost:4000/2018/07/09/japan-lookback.html + http://localhost:4000/2018/07/09/japan-lookback.html + + Japan + + + + + + I just flew to Japan + <p>Wifi or SkyTV, I needed at least one. The UEFA Champions League Final was on at night, and I was flying the ANA to Tokyo.</p> + +<p>I was travelling from Mumbai to Tokyo for my summer internship at Mercari. I left for the airport at 4 PM. My plane was to depart at 8:15 PM. The traffic was unusually high for a non-working Saturday afternoon; I ended up reaching the airport at 5:45 PM. The airport stuff didn’t take long, and I was near the boarding gates by 6:30. I decided to wait in the lounge. <strong>PROTIP</strong>: always try to carry a <a href="https://www1.mastercard.com/content/mc/campaign-exchange/moments/india/en/local-campaigns/exclusive-airport-lounge-access.html">MasterCard</a> to the lounge, you get free food and drinks.</p> + +<p class="center"><img src="/img/lounge.jpg" alt="Lounge" title="Lounge" style="max-height: 250px;" /></p> + +<p>As soon as I boarded the flight, I checked the entertainment system. SkyTV was disabled. I accepted my fate of missing the finals and decided to watch a movie- The Butterfly Effect. My flight’s departure got delayed by an hour. After the flight took off, I realised that SkyTV started working. With my plans of sleeping destroyed, I braced myself for the match. The match was disappointing (save for Bale’s bicycle), thanks to Sergio Ramos’ <a href="https://www.youtube.com/watch?v=UxCcZe_q1iI">love for clean play</a>.</p> + +<p>Barely able to sleep at night, I arrived in Japan with numb legs. I found Emily-san from Fourth Valley Concierge waiting to pick me up. The other interns had already reached. We took a bus to the Ginza station and then a train to the Tameikei Sanno station. Our apartment was located somewhere in Roppongi. We picked up the keys to our apartments and went in to freshen up. Seeing the apartment for the first time was a delight, and I really couldn’t wish for better.</p> + +<p class="center"><img src="/img/homeJapan.jpeg" alt="Home" title="Home" style="max-height: 300px;" /></p> + +<p>Emily-san and Tanaka-san took us out for lunch and showed us around. I started falling in love with Tokyo. I spent most of the afternoon unpacking and getting used to my new home. I had a hard time trying to figure out a few things since almost everything was documented in Japanese, from the toilet seat temperature controls to the TV remote. The waste segregation was pretty complicated too, and I pushed it off for later.</p> + +<p class="center"><img src="/img/viewJapan.jpeg" alt="View" title="View" style="max-height: 400px;" /></p> + +<p>I called over Prateek in the evening, who lives only an hour away. He was doing his research internship at the University of Tokyo. We went out and explored the locality, hopped across a few convenience stores and got a few ready to cook items for dinner.</p> + +<p class="center"><img src="/img/dinnerJapan.jpeg" alt="dinnerJapan" title="Dinner" style="max-height: 250px;" /></p> + +<p>I retired to bed early, super excited for my first day at work.</p> + + Mon, 28 May 2018 00:00:00 +0530 + http://localhost:4000/2018/05/28/flew-to-japan.html + http://localhost:4000/2018/05/28/flew-to-japan.html + + Japan + + + + + + Flying a DJI Mavic + <p>On yet another Summer weekend, I drove to the NRI Complex in Seawoods. It was a sunny day, and we were to fly a drone that evening.</p> + +<h3 id="the-lake">The Lake</h3> + +<p>Just adjacent to the NRI Estate is a lake where a raft of flamingoes with almost a dozen other species visit during the summer. During the season, the lake also becomes a hive for photographers from all over Navi Mumbai. +During winter, this lake also becomes home to thousands of migratory aquatic birds including ducks, herons, and kingfishers. There’s also an interesting <a href="https://www.thebetterindia.com/120843/shruti-agarwal-sunil-agarwal-seawoods-lake-mumbai/">story</a> behind the lake’s preservation and it’s battle against being converted to a golf course.</p> + +<p class="center"><img src="/img/lake.jpg" alt="Lake" title="Lake" style="max-height: 500px;" /></p> + +<h3 id="the-drone">The Drone</h3> + +<p>The drone belonged to Vaibhav. It was a DJI Mavic, the one listed <a href="https://www.dji.com/mavic">here</a>. A small transmitter hooks on to a phone, and the drone relays a clear view to the phone’s screen, saving higher quality footage to the SD card. There were four of us flying that evening, each reluctantly passing on the transmitter to the other.</p> + +<p class="center"><img src="/img/drone1.jpg" alt="drone1" title="drone1" style="max-height: 500px;" /></p> + +<p>The drone is pretty smart and packed with features including collision avoidance, wind monitoring, constant battery monitoring for safe return and a fantastic return-to-home option that brings the drone back to the take-off point with centimeter accuracy.</p> + +<p>The software side from DJI is pretty amazing too. In addition to providing the above-listed features in a clean interface, it does a great job at pre-processing too- threading together an entire video from the shots taken during flight and overlaying music with one button tap. The videos attached below are created automagically by the DJI app.</p> + +<div class="videowrapper"> + <iframe width="1024" height="768" src="https://www.youtube.com/embed/_7gnN7xBIlM" frameborder="0" allowfullscreen=""></iframe> +</div> + +<p>After Saturday’s exciting flight session, Arpan and I couldn’t get enough and ended up exhorting Vaibhav for another flying session on Sunday.</p> + +<p class="center"><img src="/img/drone2.jpg" alt="drone2" title="drone2" style="max-height: 500px;" /></p> + +<p>This time we took off from Vaibhav’s roof (14 storeys high) getting an aerial perspective and a larger field of view to maneuver the drone. We flew past the lake again and also took cinematic landscape shots of the NRI colony.</p> + +<div class="videowrapper"> + <iframe width="1024" height="768" src="https://www.youtube.com/embed/iOXtOOut9f4" frameborder="0" allowfullscreen=""></iframe> +</div> + +<p>Overall, it was a weekend well spent. Also, this happens to be my last weekend here in Mumbai as I fly to Tokyo this Saturday for my internship.</p> + + Sun, 20 May 2018 00:00:00 +0530 + http://localhost:4000/2018/05/20/flying-dji-mavic.html + http://localhost:4000/2018/05/20/flying-dji-mavic.html + + drone + + + + + + Voice Conversion- Machine Learning Project + <p>As the course project for CS 419 - Introducing to Machine Learning, Spring 2018, I teamed up with Arpan Banerjee and Srivatsan Sridhar to work on the task of Voice Conversion.</p> + +<p>We built a pipelined approach to convert one person’s voice into another person’s voice. We proposed a deep learning approach to convert source waveform to phonemes and further phonemes to target waveform. This approach consisted of two neural networks. +The first network was used to convert the source speaker’s waveforms to phonemes.</p> + +<p class="center"><img src="/img/voice-conversion/net1.png" alt="Net1" title="Net1" style="max-height: 500px;" /></p> + +<p>While the second network involved converting the obtained phonemes to the target speaker’s waveforms.</p> + +<p class="center"><img src="/img/voice-conversion/net2.png" alt="Net2" title="Net2" style="max-height: 500px;" /></p> + +<p>We used the TIMIT (different sources) and CMU ARCTIC (single target) corpus respectively for training our network. As part of our project, we performed extensive experimentation with bi-directional Recurrent Neural Networks using LSTM and GRU cells.</p> + +<p>We’ve used the multitask approach to train the network as per both the mel spectral coefficients (as an intermediate representation) and magnitude spectrum which forms the final output while using a pyramidal network architecture.</p> + +<p class="center"><img src="/img/voice-conversion/multitask.png" alt="multitask" title="multitask" style="max-height: 500px;" /></p> + +<p>Our experiments and approaches are detailed here- <a href="/docs/voice_conversion_report.pdf">Report</a></p> + + Mon, 30 Apr 2018 00:00:00 +0530 + http://localhost:4000/2018/04/30/voice-conversion.html + http://localhost:4000/2018/04/30/voice-conversion.html + + Machine Learning + + Reinforcement Learning + + + + + + Update time on Windows with IIT Bombay NTP server + <p><em>The following blog post discusses two solutions to updating time through an external/local NTP server on a Windows machine.</em></p> + +<h1 id="problem">Problem</h1> +<p><strong>Windows would not update time using the standard NTP servers since they are blocked on the network.</strong></p> + +<p>The system time often gets messed up when <strong>switching between different operating systems on a multi-boot machine</strong> (solution to this specific problem in <a href="#appendix">appendix</a>). This problem arises when you are on a network (like the IIT Bombay network) that blocks outside NTP servers. IIT Bombay has its own NTP server- ntp.iitb.ac.in. All other standard NTP servers (like time.windows.com, time.nist.gov, pool.ntp.org) are blocked.</p> + +<p>This problem can be <a href="https://askubuntu.com/questions/14558/how-do-i-setup-a-local-ntp-server">easily solved</a> on linux machines by simply adding the NTP server to <code class="highlighter-rouge">/etc/ntp.conf</code>. However, in Windows, the control panel settings would not allow you to add an external NTP server (in our case ntp.iitb.ac.in).</p> + +<p class="center"><img src="/img/ntp_no_option.png" alt="ntp_no_option" title="No Option" style="max-height: 500px;" /></p> + +<p>Trying to force an update through a pre-defined NTP server (like time.nist.gov) results in a time out, as shown-</p> + +<p class="center"><img src="/img/ntp_timeout.png" alt="ntp_timeout" title="Timeout" style="max-height: 500px;" /></p> + +<h3 id="checking-if-an-ntp-server-is-accessible-">Checking if an NTP server is accessible-</h3> +<p>On windows you can check if an NTP server is accessible by running the following command in command prompt-</p> + +<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>w32tm /stripchart /computer:ntp.iitb.ac.in /dataonly /samples:3 +</code></pre></div></div> +<p>(Replace ntp.iitb.ac.in with your NTP server address)</p> + +<p>This command is analogous to running <code class="highlighter-rouge">ntpdate -q ntp.iitb.ac.in</code> on a linux machine.</p> + +<p>Testing the above command on IIT-B network, reveals this-</p> + +<p class="center"><img src="/img/cmd_check_ntp_server.png" alt="cmd_check_ntp_server" title="cmd check ntp server" style="max-height: 500px;" /></p> + +<p>time.nist.gov is inaccessible while ntp.iitb.ac.in is accessible.</p> + +<hr /> + +<h1 id="solution-1-python-script-with-windows-task-scheduler">Solution 1: Python Script with Windows Task Scheduler</h1> + +<h3 id="description">Description:</h3> +<p>Make a list of NTP servers, and send a request to each until a response is received. Use socket to send a request to the NTP server on port 123. (Reference: <a href="http://code.activestate.com/recipes/117211-simple-very-sntp-client/">Simon Foster’s recipe</a>). Use win32api to update system time.</p> + +<h3 id="step-1-install-dependencies">Step 1: Install Dependencies</h3> +<p>All dependencies are standard libraries apart from win32api (a.k.a. pywin32).</p> + +<p>Install <code class="highlighter-rouge">pywin32</code> from <a href="https://sourceforge.net/projects/pywin32/">here</a> or simply do a <code class="highlighter-rouge">pip install pywin32</code>.<br /> +To install pip for Windows, refer <a href="https://stackoverflow.com/questions/4750806/how-do-i-install-pip-on-windows">this</a>.</p> + +<h3 id="step-2-download-the-script">Step 2: Download the script</h3> +<p>The script can be found in <a href="https://gist.github.com/nihal111/23faa51c3f88a281b676dcbac77ce015">this gist</a>.<br /> +Find Raw file <a href="https://gist.githubusercontent.com/nihal111/23faa51c3f88a281b676dcbac77ce015/raw/fc1e5009837ab7920cd34acc8113c2451618e6f5/ntp_update_time.py">here</a>.</p> + +<p>This script is tested with Python 2 and 3.</p> + +<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="kn">import</span> <span class="nn">socket</span> +<span class="kn">import</span> <span class="nn">struct</span> +<span class="kn">import</span> <span class="nn">sys</span> +<span class="kn">import</span> <span class="nn">time</span> +<span class="kn">import</span> <span class="nn">datetime</span> +<span class="kn">import</span> <span class="nn">win32api</span> + +<span class="c"># List of servers in order of attempt of fetching</span> +<span class="n">server_list</span> <span class="o">=</span> <span class="p">[</span><span class="s">'ntp.iitb.ac.in'</span><span class="p">,</span> <span class="s">'time.nist.gov'</span><span class="p">,</span> <span class="s">'time.windows.com'</span><span class="p">,</span> <span class="s">'pool.ntp.org'</span><span class="p">]</span> + +<span class="s">''' +Returns the epoch time fetched from the NTP server passed as argument. +Returns none if the request is timed out (5 seconds). +'''</span> +<span class="k">def</span> <span class="nf">gettime_ntp</span><span class="p">(</span><span class="n">addr</span><span class="o">=</span><span class="s">'time.nist.gov'</span><span class="p">):</span> + <span class="c"># http://code.activestate.com/recipes/117211-simple-very-sntp-client/</span> + <span class="n">TIME1970</span> <span class="o">=</span> <span class="mi">2208988800</span> <span class="c"># Thanks to F.Lundh</span> + <span class="n">client</span> <span class="o">=</span> <span class="n">socket</span><span class="o">.</span><span class="n">socket</span><span class="p">(</span> <span class="n">socket</span><span class="o">.</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">socket</span><span class="o">.</span><span class="n">SOCK_DGRAM</span> <span class="p">)</span> + <span class="n">data</span> <span class="o">=</span> <span class="s">'</span><span class="se">\x1b</span><span class="s">'</span> <span class="o">+</span> <span class="mi">47</span> <span class="o">*</span> <span class="s">'</span><span class="se">\0</span><span class="s">'</span> + <span class="k">try</span><span class="p">:</span> + <span class="c"># Timing out the connection after 5 seconds, if no response received</span> + <span class="n">client</span><span class="o">.</span><span class="n">settimeout</span><span class="p">(</span><span class="mf">5.0</span><span class="p">)</span> + <span class="n">client</span><span class="o">.</span><span class="n">sendto</span><span class="p">(</span> <span class="n">data</span><span class="p">,</span> <span class="p">(</span><span class="n">addr</span><span class="p">,</span> <span class="mi">123</span><span class="p">))</span> + <span class="n">data</span><span class="p">,</span> <span class="n">address</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">recvfrom</span><span class="p">(</span> <span class="mi">1024</span> <span class="p">)</span> + <span class="k">if</span> <span class="n">data</span><span class="p">:</span> + <span class="n">epoch_time</span> <span class="o">=</span> <span class="n">struct</span><span class="o">.</span><span class="n">unpack</span><span class="p">(</span> <span class="s">'!12I'</span><span class="p">,</span> <span class="n">data</span> <span class="p">)[</span><span class="mi">10</span><span class="p">]</span> + <span class="n">epoch_time</span> <span class="o">-=</span> <span class="n">TIME1970</span> + <span class="k">return</span> <span class="n">epoch_time</span> + <span class="k">except</span> <span class="n">socket</span><span class="o">.</span><span class="n">timeout</span><span class="p">:</span> + <span class="k">return</span> <span class="bp">None</span> + +<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">"__main__"</span><span class="p">:</span> + <span class="c"># Iterates over every server in the list until it finds time from any one.</span> + <span class="k">for</span> <span class="n">server</span> <span class="ow">in</span> <span class="n">server_list</span><span class="p">:</span> + <span class="n">epoch_time</span> <span class="o">=</span> <span class="n">gettime_ntp</span><span class="p">(</span><span class="n">server</span><span class="p">)</span> + <span class="k">if</span> <span class="n">epoch_time</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span> + <span class="c"># SetSystemTime takes time as argument in UTC time. UTC time is obtained using utcfromtimestamp()</span> + <span class="n">utcTime</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">utcfromtimestamp</span><span class="p">(</span><span class="n">epoch_time</span><span class="p">)</span> + <span class="n">win32api</span><span class="o">.</span><span class="n">SetSystemTime</span><span class="p">(</span><span class="n">utcTime</span><span class="o">.</span><span class="n">year</span><span class="p">,</span> <span class="n">utcTime</span><span class="o">.</span><span class="n">month</span><span class="p">,</span> <span class="n">utcTime</span><span class="o">.</span><span class="n">weekday</span><span class="p">(),</span> <span class="n">utcTime</span><span class="o">.</span><span class="n">day</span><span class="p">,</span> <span class="n">utcTime</span><span class="o">.</span><span class="n">hour</span><span class="p">,</span> <span class="n">utcTime</span><span class="o">.</span><span class="n">minute</span><span class="p">,</span> <span class="n">utcTime</span><span class="o">.</span><span class="n">second</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> + <span class="c"># Local time is obtained using fromtimestamp()</span> + <span class="n">localTime</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">fromtimestamp</span><span class="p">(</span><span class="n">epoch_time</span><span class="p">)</span> + <span class="k">print</span><span class="p">(</span><span class="s">"Time updated to: "</span> <span class="o">+</span> <span class="n">localTime</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s">"</span><span class="si">%</span><span class="s">Y-</span><span class="si">%</span><span class="s">m-</span><span class="si">%</span><span class="s">d </span><span class="si">%</span><span class="s">H:</span><span class="si">%</span><span class="s">M"</span><span class="p">)</span> <span class="o">+</span> <span class="s">" from "</span> <span class="o">+</span> <span class="n">server</span><span class="p">)</span> + <span class="k">break</span> + <span class="k">else</span><span class="p">:</span> + <span class="k">print</span><span class="p">(</span><span class="s">"Could not find time from "</span> <span class="o">+</span> <span class="n">server</span><span class="p">)</span></code></pre></figure> + +<p>Download the file and save it at a location you’ll remember. +For the purpose of this demonstration, I’ll be saving it inside- <code class="highlighter-rouge">C:\Python27\ntp_update_time.py</code> with my Python installation directory as <code class="highlighter-rouge">C:\Python27</code>.</p> + +<h3 id="step-3-test-the-script">Step 3: Test the script</h3> +<p>Open Command Prompt with admin privileges- Hit key combo <code class="highlighter-rouge">Windows</code> + <code class="highlighter-rouge">X</code>, and click on <code class="highlighter-rouge">Command Prompt (Admin)</code>.</p> + +<p>Type:</p> +<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd C:\Python27 +python ntp_update_time.py +</code></pre></div></div> + +<p>If you were on IIT-B network and everything worked well, it should say- <code class="highlighter-rouge">Time updated to: 2018-03-30 19:04 from ntp.iitb.ac.in</code></p> + +<h3 id="step-4-schedule-a-task">Step 4: Schedule a Task</h3> +<p>Similar to a cronjob in Unix, you can create a task to run periodically using Windows Task Scheduler.</p> + +<ul> + <li> + <p>Search for “Task Scheduler” from the start menu and open it.</p> + </li> + <li> + <p>Create a basic task from the Actions menu at the right</p> + </li> +</ul> + +<p class="center"><img src="/img/ntp_ts_1.png" alt="ntp_ts_1" title="ntp_ts_1" style="max-height: 500px;" /></p> + +<ul> + <li>Under the General tab, give a name and description to the task. Check the “Run with highest privileges” checkbox.</li> +</ul> + +<p class="center"><img src="/img/ntp_ts_2.png" alt="ntp_ts_2" title="ntp_ts_2" style="max-height: 500px;" /></p> + +<ul> + <li>Under the Triggers tab, click on New, and set “Begin the task:” to “On workstation unlock”. Leave everything as is, and hit Ok.</li> +</ul> + +<p class="center"><img src="/img/ntp_ts_3.png" alt="ntp_ts_3" title="ntp_ts_3" style="max-height: 500px;" /></p> + +<ul> + <li>Under the Actions tab, set Program/Script to your python path (<code class="highlighter-rouge">C:\Python27\python.exe</code>) and set “Add arguments (optional)” to the script path (<code class="highlighter-rouge">C:\Python27\ntp_update_time.py</code>).</li> +</ul> + +<p class="center"><img src="/img/ntp_ts_4.png" alt="ntp_ts_4" title="ntp_ts_4" style="max-height: 500px;" /></p> + +<ul> + <li>Under the Conditions tab, uncheck the checkbox under Power which says “Start the task only if the computer is on AC power”.</li> +</ul> + +<p class="center"><img src="/img/ntp_ts_5.png" alt="ntp_ts_5" title="ntp_ts_5" style="max-height: 500px;" /></p> + +<ul> + <li>Hit Ok and save the Task. Return to the Task Scheduler window, double click on “Task Scheduler Library” on the left navigation drawer. Select the task you made from the list and click on it. Hit “Run” from the right hand actions menu. (Make sure to screw up your system time before running. If it gets fixed after you run the task, everything is set up to work.)</li> +</ul> + +<p class="center"><img src="/img/ntp_ts_6.png" alt="ntp_ts_6" title="ntp_ts_6" style="max-height: 500px;" /></p> + +<p>The task would be scheduled to run every time you unlock your machine. This makes sense since mostly the time gets messed up when switching between two different Operating Systems on a multi-boot machine.</p> + +<hr /> + +<h1 id="solution-2-use-windows-time-service-tools-to-query-local-ntp-server">Solution 2: Use Windows Time Service tools to query local NTP server</h1> + +<p>This solution uses the Windows Time Service tool to add an external/local NTP server.</p> + +<ol> + <li>Open Command Prompt with admin privileges- Hit key combo <code class="highlighter-rouge">Windows</code> + <code class="highlighter-rouge">X</code>, and click on <code class="highlighter-rouge">Command Prompt (Admin)</code>.</li> + <li>Stop the time service- <code class="highlighter-rouge">net stop w32time</code></li> + <li>Type in <code class="highlighter-rouge">w32tm /config /syncfromflags:manual /manualpeerlist:"ntp.iitb.ac.in,pool.ntp.org"</code> to manually set the list of external/local NTP servers.</li> + <li>Force set the connection as reliable- <code class="highlighter-rouge">w32tm /config /reliable:yes</code></li> + <li>Start the time service- <code class="highlighter-rouge">net start w32time</code></li> + <li>Check if the configuration has been written successfully- <code class="highlighter-rouge">w32tm /query /configuration</code> and <code class="highlighter-rouge">w32tm /query /status</code>. You should see “NtpServer: ntp.iitb.ac.in,pool.ntp.org (Local)”.</li> + <li>Do a <code class="highlighter-rouge">w32tm /resync</code> to force an update. (Make sure your system time is messed up to see if it gets corrected).</li> +</ol> + +<hr /> + +<h1 id="solution-3-no-ntp-server-reachable-update-using-https">Solution 3: No NTP server reachable, update using HTTPS</h1> +<p>In case you are unable to reach any NTP server, you can use the following script to update the time by scraping duration since epoch time from www.unixtimestamp.com.</p> + +<p>The script can be found in <a href="https://gist.github.com/nihal111/7d95fa52fb91bf3298947cd36b700ce8">this gist</a>.<br /> +Find Raw file <a href="https://gist.githubusercontent.com/nihal111/7d95fa52fb91bf3298947cd36b700ce8/raw/b65d8c187329d85ac971efc23291c06eff4d433b/update_time.py">here</a>.</p> + +<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="kn">import</span> <span class="nn">requests</span> +<span class="kn">import</span> <span class="nn">datetime</span> +<span class="kn">import</span> <span class="nn">win32api</span> + +<span class="n">page</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'https://www.unixtimestamp.com/'</span><span class="p">,</span> <span class="n">headers</span><span class="o">=</span><span class="p">{</span><span class="s">'Cache-Control'</span><span class="p">:</span> <span class="s">'no-cache'</span><span class="p">})</span> +<span class="n">text</span> <span class="o">=</span> <span class="n">page</span><span class="o">.</span><span class="n">text</span> + + +<span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">text</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">):</span> + <span class="n">match_text</span> <span class="o">=</span> <span class="s">"&lt;h3 class=</span><span class="se">\"</span><span class="s">text-danger</span><span class="se">\"</span><span class="s">&gt;"</span> + <span class="n">suffix</span> <span class="o">=</span> <span class="s">" &lt;small&gt;seconds since Jan 01 1970. (UTC)&lt;/small&gt;&lt;/h3&gt;"</span> + <span class="k">if</span> <span class="n">match_text</span> <span class="ow">in</span> <span class="n">line</span><span class="p">:</span> + <span class="n">line</span> <span class="o">=</span> <span class="n">line</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">'&lt;'</span><span class="p">,</span><span class="s">' '</span><span class="p">)</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">'&gt;'</span><span class="p">,</span><span class="s">' '</span><span class="p">)</span> + <span class="n">epoch_time</span> <span class="o">=</span> <span class="p">[</span><span class="nb">int</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="k">for</span> <span class="n">s</span> <span class="ow">in</span> <span class="n">line</span><span class="o">.</span><span class="n">split</span><span class="p">()</span> <span class="k">if</span> <span class="n">s</span><span class="o">.</span><span class="n">isdigit</span><span class="p">()][</span><span class="mi">0</span><span class="p">]</span> + <span class="k">break</span> + +<span class="n">utcTime</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">utcfromtimestamp</span><span class="p">(</span><span class="n">epoch_time</span><span class="p">)</span> + +<span class="k">try</span><span class="p">:</span> + <span class="c"># SetSystemTime takes time as argument in UTC time</span> + <span class="n">win32api</span><span class="o">.</span><span class="n">SetSystemTime</span><span class="p">(</span><span class="n">utcTime</span><span class="o">.</span><span class="n">year</span><span class="p">,</span> <span class="n">utcTime</span><span class="o">.</span><span class="n">month</span><span class="p">,</span> <span class="n">utcTime</span><span class="o">.</span><span class="n">weekday</span><span class="p">(),</span> <span class="n">utcTime</span><span class="o">.</span><span class="n">day</span><span class="p">,</span> <span class="n">utcTime</span><span class="o">.</span><span class="n">hour</span><span class="p">,</span> <span class="n">utcTime</span><span class="o">.</span><span class="n">minute</span><span class="p">,</span> <span class="n">utcTime</span><span class="o">.</span><span class="n">second</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> + <span class="n">localTime</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">fromtimestamp</span><span class="p">(</span><span class="n">epoch_time</span><span class="p">)</span> + <span class="k">print</span><span class="p">(</span><span class="s">"Time updated to: "</span> <span class="o">+</span> <span class="n">localTime</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s">"</span><span class="si">%</span><span class="s">Y-</span><span class="si">%</span><span class="s">m-</span><span class="si">%</span><span class="s">d </span><span class="si">%</span><span class="s">H:</span><span class="si">%</span><span class="s">M"</span><span class="p">))</span> +<span class="k">except</span><span class="p">:</span> + <span class="k">print</span><span class="p">(</span><span class="s">"Could not update time"</span><span class="p">)</span></code></pre></figure> + +<ol> + <li>Install requests- <code class="highlighter-rouge">pip install requests</code>. +To install pip for Windows, refer <a href="https://stackoverflow.com/questions/4750806/how-do-i-install-pip-on-windows">this</a>.</li> + <li>Follow Step 3 and Step 4 from Solution 1, using the script above.</li> +</ol> + +<hr /> + +<h3 id="appendix">Appendix</h3> + +<p>Specifically pertaining to the problem of the system time going haywire when dual booting across Windows and Linux, the <a href="https://help.ubuntu.com/community/UbuntuTime#Multiple_Boot_Systems_Time_Conflicts">Official Ubuntu documentation explains</a> what causes this.</p> + +<p>In essence, Linux/Unix systems store UTC as the time on the hardware clock and with good reason, since this saves unnecessary changes to the hardware clock when moving between timezones. On the other hand, Windows stores the local time as the time on the hardware clock. This ends up messing with the system time since both OS deal with the hardware clock differently.</p> + +<p>The <a href="https://help.ubuntu.com/community/UbuntuTime#Multiple_Boot_Systems_Time_Conflicts">Official Ubuntu Docs</a> list down a step by step solution to avoid this from happening.</p> + +<hr /> + +<p>That should save you from manually setting time again.</p> + +<p>Till next ‘time’..<br /> +Cheers!</p> + + Fri, 30 Mar 2018 00:00:00 +0530 + http://localhost:4000/2018/03/30/ntp-update-time.html + http://localhost:4000/2018/03/30/ntp-update-time.html + + python + + windows + + + + + + CFS Visualizer- Operating Systems Project + <p>As the course project for CS 347 - Operating Systems, Fall 2017, I teamed up with Arpan Banerjee and Srivatsan Sridhar to work on building a visulizer for the Completely Fair Scheduler that’s widely present in all Linux systems as the default scheduler.</p> + +<p>The visualizer is available at- <a href="https://nihal111.github.io/CFS-visualizer/">https://nihal111.github.io/CFS-visualizer/</a>.</p> + +<h3 id="schedulers">Schedulers</h3> + +<p>Linux is a multitasking operating system, and therefore, it has a scheduler to manage the processes. The Linux scheduler has evolved over time. With the Linux Kernerl 2.6, the O(1) scheduler came in. It relies on active and expired arrays of processes to achieve constant scheduling time. Each process is given a fixed time quantum, after which it is preempted and moved to the expired array. Once all the tasks from the active array have exhausted their time quantum and have been moved to the expired array, an array switch takes place. This switch makes the active array the new empty expired array, while the expired array becomes the active array. The main issue with this algorithm is the complex heuristics used to mark a task as interactive or non-interactive.</p> + +<h3 id="the-completely-fair-scheduler">The Completely Fair Scheduler</h3> + +<p>The Completely Fair Scheduler is a process scheduler that handles CPU resource allocation for executing processes and aims to maximize overall CPU utilization while also maximizing interactive performance. This was merged into the 2.6.23 (October 2007) release of the Linux kernel and is the default scheduler.</p> + +<p>By “Completely Fair”, the CFS Scheduler means to allocate the CPU resources equally and fairly among all the queued processes depending on their nice values.</p> + +<p>The Completely Fair Scheduler uses a Red-Black tree to keep track of all the queued processes and handles switching with a nano second granularity. The fair queuing CFS scheduler has a scheduling complexity of <code class="highlighter-rouge">O(log N)</code>, where <code class="highlighter-rouge">N</code> is the number of tasks in the runqueue. Choosing a task can be done in constant time, but reinserting a task after it has run requires <code class="highlighter-rouge">O(log N)</code> operations, because the runqueue is implemented as a red-black tree. +The Visualizer</p> + +<p>The <a href="https://nihal111.github.io/CFS-visualizer/">CFS visualizer</a> allows one to look at the process queue and the populated dynamic red-black tree while the scheduler is in action. The time scale has been magnified so that one can slow down and visualize the scheduler with nano-second granularity work in real time.</p> + + Wed, 15 Nov 2017 00:00:00 +0530 + http://localhost:4000/2017/11/15/cfs-visualizer.html + http://localhost:4000/2017/11/15/cfs-visualizer.html + + Machine Learning + + Reinforcement Learning + + + + + + GSoC Wrap Up + <style type="text/css"> +.collapsiblecontainer { +width:100%; +border:1px solid #d3d3d3; +} +.collapsiblecontainer div { +width:100%; +} +.collapsiblecontainer .collapsibleheader { +background-color:#d3d3d3; +padding: 2px; +cursor: pointer; +font-weight: bold; +} +.collapsiblecontainer .collapsiblecontent { +display: none; +padding : 5px; +} +</style> + +<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script> + +<script type="text/javascript" src="/js/github-buttons.js"></script> + +<script type="text/javascript"> +$(document) .ready(function() { +$(".collapsibleheader") .click(function () { +$collapsibleheader = $(this) ; +//getting the next element +$collapsiblecontent = $collapsibleheader.next() ; +//open up the collapsiblecontent needed - toggle the slide- if visible, slide up, if not slidedown. +$collapsiblecontent.slideToggle(500, function () { +//execute this after slideToggle is done +//change text of collapsibleheader based on visibility of collapsiblecontent div +$collapsibleheader.find("span:first-child") .text(function () { +//change text based on condition +return $collapsiblecontent.is(":visible") ? "- " : "+ "; +}) ; +}) ; + +}) ; +}) ; + +</script> + +<p>Finally it is time for wrapping up my GSoC project and along with it a highly eventful summer. It has been an amazing experience. I’ve learned a lot over the summer, spending countless days and nights in a row to add new things to this game. The community has been more than helpful. I couldn’t have asked for more.</p> + +<p>This wrap up post links to all the work done over the summer. There have been a total of <strong>72 PRs</strong> and quite a few independent commits in the new modules I’ve created. With over <strong>19,000 lines of code</strong>, this summer has boosted my Github stats to a whole new level.</p> + +<p class="center"><img src="/img/GSoCStreak.png" alt="GSoCStreak" title="GSoCStreak" style="max-height: 500px;" /></p> + +<h2 id="final-product">Final Product</h2> +<p>The final product out of my GSoC is a whole new gameplay setting in the world of Terasology. It is a single player gameplay mode called <strong>Lost</strong>. You take up the role of a player that ends up stranded on a planet with no way left to get back home. Set on an expedition to find signs of life in neighbouring galaxies, you come across several intriguing things that confirm the existence of intelligent life outside your planet. <em>Are you truly lost? Will you ever return home?</em></p> + +<p class="center"><img src="/img/lostBackground.jpg" alt="lostBackground" title="Lost" style="max-height: 500px;" /></p> + +<p>To test it out simply follow the below instructions-</p> + +<h4 id="instructions-to-run-lost">Instructions to run Lost:</h4> +<ol> + <li>Download <a href="https://slack-files.com/T03G8SB1X-F6N474GS0-867f5f5289">this</a> Omega.</li> + <li>Extract the Omega.</li> + <li>Move the save folder called “Lost” inside <code class="highlighter-rouge">omega796/saves</code> to the save directory- + <ul> + <li>in Windows, C:/Users/name/Saved Games/Terasology/</li> + <li>in Linux, /home/name/.local/share/terasology/saves/<br /> +<strong><em>Alternatively</em></strong>, you can run the game with the <code class="highlighter-rouge">-homedir</code> flag.</li> + <li>in Windows, run the game from cmd using a command like: <code class="highlighter-rouge">Terasology.x64.exe -homedir</code> +or add the <code class="highlighter-rouge">-homedir</code> flag to the target field of the shortcut to the exe file.</li> + <li>in Linux, modify the run_linux.sh script so that it has a <code class="highlighter-rouge">-homedir</code> flag at the end, like so: +<code class="highlighter-rouge">java -Xms128m -Xmx1536m -jar libs/Terasology.jar -homedir</code></li> + </ul> + </li> + <li>Launch the game using the script or the .exe file.</li> + <li>Select Singleplayer -&gt; Lost and load the saved game.</li> +</ol> + +<h3 id="list-of-new-modules-created-">List of new modules created-</h3> + +<ul> + <li><a href="https://github.com/Terasology/AdvancedBehaviors">Terasology/AdvancedBehaviors</a></li> + <li><a href="https://github.com/Terasology/WorldlyTooltipAPI">Terasology/WorldlyTooltipAPI</a></li> + <li><a href="https://github.com/Terasology/WoodAndStoneCraftingJournal">Terasology/WoodAndStoneCraftingJournal</a></li> + <li><a href="https://github.com/Terasology/AdventureAssets">Terasology/AdventureAssets</a></li> + <li><a href="https://github.com/Terasology/Lost">Terasology/Lost</a></li> +</ul> + +<p class="center"><img src="/img/newModules.png" alt="newModules" title="newModules" style="max-height: 500px;" /></p> + +<h3 id="list-of-repositories-contributed-to-">List of repositories contributed to-</h3> + +<ul> + <li><a href="https://github.com/MovingBlocks/Terasology">Engine- MovingBlocks/Terasology</a></li> +</ul> + +<p class="center"><img src="/img/engine.png" alt="engine" title="engine" style="max-height: 500px;" /></p> + +<ul> + <li><a href="https://github.com/Terasology/WildAnimals">Terasology/WildAnimals</a></li> + <li><a href="https://github.com/Terasology/StructureTemplates">Terasology/StructureTemplates</a></li> + <li><a href="https://github.com/Terasology/Books">Terasology/Books</a></li> + <li><a href="https://github.com/Terasology/WorldlyTooltip">Terasology/WorldlyTooltip</a></li> + <li><a href="https://github.com/Terasology/Projectile">Terasology/Projectile</a></li> + <li><a href="https://github.com/Terasology/Pathfinding">Terasology/Pathfinding</a></li> + <li><a href="https://github.com/Terasology/Journal">Terasology/Journal</a></li> + <li><a href="https://github.com/Terasology/Scenario">Terasology/Scenario</a></li> + <li><a href="https://github.com/Terasology/Thirst">Terasology/Thirst</a></li> + <li><a href="https://github.com/Terasology/Hunger">Terasology/Hunger</a></li> +</ul> + +<p class="center"><img src="/img/oldModules.jpg" alt="oldModules" title="oldModules" style="max-height: 700px;" /></p> + +<h3 id="list-of-pull-requests-">List of Pull Requests-</h3> + +<p>Here is a <a href="https://github.com/pulls?utf8=%E2%9C%93&amp;q=is%3Apr+is%3Amerged+author%3Anihal111+created%3A2017-05-04..2017-08-15+">list of pull requests</a> from the start of GSoC up until now.</p> + +<div class="collapsiblecontainer"> +<div class="collapsibleheader"><span>+ </span><span>Click here to view all PRs?</span></div> +<div class="collapsiblecontent"> +<a href="https://github.com/MovingBlocks/Terasology/pull/3065"><strong>MovingBlocks/Terasology</strong> Added setSpawnLocation command</a><br /> +<a href="https://github.com/Terasology/AdventureAssets/pull/20"><strong>Terasology/AdventureAssets</strong> Added MCQ Button Door</a><br /> +<a href="https://github.com/MovingBlocks/Terasology/pull/3061"><strong>MovingBlocks/Terasology</strong> Added removeAllWidgets method API UI</a><br /> +<a href="https://github.com/MovingBlocks/Terasology/pull/3033"><strong>MovingBlocks/Terasology</strong> Dead players alive-d on join</a><br /> +<a href="https://github.com/Terasology/StructureTemplates/pull/20"><strong>Terasology/StructureTemplates</strong> Consumes AttackEvent for BlockRegions</a><br /> +<a href="https://github.com/MovingBlocks/Terasology/pull/3030"><strong>MovingBlocks/Terasology</strong> PlayerDeath event should be sent to character entity</a><br /> +<a href="https://github.com/Terasology/Hunger/pull/12"><strong>Terasology/Hunger</strong> Fix for Hunger related Alive/Death handling</a><br /> +<a href="https://github.com/Terasology/Thirst/pull/5"><strong>Terasology/Thirst</strong> Fix for Thirst related Alive/Death handling</a><br /> +<a href="https://github.com/Terasology/AdventureAssets/pull/19"><strong>Terasology/AdventureAssets</strong> Added NoInteraction component</a><br /> +<a href="https://github.com/MovingBlocks/Terasology/pull/3024"><strong>MovingBlocks/Terasology</strong> Checking isHeadless from DisplayDevice</a><br /> +<a href="https://github.com/MovingBlocks/Terasology/pull/3020"><strong>MovingBlocks/Terasology</strong> Change ActivationPredicted to consumable event</a><br /> +<a href="https://github.com/Terasology/StructureTemplates/pull/18"><strong>Terasology/StructureTemplates</strong> Consuming ActivationPredicted event</a><br /> +<a href="https://github.com/Terasology/Scenario/pull/33"><strong>Terasology/Scenario</strong> Added Protected Regions and Resizing functionality</a><br /> +<a href="https://github.com/Terasology/Projectile/pull/4"><strong>Terasology/Projectile</strong> MaxDistance check during displacement calculation</a><br /> +<a href="https://github.com/Terasology/AdventureAssets/pull/18"><strong>Terasology/AdventureAssets</strong> Structure Template Integration fixes</a><br /> +<a href="https://github.com/Terasology/Books/pull/15"><strong>Terasology/Books</strong> Multiplayer + newline fix</a><br /> +<a href="https://github.com/Terasology/AdventureAssets/pull/17"><strong>Terasology/AdventureAssets</strong> Swinging Blade is multiplayer ready</a><br /> +<a href="https://github.com/Terasology/AdventureAssets/pull/16"><strong>Terasology/AdventureAssets</strong> WipeOut is multiplayer ready</a><br /> +<a href="https://github.com/Terasology/AdventureAssets/pull/15"><strong>Terasology/AdventureAssets</strong> Fixed Fireball Launcher for multiplayer</a><br /> +<a href="https://github.com/Terasology/AdventureAssets/pull/14"><strong>Terasology/AdventureAssets</strong> Door works in multiplayer</a><br /> +<a href="https://github.com/Terasology/AdventureAssets/pull/13"><strong>Terasology/AdventureAssets</strong> Password Door is now multiplayer ready</a><br /> +<a href="https://github.com/MovingBlocks/Terasology/pull/2994"><strong>MovingBlocks/Terasology</strong> Added door related events</a><br /> +<a href="https://github.com/MovingBlocks/Terasology/pull/2993"><strong>MovingBlocks/Terasology</strong> FloatingTextRenderer accepts multiple \n separated lines</a><br /> +<a href="https://github.com/MovingBlocks/Terasology/pull/2988"><strong>MovingBlocks/Terasology</strong> Multiline UIText, enter produces newline</a><br /> +<a href="https://github.com/MovingBlocks/Terasology/pull/2987"><strong>MovingBlocks/Terasology</strong> Store DoorRegion prefab as component parameter</a><br /> +<a href="https://github.com/Terasology/AdventureAssets/pull/12"><strong>Terasology/AdventureAssets</strong> Added a UI Screen Password locked Door</a><br /> +<a href="https://github.com/MovingBlocks/Terasology/pull/2983"><strong>MovingBlocks/Terasology</strong> Separated spawnLocation calculation from respawnPlayer method</a><br /> +<a href="https://github.com/Terasology/AdventureAssets/pull/11"><strong>Terasology/AdventureAssets</strong> Add the Revival Stone</a><br /> +<a href="https://github.com/Terasology/AdventureAssets/pull/10"><strong>Terasology/AdventureAssets</strong> Moved duplicate methods to utility class</a><br /> +<a href="https://github.com/Terasology/AdventureAssets/pull/9"><strong>Terasology/AdventureAssets</strong> Remember rotation after mining of trap blocks</a><br /> +<a href="https://github.com/Terasology/Projectile/pull/3"><strong>Terasology/Projectile</strong> Revert to old constructor</a><br /> +<a href="https://github.com/Terasology/AdventureAssets/pull/8"><strong>Terasology/AdventureAssets</strong> Added more parameters for Fireball with Structure Template integration</a><br /> +<a href="https://github.com/Terasology/Projectile/pull/2"><strong>Terasology/Projectile</strong> Changed CollisionGroup filter to ALL</a><br /> +<a href="https://github.com/Terasology/Projectile/pull/1"><strong>Terasology/Projectile</strong> Added new event constructor for configurable maxDistance</a><br /> +<a href="https://github.com/Terasology/DamagingBlocks/pull/6"><strong>Terasology/DamagingBlocks</strong> Reverted the AliveCharacter check</a><br /> +<a href="https://github.com/Terasology/AdventureAssets/pull/6"><strong>Terasology/AdventureAssets</strong> Added Fireball Launcher</a><br /> +<a href="https://github.com/MovingBlocks/Terasology/pull/2982"><strong>MovingBlocks/Terasology</strong> Prevents player entity from being destroyed after death onDamage</a><br /> +<a href="https://github.com/Terasology/DamagingBlocks/pull/5"><strong>Terasology/DamagingBlocks</strong> Added Alive Character check</a><br /> +<a href="https://github.com/Terasology/AdventureAssets/pull/5"><strong>Terasology/AdventureAssets</strong> Added Wipeout</a><br /> +<a href="https://github.com/Terasology/AdventureAssets/pull/4"><strong>Terasology/AdventureAssets</strong> Changed trap placement approach to root block</a><br /> +<a href="https://github.com/Terasology/AdventureAssets/pull/3"><strong>Terasology/AdventureAssets</strong> Changed trapPlaceholder block shape and fixed readme</a><br /> +<a href="https://github.com/Terasology/StructureTemplates/pull/16"><strong>Terasology/StructureTemplates</strong> Moved rotation logic</a><br /> +<a href="https://github.com/MovingBlocks/Terasology/pull/2973"><strong>MovingBlocks/Terasology</strong> Fixes <code class="highlighter-rouge">dumpEntities</code> console command</a><br /> +<a href="https://github.com/Terasology/AdventureAssets/pull/2"><strong>Terasology/AdventureAssets</strong> Added SwingingBlade</a><br /> +<a href="https://github.com/Terasology/StructureTemplates/pull/15"><strong>Terasology/StructureTemplates</strong> Added rotation logic for spawning entities</a><br /> +<a href="https://github.com/Terasology/AdventureAssets/pull/1"><strong>Terasology/AdventureAssets</strong> Add module.txt and gitignore</a><br /> +<a href="https://github.com/Terasology/AdvancedBehaviors/pull/7"><strong>Terasology/AdvancedBehaviors</strong> Added alive character check</a><br /> +<a href="https://github.com/Terasology/Pathfinding/pull/31"><strong>Terasology/Pathfinding</strong> Added alive character check</a><br /> +<a href="https://github.com/Terasology/WildAnimals/pull/16"><strong>Terasology/WildAnimals</strong> Added alive character component</a><br /> +<a href="https://github.com/Terasology/GooeysQuests/pull/14"><strong>Terasology/GooeysQuests</strong> Added alive character component</a><br /> +<a href="https://github.com/Terasology/Journal/pull/4"><strong>Terasology/Journal</strong> Added Recipe and Image paragraph</a><br /> +<a href="https://github.com/Terasology/WoodCrafting/pull/3"><strong>Terasology/WoodCrafting</strong> Moved generators to NeoTTA</a><br /> +<a href="https://github.com/Terasology/NeoTTA/pull/1"><strong>Terasology/NeoTTA</strong> Moved generators from WoodCrafting</a><br /> +<a href="https://github.com/MovingBlocks/Terasology/pull/2962"><strong>MovingBlocks/Terasology</strong> Fixed eye height movement debug command</a><br /> +<a href="https://github.com/Terasology/PhysicalStats/pull/3"><strong>Terasology/PhysicalStats</strong> Fixes missing save component bugs</a><br /> +<a href="https://github.com/MovingBlocks/Terasology/pull/2958"><strong>MovingBlocks/Terasology</strong> Do not destroy player entity completely on death</a><br /> +<a href="https://github.com/Terasology/Journal/pull/3"><strong>Terasology/Journal</strong> Adds different colored entries for Unread Journal entries</a><br /> +<a href="https://github.com/Terasology/Pathfinding/pull/30"><strong>Terasology/Pathfinding</strong> Fixed intelligent flee</a><br /> +<a href="https://github.com/Terasology/AdvancedBehaviors/pull/6"><strong>Terasology/AdvancedBehaviors</strong> Added intelligent flee</a><br /> +<a href="https://github.com/Terasology/Pathfinding/pull/29"><strong>Terasology/Pathfinding</strong> Added intelligent flee</a><br /> +<a href="https://github.com/Terasology/AdvancedBehaviors/pull/5"><strong>Terasology/AdvancedBehaviors</strong> Refactor</a><br /> +<a href="https://github.com/Terasology/AdvancedBehaviors/pull/3"><strong>Terasology/AdvancedBehaviors</strong> Added the fleeInProximity package</a><br /> +<a href="https://github.com/Terasology/WildAnimals/pull/15"><strong>Terasology/WildAnimals</strong> Added a scaredDeer</a><br /> +<a href="https://github.com/Terasology/AdvancedBehaviors/pull/2"><strong>Terasology/AdvancedBehaviors</strong> Added followInProximity package</a><br /> +<a href="https://github.com/Terasology/WildAnimals/pull/14"><strong>Terasology/WildAnimals</strong> Added a friendlyDeer</a><br /> +<a href="https://github.com/Terasology/WildAnimals/pull/13"><strong>Terasology/WildAnimals</strong> Moved packages to AdvancedBehaviors** module</a><br /> +<a href="https://github.com/Terasology/AdvancedBehaviors/pull/1"><strong>Terasology/AdvancedBehaviors</strong> Moved packages from WildAnimals** module</a><br /> +<a href="https://github.com/Terasology/WildAnimals/pull/12"><strong>Terasology/WildAnimals</strong> AttackInProximity- adds hostile-stray behavior switching</a><br /> +<a href="https://github.com/Terasology/FunnyBlocks/pull/11"><strong>Terasology/FunnyBlocks</strong> Portals work in multiplayer</a><br /> +<a href="https://github.com/Terasology/WildAnimals/pull/10"><strong>Terasology/WildAnimals</strong> Added aggressiveDeer</a><br /> +<a href="https://github.com/Terasology/WorldlyTooltip/pull/7"><strong>Terasology/WorldlyTooltip</strong> Configured with WorldlyTooltipAPI module</a><br /> +<a href="https://github.com/MovingBlocks/Terasology/pull/2932"><strong>MovingBlocks/Terasology</strong> Fixes the blocker #2913</a><br /> +<a href="https://github.com/Terasology/WorldlyTooltip/pull/6"><strong>Terasology/WorldlyTooltip</strong> Added character entity support</a><br /> +<a href="https://github.com/MovingBlocks/Terasology/pull/2930"><strong>MovingBlocks/Terasology</strong> BehaviorSystem- use cachedInterpreters</a><br /> +<a href="https://github.com/MovingBlocks/Terasology/pull/2929"><strong>MovingBlocks/Terasology</strong> Worldly tooltip addition for character entities</a><br /> +<a href="https://github.com/Terasology/WildAnimals/pull/9"><strong>Terasology/WildAnimals</strong> Worldly tooltip Integration</a> +</div> +</div> + +<h3 id="what-more-to-look-at">What more to look at?</h3> + +<p>There have been a whole lot of videos I’ve made over the summer. You can have a look at them at <a href="https://www.youtube.com/channel/UCVDrDJDt7sI8A9Ww1FekUMQ">my channel</a>.</p> + +<p>I have also written a set of blog posts marking the progress I made through the summers. A list of all these can be found under the #GSoC tag <a href="http://nihal111.github.io/tags/#GSoC">here</a>.</p> + +<h3 id="whats-next">What’s next?</h3> + +<p>Although I have checked off most of my primary targets from the proposal. There are quite a few things that need work on-</p> +<ol> + <li>Some of the traps like the Swinging Blade work well only in Single Player. This is because the Movement Prediction works quite differently on the server side. The <code class="highlighter-rouge">CharacterImpulseEvent</code> triggers differently even with a little lag.</li> + <li>Traps like the Wipe Out, require the player to move constantly along with the surfboard. There have also been instances when a collision is not detected between the player and the surfboard. Again something to deal with the Movement Prediction and Physics engine.</li> + <li>On the Gameplay side, I’ve attempted to make interesting short riddles for the three treasure locations, however they get boring very fast. The player might feel it is too much effort to solve a text based riddle. It can be difficult to strike the right chord while making riddles and clues that are both short, engaging and require the player to think.</li> + <li>The Portal upon construction does nothing yet. Well, it is supposed to take you back to your home planet. But I guess we could display a “Game Over” dialog or somehow bring up the Credits screen.</li> +</ol> + +<p>Some of these might be fixed by a long overdue movement refactoring. With Tyler Thompson’s Scenario module developed alongside in <a href="https://thompsontyler.github.io/gsoc/2017/08/25/scenario-gsoc.html">another GSoC project</a>, the Lost module serves as an example of how a gameplay scenario can be made.<br /> +With the completion of this GSoC project making adventure assets like locked doors, traps, resurrection statues etc are now a lot more easier. Creation of more such things can probably serve as one of the tougher GCI tasks later.</p> + +<h3 id="wrapping-it-up">Wrapping it up</h3> + +<p>Once again, I would like to thank all my mentors. My primary mentor, <a href="http://forum.terasology.org/members/skysom.1621/">Skylar ‘skysom’ Sommers</a>, for replying always within a splitsecond (save for the times when he forgets to hit the Send button :P). <a href="http://forum.terasology.org/members/florian.1335/">Florian ‘flo’ Köberle</a>, who was my secondary but went out of his way and functioned effectively as my primary. I got to learn a lot from flo regarding various aspects about the game. It would have been impossible to complete my project without his aid. <a href="http://forum.terasology.org/members/xtariq.1697/">Xavier ‘xtariq’ Tariq</a>, who was also my secondary mentor, helped me whenever I needed him. I’d like to specially thank <a href="http://forum.terasology.org/members/cervator.2/">Rasmus ‘cervator’ Praestholm</a> here. Had he not been there that night in October, welcoming me on IRC and helping me set up my codebase, maybe I would have given up, moved on and never have done GSoC in the first place.</p> + +<p>All in all, it has been a thrilling summer. By this time I am familiar with a good part of the game’s codebase. I would love to continue contributing, albeit in different capacities. Let’s hope real life doesn’t get in the way too much. Also, GCI is almost here and another storm’s coming!</p> + +<p>Here’s a snap from one of the many exciting multiplayer play test sessions-</p> + +<p class="center"><img src="/img/multiplayerPlayTest.jpg" alt="multiplayerPlayTest" title="multiplayerPlayTest" style="max-height: 500px;" /></p> + + Tue, 15 Aug 2017 00:00:00 +0530 + http://localhost:4000/2017/08/15/GSoC-wrap-up.html + http://localhost:4000/2017/08/15/GSoC-wrap-up.html + + open source + + MovingBlocks + + Terasology + + GSoC + + + + + + diff --git a/_site/index.html b/_site/index.html new file mode 100644 index 0000000..119d811 --- /dev/null +++ b/_site/index.html @@ -0,0 +1,163 @@ + + + + + + + + Nihal Singh - nihal111 + + + + + + + + + + + + + + + + + +
+
+
+ author thumb +

nihal111

+

I'm Nihal Singh. Welcome to my space.

+

I walk fast and I like chocolate.

+ + + + About + + + + + + + + + + + + + + + + + + Projects + + + + + + + + + + + + + + CV + Blog + +
+
+
+ + + \ No newline at end of file diff --git a/_site/projects/index.html b/_site/projects/index.html new file mode 100644 index 0000000..0d101fc --- /dev/null +++ b/_site/projects/index.html @@ -0,0 +1,289 @@ + + + + + + + + Nihal Singh - Projects + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+

Nihal Singh

+

I like to know things

+
+ + + +
+
+
+ +
+
+

Projects

+ +

Projects are good things. Perhaps the best of things and no good project ever gets completed. +Here is the list of projects I own or have contributed to:

+ +
    +
  • Google Summer of Code- I completed my GSoC in 2017 under MovingBlocks- Terasology. The broad goal was to introduce content systems and gameplay connections to support a new template with solid replayability. I developed a new survival gameplay mode called Lost involving puzzles, traps and exploration based content packed in a new world with a backing lore. Dealt with the game’s physics, multiplayer and Entity Component System. Created new modules like AdvancedBehaviors (for event driven behavior switching), AdventureAssets (for traps and puzzle elements). Made several accompanying API changes to the engine. Created and added WildAnimals to the game.
  • +
+ +

Hackathons

+ +
    +
  • +

    Flood League: Designed and developed an endless runner game using Unity3D. Superheroes have to drive past the obstacles while rescuing the drowning civilians as their boat rushes past the flood-stricken city. Extensively worked on level design and implemented functionality such as continuous scoring, heat vision, super stretch arms, superpower cooldown among others. First prize winner in Ubisoft GameJam 2017.

    +
  • +
  • +

    Run: The Run app was born at the Yahoo! hackathon and ended up winning the “most creative and fun hack” award. Our team built a multi-player treasure hunt Android game supported by a Django server. Players look for and click a picture of an object around them as shown in the clue received on their phones to get the next clue. The first to finish the trail and decipher the clues wins. Used histogram equalization and scale invariant feature transform (SIFT) for rudimentary image matching.

    +
  • +
  • +

    Lend-It: Designed a Django-based web application that serves as a platform to bridge the gap between lenders and borrowers. Through Lend-It one can find people nearby who wish to lend and borrow books or other shareable commodities and perform a safe exchange. Implemented a backend using Django for the Lend-It website, which allows user interaction, sending notifications, searching and lending books, maintaining a user profile among other features Hosted temporarily online here. Third prize winner in Microsoft code.fun.do November ‘16.

    +
  • +
  • +

    RPG: A real time RPG game in which players assume roles of characters lost on a island. Players are each given a backstory and an objective. Players can interact and communicate with each other using video chat. The story progresses and you have to convince the other player to join your objective and let you live. Made using Kandy API. Third prize winner in Kandy Hackathon 2016.

    +
  • +
  • +

    AssistANT: Help the ant find sugar for its family. Built a puzzle game using Unity similar to the classic Bulldozer game. Guide the ant to push the sugar cubes down the ant holes. Dealt with basic 2-D physics and box colliders. Made custom sprites and worked largely on level design. Created using Unity 2D. Second prize winner for Lenovo GameJam ‘15.

    +
  • +
  • +

    alCHEMy: A game which completes chemical reactions, much like the classical Alchemy. Microsoft code.fun.do submission in January ‘16.

    +
  • +
+ +

Open Source

+ +
    +
  • +

    WnCC Website: The official Web and Coding Club, IIT Bombay website. Created, managed and maintained largely by me. The entire website is static and runs on Jekyll. Mainly serves as a portal for the Seasons Of Code (SOC) program. If you want to mentor a SOC project or have any ideas to make it look better, send a PR here.

    +
  • +
  • +

    Bashortcuts: ‘bashortcuts’ or bash-shortcuts is a skinny python script that helps build a personalized inputrc, which is a customized configuration of GNU Readline, the input related library used by bash and most other shells. Additionally, it makes it easy to define macros that can be used to tie shell_commands and functions to key sequences.

    +
  • +
  • +

    Terasology: Terasology is an open source renedition of Minecraft and is a platform to develop gameplay settings in the voxel world. I’ve been contributing to this project since October ‘16. The community is very active and enthusiastic, and I’ve had a great time with them.

    +
  • +
+ +

Course Projects and Research Work

+ +
    +
  • +

    Synthetic generation and Language Modeling of Code-Switched Hindi-English Text: Working on the generation of code-mixed Hindi-English text using linguistic theories and several strategies by leveraging parse-trees. Using the synthetic code-mixed data to improve performance of a language model.

    +
  • +
  • +

    Pommerman: Explored different strategies for training learning agents in a multi-agent scenario as part of the NeurIPS 2018 Pommerman Challenge. Read more here.

    +
  • +
  • +

    Voice Conversion: Built a pipelined approach to convert one person’s voice into another person’s voice. Proposed a deep learning approach to convert source waveform to phonemes and further phonemes to target waveform. Read more here.

    +
  • +
  • +

    CFS Visualizer: Created a visualization tool to see the Completely Fair Scheduler in action. CFS is a widely used process scheduler present in Linux kernels. Read more here.

    +
  • +
  • +

    SAFE Quiz App: Worked for the development of the SAFE Android application that facilitates online paperless tests in educational institutes. Multiple devices concurrently connect to a Wireless Access Point to fetch test data with action-logging happening in real time at the invigilator’s console. Worked on fetching and displaying of performance history and correct/incorrect answer visuals on the app. I worked on this as a part of my R & D Project in Fall ‘16.

    +
  • +
  • +

    Steganography Tool: Implemented a steganography tool using MATLAB with custom terminal GUI. Implemented variations of encryption algorithms using Least Significant Bit to encrypt/decrypt text within an image with a custom passphrase. This was done as a part of my Digital Image Processing course project in Fall ‘17.

    +
  • +
+ +

Hobby Projects

+ +
    +
  • +

    MooDLD: A python application that automates the download of course material from moodle.iitb.ac.in. It has a Tkinter based GUI and uses Mechanize for scraping. Made independently for Windows, it consists of a setup which installs MooDLD with all dependencies. Developed further as an android app that lets you download all the courses with the click of a button. [UPDATE: Was officially launched by the UG Academics Council at IIT Bombay in Aug ‘16. However, project has been dicontinued due to the recent Moodle version bump to support the official Moodle Mobile app.]

    +
  • +
  • +

    EVENTual: No more painstakingly filling or remembering event details. Save events to your default calendar with one tap. Fill out the details and get a sharable link and QR code. Use the EVENTual android app to directly add that. Created a platform for creating and sharing events easily, automating the task of filling details in the calendar by generating shareable links and QR Codes. Made a Django based web application to facilitate creation and searching of events. Developed an Android app which would pick up sharable links and scan QR Codes, to automatically add the event to calendar.

    +
  • +
  • +

    J.A.R.V.I.S.: An attempt to make a very simple, Personal Assistant that understands speech as well as text input and is capable of performing tasks other than conversing. This project is based on AIML 1.0 and uses pyaiml for using the AIML interpreter in python. AIML, is based on pattern matching and this project does not implement any sort of machine learning or language processing.

    +
  • +
  • +

    IITB login extension for Chrome: This extension automatically logs in to internet.iitb.ac.in page whenever Chrome browser is opened. Added integration for moodle and gpo.

    +
  • +
  • +

    Kibo: In the summer of 2016, I worked on Project Awaaz, a non-profit initiative to create an audiobook repository for the blind. Anybody can record text by reading out uploaded content and the recordings would be compiled, stitched and distributed. Built the backend for Project Awaaz and the Kibo website using the Django framework- Python/Django/Apache/MySQL. Designed responsive websites. Worked extensively on the Android application for Project Awaaz and handled server side integration.

    +
  • +
+ + + +
+ +
+ + + + + diff --git a/blog/index.html b/blog/index.html new file mode 100644 index 0000000..f2243ea --- /dev/null +++ b/blog/index.html @@ -0,0 +1,16 @@ +--- +layout: default +--- + +

Blog

+{% for post in site.posts %} + + +{% endfor %} + + diff --git a/css/main.scss b/css/main.scss new file mode 100644 index 0000000..721bc81 --- /dev/null +++ b/css/main.scss @@ -0,0 +1,9 @@ +--- +# Front matter comment to ensure Jekyll properly reads file. +--- +@import + "base", + "layout", + "syntax-highlighting", + "github-buttons" + /*,"icons" Commented because not in use currently. Uncomment if required later.*/ \ No newline at end of file diff --git a/docs/CV.pdf b/docs/CV.pdf new file mode 100644 index 0000000..88e172d Binary files /dev/null and b/docs/CV.pdf differ diff --git a/docs/RnD_Report.pdf b/docs/RnD_Report.pdf new file mode 100644 index 0000000..e9e5919 Binary files /dev/null and b/docs/RnD_Report.pdf differ diff --git a/docs/pommerman_report.pdf b/docs/pommerman_report.pdf new file mode 100644 index 0000000..8728e9b Binary files /dev/null and b/docs/pommerman_report.pdf differ diff --git a/docs/voice_conversion_report.pdf b/docs/voice_conversion_report.pdf new file mode 100644 index 0000000..79667ad Binary files /dev/null and b/docs/voice_conversion_report.pdf differ diff --git a/favicon-16x16.png b/favicon-16x16.png new file mode 100644 index 0000000..3bd5a4c Binary files /dev/null and b/favicon-16x16.png differ diff --git a/favicon-32x32.png b/favicon-32x32.png new file mode 100644 index 0000000..c778ee1 Binary files /dev/null and b/favicon-32x32.png differ diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000..1d16dd3 Binary files /dev/null and b/favicon.ico differ diff --git a/feed.xml b/feed.xml new file mode 100644 index 0000000..022378b --- /dev/null +++ b/feed.xml @@ -0,0 +1,30 @@ +--- +layout: null +--- + + + + {{ site.title | xml_escape }} + {{ site.description | xml_escape }} + {{ site.url }}{{ site.baseurl }}/ + + {{ site.time | date_to_rfc822 }} + {{ site.time | date_to_rfc822 }} + Jekyll v{{ jekyll.version }} + {% for post in site.posts limit:10 %} + + {{ post.title | xml_escape }} + {{ post.content | xml_escape }} + {{ post.date | date_to_rfc822 }} + {{ post.url | prepend: site.baseurl | prepend: site.url }} + {{ post.url | prepend: site.baseurl | prepend: site.url }} + {% for tag in post.tags %} + {{ tag | xml_escape }} + {% endfor %} + {% for cat in post.categories %} + {{ cat | xml_escape }} + {% endfor %} + + {% endfor %} + + diff --git a/feed_gsoc.xml b/feed_gsoc.xml new file mode 100644 index 0000000..d914844 --- /dev/null +++ b/feed_gsoc.xml @@ -0,0 +1,28 @@ +--- +layout: null +--- + + + + {{ site.title | xml_escape }} + {{ "My Google Summer of Code '17 experience" | xml_escape }} + {{ site.url }}{{ site.baseurl }}/ + + {{ site.time | date_to_rfc822 }} + {{ site.time | date_to_rfc822 }} + Jekyll v{{ jekyll.version }} + {% for post in site.posts %} + {% for tag in post.tags %} + {% if tag == 'GSoC' %} + + {{ post.title | xml_escape }} + {{ post.content | xml_escape }} + {{ post.date | date_to_xmlschema }} + {{ post.url | prepend: site.url }} + {{ post.url | prepend: site.url }} + + {% endif %} +{% endfor %} + {% endfor %} + + \ No newline at end of file diff --git a/fonts/nihal111.svg b/fonts/nihal111.svg new file mode 100644 index 0000000..f774954 --- /dev/null +++ b/fonts/nihal111.svg @@ -0,0 +1,180 @@ + + + +Generated by IcoMoon + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/fonts/nihal111.ttf b/fonts/nihal111.ttf new file mode 100644 index 0000000..bd2937e Binary files /dev/null and b/fonts/nihal111.ttf differ diff --git a/fonts/nihal111.woff b/fonts/nihal111.woff new file mode 100644 index 0000000..dfea3ae Binary files /dev/null and b/fonts/nihal111.woff differ diff --git a/img/AssistANTLevel1.jpg b/img/AssistANTLevel1.jpg new file mode 100644 index 0000000..5aaa2dc Binary files /dev/null and b/img/AssistANTLevel1.jpg differ diff --git a/img/AssistANTNewLevel.jpg b/img/AssistANTNewLevel.jpg new file mode 100644 index 0000000..80cfc6d Binary files /dev/null and b/img/AssistANTNewLevel.jpg differ diff --git a/img/GCI.png b/img/GCI.png new file mode 100644 index 0000000..04ca601 Binary files /dev/null and b/img/GCI.png differ diff --git a/img/GCIwinners.png b/img/GCIwinners.png new file mode 100644 index 0000000..c69b2f6 Binary files /dev/null and b/img/GCIwinners.png differ diff --git a/img/GSoC.png b/img/GSoC.png new file mode 100644 index 0000000..1dd7b95 Binary files /dev/null and b/img/GSoC.png differ diff --git a/img/GSoCStreak.png b/img/GSoCStreak.png new file mode 100644 index 0000000..ffdf1ef Binary files /dev/null and b/img/GSoCStreak.png differ diff --git a/img/SB1.jpeg b/img/SB1.jpeg new file mode 100644 index 0000000..ed950b1 Binary files /dev/null and b/img/SB1.jpeg differ diff --git a/img/SB2.jpg b/img/SB2.jpg new file mode 100644 index 0000000..ed302d6 Binary files /dev/null and b/img/SB2.jpg differ diff --git a/img/SB3.png b/img/SB3.png new file mode 100644 index 0000000..7e6ee02 Binary files /dev/null and b/img/SB3.png differ diff --git a/img/SB4.jpg b/img/SB4.jpg new file mode 100644 index 0000000..668c6d9 Binary files /dev/null and b/img/SB4.jpg differ diff --git a/img/SBmath.png b/img/SBmath.png new file mode 100644 index 0000000..698c9d1 Binary files /dev/null and b/img/SBmath.png differ diff --git a/img/Terasology.jpg b/img/Terasology.jpg new file mode 100644 index 0000000..6389163 Binary files /dev/null and b/img/Terasology.jpg differ diff --git a/img/UnreadJournal.jpg b/img/UnreadJournal.jpg new file mode 100644 index 0000000..fe03876 Binary files /dev/null and b/img/UnreadJournal.jpg differ diff --git a/img/WaSJournal.jpg b/img/WaSJournal.jpg new file mode 100644 index 0000000..ad40663 Binary files /dev/null and b/img/WaSJournal.jpg differ diff --git a/img/angelActiveAndInactive.jpg b/img/angelActiveAndInactive.jpg new file mode 100644 index 0000000..54124c9 Binary files /dev/null and b/img/angelActiveAndInactive.jpg differ diff --git a/img/angelFlatAndSmooth.jpg b/img/angelFlatAndSmooth.jpg new file mode 100644 index 0000000..19f567e Binary files /dev/null and b/img/angelFlatAndSmooth.jpg differ diff --git a/img/angelFloatingText.jpg b/img/angelFloatingText.jpg new file mode 100644 index 0000000..7aca52c Binary files /dev/null and b/img/angelFloatingText.jpg differ diff --git a/img/angelLightAndDark.jpg b/img/angelLightAndDark.jpg new file mode 100644 index 0000000..fb64610 Binary files /dev/null and b/img/angelLightAndDark.jpg differ diff --git a/img/angelNew.jpg b/img/angelNew.jpg new file mode 100644 index 0000000..86f8e94 Binary files /dev/null and b/img/angelNew.jpg differ diff --git a/img/angelNewPE.jpg b/img/angelNewPE.jpg new file mode 100644 index 0000000..d8118d4 Binary files /dev/null and b/img/angelNewPE.jpg differ diff --git a/img/angelOld.jpg b/img/angelOld.jpg new file mode 100644 index 0000000..3dd720e Binary files /dev/null and b/img/angelOld.jpg differ diff --git a/img/angelParticleEffects.gif b/img/angelParticleEffects.gif new file mode 100644 index 0000000..6c077d5 Binary files /dev/null and b/img/angelParticleEffects.gif differ diff --git a/img/antrumSabre.jpg b/img/antrumSabre.jpg new file mode 100644 index 0000000..060d7b7 Binary files /dev/null and b/img/antrumSabre.jpg differ diff --git a/img/arkenstone.jpg b/img/arkenstone.jpg new file mode 100644 index 0000000..2ef5122 Binary files /dev/null and b/img/arkenstone.jpg differ diff --git a/img/cmd_check_ntp_server.png b/img/cmd_check_ntp_server.png new file mode 100644 index 0000000..bdf51a5 Binary files /dev/null and b/img/cmd_check_ntp_server.png differ diff --git a/img/crudeSB.png b/img/crudeSB.png new file mode 100644 index 0000000..46c6706 Binary files /dev/null and b/img/crudeSB.png differ diff --git a/img/crudeSwingingBlade.gif b/img/crudeSwingingBlade.gif new file mode 100644 index 0000000..56ad11b Binary files /dev/null and b/img/crudeSwingingBlade.gif differ diff --git a/img/dinnerJapan.jpeg b/img/dinnerJapan.jpeg new file mode 100644 index 0000000..7ac03ec Binary files /dev/null and b/img/dinnerJapan.jpeg differ diff --git a/img/drone1.jpg b/img/drone1.jpg new file mode 100644 index 0000000..40529fb Binary files /dev/null and b/img/drone1.jpg differ diff --git a/img/drone2.jpg b/img/drone2.jpg new file mode 100644 index 0000000..0422ecb Binary files /dev/null and b/img/drone2.jpg differ diff --git a/img/engine.png b/img/engine.png new file mode 100644 index 0000000..1a784e5 Binary files /dev/null and b/img/engine.png differ diff --git a/img/facadeOfTruth.jpg b/img/facadeOfTruth.jpg new file mode 100644 index 0000000..b6b784e Binary files /dev/null and b/img/facadeOfTruth.jpg differ diff --git a/img/facebook.png b/img/facebook.png new file mode 100644 index 0000000..ef843b5 Binary files /dev/null and b/img/facebook.png differ diff --git a/img/finishflag.png b/img/finishflag.png new file mode 100644 index 0000000..efa64ee Binary files /dev/null and b/img/finishflag.png differ diff --git a/img/fork.png b/img/fork.png new file mode 100644 index 0000000..7b8fbeb Binary files /dev/null and b/img/fork.png differ diff --git a/img/git.png b/img/git.png new file mode 100644 index 0000000..dac23a0 Binary files /dev/null and b/img/git.png differ diff --git a/img/github.png b/img/github.png new file mode 100644 index 0000000..84c7055 Binary files /dev/null and b/img/github.png differ diff --git a/img/githubButtonResponsive.jpg b/img/githubButtonResponsive.jpg new file mode 100644 index 0000000..8f9ddfa Binary files /dev/null and b/img/githubButtonResponsive.jpg differ diff --git a/img/gooey.jpg b/img/gooey.jpg new file mode 100644 index 0000000..9a9144b Binary files /dev/null and b/img/gooey.jpg differ diff --git a/img/hut.jpg b/img/hut.jpg new file mode 100644 index 0000000..3a2403a Binary files /dev/null and b/img/hut.jpg differ diff --git a/img/intellij.jpeg b/img/intellij.jpeg new file mode 100644 index 0000000..92a2f1c Binary files /dev/null and b/img/intellij.jpeg differ diff --git a/img/jarvis.jpg b/img/jarvis.jpg new file mode 100644 index 0000000..e6ec806 Binary files /dev/null and b/img/jarvis.jpg differ diff --git a/img/java.png b/img/java.png new file mode 100644 index 0000000..6098c5e Binary files /dev/null and b/img/java.png differ diff --git a/img/lake.jpg b/img/lake.jpg new file mode 100644 index 0000000..f74fb8b Binary files /dev/null and b/img/lake.jpg differ diff --git a/img/lenovoposter.jpg b/img/lenovoposter.jpg new file mode 100644 index 0000000..f35c1d2 Binary files /dev/null and b/img/lenovoposter.jpg differ diff --git a/img/linkedin.png b/img/linkedin.png new file mode 100644 index 0000000..ecda046 Binary files /dev/null and b/img/linkedin.png differ diff --git a/img/lostBackground.jpg b/img/lostBackground.jpg new file mode 100644 index 0000000..2676daa Binary files /dev/null and b/img/lostBackground.jpg differ diff --git a/img/lounge.jpg b/img/lounge.jpg new file mode 100644 index 0000000..d83679a Binary files /dev/null and b/img/lounge.jpg differ diff --git a/img/mercari/androidteam.jpg b/img/mercari/androidteam.jpg new file mode 100644 index 0000000..3b13baf Binary files /dev/null and b/img/mercari/androidteam.jpg differ diff --git a/img/mercari/balloons.jpg b/img/mercari/balloons.jpg new file mode 100644 index 0000000..edb0d88 Binary files /dev/null and b/img/mercari/balloons.jpg differ diff --git a/img/mercari/desk.jpg b/img/mercari/desk.jpg new file mode 100644 index 0000000..a9ed488 Binary files /dev/null and b/img/mercari/desk.jpg differ diff --git a/img/mercari/gear.jpg b/img/mercari/gear.jpg new file mode 100644 index 0000000..3fbd9a8 Binary files /dev/null and b/img/mercari/gear.jpg differ diff --git a/img/mercari/moritower.jpg b/img/mercari/moritower.jpg new file mode 100644 index 0000000..c160ace Binary files /dev/null and b/img/mercari/moritower.jpg differ diff --git a/img/mercari/officeview.jpg b/img/mercari/officeview.jpg new file mode 100644 index 0000000..1ac4f04 Binary files /dev/null and b/img/mercari/officeview.jpg differ diff --git a/img/mercari/rum.jpg b/img/mercari/rum.jpg new file mode 100644 index 0000000..3ad1d5d Binary files /dev/null and b/img/mercari/rum.jpg differ diff --git a/img/mercari/spider.jpg b/img/mercari/spider.jpg new file mode 100644 index 0000000..136fa62 Binary files /dev/null and b/img/mercari/spider.jpg differ diff --git a/img/mercari/tokyotour.jpg b/img/mercari/tokyotour.jpg new file mode 100644 index 0000000..9e2d018 Binary files /dev/null and b/img/mercari/tokyotour.jpg differ diff --git a/img/multiplayerPlayTest.jpg b/img/multiplayerPlayTest.jpg new file mode 100644 index 0000000..1247e4d Binary files /dev/null and b/img/multiplayerPlayTest.jpg differ diff --git a/img/newModules.png b/img/newModules.png new file mode 100644 index 0000000..c6b749a Binary files /dev/null and b/img/newModules.png differ diff --git a/img/ntp_no_option.png b/img/ntp_no_option.png new file mode 100644 index 0000000..99506cb Binary files /dev/null and b/img/ntp_no_option.png differ diff --git a/img/ntp_timeout.png b/img/ntp_timeout.png new file mode 100644 index 0000000..8d856c8 Binary files /dev/null and b/img/ntp_timeout.png differ diff --git a/img/ntp_ts_1.png b/img/ntp_ts_1.png new file mode 100644 index 0000000..2a6b0a8 Binary files /dev/null and b/img/ntp_ts_1.png differ diff --git a/img/ntp_ts_2.png b/img/ntp_ts_2.png new file mode 100644 index 0000000..c2f5c3f Binary files /dev/null and b/img/ntp_ts_2.png differ diff --git a/img/ntp_ts_3.png b/img/ntp_ts_3.png new file mode 100644 index 0000000..5228355 Binary files /dev/null and b/img/ntp_ts_3.png differ diff --git a/img/ntp_ts_4.png b/img/ntp_ts_4.png new file mode 100644 index 0000000..a2d6a2b Binary files /dev/null and b/img/ntp_ts_4.png differ diff --git a/img/ntp_ts_5.png b/img/ntp_ts_5.png new file mode 100644 index 0000000..feff8e0 Binary files /dev/null and b/img/ntp_ts_5.png differ diff --git a/img/ntp_ts_6.png b/img/ntp_ts_6.png new file mode 100644 index 0000000..c42900f Binary files /dev/null and b/img/ntp_ts_6.png differ diff --git a/img/obsidianTorch.jpg b/img/obsidianTorch.jpg new file mode 100644 index 0000000..09cc901 Binary files /dev/null and b/img/obsidianTorch.jpg differ diff --git a/img/oldModules.jpg b/img/oldModules.jpg new file mode 100644 index 0000000..315397a Binary files /dev/null and b/img/oldModules.jpg differ diff --git a/img/pommerman.gif b/img/pommerman.gif new file mode 100644 index 0000000..f4b4556 Binary files /dev/null and b/img/pommerman.gif differ diff --git a/img/portal.jpg b/img/portal.jpg new file mode 100644 index 0000000..c7de606 Binary files /dev/null and b/img/portal.jpg differ diff --git a/img/pyramid.jpg b/img/pyramid.jpg new file mode 100644 index 0000000..e3d25d7 Binary files /dev/null and b/img/pyramid.jpg differ diff --git a/img/pyramidActual.jpg b/img/pyramidActual.jpg new file mode 100644 index 0000000..2fbcb4e Binary files /dev/null and b/img/pyramidActual.jpg differ diff --git a/img/pyramidAngel.jpg b/img/pyramidAngel.jpg new file mode 100644 index 0000000..1b79250 Binary files /dev/null and b/img/pyramidAngel.jpg differ diff --git a/img/shatteredPlasma.jpg b/img/shatteredPlasma.jpg new file mode 100644 index 0000000..a756a1c Binary files /dev/null and b/img/shatteredPlasma.jpg differ diff --git a/img/stonehenge.jpg b/img/stonehenge.jpg new file mode 100644 index 0000000..a06dcec Binary files /dev/null and b/img/stonehenge.jpg differ diff --git a/img/stonehengeActual.jpg b/img/stonehengeActual.jpg new file mode 100644 index 0000000..4dfced3 Binary files /dev/null and b/img/stonehengeActual.jpg differ diff --git a/img/stonehengeAngel.jpg b/img/stonehengeAngel.jpg new file mode 100644 index 0000000..0cb649d Binary files /dev/null and b/img/stonehengeAngel.jpg differ diff --git a/img/stonehengePillar.jpg b/img/stonehengePillar.jpg new file mode 100644 index 0000000..f9fc45a Binary files /dev/null and b/img/stonehengePillar.jpg differ diff --git a/img/stonehengeTwoPillar.jpg b/img/stonehengeTwoPillar.jpg new file mode 100644 index 0000000..c30ad56 Binary files /dev/null and b/img/stonehengeTwoPillar.jpg differ diff --git a/img/strayBT.jpg b/img/strayBT.jpg new file mode 100644 index 0000000..2145984 Binary files /dev/null and b/img/strayBT.jpg differ diff --git a/img/swingingbladeentities.png b/img/swingingbladeentities.png new file mode 100644 index 0000000..74fdd9a Binary files /dev/null and b/img/swingingbladeentities.png differ diff --git a/img/temple.jpg b/img/temple.jpg new file mode 100644 index 0000000..1f4f1c5 Binary files /dev/null and b/img/temple.jpg differ diff --git a/img/templeActual.jpg b/img/templeActual.jpg new file mode 100644 index 0000000..c1288f5 Binary files /dev/null and b/img/templeActual.jpg differ diff --git a/img/templeAngel.jpg b/img/templeAngel.jpg new file mode 100644 index 0000000..a89deff Binary files /dev/null and b/img/templeAngel.jpg differ diff --git a/img/templeEntrance.jpg b/img/templeEntrance.jpg new file mode 100644 index 0000000..5c0b104 Binary files /dev/null and b/img/templeEntrance.jpg differ diff --git a/img/terasologyPR.png b/img/terasologyPR.png new file mode 100644 index 0000000..6756b8b Binary files /dev/null and b/img/terasologyPR.png differ diff --git a/img/terasologylogo.png b/img/terasologylogo.png new file mode 100644 index 0000000..f015d2c Binary files /dev/null and b/img/terasologylogo.png differ diff --git a/img/tokyo/akihabara.jpg b/img/tokyo/akihabara.jpg new file mode 100644 index 0000000..36b93da Binary files /dev/null and b/img/tokyo/akihabara.jpg differ diff --git a/img/tokyo/disneysea.jpg b/img/tokyo/disneysea.jpg new file mode 100644 index 0000000..d4e94d2 Binary files /dev/null and b/img/tokyo/disneysea.jpg differ diff --git a/img/tokyo/fujiq.jpg b/img/tokyo/fujiq.jpg new file mode 100644 index 0000000..2a8dba1 Binary files /dev/null and b/img/tokyo/fujiq.jpg differ diff --git a/img/tokyo/kyoto.jpg b/img/tokyo/kyoto.jpg new file mode 100644 index 0000000..63b166d Binary files /dev/null and b/img/tokyo/kyoto.jpg differ diff --git a/img/tokyo/mtfuji.jpg b/img/tokyo/mtfuji.jpg new file mode 100644 index 0000000..3df5e1e Binary files /dev/null and b/img/tokyo/mtfuji.jpg differ diff --git a/img/tokyo/oshima.jpg b/img/tokyo/oshima.jpg new file mode 100644 index 0000000..a93c41b Binary files /dev/null and b/img/tokyo/oshima.jpg differ diff --git a/img/viewJapan.jpeg b/img/viewJapan.jpeg new file mode 100644 index 0000000..93fea87 Binary files /dev/null and b/img/viewJapan.jpeg differ diff --git a/img/voice-conversion/multitask.png b/img/voice-conversion/multitask.png new file mode 100644 index 0000000..ccffd34 Binary files /dev/null and b/img/voice-conversion/multitask.png differ diff --git a/img/voice-conversion/net1.png b/img/voice-conversion/net1.png new file mode 100644 index 0000000..beb638b Binary files /dev/null and b/img/voice-conversion/net1.png differ diff --git a/img/voice-conversion/net2.png b/img/voice-conversion/net2.png new file mode 100644 index 0000000..da6442b Binary files /dev/null and b/img/voice-conversion/net2.png differ diff --git a/img/well.jpg b/img/well.jpg new file mode 100644 index 0000000..ddd4c2d Binary files /dev/null and b/img/well.jpg differ diff --git a/img/winterhascome.jpg b/img/winterhascome.jpg new file mode 100644 index 0000000..a0e0dec Binary files /dev/null and b/img/winterhascome.jpg differ diff --git a/img/wipeOutMath.PNG b/img/wipeOutMath.PNG new file mode 100644 index 0000000..405a315 Binary files /dev/null and b/img/wipeOutMath.PNG differ diff --git a/img/wipeout.jpg b/img/wipeout.jpg new file mode 100644 index 0000000..6b6f733 Binary files /dev/null and b/img/wipeout.jpg differ diff --git a/index.html b/index.html new file mode 100644 index 0000000..0cf9234 --- /dev/null +++ b/index.html @@ -0,0 +1,24 @@ +--- +layout: landing +title : nihal111 +header: False +--- + +
+
+
+ author thumb +

nihal111

+ {% for page in site.pages %} + {% if page.header %} + {% if page.title %} + {{ page.title }} + {% endif %} + {% endif %} + {% endfor %} + CV + Blog + {% include landing_social.html %} +
+
+
diff --git a/js/github-buttons.js b/js/github-buttons.js new file mode 100644 index 0000000..e8d7a9c --- /dev/null +++ b/js/github-buttons.js @@ -0,0 +1,76 @@ +$(function() { + $('head').append(''); + createButtons(); +}); + +function createButtons() { + $('.github-button').each(function(i, button) { + var url = $(button).attr("url"); + var params = url.split("/"); + var owner = params[3]; + var repo = params[4]; + var num = params[6]; + + if (url.indexOf("pull") !== -1) { + url = "https://api.github.com/repos/" + owner + "/" + repo + "/pulls/" + num; + $.get( + url, + function(data) { + var date = formatDate(new Date(data.created_at)); + $(button).append( + $('', {'class': 'number', 'href': data.html_url, 'text': "#" + data.number}), + $('', {'class': 'title', 'href': data.html_url, 'text': data.title}), + $('', {'class': 'meta'}).append( + $('', {'class': 'repo', 'href': data.base.repo.html_url, 'text': data.base.repo.full_name}), + $('', {'class': 'octicon octicon-clock'}), + $('', {'class': 'date', 'text': date}) + ), + $('', {'class': 'right-icon mega-octicon octicon-git-pull-request'}) + ) + if (data.merged ) { + $(button).find('.octicon-git-pull-request').addClass('octicon-git-merge').removeClass('octicon-git-pull-request'); + $(button).addClass('merged-PR-button'); + } else { + $(button).addClass('open-PR-button'); + } + } + ); + } else if (url.indexOf("issue") !== -1) { + url = "https://api.github.com/repos/" + owner + "/" + repo + "/issues/" + num; + $.get( + url, + function(data) { + var repo_name = data.repository_url.split("/"); + repo_name = repo_name[repo_name.length - 2] + "/" + repo_name[repo_name.length - 1]; + var date = formatDate(new Date(data.created_at)); + $(button).append( + $('', {'class': 'number', 'href': data.html_url, 'text': "#" + data.number}), + $('', {'class': 'title', 'href': data.html_url, 'text': data.title}), + $('', {'class': 'meta'}).append( + $('', {'class': 'repo', 'href': data.repository_url, 'text': repo_name}), + $('', {'class': 'octicon octicon-clock'}), + $('', {'class': 'date', 'text': date}) + ), + $('', {'class': 'right-icon mega-octicon octicon-issue-opened'}) + ) + var open = "open"; + if (data.state === "open") { + $(button).addClass('open-issue-button'); + } else { + $(button).find('.octicon-issue-opened').addClass('octicon-issue-closed').removeClass('octicon-issue-opened'); + $(button).addClass('closed-issue-button'); + } + } + ); + } + }); +} + +function formatDate(d) { + var m_names = new Array("Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sept", "Oct", "Nov", "Dec"); + var curr_date = d.getDate(); + var curr_month = d.getMonth(); + var curr_year = d.getFullYear(); + return m_names[curr_month] + " " + curr_date + ", " + curr_year; +} \ No newline at end of file diff --git a/something.py b/something.py new file mode 100644 index 0000000..e69de29 diff --git a/tags.html b/tags.html new file mode 100644 index 0000000..f4a49ad --- /dev/null +++ b/tags.html @@ -0,0 +1,33 @@ +--- +layout: page +permalink: /tags/ +--- + + + +
+{% for tag in site.tags %} +
+ {% capture tag_name %}{{ tag | first }}{% endcapture %} +

{{ tag_name }}

+ + {% for post in site.tags[tag_name] %} + + {% endfor %} +
+{% endfor %} +
\ No newline at end of file