<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-8927794127513218467</id><updated>2026-03-22T13:20:16.189+01:00</updated><category term="aws"/><category term="machine learning"/><category term="sagemaker"/><title type='text'>Code Bazaar</title><subtitle type='html'>Just A Few Bites Of Code</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://codebazaar.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8927794127513218467/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://codebazaar.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Matt Buchner</name><uri>http://www.blogger.com/profile/03993705703169676412</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGJBh157km2WvcRk9Fd0alqVRHYw3pldCvcehZRPx8NXBkVlqWclPGMXjjvP_CKoYtUwPQECmIfijWZo-2-O64i5ogn-LI4qplVUgMixVlbsXwbJgQrwlSr44Wxp3Cr4o/s113/headshot.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>19</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8927794127513218467.post-2577644716075617274</id><published>2024-01-29T18:04:00.006+01:00</published><updated>2024-01-29T18:06:09.438+01:00</updated><title type='text'>Experimenting with AI Diffusion</title><content type='html'>&lt;div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;Code, notebook and live demo are available on my 🤗&amp;nbsp;&lt;a href=&quot;https://huggingface.co/spaces/mattb512/fastai-lesson-10-diffusers&quot; target=&quot;_blank&quot;&gt;HuggingFace Space&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;I made it to the Lesson 10 of the fast.ai &lt;a href=&quot;https://course.fast.ai/Lessons/lesson10.html&quot; target=&quot;_blank&quot;&gt;course&lt;/a&gt;. Its homework was particularly fun and challenging.

In a nutshell, the goal is to deconstruct an existing Diffusion model available on 🤗 &lt;a href=&quot;https://huggingface.co/docs/diffusers/main/en/api/pipelines/stable_diffusion/text2img#diffusers.StableDiffusionPipeline&quot; target=&quot;_blank&quot;&gt;HuggingFace&lt;/a&gt; and rebuild it component by component.

This model is capable of generateing an image based on a text (prompt) and optionally an existing image. Just like this:
&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzsaMWNbNfsiYMpfvKrB5yD8929LhAmEJhsyBRDexV_WgYtvAjG9AfzsKS_PdYYz5TKZkmn12Se2Nk1SIJg7poqC6E5v9rCwaIU9ryqwGR7rH2puOPJLF5sVMCm09LeXJN-3AAjuxJGQftucUjmehijUj6DXK6WsTkSB3oq9sqvvIisQ8RIG0Pwc32pBse/s874/ai-math.png&quot; style=&quot;display: block; padding: 1em 0px; text-align: center;&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; data-original-height=&quot;231&quot; data-original-width=&quot;874&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzsaMWNbNfsiYMpfvKrB5yD8929LhAmEJhsyBRDexV_WgYtvAjG9AfzsKS_PdYYz5TKZkmn12Se2Nk1SIJg7poqC6E5v9rCwaIU9ryqwGR7rH2puOPJLF5sVMCm09LeXJN-3AAjuxJGQftucUjmehijUj6DXK6WsTkSB3oq9sqvvIisQ8RIG0Pwc32pBse/s320/ai-math.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;The first step is to use an Auto-encoder to reduce the amount of data used by image. We can encode an image to a smaller Tensor, then decode it back. It does not come back exactly the same, but the difference is marginal.&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5f4lqb7nZSEeVK03i9Be5q_irkpGKi8jTIQ2hHqZu3TwFbWfZCxXP8lvX0yS1S7UsHBWTOkLL9c_BgoE8ybKLcYr1J3AumlNm9iXP4rSodeR-juJnX3WKOe_D9zOTC8KejCg3nMzYXqIHJ8Vddyp5R41J7h8IJ-BJ0otSpsWQd1ySEaip3mMcYNtdZvd9/s1024/1-autoencoder.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;512&quot; data-original-width=&quot;1024&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5f4lqb7nZSEeVK03i9Be5q_irkpGKi8jTIQ2hHqZu3TwFbWfZCxXP8lvX0yS1S7UsHBWTOkLL9c_BgoE8ybKLcYr1J3AumlNm9iXP4rSodeR-juJnX3WKOe_D9zOTC8KejCg3nMzYXqIHJ8Vddyp5R41J7h8IJ-BJ0otSpsWQd1ySEaip3mMcYNtdZvd9/w640-h320/1-autoencoder.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;Can you spot the difference?&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;Now that we can work on smaller Tensor, we can efficiently generate images based on a prompt. We can control how closely the model should follow the prompt by setting the guidance parameter. In the picture below, I try different value for the guidance.&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqHVIacFDfV6dqg3LckaWK9pdBZeLArjyYwlaU-yIT1mXgmXSzB58m9Q5aFEttwX6ZEcbuH0v5YMmpr7dD4w8N5WeTxSYNhuKNDle705NRvtYjECzA3hYA_FtV5Dzp5IwWWN0VT2rNfGpO7pA-xf3-4F2X9x4OFApedMCw61T97vxHjNV-wkmnFeJwpzi6/s5120/3-guidance.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;512&quot; data-original-width=&quot;5120&quot; height=&quot;64&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqHVIacFDfV6dqg3LckaWK9pdBZeLArjyYwlaU-yIT1mXgmXSzB58m9Q5aFEttwX6ZEcbuH0v5YMmpr7dD4w8N5WeTxSYNhuKNDle705NRvtYjECzA3hYA_FtV5Dzp5IwWWN0VT2rNfGpO7pA-xf3-4F2X9x4OFApedMCw61T97vxHjNV-wkmnFeJwpzi6/w640-h64/3-guidance.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;Often, the model will generate an image which does not match our expectation. We can use the negative prompt to constantly remind the model to not match specific criteria throughout the generation. In the picture on the left, we asked the model to generate &quot;a beautiful tree&quot; which came with a lot of green. If we don&#39;t want so much green, we can set &quot;green&quot; in the negative prompt.&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkS2e-wAU_Ync8ISA6dcQmAfk-MsWrRmfUZWfXLMw3PViyOi9EC8cke6_lybYjWtIfO9AN7Z3Q7lvnfKGGjpkfbEifDpJH9MLedjRpNdy3WlJgUfwKPtT38aqs3nkqnVHwZqRlUmoiT4ZlMQ3GmL3t63hp-ku6_oGw_9BLuEqaO1F54Hy-JtRQ-e6E75pB/s1024/4-negative-prompt.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;512&quot; data-original-width=&quot;1024&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkS2e-wAU_Ync8ISA6dcQmAfk-MsWrRmfUZWfXLMw3PViyOi9EC8cke6_lybYjWtIfO9AN7Z3Q7lvnfKGGjpkfbEifDpJH9MLedjRpNdy3WlJgUfwKPtT38aqs3nkqnVHwZqRlUmoiT4ZlMQ3GmL3t63hp-ku6_oGw_9BLuEqaO1F54Hy-JtRQ-e6E75pB/w640-h320/4-negative-prompt.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;Before the image generation starts, the model generates embeddings based on the prompt given. Multiple prompts can be used, and their respective embeddings can be merged. This method can generate some interesting pictures! We can also set weights on each prompt. In the example below, we generated 10 images with different weights.&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNkC8PrFg917wOZxG7H03-nJsMP3GtrhRG2UYOTjBSTb7kSh7fOlmqJ9OaAu6prnJFxaz6I6SSadWY2FyyBwJC4jb7OGPuocWeCwI0Lm9swS4BciIRU-krkDnMZWaDkfRlcI0QSuxCzhgMw_EPfWsilemU0ANgY0pd_vymSRMXwk1CL2enW2ZWVN2tYV1U/s5120/5-start-step.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;512&quot; data-original-width=&quot;5120&quot; height=&quot;64&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNkC8PrFg917wOZxG7H03-nJsMP3GtrhRG2UYOTjBSTb7kSh7fOlmqJ9OaAu6prnJFxaz6I6SSadWY2FyyBwJC4jb7OGPuocWeCwI0Lm9swS4BciIRU-krkDnMZWaDkfRlcI0QSuxCzhgMw_EPfWsilemU0ANgY0pd_vymSRMXwk1CL2enW2ZWVN2tYV1U/w640-h64/5-start-step.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;&lt;/div&gt;If we just provide a prompt as input to the model, it will use an random noise picture as a starting point. But we can also provide an existing image as a starting point. To use this method, we need to first add some noise to the picture, then finish the image generation as usual. In the picture below, we show a starting image, the same image with the added noise, and on the right the final generated image. The prompt for it is: &quot;a cute dog&quot;.&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhscJhWxHMjIKJDJgkK47z-8jgjQEPWkcLu5AZBr955RQ4OVzqWIQY4NhF-0y4a6QDNilA5vablwAG-XlWp191yFw1yOKw-czurpgl86mpLN5TsSMv58XiEhoyWPa_VJQzXwvQjP34bTROGC6IVoMmOdpcwwNUG5YCMrA7_z29y7qtzZuzcELv1D4izIhz_/s1536/6-starting-image.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;512&quot; data-original-width=&quot;1536&quot; height=&quot;214&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhscJhWxHMjIKJDJgkK47z-8jgjQEPWkcLu5AZBr955RQ4OVzqWIQY4NhF-0y4a6QDNilA5vablwAG-XlWp191yFw1yOKw-czurpgl86mpLN5TsSMv58XiEhoyWPa_VJQzXwvQjP34bTROGC6IVoMmOdpcwwNUG5YCMrA7_z29y7qtzZuzcELv1D4izIhz_/w640-h214/6-starting-image.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;To go from the middle picture to the one on the right, the model progressively removes noise from the picture. Each step generates what is called a latent. We can capture these latents and turn them in images to show how the model progress through the image generation.&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglyWmTOlcVaHuvdQLKHGzErnMtU_n_gHN-tuLA0W11qOZ9xtDM-woWNYx2or0UeLvOn5akaiYInG3GdqKzIn2_ufk5gxvojT-gMWTPiF2vXCrp-Mg4BtvHCkOlHD0vYqBHuC5-Ut6HarYddHatFfEtEN-AbsGUr8jhecOO_sjJpLkKlHzeQPB3zKkjQ4ou/s9216/7-starting-image-step.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;512&quot; data-original-width=&quot;9216&quot; height=&quot;36&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglyWmTOlcVaHuvdQLKHGzErnMtU_n_gHN-tuLA0W11qOZ9xtDM-woWNYx2or0UeLvOn5akaiYInG3GdqKzIn2_ufk5gxvojT-gMWTPiF2vXCrp-Mg4BtvHCkOlHD0vYqBHuC5-Ut6HarYddHatFfEtEN-AbsGUr8jhecOO_sjJpLkKlHzeQPB3zKkjQ4ou/w640-h36/7-starting-image-step.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;We can set the amount of noise added to the original picture. Here, we set different amount of noise (2nd row) and see the final image generated (1st row).&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDH5DTTAJa3Vgs9azO0fMHRAySX4OwSb4F6iEB3PJOAHG6hcaLHDJTshOGSoTgPu08HbYMjQUwjqnI_K05bXzE444Sdca_keyIP_JPcrB-fLDpWxryqmPzyc8MyjJ0zmHU8DnVMJhANxNcs99SLIKgS-8_l6aLCqPN7OK8_zwgxBcxkjcyFrqH3MPysm5z/s2048/8b-output.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;205&quot; data-original-width=&quot;2048&quot; height=&quot;64&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDH5DTTAJa3Vgs9azO0fMHRAySX4OwSb4F6iEB3PJOAHG6hcaLHDJTshOGSoTgPu08HbYMjQUwjqnI_K05bXzE444Sdca_keyIP_JPcrB-fLDpWxryqmPzyc8MyjJ0zmHU8DnVMJhANxNcs99SLIKgS-8_l6aLCqPN7OK8_zwgxBcxkjcyFrqH3MPysm5z/w640-h64/8b-output.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjK4N9yl8c7v7ZjU84cVR0fINnxPrtqb69cu281wqrTUuA9p_AsR4S1lNP9j_a0ugecUh6NG_0a5PXIEbOf-DxRYYYVeUGz4RDtOeEGtnRkNkmJYYTDk8ITGaAnwQmcL7PX7Yd-yH5Ln3ccL3_DgfR0gQjAmrAhehHc1-unaE0s9j_xr-MB9PxWdagB0xNm/s5120/8-starting-image-ratio-noise.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;512&quot; data-original-width=&quot;5120&quot; height=&quot;64&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjK4N9yl8c7v7ZjU84cVR0fINnxPrtqb69cu281wqrTUuA9p_AsR4S1lNP9j_a0ugecUh6NG_0a5PXIEbOf-DxRYYYVeUGz4RDtOeEGtnRkNkmJYYTDk8ITGaAnwQmcL7PX7Yd-yH5Ln3ccL3_DgfR0gQjAmrAhehHc1-unaE0s9j_xr-MB9PxWdagB0xNm/w640-h64/8-starting-image-ratio-noise.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;You can head to my &lt;a href=&quot;https://huggingface.co/spaces/mattb512/fastai-lesson-10-diffusers&quot; target=&quot;_blank&quot;&gt;HuggingFace Space&lt;/a&gt; to try it out!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEjdYuj6XmxRoPaUhmcZuFMw8j1sjExcsAC0T78uBEgIy8FxVN3yp7b_Rc_FbyPFHApYx4MwG_35jDYUF_GSvnkXKDKsoCsY2yotKhx74znxxc5SWXHZyg9b_PLhMjbmTI3ZgsIxLfubA4f_wXsyJKOT7CLq5bJSRzsNHA1O5iEuT8v1VlLQp38QYGg9CIy7&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img data-original-height=&quot;1040&quot; data-original-width=&quot;1052&quot; height=&quot;632&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEjdYuj6XmxRoPaUhmcZuFMw8j1sjExcsAC0T78uBEgIy8FxVN3yp7b_Rc_FbyPFHApYx4MwG_35jDYUF_GSvnkXKDKsoCsY2yotKhx74znxxc5SWXHZyg9b_PLhMjbmTI3ZgsIxLfubA4f_wXsyJKOT7CLq5bJSRzsNHA1O5iEuT8v1VlLQp38QYGg9CIy7=w640-h632&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codebazaar.blogspot.com/feeds/2577644716075617274/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/8927794127513218467/2577644716075617274?isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8927794127513218467/posts/default/2577644716075617274'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8927794127513218467/posts/default/2577644716075617274'/><link rel='alternate' type='text/html' href='http://codebazaar.blogspot.com/2024/01/experimenting-with-ai-diffusion.html' title='Experimenting with AI Diffusion'/><author><name>Matt Buchner</name><uri>http://www.blogger.com/profile/03993705703169676412</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGJBh157km2WvcRk9Fd0alqVRHYw3pldCvcehZRPx8NXBkVlqWclPGMXjjvP_CKoYtUwPQECmIfijWZo-2-O64i5ogn-LI4qplVUgMixVlbsXwbJgQrwlSr44Wxp3Cr4o/s113/headshot.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzsaMWNbNfsiYMpfvKrB5yD8929LhAmEJhsyBRDexV_WgYtvAjG9AfzsKS_PdYYz5TKZkmn12Se2Nk1SIJg7poqC6E5v9rCwaIU9ryqwGR7rH2puOPJLF5sVMCm09LeXJN-3AAjuxJGQftucUjmehijUj6DXK6WsTkSB3oq9sqvvIisQ8RIG0Pwc32pBse/s72-c/ai-math.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8927794127513218467.post-2844100913573876537</id><published>2023-12-24T15:00:00.007+01:00</published><updated>2023-12-27T15:46:52.344+01:00</updated><title type='text'>Can AI replace Captcha click farms?</title><content type='html'>&lt;p&gt;&lt;i&gt;The code and demo for this blog is available &lt;a href=&quot;https://huggingface.co/spaces/mattb512/trafficlight&quot;&gt;here&lt;/a&gt; on my Hugging Face Space&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;I recently took some great AI training (&lt;a href=&quot;https://karpathy.ai/zero-to-hero.html&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;&amp;nbsp;and &lt;a href=&quot;http://fast.ai&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;). One of the courses is introduced with this &lt;a href=&quot;https://xkcd.com/1425&quot; target=&quot;_blank&quot;&gt;xkcd joke&lt;/a&gt; from 2014:&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://imgs.xkcd.com/comics/tasks.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;448&quot; data-original-width=&quot;267&quot; src=&quot;https://imgs.xkcd.com/comics/tasks.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;It made me think: what task was considered impossible for a computer to accomplish in 2014, and can now be easily achieved using AI? 🤔&lt;/p&gt;&lt;p&gt;2014 was the year Google released &lt;a href=&quot;https://www.google.com/recaptcha/about/&quot; target=&quot;_blank&quot;&gt;reCaptcha v2&lt;/a&gt;&amp;nbsp;which became, by far, the &lt;a href=&quot;https://trends.builtwith.com/widgets/captcha&quot; target=&quot;_blank&quot;&gt;most popular&lt;/a&gt; captcha solution. We&#39;ve all seen these prompts:&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8X_rFaR1MuyQSyEs3Y7d9f1OYIZVEMr79geGGCTf4Ag2ncx_323chXvnlyXfAcIJNls-qzPzOSRX9Uq-aMoXLJs9ecHWUI6KtxSCF-zF-EoMYMMUgSoOqdLtDUMOwY2ohvoqa7rBgGQ0izRkvm97q4BpmHcDRslDHCJ7cssBOV8BLWhm5iAvfwKjNpCG5/s701/main-qimg-df0968efea4fcc318cf815e67fd63292%20(1).jpeg&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;701&quot; data-original-width=&quot;605&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8X_rFaR1MuyQSyEs3Y7d9f1OYIZVEMr79geGGCTf4Ag2ncx_323chXvnlyXfAcIJNls-qzPzOSRX9Uq-aMoXLJs9ecHWUI6KtxSCF-zF-EoMYMMUgSoOqdLtDUMOwY2ohvoqa7rBgGQ0izRkvm97q4BpmHcDRslDHCJ7cssBOV8BLWhm5iAvfwKjNpCG5/w276-h320/main-qimg-df0968efea4fcc318cf815e67fd63292%20(1).jpeg&quot; width=&quot;276&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;To illegally promote companies, products, influence elections, or launder money, hackers need to create thousands of fake accounts. Captcha are meant to prevent this issue by ensuring a real human is behind the screen to verify the image. If a computer can pass the Captcha test, a hacker could automate the user creation process. I haven&#39;t tested these illegal services but it seems hackers hire Captcha click-farms where humans solve the Captcha tests for a fee ($3 for 1000 captcha&amp;nbsp;&lt;span style=&quot;background-color: white; color: red; text-align: left;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: white; text-align: left;&quot;&gt;according to this&amp;nbsp;&lt;a href=&quot;https://www.f5.com/labs/articles/cisotociso/i-was-a-human-captcha-solver&quot; target=&quot;_blank&quot;&gt;F5 Labs article&lt;/a&gt;&lt;/span&gt;).&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Now that we have self-driving cars on the road, there is no secret that computers can recognize traffic lights. However, these cars (e.g. Tesla and Waymo) are equipped with expensive hardware and backed by top engineering teams. &lt;b&gt;What I was actually interested to see is&amp;nbsp;whether I could easily built a cost-efficient AI tool to solve a Captcha test.&lt;/b&gt;&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;The Captcha test splits an image in 4x4=16 squares and asks users which squares contain a specific object (e.g. traffic lights). One approach would be to use an image classification model and run it 16 times on each sub square. But it would not be very accurate as a traffic light might go across multiple squares and it may not be possible to identify part of a traffic light as one.&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeaQvQGMLtB_9BQ1RIbqwiTKqup0Mr9HRvKCdTpyHJT_PESShZyexSVdAmZElHa3MYNGf4z8GXyNA81tGhIbc0ZdHwdD_IIQERlMlVbKEDbbHyD3_4IjeVyNVq3jtZAFLjh3KB6UhC65Ie4iy4enNV56VAhC56i6VWiJTKtpf9i9PF7RAyID38_sanWQ99/s700/3-5f634608b987f__700.jpg&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;606&quot; data-original-width=&quot;700&quot; height=&quot;277&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeaQvQGMLtB_9BQ1RIbqwiTKqup0Mr9HRvKCdTpyHJT_PESShZyexSVdAmZElHa3MYNGf4z8GXyNA81tGhIbc0ZdHwdD_IIQERlMlVbKEDbbHyD3_4IjeVyNVq3jtZAFLjh3KB6UhC65Ie4iy4enNV56VAhC56i6VWiJTKtpf9i9PF7RAyID38_sanWQ99/s320/3-5f634608b987f__700.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;p style=&quot;text-align: center;&quot;&gt;It turns out humans are not the only one struggling with those 😅&lt;/p&gt;&lt;p&gt;&lt;b&gt;My first approach: train my own AI model&amp;nbsp;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;I started collecting online pictures and train my own model to solve the test. I used the&lt;a href=&quot;https://pypi.org/project/duckduckgo-search/&quot; target=&quot;_blank&quot;&gt; duckduckgo-search&lt;/a&gt;&amp;nbsp;python library with some keywords search such as:&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;ul style=&quot;text-align: left;&quot;&gt;&lt;li&gt;cars and trucks on a road with a traffic light&lt;/li&gt;&lt;li&gt;cars at a traffic junction&lt;/li&gt;&lt;li&gt;cars and buses on a road at a stop&lt;/li&gt;&lt;li&gt;car traffic taken from dash cam&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Here is code snippet for this:&lt;/div&gt;&lt;blockquote&gt;&lt;div style=&quot;background-color: #1e1e1e; color: #d4d4d4; font-family: monospace, Menlo, Monaco, &amp;quot;Courier New&amp;quot;, monospace; font-size: 14px; line-height: 19px; white-space: pre;&quot;&gt;&lt;div style=&quot;line-height: 19px;&quot;&gt;&lt;div&gt;&lt;span style=&quot;color: #c586c0;&quot;&gt;from&lt;/span&gt; duckduckgo_search &lt;span style=&quot;color: #c586c0;&quot;&gt;import&lt;/span&gt; DDGS&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;span style=&quot;color: #569cd6;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #dcdcaa;&quot;&gt;search_images&lt;/span&gt;(&lt;span style=&quot;color: #9cdcfe;&quot;&gt;keywords&lt;/span&gt;, &lt;span style=&quot;color: #9cdcfe;&quot;&gt;max_images&lt;/span&gt;=&lt;span style=&quot;color: #b5cea8;&quot;&gt;1&lt;/span&gt;)&lt;span style=&quot;color: gainsboro;&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;  &lt;span style=&quot;color: #c586c0;&quot;&gt;with&lt;/span&gt; DDGS&lt;span style=&quot;color: gainsboro;&quot;&gt;()&lt;/span&gt; &lt;span style=&quot;color: #c586c0;&quot;&gt;as&lt;/span&gt; ddgs&lt;span style=&quot;color: gainsboro;&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;    &lt;span style=&quot;color: #c586c0;&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: gainsboro;&quot;&gt;[&lt;/span&gt;r&lt;span style=&quot;color: gainsboro;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;&#39;image&#39;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;]&lt;/span&gt; &lt;span style=&quot;color: #c586c0;&quot;&gt;for&lt;/span&gt; r &lt;span style=&quot;color: #82c6ff;&quot;&gt;in&lt;/span&gt; ddgs.images&lt;span style=&quot;color: gainsboro;&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;div&gt;        keywords=keywords&lt;span style=&quot;color: gainsboro;&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;div&gt;        type_image=&lt;span style=&quot;color: #ce9178;&quot;&gt;&#39;photo&#39;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;div&gt;        max_results=max_images &lt;span style=&quot;color: gainsboro;&quot;&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;It was time-consuming to find relevant photos and label them. Some pictures were aerial pictures, some had watermarks, some were artistic photos, some were pictures of the dash cam instead of picture taken by dash cam, others were just irrelevant or duplicates. After quite some work, I was left with only about 30 descent pictures.&amp;nbsp;&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;This model did not perform well. One of the reasons is that the dataset was too small. I tried finding an existing dataset but it wasn&#39;t that easy. I submitted an application&amp;nbsp;to access the &lt;a href=&quot;https://www.cityscapes-dataset.com/login/&quot; target=&quot;_blank&quot;&gt;CityScape dataset&lt;/a&gt;&amp;nbsp;but by the time my access was granted, I already had another working solution.&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;&lt;b&gt;Second Attempt: Use a pre-trained Image Segmentation Model&lt;/b&gt;&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;I looked on HuggingFace for an existing Image Segmentation model and found &lt;a href=&quot;https://huggingface.co/nvidia/segformer-b5-finetuned-cityscapes-1024-1024&quot; target=&quot;_blank&quot;&gt;one from nvidia&lt;/a&gt; which is pre-trained on the &lt;a href=&quot;https://www.cityscapes-dataset.com/&quot; target=&quot;_blank&quot;&gt;city scape dataset&lt;/a&gt;. I tested it and found that it can identify traffic lights very well. I wrote a script script that follows these steps:&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;resize the image to 1024x1024 as expected by the model&lt;/li&gt;&lt;li&gt;use the &lt;a href=&quot;https://huggingface.co/docs/transformers/index&quot; target=&quot;_blank&quot;&gt;transformer&lt;/a&gt; python library to instantiate the model and pass the resized picture as input&lt;/li&gt;&lt;li&gt;as the model returns a list of masks for each object it can identify, I take the mask for the traffic lights and ignore the others&lt;/li&gt;&lt;li&gt;finally, I calculate which of the 16 squares the traffic lights fall into.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;You can see the code &lt;a href=&quot;https://huggingface.co/spaces/mattb512/trafficlight/blob/main/app.py&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;I built this demo using &lt;a href=&quot;https://www.gradio.app/&quot; target=&quot;_blank&quot;&gt;Gradio&lt;/a&gt;&amp;nbsp;(which you&amp;nbsp;can find on my &lt;a href=&quot;https://huggingface.co/spaces/mattb512/trafficlight&quot; target=&quot;_blank&quot;&gt;HuggingFace Space&lt;/a&gt;). Feel free to try it out but expect to wait a minute or so for the app to start, and it will be slow because it is running on a CPU. The white squares indicate where the traffic lights are located.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-8-D0rxgq0hHHOTKr-i6sMn774rsDdpZLnmkwxM0hf8Bdly__RWwPLDQJE31-CTOY84c5d1HW3leoL3RqhgxmDjJRSzRczdbZF4dLquCy0xFaxguhILGt8YSDuc9GKmgRDc3MYrqUuDlvpJJpcDmojwkmSmJ_0zaG0gDoi-Uzur0p43BJp-DfHNjjNrU5/s1562/Screenshot%202023-12-22%20at%2018.29.04.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1058&quot; data-original-width=&quot;1562&quot; height=&quot;434&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-8-D0rxgq0hHHOTKr-i6sMn774rsDdpZLnmkwxM0hf8Bdly__RWwPLDQJE31-CTOY84c5d1HW3leoL3RqhgxmDjJRSzRczdbZF4dLquCy0xFaxguhILGt8YSDuc9GKmgRDc3MYrqUuDlvpJJpcDmojwkmSmJ_0zaG0gDoi-Uzur0p43BJp-DfHNjjNrU5/w640-h434/Screenshot%202023-12-22%20at%2018.29.04.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;Conclusion: Can my model beat the click-farm?&lt;/b&gt;&lt;/p&gt;&lt;p&gt;I ran some basic performance tests on various hardware on Hugging Face and RunPod, then I calculated the cost of solving 1000 Captcha test.&lt;/p&gt;&lt;p&gt;&lt;google-sheets-html-origin&gt;&lt;/google-sheets-html-origin&gt;&lt;/p&gt;&lt;table border=&quot;1&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; data-sheets-root=&quot;1&quot; dir=&quot;ltr&quot; style=&quot;border-collapse: collapse; border: none; font-family: Arial; font-size: 10pt; table-layout: fixed; width: 0px;&quot; xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;&lt;colgroup&gt;&lt;col width=&quot;90&quot;&gt;&lt;/col&gt;&lt;col width=&quot;120&quot;&gt;&lt;/col&gt;&lt;col width=&quot;93&quot;&gt;&lt;/col&gt;&lt;col width=&quot;74&quot;&gt;&lt;/col&gt;&lt;col width=&quot;87&quot;&gt;&lt;/col&gt;&lt;col width=&quot;71&quot;&gt;&lt;/col&gt;&lt;/colgroup&gt;&lt;tbody&gt;&lt;tr style=&quot;height: 21px;&quot;&gt;&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;Provider&amp;quot;}&quot; style=&quot;background-color: #efefef; border: 1px solid rgb(0, 0, 0); font-weight: bold; overflow-wrap: break-word; overflow: hidden; padding: 2px 3px; vertical-align: top; white-space: normal;&quot;&gt;Provider&lt;/td&gt;&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;Device&amp;quot;}&quot; style=&quot;background-color: #efefef; border-color: rgb(0, 0, 0) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; font-weight: bold; overflow-wrap: break-word; overflow: hidden; padding: 2px 3px; vertical-align: top; white-space: normal;&quot;&gt;Device&lt;/td&gt;&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;Specs&amp;quot;}&quot; style=&quot;background-color: #efefef; border-color: rgb(0, 0, 0) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; font-weight: bold; overflow-wrap: break-word; overflow: hidden; padding: 2px 3px; vertical-align: top; white-space: normal;&quot;&gt;Specs&lt;/td&gt;&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;Time to Solve (in Seconds) / Image&amp;quot;}&quot; style=&quot;background-color: #efefef; border-color: rgb(0, 0, 0) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; font-weight: bold; overflow-wrap: break-word; overflow: hidden; padding: 2px 3px; vertical-align: top; white-space: normal;&quot;&gt;Time to Solve (in Seconds) / Image&lt;/td&gt;&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;Hardware Cost ($) / Hour&amp;quot;}&quot; style=&quot;background-color: #efefef; border-color: rgb(0, 0, 0) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; font-weight: bold; overflow-wrap: break-word; overflow: hidden; padding: 2px 3px; vertical-align: top; white-space: normal;&quot;&gt;Hardware Cost ($) / Hour&lt;/td&gt;&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;cost ($) / 1000 captchas&amp;quot;}&quot; style=&quot;background-color: #efefef; border-color: rgb(0, 0, 0) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; font-weight: bold; overflow-wrap: break-word; overflow: hidden; padding: 2px 3px; vertical-align: top; white-space: normal;&quot;&gt;cost ($) / 1000 captchas&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;height: 21px;&quot;&gt;&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;Apple&amp;quot;}&quot; style=&quot;border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; vertical-align: bottom;&quot;&gt;Apple&lt;/td&gt;&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;macbook&amp;quot;}&quot; style=&quot;border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; vertical-align: bottom;&quot;&gt;macbook&lt;/td&gt;&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;M3 Pro \n18 GB RAM&amp;quot;}&quot; style=&quot;border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; vertical-align: bottom;&quot;&gt;M3 Pro&lt;br /&gt;18 GB RAM&lt;/td&gt;&lt;td data-sheets-numberformat=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;3&amp;quot;:1}&quot; data-sheets-value=&quot;{&amp;quot;1&amp;quot;:3,&amp;quot;3&amp;quot;:9}&quot; style=&quot;border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;&quot;&gt;9&lt;/td&gt;&lt;td data-sheets-numberformat=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;0.00&amp;quot;,&amp;quot;3&amp;quot;:1}&quot; style=&quot;border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; vertical-align: bottom;&quot;&gt;&lt;/td&gt;&lt;td data-sheets-numberformat=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;0.00&amp;quot;,&amp;quot;3&amp;quot;:1}&quot; style=&quot;border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; vertical-align: bottom;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;height: 21px;&quot;&gt;&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;Hugging Face&amp;quot;}&quot; style=&quot;border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; vertical-align: bottom;&quot;&gt;Hugging Face&lt;/td&gt;&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;Base cpu&amp;quot;}&quot; style=&quot;border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; vertical-align: bottom;&quot;&gt;Base cpu&lt;/td&gt;&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;2 vCPU\n16 GB RAM&amp;quot;}&quot; style=&quot;border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; vertical-align: bottom;&quot;&gt;2 vCPU&lt;br /&gt;16 GB RAM&lt;/td&gt;&lt;td data-sheets-numberformat=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;3&amp;quot;:1}&quot; data-sheets-value=&quot;{&amp;quot;1&amp;quot;:3,&amp;quot;3&amp;quot;:35}&quot; style=&quot;border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;&quot;&gt;35&lt;/td&gt;&lt;td data-sheets-numberformat=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;0.00&amp;quot;,&amp;quot;3&amp;quot;:1}&quot; style=&quot;border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; vertical-align: bottom;&quot;&gt;&lt;/td&gt;&lt;td data-sheets-numberformat=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;0.00&amp;quot;,&amp;quot;3&amp;quot;:1}&quot; style=&quot;border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; vertical-align: bottom;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;height: 21px;&quot;&gt;&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;Hugging Face&amp;quot;}&quot; style=&quot;border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; vertical-align: bottom;&quot;&gt;Hugging Face&lt;/td&gt;&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;CPU upgrade&amp;quot;}&quot; style=&quot;border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; vertical-align: bottom;&quot;&gt;CPU upgrade&lt;/td&gt;&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;8 vCPU\n32 GB RAM&amp;quot;}&quot; style=&quot;border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; vertical-align: bottom;&quot;&gt;8 vCPU&lt;br /&gt;32 GB RAM&lt;/td&gt;&lt;td data-sheets-numberformat=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;3&amp;quot;:1}&quot; data-sheets-value=&quot;{&amp;quot;1&amp;quot;:3,&amp;quot;3&amp;quot;:24}&quot; style=&quot;border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;&quot;&gt;24&lt;/td&gt;&lt;td data-sheets-numberformat=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;0.00&amp;quot;,&amp;quot;3&amp;quot;:1}&quot; data-sheets-value=&quot;{&amp;quot;1&amp;quot;:3,&amp;quot;3&amp;quot;:0.03}&quot; style=&quot;border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;&quot;&gt;0.03&lt;/td&gt;&lt;td data-sheets-formula=&quot;=(R[0]C[-1]/(3600/R[0]C[-2]))*1000&quot; data-sheets-numberformat=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;0.00&amp;quot;,&amp;quot;3&amp;quot;:1}&quot; data-sheets-value=&quot;{&amp;quot;1&amp;quot;:3,&amp;quot;3&amp;quot;:0.19999999999999998}&quot; style=&quot;border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;&quot;&gt;0.20&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;height: 21px;&quot;&gt;&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;Hugging Face&amp;quot;}&quot; style=&quot;border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; vertical-align: bottom;&quot;&gt;Hugging Face&lt;/td&gt;&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;Nvidia t4 medium&amp;quot;}&quot; style=&quot;border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; vertical-align: bottom;&quot;&gt;Nvidia t4 medium&lt;/td&gt;&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;8 vCPU\n30 GB RAM\n16GB VRAM&amp;quot;}&quot; style=&quot;border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; vertical-align: bottom;&quot;&gt;8 vCPU&lt;br /&gt;30 GB RAM&lt;br /&gt;16GB VRAM&lt;/td&gt;&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:3,&amp;quot;3&amp;quot;:1.2}&quot; style=&quot;border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;&quot;&gt;1.2&lt;/td&gt;&lt;td data-sheets-numberformat=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;0.00&amp;quot;,&amp;quot;3&amp;quot;:1}&quot; data-sheets-value=&quot;{&amp;quot;1&amp;quot;:3,&amp;quot;3&amp;quot;:0.9}&quot; style=&quot;border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;&quot;&gt;0.90&lt;/td&gt;&lt;td data-sheets-formula=&quot;=(R[0]C[-1]/(3600/R[0]C[-2]))*1000&quot; data-sheets-numberformat=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;0.00&amp;quot;,&amp;quot;3&amp;quot;:1}&quot; data-sheets-value=&quot;{&amp;quot;1&amp;quot;:3,&amp;quot;3&amp;quot;:0.30000000000000004}&quot; style=&quot;border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;&quot;&gt;0.30&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;height: 21px;&quot;&gt;&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;RunPod&amp;quot;}&quot; style=&quot;background-color: #d9ead3; border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; vertical-align: bottom;&quot;&gt;RunPod&lt;/td&gt;&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;RTX 4000 Ada&amp;quot;}&quot; style=&quot;background-color: #d9ead3; border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; vertical-align: bottom;&quot;&gt;RTX 4000 Ada&lt;/td&gt;&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;9 vCPU \n50 GB RAM&amp;quot;}&quot; style=&quot;background-color: #d9ead3; border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; vertical-align: bottom;&quot;&gt;9 vCPU&lt;br /&gt;50 GB RAM&lt;/td&gt;&lt;td data-sheets-numberformat=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;0&amp;quot;,&amp;quot;3&amp;quot;:1}&quot; data-sheets-value=&quot;{&amp;quot;1&amp;quot;:3,&amp;quot;3&amp;quot;:1.1}&quot; style=&quot;background-color: #d9ead3; border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;&quot;&gt;1&lt;/td&gt;&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:3,&amp;quot;3&amp;quot;:0.15}&quot; style=&quot;background-color: #d9ead3; border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;&quot;&gt;0.15&lt;/td&gt;&lt;td data-sheets-formula=&quot;=(R[0]C[-1]/(3600/R[0]C[-2]))*1000&quot; data-sheets-numberformat=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;0.00&amp;quot;,&amp;quot;3&amp;quot;:1}&quot; data-sheets-value=&quot;{&amp;quot;1&amp;quot;:3,&amp;quot;3&amp;quot;:0.04583333333333334}&quot; style=&quot;background-color: #d9ead3; border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;&quot;&gt;0.05&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;height: 21px;&quot;&gt;&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;RunPod&amp;quot;}&quot; style=&quot;border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; vertical-align: bottom;&quot;&gt;RunPod&lt;/td&gt;&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;RTX 4090&amp;quot;}&quot; style=&quot;border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; vertical-align: bottom;&quot;&gt;RTX 4090&lt;/td&gt;&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;24 GB VRAM\n46 GB RAM\n16 vCPU&amp;quot;}&quot; style=&quot;border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; vertical-align: bottom;&quot;&gt;24 GB VRAM&lt;br /&gt;46 GB RAM&lt;br /&gt;16 vCPU&lt;/td&gt;&lt;td data-sheets-numberformat=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;0.0&amp;quot;,&amp;quot;3&amp;quot;:1}&quot; data-sheets-value=&quot;{&amp;quot;1&amp;quot;:3,&amp;quot;3&amp;quot;:1}&quot; style=&quot;border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;&quot;&gt;1.0&lt;/td&gt;&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:3,&amp;quot;3&amp;quot;:0.39}&quot; style=&quot;border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;&quot;&gt;0.39&lt;/td&gt;&lt;td data-sheets-formula=&quot;=(R[0]C[-1]/(3600/R[0]C[-2]))*1000&quot; data-sheets-numberformat=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;0.00&amp;quot;,&amp;quot;3&amp;quot;:1}&quot; data-sheets-value=&quot;{&amp;quot;1&amp;quot;:3,&amp;quot;3&amp;quot;:0.10833333333333334}&quot; style=&quot;border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;&quot;&gt;0.11&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;height: 21px;&quot;&gt;&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;RunPod&amp;quot;}&quot; style=&quot;border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; vertical-align: bottom;&quot;&gt;RunPod&lt;/td&gt;&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;RTX 6000 Ada&amp;quot;}&quot; style=&quot;border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; vertical-align: bottom;&quot;&gt;RTX 6000 Ada&lt;/td&gt;&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;22 vCPU\n50 GB RAM&amp;quot;}&quot; style=&quot;border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; vertical-align: bottom;&quot;&gt;22 vCPU&lt;br /&gt;50 GB RAM&lt;/td&gt;&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:3,&amp;quot;3&amp;quot;:0.85}&quot; style=&quot;border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;&quot;&gt;0.85&lt;/td&gt;&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:3,&amp;quot;3&amp;quot;:0.69}&quot; style=&quot;border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;&quot;&gt;0.69&lt;/td&gt;&lt;td data-sheets-formula=&quot;=(R[0]C[-1]/(3600/R[0]C[-2]))*1000&quot; data-sheets-numberformat=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;0.00&amp;quot;,&amp;quot;3&amp;quot;:1}&quot; data-sheets-value=&quot;{&amp;quot;1&amp;quot;:3,&amp;quot;3&amp;quot;:0.16291666666666665}&quot; style=&quot;border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;&quot;&gt;0.16&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;As expected, the model runs much faster on GPU than CPU. The GPUs are more expensive per hour, but cheaper per 1000s Captcha images. Assuming a hacker would not care about security and reliability (which is debatable), I used spot (i.e. interruptible), community (i.e. run by 3rd parties) GPU instances.&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;The cheapest option I found was the RTX 4000 Ada, which can process each image in 1 second and costs $ 0.15 per hour, which translate is a cost of $0.05 for each 1000 captchas processed.&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;&lt;span style=&quot;background-color: white;&quot;&gt;This is still more expensive than the price of $0.003 per image charged by click farms, but I haven&#39;t tried hard to optimize my model.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;google-sheets-html-origin&gt;&lt;/google-sheets-html-origin&gt;&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Captcha services like Google ReCaptcha or &lt;a href=&quot;https://www.hcaptcha.com/&quot; target=&quot;_blank&quot;&gt;hCaptcha&lt;/a&gt; have others security controls and risk assessment methods which are out of scope of this blog. My focus here is only on the traffic light identification task as it is really just an excuse for me to practice what I learned in AI courses.&amp;nbsp;&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Still, if you think of security as an onion, captchas look like a very thin outer layer. It may prevent unskilled hackers to bypass them, but it won&#39;t hold against a motivated hacker with basic AI knowledge.&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://codebazaar.blogspot.com/feeds/2844100913573876537/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/8927794127513218467/2844100913573876537?isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8927794127513218467/posts/default/2844100913573876537'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8927794127513218467/posts/default/2844100913573876537'/><link rel='alternate' type='text/html' href='http://codebazaar.blogspot.com/2023/12/can-ai-replace-captcha-click-farms.html' title='Can AI replace Captcha click farms?'/><author><name>Matt Buchner</name><uri>http://www.blogger.com/profile/03993705703169676412</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGJBh157km2WvcRk9Fd0alqVRHYw3pldCvcehZRPx8NXBkVlqWclPGMXjjvP_CKoYtUwPQECmIfijWZo-2-O64i5ogn-LI4qplVUgMixVlbsXwbJgQrwlSr44Wxp3Cr4o/s113/headshot.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8X_rFaR1MuyQSyEs3Y7d9f1OYIZVEMr79geGGCTf4Ag2ncx_323chXvnlyXfAcIJNls-qzPzOSRX9Uq-aMoXLJs9ecHWUI6KtxSCF-zF-EoMYMMUgSoOqdLtDUMOwY2ohvoqa7rBgGQ0izRkvm97q4BpmHcDRslDHCJ7cssBOV8BLWhm5iAvfwKjNpCG5/s72-w276-h320-c/main-qimg-df0968efea4fcc318cf815e67fd63292%20(1).jpeg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8927794127513218467.post-7711488535879971313</id><published>2022-09-21T13:58:00.008+02:00</published><updated>2022-09-23T20:41:10.501+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="aws"/><category scheme="http://www.blogger.com/atom/ns#" term="machine learning"/><category scheme="http://www.blogger.com/atom/ns#" term="sagemaker"/><title type='text'>Configure Amazon SageMaker Studio to auto-shutdown unused compute resources and install developer productivity extensions</title><content type='html'>&lt;p&gt;I have been learning and exploring Machine Learning lately. As I experimented with various tutorials and Jupyter notebooks, I found that Amazon SageMaker Studio was great for productivity. Simply put, it is a cloud IDE for Machine Learning.&lt;/p&gt;&lt;p&gt;There are many great extensions available to enhance the developer experience. For example, the LSP extension enables code auto-completion.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKKE84lTla7JjwYeF97Suzxu2iCGu7HyUOnmeqQiueodj90x7isGEQsSIem9Vzmc84ot4xdsnh-r7aAUPbPhvai02OuGyCTfscP9EU9R52NDKSYP-swyEwQpe3YCQ-K1t8tUHKoht1-PIaI3PA5QiPXnhQVf05n1QljrvUhy0Xr6bthIWDtRr6VEa0Xg/s669/10-autocomplete.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;255&quot; data-original-width=&quot;669&quot; height=&quot;189&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKKE84lTla7JjwYeF97Suzxu2iCGu7HyUOnmeqQiueodj90x7isGEQsSIem9Vzmc84ot4xdsnh-r7aAUPbPhvai02OuGyCTfscP9EU9R52NDKSYP-swyEwQpe3YCQ-K1t8tUHKoht1-PIaI3PA5QiPXnhQVf05n1QljrvUhy0Xr6bthIWDtRr6VEa0Xg/w497-h189/10-autocomplete.png&quot; width=&quot;497&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;&lt;/div&gt;In the example above, the auto-completion helps me navigate the class and functions available. Also, pyflakes indicates I imported the sagemaker module but I am not using it, which helps me to keep my code clean.&lt;p&gt;&lt;/p&gt;&lt;p&gt;Also, I (painfully) learned that it is easy to forget a running instance. From SageMaker Studio, you can launch services such as SageMaker Training Job, Hyperparameter tuning job or Serverless Inference. With these services, you will pay only for what you use, which is great. But SageMaker Studio can run multiple instances for the various notebooks you are working on. And if you are training your model directly in the notebook, you will need a beefy instance. In my case, I was using a&amp;nbsp;ml.g4dn.xlarge instance which has 4 vCPU, 16 Gb of RAM and 1 GPU. If I let it run 24/7, it will generate unnecessary costs and CO2 emissions.&lt;/p&gt;&lt;p&gt;To enable the developer productivity extensions and configure the server to automatically shut down all SageMaker Studio compute resources, you have to configure a&amp;nbsp;&lt;a href=&quot;https://docs.aws.amazon.com/sagemaker/latest/dg/studio-lcc.html&quot;&gt;Lifecycle Configuration&lt;/a&gt;. There are other ways to install these extensions, but they won&#39;t persist after a shutdown, so I don&#39;t recommend using them.&lt;/p&gt;&lt;p&gt;This &lt;a href=&quot;https://github.com/aws-samples/sagemaker-studio-lifecycle-config-examples&quot;&gt;repo&lt;/a&gt; contains some examples of scripts to be used with the Lifecycle Configuration. For this blog, we will enable the LSP Server and auto-shutdown extensions. I tweaked the examples from this repo and combined them in a single bash script.&lt;/p&gt;&lt;p&gt;The first step is to configure the server timeout. After 45 minutes of inactivity, I want the server to shut down.&lt;/p&gt;

&lt;pre class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;
#!/bin/bash
# This script installs the idle notebook auto-checker server extension to SageMaker Studio
# The original extension has a lab extension part where users can set the idle timeout via a Jupyter Lab widget.
# In this version the script installs the server side of the extension only. The idle timeout
# can be set via a command-line script which will be also created by this create and places into the
# user&#39;s home folder
#
# Installing the server side extension does not require Internet connection (as all the dependencies are stored in the
# install tarball) and can be done via VPCOnly mode.

set -eux

# timeout in minutes
export TIMEOUT_IN_MINS=45&lt;/code&gt;&lt;/pre&gt;

Next, the script prepares the installation of the shutdown.

&lt;pre class=&quot;line-numbers&quot; data-start=&quot;15&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;
# Should already be running in user home directory, but just to check:
cd /home/sagemaker-user

# By working in a directory starting with &quot;.&quot;, we won&#39;t clutter up users&#39; Jupyter file tree views
mkdir -p .auto-shutdown

# Create the command-line script for setting the idle timeout
cat &amp;gt; .auto-shutdown/set-time-interval.sh &amp;lt;&amp;lt; EOF
#!/opt/conda/bin/python
import json
import requests
TIMEOUT=${TIMEOUT_IN_MINS}
session = requests.Session()
# Getting the xsrf token first from Jupyter Server
response = session.get(&quot;http://localhost:8888/jupyter/default/tree&quot;)
# calls the idle_checker extension&#39;s interface to set the timeout value
response = session.post(&quot;http://localhost:8888/jupyter/default/sagemaker-studio-autoshutdown/idle_checker&quot;,
            json={&quot;idle_time&quot;: TIMEOUT, &quot;keep_terminals&quot;: False},
            params={&quot;_xsrf&quot;: response.headers[&#39;Set-Cookie&#39;].split(&quot;;&quot;)[0].split(&quot;=&quot;)[1]})
if response.status_code == 200:
    print(&quot;Succeeded, idle timeout set to {} minutes&quot;.format(TIMEOUT))
else:
    print(&quot;Error!&quot;)
    print(response.status_code)
EOF
chmod +x .auto-shutdown/set-time-interval.sh

# &quot;wget&quot; is not part of the base Jupyter Server image, you need to install it first if needed to download the tarball
sudo yum install -y wget
# You can download the tarball from GitHub or alternatively, if you&#39;re using VPCOnly mode, you can host on S3
wget -O .auto-shutdown/extension.tar.gz https://github.com/aws-samples/sagemaker-studio-auto-shutdown-extension/raw/main/sagemaker_studio_autoshutdown-0.1.5.tar.gz

# Or instead, could serve the tarball from an S3 bucket in which case &quot;wget&quot; would not be needed:
# aws s3 --endpoint-url [S3 Interface Endpoint] cp s3://[tarball location] .auto-shutdown/extension.tar.gz

# Installs the extension
cd .auto-shutdown
tar xzf extension.tar.gz
cd sagemaker_studio_autoshutdown-0.1.5

# Activate studio environment just for installing extension
export AWS_SAGEMAKER_JUPYTERSERVER_IMAGE=&quot;${AWS_SAGEMAKER_JUPYTERSERVER_IMAGE:-&#39;jupyter-server&#39;}&quot;
if [ &quot;$AWS_SAGEMAKER_JUPYTERSERVER_IMAGE&quot; = &quot;jupyter-server-3&quot; ] ; then
    eval &quot;$(conda shell.bash hook)&quot;
    conda activate studio
fi;

pip install --no-dependencies --no-build-isolation -e .
jupyter serverextension enable --py sagemaker_studio_autoshutdown&lt;/code&gt;&lt;/pre&gt;

Then we install the LSP

&lt;pre class=&quot;line-numbers&quot; data-start=&quot;64&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;
# Install:
# - The core JupyterLab LSP integration and whatever language servers you need (omitting autopep8
#   and yapf code formatters for Python, which don&#39;t yet have integrations per
#   https://github.com/jupyter-lsp/jupyterlab-lsp/issues/632)
# - Additional LSP plugins for formatting (black, isort) and refactoring (rope)
# - Spellchecker for markdown cells
# - Code formatting extension to bridge the LSP gap, and supported formatters
echo &quot;Installing jupyterlab-lsp and language tools&quot;
pip install jupyterlab-lsp \
    &#39;python-lsp-server[flake8,mccabe,pycodestyle,pydocstyle,pyflakes,pylint,rope]&#39; \
    jupyterlab-spellchecker \
    jupyterlab-code-formatter black isort
# Some LSP language servers install via JS, not Python. For full list of language servers see:
# https://jupyterlab-lsp.readthedocs.io/en/latest/Language%20Servers.html
jlpm add --dev bash-language-server dockerfile-language-server-nodejs

# This configuration override is optional, to make LSP &quot;extra-helpful&quot; by default:
CMP_CONFIG_DIR=.jupyter/lab/user-settings/@krassowski/jupyterlab-lsp/
CMP_CONFIG_FILE=completion.jupyterlab-settings
CMP_CONFIG_PATH=&quot;$CMP_CONFIG_DIR/$CMP_CONFIG_FILE&quot;
if test -f $CMP_CONFIG_PATH; then
    echo &quot;jupyterlab-lsp config file already exists: Skipping default config setup&quot;
else
    echo &quot;Setting continuous hinting to enabled by default&quot;
    mkdir -p $CMP_CONFIG_DIR
    echo &#39;{ &quot;continuousHinting&quot;: true }&#39; &amp;gt; $CMP_CONFIG_PATH
fi&lt;/code&gt;&lt;/pre&gt;

Finally, the script restart the server and configure the timeout.

&lt;pre class=&quot;line-numbers&quot; data-start=&quot;91&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;
if [ &quot;$AWS_SAGEMAKER_JUPYTERSERVER_IMAGE&quot; = &quot;jupyter-server-3&quot; ] ; then
    conda deactivate
fi;

# Restarts the jupyter server
nohup supervisorctl -c /etc/supervisor/conf.d/supervisord.conf restart jupyterlabserver

# Waiting for 30 seconds to make sure the Jupyter Server is up and running
sleep 30

# Calling the script to set the idle-timeout and active the extension
/home/sagemaker-user/.auto-shutdown/set-time-interval.sh&lt;/code&gt;&lt;/pre&gt;






Now that we have the script, we can load it using the AWS CLI or from the console. Since there is already an example with the CLI &lt;a href=&quot;https://aws.amazon.com/blogs/machine-learning/customize-amazon-sagemaker-studio-using-lifecycle-configurations/&quot;&gt;here&lt;/a&gt;, I will show how to do this with the console.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I already have Sagemaker Studio configured and working. In the AWS console for SageMaker Studio, click on the &lt;b&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;Attach&lt;/span&gt;&lt;/b&gt; button of the Lifecycle Configurations section.&lt;/div&gt;&lt;div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqjZHganAYRGmfiM5s48OhapVLdkkO2pxW4_gMeBico_Y5rBFGpCtzZknVq7MYO6gukfc2QlkgM923p4_8Pf_kT_nMAv8H3EkWQgGjSCEP0AXlxpLKASASjB-0z4wbqP8rjidiBOlRx37ELm0ZSFbFIfj6-c2QIvbYLLIbYeroZlrJvRFrWN7cJJesUQ/s1195/attach-lifecycle-configs.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;297&quot; data-original-width=&quot;1195&quot; height=&quot;109&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqjZHganAYRGmfiM5s48OhapVLdkkO2pxW4_gMeBico_Y5rBFGpCtzZknVq7MYO6gukfc2QlkgM923p4_8Pf_kT_nMAv8H3EkWQgGjSCEP0AXlxpLKASASjB-0z4wbqP8rjidiBOlRx37ELm0ZSFbFIfj6-c2QIvbYLLIbYeroZlrJvRFrWN7cJJesUQ/w436-h109/attach-lifecycle-configs.png&quot; width=&quot;436&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;Select &lt;b&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;New configuration&lt;/span&gt;&lt;/b&gt;. The configuration type is &lt;b&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;Jupyter server app&lt;/span&gt;&lt;/b&gt;. And I gave it the name &lt;b&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;autoshutdown-and-lsp&lt;/span&gt;&lt;/b&gt;.&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAgMPcL51Gk7-TOFnZydmY3P9AJ7X40_Vt8XokaYnymYePrBKVBgVrEztQXphaHAeC9w8u_BmzVWHS-NwAx8bVU9SiWkcREBwN5HycQh-xCbVmJwGAdlGl_gUra4sJGCTwLhK7rPuk3bZqzx1JWck2rTbbdRifwcrKSId3TTtpk009X4Pw7Qn936KeOg/s826/2-settings.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;
    &lt;img border=&quot;0&quot; data-original-height=&quot;578&quot; data-original-width=&quot;826&quot; height=&quot;305&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAgMPcL51Gk7-TOFnZydmY3P9AJ7X40_Vt8XokaYnymYePrBKVBgVrEztQXphaHAeC9w8u_BmzVWHS-NwAx8bVU9SiWkcREBwN5HycQh-xCbVmJwGAdlGl_gUra4sJGCTwLhK7rPuk3bZqzx1JWck2rTbbdRifwcrKSId3TTtpk009X4Pw7Qn936KeOg/w436-h305/2-settings.png&quot; width=&quot;436&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;Copy and paste your script and click on the button &lt;b&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;Attach&lt;/span&gt;&lt;/b&gt; to domain.&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi42iWg7LhUO959BATDmlTLQEMILHxkYIX2WymH1liKhihY7T5j0zFbdCcxukIMHsWCylYMvIt5syuJs4jPTf7fDfkQUd8N3h6-I6YhFlqGiVXAFlpqZKEAuurJ3DyVSjQA4yoc6d8Oq5G4ZYje0QLysyM9X82HcynpYv8joMTCt7Vbn4cXm6vrq9toJg/s829/3-scripts.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;447&quot; data-original-width=&quot;829&quot; height=&quot;237&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi42iWg7LhUO959BATDmlTLQEMILHxkYIX2WymH1liKhihY7T5j0zFbdCcxukIMHsWCylYMvIt5syuJs4jPTf7fDfkQUd8N3h6-I6YhFlqGiVXAFlpqZKEAuurJ3DyVSjQA4yoc6d8Oq5G4ZYje0QLysyM9X82HcynpYv8joMTCt7Vbn4cXm6vrq9toJg/w439-h237/3-scripts.png&quot; width=&quot;439&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;The Lifecycle Configuration should now be visible.&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2Q4FC0EOAao_TroFQrnQLyYIUs_Y5PE5N1wO6k0BtTIdnvlqrdDVSfdZKWeebpfcbjVqsr0X8pvIBcdbAVfRUH7m4UoHIsyq-GPz8MuBEKJZm6d8Qd-sP7dbXU4ivaysRF6ZZUheEcbgRvX91h-vxzIbJPz79NMzgYd7TyGXWmZJMhQIbBtDmhc9WAg/s1186/4-created.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;279&quot; data-original-width=&quot;1186&quot; height=&quot;104&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2Q4FC0EOAao_TroFQrnQLyYIUs_Y5PE5N1wO6k0BtTIdnvlqrdDVSfdZKWeebpfcbjVqsr0X8pvIBcdbAVfRUH7m4UoHIsyq-GPz8MuBEKJZm6d8Qd-sP7dbXU4ivaysRF6ZZUheEcbgRvX91h-vxzIbJPz79NMzgYd7TyGXWmZJMhQIbBtDmhc9WAg/w444-h104/4-created.png&quot; width=&quot;444&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;Select the script and click on the button &lt;b&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;Set as default&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihZ0n4Gj3LkYaLufcbjPE-gu-d9Wq-YNsEgnvPcVxtnOxt5cnKlf7bHRUSTj7fV4ci0HxDmbbufbrLlHLXR6nzt6l7iEjRQVAk5D_Aen32METpfP6EQrnwljfZnXfyvnlm4J2eIuEbeGwkQ08X9kvzeZCLfm2KQI3HNwzU_zWfItjUEqj3SdEviFOqCQ/s1201/5-default.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;292&quot; data-original-width=&quot;1201&quot; height=&quot;107&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihZ0n4Gj3LkYaLufcbjPE-gu-d9Wq-YNsEgnvPcVxtnOxt5cnKlf7bHRUSTj7fV4ci0HxDmbbufbrLlHLXR6nzt6l7iEjRQVAk5D_Aen32METpfP6EQrnwljfZnXfyvnlm4J2eIuEbeGwkQ08X9kvzeZCLfm2KQI3HNwzU_zWfItjUEqj3SdEviFOqCQ/w441-h107/5-default.png&quot; width=&quot;441&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;From the console, you can see what is running for a user but it is not telling which instance types are used.&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiopKW34d9DMr5A47222t6D1vr_rZfNTQOI2xEOD9ydX7KEWAU8jVEKbjOwstfpLE9dzdoDF_TxAVsn7FfIRD1PYWNHc49jPNWoWWjhAGP4EAq5vsH_vbbVCQgAIsmGAV-se785NsZVG0VuUBCeJouV8uuPLgQWuK1aAiYP_EN6QZYs5YwUlUy6ZwEgpQ/s1079/6-user-details.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;619&quot; data-original-width=&quot;1079&quot; height=&quot;248&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiopKW34d9DMr5A47222t6D1vr_rZfNTQOI2xEOD9ydX7KEWAU8jVEKbjOwstfpLE9dzdoDF_TxAVsn7FfIRD1PYWNHc49jPNWoWWjhAGP4EAq5vsH_vbbVCQgAIsmGAV-se785NsZVG0VuUBCeJouV8uuPLgQWuK1aAiYP_EN6QZYs5YwUlUy6ZwEgpQ/w431-h248/6-user-details.png&quot; width=&quot;431&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;&lt;/div&gt;Here is an example showing all compute resources shut down.&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtqFGwPYU3HHG-v9DSEjvyVmCFdCOIjw52cF6dbj8lBI6cr2eMlBSkM95e2QB_qnEEE77yJeKEjUHm4BH3VG6BV73KiuT8Ro_X1CF7M0be-tQzh4_vA-TIL6-Kao4aV5HD0a08aOLEHB2SjK9f71xFiR2PxmjguzR5odg2OnruBMk5PuY_9zri9ZV16Q/s1056/6b-all-down.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;591&quot; data-original-width=&quot;1056&quot; height=&quot;240&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtqFGwPYU3HHG-v9DSEjvyVmCFdCOIjw52cF6dbj8lBI6cr2eMlBSkM95e2QB_qnEEE77yJeKEjUHm4BH3VG6BV73KiuT8Ro_X1CF7M0be-tQzh4_vA-TIL6-Kao4aV5HD0a08aOLEHB2SjK9f71xFiR2PxmjguzR5odg2OnruBMk5PuY_9zri9ZV16Q/w429-h240/6b-all-down.png&quot; width=&quot;429&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;&lt;/div&gt;If SageMaker Studio is running, you can also see which Apps and Kernels are running.&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZQPamQnfr24yrKdw-ELt3GpleepNNREqYXVQKTI-fYt5k2DNdgbV9NHI-UA4B8hkiCjhPQ5TTrHuPTEvuaZmlGZ5mFFrTDTySCZV0Gm0JenuQFWiWpL57xjA7iZPajoK--tbCBetY3A4k7z4ZmPPPwsXLwgvuH-YPO9p0BVg332w3-gmnTLxVbkwbUA/s528/7-running-apps.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;393&quot; data-original-width=&quot;528&quot; height=&quot;317&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZQPamQnfr24yrKdw-ELt3GpleepNNREqYXVQKTI-fYt5k2DNdgbV9NHI-UA4B8hkiCjhPQ5TTrHuPTEvuaZmlGZ5mFFrTDTySCZV0Gm0JenuQFWiWpL57xjA7iZPajoK--tbCBetY3A4k7z4ZmPPPwsXLwgvuH-YPO9p0BVg332w3-gmnTLxVbkwbUA/w427-h317/7-running-apps.png&quot; width=&quot;427&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;If you search for &lt;b&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;lsp&lt;/span&gt;&lt;/b&gt; in the Extension section, you will see it has been automatically installed.&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-KBLc46lN2dDF7yM6MNjHIQiKQP0MV9w1rFN16a4OnMk9DqbRIkQHHWCfznDWCBGHLFM4LQDXtDO6Z6ruCW6XVFodHA0LUXcG602MMHBLyYCofayzuVBVjD9RefAMOLN4zZjLb_p6w_MohGJrnB7r8pHiUtzk48lCeIRCuJ78-7gj0zYw0FsYXlBKAA/s474/9-extensions.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;474&quot; data-original-width=&quot;316&quot; height=&quot;401&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-KBLc46lN2dDF7yM6MNjHIQiKQP0MV9w1rFN16a4OnMk9DqbRIkQHHWCfznDWCBGHLFM4LQDXtDO6Z6ruCW6XVFodHA0LUXcG602MMHBLyYCofayzuVBVjD9RefAMOLN4zZjLb_p6w_MohGJrnB7r8pHiUtzk48lCeIRCuJ78-7gj0zYw0FsYXlBKAA/w267-h401/9-extensions.png&quot; width=&quot;267&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;div&gt;Finally, you can see the logs from your bash script in Cloudwatch. The log group is called &lt;b&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;/aws/sagemaker/studio&lt;/span&gt;&lt;/b&gt; and the Log streams ends with &lt;span style=&quot;font-family: courier;&quot;&gt;&lt;b&gt;/LifecycleConfigOnStart&lt;/b&gt;&lt;/span&gt;.&lt;/div&gt;&lt;div&gt;&amp;nbsp;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjFlYW3UDstK5gkK1yNH-SqgbMp2mHEsXSxKpkKMOvTh3WzQAiLiFA6V9MYQpHIedOmj5ik7EAAPz_bXi20rqEBuhP1tDZxIhj_iEXJKaKcP21rjaUP71ZNOXVaX6Yg4-TkS1iF7sQIIND4k-l6LNkGYlvh5e8uLieFfogTWDEh-RS7qaGJILqiIFg9mg/s1628/8-cloudwatch.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;636&quot; data-original-width=&quot;1628&quot; height=&quot;227&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjFlYW3UDstK5gkK1yNH-SqgbMp2mHEsXSxKpkKMOvTh3WzQAiLiFA6V9MYQpHIedOmj5ik7EAAPz_bXi20rqEBuhP1tDZxIhj_iEXJKaKcP21rjaUP71ZNOXVaX6Yg4-TkS1iF7sQIIND4k-l6LNkGYlvh5e8uLieFfogTWDEh-RS7qaGJILqiIFg9mg/w583-h227/8-cloudwatch.png&quot; width=&quot;583&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;Note that if you want to update your script, you will have to start from step 1. You can&#39;t update a script in a Lifecycle Configuration that has already been created. For this reason, I recommend creating a pipeline using the AWS CLI to manage this process. Also, you could store the settings such as the timeout in AWS System Manager Parameter Store. Another approach would be to make the bash script generic and make it download and execute the necessary updatable scripts.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;Update 09/22: I realized I had another incurring charges from a ml.p3.2xlarge instance but I did not have any visible inference host in the console. The support team advised me to delete all endpoint configurations, models, users and domains from the console. In the Cost Explorer, you can filter per instance type to understand what is generating the cost. Additionally, I set up a daily and monthly billing alert.&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcHmNpx0y7L13My_6iTGcWivpdSHS68lxmnIhhsw141-twmokFpfllRgEpgaggKsTpwDpgOG0mTpi7C0tBGtRuyWyNbs3yThaLp6xDa0vx4YiHvEv7UkGiCXmCoOYjIbs-Y3Cn2A0PtzRLO_ad7noLkdSQej384d6UeqJyRp_9QDxAjm_Eg8N7x-qNhg/s1024/11-cost-reduction.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;412&quot; data-original-width=&quot;1024&quot; height=&quot;231&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcHmNpx0y7L13My_6iTGcWivpdSHS68lxmnIhhsw141-twmokFpfllRgEpgaggKsTpwDpgOG0mTpi7C0tBGtRuyWyNbs3yThaLp6xDa0vx4YiHvEv7UkGiCXmCoOYjIbs-Y3Cn2A0PtzRLO_ad7noLkdSQej384d6UeqJyRp_9QDxAjm_Eg8N7x-qNhg/w574-h231/11-cost-reduction.png&quot; width=&quot;574&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codebazaar.blogspot.com/feeds/7711488535879971313/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/8927794127513218467/7711488535879971313?isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8927794127513218467/posts/default/7711488535879971313'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8927794127513218467/posts/default/7711488535879971313'/><link rel='alternate' type='text/html' href='http://codebazaar.blogspot.com/2022/09/configure-amazon-sagemaker-studio-to.html' title='Configure Amazon SageMaker Studio to auto-shutdown unused compute resources and install developer productivity extensions'/><author><name>Matt Buchner</name><uri>http://www.blogger.com/profile/03993705703169676412</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGJBh157km2WvcRk9Fd0alqVRHYw3pldCvcehZRPx8NXBkVlqWclPGMXjjvP_CKoYtUwPQECmIfijWZo-2-O64i5ogn-LI4qplVUgMixVlbsXwbJgQrwlSr44Wxp3Cr4o/s113/headshot.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKKE84lTla7JjwYeF97Suzxu2iCGu7HyUOnmeqQiueodj90x7isGEQsSIem9Vzmc84ot4xdsnh-r7aAUPbPhvai02OuGyCTfscP9EU9R52NDKSYP-swyEwQpe3YCQ-K1t8tUHKoht1-PIaI3PA5QiPXnhQVf05n1QljrvUhy0Xr6bthIWDtRr6VEa0Xg/s72-w497-h189-c/10-autocomplete.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8927794127513218467.post-3270103098400915063</id><published>2017-01-14T04:59:00.003+01:00</published><updated>2022-09-21T11:38:28.467+02:00</updated><title type='text'>Encrypt your MSSQL database with TDE and SafeNet KeySecure, and why!</title><content type='html'>&lt;br /&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
One of the easiest way to encrypt a MSSQL (or Oracle) database is to use TDE - &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/bb934049.aspx&quot;&gt;Transparent Data Encryption&lt;/a&gt;. TDE requires the higher end enterprise MSSQL license and requires a DBA to execute SQL commands.&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
Why should you encrypt your database? If a hacker gets into your network, he may be able to steal a copy of the database or parts of the database. If the data is confidential or under HIPAA, SOX, CJIS or one of the many regulations out there, it can become quite a headache.&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
One of the benefit of TDE is that the application querying the database does not need to be aware the database encryption: it is transparent to the application. If you have an existing application and database, you can enable TDE on the database without downtime and without changing the code of the application.&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
But there is catch! By default, MSSQL (or Oracle) stores the encryption key in software on the same machine, so it is not protected and not physically separated from the data. Again, if a hacker has access to you network and access to the data, he will have access to the key next to it so he can just decrypt the data. It is basically like leaving the key on the door of your car. Might as well not lock it!&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;a href=&quot;https://safenet.gemalto.com/data-encryption/enterprise-key-management/key-secure/&quot;&gt;SafeNet KeySecure&lt;/a&gt; solves this issue by keeping a Key Encryption Key outside of the database. In the video below, I walk you through the step of encrypting a SQL database with KeySecure. We look at the MDF and backup files in a text editor before and after encryption to prove the data is being encrypted. We also look at how the access to key in KeySecure is being logged.&lt;/div&gt;


&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;iframe allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/C90O4ZnnA4M?hd=1&quot; width=&quot;560&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;

&lt;pre class=&quot;line-numbers&quot;&gt;
&lt;code class=&quot;language-sql&quot;&gt;
/****************************************************/
/* Dummy database */
/****************************************************/
USE master;

CREATE DATABASE SampleDBwithPII;
GO

USE SampleDBwithPII;

Create table Customers (Id int not null, Name varchar(max) not null, Address varchar(max) not null, SSN varchar(max) not null);
GO

INSERT INTO Customers values (2, &#39;Matt Buchner&#39;, &#39;Arboretum Plaza II, 9442 Capitol of Texas Hwy, 78759 Austin TX&#39;, &#39;111-222-3333&#39;);



/****************************************************/
/* PREP FOR TDE */
/****************************************************/


/*  enable EKM - Extensible Key Management
 you must be a sysadmin
*/

USE master;

GO 

sp_configure &#39;show advanced options&#39;, 1;
RECONFIGURE;

GO 

sp_configure &#39;EKM provider enabled&#39;, 1;
RECONFIGURE;

GO 


/* Load KS EKM - must be a sysadmin */
/* After running this command, check Security\Cryptographic Providers */
CREATE CRYPTOGRAPHIC PROVIDER safenetSQLEKM
FROM FILE = &#39;C:\Program Files\Safenet\SQLEKM\safenetsqlekm.dll&#39;

GO 

/* The credentials below should match the credential in KS */
/* After running this command, check Security\Credentials */
CREATE CREDENTIAL EKMCred WITH IDENTITY=&#39;tdeuser&#39;, SECRET=&#39;P@ssw0rd&#39;
FOR CRYPTOGRAPHIC PROVIDER safenetSQLEKM

GO 

ALTER LOGIN sa ADD CREDENTIAL EKMCred
/* example with Windows credentials
ALTER LOGIN [GTOLAB\mbuchner] ADD CREDENTIAL EKMCred;
*/

GO 

/* create a key in KS and create a reference to it in MSSQL */
CREATE ASYMMETRIC KEY SQL_EKM_RSA_2048_Key
FROM Provider safenetSQLEKM
WITH ALGORITHM = RSA_2048,
PROVIDER_KEY_NAME = &#39;MSSQL_TDE_EKM_RSA_2048_Key&#39;,
CREATION_DISPOSITION=CREATE_NEW

GO 

/* reuse the existing key in other cluster nodes 
CREATE ASYMMETRIC KEY SQL_EKM_RSA_2048_Key
FROM Provider safenetSQLEKM
WITH ALGORITHM = RSA_2048,
PROVIDER_KEY_NAME = &#39;MSSQL_TDE_EKM_RSA_2048_Key&#39;,
CREATION_DISPOSITION=OPEN_EXISTING
*/


/* check the keys have been created */
Select * from [master].[sys].[asymmetric_keys]



/****************************************************/
/* HOW TO CONFIGURE TDE */
/****************************************************/
USE master;

GO 

CREATE CREDENTIAL EKMCredTDE
WITH IDENTITY = &#39;tdeuser&#39;,
SECRET = &#39;P@ssw0rd&#39;
FOR CRYPTOGRAPHIC PROVIDER safenetSQLEKM ;

CREATE LOGIN tde_login
FROM ASYMMETRIC KEY SQL_EKM_RSA_2048_Key ;
GO

ALTER LOGIN tde_login
ADD CREDENTIAL EKMCredTDE;
GO


/* connect to our database */
USE SampleDBwithPII ;
GO

/* create symmetric encryption key */
CREATE DATABASE ENCRYPTION KEY
WITH ALGORITHM = AES_256
ENCRYPTION BY SERVER ASYMMETRIC KEY SQL_EKM_RSA_2048_Key ;
GO

/* enable encryption */
ALTER DATABASE SampleDBwithPII
SET ENCRYPTION ON ;
GO

/* query encryption state */
SELECT DB_NAME(e.database_id) AS DatabaseName, e.database_id, e.encryption_state,
CASE e.encryption_state
 WHEN 0 THEN &#39;No database encryption key present, no encryption&#39;
 WHEN 1 THEN &#39;Unencrypted&#39;
 WHEN 2 THEN &#39;Encryption in progress&#39;
 WHEN 3 THEN &#39;Encrypted&#39;
 WHEN 4 THEN &#39;Key change in progress&#39;
 WHEN 5 THEN &#39;Decryption in progress&#39;
END AS encryption_state_desc, c.name, e.percent_complete
FROM sys.dm_database_encryption_keys AS e
LEFT JOIN master.sys.asymmetric_keys AS c
ON e.encryptor_thumbprint = c.thumbprint
&lt;/code&gt;&lt;/pre&gt;
</content><link rel='replies' type='application/atom+xml' href='http://codebazaar.blogspot.com/feeds/3270103098400915063/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/8927794127513218467/3270103098400915063?isPopup=true' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8927794127513218467/posts/default/3270103098400915063'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8927794127513218467/posts/default/3270103098400915063'/><link rel='alternate' type='text/html' href='http://codebazaar.blogspot.com/2017/01/encrypt-your-mssql-database-with-tde.html' title='Encrypt your MSSQL database with TDE and SafeNet KeySecure, and why!'/><author><name>Matt Buchner</name><uri>http://www.blogger.com/profile/03993705703169676412</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGJBh157km2WvcRk9Fd0alqVRHYw3pldCvcehZRPx8NXBkVlqWclPGMXjjvP_CKoYtUwPQECmIfijWZo-2-O64i5ogn-LI4qplVUgMixVlbsXwbJgQrwlSr44Wxp3Cr4o/s113/headshot.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img.youtube.com/vi/C90O4ZnnA4M/default.jpg" height="72" width="72"/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8927794127513218467.post-6688832207497697208</id><published>2017-01-14T04:30:00.000+01:00</published><updated>2017-01-14T04:30:18.026+01:00</updated><title type='text'>SafeNet Authentication Service video demos</title><content type='html'>Below are a couple of video demos which I made for my work as Sales Engineer at Gemalto.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Demonstration of the SAS integration with the Microsoft Remote Desktop Gateway and Remote Desktop WebAccess. The most interesting part is when we show how the 2nd factor authentication can be bypassed by clicking directly on a cached RDP file.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;iframe width=&quot;320&quot; height=&quot;266&quot; class=&quot;YOUTUBE-iframe-video&quot; data-thumbnail-src=&quot;https://i.ytimg.com/vi/yYQ1QsB_Q7g/0.jpg&quot; src=&quot;https://www.youtube.com/embed/yYQ1QsB_Q7g?feature=player_embedded&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li style=&quot;text-align: left;&quot;&gt;Demonstration of the SAS integration with Netscaler using SAML, where SAS is the IdP and Netscaler is the SP.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;iframe width=&quot;320&quot; height=&quot;266&quot; class=&quot;YOUTUBE-iframe-video&quot; data-thumbnail-src=&quot;https://i.ytimg.com/vi/rqVIMiHqTY8/0.jpg&quot; src=&quot;https://www.youtube.com/embed/rqVIMiHqTY8?feature=player_embedded&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li style=&quot;text-align: left;&quot;&gt;Demonstration of the integration of SAS with CryptoAuditor from the company&amp;nbsp;&lt;a href=&quot;https://www.ssh.com/products/cryptoauditor/&quot;&gt;SSH Communications Security Corp&lt;/a&gt;.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;iframe width=&quot;320&quot; height=&quot;266&quot; class=&quot;YOUTUBE-iframe-video&quot; data-thumbnail-src=&quot;https://i.ytimg.com/vi/qSWpeihs8xg/0.jpg&quot; src=&quot;https://www.youtube.com/embed/qSWpeihs8xg?feature=player_embedded&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li style=&quot;text-align: left;&quot;&gt;Demonstration of the integration of SAS with Salesforce.com. The first video shows the configuration, the 2nd video shows the authentication user experience.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;iframe width=&quot;320&quot; height=&quot;266&quot; class=&quot;YOUTUBE-iframe-video&quot; data-thumbnail-src=&quot;https://i.ytimg.com/vi/Q5InwYbU3Wo/0.jpg&quot; src=&quot;https://www.youtube.com/embed/Q5InwYbU3Wo?feature=player_embedded&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;iframe width=&quot;320&quot; height=&quot;266&quot; class=&quot;YOUTUBE-iframe-video&quot; data-thumbnail-src=&quot;https://i.ytimg.com/vi/figU5_FFIOo/0.jpg&quot; src=&quot;https://www.youtube.com/embed/figU5_FFIOo?feature=player_embedded&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li style=&quot;text-align: left;&quot;&gt;Demonstration of the integration of SAS with Twillio &lt;a href=&quot;https://www.twilio.com/voice&quot;&gt;Programmable Voice&lt;/a&gt; APIs. The authenticating user receives a call and Twillio plays the 6 digit code the user need to authenticate.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;iframe width=&quot;320&quot; height=&quot;266&quot; class=&quot;YOUTUBE-iframe-video&quot; data-thumbnail-src=&quot;https://i.ytimg.com/vi/M8bS8du07ok/0.jpg&quot; src=&quot;https://www.youtube.com/embed/M8bS8du07ok?feature=player_embedded&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li style=&quot;text-align: left;&quot;&gt;Demonstration of SAS integration with Linux PAM.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;iframe width=&quot;320&quot; height=&quot;266&quot; class=&quot;YOUTUBE-iframe-video&quot; data-thumbnail-src=&quot;https://i.ytimg.com/vi/UCnzT3zIlJE/0.jpg&quot; src=&quot;https://www.youtube.com/embed/UCnzT3zIlJE?feature=player_embedded&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://codebazaar.blogspot.com/feeds/6688832207497697208/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/8927794127513218467/6688832207497697208?isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8927794127513218467/posts/default/6688832207497697208'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8927794127513218467/posts/default/6688832207497697208'/><link rel='alternate' type='text/html' href='http://codebazaar.blogspot.com/2017/01/safenet-authentication-service-video.html' title='SafeNet Authentication Service video demos'/><author><name>Matt Buchner</name><uri>http://www.blogger.com/profile/03993705703169676412</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGJBh157km2WvcRk9Fd0alqVRHYw3pldCvcehZRPx8NXBkVlqWclPGMXjjvP_CKoYtUwPQECmIfijWZo-2-O64i5ogn-LI4qplVUgMixVlbsXwbJgQrwlSr44Wxp3Cr4o/s113/headshot.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img.youtube.com/vi/yYQ1QsB_Q7g/default.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8927794127513218467.post-4422068805386961413</id><published>2014-07-11T05:11:00.001+02:00</published><updated>2014-07-11T06:22:39.077+02:00</updated><title type='text'>How to SSH with your Smart Card</title><content type='html'>If you have Linux servers, you must be familiar with SSH - &lt;a href=&quot;http://en.wikipedia.org/wiki/Secure_Shell&quot;&gt;Secure SHell&lt;/a&gt;. It is common for administrators to use strong authentication because they have the control of the entire company network and resources.&lt;br /&gt;
&lt;br /&gt;
You can configure tools such as &lt;a href=&quot;http://www.joebar.ch/puttysc/&quot;&gt;PuttySC&lt;/a&gt;, &lt;a href=&quot;http://www.risacher.org/putty-cac/&quot;&gt;PuttyCAC&lt;/a&gt; or &lt;a href=&quot;http://www.vandyke.com/products/securecrt/&quot;&gt;SecureCRT&lt;/a&gt; to use smart card credentials to SSH to your servers.&lt;br /&gt;
&lt;br /&gt;
I made this video to show how it works, enjoy!&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;iframe allowfullscreen=&#39;allowfullscreen&#39; webkitallowfullscreen=&#39;webkitallowfullscreen&#39; mozallowfullscreen=&#39;mozallowfullscreen&#39; width=&#39;320&#39; height=&#39;266&#39; src=&#39;https://www.youtube.com/embed/r55lPYtkXuc?feature=player_embedded&#39; frameborder=&#39;0&#39;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;br /&gt;
To configure your server for smart card authentication:&lt;br /&gt;
1. Extract the public key out of the certificate in the card, I run the following command:&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
pprint.exe -l &quot;c:\Program Files (x86)\Gemalto\DotNet PKCS11\gtop11dotnet.dll&quot;&lt;/blockquote&gt;
2. Add the public key to ~/.sshd/authorized_keys on the server, it looks like this:&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
ssh-rsa AAAAB3NzaC1yc2EAAAAFAAABAAEAAACBANnQe0X1Rl6QezigIXlfe4uzBtKkI083/oL3fl3vfQKdpdwwlwit3ODAOh2qpfs97r+OYUQPY66knNCW/u6hX2hiQk5DXeMR1HuZXQRxGKBxJZAftRXO3pD6b3pfH7djnfudGpg8UMHUBoWDUJ1UMh60K/+0QUqAyKT42vexh1Kj token-key&lt;/blockquote&gt;
&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://codebazaar.blogspot.com/feeds/4422068805386961413/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/8927794127513218467/4422068805386961413?isPopup=true' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8927794127513218467/posts/default/4422068805386961413'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8927794127513218467/posts/default/4422068805386961413'/><link rel='alternate' type='text/html' href='http://codebazaar.blogspot.com/2014/07/how-to-ssh-with-your-smart-card.html' title='How to SSH with your Smart Card'/><author><name>Matt Buchner</name><uri>http://www.blogger.com/profile/03993705703169676412</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGJBh157km2WvcRk9Fd0alqVRHYw3pldCvcehZRPx8NXBkVlqWclPGMXjjvP_CKoYtUwPQECmIfijWZo-2-O64i5ogn-LI4qplVUgMixVlbsXwbJgQrwlSr44Wxp3Cr4o/s113/headshot.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8927794127513218467.post-8676440816474756800</id><published>2014-06-29T00:15:00.000+02:00</published><updated>2014-06-29T00:17:04.246+02:00</updated><title type='text'>Install and Configure Citrix XenApp 6.5 in 15 minutes</title><content type='html'>I recently had to build a Citrix XenApp lab and I decided to make this video to help others that are just getting started with this software.&lt;br /&gt;
&lt;br /&gt;
The video shows how to install and configure step by step:&lt;br /&gt;
- Citrix License Server&lt;br /&gt;
- Citrix XenApp 6.5&lt;br /&gt;
- Citrix Web Interface&lt;br /&gt;
&lt;br /&gt;
Finally we connect to the Citrix environment to access a virtualized application.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;iframe allowfullscreen=&#39;allowfullscreen&#39; webkitallowfullscreen=&#39;webkitallowfullscreen&#39; mozallowfullscreen=&#39;mozallowfullscreen&#39; width=&#39;320&#39; height=&#39;266&#39; src=&#39;https://www.youtube.com/embed/ReffAq5CVXQ?feature=player_embedded&#39; frameborder=&#39;0&#39;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://codebazaar.blogspot.com/feeds/8676440816474756800/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/8927794127513218467/8676440816474756800?isPopup=true' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8927794127513218467/posts/default/8676440816474756800'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8927794127513218467/posts/default/8676440816474756800'/><link rel='alternate' type='text/html' href='http://codebazaar.blogspot.com/2014/06/install-and-configure-citrix-xenapp-65.html' title='Install and Configure Citrix XenApp 6.5 in 15 minutes'/><author><name>Matt Buchner</name><uri>http://www.blogger.com/profile/03993705703169676412</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGJBh157km2WvcRk9Fd0alqVRHYw3pldCvcehZRPx8NXBkVlqWclPGMXjjvP_CKoYtUwPQECmIfijWZo-2-O64i5ogn-LI4qplVUgMixVlbsXwbJgQrwlSr44Wxp3Cr4o/s113/headshot.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8927794127513218467.post-7546925897699243621</id><published>2011-10-16T17:59:00.000+02:00</published><updated>2011-10-16T20:04:48.048+02:00</updated><title type='text'>Neutral or stability shoes? Hack into your running!</title><content type='html'>&lt;div class=&quot;fb-like&quot; data-href=&quot;http://codebazaar.blogspot.com/2011/10/neutral-or-stability-shoes-hack-into.html&quot; data-send=&quot;true&quot; data-width=&quot;450&quot; data-show-faces=&quot;true&quot;&gt;&lt;/div&gt;&lt;br /&gt;
Two month ago, I sprained my ankle. Now that my ankle recovered, I feel comfortable running again. My shoes had about 200 miles on them already so I decided to buy a new pair. I went to &lt;a href=&quot;http://www.therunningcompany.net/austin-store-info&quot;&gt;Texas Running Company&lt;/a&gt;&amp;nbsp;and I discovered a very geeky equipment there, and I could not resist to share it on this blog.&lt;br /&gt;
&lt;br /&gt;
I am not an expert in running shoes business but from what I understand there are two types: neutral or stability. Depending on how you run, you will need one or the other. But how do you know which one is good for you? You could ask somebody to run behind you and look, or you can go the techie way. And of course, this is the way I like the best. :)&lt;br /&gt;
&lt;br /&gt;
In the store, they had a camera positioned right behind a treadmill. We recorded 2 short runs (about 30 seconds for each run) and analyzed them. I was honestly very surprised by the results.&lt;br /&gt;
&lt;br /&gt;
The two pictures below shows the two shoe types. On the left, I was trying neutral shoes; on the right it is stability shoes.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjj2B3DwZaU193sFKTHFTEp-GqWyIon7N2GvFVBbIs3PW67f65-nfUor1vXEbcwBl1zeij-HDcx5E8u9oDVjD1zh5pB8zL1XidkfG3bEYpL9vBcj6BODPulJJPi1DmGoZ1HIEi_Ix2eM-Kp/s1600/both-shoes.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;240&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjj2B3DwZaU193sFKTHFTEp-GqWyIon7N2GvFVBbIs3PW67f65-nfUor1vXEbcwBl1zeij-HDcx5E8u9oDVjD1zh5pB8zL1XidkfG3bEYpL9vBcj6BODPulJJPi1DmGoZ1HIEi_Ix2eM-Kp/s640/both-shoes.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
As you can see, my right ankle bends inward when my feet is landing with the neutral shoes. The technical term for it is actually &lt;a href=&quot;http://www.runnersworld.ltd.uk/pronation.htm&quot;&gt;overpronation&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
Here is the video of the 2 runs.&lt;/div&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;iframe allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;315&quot; src=&quot;http://www.youtube.com/embed/84ccsvzGIfU&quot; width=&quot;420&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
Since this is a tech blog, I would like to share how I merge the 2 videos I got from the store. I used &lt;a href=&quot;http://avisynth.org/mediawiki/Main_Page&quot;&gt;Avisynth&lt;/a&gt;&amp;nbsp;and &lt;a href=&quot;http://www.virtualdub.org/&quot;&gt;VirtualDub&lt;/a&gt; with the following script.&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:js&quot;&gt;clip1=AVISource(&quot;run1.avi&quot;).AssumeFPS(5, false)
clip2=AVISource(&quot;run2.avi&quot;).AssumeFPS(5, false)
StackHorizontal(clip1,clip2)
&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://codebazaar.blogspot.com/feeds/7546925897699243621/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/8927794127513218467/7546925897699243621?isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8927794127513218467/posts/default/7546925897699243621'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8927794127513218467/posts/default/7546925897699243621'/><link rel='alternate' type='text/html' href='http://codebazaar.blogspot.com/2011/10/neutral-or-stability-shoes-hack-into.html' title='Neutral or stability shoes? Hack into your running!'/><author><name>Matt Buchner</name><uri>http://www.blogger.com/profile/03993705703169676412</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGJBh157km2WvcRk9Fd0alqVRHYw3pldCvcehZRPx8NXBkVlqWclPGMXjjvP_CKoYtUwPQECmIfijWZo-2-O64i5ogn-LI4qplVUgMixVlbsXwbJgQrwlSr44Wxp3Cr4o/s113/headshot.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjj2B3DwZaU193sFKTHFTEp-GqWyIon7N2GvFVBbIs3PW67f65-nfUor1vXEbcwBl1zeij-HDcx5E8u9oDVjD1zh5pB8zL1XidkfG3bEYpL9vBcj6BODPulJJPi1DmGoZ1HIEi_Ix2eM-Kp/s72-c/both-shoes.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8927794127513218467.post-3694979386560666072</id><published>2011-08-04T06:41:00.000+02:00</published><updated>2011-08-05T04:49:55.901+02:00</updated><title type='text'>Chessboard picture recognition project - part 1</title><content type='html'>&lt;div id=&quot;fb-root&quot;&gt;&lt;/div&gt;&lt;script src=&quot;http://connect.facebook.net/en_US/all.js#appId=134707656604826&amp;amp;xfbml=1&quot;&gt;&lt;/script&gt;&lt;fb:like href=&quot;http://codebazaar.blogspot.com/2011/08/chess-board-recognition-project-part-1.html&quot; send=&quot;true&quot; width=&quot;450&quot; show_faces=&quot;true&quot; font=&quot;&quot;&gt;&lt;/fb:like&gt;&lt;br /&gt;
&lt;br /&gt;
Follow the discussion on &lt;a href=&quot;http://news.ycombinator.com/item?id=2848516&quot;&gt;YCombinator&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;I like to play chess. It is challenging, it requires strategic thinking and it is a great way to clear up your mind. I also like to take my time to play it. It can take a day, a week or even a month! One day I took a picture of the game I was playing to help me to think about it later in the day. This picture gave me the idea to write an application that is capable to analyze the game picture and determine the position of each piece on the board. Maybe someday it could even determine the next best move or continue the game online. &lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;I successfully implemented the first part of the application. This blog post describes how this program is working.&lt;/div&gt;&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTFcfflrXNp2HVX8yWZsHMoazEnFrqjL3h8m0sIzQXCzRwL6Jbj_pK4QZ31MAB0Orf0DeSEhTVvFMBkJspcSuleZVMynIHWJblTzzjT8IoGh0KchsZ7yNgM_YjLABBCLDbH1TwQB7xGUc7/s1600/4.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTFcfflrXNp2HVX8yWZsHMoazEnFrqjL3h8m0sIzQXCzRwL6Jbj_pK4QZ31MAB0Orf0DeSEhTVvFMBkJspcSuleZVMynIHWJblTzzjT8IoGh0KchsZ7yNgM_YjLABBCLDbH1TwQB7xGUc7/s320/4.png&quot; width=&quot;240&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;The photo on the left is the original picture I worked on.&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;Since I have never worked on computer vision, I started by reading about it on &lt;a href=&quot;http://en.wikipedia.org/wiki/Computer_vision&quot;&gt;wikipedia&lt;/a&gt;. I also found a few student&#39;s research papers that put me in the right direction such as &lt;a href=&quot;http://homepages.inf.ed.ac.uk/s0346435/projects/chess_project/visual_chess_diss.pdf&quot;&gt;Scott Blunsden&#39;s paper&lt;/a&gt; and &lt;a href=&quot;http://www.comp.nus.edu.sg/%7Ecs4243/showcase/chess_vision/chess_vision.html&quot;&gt;Chua Huiyan, Le Vinh and Wong Lai Kuan&#39;s paper&lt;/a&gt;. &lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;The first step is to find the gridlines of the chessboard. I processed the image with a &lt;a href=&quot;http://en.wikipedia.org/wiki/Canny_edge_detector&quot;&gt;Canny edge detector&lt;/a&gt; and then a &lt;a href=&quot;http://en.wikipedia.org/wiki/Hough_transform&quot;&gt;Hough line detector&lt;/a&gt;. I found a Java implementation for these algorithms from &lt;a href=&quot;http://www.tomgibara.com/computer-vision/&quot;&gt;Tom Gibara&#39;s website&lt;/a&gt; and the &lt;a href=&quot;http://csb.essex.ac.uk/software/HoughTransform/&quot;&gt;Vision and Synthetic Environments Laboratory&#39;s web site&lt;/a&gt;.&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;The picture below on the left is the output of the Canny edge detector. The green lines on the right picture are the result of the Hough line detection.&lt;/div&gt;&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNOjcGEIJmW-veyJcqIe1pS2bkVWMP0UsGeGKKRL_8gD4d520vl2s-6NVwVzr66Oj4bPb6Waswo_ThD6azOgsl4ZJYCqYU6kSEOTcasZUc6Xeu8gaj1kgqVVo9sqT-RauUP3AU-3D54EAN/s1600/canny-4.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNOjcGEIJmW-veyJcqIe1pS2bkVWMP0UsGeGKKRL_8gD4d520vl2s-6NVwVzr66Oj4bPb6Waswo_ThD6azOgsl4ZJYCqYU6kSEOTcasZUc6Xeu8gaj1kgqVVo9sqT-RauUP3AU-3D54EAN/s320/canny-4.png&quot; width=&quot;240&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpnzEyiWLsD-JgC-n5xPgErHTJGsQmfZPdRQLftStS8tYbhbTKQN1cCbgZobjDwnuJOIWeL7LVK_JPoXyel_Zte0FgBpDYH0PAq1jsvPnkGYQJ9TcPrHUo_gR7WfxzbVq8WfJ44D_JlKlS/s1600/hough-4.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpnzEyiWLsD-JgC-n5xPgErHTJGsQmfZPdRQLftStS8tYbhbTKQN1cCbgZobjDwnuJOIWeL7LVK_JPoXyel_Zte0FgBpDYH0PAq1jsvPnkGYQJ9TcPrHUo_gR7WfxzbVq8WfJ44D_JlKlS/s320/hough-4.png&quot; width=&quot;240&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidjp2OE66ZeQzqggb52EYulvU_a2VvlD2OWCHdeoApOxx4gCkfx3h6_K9rjeUHEKEbZOF55gGAm0rWVK2gDn_DpC_YfAZJOHWmkc-j8b_m-LQSSXkCGTvEDdZ1MeNDfSLm0L_2A2N77M5Y/s1600/hough-filtered3.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;150&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidjp2OE66ZeQzqggb52EYulvU_a2VvlD2OWCHdeoApOxx4gCkfx3h6_K9rjeUHEKEbZOF55gGAm0rWVK2gDn_DpC_YfAZJOHWmkc-j8b_m-LQSSXkCGTvEDdZ1MeNDfSLm0L_2A2N77M5Y/s200/hough-filtered3.png&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;The lines found on the picture above are actually the lines of the chessboard. But in some cases, the objects taken in the picture around the  chessboard can bring some confusion. On the left picture, the chairs  are introducing some lines that are not part of the board. To filter these lines out, I implemented an algorithm to filter 2 larger sets of lines with a 90-degree angle.&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhluJDhB7AZlhBKSeOUcwTnbnXbiKQoxQmihzZGLklnVdOFlDz9i-8ZJWwn8WOqPOlWTDWqnADq7rd1yRJ-UY1nEDpvzPe2HC4uTgcPnU7Wkd7mdBsho41xmC4RsPcfBnmilEMf45hmw-5i/s1600/with-intersection-points.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;200&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhluJDhB7AZlhBKSeOUcwTnbnXbiKQoxQmihzZGLklnVdOFlDz9i-8ZJWwn8WOqPOlWTDWqnADq7rd1yRJ-UY1nEDpvzPe2HC4uTgcPnU7Wkd7mdBsho41xmC4RsPcfBnmilEMf45hmw-5i/s200/with-intersection-points.png&quot; width=&quot;150&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;Once I got the 2 sets of 9 perpendicular lines, the program finds all the intersection points between these lines on the picture as shown on the picture on the left.&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;The program then finds the coordinates of each square that forms the chessboard. &lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGeVkTioVr6BnidJi-XaqNL05sek4QkWH11eoFLn73JvPgbqCSgiqbKSqUc_ws4gwzRsJavaK8UlOZPMXZkPYFbQJ-OhPkVk5QoBOHmqNV6M4AMxjyhvlKiTHkKzwCiC9zVOtpoyO0qMUA/s1600/chess-board-cut-out.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;180&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGeVkTioVr6BnidJi-XaqNL05sek4QkWH11eoFLn73JvPgbqCSgiqbKSqUc_ws4gwzRsJavaK8UlOZPMXZkPYFbQJ-OhPkVk5QoBOHmqNV6M4AMxjyhvlKiTHkKzwCiC9zVOtpoyO0qMUA/s200/chess-board-cut-out.png&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;At this point, I was able to isolate each square and process them separately. For example, the program is able to determine whether each square is white or black by calculating its average color and comparing it to the black and white colors. The results were correct except for one of the square because a piece of the opposite color was standing on it. Since the color of the squares of chessboard alternates, I could easily identify these errors.&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;What&#39;s next? I probably completed the easiest part of the project. I expect the chess piece recognition algorithm to be quite complex.&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;If you have a suggestion to help me finish this app, please leave a comment.&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;I am working on this project just for fun. If you are interested to see what are the real world applications of computer vision in the game industry, check out this web site: &lt;a href=&quot;http://www.sportvision.com/&quot;&gt;http://www.sportvision.com/&lt;/a&gt;.&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codebazaar.blogspot.com/feeds/3694979386560666072/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/8927794127513218467/3694979386560666072?isPopup=true' title='31 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8927794127513218467/posts/default/3694979386560666072'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8927794127513218467/posts/default/3694979386560666072'/><link rel='alternate' type='text/html' href='http://codebazaar.blogspot.com/2011/08/chess-board-recognition-project-part-1.html' title='Chessboard picture recognition project - part 1'/><author><name>Matt Buchner</name><uri>http://www.blogger.com/profile/03993705703169676412</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGJBh157km2WvcRk9Fd0alqVRHYw3pldCvcehZRPx8NXBkVlqWclPGMXjjvP_CKoYtUwPQECmIfijWZo-2-O64i5ogn-LI4qplVUgMixVlbsXwbJgQrwlSr44Wxp3Cr4o/s113/headshot.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTFcfflrXNp2HVX8yWZsHMoazEnFrqjL3h8m0sIzQXCzRwL6Jbj_pK4QZ31MAB0Orf0DeSEhTVvFMBkJspcSuleZVMynIHWJblTzzjT8IoGh0KchsZ7yNgM_YjLABBCLDbH1TwQB7xGUc7/s72-c/4.png" height="72" width="72"/><thr:total>31</thr:total><georss:featurename>Austin, TX, USA</georss:featurename><georss:point>30.267153 -97.743060799999967</georss:point><georss:box>30.058051 -97.928042299999973 30.476255000000002 -97.55807929999996</georss:box></entry><entry><id>tag:blogger.com,1999:blog-8927794127513218467.post-7313617545406155020</id><published>2011-06-18T02:49:00.000+02:00</published><updated>2011-07-19T00:33:15.781+02:00</updated><title type='text'>Introduction to Metasploit and Armitage</title><content type='html'>&lt;div id=&quot;fb-root&quot;&gt;&lt;/div&gt;&lt;script src=&quot;http://connect.facebook.net/en_US/all.js#appId=134707656604826&amp;amp;xfbml=1&quot;&gt;
&lt;/script&gt;&lt;fb:like font=&quot;&quot; href=&quot;http://codebazaar.blogspot.com/2011/06/introduction-to-metasploit-and-armitage.html&quot; send=&quot;true&quot; show_faces=&quot;true&quot; width=&quot;450&quot;&gt;&lt;/fb:like&gt;&lt;br /&gt;
Today I had a great half-day training on &lt;a href=&quot;http://www.metasploit.com/&quot;&gt;Metasploit&lt;/a&gt; and &lt;a href=&quot;http://www.fastandeasyhacking.com/&quot;&gt;Armitage&lt;/a&gt; organized by our local OWASP Austin chapter and hosted by Microsoft. What I learned today was so interesting that I can&#39;t resist to share it here.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipVSJvQSW3yq62kRR2NYVnzCfkdGzI9to_U85BzhjDnLUd2UFefpoOn1EOARaqaSuqFrvpiAyswM96SaUS1lGTfp0o3hLm5YYi_PZlWFPp3i4Y-J2LyudQBYR6WEONlfQK7RcFT7WZL7Z6/s1600/2011-06-17+16.54.39.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;300&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipVSJvQSW3yq62kRR2NYVnzCfkdGzI9to_U85BzhjDnLUd2UFefpoOn1EOARaqaSuqFrvpiAyswM96SaUS1lGTfp0o3hLm5YYi_PZlWFPp3i4Y-J2LyudQBYR6WEONlfQK7RcFT7WZL7Z6/s400/2011-06-17+16.54.39.jpg&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style=&quot;text-align: center;&quot;&gt;Raphael Mudge - Designer of Armitage&lt;/div&gt;&lt;br /&gt;
Metasploit is an open source penetration testing framework. It contains a database of exploits, payloads and post modules. The goal of the training was to find an exploit on a remote machine, run a payload through this exploit and execute a post module (which is what you can do after taking control over the victim&#39;s machine). Of course, you can find more detail about it on &lt;a href=&quot;http://en.wikipedia.org/wiki/Metasploit_Project&quot;&gt;wikipedia&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Metasploit is a command line tool. To make it easier (and funnier), Raphael Mudge designed Armitage, which is a user interface for Metasploit. Here is how it looks like:&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh30ANEwxH1m_1KdHMj_ZD1L1L0TNz8DZYhJYdjpmTlZsZ3I82QUJKNRYpVrNR6gYxoPiW2c6FWzxEuPsh96dd8dOe7E41zw_oXUTJ6Z75p6rPuimASidXJz8LcS_jocoUJOLOiBXMQ2oEG/s1600/armitage.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;202&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh30ANEwxH1m_1KdHMj_ZD1L1L0TNz8DZYhJYdjpmTlZsZ3I82QUJKNRYpVrNR6gYxoPiW2c6FWzxEuPsh96dd8dOe7E41zw_oXUTJ6Z75p6rPuimASidXJz8LcS_jocoUJOLOiBXMQ2oEG/s400/armitage.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;Armitage - GUI for Metasploit&lt;br /&gt;
&lt;br /&gt;
When a machine on the network is comprised, Armitage illustrates it as a monitor wrapped into thunder lights. Perfect for a hacker movie:D&lt;br /&gt;
&lt;br /&gt;
Here are the materials we had for this training:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;The training slides are available &lt;a href=&quot;http://www.hick.org/~raffi/austin_slides.pptx&quot;&gt;here&lt;/a&gt;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;The exercises sheet is available at &lt;a href=&quot;https://docs.google.com/viewer?a=v&amp;amp;pid=explorer&amp;amp;chrome=true&amp;amp;srcid=0B69eBFipm7NiMWYxNjA4NjEtMTQ5ZC00ZWY5LWJmYjgtOTA3ZTZjZWQ1YWQ3&amp;amp;hl=en_US&quot;&gt;here&lt;/a&gt; &lt;/li&gt;
&lt;li&gt; Metasploit - &lt;a href=&quot;http://www.metasploit.com/download/&quot;&gt;http://www.metasploit.com/download/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Metasploitable - &lt;a href=&quot;http://blog.metasploit.com/2010/05/introducing-metasploitable.html&quot;&gt;http://blog.metasploit.com/2010/05/introducing-metasploitable.html&lt;/a&gt;&amp;nbsp; &lt;/li&gt;
&lt;li&gt;VM Ware player - &lt;a href=&quot;http://www.vmware.com/&quot;&gt;http://www.vmware.com/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;The youtube video below is the screen-cast of the exercises. I show how to setup the lab environment. Then I demonstrate how to use Armitage to find and use an exploit. The video ends with a demonstration of social engineering where the attacker takes full control over the victim&#39;s computer.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;iframe allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;344&quot; src=&quot;http://www.youtube.com/embed/EmDQnavYFgI?fs=1&quot; width=&quot;425&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;br /&gt;
When I first started Armitage, it could not connect to the database. I had to kill all ruby processes and reconnect again.Once Armitage started, you may be asked to enter your IP address. If you dont you can always set it later by running the following command in the console; it will set a global variable. &lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:plain&quot;&gt;setg LHOST 10.10.10.10
&lt;/pre&gt;&lt;br /&gt;
Here are some interesting resources for further reading:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://www.offensive-security.com/metasploit-unleashed/Metasploit_Unleashed_Information_Security_Training&quot;&gt;offensive-security.com&lt;/a&gt; - online courses on Metasploit&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://pentest.cryptocity.net/&quot;&gt;pentest.cryptocity.net&lt;/a&gt; - online courses for Penetration Testing and Vulnerability Analysis currently taught at the Polytechnic Institute of New York University&lt;/li&gt;
&lt;/ul&gt;</content><link rel='replies' type='application/atom+xml' href='http://codebazaar.blogspot.com/feeds/7313617545406155020/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/8927794127513218467/7313617545406155020?isPopup=true' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8927794127513218467/posts/default/7313617545406155020'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8927794127513218467/posts/default/7313617545406155020'/><link rel='alternate' type='text/html' href='http://codebazaar.blogspot.com/2011/06/introduction-to-metasploit-and-armitage.html' title='Introduction to Metasploit and Armitage'/><author><name>Matt Buchner</name><uri>http://www.blogger.com/profile/03993705703169676412</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGJBh157km2WvcRk9Fd0alqVRHYw3pldCvcehZRPx8NXBkVlqWclPGMXjjvP_CKoYtUwPQECmIfijWZo-2-O64i5ogn-LI4qplVUgMixVlbsXwbJgQrwlSr44Wxp3Cr4o/s113/headshot.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipVSJvQSW3yq62kRR2NYVnzCfkdGzI9to_U85BzhjDnLUd2UFefpoOn1EOARaqaSuqFrvpiAyswM96SaUS1lGTfp0o3hLm5YYi_PZlWFPp3i4Y-J2LyudQBYR6WEONlfQK7RcFT7WZL7Z6/s72-c/2011-06-17+16.54.39.jpg" height="72" width="72"/><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8927794127513218467.post-2969295052868542228</id><published>2011-06-01T02:58:00.000+02:00</published><updated>2011-06-01T03:12:10.587+02:00</updated><title type='text'>Visualization of randomness</title><content type='html'>&lt;div id=&quot;fb-root&quot;&gt;&lt;/div&gt;&lt;script src=&quot;http://connect.facebook.net/en_US/all.js#appId=134707656604826&amp;amp;xfbml=1&quot;&gt;&lt;/script&gt;&lt;fb:like href=&quot;http://codebazaar.blogspot.com/2011/05/visualization-of-randomness.html&quot; send=&quot;true&quot; width=&quot;450&quot; show_faces=&quot;true&quot; font=&quot;&quot;&gt;&lt;/fb:like&gt;&lt;br /&gt;
As I was writing a function to generate random values, I realized it is hard to tell if the implemented function truly generates random values. A unit test can validate the length and the format of the generated values, but not its randomness.&lt;br /&gt;
&lt;br /&gt;
To identify potential implementation flaws in my random generator, I developed the following tool.&lt;br /&gt;
&lt;br /&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;https://www.google.com/jsapi&quot;&gt;&lt;/script&gt;&lt;br /&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
//Matthias Buchner 2011
//codebazaar.blogspot.com
var RV_RANGE_MIN = 0;
var RV_RANGE_MAX = 10;
var RV_DEFAULT_VALUES_TO_KEEP = 100;

var rvValuesToKeep = RV_DEFAULT_VALUES_TO_KEEP; //null: keep all values, 100: keep the latest 100 values

var rvLineChart = null;

var rvGoogleDataTable = null;

var RandomData = function() {
 this.randomValues = new Array();
 this.allRandomValues = new Array();
 this.currentValueIndex = 0;
 this.randomGeneratorFunction = null;
 
 this.init = function(rgFunc) {
  this.randomGeneratorFunction = rgFunc;
 
  for (var cnt = RV_RANGE_MIN; cnt &lt; RV_RANGE_MAX; cnt ++) {
   this.randomValues[cnt] = 0;
  }

  for (var cnt = RV_RANGE_MIN; cnt &lt; rvValuesToKeep; cnt ++) {
   var rnd = this.randomGeneratorFunction();
   this.allRandomValues[cnt] = rnd;
   this.randomValues[rnd] ++;
  }
 }
 
 this.storeNextValue = function (value) {
  if (rvValuesToKeep == null) {
   this.randomValues[value] += 1;
  } else {
   if (this.currentValueIndex == rvValuesToKeep) {
    this.currentValueIndex = 0;
   }

   this.allRandomValues[this.currentValueIndex] = value;
   this.currentValueIndex++;

   for (var cnt = RV_RANGE_MIN; cnt &lt; RV_RANGE_MAX; cnt ++) {
    this.randomValues[cnt] = 0;
   }

   for (var cnt = RV_RANGE_MIN; cnt &lt; rvValuesToKeep; cnt ++) {
    this.randomValues[ this.allRandomValues[cnt] ] = this.randomValues[ this.allRandomValues[cnt] ] + 1;
   }
  }
 }

 this.generateNewData = function () {
  this.storeNextValue( this.randomGeneratorFunction() );
 }
}

function randomGeneratorUsingFloor() { 
 return Math.floor( Math.random() * RV_RANGE_MAX ); 
}

function randomGeneratorUsingRound() { 
 return Math.round( Math.random() * (RV_RANGE_MAX - 1) ); 
}

var randomDataImpl1 = new RandomData();
randomDataImpl1.init( randomGeneratorUsingFloor );

var randomDataImpl2 = new RandomData();
randomDataImpl2.init( randomGeneratorUsingRound );

// Load the Visualization API and the piechart package.
google.load(&#39;visualization&#39;, &#39;1&#39;, {&#39;packages&#39;:[&#39;corechart&#39;]});

// Set a callback to run when the Google Visualization API is loaded.
google.setOnLoadCallback(drawVisualization);

function update() {  
   randomDataImpl1.generateNewData();
   randomDataImpl2.generateNewData();
    
   for (var cnt = RV_RANGE_MIN; cnt &lt; RV_RANGE_MAX; cnt ++) {
       rvGoogleDataTable.setValue(cnt , 1, this.randomDataImpl1.randomValues[cnt]);
    rvGoogleDataTable.setValue(cnt , 2, this.randomDataImpl2.randomValues[cnt]);
   }

   draw();
 
   setTimeout( &quot;update()&quot;, 1 ); 
}

function draw() {
    if (rvLineChart == null) {
       var visualizationElement = document.getElementById(&#39;visualization&#39;);
       rvLineChart = new google.visualization.LineChart( visualizationElement );
    }
  
    rvLineChart.draw( rvGoogleDataTable, 
                    { curveType: &quot;function&quot;, 
                      width: 600, 
                      height: 400,
       title: &#39;Visualization Of Randomness&#39;,
       hAxis: { title: &#39;Range Of The Random Values Generated&#39; },
       vAxis: { title: &#39;Number Of Generation&#39; }
                    }
          );
}

function drawVisualization() {
  rvGoogleDataTable = new google.visualization.DataTable();
  
  // Create and populate the rvGoogleDataTable table.
  rvGoogleDataTable.addColumn(&#39;string&#39;, &#39;x&#39;);
  rvGoogleDataTable.addColumn(&#39;number&#39;, &#39;Math.floor&#39;);
  rvGoogleDataTable.addColumn(&#39;number&#39;, &#39;Math.round&#39;);

  for (var cnt = RV_RANGE_MIN; cnt &lt; RV_RANGE_MAX; cnt ++) {
      rvGoogleDataTable.addRow([&quot;&quot; + cnt,  0, 0]);
  }

  // Create and draw the visualization.
  draw();
  update();
}

function startRandomVisualization(keepAllData) {
 if (keepAllData) {
  rvValuesToKeep = null;
 } else {
  rvValuesToKeep = RV_DEFAULT_VALUES_TO_KEEP;
 }
}
&lt;/script&gt;
&lt;div align=&quot;center&quot;&gt;
&lt;input type=radio name=&quot;keepAllData&quot; value=&quot;false&quot; checked=true onClick=&quot;startRandomVisualization(false)&quot;/&gt;Keep Last 100 Random Values
&lt;input type=radio name=&quot;keepAllData&quot; value=&quot;true&quot; onClick=&quot;startRandomVisualization(true)&quot;/&gt;Keep All Random Values 
&lt;div id=&quot;visualization&quot;&gt;
&lt;/div&gt;&lt;/div&gt;The chart above compares 2 random generators. It shows the frequency for each value generated. By default, the chart keeps the last 100 generated values. You can click on the radio button above the chart to keep track of all generated values.
&lt;br&gt;&lt;br&gt;
What I expect to see from a bad random generator is an uneven distribution of the random values.
&lt;br&gt;&lt;br&gt;
In the example above, I am comparing the 2 following JavaScript random generators. They both generate a random value from 0 to 9.
&lt;pre class=&quot;brush:js&quot;&gt;
function randomGeneratorUsingFloor() { 
 return Math.floor( Math.random() * 10 ); 
}

function randomGeneratorUsingRound() { 
 return Math.round( Math.random() * 9 ); 
}
&lt;/pre&gt;Can you spot what is wrong with the second implementation? The numbers 0 and 9 have a smaller chance to be generated compared to the other numbers. If this is not obvious on the chart above, select &quot;Keep All Random Values&quot;, it should reveal the issue as shown in the picture below.
&lt;br&gt;&lt;br&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8Zzr6Zdw_7eZVc1M0ToOqFQVmzeHjAGQI9CpVh_eheS-fciKgAWEF8rteODQlwjpFEopgaiqcg1Tw3WOVdbq_SSkokvVuoY5uefvwdWq39lybBRW7yBZrZjxOklkfMp1Iy15ytCoRuX4E/s1600/random+generator+comparison.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left:1em; margin-right:1em&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;170&quot; width=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8Zzr6Zdw_7eZVc1M0ToOqFQVmzeHjAGQI9CpVh_eheS-fciKgAWEF8rteODQlwjpFEopgaiqcg1Tw3WOVdbq_SSkokvVuoY5uefvwdWq39lybBRW7yBZrZjxOklkfMp1Iy15ytCoRuX4E/s400/random+generator+comparison.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;Math.random() generates a number between 0 and 1. The value generated is then multiplied. In the implementation using Math.floor(), all the values between 0 and 0.99.. will result as a 0. In the implementation using Math.round(), only the values between 0 and 0.49.. will result as a 0.
&lt;br&gt;&lt;br&gt;
It appears that this is a common mistake as you can see it on &lt;a href=&quot;http://www.google.com/codesearch?hl=en&amp;lr=&amp;q=Math\.round\%28\%29+Math\.random\%28\%29&amp;sbtn=Search&quot;&gt;Google Code Hosting&lt;/a&gt; and &lt;a href=&quot;https://github.com/search?type=Code&amp;language=javascript&amp;q=Math.round+Math.random&quot;&gt;GitHub&lt;/a&gt;.
&lt;br&gt;&lt;br&gt;
The test I put in place here is very basic. It exists some advanced work such as the &lt;a href=&quot;http://en.wikipedia.org/wiki/Diehard_tests&quot;&gt;Diehard tests&lt;/a&gt;. I also found a very creative randomness visualization on &lt;a href=&quot;http://www.random-walk.com/index_en.htm&quot;&gt;random-walk.com&lt;/a&gt;.</content><link rel='replies' type='application/atom+xml' href='http://codebazaar.blogspot.com/feeds/2969295052868542228/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/8927794127513218467/2969295052868542228?isPopup=true' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8927794127513218467/posts/default/2969295052868542228'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8927794127513218467/posts/default/2969295052868542228'/><link rel='alternate' type='text/html' href='http://codebazaar.blogspot.com/2011/05/visualization-of-randomness.html' title='Visualization of randomness'/><author><name>Matt Buchner</name><uri>http://www.blogger.com/profile/03993705703169676412</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGJBh157km2WvcRk9Fd0alqVRHYw3pldCvcehZRPx8NXBkVlqWclPGMXjjvP_CKoYtUwPQECmIfijWZo-2-O64i5ogn-LI4qplVUgMixVlbsXwbJgQrwlSr44Wxp3Cr4o/s113/headshot.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8Zzr6Zdw_7eZVc1M0ToOqFQVmzeHjAGQI9CpVh_eheS-fciKgAWEF8rteODQlwjpFEopgaiqcg1Tw3WOVdbq_SSkokvVuoY5uefvwdWq39lybBRW7yBZrZjxOklkfMp1Iy15ytCoRuX4E/s72-c/random+generator+comparison.png" height="72" width="72"/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8927794127513218467.post-1115448689832365227</id><published>2011-05-03T06:46:00.000+02:00</published><updated>2011-05-05T02:57:55.290+02:00</updated><title type='text'>Why we need strong p4ssw0rds</title><content type='html'>&lt;div id=&quot;fb-root&quot;&gt;&lt;/div&gt;&lt;script src=&quot;http://connect.facebook.net/en_US/all.js#xfbml=1&quot;&gt;&lt;/script&gt;&lt;fb:like href=&quot;http://codebazaar.blogspot.com/2011/05/why-we-need-strong-p4ssw0rds.html&quot; send=&quot;true&quot; width=&quot;450&quot; show_faces=&quot;true&quot; font=&quot;&quot;&gt;&lt;/fb:like&gt;&lt;br /&gt;
Back in February 2011, Rick Redman from Korelogic came to present his &lt;a href=&quot;https://www.owasp.org/images/a/af/2011-Supercharged-Slides-Redman-OWASP-Feb.pdf&quot;&gt;Supercharged Password Cracking Techniques&lt;/a&gt; at the &lt;a href=&quot;http://www.owasp.org/index.php/Austin&quot;&gt;Austin OWASP chapter&lt;/a&gt; monthly meeting.&lt;br /&gt;
&lt;br /&gt;
With these techniques, he was able to crack large password database in a very short time using a tool called &lt;a href=&quot;http://www.openwall.com/john/&quot;&gt;John The Ripper&lt;/a&gt;. In this article, I want to present what are these techniques and what we can do to secure our identities online.&lt;br /&gt;
&lt;br /&gt;
In December 2010, the media group Gawker (Gizmodo.com, Lifehacker.com) &lt;a href=&quot;http://www.google.com/search?q=gawker+site%3Ainfosecnews.org&quot;&gt;was attacked&lt;/a&gt; and their 750,000-password database was stolen. The passwords were encrypted with the algorithm DES, but it did not prevent them from being cracked. More recently, the &lt;a href=&quot;http://www.wired.com/threatlevel/2011/04/sony-says-playstation-credit-cards-were-encrypted/&quot;&gt;Sony&#39;s Playstation Network was also being attacked&lt;/a&gt;. More than 75 million passwords, emails, credit card numbers and other personal data have been compromised.&lt;br /&gt;
&lt;br /&gt;
&lt;table&gt;&lt;tr&gt; &lt;td&gt; &lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8GJf7B1FMfekErk2GxRoCYTMC49wOWL_v98jyKv8VBO2mY4g-F9Taa3x4VWFvZp2RWubSg16JOkNPL5ZCH7TxQYNmPNcdBNVEYvKWkLL7KAM5BaMIwz0aY3HbNABGT1ijWaW43RZgFZT1/s1600/gawker-top-250.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;231&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8GJf7B1FMfekErk2GxRoCYTMC49wOWL_v98jyKv8VBO2mY4g-F9Taa3x4VWFvZp2RWubSg16JOkNPL5ZCH7TxQYNmPNcdBNVEYvKWkLL7KAM5BaMIwz0aY3HbNABGT1ijWaW43RZgFZT1/s320/gawker-top-250.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;  &lt;script type=&quot;text/javascript&quot; &gt;
//mootools
var MooTools={version:&quot;1.2.1&quot;,build:&quot;0d4845aab3d9a4fdee2f0d4a6dd59210e4b697cf&quot;};var Native=function(k){k=k||{};var a=k.name;var i=k.legacy;var b=k.protect;var c=k.implement;var h=k.generics;var f=k.initialize;var g=k.afterImplement||function(){};var d=f||i;h=h!==false;d.constructor=Native;d.$family={name:&quot;native&quot;};if(i&amp;&amp;f){d.prototype=i.prototype}d.prototype.constructor=d;if(a){var e=a.toLowerCase();d.prototype.$family={name:e};Native.typize(d,e)}var j=function(n,l,o,m){if(!b||m||!n.prototype[l]){n.prototype[l]=o}if(h){Native.genericize(n,l,b)}g.call(n,l,o);return n};d.alias=function(n,l,o){if(typeof n==&quot;string&quot;){if((n=this.prototype[n])){return j(this,l,n,o)}}for(var m in n){this.alias(m,n[m],l)}return this};d.implement=function(m,l,o){if(typeof m==&quot;string&quot;){return j(this,m,l,o)}for(var n in m){j(this,n,m[n],l)}return this};if(c){d.implement(c)}return d};Native.genericize=function(b,c,a){if((!a||!b[c])&amp;&amp;typeof b.prototype[c]==&quot;function&quot;){b[c]=function(){var d=Array.prototype.slice.call(arguments);return b.prototype[c].apply(d.shift(),d)}}};Native.implement=function(d,c){for(var b=0,a=d.length;b&lt;a;b++){d[b].implement(c)}};Native.typize=function(a,b){if(!a.type){a.type=function(c){return($type(c)===b)}}};(function(){var a={Array:Array,Date:Date,Function:Function,Number:Number,RegExp:RegExp,String:String};for(var h in a){new Native({name:h,initialize:a[h],protect:true})}var d={&quot;boolean&quot;:Boolean,&quot;native&quot;:Native,object:Object};for(var c in d){Native.typize(d[c],c)}var f={Array:[&quot;concat&quot;,&quot;indexOf&quot;,&quot;join&quot;,&quot;lastIndexOf&quot;,&quot;pop&quot;,&quot;push&quot;,&quot;reverse&quot;,&quot;shift&quot;,&quot;slice&quot;,&quot;sort&quot;,&quot;splice&quot;,&quot;toString&quot;,&quot;unshift&quot;,&quot;valueOf&quot;],String:[&quot;charAt&quot;,&quot;charCodeAt&quot;,&quot;concat&quot;,&quot;indexOf&quot;,&quot;lastIndexOf&quot;,&quot;match&quot;,&quot;replace&quot;,&quot;search&quot;,&quot;slice&quot;,&quot;split&quot;,&quot;substr&quot;,&quot;substring&quot;,&quot;toLowerCase&quot;,&quot;toUpperCase&quot;,&quot;valueOf&quot;]};for(var e in f){for(var b=f[e].length;b--;){Native.genericize(window[e],f[e][b],true)}}})();var Hash=new Native({name:&quot;Hash&quot;,initialize:function(a){if($type(a)==&quot;hash&quot;){a=$unlink(a.getClean())}for(var b in a){this[b]=a[b]}return this}});Hash.implement({forEach:function(b,c){for(var a in this){if(this.hasOwnProperty(a)){b.call(c,this[a],a,this)}}},getClean:function(){var b={};for(var a in this){if(this.hasOwnProperty(a)){b[a]=this[a]}}return b},getLength:function(){var b=0;for(var a in this){if(this.hasOwnProperty(a)){b++}}return b}});Hash.alias(&quot;forEach&quot;,&quot;each&quot;);Array.implement({forEach:function(c,d){for(var b=0,a=this.length;b&lt;a;b++){c.call(d,this[b],b,this)}}});Array.alias(&quot;forEach&quot;,&quot;each&quot;);function $A(c){if(c.item){var d=[];for(var b=0,a=c.length;b&lt;a;b++){d[b]=c[b]}return d}return Array.prototype.slice.call(c)}function $arguments(a){return function(){return arguments[a]}}function $chk(a){return !!(a||a===0)}function $clear(a){clearTimeout(a);clearInterval(a);return null}function $defined(a){return(a!=undefined)}function $each(c,b,d){var a=$type(c);((a==&quot;arguments&quot;||a==&quot;collection&quot;||a==&quot;array&quot;)?Array:Hash).each(c,b,d)}function $empty(){}function $extend(c,a){for(var b in (a||{})){c[b]=a[b]}return c}function $H(a){return new Hash(a)}function $lambda(a){return(typeof a==&quot;function&quot;)?a:function(){return a}}function $merge(){var e={};for(var d=0,a=arguments.length;d&lt;a;d++){var b=arguments[d];if($type(b)!=&quot;object&quot;){continue}for(var c in b){var g=b[c],f=e[c];e[c]=(f&amp;&amp;$type(g)==&quot;object&quot;&amp;&amp;$type(f)==&quot;object&quot;)?$merge(f,g):$unlink(g)}}return e}function $pick(){for(var b=0,a=arguments.length;b&lt;a;b++){if(arguments[b]!=undefined){return arguments[b]}}return null}function $random(b,a){return Math.floor(Math.random()*(a-b+1)+b)}function $splat(b){var a=$type(b);return(a)?((a!=&quot;array&quot;&amp;&amp;a!=&quot;arguments&quot;)?[b]:b):[]}var $time=Date.now||function(){return +new Date};function $try(){for(var b=0,a=arguments.length;b&lt;a;b++){try{return arguments[b]()}catch(c){}}return null}function $type(a){if(a==undefined){return false}if(a.$family){return(a.$family.name==&quot;number&quot;&amp;&amp;!isFinite(a))?false:a.$family.name}if(a.nodeName){switch(a.nodeType){case 1:return&quot;element&quot;;case 3:return(/\S/).test(a.nodeValue)?&quot;textnode&quot;:&quot;whitespace&quot;}}else{if(typeof a.length==&quot;number&quot;){if(a.callee){return&quot;arguments&quot;}else{if(a.item){return&quot;collection&quot;}}}}return typeof a}function $unlink(c){var b;switch($type(c)){case&quot;object&quot;:b={};for(var e in c){b[e]=$unlink(c[e])}break;case&quot;hash&quot;:b=new Hash(c);break;case&quot;array&quot;:b=[];for(var d=0,a=c.length;d&lt;a;d++){b[d]=$unlink(c[d])}break;default:return c}return b}var Browser=$merge({Engine:{name:&quot;unknown&quot;,version:0},Platform:{name:(window.orientation!=undefined)?&quot;ipod&quot;:(navigator.platform.match(/mac|win|linux/i)||[&quot;other&quot;])[0].toLowerCase()},Features:{xpath:!!(document.evaluate),air:!!(window.runtime),query:!!(document.querySelector)},Plugins:{},Engines:{presto:function(){return(!window.opera)?false:((arguments.callee.caller)?960:((document.getElementsByClassName)?950:925))},trident:function(){return(!window.ActiveXObject)?false:((window.XMLHttpRequest)?5:4)},webkit:function(){return(navigator.taintEnabled)?false:((Browser.Features.xpath)?((Browser.Features.query)?525:420):419)},gecko:function(){return(document.getBoxObjectFor==undefined)?false:((document.getElementsByClassName)?19:18)}}},Browser||{});Browser.Platform[Browser.Platform.name]=true;Browser.detect=function(){for(var b in this.Engines){var a=this.Engines[b]();if(a){this.Engine={name:b,version:a};this.Engine[b]=this.Engine[b+a]=true;break}}return{name:b,version:a}};Browser.detect();Browser.Request=function(){return $try(function(){return new XMLHttpRequest()},function(){return new ActiveXObject(&quot;MSXML2.XMLHTTP&quot;)})};Browser.Features.xhr=!!(Browser.Request());Browser.Plugins.Flash=(function(){var a=($try(function(){return navigator.plugins[&quot;Shockwave Flash&quot;].description},function(){return new ActiveXObject(&quot;ShockwaveFlash.ShockwaveFlash&quot;).GetVariable(&quot;$version&quot;)})||&quot;0 r0&quot;).match(/\d+/g);return{version:parseInt(a[0]||0+&quot;.&quot;+a[1]||0),build:parseInt(a[2]||0)}})();function $exec(b){if(!b){return b}if(window.execScript){window.execScript(b)}else{var a=document.createElement(&quot;script&quot;);a.setAttribute(&quot;type&quot;,&quot;text/javascript&quot;);a[(Browser.Engine.webkit&amp;&amp;Browser.Engine.version&lt;420)?&quot;innerText&quot;:&quot;text&quot;]=b;document.head.appendChild(a);document.head.removeChild(a)}return b}Native.UID=1;var $uid=(Browser.Engine.trident)?function(a){return(a.uid||(a.uid=[Native.UID++]))[0]}:function(a){return a.uid||(a.uid=Native.UID++)};var Window=new Native({name:&quot;Window&quot;,legacy:(Browser.Engine.trident)?null:window.Window,initialize:function(a){$uid(a);if(!a.Element){a.Element=$empty;if(Browser.Engine.webkit){a.document.createElement(&quot;iframe&quot;)}a.Element.prototype=(Browser.Engine.webkit)?window[&quot;[[DOMElement.prototype]]&quot;]:{}}a.document.window=a;return $extend(a,Window.Prototype)},afterImplement:function(b,a){window[b]=Window.Prototype[b]=a}});Window.Prototype={$family:{name:&quot;window&quot;}};new Window(window);var Document=new Native({name:&quot;Document&quot;,legacy:(Browser.Engine.trident)?null:window.Document,initialize:function(a){$uid(a);a.head=a.getElementsByTagName(&quot;head&quot;)[0];a.html=a.getElementsByTagName(&quot;html&quot;)[0];if(Browser.Engine.trident&amp;&amp;Browser.Engine.version&lt;=4){$try(function(){a.execCommand(&quot;BackgroundImageCache&quot;,false,true)})}if(Browser.Engine.trident){a.window.attachEvent(&quot;onunload&quot;,function(){a.window.detachEvent(&quot;onunload&quot;,arguments.callee);a.head=a.html=a.window=null})}return $extend(a,Document.Prototype)},afterImplement:function(b,a){document[b]=Document.Prototype[b]=a}});Document.Prototype={$family:{name:&quot;document&quot;}};new Document(document);Array.implement({every:function(c,d){for(var b=0,a=this.length;b&lt;a;b++){if(!c.call(d,this[b],b,this)){return false}}return true},filter:function(d,e){var c=[];for(var b=0,a=this.length;b&lt;a;b++){if(d.call(e,this[b],b,this)){c.push(this[b])}}return c},clean:function(){return this.filter($defined)},indexOf:function(c,d){var a=this.length;for(var b=(d&lt;0)?Math.max(0,a+d):d||0;b&lt;a;b++){if(this[b]===c){return b}}return -1},map:function(d,e){var c=[];for(var b=0,a=this.length;b&lt;a;b++){c[b]=d.call(e,this[b],b,this)}return c},some:function(c,d){for(var b=0,a=this.length;b&lt;a;b++){if(c.call(d,this[b],b,this)){return true}}return false},associate:function(c){var d={},b=Math.min(this.length,c.length);for(var a=0;a&lt;b;a++){d[c[a]]=this[a]}return d},link:function(c){var a={};for(var e=0,b=this.length;e&lt;b;e++){for(var d in c){if(c[d](this[e])){a[d]=this[e];delete c[d];break}}}return a},contains:function(a,b){return this.indexOf(a,b)!=-1},extend:function(c){for(var b=0,a=c.length;b&lt;a;b++){this.push(c[b])}return this},getLast:function(){return(this.length)?this[this.length-1]:null},getRandom:function(){return(this.length)?this[$random(0,this.length-1)]:null},include:function(a){if(!this.contains(a)){this.push(a)}return this},combine:function(c){for(var b=0,a=c.length;b&lt;a;b++){this.include(c[b])}return this},erase:function(b){for(var a=this.length;a--;a){if(this[a]===b){this.splice(a,1)}}return this},empty:function(){this.length=0;return this},flatten:function(){var d=[];for(var b=0,a=this.length;b&lt;a;b++){var c=$type(this[b]);if(!c){continue}d=d.concat((c==&quot;array&quot;||c==&quot;collection&quot;||c==&quot;arguments&quot;)?Array.flatten(this[b]):this[b])}return d},hexToRgb:function(b){if(this.length!=3){return null}var a=this.map(function(c){if(c.length==1){c+=c}return c.toInt(16)});return(b)?a:&quot;rgb(&quot;+a+&quot;)&quot;},rgbToHex:function(d){if(this.length&lt;3){return null}if(this.length==4&amp;&amp;this[3]==0&amp;&amp;!d){return&quot;transparent&quot;}var b=[];for(var a=0;a&lt;3;a++){var c=(this[a]-0).toString(16);b.push((c.length==1)?&quot;0&quot;+c:c)}return(d)?b:&quot;#&quot;+b.join(&quot;&quot;)}});Function.implement({extend:function(a){for(var b in a){this[b]=a[b]}return this},create:function(b){var a=this;b=b||{};return function(d){var c=b.arguments;c=(c!=undefined)?$splat(c):Array.slice(arguments,(b.event)?1:0);if(b.event){c=[d||window.event].extend(c)}var e=function(){return a.apply(b.bind||null,c)};if(b.delay){return setTimeout(e,b.delay)}if(b.periodical){return setInterval(e,b.periodical)}if(b.attempt){return $try(e)}return e()}},run:function(a,b){return this.apply(b,$splat(a))},pass:function(a,b){return this.create({bind:b,arguments:a})},bind:function(b,a){return this.create({bind:b,arguments:a})},bindWithEvent:function(b,a){return this.create({bind:b,arguments:a,event:true})},attempt:function(a,b){return this.create({bind:b,arguments:a,attempt:true})()},delay:function(b,c,a){return this.create({bind:c,arguments:a,delay:b})()},periodical:function(c,b,a){return this.create({bind:b,arguments:a,periodical:c})()}});Number.implement({limit:function(b,a){return Math.min(a,Math.max(b,this))},round:function(a){a=Math.pow(10,a||0);return Math.round(this*a)/a},times:function(b,c){for(var a=0;a&lt;this;a++){b.call(c,a,this)}},toFloat:function(){return parseFloat(this)},toInt:function(a){return parseInt(this,a||10)}});Number.alias(&quot;times&quot;,&quot;each&quot;);(function(b){var a={};b.each(function(c){if(!Number[c]){a[c]=function(){return Math[c].apply(null,[this].concat($A(arguments)))}}});Number.implement(a)})([&quot;abs&quot;,&quot;acos&quot;,&quot;asin&quot;,&quot;atan&quot;,&quot;atan2&quot;,&quot;ceil&quot;,&quot;cos&quot;,&quot;exp&quot;,&quot;floor&quot;,&quot;log&quot;,&quot;max&quot;,&quot;min&quot;,&quot;pow&quot;,&quot;sin&quot;,&quot;sqrt&quot;,&quot;tan&quot;]);String.implement({test:function(a,b){return((typeof a==&quot;string&quot;)?new RegExp(a,b):a).test(this)},contains:function(a,b){return(b)?(b+this+b).indexOf(b+a+b)&gt;-1:this.indexOf(a)&gt;-1},trim:function(){return this.replace(/^\s+|\s+$/g,&quot;&quot;)},clean:function(){return this.replace(/\s+/g,&quot; &quot;).trim()},camelCase:function(){return this.replace(/-\D/g,function(a){return a.charAt(1).toUpperCase()})},hyphenate:function(){return this.replace(/[A-Z]/g,function(a){return(&quot;-&quot;+a.charAt(0).toLowerCase())})},capitalize:function(){return this.replace(/\b[a-z]/g,function(a){return a.toUpperCase()})},escapeRegExp:function(){return this.replace(/([-.*+?^${}()|[\]\/\\])/g,&quot;\\$1&quot;)},toInt:function(a){return parseInt(this,a||10)},toFloat:function(){return parseFloat(this)},hexToRgb:function(b){var a=this.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);return(a)?a.slice(1).hexToRgb(b):null},rgbToHex:function(b){var a=this.match(/\d{1,3}/g);return(a)?a.rgbToHex(b):null},stripScripts:function(b){var a=&quot;&quot;;var c=this.replace(/&lt;script[^&gt;]*&gt;([\s\S]*?)&lt;\/script&gt;/gi,function(){a+=arguments[1]+&quot;\n&quot;;return&quot;&quot;});if(b===true){$exec(a)}else{if($type(b)==&quot;function&quot;){b(a,c)}}return c},substitute:function(a,b){return this.replace(b||(/\\?\{([^{}]+)\}/g),function(d,c){if(d.charAt(0)==&quot;\\&quot;){return d.slice(1)}return(a[c]!=undefined)?a[c]:&quot;&quot;})}});Hash.implement({has:Object.prototype.hasOwnProperty,keyOf:function(b){for(var a in this){if(this.hasOwnProperty(a)&amp;&amp;this[a]===b){return a}}return null},hasValue:function(a){return(Hash.keyOf(this,a)!==null)},extend:function(a){Hash.each(a,function(c,b){Hash.set(this,b,c)},this);return this},combine:function(a){Hash.each(a,function(c,b){Hash.include(this,b,c)},this);return this},erase:function(a){if(this.hasOwnProperty(a)){delete this[a]}return this},get:function(a){return(this.hasOwnProperty(a))?this[a]:null},set:function(a,b){if(!this[a]||this.hasOwnProperty(a)){this[a]=b}return this},empty:function(){Hash.each(this,function(b,a){delete this[a]},this);return this},include:function(b,c){var a=this[b];if(a==undefined){this[b]=c}return this},map:function(b,c){var a=new Hash;Hash.each(this,function(e,d){a.set(d,b.call(c,e,d,this))},this);return a},filter:function(b,c){var a=new Hash;Hash.each(this,function(e,d){if(b.call(c,e,d,this)){a.set(d,e)}},this);return a},every:function(b,c){for(var a in this){if(this.hasOwnProperty(a)&amp;&amp;!b.call(c,this[a],a)){return false}}return true},some:function(b,c){for(var a in this){if(this.hasOwnProperty(a)&amp;&amp;b.call(c,this[a],a)){return true}}return false},getKeys:function(){var a=[];Hash.each(this,function(c,b){a.push(b)});return a},getValues:function(){var a=[];Hash.each(this,function(b){a.push(b)});return a},toQueryString:function(a){var b=[];Hash.each(this,function(f,e){if(a){e=a+&quot;[&quot;+e+&quot;]&quot;}var d;switch($type(f)){case&quot;object&quot;:d=Hash.toQueryString(f,e);break;case&quot;array&quot;:var c={};f.each(function(h,g){c[g]=h});d=Hash.toQueryString(c,e);break;default:d=e+&quot;=&quot;+encodeURIComponent(f)}if(f!=undefined){b.push(d)}});return b.join(&quot;&amp;&quot;)}});Hash.alias({keyOf:&quot;indexOf&quot;,hasValue:&quot;contains&quot;});var Event=new Native({name:&quot;Event&quot;,initialize:function(a,f){f=f||window;var k=f.document;a=a||f.event;if(a.$extended){return a}this.$extended=true;var j=a.type;var g=a.target||a.srcElement;while(g&amp;&amp;g.nodeType==3){g=g.parentNode}if(j.test(/key/)){var b=a.which||a.keyCode;var m=Event.Keys.keyOf(b);if(j==&quot;keydown&quot;){var d=b-111;if(d&gt;0&amp;&amp;d&lt;13){m=&quot;f&quot;+d}}m=m||String.fromCharCode(b).toLowerCase()}else{if(j.match(/(click|mouse|menu)/i)){k=(!k.compatMode||k.compatMode==&quot;CSS1Compat&quot;)?k.html:k.body;var i={x:a.pageX||a.clientX+k.scrollLeft,y:a.pageY||a.clientY+k.scrollTop};var c={x:(a.pageX)?a.pageX-f.pageXOffset:a.clientX,y:(a.pageY)?a.pageY-f.pageYOffset:a.clientY};if(j.match(/DOMMouseScroll|mousewheel/)){var h=(a.wheelDelta)?a.wheelDelta/120:-(a.detail||0)/3}var e=(a.which==3)||(a.button==2);var l=null;if(j.match(/over|out/)){switch(j){case&quot;mouseover&quot;:l=a.relatedTarget||a.fromElement;break;case&quot;mouseout&quot;:l=a.relatedTarget||a.toElement}if(!(function(){while(l&amp;&amp;l.nodeType==3){l=l.parentNode}return true}).create({attempt:Browser.Engine.gecko})()){l=false}}}}return $extend(this,{event:a,type:j,page:i,client:c,rightClick:e,wheel:h,relatedTarget:l,target:g,code:b,key:m,shift:a.shiftKey,control:a.ctrlKey,alt:a.altKey,meta:a.metaKey})}});Event.Keys=new Hash({enter:13,up:38,down:40,left:37,right:39,esc:27,space:32,backspace:8,tab:9,&quot;delete&quot;:46});Event.implement({stop:function(){return this.stopPropagation().preventDefault()},stopPropagation:function(){if(this.event.stopPropagation){this.event.stopPropagation()}else{this.event.cancelBubble=true}return this},preventDefault:function(){if(this.event.preventDefault){this.event.preventDefault()}else{this.event.returnValue=false}return this}});var Class=new Native({name:&quot;Class&quot;,initialize:function(b){b=b||{};var a=function(){for(var e in this){if($type(this[e])!=&quot;function&quot;){this[e]=$unlink(this[e])}}this.constructor=a;if(Class.prototyping){return this}var d=(this.initialize)?this.initialize.apply(this,arguments):this;if(this.options&amp;&amp;this.options.initialize){this.options.initialize.call(this)}return d};for(var c in Class.Mutators){if(!b[c]){continue}b=Class.Mutators[c](b,b[c]);delete b[c]}$extend(a,this);a.constructor=Class;a.prototype=b;return a}});Class.Mutators={Extends:function(c,a){Class.prototyping=a.prototype;var b=new a;delete b.parent;b=Class.inherit(b,c);delete Class.prototyping;return b},Implements:function(a,b){$splat(b).each(function(c){Class.prototying=c;$extend(a,($type(c)==&quot;class&quot;)?new c:c);delete Class.prototyping});return a}};Class.extend({inherit:function(b,e){var a=arguments.callee.caller;for(var d in e){var c=e[d];var g=b[d];var f=$type(c);if(g&amp;&amp;f==&quot;function&quot;){if(c!=g){if(a){c.__parent=g;b[d]=c}else{Class.override(b,d,c)}}}else{if(f==&quot;object&quot;){b[d]=$merge(g,c)}else{b[d]=c}}}if(a){b.parent=function(){return arguments.callee.caller.__parent.apply(this,arguments)}}return b},override:function(b,a,e){var d=Class.prototyping;if(d&amp;&amp;b[a]!=d[a]){d=null}var c=function(){var f=this.parent;this.parent=d?d[a]:b[a];var g=e.apply(this,arguments);this.parent=f;return g};b[a]=c}});Class.implement({implement:function(){var a=this.prototype;$each(arguments,function(b){Class.inherit(a,b)});return this}});var Chain=new Class({$chain:[],chain:function(){this.$chain.extend(Array.flatten(arguments));return this},callChain:function(){return(this.$chain.length)?this.$chain.shift().apply(this,arguments):false},clearChain:function(){this.$chain.empty();return this}});var Events=new Class({$events:{},addEvent:function(c,b,a){c=Events.removeOn(c);if(b!=$empty){this.$events[c]=this.$events[c]||[];this.$events[c].include(b);if(a){b.internal=true}}return this},addEvents:function(a){for(var b in a){this.addEvent(b,a[b])}return this},fireEvent:function(c,b,a){c=Events.removeOn(c);if(!this.$events||!this.$events[c]){return this}this.$events[c].each(function(d){d.create({bind:this,delay:a,&quot;arguments&quot;:b})()},this);return this},removeEvent:function(b,a){b=Events.removeOn(b);if(!this.$events[b]){return this}if(!a.internal){this.$events[b].erase(a)}return this},removeEvents:function(c){if($type(c)==&quot;object&quot;){for(var d in c){this.removeEvent(d,c[d])}return this}if(c){c=Events.removeOn(c)}for(var d in this.$events){if(c&amp;&amp;c!=d){continue}var b=this.$events[d];for(var a=b.length;a--;a){this.removeEvent(d,b[a])}}return this}});Events.removeOn=function(a){return a.replace(/^on([A-Z])/,function(b,c){return c.toLowerCase()})};var Options=new Class({setOptions:function(){this.options=$merge.run([this.options].extend(arguments));if(!this.addEvent){return this}for(var a in this.options){if($type(this.options[a])!=&quot;function&quot;||!(/^on[A-Z]/).test(a)){continue}this.addEvent(a,this.options[a]);delete this.options[a]}return this}});var Element=new Native({name:&quot;Element&quot;,legacy:window.Element,initialize:function(a,b){var c=Element.Constructors.get(a);if(c){return c(b)}if(typeof a==&quot;string&quot;){return document.newElement(a,b)}return $(a).set(b)},afterImplement:function(a,b){Element.Prototype[a]=b;if(Array[a]){return}Elements.implement(a,function(){var c=[],g=true;for(var e=0,d=this.length;e&lt;d;e++){var f=this[e][a].apply(this[e],arguments);c.push(f);if(g){g=($type(f)==&quot;element&quot;)}}return(g)?new Elements(c):c})}});Element.Prototype={$family:{name:&quot;element&quot;}};Element.Constructors=new Hash;var IFrame=new Native({name:&quot;IFrame&quot;,generics:false,initialize:function(){var e=Array.link(arguments,{properties:Object.type,iframe:$defined});var c=e.properties||{};var b=$(e.iframe)||false;var d=c.onload||$empty;delete c.onload;c.id=c.name=$pick(c.id,c.name,b.id,b.name,&quot;IFrame_&quot;+$time());b=new Element(b||&quot;iframe&quot;,c);var a=function(){var f=$try(function(){return b.contentWindow.location.host});if(f&amp;&amp;f==window.location.host){var g=new Window(b.contentWindow);new Document(b.contentWindow.document);$extend(g.Element.prototype,Element.Prototype)}d.call(b.contentWindow,b.contentWindow.document)};(window.frames[c.id])?a():b.addListener(&quot;load&quot;,a);return b}});var Elements=new Native({initialize:function(f,b){b=$extend({ddup:true,cash:true},b);f=f||[];if(b.ddup||b.cash){var g={},e=[];for(var c=0,a=f.length;c&lt;a;c++){var d=$.element(f[c],!b.cash);if(b.ddup){if(g[d.uid]){continue}g[d.uid]=true}e.push(d)}f=e}return(b.cash)?$extend(f,this):f}});Elements.implement({filter:function(a,b){if(!a){return this}return new Elements(Array.filter(this,(typeof a==&quot;string&quot;)?function(c){return c.match(a)}:a,b))}});Document.implement({newElement:function(a,b){if(Browser.Engine.trident&amp;&amp;b){[&quot;name&quot;,&quot;type&quot;,&quot;checked&quot;].each(function(c){if(!b[c]){return}a+=&quot; &quot;+c+&#39;=&quot;&#39;+b[c]+&#39;&quot;&#39;;if(c!=&quot;checked&quot;){delete b[c]}});a=&quot;&lt;&quot;+a+&quot;&gt;&quot;}return $.element(this.createElement(a)).set(b)},newTextNode:function(a){return this.createTextNode(a)},getDocument:function(){return this},getWindow:function(){return this.window}});Window.implement({$:function(b,c){if(b&amp;&amp;b.$family&amp;&amp;b.uid){return b}var a=$type(b);return($[a])?$[a](b,c,this.document):null},$$:function(a){if(arguments.length==1&amp;&amp;typeof a==&quot;string&quot;){return this.document.getElements(a)}var f=[];var c=Array.flatten(arguments);for(var d=0,b=c.length;d&lt;b;d++){var e=c[d];switch($type(e)){case&quot;element&quot;:f.push(e);break;case&quot;string&quot;:f.extend(this.document.getElements(e,true))}}return new Elements(f)},getDocument:function(){return this.document},getWindow:function(){return this}});$.string=function(c,b,a){c=a.getElementById(c);return(c)?$.element(c,b):null};$.element=function(a,d){$uid(a);if(!d&amp;&amp;!a.$family&amp;&amp;!(/^object|embed$/i).test(a.tagName)){var b=Element.Prototype;for(var c in b){a[c]=b[c]}}return a};$.object=function(b,c,a){if(b.toElement){return $.element(b.toElement(a),c)}return null};$.textnode=$.whitespace=$.window=$.document=$arguments(0);Native.implement([Element,Document],{getElement:function(a,b){return $(this.getElements(a,true)[0]||null,b)},getElements:function(a,d){a=a.split(&quot;,&quot;);var c=[];var b=(a.length&gt;1);a.each(function(e){var f=this.getElementsByTagName(e.trim());(b)?c.extend(f):c=f},this);return new Elements(c,{ddup:b,cash:!d})}});(function(){var h={},f={};var i={input:&quot;checked&quot;,option:&quot;selected&quot;,textarea:(Browser.Engine.webkit&amp;&amp;Browser.Engine.version&lt;420)?&quot;innerHTML&quot;:&quot;value&quot;};var c=function(l){return(f[l]||(f[l]={}))};var g=function(n,l){if(!n){return}var m=n.uid;if(Browser.Engine.trident){if(n.clearAttributes){var q=l&amp;&amp;n.cloneNode(false);n.clearAttributes();if(q){n.mergeAttributes(q)}}else{if(n.removeEvents){n.removeEvents()}}if((/object/i).test(n.tagName)){for(var o in n){if(typeof n[o]==&quot;function&quot;){n[o]=$empty}}Element.dispose(n)}}if(!m){return}h[m]=f[m]=null};var d=function(){Hash.each(h,g);if(Browser.Engine.trident){$A(document.getElementsByTagName(&quot;object&quot;)).each(g)}if(window.CollectGarbage){CollectGarbage()}h=f=null};var j=function(n,l,s,m,p,r){var o=n[s||l];var q=[];while(o){if(o.nodeType==1&amp;&amp;(!m||Element.match(o,m))){if(!p){return $(o,r)}q.push(o)}o=o[l]}return(p)?new Elements(q,{ddup:false,cash:!r}):null};var e={html:&quot;innerHTML&quot;,&quot;class&quot;:&quot;className&quot;,&quot;for&quot;:&quot;htmlFor&quot;,text:(Browser.Engine.trident||(Browser.Engine.webkit&amp;&amp;Browser.Engine.version&lt;420))?&quot;innerText&quot;:&quot;textContent&quot;};var b=[&quot;compact&quot;,&quot;nowrap&quot;,&quot;ismap&quot;,&quot;declare&quot;,&quot;noshade&quot;,&quot;checked&quot;,&quot;disabled&quot;,&quot;readonly&quot;,&quot;multiple&quot;,&quot;selected&quot;,&quot;noresize&quot;,&quot;defer&quot;];var k=[&quot;value&quot;,&quot;accessKey&quot;,&quot;cellPadding&quot;,&quot;cellSpacing&quot;,&quot;colSpan&quot;,&quot;frameBorder&quot;,&quot;maxLength&quot;,&quot;readOnly&quot;,&quot;rowSpan&quot;,&quot;tabIndex&quot;,&quot;useMap&quot;];Hash.extend(e,b.associate(b));Hash.extend(e,k.associate(k.map(String.toLowerCase)));var a={before:function(m,l){if(l.parentNode){l.parentNode.insertBefore(m,l)}},after:function(m,l){if(!l.parentNode){return}var n=l.nextSibling;(n)?l.parentNode.insertBefore(m,n):l.parentNode.appendChild(m)},bottom:function(m,l){l.appendChild(m)},top:function(m,l){var n=l.firstChild;(n)?l.insertBefore(m,n):l.appendChild(m)}};a.inside=a.bottom;Hash.each(a,function(l,m){m=m.capitalize();Element.implement(&quot;inject&quot;+m,function(n){l(this,$(n,true));return this});Element.implement(&quot;grab&quot;+m,function(n){l($(n,true),this);return this})});Element.implement({set:function(o,m){switch($type(o)){case&quot;object&quot;:for(var n in o){this.set(n,o[n])}break;case&quot;string&quot;:var l=Element.Properties.get(o);(l&amp;&amp;l.set)?l.set.apply(this,Array.slice(arguments,1)):this.setProperty(o,m)}return this},get:function(m){var l=Element.Properties.get(m);return(l&amp;&amp;l.get)?l.get.apply(this,Array.slice(arguments,1)):this.getProperty(m)},erase:function(m){var l=Element.Properties.get(m);(l&amp;&amp;l.erase)?l.erase.apply(this):this.removeProperty(m);return this},setProperty:function(m,n){var l=e[m];if(n==undefined){return this.removeProperty(m)}if(l&amp;&amp;b[m]){n=!!n}(l)?this[l]=n:this.setAttribute(m,&quot;&quot;+n);return this},setProperties:function(l){for(var m in l){this.setProperty(m,l[m])}return this},getProperty:function(m){var l=e[m];var n=(l)?this[l]:this.getAttribute(m,2);return(b[m])?!!n:(l)?n:n||null},getProperties:function(){var l=$A(arguments);return l.map(this.getProperty,this).associate(l)},removeProperty:function(m){var l=e[m];(l)?this[l]=(l&amp;&amp;b[m])?false:&quot;&quot;:this.removeAttribute(m);return this},removeProperties:function(){Array.each(arguments,this.removeProperty,this);return this},hasClass:function(l){return this.className.contains(l,&quot; &quot;)},addClass:function(l){if(!this.hasClass(l)){this.className=(this.className+&quot; &quot;+l).clean()}return this},removeClass:function(l){this.className=this.className.replace(new RegExp(&quot;(^|\\s)&quot;+l+&quot;(?:\\s|$)&quot;),&quot;$1&quot;);return this},toggleClass:function(l){return this.hasClass(l)?this.removeClass(l):this.addClass(l)},adopt:function(){Array.flatten(arguments).each(function(l){l=$(l,true);if(l){this.appendChild(l)}},this);return this},appendText:function(m,l){return this.grab(this.getDocument().newTextNode(m),l)},grab:function(m,l){a[l||&quot;bottom&quot;]($(m,true),this);return this},inject:function(m,l){a[l||&quot;bottom&quot;](this,$(m,true));return this},replaces:function(l){l=$(l,true);l.parentNode.replaceChild(this,l);return this},wraps:function(m,l){m=$(m,true);return this.replaces(m).grab(m,l)},getPrevious:function(l,m){return j(this,&quot;previousSibling&quot;,null,l,false,m)},getAllPrevious:function(l,m){return j(this,&quot;previousSibling&quot;,null,l,true,m)},getNext:function(l,m){return j(this,&quot;nextSibling&quot;,null,l,false,m)},getAllNext:function(l,m){return j(this,&quot;nextSibling&quot;,null,l,true,m)},getFirst:function(l,m){return j(this,&quot;nextSibling&quot;,&quot;firstChild&quot;,l,false,m)},getLast:function(l,m){return j(this,&quot;previousSibling&quot;,&quot;lastChild&quot;,l,false,m)},getParent:function(l,m){return j(this,&quot;parentNode&quot;,null,l,false,m)},getParents:function(l,m){return j(this,&quot;parentNode&quot;,null,l,true,m)},getChildren:function(l,m){return j(this,&quot;nextSibling&quot;,&quot;firstChild&quot;,l,true,m)},getWindow:function(){return this.ownerDocument.window},getDocument:function(){return this.ownerDocument},getElementById:function(o,n){var m=this.ownerDocument.getElementById(o);if(!m){return null}for(var l=m.parentNode;l!=this;l=l.parentNode){if(!l){return null}}return $.element(m,n)},getSelected:function(){return new Elements($A(this.options).filter(function(l){return l.selected}))},getComputedStyle:function(m){if(this.currentStyle){return this.currentStyle[m.camelCase()]}var l=this.getDocument().defaultView.getComputedStyle(this,null);return(l)?l.getPropertyValue([m.hyphenate()]):null},toQueryString:function(){var l=[];this.getElements(&quot;input, select, textarea&quot;,true).each(function(m){if(!m.name||m.disabled){return}var n=(m.tagName.toLowerCase()==&quot;select&quot;)?Element.getSelected(m).map(function(o){return o.value}):((m.type==&quot;radio&quot;||m.type==&quot;checkbox&quot;)&amp;&amp;!m.checked)?null:m.value;$splat(n).each(function(o){if(typeof o!=&quot;undefined&quot;){l.push(m.name+&quot;=&quot;+encodeURIComponent(o))}})});return l.join(&quot;&amp;&quot;)},clone:function(o,l){o=o!==false;var r=this.cloneNode(o);var n=function(v,u){if(!l){v.removeAttribute(&quot;id&quot;)}if(Browser.Engine.trident){v.clearAttributes();v.mergeAttributes(u);v.removeAttribute(&quot;uid&quot;);if(v.options){var w=v.options,s=u.options;for(var t=w.length;t--;){w[t].selected=s[t].selected}}}var x=i[u.tagName.toLowerCase()];if(x&amp;&amp;u[x]){v[x]=u[x]}};if(o){var p=r.getElementsByTagName(&quot;*&quot;),q=this.getElementsByTagName(&quot;*&quot;);for(var m=p.length;m--;){n(p[m],q[m])}}n(r,this);return $(r)},destroy:function(){Element.empty(this);Element.dispose(this);g(this,true);return null},empty:function(){$A(this.childNodes).each(function(l){Element.destroy(l)});return this},dispose:function(){return(this.parentNode)?this.parentNode.removeChild(this):this},hasChild:function(l){l=$(l,true);if(!l){return false}if(Browser.Engine.webkit&amp;&amp;Browser.Engine.version&lt;420){return $A(this.getElementsByTagName(l.tagName)).contains(l)}return(this.contains)?(this!=l&amp;&amp;this.contains(l)):!!(this.compareDocumentPosition(l)&amp;16)},match:function(l){return(!l||(l==this)||(Element.get(this,&quot;tag&quot;)==l))}});Native.implement([Element,Window,Document],{addListener:function(o,n){if(o==&quot;unload&quot;){var l=n,m=this;n=function(){m.removeListener(&quot;unload&quot;,n);l()}}else{h[this.uid]=this}if(this.addEventListener){this.addEventListener(o,n,false)}else{this.attachEvent(&quot;on&quot;+o,n)}return this},removeListener:function(m,l){if(this.removeEventListener){this.removeEventListener(m,l,false)}else{this.detachEvent(&quot;on&quot;+m,l)}return this},retrieve:function(m,l){var o=c(this.uid),n=o[m];if(l!=undefined&amp;&amp;n==undefined){n=o[m]=l}return $pick(n)},store:function(m,l){var n=c(this.uid);n[m]=l;return this},eliminate:function(l){var m=c(this.uid);delete m[l];return this}});window.addListener(&quot;unload&quot;,d)})();Element.Properties=new Hash;Element.Properties.style={set:function(a){this.style.cssText=a},get:function(){return this.style.cssText},erase:function(){this.style.cssText=&quot;&quot;}};Element.Properties.tag={get:function(){return this.tagName.toLowerCase()}};Element.Properties.html=(function(){var c=document.createElement(&quot;div&quot;);var a={table:[1,&quot;&lt;table&gt;&quot;,&quot;&lt;/table&gt;&quot;],select:[1,&quot;&lt;select&gt;&quot;,&quot;&lt;/select&gt;&quot;],tbody:[2,&quot;&lt;table&gt;&lt;tbody&gt;&quot;,&quot;&lt;/tbody&gt;&lt;/table&gt;&quot;],tr:[3,&quot;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&quot;,&quot;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&quot;]};a.thead=a.tfoot=a.tbody;var b={set:function(){var e=Array.flatten(arguments).join(&quot;&quot;);var f=Browser.Engine.trident&amp;&amp;a[this.get(&quot;tag&quot;)];if(f){var g=c;g.innerHTML=f[1]+e+f[2];for(var d=f[0];d--;){g=g.firstChild}this.empty().adopt(g.childNodes)}else{this.innerHTML=e}}};b.erase=b.set;return b})();if(Browser.Engine.webkit&amp;&amp;Browser.Engine.version&lt;420){Element.Properties.text={get:function(){if(this.innerText){return this.innerText}var a=this.ownerDocument.newElement(&quot;div&quot;,{html:this.innerHTML}).inject(this.ownerDocument.body);var b=a.innerText;a.destroy();return b}}}Element.Properties.events={set:function(a){this.addEvents(a)}};Native.implement([Element,Window,Document],{addEvent:function(e,g){var h=this.retrieve(&quot;events&quot;,{});h[e]=h[e]||{keys:[],values:[]};if(h[e].keys.contains(g)){return this}h[e].keys.push(g);var f=e,a=Element.Events.get(e),c=g,i=this;if(a){if(a.onAdd){a.onAdd.call(this,g)}if(a.condition){c=function(j){if(a.condition.call(this,j)){return g.call(this,j)}return true}}f=a.base||f}var d=function(){return g.call(i)};var b=Element.NativeEvents[f];if(b){if(b==2){d=function(j){j=new Event(j,i.getWindow());if(c.call(i,j)===false){j.stop()}}}this.addListener(f,d)}h[e].values.push(d);return this},removeEvent:function(c,b){var a=this.retrieve(&quot;events&quot;);if(!a||!a[c]){return this}var f=a[c].keys.indexOf(b);if(f==-1){return this}a[c].keys.splice(f,1);var e=a[c].values.splice(f,1)[0];var d=Element.Events.get(c);if(d){if(d.onRemove){d.onRemove.call(this,b)}c=d.base||c}return(Element.NativeEvents[c])?this.removeListener(c,e):this},addEvents:function(a){for(var b in a){this.addEvent(b,a[b])}return this},removeEvents:function(a){if($type(a)==&quot;object&quot;){for(var c in a){this.removeEvent(c,a[c])}return this}var b=this.retrieve(&quot;events&quot;);if(!b){return this}if(!a){for(var c in b){this.removeEvents(c)}this.eliminate(&quot;events&quot;)}else{if(b[a]){while(b[a].keys[0]){this.removeEvent(a,b[a].keys[0])}b[a]=null}}return this},fireEvent:function(d,b,a){var c=this.retrieve(&quot;events&quot;);if(!c||!c[d]){return this}c[d].keys.each(function(e){e.create({bind:this,delay:a,&quot;arguments&quot;:b})()},this);return this},cloneEvents:function(d,a){d=$(d);var c=d.retrieve(&quot;events&quot;);if(!c){return this}if(!a){for(var b in c){this.cloneEvents(d,b)}}else{if(c[a]){c[a].keys.each(function(e){this.addEvent(a,e)},this)}}return this}});Element.NativeEvents={click:2,dblclick:2,mouseup:2,mousedown:2,contextmenu:2,mousewheel:2,DOMMouseScroll:2,mouseover:2,mouseout:2,mousemove:2,selectstart:2,selectend:2,keydown:2,keypress:2,keyup:2,focus:2,blur:2,change:2,reset:2,select:2,submit:2,load:1,unload:1,beforeunload:2,resize:1,move:1,DOMContentLoaded:1,readystatechange:1,error:1,abort:1,scroll:1};(function(){var a=function(b){var c=b.relatedTarget;if(c==undefined){return true}if(c===false){return false}return($type(this)!=&quot;document&quot;&amp;&amp;c!=this&amp;&amp;c.prefix!=&quot;xul&quot;&amp;&amp;!this.hasChild(c))};Element.Events=new Hash({mouseenter:{base:&quot;mouseover&quot;,condition:a},mouseleave:{base:&quot;mouseout&quot;,condition:a},mousewheel:{base:(Browser.Engine.gecko)?&quot;DOMMouseScroll&quot;:&quot;mousewheel&quot;}})})();Element.Properties.styles={set:function(a){this.setStyles(a)}};Element.Properties.opacity={set:function(a,b){if(!b){if(a==0){if(this.style.visibility!=&quot;hidden&quot;){this.style.visibility=&quot;hidden&quot;}}else{if(this.style.visibility!=&quot;visible&quot;){this.style.visibility=&quot;visible&quot;}}}if(!this.currentStyle||!this.currentStyle.hasLayout){this.style.zoom=1}if(Browser.Engine.trident){this.style.filter=(a==1)?&quot;&quot;:&quot;alpha(opacity=&quot;+a*100+&quot;)&quot;}this.style.opacity=a;this.store(&quot;opacity&quot;,a)},get:function(){return this.retrieve(&quot;opacity&quot;,1)}};Element.implement({setOpacity:function(a){return this.set(&quot;opacity&quot;,a,true)},getOpacity:function(){return this.get(&quot;opacity&quot;)},setStyle:function(b,a){switch(b){case&quot;opacity&quot;:return this.set(&quot;opacity&quot;,parseFloat(a));case&quot;float&quot;:b=(Browser.Engine.trident)?&quot;styleFloat&quot;:&quot;cssFloat&quot;}b=b.camelCase();if($type(a)!=&quot;string&quot;){var c=(Element.Styles.get(b)||&quot;@&quot;).split(&quot; &quot;);a=$splat(a).map(function(e,d){if(!c[d]){return&quot;&quot;}return($type(e)==&quot;number&quot;)?c[d].replace(&quot;@&quot;,Math.round(e)):e}).join(&quot; &quot;)}else{if(a==String(Number(a))){a=Math.round(a)}}this.style[b]=a;return this},getStyle:function(g){switch(g){case&quot;opacity&quot;:return this.get(&quot;opacity&quot;);case&quot;float&quot;:g=(Browser.Engine.trident)?&quot;styleFloat&quot;:&quot;cssFloat&quot;}g=g.camelCase();var a=this.style[g];if(!$chk(a)){a=[];for(var f in Element.ShortStyles){if(g!=f){continue}for(var e in Element.ShortStyles[f]){a.push(this.getStyle(e))}return a.join(&quot; &quot;)}a=this.getComputedStyle(g)}if(a){a=String(a);var c=a.match(/rgba?\([\d\s,]+\)/);if(c){a=a.replace(c[0],c[0].rgbToHex())}}if(Browser.Engine.presto||(Browser.Engine.trident&amp;&amp;!$chk(parseInt(a)))){if(g.test(/^(height|width)$/)){var b=(g==&quot;width&quot;)?[&quot;left&quot;,&quot;right&quot;]:[&quot;top&quot;,&quot;bottom&quot;],d=0;b.each(function(h){d+=this.getStyle(&quot;border-&quot;+h+&quot;-width&quot;).toInt()+this.getStyle(&quot;padding-&quot;+h).toInt()},this);return this[&quot;offset&quot;+g.capitalize()]-d+&quot;px&quot;}if((Browser.Engine.presto)&amp;&amp;String(a).test(&quot;px&quot;)){return a}if(g.test(/(border(.+)Width|margin|padding)/)){return&quot;0px&quot;}}return a},setStyles:function(b){for(var a in b){this.setStyle(a,b[a])}return this},getStyles:function(){var a={};Array.each(arguments,function(b){a[b]=this.getStyle(b)},this);return a}});Element.Styles=new Hash({left:&quot;@px&quot;,top:&quot;@px&quot;,bottom:&quot;@px&quot;,right:&quot;@px&quot;,width:&quot;@px&quot;,height:&quot;@px&quot;,maxWidth:&quot;@px&quot;,maxHeight:&quot;@px&quot;,minWidth:&quot;@px&quot;,minHeight:&quot;@px&quot;,backgroundColor:&quot;rgb(@, @, @)&quot;,backgroundPosition:&quot;@px @px&quot;,color:&quot;rgb(@, @, @)&quot;,fontSize:&quot;@px&quot;,letterSpacing:&quot;@px&quot;,lineHeight:&quot;@px&quot;,clip:&quot;rect(@px @px @px @px)&quot;,margin:&quot;@px @px @px @px&quot;,padding:&quot;@px @px @px @px&quot;,border:&quot;@px @ rgb(@, @, @) @px @ rgb(@, @, @) @px @ rgb(@, @, @)&quot;,borderWidth:&quot;@px @px @px @px&quot;,borderStyle:&quot;@ @ @ @&quot;,borderColor:&quot;rgb(@, @, @) rgb(@, @, @) rgb(@, @, @) rgb(@, @, @)&quot;,zIndex:&quot;@&quot;,zoom:&quot;@&quot;,fontWeight:&quot;@&quot;,textIndent:&quot;@px&quot;,opacity:&quot;@&quot;});Element.ShortStyles={margin:{},padding:{},border:{},borderWidth:{},borderStyle:{},borderColor:{}};[&quot;Top&quot;,&quot;Right&quot;,&quot;Bottom&quot;,&quot;Left&quot;].each(function(g){var f=Element.ShortStyles;var b=Element.Styles;[&quot;margin&quot;,&quot;padding&quot;].each(function(h){var i=h+g;f[h][i]=b[i]=&quot;@px&quot;});var e=&quot;border&quot;+g;f.border[e]=b[e]=&quot;@px @ rgb(@, @, @)&quot;;var d=e+&quot;Width&quot;,a=e+&quot;Style&quot;,c=e+&quot;Color&quot;;f[e]={};f.borderWidth[d]=f[e][d]=b[d]=&quot;@px&quot;;f.borderStyle[a]=f[e][a]=b[a]=&quot;@&quot;;f.borderColor[c]=f[e][c]=b[c]=&quot;rgb(@, @, @)&quot;});(function(){Element.implement({scrollTo:function(h,i){if(b(this)){this.getWindow().scrollTo(h,i)}else{this.scrollLeft=h;this.scrollTop=i}return this},getSize:function(){if(b(this)){return this.getWindow().getSize()}return{x:this.offsetWidth,y:this.offsetHeight}},getScrollSize:function(){if(b(this)){return this.getWindow().getScrollSize()}return{x:this.scrollWidth,y:this.scrollHeight}},getScroll:function(){if(b(this)){return this.getWindow().getScroll()}return{x:this.scrollLeft,y:this.scrollTop}},getScrolls:function(){var i=this,h={x:0,y:0};while(i&amp;&amp;!b(i)){h.x+=i.scrollLeft;h.y+=i.scrollTop;i=i.parentNode}return h},getOffsetParent:function(){var h=this;if(b(h)){return null}if(!Browser.Engine.trident){return h.offsetParent}while((h=h.parentNode)&amp;&amp;!b(h)){if(d(h,&quot;position&quot;)!=&quot;static&quot;){return h}}return null},getOffsets:function(){if(Browser.Engine.trident){var l=this.getBoundingClientRect(),j=this.getDocument().documentElement;return{x:l.left+j.scrollLeft-j.clientLeft,y:l.top+j.scrollTop-j.clientTop}}var i=this,h={x:0,y:0};if(b(this)){return h}while(i&amp;&amp;!b(i)){h.x+=i.offsetLeft;h.y+=i.offsetTop;if(Browser.Engine.gecko){if(!f(i)){h.x+=c(i);h.y+=g(i)}var k=i.parentNode;if(k&amp;&amp;d(k,&quot;overflow&quot;)!=&quot;visible&quot;){h.x+=c(k);h.y+=g(k)}}else{if(i!=this&amp;&amp;Browser.Engine.webkit){h.x+=c(i);h.y+=g(i)}}i=i.offsetParent}if(Browser.Engine.gecko&amp;&amp;!f(this)){h.x-=c(this);h.y-=g(this)}return h},getPosition:function(k){if(b(this)){return{x:0,y:0}}var l=this.getOffsets(),i=this.getScrolls();var h={x:l.x-i.x,y:l.y-i.y};var j=(k&amp;&amp;(k=$(k)))?k.getPosition():{x:0,y:0};return{x:h.x-j.x,y:h.y-j.y}},getCoordinates:function(j){if(b(this)){return this.getWindow().getCoordinates()}var h=this.getPosition(j),i=this.getSize();var k={left:h.x,top:h.y,width:i.x,height:i.y};k.right=k.left+k.width;k.bottom=k.top+k.height;return k},computePosition:function(h){return{left:h.x-e(this,&quot;margin-left&quot;),top:h.y-e(this,&quot;margin-top&quot;)}},position:function(h){return this.setStyles(this.computePosition(h))}});Native.implement([Document,Window],{getSize:function(){var i=this.getWindow();if(Browser.Engine.presto||Browser.Engine.webkit){return{x:i.innerWidth,y:i.innerHeight}}var h=a(this);return{x:h.clientWidth,y:h.clientHeight}},getScroll:function(){var i=this.getWindow();var h=a(this);return{x:i.pageXOffset||h.scrollLeft,y:i.pageYOffset||h.scrollTop}},getScrollSize:function(){var i=a(this);var h=this.getSize();return{x:Math.max(i.scrollWidth,h.x),y:Math.max(i.scrollHeight,h.y)}},getPosition:function(){return{x:0,y:0}},getCoordinates:function(){var h=this.getSize();return{top:0,left:0,bottom:h.y,right:h.x,height:h.y,width:h.x}}});var d=Element.getComputedStyle;function e(h,i){return d(h,i).toInt()||0}function f(h){return d(h,&quot;-moz-box-sizing&quot;)==&quot;border-box&quot;}function g(h){return e(h,&quot;border-top-width&quot;)}function c(h){return e(h,&quot;border-left-width&quot;)}function b(h){return(/^(?:body|html)$/i).test(h.tagName)}function a(h){var i=h.getDocument();return(!i.compatMode||i.compatMode==&quot;CSS1Compat&quot;)?i.html:i.body}})();Native.implement([Window,Document,Element],{getHeight:function(){return this.getSize().y},getWidth:function(){return this.getSize().x},getScrollTop:function(){return this.getScroll().y},getScrollLeft:function(){return this.getScroll().x},getScrollHeight:function(){return this.getScrollSize().y},getScrollWidth:function(){return this.getScrollSize().x},getTop:function(){return this.getPosition().y},getLeft:function(){return this.getPosition().x}});Native.implement([Document,Element],{getElements:function(h,g){h=h.split(&quot;,&quot;);var c,e={};for(var d=0,b=h.length;d&lt;b;d++){var a=h[d],f=Selectors.Utils.search(this,a,e);if(d!=0&amp;&amp;f.item){f=$A(f)}c=(d==0)?f:(c.item)?$A(c).concat(f):c.concat(f)}return new Elements(c,{ddup:(h.length&gt;1),cash:!g})}});Element.implement({match:function(b){if(!b||(b==this)){return true}var d=Selectors.Utils.parseTagAndID(b);var a=d[0],e=d[1];if(!Selectors.Filters.byID(this,e)||!Selectors.Filters.byTag(this,a)){return false}var c=Selectors.Utils.parseSelector(b);return(c)?Selectors.Utils.filter(this,c,{}):true}});var Selectors={Cache:{nth:{},parsed:{}}};Selectors.RegExps={id:(/#([\w-]+)/),tag:(/^(\w+|\*)/),quick:(/^(\w+|\*)$/),splitter:(/\s*([+&gt;~\s])\s*([a-zA-Z#.*:\[])/g),combined:(/\.([\w-]+)|\[(\w+)(?:([!*^$~|]?=)([&quot;&#39;]?)([^\4]*?)\4)?\]|:([\w-]+)(?:\([&quot;&#39;]?(.*?)?[&quot;&#39;]?\)|$)/g)};Selectors.Utils={chk:function(b,c){if(!c){return true}var a=$uid(b);if(!c[a]){return c[a]=true}return false},parseNthArgument:function(h){if(Selectors.Cache.nth[h]){return Selectors.Cache.nth[h]}var e=h.match(/^([+-]?\d*)?([a-z]+)?([+-]?\d*)?$/);if(!e){return false}var g=parseInt(e[1]);var d=(g||g===0)?g:1;var f=e[2]||false;var c=parseInt(e[3])||0;if(d!=0){c--;while(c&lt;1){c+=d}while(c&gt;=d){c-=d}}else{d=c;f=&quot;index&quot;}switch(f){case&quot;n&quot;:e={a:d,b:c,special:&quot;n&quot;};break;case&quot;odd&quot;:e={a:2,b:0,special:&quot;n&quot;};break;case&quot;even&quot;:e={a:2,b:1,special:&quot;n&quot;};break;case&quot;first&quot;:e={a:0,special:&quot;index&quot;};break;case&quot;last&quot;:e={special:&quot;last-child&quot;};break;case&quot;only&quot;:e={special:&quot;only-child&quot;};break;default:e={a:(d-1),special:&quot;index&quot;}}return Selectors.Cache.nth[h]=e},parseSelector:function(e){if(Selectors.Cache.parsed[e]){return Selectors.Cache.parsed[e]}var d,h={classes:[],pseudos:[],attributes:[]};while((d=Selectors.RegExps.combined.exec(e))){var i=d[1],g=d[2],f=d[3],b=d[5],c=d[6],j=d[7];if(i){h.classes.push(i)}else{if(c){var a=Selectors.Pseudo.get(c);if(a){h.pseudos.push({parser:a,argument:j})}else{h.attributes.push({name:c,operator:&quot;=&quot;,value:j})}}else{if(g){h.attributes.push({name:g,operator:f,value:b})}}}}if(!h.classes.length){delete h.classes}if(!h.attributes.length){delete h.attributes}if(!h.pseudos.length){delete h.pseudos}if(!h.classes&amp;&amp;!h.attributes&amp;&amp;!h.pseudos){h=null}return Selectors.Cache.parsed[e]=h},parseTagAndID:function(b){var a=b.match(Selectors.RegExps.tag);var c=b.match(Selectors.RegExps.id);return[(a)?a[1]:&quot;*&quot;,(c)?c[1]:false]},filter:function(f,c,e){var d;if(c.classes){for(d=c.classes.length;d--;d){var g=c.classes[d];if(!Selectors.Filters.byClass(f,g)){return false}}}if(c.attributes){for(d=c.attributes.length;d--;d){var b=c.attributes[d];if(!Selectors.Filters.byAttribute(f,b.name,b.operator,b.value)){return false}}}if(c.pseudos){for(d=c.pseudos.length;d--;d){var a=c.pseudos[d];if(!Selectors.Filters.byPseudo(f,a.parser,a.argument,e)){return false}}}return true},getByTagAndID:function(b,a,d){if(d){var c=(b.getElementById)?b.getElementById(d,true):Element.getElementById(b,d,true);return(c&amp;&amp;Selectors.Filters.byTag(c,a))?[c]:[]}else{return b.getElementsByTagName(a)}},search:function(o,h,t){var b=[];var c=h.trim().replace(Selectors.RegExps.splitter,function(k,j,i){b.push(j);return&quot;:)&quot;+i}).split(&quot;:)&quot;);var p,e,A;for(var z=0,v=c.length;z&lt;v;z++){var y=c[z];if(z==0&amp;&amp;Selectors.RegExps.quick.test(y)){p=o.getElementsByTagName(y);continue}var a=b[z-1];var q=Selectors.Utils.parseTagAndID(y);var B=q[0],r=q[1];if(z==0){p=Selectors.Utils.getByTagAndID(o,B,r)}else{var d={},g=[];for(var x=0,w=p.length;x&lt;w;x++){g=Selectors.Getters[a](g,p[x],B,r,d)}p=g}var f=Selectors.Utils.parseSelector(y);if(f){e=[];for(var u=0,s=p.length;u&lt;s;u++){A=p[u];if(Selectors.Utils.filter(A,f,t)){e.push(A)}}p=e}}return p}};Selectors.Getters={&quot; &quot;:function(h,g,j,a,e){var d=Selectors.Utils.getByTagAndID(g,j,a);for(var c=0,b=d.length;c&lt;b;c++){var f=d[c];if(Selectors.Utils.chk(f,e)){h.push(f)}}return h},&quot;&gt;&quot;:function(h,g,j,a,f){var c=Selectors.Utils.getByTagAndID(g,j,a);for(var e=0,d=c.length;e&lt;d;e++){var b=c[e];if(b.parentNode==g&amp;&amp;Selectors.Utils.chk(b,f)){h.push(b)}}return h},&quot;+&quot;:function(c,b,a,e,d){while((b=b.nextSibling)){if(b.nodeType==1){if(Selectors.Utils.chk(b,d)&amp;&amp;Selectors.Filters.byTag(b,a)&amp;&amp;Selectors.Filters.byID(b,e)){c.push(b)}break}}return c},&quot;~&quot;:function(c,b,a,e,d){while((b=b.nextSibling)){if(b.nodeType==1){if(!Selectors.Utils.chk(b,d)){break}if(Selectors.Filters.byTag(b,a)&amp;&amp;Selectors.Filters.byID(b,e)){c.push(b)}}}return c}};Selectors.Filters={byTag:function(b,a){return(a==&quot;*&quot;||(b.tagName&amp;&amp;b.tagName.toLowerCase()==a))},byID:function(a,b){return(!b||(a.id&amp;&amp;a.id==b))},byClass:function(b,a){return(b.className&amp;&amp;b.className.contains(a,&quot; &quot;))},byPseudo:function(a,d,c,b){return d.call(a,c,b)},byAttribute:function(c,d,b,e){var a=Element.prototype.getProperty.call(c,d);if(!a){return(b==&quot;!=&quot;)}if(!b||e==undefined){return true}switch(b){case&quot;=&quot;:return(a==e);case&quot;*=&quot;:return(a.contains(e));case&quot;^=&quot;:return(a.substr(0,e.length)==e);case&quot;$=&quot;:return(a.substr(a.length-e.length)==e);case&quot;!=&quot;:return(a!=e);case&quot;~=&quot;:return a.contains(e,&quot; &quot;);case&quot;|=&quot;:return a.contains(e,&quot;-&quot;)}return false}};Selectors.Pseudo=new Hash({checked:function(){return this.checked},empty:function(){return !(this.innerText||this.textContent||&quot;&quot;).length},not:function(a){return !Element.match(this,a)},contains:function(a){return(this.innerText||this.textContent||&quot;&quot;).contains(a)},&quot;first-child&quot;:function(){return Selectors.Pseudo.index.call(this,0)},&quot;last-child&quot;:function(){var a=this;while((a=a.nextSibling)){if(a.nodeType==1){return false}}return true},&quot;only-child&quot;:function(){var b=this;while((b=b.previousSibling)){if(b.nodeType==1){return false}}var a=this;while((a=a.nextSibling)){if(a.nodeType==1){return false}}return true},&quot;nth-child&quot;:function(g,e){g=(g==undefined)?&quot;n&quot;:g;var c=Selectors.Utils.parseNthArgument(g);if(c.special!=&quot;n&quot;){return Selectors.Pseudo[c.special].call(this,c.a,e)}var f=0;e.positions=e.positions||{};var d=$uid(this);if(!e.positions[d]){var b=this;while((b=b.previousSibling)){if(b.nodeType!=1){continue}f++;var a=e.positions[$uid(b)];if(a!=undefined){f=a+f;break}}e.positions[d]=f}return(e.positions[d]%c.a==c.b)},index:function(a){var b=this,c=0;while((b=b.previousSibling)){if(b.nodeType==1&amp;&amp;++c&gt;a){return false}}return(c==a)},even:function(b,a){return Selectors.Pseudo[&quot;nth-child&quot;].call(this,&quot;2n+1&quot;,a)},odd:function(b,a){return Selectors.Pseudo[&quot;nth-child&quot;].call(this,&quot;2n&quot;,a)}});Element.Events.domready={onAdd:function(a){if(Browser.loaded){a.call(this)}}};(function(){var b=function(){if(Browser.loaded){return}Browser.loaded=true;window.fireEvent(&quot;domready&quot;);document.fireEvent(&quot;domready&quot;)};if(Browser.Engine.trident){var a=document.createElement(&quot;div&quot;);(function(){($try(function(){a.doScroll(&quot;left&quot;);return $(a).inject(document.body).set(&quot;html&quot;,&quot;temp&quot;).dispose()}))?b():arguments.callee.delay(50)})()}else{if(Browser.Engine.webkit&amp;&amp;Browser.Engine.version&lt;525){(function(){([&quot;loaded&quot;,&quot;complete&quot;].contains(document.readyState))?b():arguments.callee.delay(50)})()}else{window.addEvent(&quot;load&quot;,b);document.addEvent(&quot;DOMContentLoaded&quot;,b)}}})();var JSON=new Hash({$specialChars:{&quot;\b&quot;:&quot;\\b&quot;,&quot;\t&quot;:&quot;\\t&quot;,&quot;\n&quot;:&quot;\\n&quot;,&quot;\f&quot;:&quot;\\f&quot;,&quot;\r&quot;:&quot;\\r&quot;,&#39;&quot;&#39;:&#39;\\&quot;&#39;,&quot;\\&quot;:&quot;\\\\&quot;},$replaceChars:function(a){return JSON.$specialChars[a]||&quot;\\u00&quot;+Math.floor(a.charCodeAt()/16).toString(16)+(a.charCodeAt()%16).toString(16)},encode:function(b){switch($type(b)){case&quot;string&quot;:return&#39;&quot;&#39;+b.replace(/[\x00-\x1f\\&quot;]/g,JSON.$replaceChars)+&#39;&quot;&#39;;case&quot;array&quot;:return&quot;[&quot;+String(b.map(JSON.encode).filter($defined))+&quot;]&quot;;case&quot;object&quot;:case&quot;hash&quot;:var a=[];Hash.each(b,function(e,d){var c=JSON.encode(e);if(c){a.push(JSON.encode(d)+&quot;:&quot;+c)}});return&quot;{&quot;+a+&quot;}&quot;;case&quot;number&quot;:case&quot;boolean&quot;:return String(b);case false:return&quot;null&quot;}return null},decode:function(string,secure){if($type(string)!=&quot;string&quot;||!string.length){return null}if(secure&amp;&amp;!(/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(string.replace(/\\./g,&quot;@&quot;).replace(/&quot;[^&quot;\\\n\r]*&quot;/g,&quot;&quot;))){return null}return eval(&quot;(&quot;+string+&quot;)&quot;)}});Native.implement([Hash,Array,String,Number],{toJSON:function(){return JSON.encode(this)}});var Cookie=new Class({Implements:Options,options:{path:false,domain:false,duration:false,secure:false,document:document},initialize:function(b,a){this.key=b;this.setOptions(a)},write:function(b){b=encodeURIComponent(b);if(this.options.domain){b+=&quot;; domain=&quot;+this.options.domain}if(this.options.path){b+=&quot;; path=&quot;+this.options.path}if(this.options.duration){var a=new Date();a.setTime(a.getTime()+this.options.duration*24*60*60*1000);b+=&quot;; expires=&quot;+a.toGMTString()}if(this.options.secure){b+=&quot;; secure&quot;}this.options.document.cookie=this.key+&quot;=&quot;+b;return this},read:function(){var a=this.options.document.cookie.match(&quot;(?:^|;)\\s*&quot;+this.key.escapeRegExp()+&quot;=([^;]*)&quot;);return(a)?decodeURIComponent(a[1]):null},dispose:function(){new Cookie(this.key,$merge(this.options,{duration:-1})).write(&quot;&quot;);return this}});Cookie.write=function(b,c,a){return new Cookie(b,a).write(c)};Cookie.read=function(a){return new Cookie(a).read()};Cookie.dispose=function(b,a){return new Cookie(b,a).dispose()};var Swiff=new Class({Implements:[Options],options:{id:null,height:1,width:1,container:null,properties:{},params:{quality:&quot;high&quot;,allowScriptAccess:&quot;always&quot;,wMode:&quot;transparent&quot;,swLiveConnect:true},callBacks:{},vars:{}},toElement:function(){return this.object},initialize:function(l,m){this.instance=&quot;Swiff_&quot;+$time();this.setOptions(m);m=this.options;var b=this.id=m.id||this.instance;var a=$(m.container);Swiff.CallBacks[this.instance]={};var e=m.params,g=m.vars,f=m.callBacks;var h=$extend({height:m.height,width:m.width},m.properties);var k=this;for(var d in f){Swiff.CallBacks[this.instance][d]=(function(n){return function(){return n.apply(k.object,arguments)}})(f[d]);g[d]=&quot;Swiff.CallBacks.&quot;+this.instance+&quot;.&quot;+d}e.flashVars=Hash.toQueryString(g);if(Browser.Engine.trident){h.classid=&quot;clsid:D27CDB6E-AE6D-11cf-96B8-444553540000&quot;;e.movie=l}else{h.type=&quot;application/x-shockwave-flash&quot;;h.data=l}var j=&#39;&lt;object id=&quot;&#39;+b+&#39;&quot;&#39;;for(var i in h){j+=&quot; &quot;+i+&#39;=&quot;&#39;+h[i]+&#39;&quot;&#39;}j+=&quot;&gt;&quot;;for(var c in e){if(e[c]){j+=&#39;&lt;param name=&quot;&#39;+c+&#39;&quot; value=&quot;&#39;+e[c]+&#39;&quot; /&gt;&#39;}}j+=&quot;&lt;/object&gt;&quot;;this.object=((a)?a.empty():new Element(&quot;div&quot;)).set(&quot;html&quot;,j).firstChild},replaces:function(a){a=$(a,true);a.parentNode.replaceChild(this.toElement(),a);return this},inject:function(a){$(a,true).appendChild(this.toElement());return this},remote:function(){return Swiff.remote.apply(Swiff,[this.toElement()].extend(arguments))}});Swiff.CallBacks={};Swiff.remote=function(obj,fn){var rs=obj.CallFunction(&#39;&lt;invoke name=&quot;&#39;+fn+&#39;&quot; returntype=&quot;javascript&quot;&gt;&#39;+__flash__argumentsToXML(arguments,2)+&quot;&lt;/invoke&gt;&quot;);return eval(rs)};var Fx=new Class({Implements:[Chain,Events,Options],options:{fps:50,unit:false,duration:500,link:&quot;ignore&quot;},initialize:function(a){this.subject=this.subject||this;this.setOptions(a);this.options.duration=Fx.Durations[this.options.duration]||this.options.duration.toInt();var b=this.options.wait;if(b===false){this.options.link=&quot;cancel&quot;}},getTransition:function(){return function(a){return -(Math.cos(Math.PI*a)-1)/2}},step:function(){var a=$time();if(a&lt;this.time+this.options.duration){var b=this.transition((a-this.time)/this.options.duration);this.set(this.compute(this.from,this.to,b))}else{this.set(this.compute(this.from,this.to,1));this.complete()}},set:function(a){return a},compute:function(c,b,a){return Fx.compute(c,b,a)},check:function(a){if(!this.timer){return true}switch(this.options.link){case&quot;cancel&quot;:this.cancel();return true;case&quot;chain&quot;:this.chain(a.bind(this,Array.slice(arguments,1)));return false}return false},start:function(b,a){if(!this.check(arguments.callee,b,a)){return this}this.from=b;this.to=a;this.time=0;this.transition=this.getTransition();this.startTimer();this.onStart();return this},complete:function(){if(this.stopTimer()){this.onComplete()}return this},cancel:function(){if(this.stopTimer()){this.onCancel()}return this},onStart:function(){this.fireEvent(&quot;start&quot;,this.subject)},onComplete:function(){this.fireEvent(&quot;complete&quot;,this.subject);if(!this.callChain()){this.fireEvent(&quot;chainComplete&quot;,this.subject)}},onCancel:function(){this.fireEvent(&quot;cancel&quot;,this.subject).clearChain()},pause:function(){this.stopTimer();return this},resume:function(){this.startTimer();return this},stopTimer:function(){if(!this.timer){return false}this.time=$time()-this.time;this.timer=$clear(this.timer);return true},startTimer:function(){if(this.timer){return false}this.time=$time()-this.time;this.timer=this.step.periodical(Math.round(1000/this.options.fps),this);return true}});Fx.compute=function(c,b,a){return(b-c)*a+c};Fx.Durations={&quot;short&quot;:250,normal:500,&quot;long&quot;:1000};Fx.CSS=new Class({Extends:Fx,prepare:function(d,e,b){b=$splat(b);var c=b[1];if(!$chk(c)){b[1]=b[0];b[0]=d.getStyle(e)}var a=b.map(this.parse);return{from:a[0],to:a[1]}},parse:function(a){a=$lambda(a)();a=(typeof a==&quot;string&quot;)?a.split(&quot; &quot;):$splat(a);return a.map(function(c){c=String(c);var b=false;Fx.CSS.Parsers.each(function(f,e){if(b){return}var d=f.parse(c);if($chk(d)){b={value:d,parser:f}}});b=b||{value:c,parser:Fx.CSS.Parsers.String};return b})},compute:function(d,c,b){var a=[];(Math.min(d.length,c.length)).times(function(e){a.push({value:d[e].parser.compute(d[e].value,c[e].value,b),parser:d[e].parser})});a.$family={name:&quot;fx:css:value&quot;};return a},serve:function(c,b){if($type(c)!=&quot;fx:css:value&quot;){c=this.parse(c)}var a=[];c.each(function(d){a=a.concat(d.parser.serve(d.value,b))});return a},render:function(a,d,c,b){a.setStyle(d,this.serve(c,b))},search:function(a){if(Fx.CSS.Cache[a]){return Fx.CSS.Cache[a]}var b={};Array.each(document.styleSheets,function(e,d){var c=e.href;if(c&amp;&amp;c.contains(&quot;://&quot;)&amp;&amp;!c.contains(document.domain)){return}var f=e.rules||e.cssRules;Array.each(f,function(j,g){if(!j.style){return}var h=(j.selectorText)?j.selectorText.replace(/^\w+/,function(i){return i.toLowerCase()}):null;if(!h||!h.test(&quot;^&quot;+a+&quot;$&quot;)){return}Element.Styles.each(function(k,i){if(!j.style[i]||Element.ShortStyles[i]){return}k=String(j.style[i]);b[i]=(k.test(/^rgb/))?k.rgbToHex():k})})});return Fx.CSS.Cache[a]=b}});Fx.CSS.Cache={};Fx.CSS.Parsers=new Hash({Color:{parse:function(a){if(a.match(/^#[0-9a-f]{3,6}$/i)){return a.hexToRgb(true)}return((a=a.match(/(\d+),\s*(\d+),\s*(\d+)/)))?[a[1],a[2],a[3]]:false},compute:function(c,b,a){return c.map(function(e,d){return Math.round(Fx.compute(c[d],b[d],a))})},serve:function(a){return a.map(Number)}},Number:{parse:parseFloat,compute:Fx.compute,serve:function(b,a){return(a)?b+a:b}},String:{parse:$lambda(false),compute:$arguments(1),serve:$arguments(0)}});Fx.Tween=new Class({Extends:Fx.CSS,initialize:function(b,a){this.element=this.subject=$(b);this.parent(a)},set:function(b,a){if(arguments.length==1){a=b;b=this.property||this.options.property}this.render(this.element,b,a,this.options.unit);return this},start:function(c,e,d){if(!this.check(arguments.callee,c,e,d)){return this}var b=Array.flatten(arguments);this.property=this.options.property||b.shift();var a=this.prepare(this.element,this.property,b);return this.parent(a.from,a.to)}});Element.Properties.tween={set:function(a){var b=this.retrieve(&quot;tween&quot;);if(b){b.cancel()}return this.eliminate(&quot;tween&quot;).store(&quot;tween:options&quot;,$extend({link:&quot;cancel&quot;},a))},get:function(a){if(a||!this.retrieve(&quot;tween&quot;)){if(a||!this.retrieve(&quot;tween:options&quot;)){this.set(&quot;tween&quot;,a)}this.store(&quot;tween&quot;,new Fx.Tween(this,this.retrieve(&quot;tween:options&quot;)))}return this.retrieve(&quot;tween&quot;)}};Element.implement({tween:function(a,c,b){this.get(&quot;tween&quot;).start(arguments);return this},fade:function(c){var e=this.get(&quot;tween&quot;),d=&quot;opacity&quot;,a;c=$pick(c,&quot;toggle&quot;);switch(c){case&quot;in&quot;:e.start(d,1);break;case&quot;out&quot;:e.start(d,0);break;case&quot;show&quot;:e.set(d,1);break;case&quot;hide&quot;:e.set(d,0);break;case&quot;toggle&quot;:var b=this.retrieve(&quot;fade:flag&quot;,this.get(&quot;opacity&quot;)==1);e.start(d,(b)?0:1);this.store(&quot;fade:flag&quot;,!b);a=true;break;default:e.start(d,arguments)}if(!a){this.eliminate(&quot;fade:flag&quot;)}return this},highlight:function(c,a){if(!a){a=this.retrieve(&quot;highlight:original&quot;,this.getStyle(&quot;background-color&quot;));a=(a==&quot;transparent&quot;)?&quot;#fff&quot;:a}var b=this.get(&quot;tween&quot;);b.start(&quot;background-color&quot;,c||&quot;#ffff88&quot;,a).chain(function(){this.setStyle(&quot;background-color&quot;,this.retrieve(&quot;highlight:original&quot;));b.callChain()}.bind(this));return this}});Fx.Morph=new Class({Extends:Fx.CSS,initialize:function(b,a){this.element=this.subject=$(b);this.parent(a)},set:function(a){if(typeof a==&quot;string&quot;){a=this.search(a)}for(var b in a){this.render(this.element,b,a[b],this.options.unit)}return this},compute:function(e,d,c){var a={};for(var b in e){a[b]=this.parent(e[b],d[b],c)}return a},start:function(b){if(!this.check(arguments.callee,b)){return this}if(typeof b==&quot;string&quot;){b=this.search(b)}var e={},d={};for(var c in b){var a=this.prepare(this.element,c,b[c]);e[c]=a.from;d[c]=a.to}return this.parent(e,d)}});Element.Properties.morph={set:function(a){var b=this.retrieve(&quot;morph&quot;);if(b){b.cancel()}return this.eliminate(&quot;morph&quot;).store(&quot;morph:options&quot;,$extend({link:&quot;cancel&quot;},a))},get:function(a){if(a||!this.retrieve(&quot;morph&quot;)){if(a||!this.retrieve(&quot;morph:options&quot;)){this.set(&quot;morph&quot;,a)}this.store(&quot;morph&quot;,new Fx.Morph(this,this.retrieve(&quot;morph:options&quot;)))}return this.retrieve(&quot;morph&quot;)}};Element.implement({morph:function(a){this.get(&quot;morph&quot;).start(a);return this}});Fx.implement({getTransition:function(){var a=this.options.transition||Fx.Transitions.Sine.easeInOut;if(typeof a==&quot;string&quot;){var b=a.split(&quot;:&quot;);a=Fx.Transitions;a=a[b[0]]||a[b[0].capitalize()];if(b[1]){a=a[&quot;ease&quot;+b[1].capitalize()+(b[2]?b[2].capitalize():&quot;&quot;)]}}return a}});Fx.Transition=function(b,a){a=$splat(a);return $extend(b,{easeIn:function(c){return b(c,a)},easeOut:function(c){return 1-b(1-c,a)},easeInOut:function(c){return(c&lt;=0.5)?b(2*c,a)/2:(2-b(2*(1-c),a))/2}})};Fx.Transitions=new Hash({linear:$arguments(0)});Fx.Transitions.extend=function(a){for(var b in a){Fx.Transitions[b]=new Fx.Transition(a[b])}};Fx.Transitions.extend({Pow:function(b,a){return Math.pow(b,a[0]||6)},Expo:function(a){return Math.pow(2,8*(a-1))},Circ:function(a){return 1-Math.sin(Math.acos(a))},Sine:function(a){return 1-Math.sin((1-a)*Math.PI/2)},Back:function(b,a){a=a[0]||1.618;return Math.pow(b,2)*((a+1)*b-a)},Bounce:function(f){var e;for(var d=0,c=1;1;d+=c,c/=2){if(f&gt;=(7-4*d)/11){e=c*c-Math.pow((11-6*d-11*f)/4,2);break}}return e},Elastic:function(b,a){return Math.pow(2,10*--b)*Math.cos(20*b*Math.PI*(a[0]||1)/3)}});[&quot;Quad&quot;,&quot;Cubic&quot;,&quot;Quart&quot;,&quot;Quint&quot;].each(function(b,a){Fx.Transitions[b]=new Fx.Transition(function(c){return Math.pow(c,[a+2])})});var Request=new Class({Implements:[Chain,Events,Options],options:{url:&quot;&quot;,data:&quot;&quot;,headers:{&quot;X-Requested-With&quot;:&quot;XMLHttpRequest&quot;,Accept:&quot;text/javascript, text/html, application/xml, text/xml, */*&quot;},async:true,format:false,method:&quot;post&quot;,link:&quot;ignore&quot;,isSuccess:null,emulation:true,urlEncoded:true,encoding:&quot;utf-8&quot;,evalScripts:false,evalResponse:false},initialize:function(a){this.xhr=new Browser.Request();this.setOptions(a);this.options.isSuccess=this.options.isSuccess||this.isSuccess;this.headers=new Hash(this.options.headers)},onStateChange:function(){if(this.xhr.readyState!=4||!this.running){return}this.running=false;this.status=0;$try(function(){this.status=this.xhr.status}.bind(this));if(this.options.isSuccess.call(this,this.status)){this.response={text:this.xhr.responseText,xml:this.xhr.responseXML};this.success(this.response.text,this.response.xml)}else{this.response={text:null,xml:null};this.failure()}this.xhr.onreadystatechange=$empty},isSuccess:function(){return((this.status&gt;=200)&amp;&amp;(this.status&lt;300))},processScripts:function(a){if(this.options.evalResponse||(/(ecma|java)script/).test(this.getHeader(&quot;Content-type&quot;))){return $exec(a)}return a.stripScripts(this.options.evalScripts)},success:function(b,a){this.onSuccess(this.processScripts(b),a)},onSuccess:function(){this.fireEvent(&quot;complete&quot;,arguments).fireEvent(&quot;success&quot;,arguments).callChain()},failure:function(){this.onFailure()},onFailure:function(){this.fireEvent(&quot;complete&quot;).fireEvent(&quot;failure&quot;,this.xhr)},setHeader:function(a,b){this.headers.set(a,b);return this},getHeader:function(a){return $try(function(){return this.xhr.getResponseHeader(a)}.bind(this))},check:function(a){if(!this.running){return true}switch(this.options.link){case&quot;cancel&quot;:this.cancel();return true;case&quot;chain&quot;:this.chain(a.bind(this,Array.slice(arguments,1)));return false}return false},send:function(i){if(!this.check(arguments.callee,i)){return this}this.running=true;var g=$type(i);if(g==&quot;string&quot;||g==&quot;element&quot;){i={data:i}}var d=this.options;i=$extend({data:d.data,url:d.url,method:d.method},i);var e=i.data,b=i.url,a=i.method;switch($type(e)){case&quot;element&quot;:e=$(e).toQueryString();break;case&quot;object&quot;:case&quot;hash&quot;:e=Hash.toQueryString(e)}if(this.options.format){var h=&quot;format=&quot;+this.options.format;e=(e)?h+&quot;&amp;&quot;+e:h}if(this.options.emulation&amp;&amp;[&quot;put&quot;,&quot;delete&quot;].contains(a)){var f=&quot;_method=&quot;+a;e=(e)?f+&quot;&amp;&quot;+e:f;a=&quot;post&quot;}if(this.options.urlEncoded&amp;&amp;a==&quot;post&quot;){var c=(this.options.encoding)?&quot;; charset=&quot;+this.options.encoding:&quot;&quot;;this.headers.set(&quot;Content-type&quot;,&quot;application/x-www-form-urlencoded&quot;+c)}if(e&amp;&amp;a==&quot;get&quot;){b=b+(b.contains(&quot;?&quot;)?&quot;&amp;&quot;:&quot;?&quot;)+e;e=null}this.xhr.open(a.toUpperCase(),b,this.options.async);this.xhr.onreadystatechange=this.onStateChange.bind(this);this.headers.each(function(k,j){try{this.xhr.setRequestHeader(j,k)}catch(l){this.fireEvent(&quot;exception&quot;,[j,k])}},this);this.fireEvent(&quot;request&quot;);this.xhr.send(e);if(!this.options.async){this.onStateChange()}return this},cancel:function(){if(!this.running){return this}this.running=false;this.xhr.abort();this.xhr.onreadystatechange=$empty;this.xhr=new Browser.Request();this.fireEvent(&quot;cancel&quot;);return this}});(function(){var a={};[&quot;get&quot;,&quot;post&quot;,&quot;put&quot;,&quot;delete&quot;,&quot;GET&quot;,&quot;POST&quot;,&quot;PUT&quot;,&quot;DELETE&quot;].each(function(b){a[b]=function(){var c=Array.link(arguments,{url:String.type,data:$defined});return this.send($extend(c,{method:b.toLowerCase()}))}});Request.implement(a)})();Element.Properties.send={set:function(a){var b=this.retrieve(&quot;send&quot;);if(b){b.cancel()}return this.eliminate(&quot;send&quot;).store(&quot;send:options&quot;,$extend({data:this,link:&quot;cancel&quot;,method:this.get(&quot;method&quot;)||&quot;post&quot;,url:this.get(&quot;action&quot;)},a))},get:function(a){if(a||!this.retrieve(&quot;send&quot;)){if(a||!this.retrieve(&quot;send:options&quot;)){this.set(&quot;send&quot;,a)}this.store(&quot;send&quot;,new Request(this.retrieve(&quot;send:options&quot;)))}return this.retrieve(&quot;send&quot;)}};Element.implement({send:function(a){var b=this.get(&quot;send&quot;);b.send({data:this,url:a||b.options.url});return this}});Request.HTML=new Class({Extends:Request,options:{update:false,evalScripts:true,filter:false},processHTML:function(c){var b=c.match(/&lt;body[^&gt;]*&gt;([\s\S]*?)&lt;\/body&gt;/i);c=(b)?b[1]:c;var a=new Element(&quot;div&quot;);return $try(function(){var d=&quot;&lt;root&gt;&quot;+c+&quot;&lt;/root&gt;&quot;,g;if(Browser.Engine.trident){g=new ActiveXObject(&quot;Microsoft.XMLDOM&quot;);g.async=false;g.loadXML(d)}else{g=new DOMParser().parseFromString(d,&quot;text/xml&quot;)}d=g.getElementsByTagName(&quot;root&quot;)[0];for(var f=0,e=d.childNodes.length;f&lt;e;f++){var h=Element.clone(d.childNodes[f],true,true);if(h){a.grab(h)}}return a})||a.set(&quot;html&quot;,c)},success:function(d){var c=this.options,b=this.response;b.html=d.stripScripts(function(e){b.javascript=e});var a=this.processHTML(b.html);b.tree=a.childNodes;b.elements=a.getElements(&quot;*&quot;);if(c.filter){b.tree=b.elements.filter(c.filter)}if(c.update){$(c.update).empty().set(&quot;html&quot;,b.html)}if(c.evalScripts){$exec(b.javascript)}this.onSuccess(b.tree,b.elements,b.html,b.javascript)}});Element.Properties.load={set:function(a){var b=this.retrieve(&quot;load&quot;);if(b){b.cancel()}return this.eliminate(&quot;load&quot;).store(&quot;load:options&quot;,$extend({data:this,link:&quot;cancel&quot;,update:this,method:&quot;get&quot;},a))},get:function(a){if(a||!this.retrieve(&quot;load&quot;)){if(a||!this.retrieve(&quot;load:options&quot;)){this.set(&quot;load&quot;,a)}this.store(&quot;load&quot;,new Request.HTML(this.retrieve(&quot;load:options&quot;)))}return this.retrieve(&quot;load&quot;)}};Element.implement({load:function(){this.get(&quot;load&quot;).send(Array.link(arguments,{data:Object.type,url:String.type}));return this}});Request.JSON=new Class({Extends:Request,options:{secure:true},initialize:function(a){this.parent(a);this.headers.extend({Accept:&quot;application/json&quot;,&quot;X-Request&quot;:&quot;JSON&quot;})},success:function(a){this.response.json=JSON.decode(a,this.options.secure);this.onSuccess(this.response.json,a)}});
//stratus
var Config={Smallest:8,Biggest:18,Depth:150,Speed:100,Opacity:true,Background:&quot;#fff&quot;,Color:&quot;#000000 &quot;,Hover:&quot;#ffdb00&quot;,Radius:75,UseFx:false,AnimationTime:25};var SizeRange=Config.Biggest-Config.Smallest;var Radian=Math.PI/180;function invokeLater(a,b){window.addEvent(&quot;domready&quot;,a.pass([],b))}var s=[],c=[],i=0;while(i&lt;3600){s[i]=Math.sin(i/10*Radian);c[i]=Math.cos(i/10*Radian);i+=1}var Sine=$A(s);var Cosine=$A(c);function sine(a){while(a&lt;0){a+=360}return Sine[Math.round(a*10)%3600]}function cosine(a){return Cosine[Math.round(Math.abs(a)*10)%3600]}var Body;invokeLater(function(){Body=$(document.body)});var Vector=new Class({initialize:function(a,d,b){if(typeof a==&quot;object&quot;){this.set(a.x,a.y,a.z)}else{this.set(a,d,b)}},mult:function(a){this.x*=a;this.y*=a;this.z*=a;return this},sqr:function(){return this.x*this.x+this.y*this.y+this.z*this.z},set:function(a,d,b){this.x=$pick(a,0);this.y=$pick(d,0);this.z=$pick(b,0)},longEnough:function(){return Math.abs(this.x)&gt;0.01||Math.abs(this.y)&gt;0.01||Math.abs(this.z)&gt;0.01},normalize:function(b){var a=Math.sqrt(this.sqr());return this.mult($pick(b,1)/a)}});var ZeroVector=new Vector();var Atractor=new Class({Implements:Options,options:{id:null,position:&quot;&quot;,width:200,height:200,top:0,left:0},initialize:function(b){this.setOptions(b||{});this.mouse=new Vector();this.element=$(this.options.id);var f={position:this.options.position,top:this.options.top,left:this.options.left,width:this.options.width,height:this.options.height,background:&quot;transparent&quot;};if(!$defined(this.element)){this.options.id=&quot;tagCloudAtr&quot;;this.element=new Element(&quot;div&quot;,{id:this.options.id,styles:f}).inject(Body)}else{this.element.setStyles(f)}this.setOptions($(this.element).getCoordinates());var e=this.options;var a=this.mouse;this.element.addEvent(&quot;mousemove&quot;,function(g){a.set(((-g.page.y+e.top)*2/e.height+1)*1.8,((g.page.x-e.left)*2/e.width-1)*1.8)});var d=this;this.element.addEvent(&quot;mouseenter&quot;,function(){d.active=true});this.element.addEvent(&quot;mouseleave&quot;,function(){d.active=false})},active:false});var __TagId=0;function getTagId(){__TagId+=1;return __TagId}var Tag=new Class({initialize:function(d,b,a){this.id=getTagId();this.title=d;this.rank=($defined(b)&amp;&amp;b&gt;=0)?b:30;if(this.rank&gt;1){this.rank/=100}this.rank=Math.min(this.rank,1);this.url=$pick(a,&quot;#&quot;);this.element=new Element(&quot;a&quot;,{id:&quot;stratusTag&quot;+this.id,href:this.url,&quot;class&quot;:&quot;tagClass&quot;,html:this.title,styles:{&quot;font-size&quot;:this.rank*SizeRange+Config.Smallest+&quot;pt&quot;}}).inject(Body);this.fx=new Fx.Morph(this.element,{duration:Config.AnimationTime,transition:Fx.Transitions.Linear})},position:new Vector()});var commonPasswordArray=[&quot;12345&quot;,&quot;abc123&quot;,&quot;password&quot;,&quot;computer&quot;,&quot;123456&quot;,&quot;tigger&quot;,&quot;1234&quot;,&quot;a1b2c3&quot;,&quot;qwerty&quot;,&quot;123&quot;,&quot;xxx&quot;,&quot;money&quot;,&quot;test&quot;,&quot;carmen&quot;,&quot;mickey&quot;,&quot;secret&quot;,&quot;summer&quot;,&quot;internet&quot;,&quot;service&quot;];var TagCloud=new Class({initialize:function(e,b,a){e=e||400;b=b||200;this.radius=$pick(Math.min(e,b)/4.5,Config.Radius);this.uniform=$pick(a,true);this.items=new Array();(commonPasswordArray.length).times(function(f){this.items[f]=new Tag(commonPasswordArray[f],100)},this);var d=&quot;.tagClass { position: absolute; padding: 3px; color: &quot;+Config.Color+&quot;; } .tagClass:hover { text-decoration: none; color: &quot;+Config.Hover+&quot;; border: solid 1px &quot;+Config.Hover+&quot;; }&quot;;if(!Browser.webkit){new Element(&quot;style&quot;,{html:d}).inject(document.head,&quot;top&quot;)}else{if(!Browser.trident){$$(&quot;style&quot;)[0].appendText(d)}}this.atractor=new Atractor({id:&quot;atractor&quot;,width:e,height:b});this.position=new Vector(this.atractor.options.left+this.atractor.options.width/2-e/4,this.atractor.options.top+this.atractor.options.height/2-b/16);this.distribute()},delta:new Vector(-2,-2),distribute:function(){var g=0,e=0,d=1,f=this.items.length,a=this.radius,b=this.items;while(d&lt;=f){if(this.uniform){g=Math.acos(-1+(2*d-1)/f);e=Math.sqrt(f*Math.PI)*g}else{g=Math.random()*(Math.PI);e=Math.random()*(2*Math.PI)}b[d-1].position.set(a*Math.cos(e)*Math.sin(g),a*Math.sin(e)*Math.sin(g),a*Math.cos(g));d+=1}this.update()},update:function(l){var l=$pick(l,ZeroVector),f=this.items,e=$pick(l.x,0),d=$pick(l.y,0),j=sine(e),k=cosine(e),g=sine(d),h=cosine(d);f.each(function(t){var o=t.position,a=o.x,q=o.y*k+o.z*(-j),m=o.y*j+o.z*k;var r=a*h+m*g,p=q,n=a*(-g)+m*h;o.set(r,p,n);var b=Config.Depth/(Config.Depth+n);if(Config.UseFx){t.fx.start({left:this.position.x+r*b,top:this.position.y+p*b,opacity:Math.max(b-0.7,0)/0.5+0.2,&quot;font-size&quot;:(t.rank*b*SizeRange*2+Config.Smallest)+&quot;pt&quot;})}else{t.element.setStyles({left:this.position.x+r*b,top:this.position.y+p*b,opacity:Math.max(b-0.7,0)/0.5+0.2,&quot;font-size&quot;:(t.rank*b*SizeRange+Config.Smallest)+&quot;pt&quot;})}},this)},pause:function(){if($defined(this.animation)){$clear(this.animation)}},animate:function(){this.animation=(function(){if(this.atractor.active){var a=this.atractor.mouse;this.delta=a}else{var a=this.delta.mult(0.98)}if(a.longEnough()){this.update(a)}}).periodical(Config.AnimationTime,this)}});invokeLater(function(){try{new TagCloud(600,400).animate()}catch(a){alert(a)}});
&lt;/SCRIPT&gt;
&lt;style type=&quot;text/css&quot;&gt;
.tagClass{text-decoration: none;font-family: Sans;font-weight: normal;}
&lt;/style&gt;
&lt;td&gt; &lt;div id=&quot;atractor&quot;&gt;

&lt;/div&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;The top left  shows the 250 most commonly used passwords from the Gawker database. I built this word cloud with &lt;a href=&quot;http://www.wordle.net/&quot;&gt;wordle.net&lt;/a&gt;. On the right, it is an extract of the password dictionary used by John The Ripper. I built this with &lt;a href=&quot;http://student.agh.edu.pl/~fatyga/repos/stratus/example.php&quot;&gt;a JS library called stratus&lt;/a&gt;. If you are currently using one of these passwords for your bank account, you should probably change it quickly! 
&lt;br&gt;&lt;br&gt;
These decrypted real user passwords not only revealed what are the commonly used passwords but also showed that many people are using the same patterns to build their passwords. Knowing these patterns, it is possible to crack passwords in a much shorter time than using a basic brute force technique.
&lt;br&gt;&lt;br&gt;
Here is how you can customize John The Ripper (JTR) to crack encrypted passwords. Please note that I am using an unofficial build of JTR available &lt;a href=&quot;http://openwall.info/wiki/john/custom-builds&quot;&gt;here&lt;/a&gt;. First, you need to create a file containing the passwords to crack. In our example, this file is called pwd2crack.txt and here is the file content:
&lt;pre class=&quot;brush:text&quot;&gt;
user1:d0763edaa9d9bd2a9516280e9044d885
user2:a8e003b1180fd689f558657079d05f5a
&lt;/pre&gt;The file contains the passwords for 2 users: user1 and user2. The passwords are hashed using the MD5 algorithm. 
&lt;br&gt;&lt;br&gt;
To run John The Ripper, you can use the following command:
&lt;pre class=&quot;brush:plain&quot;&gt;
&gt;john --wordlist=password.lst --format=raw-MD5 pwd2crack.txt
Loaded 2 password hashes with no different salts (Raw MD5 [raw-md5 SSE2 16x4])
monkey           (user1)
guesses: 1  time: 0:00:00:00 100.00% (ETA: Mon May  2 22:42:22 2011)  c/s: 469428  trying: trinity - hallo
&lt;/pre&gt;As you can see, JTR was able to crack user1&#39;s password almost instantly because &quot;monkey&quot; was in its list of passwords. But JTR was unable to crack user2&#39;s password. You can try the default command using the built-in logic to guess the passwords.
&lt;pre class=&quot;brush:plain&quot;&gt;
&gt;john --format=raw-MD5 pwd2crack.txt
Loaded 2 password hashes with no different salts (Raw MD5 [raw-md5 SSE2 16x4])
Remaining 1 password hash
guesses: 0  time: 0:00:00:04 (3)  c/s: 195765  trying: 39of - 3ayo
guesses: 0  time: 0:00:00:15 (3)  c/s: 2965K  trying: beteng95 - betel197
guesses: 0  time: 0:00:00:43 (3)  c/s: 5430K  trying: swoji1x - swojsem
guesses: 0  time: 0:00:00:55 (3)  c/s: 5817K  trying: ahabh9 - ahabu2
guesses: 0  time: 0:00:01:08 (3)  c/s: 6052K  trying: luk12ay - luk11io
Session aborted
&lt;/pre&gt;After running this command for a few minutes, my computer got really hot and JTR was still not able to crack user2&#39;s password. While JTR is running, press the space bar to print in the console the progress of the operation.
&lt;br&gt;&lt;br&gt;
One of the common patterns for password is to add a date at the end of the password, especially the current year. You can configure JTR to use its password dictionary with &quot;2011&quot; at the end of each entry by adding the following to the file john.ini or john.conf.
&lt;pre class=&quot;brush:c&quot;&gt;
[List.External:CustomWithYear2011]
void filter() {
 /* calculate word length */
 int length;
 length = 0;
 while (word[length]) length++;

 word[length] = &#39;2&#39;;
 word[length+1] = &#39;0&#39;;
 word[length+2] = &#39;1&#39;;
 word[length+3] = &#39;1&#39;;
 word[length+4] = 0;
}
&lt;/pre&gt;This function, written in C, alters the password to hash before it is compared to the one in pwd2crack.txt. Then you can call JTR with this customization.
&lt;pre class=&quot;brush:plain&quot;&gt;
&gt;john.exe --format=raw-MD5 --wordlist=password.lst --external=CustomWithYear2011 pwd2crack.txt
Loaded 2 password hashes with no different salts (Raw MD5 [raw-md5 SSE2 16x4])
Remaining 1 password hash
monkey2011       (user2)
guesses: 1  time: 0:00:00:00 100.00% (ETA: Mon May  2 22:06:09 2011)  c/s: 25600  trying: freedom2011 - barney2011
&lt;/pre&gt;This time JTR was able to crack the second password: monkey2011.
&lt;br&gt;&lt;br&gt;
You can get more details about these techniques on the &lt;a href=&quot;http://contest.korelogic.com/rules.html&quot;&gt;Korelogic website&lt;/a&gt;.
&lt;br&gt;&lt;br&gt;
Here are a few tips I would recommend:
&lt;ul&gt;
&lt;li&gt;The passwords protecting your most valuable accounts should not be shared with other website&lt;/li&gt;
&lt;li&gt;Use password that are strong and &lt;a href=&quot;http://www.baekdal.com/tips/password-security-usability&quot;&gt;easy to remember&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;If available, use 2-factor authentication (eg: Paypal, Google, World of Warcraft)&lt;/li&gt;
&lt;/ul&gt;If you are responsible of a website, you can:
&lt;ul&gt;
&lt;li&gt;Raise your users awareness (password strength indicator, trainings)&lt;/li&gt;
&lt;li&gt;Use a strong hash algorithm to store the passwords (BlowFish)&lt;/li&gt;
&lt;li&gt;Integrate a second factor of authentication&lt;/li&gt;
&lt;/ul&gt;</content><link rel='replies' type='application/atom+xml' href='http://codebazaar.blogspot.com/feeds/1115448689832365227/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/8927794127513218467/1115448689832365227?isPopup=true' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8927794127513218467/posts/default/1115448689832365227'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8927794127513218467/posts/default/1115448689832365227'/><link rel='alternate' type='text/html' href='http://codebazaar.blogspot.com/2011/05/why-we-need-strong-p4ssw0rds.html' title='Why we need strong p4ssw0rds'/><author><name>Matt Buchner</name><uri>http://www.blogger.com/profile/03993705703169676412</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGJBh157km2WvcRk9Fd0alqVRHYw3pldCvcehZRPx8NXBkVlqWclPGMXjjvP_CKoYtUwPQECmIfijWZo-2-O64i5ogn-LI4qplVUgMixVlbsXwbJgQrwlSr44Wxp3Cr4o/s113/headshot.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8GJf7B1FMfekErk2GxRoCYTMC49wOWL_v98jyKv8VBO2mY4g-F9Taa3x4VWFvZp2RWubSg16JOkNPL5ZCH7TxQYNmPNcdBNVEYvKWkLL7KAM5BaMIwz0aY3HbNABGT1ijWaW43RZgFZT1/s72-c/gawker-top-250.png" height="72" width="72"/><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8927794127513218467.post-943676559340316723</id><published>2011-04-10T04:12:00.000+02:00</published><updated>2011-04-10T08:48:03.319+02:00</updated><title type='text'>Get in a hot air balloon ride with Google Street View and Maps API</title><content type='html'>&lt;script src=&quot;http://connect.facebook.net/en_US/all.js#xfbml=1&quot;&gt;&lt;/script&gt;&lt;fb:like href=&quot;http://codebazaar.blogspot.com/2011/04/get-in-hot-air-balloon-ride-with-google.html&quot; show_faces=&quot;true&quot; width=&quot;450&quot; font=&quot;&quot;&gt;&lt;/fb:like&gt;&lt;br /&gt;
I have wanted to experiment the Google Maps API for a long time. So today I used it to create an animation replaying a hot air balloon trip I did in 2009 in Santa Rosa, California.&lt;br /&gt;
&lt;br /&gt;
Before I got into the balloon, I started the &lt;a href=&quot;http://mytracks.appspot.com/&quot;&gt;Google MyTracks&lt;/a&gt; application on my phone. It records your GPS coordinates and altitude periodically. I used this data, Google Street View and Maps API to create the following animation.&lt;br /&gt;
&lt;br /&gt;
&lt;input type=&quot;button&quot; onClick=&quot;startAnimation()&quot; value=&quot;Start Animation&quot;&gt;&lt;br /&gt;
&lt;div id=&quot;map-canvas&quot; style=&quot;width:600px; height:400px&quot;&gt;&lt;/div&gt;&lt;script type=&quot;text/javascript&quot; src=&quot;http://maps.google.com/maps/api/js?sensor=false&quot;&gt;&lt;/script&gt;&lt;br /&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
var MAP_CANVAS_DIV_ID = &#39;map-canvas&#39;;

var TIME_BETWEEN_UPDATES_MAX = 1000; //slow update
var TIME_BETWEEN_UPDATES_MIN = 300;  //fast update

var TAKE_OFF_POV_LIST = [
  {heading:20,  pitch:0,   zoom:4},{heading:20,  pitch:-5,  zoom:3},{heading:20,  pitch:-10, zoom:3},{heading:20,  pitch:-15, zoom:2},{heading:20, pitch:-20, zoom:2},{heading:20, pitch:-25, zoom:1},{heading:20, pitch:-30, zoom:1},{heading:20, pitch:-35, zoom:0},{heading:20, pitch:-40, zoom:0},{heading:20, pitch:-50, zoom:0},{heading:20, pitch:-60, zoom:0},{heading:20, pitch:-70, zoom:0},{heading:20, pitch:-80, zoom:0},{heading:20, pitch:-90, zoom:0},
];

var LLA_LIST= [
  {lg:-122.772163, lt:38.467121},{lg:-122.771675, lt:38.466976},{lg:-122.771484, lt:38.466850},{lg:-122.771400, lt:38.466766},{lg:-122.771362, lt:38.466644},{lg:-122.771255, lt:38.466476},{lg:-122.770973, lt:38.466240},{lg:-122.770546, lt:38.466118},{lg:-122.770493, lt:38.466080},{lg:-122.770317, lt:38.466045},{lg:-122.770218, lt:38.465919},{lg:-122.769943, lt:38.465828},{lg:-122.769608, lt:38.465813},{lg:-122.769341, lt:38.465752},{lg:-122.769211, lt:38.465698},{lg:-122.769173, lt:38.465649},{lg:-122.768806, lt:38.465542},{lg:-122.768677, lt:38.465450},{lg:-122.768578, lt:38.465420},{lg:-122.768555, lt:38.465366},{lg:-122.768265, lt:38.465172},{lg:-122.768082, lt:38.465122},{lg:-122.767906, lt:38.465130},{lg:-122.767807, lt:38.465103},{lg:-122.767776, lt:38.465061},{lg:-122.767792, lt:38.464985},{lg:-122.767723, lt:38.464909},{lg:-122.767708, lt:38.464825},{lg:-122.767471, lt:38.464607},{lg:-122.767303, lt:38.464512},{lg:-122.766640, lt:38.464256},{lg:-122.765892, lt:38.464115},{lg:-122.765556, lt:38.463951},{lg:-122.765106, lt:38.463650},{lg:-122.764442, lt:38.463322},{lg:-122.764153, lt:38.463093},{lg:-122.763969, lt:38.462990},{lg:-122.763786, lt:38.462967},{lg:-122.762344, lt:38.462025},{lg:-122.761871, lt:38.461674},{lg:-122.761208, lt:38.461288},{lg:-122.761009, lt:38.461105},{lg:-122.760544, lt:38.460865},{lg:-122.760155, lt:38.460442},{lg:-122.758858, lt:38.459450},{lg:-122.758034, lt:38.458717},{lg:-122.757828, lt:38.458584},{lg:-122.757706, lt:38.458466},{lg:-122.757515, lt:38.458355},{lg:-122.757408, lt:38.458332},{lg:-122.757294, lt:38.458233},{lg:-122.757011, lt:38.458141},{lg:-122.756775, lt:38.458000},{lg:-122.756523, lt:38.457787},{lg:-122.755623, lt:38.457157},{lg:-122.755074, lt:38.456680},{lg:-122.754410, lt:38.455975},{lg:-122.754082, lt:38.455700},{lg:-122.753883, lt:38.455582},{lg:-122.753586, lt:38.455257},{lg:-122.753189, lt:38.454735},{lg:-122.752846, lt:38.454372},{lg:-122.752342, lt:38.453945},{lg:-122.751938, lt:38.453678},{lg:-122.751343, lt:38.453194},{lg:-122.750679, lt:38.452717},{lg:-122.750252, lt:38.452347},{lg:-122.749603, lt:38.451874},{lg:-122.749390, lt:38.451672},{lg:-122.749130, lt:38.451607},{lg:-122.748878, lt:38.451477},{lg:-122.748840, lt:38.451439},{lg:-122.748871, lt:38.451214},{lg:-122.748734, lt:38.451042},{lg:-122.748695, lt:38.450920},{lg:-122.748627, lt:38.450932},{lg:-122.748566, lt:38.450859},{lg:-122.748184, lt:38.450813}, // top 1 - 77
  {lg:-122.748024, lt:38.450722},{lg:-122.747688, lt:38.450645},{lg:-122.747131, lt:38.450748},{lg:-122.746979, lt:38.450737},{lg:-122.746437, lt:38.450565},{lg:-122.746185, lt:38.450603},{lg:-122.746078, lt:38.450577},{lg:-122.745979, lt:38.450684},{lg:-122.745789, lt:38.450726},{lg:-122.745598, lt:38.450680},{lg:-122.745537, lt:38.450710},{lg:-122.745506, lt:38.450882},{lg:-122.745392, lt:38.451015},{lg:-122.745392, lt:38.451103},{lg:-122.745338, lt:38.451122},{lg:-122.745331, lt:38.451176}, // bottom 1 - 93
  {lg:-122.745285, lt:38.451210},{lg:-122.745399, lt:38.451199},{lg:-122.745407, lt:38.451462},{lg:-122.745453, lt:38.451500},{lg:-122.745537, lt:38.451435},{lg:-122.745583, lt:38.451462},{lg:-122.745682, lt:38.451397},{lg:-122.745644, lt:38.451500},{lg:-122.745522, lt:38.451557},{lg:-122.745445, lt:38.451664},{lg:-122.745430, lt:38.451714},{lg:-122.745506, lt:38.451870},{lg:-122.745506, lt:38.451923},{lg:-122.745407, lt:38.452309},{lg:-122.745461, lt:38.452530},{lg:-122.745636, lt:38.452877},{lg:-122.745697, lt:38.452900}, //110
  {lg:-122.745705, lt:38.452953},{lg:-122.746078, lt:38.453480},{lg:-122.746315, lt:38.453690},{lg:-122.746384, lt:38.453854},{lg:-122.746475, lt:38.453945},{lg:-122.746788, lt:38.454399},{lg:-122.746918, lt:38.454514},{lg:-122.747200, lt:38.454670},{lg:-122.747292, lt:38.454819},{lg:-122.747574, lt:38.454880},{lg:-122.748085, lt:38.455082},{lg:-122.748100, lt:38.455124},{lg:-122.748299, lt:38.455208},{lg:-122.748390, lt:38.455368},{lg:-122.748520, lt:38.455479},{lg:-122.748772, lt:38.455811},{lg:-122.749100, lt:38.456097},{lg:-122.749344, lt:38.456375},{lg:-122.749687, lt:38.456657},{lg:-122.749817, lt:38.456799},{lg:-122.749962, lt:38.456841},{lg:-122.750092, lt:38.456921},{lg:-122.750237, lt:38.457172},{lg:-122.750366, lt:38.457218},{lg:-122.750343, lt:38.457199},{lg:-122.750458, lt:38.457417},{lg:-122.750450, lt:38.457462},{lg:-122.750496, lt:38.457508},{lg:-122.750534, lt:38.457626},{lg:-122.750511, lt:38.457668},{lg:-122.750572, lt:38.457684},{lg:-122.750481, lt:38.457577},{lg:-122.750443, lt:38.457657},{lg:-122.750458, lt:38.457699},{lg:-122.750397, lt:38.457718},{lg:-122.750427, lt:38.457760},{lg:-122.750389, lt:38.457798},{lg:-122.750488, lt:38.457916},{lg:-122.750542, lt:38.458069},{lg:-122.750816, lt:38.458450},{lg:-122.751160, lt:38.458794},{lg:-122.751366, lt:38.458961},{lg:-122.751404, lt:38.459057},{lg:-122.751549, lt:38.459145},{lg:-122.751579, lt:38.459190},{lg:-122.751587, lt:38.459244},{lg:-122.751350, lt:38.459305},{lg:-122.751427, lt:38.459412},{lg:-122.751602, lt:38.459545},{lg:-122.751610, lt:38.459602},{lg:-122.751572, lt:38.459698},{lg:-122.751648, lt:38.459911},{lg:-122.751625, lt:38.460114},{lg:-122.751640, lt:38.460060},{lg:-122.751389, lt:38.460335},{lg:-122.751457, lt:38.460468},{lg:-122.751457, lt:38.460625},{lg:-122.751350, lt:38.460854},{lg:-122.751373, lt:38.460903},{lg:-122.751564, lt:38.460880},{lg:-122.751389, lt:38.461040},{lg:-122.751358, lt:38.461102},{lg:-122.751419, lt:38.461132},{lg:-122.751373, lt:38.461182},{lg:-122.751572, lt:38.461208},{lg:-122.751862, lt:38.461300},{lg:-122.751953, lt:38.461300},{lg:-122.752075, lt:38.461243},{lg:-122.752121, lt:38.461273},{lg:-122.752235, lt:38.461197},{lg:-122.752258, lt:38.461212},{lg:-122.752266, lt:38.461330},{lg:-122.752373, lt:38.461502},{lg:-122.752342, lt:38.461548},{lg:-122.752388, lt:38.461578},{lg:-122.752403, lt:38.461632},{lg:-122.752457, lt:38.461628},{lg:-122.752480, lt:38.461884},{lg:-122.752411, lt:38.462158},{lg:-122.752304, lt:38.462234},{lg:-122.752029, lt:38.462238},{lg:-122.751526, lt:38.462303},{lg:-122.751198, lt:38.462399},{lg:-122.750572, lt:38.462368},{lg:-122.750107, lt:38.462379},{lg:-122.749832, lt:38.462322},{lg:-122.749611, lt:38.462227},{lg:-122.749413, lt:38.462208},{lg:-122.749100, lt:38.462105}, //top 2 - 199
  {lg:-122.748596, lt:38.461899},{lg:-122.748482, lt:38.461815},{lg:-122.748108, lt:38.461685},{lg:-122.746880, lt:38.461411},{lg:-122.746605, lt:38.461304},{lg:-122.746239, lt:38.461090},{lg:-122.745697, lt:38.460987},{lg:-122.745232, lt:38.460842},{lg:-122.744835, lt:38.460682},{lg:-122.744225, lt:38.460484},{lg:-122.742981, lt:38.459980},{lg:-122.742203, lt:38.459713},{lg:-122.741837, lt:38.459610},{lg:-122.740707, lt:38.459503},{lg:-122.740105, lt:38.459373},{lg:-122.739464, lt:38.459187},{lg:-122.738762, lt:38.458855},{lg:-122.737259, lt:38.458424},{lg:-122.735687, lt:38.457897},{lg:-122.735649, lt:38.457985},{lg:-122.735458, lt:38.458096},{lg:-122.735252, lt:38.458084},{lg:-122.735268, lt:38.457989},{lg:-122.735184, lt:38.458023},{lg:-122.735092, lt:38.457943},{lg:-122.735031, lt:38.457829},{lg:-122.735092, lt:38.457668},{lg:-122.735039, lt:38.457687},{lg:-122.734901, lt:38.457581},{lg:-122.734863, lt:38.457546},{lg:-122.734863, lt:38.457443},{lg:-122.734772, lt:38.457401},{lg:-122.734756, lt:38.457310},{lg:-122.734695, lt:38.457275},{lg:-122.734222, lt:38.457500},{lg:-122.734146, lt:38.457520},{lg:-122.733925, lt:38.457481},{lg:-122.733879, lt:38.457520},{lg:-122.733772, lt:38.457481},{lg:-122.732864, lt:38.456966},{lg:-122.732773, lt:38.456875},{lg:-122.732254, lt:38.456558},{lg:-122.731712, lt:38.456284},{lg:-122.731155, lt:38.455910},{lg:-122.729774, lt:38.455284},{lg:-122.729599, lt:38.455177},{lg:-122.728394, lt:38.454765},{lg:-122.727791, lt:38.454590},{lg:-122.726524, lt:38.454079},{lg:-122.725983, lt:38.453934},{lg:-122.725189, lt:38.453545},{lg:-122.724068, lt:38.453033},{lg:-122.723549, lt:38.452717},{lg:-122.723259, lt:38.452812},{lg:-122.723022, lt:38.452785},{lg:-122.722839, lt:38.452717},{lg:-122.722687, lt:38.452728},{lg:-122.722466, lt:38.452812},{lg:-122.722443, lt:38.452919},{lg:-122.722359, lt:38.452991},{lg:-122.722092, lt:38.453033},{lg:-122.721977, lt:38.453079},{lg:-122.721870, lt:38.453033},{lg:-122.721939, lt:38.453209},{lg:-122.721985, lt:38.453217}, //bottom 2
];

var streetViewPanorama;

//see google.maps.MaxZoomService getMaxZoomAtLatLng(latlng:LatLng, callback:function(MaxZoomResult)))

function initialize() {
  
  var mapDiv = document.getElementById(MAP_CANVAS_DIV_ID);
  
  streetViewPanorama = new google.maps.StreetViewPanorama(mapDiv, {
    position: new google.maps.LatLng(LLA_LIST[0].lt, LLA_LIST[0].lg),  pov: TAKE_OFF_POV_LIST[0],  addressControl: false,  zoomControl: false,  scrollwheel: false,  panControl: false,  linksControl: false
  });
}

function startAnimation() {
 moveToNextPOV(0, streetViewPanorama);
}

function moveToNextPOV(cnt, streetViewPanorama) {
  cnt ++;
  if (cnt &gt;= TAKE_OFF_POV_LIST.length ) {
    switchToMap();
  } else {
    streetViewPanorama.setPov(TAKE_OFF_POV_LIST[cnt]);
    window.setTimeout(function(){moveToNextPOV(cnt, streetViewPanorama)}, TIME_BETWEEN_UPDATES_MAX );
  }  
}
                      
function switchToMap() {
  var mapDiv = document.getElementById(MAP_CANVAS_DIV_ID);
    
  var map = new google.maps.Map(mapDiv, {
    center: new google.maps.LatLng(LLA_LIST[0].lt, LLA_LIST[0].lg),  zoom: getZoom(0) ,  mapTypeId: google.maps.MapTypeId.SATELLITE,  disableDefaultUI: true
  });
    
  window.setTimeout(function(){moveToNextLLA(0, map)}, getTimeBetweenAnimation(0) );
}

function moveToNextLLA(cnt, map) {
  cnt ++;
  if (cnt == LLA_LIST.length ) {
    alert(&quot;You arrived at destination ;-)&quot;);
  } else {
    addLine(cnt, map);
    map.panTo(new google.maps.LatLng(LLA_LIST[cnt].lt, LLA_LIST[cnt].lg));
    map.setZoom( getZoom(cnt) ); 
    window.setTimeout(function(){moveToNextLLA(cnt, map)}, getTimeBetweenAnimation(cnt));
  }  
}
                      
function addLine(cnt, map) {
      
  var lnlPath = [
      new google.maps.LatLng(LLA_LIST[cnt-1].lt, LLA_LIST[cnt-1].lg),    new google.maps.LatLng(LLA_LIST[cnt].lt,   LLA_LIST[cnt].lg)
  ];
    
  var line = new google.maps.Polyline({
    path: lnlPath,  strokeColor: &#39;#ffd700&#39;,  strokeOpacity: 0.5,  strokeWeight: 3
  });

  line.setMap(map);
}

function getTimeBetweenAnimation(cnt) {
 var timeBetweenAnimationFrame = 0;
 var coefficient = TIME_BETWEEN_UPDATES_MAX - TIME_BETWEEN_UPDATES_MIN;
 if ( cnt &lt;= 10 ) {
  timeBetweenAnimationFrame = TIME_BETWEEN_UPDATES_MAX - coefficient * (cnt / 10);
 } else if ( cnt &gt;= LLA_LIST.length - 10 ) {
  timeBetweenAnimationFrame = TIME_BETWEEN_UPDATES_MIN + (coefficient * cnt);
 } else {
  timeBetweenAnimationFrame = TIME_BETWEEN_UPDATES_MIN;
 }
 return timeBetweenAnimationFrame;
}

function getZoom(x) {
 if ( 0 &lt;= x &amp;&amp; x &lt;= 77 ) {
  return Math.floor( 20 + (14-20)*(x-0)/(77-0) );
 } else if ( 77 &lt; x &amp;&amp; x &lt;= 93 ) {
  return Math.floor( 14 + (19-14)*(x-77)/(93-77) );
 } else if ( 93 &lt; x &amp;&amp; x &lt;= 199 ) {
  return Math.floor( 19 + (15-19)*(x-93)/(199-93) );
 } else {
  return Math.floor( 15 + (20-15)*(x-199)/(264-199) );
 }
}

initialize();
&lt;/script&gt;

It is fairly easy to start programming with this API. The &lt;a href=&quot;http://code.google.com/apis/ajax/playground/?exp=libraries#animate_v3&quot;&gt;Google Code Playground&lt;/a&gt; was a very useful resource of API examples. 

You can find the implementation details in the source code of this page. The following summarizes the main points of the implementation.


The animation is in a DIV element:
&lt;pre class=&quot;brush:js&quot;&gt;
&lt;div id=&quot;map-canvas&quot; style=&quot;width:600px; height:400px&quot;&gt;

&lt;/div&gt;&lt;/pre&gt;The first thing I do in the script is to obtain a JS reference to this object:
&lt;pre class=&quot;brush:js&quot;&gt;
  var mapDiv = document.getElementById(&quot;map-canvas&quot;);
&lt;/pre&gt;Then I instantiate the StreetViewPanorama class with some GPS coordinates:
&lt;pre class=&quot;brush:js&quot;&gt;
streetViewPanorama = new google.maps.StreetViewPanorama(
    mapDiv, {
        position: new google.maps.LatLng(
            latitude, 
            longitude,  
            pov: { /*pov stands for point of view*/
                heading:20, /*in degrees, relative to the north*/ 
                pitch:0,   
                zoom:4},
            /* hide all controls */  
            addressControl: false,  
            zoomControl: false,  
            scrollwheel: false,  
            panControl: false,  
            linksControl: false
    });
&lt;/pre&gt;To update the point of view, I call the following method every few milliseconds.
&lt;pre class=&quot;brush:js&quot;&gt;
streetViewPanorama.setPov({ heading:20, pitch:0, zoom:4 } );
&lt;/pre&gt;After the hot air balloon takes off, the animation switches to Google Maps.
&lt;pre class=&quot;brush:js&quot;&gt;
  var map = new google.maps.Map(mapDiv, {
    center: new google.maps.LatLng(latitude, longitude),
    zoom: 20 ,  
    mapTypeId: google.maps.MapTypeId.SATELLITE,  
    disableDefaultUI: true
  });
&lt;/pre&gt;To move the map and simulate the balloon movement, I call the following methods with new coordinates:
&lt;pre class=&quot;brush:js&quot;&gt;
map.panTo( new google.maps.LatLng(latitude, longitude ));
map.setZoom( newZoom );
&lt;/pre&gt;&lt;br /&gt;
The animation is quite shaky. I could actually get a better result using the Google Earth API, but this will be for a later post ;-)</content><link rel='replies' type='application/atom+xml' href='http://codebazaar.blogspot.com/feeds/943676559340316723/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/8927794127513218467/943676559340316723?isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8927794127513218467/posts/default/943676559340316723'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8927794127513218467/posts/default/943676559340316723'/><link rel='alternate' type='text/html' href='http://codebazaar.blogspot.com/2011/04/get-in-hot-air-balloon-ride-with-google.html' title='Get in a hot air balloon ride with Google Street View and Maps API'/><author><name>Matt Buchner</name><uri>http://www.blogger.com/profile/03993705703169676412</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGJBh157km2WvcRk9Fd0alqVRHYw3pldCvcehZRPx8NXBkVlqWclPGMXjjvP_CKoYtUwPQECmIfijWZo-2-O64i5ogn-LI4qplVUgMixVlbsXwbJgQrwlSr44Wxp3Cr4o/s113/headshot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8927794127513218467.post-7593397519788569901</id><published>2011-04-05T07:36:00.000+02:00</published><updated>2011-04-07T14:59:46.546+02:00</updated><title type='text'>Analyzing data from Twitter feeds</title><content type='html'>&lt;script src=&quot;http://connect.facebook.net/en_US/all.js#xfbml=1&quot;&gt;
&lt;/script&gt;&lt;fb:like font=&quot;&quot; href=&quot;http://codebazaar.blogspot.com/2011/04/analyzing-data-from-twitter-feeds.html&quot; show_faces=&quot;true&quot; width=&quot;450&quot;&gt;&lt;/fb:like&gt;&lt;br /&gt;
On average &lt;a href=&quot;http://blog.twitter.com/2011/03/numbers.html&quot;&gt;1 billion tweets&lt;/a&gt; are being posted per week. This gigantic amount of data represents a great opportunity to analyze live trends and opinions... if you can filter out the data you are looking for. &lt;br /&gt;
&lt;br /&gt;
I attended &lt;a href=&quot;http://schedule.sxsw.com/events/event_IAP5656&quot;&gt;a very interesting conference at SXSW&lt;/a&gt; that enticed me to try this out. The idea is to pull some data from social media websites (Twitter in this example) and analyze them.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6e1Jj2ujsiRnzL61EXtpWGs3GjHv5w1fJp3iC27dEkQfSf7UvEV8uWyL7t85fZoJUqI43hzOTTrXvtpG-1hGRPJAz16X34lOpNWkeYzMT8NVGb7u3IaZnHpfX73kJHqCKgDylkEIXONEZ/s1600/twitterdatacrunching.png&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;64&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6e1Jj2ujsiRnzL61EXtpWGs3GjHv5w1fJp3iC27dEkQfSf7UvEV8uWyL7t85fZoJUqI43hzOTTrXvtpG-1hGRPJAz16X34lOpNWkeYzMT8NVGb7u3IaZnHpfX73kJHqCKgDylkEIXONEZ/s320/twitterdatacrunching.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
I hacked a little program to download tweets, to store them in a database and to run some basic analysis on these data. It is using &lt;a href=&quot;http://twitter4j.org/&quot;&gt;twitter4j&lt;/a&gt; and &lt;a href=&quot;http://code.google.com/p/sqlite4java/&quot;&gt;sqlite4java&lt;/a&gt;. The source code is available upon request.&lt;br /&gt;
&lt;br /&gt;
My original plan was to download all tweets posted during the SXSW conference containing the word SXSW. Unfortunately, Twitter limits their search results to 1500 tweets per day, so I was not able to download them all. That&#39;s why I decided to narrow my search to all tweets posted during the time of the&amp;nbsp;&lt;a href=&quot;http://schedule.sxsw.com/events/event_IAP000264&quot;&gt;final keynote&lt;/a&gt; and at the Austin Convention Center using the GPS coordinates. With these new filters, I was able to retrieve 2600 tweets in 2 days.&lt;br /&gt;
&lt;br /&gt;
First, I counted the numbers of occurrence for each word. After excluding all the common punctuations, prepositions, articles and numbers, I looked at the most common words used in these tweets:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVvDsXxjsL8i0wkjvXr_7W4xYuj6xUUP5dzvRmzpJPHAPF4W_NpLEg1oJlFxdhhmpfpHD2TeIG1GqchTXaig8T22Vrasum5qYOGiIvFukaDUaYYKjLGuy2jY4yx2f13LEXzsChWafdhF0g/s1600/twitter_top_20_words.png&quot; imageanchor=&quot;1&quot; style=&quot;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;247&quot; width=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVvDsXxjsL8i0wkjvXr_7W4xYuj6xUUP5dzvRmzpJPHAPF4W_NpLEg1oJlFxdhhmpfpHD2TeIG1GqchTXaig8T22Vrasum5qYOGiIvFukaDUaYYKjLGuy2jY4yx2f13LEXzsChWafdhF0g/s400/twitter_top_20_words.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
The words that are tweeted the most are the users&#39; location (i.e. Austin, Convention, Center), followed by the particulars of the keynote speaker-- Blake Mycoskie.&lt;br /&gt;
&lt;br /&gt;
Only a few words are being tweeted repeatedly. Out of the 4840 words my program counted, 97% of them were used 20 times or less as you can see below.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_QiqMJ0cqLcV_zk7kxG6zdqiOMIKGPd8ZJEeAI-vBGrgwUnEEW4rHu2JvsbF5cVxaqKjSTm3VAZCt5tZzfuZvRdZCXc6ZfFkwEqWU3mo1VmszpJhfyeUj-Db0lG8paPb6pexMPx-beKzv/s1600/twitter_vocabulary_diversity.png&quot; imageanchor=&quot;1&quot; style=&quot;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;247&quot; width=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_QiqMJ0cqLcV_zk7kxG6zdqiOMIKGPd8ZJEeAI-vBGrgwUnEEW4rHu2JvsbF5cVxaqKjSTm3VAZCt5tZzfuZvRdZCXc6ZfFkwEqWU3mo1VmszpJhfyeUj-Db0lG8paPb6pexMPx-beKzv/s400/twitter_vocabulary_diversity.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
The vocabulary diversity chart above demonstrates that the words occurring more than 20 times are representative of the tweeting trend at that time and place.&lt;br /&gt;
&lt;br /&gt;
At this point, it was still very hard to determine what is the trend/opinion specific to the keynote. The program was still processing many tweets that are not related to the content of the keynote itself. So I decided to add another filter to select only the tweets that contain at least one of the following word: Blake, Mycoskie, TOMS or shoes.&amp;nbsp;I also used &lt;a href=&quot;http://wordnetcode.princeton.edu/standoff-files/core-wordnet.txt&quot;&gt;a dictionary of the 5000 most commonly used words&lt;/a&gt; from the Princeton university to filter out the results.&lt;br /&gt;
&lt;br /&gt;
With this new filters, the following words stood out:&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-size: large;&quot;&gt;great&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;amazing&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;giving&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;story&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;june&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;1for1&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: center;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-size: large;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;This may be a little simplistic but as a conclusion I would say that the attendees of the keynote speech:&lt;br /&gt;
- enjoyed the speech (great, amazing, story)&lt;br /&gt;
- understood the concept of TOMS business and were willing to share it (giving, 1for1)&lt;br /&gt;
- were excited to share the &lt;a href=&quot;http://www.youtube.com/watch?v=PmZ1iEmrExg&quot;&gt;coming announcement on June 7th&lt;/a&gt;&amp;nbsp;(june).&lt;br /&gt;
&lt;br /&gt;
This post is the result of a few long nights of coding and analyzing. There are a lot more advanced works publicly available. You may be interested in the following links:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt; &lt;a href=&quot;http://www.hpl.hp.com/research/scl/papers/socialmedia/socialmedia.pdf&quot;&gt;Predicting the Future With Social Media&lt;/a&gt;&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www2.selu.edu/Academics/Faculty/aculotta/pubs/culotta10detecting.pdf&quot;&gt;Detecting inﬂuenza outbreaks by analyzing Twitter messages&lt;/a&gt;&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href=&quot;http://www.google.com/search?q=twitter+analyze+filetype:pdf&quot;&gt;... and many more&lt;/a&gt;&lt;br /&gt;
&lt;/li&gt;
&lt;/ul&gt;</content><link rel='replies' type='application/atom+xml' href='http://codebazaar.blogspot.com/feeds/7593397519788569901/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/8927794127513218467/7593397519788569901?isPopup=true' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8927794127513218467/posts/default/7593397519788569901'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8927794127513218467/posts/default/7593397519788569901'/><link rel='alternate' type='text/html' href='http://codebazaar.blogspot.com/2011/04/analyzing-data-from-twitter-feeds.html' title='Analyzing data from Twitter feeds'/><author><name>Matt Buchner</name><uri>http://www.blogger.com/profile/03993705703169676412</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGJBh157km2WvcRk9Fd0alqVRHYw3pldCvcehZRPx8NXBkVlqWclPGMXjjvP_CKoYtUwPQECmIfijWZo-2-O64i5ogn-LI4qplVUgMixVlbsXwbJgQrwlSr44Wxp3Cr4o/s113/headshot.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6e1Jj2ujsiRnzL61EXtpWGs3GjHv5w1fJp3iC27dEkQfSf7UvEV8uWyL7t85fZoJUqI43hzOTTrXvtpG-1hGRPJAz16X34lOpNWkeYzMT8NVGb7u3IaZnHpfX73kJHqCKgDylkEIXONEZ/s72-c/twitterdatacrunching.png" height="72" width="72"/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8927794127513218467.post-5427924902276377227</id><published>2011-03-29T06:58:00.000+02:00</published><updated>2011-04-15T00:46:36.628+02:00</updated><title type='text'>How to automate tasks in Photoshop with JavaScript</title><content type='html'>&lt;script src=&quot;http://connect.facebook.net/en_US/all.js#xfbml=1&quot;&gt;&lt;/script&gt;&lt;fb:like href=&quot;http://codebazaar.blogspot.com/2011/03/how-to-build-animated-gif-with.html&quot; show_faces=&quot;true&quot; width=&quot;450&quot; font=&quot;&quot;&gt;&lt;/fb:like&gt;&lt;br /&gt;
I recently learned it is possible to control Adobe Photophop in JavaScript, so I tried it out! From this article, I hope you will learn how to get started with Photoshop scripting.&lt;br /&gt;
&lt;br /&gt;
Photoshop is able to record your manual actions into a JavaScript. To enable this feature:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;copy the file ScriptingListenerJS.8LI from C:\Program Files\Adobe\Adobe Photoshop CS5\Scripting\Utilities to C:\Program Files\Adobe\Adobe Photoshop CS5\Plug-ins\Automate&lt;/li&gt;
&lt;li&gt;restart Photoshop&lt;/li&gt;
&lt;li&gt;start manipulating Photoshop&lt;/li&gt;
&lt;/ul&gt;A file ScriptingListenerJS.txt should be created on your Desktop. I opened an image and resized it, here is the script generated:&lt;br /&gt;
&lt;pre class=&quot;brush:js&quot;&gt;// =======================================================
var idOpn = charIDToTypeID( &quot;Opn &quot; );
    var desc1 = new ActionDescriptor();
    var idnull = charIDToTypeID( &quot;null&quot; );
    desc1.putPath( idnull, new File( &quot;C:\\codebazaar\\3x3gifmaker\\input\\IMG_5032.JPG&quot; ) );
executeAction( idOpn, desc1, DialogModes.NO );

// =======================================================
var idImgS = charIDToTypeID( &quot;ImgS&quot; );
    var desc2 = new ActionDescriptor();
    var idWdth = charIDToTypeID( &quot;Wdth&quot; );
    var idPxl = charIDToTypeID( &quot;#Pxl&quot; );
    desc2.putUnitDouble( idWdth, idPxl, 3000.000000 );
    var idscaleStyles = stringIDToTypeID( &quot;scaleStyles&quot; );
    desc2.putBoolean( idscaleStyles, true );
    var idCnsP = charIDToTypeID( &quot;CnsP&quot; );
    desc2.putBoolean( idCnsP, true );
    var idIntr = charIDToTypeID( &quot;Intr&quot; );
    var idIntp = charIDToTypeID( &quot;Intp&quot; );
    var idBcbc = charIDToTypeID( &quot;Bcbc&quot; );
    desc2.putEnumerated( idIntr, idIntp, idBcbc );
executeAction( idImgS, desc2, DialogModes.NO );
&lt;/pre&gt;&lt;br /&gt;
A script helps to automate repetitive tasks in Photoshop. You can use the generated code as a starting point to do so.&lt;br /&gt;
&lt;br /&gt;
Adobe also offers an API. For example, I built a script executing the following operations:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;ask the user to select a folder&lt;/li&gt;
&lt;li&gt;open all the images present in the selected folder&lt;/li&gt;
&lt;li&gt;resize all the images&lt;/li&gt;
&lt;li&gt;copy/cut and paste all the images into different layers&lt;/li&gt;
&lt;li&gt;build a GIF animation &lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
The complete script is available for download &lt;a href=&quot;http://www.box.net/shared/brg64nd1nv&quot;&gt;here&lt;/a&gt;. &lt;br /&gt;
&lt;br /&gt;
To run the script:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;open Adobe Extended Toolkit&lt;/li&gt;
&lt;li&gt;in the dropdown menu at the top left of the window, select Adobe Photoshop&lt;/li&gt;
&lt;li&gt;in the menu, select File, then Open and select the script to execute&lt;/li&gt;
&lt;li&gt;in the menu, select Debug, Run (or press F5)&lt;/li&gt;
&lt;li&gt;Photoshop will ask to select a folder containing the images to process&lt;/li&gt;
&lt;li&gt;then you can see Photoshop executing all the tasks coded in the script&lt;/li&gt;
&lt;/ul&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2fKjOHw5Tj5EhaaTmoR7vBCMKqbp8ekPCRtbQ0VjoJyzf-UA7TF1QaCr5WIqK4QMgt14K1N3DUccBDXqbVWUDYrVfFXLdDHpNZKcj_HCLkNLRhY6vU-XFxNlwhmG-QHysn46SslCyaP-G/s1600/adobe-extended-toolkit-screenshot.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;182&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2fKjOHw5Tj5EhaaTmoR7vBCMKqbp8ekPCRtbQ0VjoJyzf-UA7TF1QaCr5WIqK4QMgt14K1N3DUccBDXqbVWUDYrVfFXLdDHpNZKcj_HCLkNLRhY6vU-XFxNlwhmG-QHysn46SslCyaP-G/s320/adobe-extended-toolkit-screenshot.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;This is a screenshot of Adobe Extended Toolkit. It allows you to set breakpoints, view the local variables as you are debugging and inspect the call stack&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;I did not find how to automatically set the time interval between each animation frame, so I manually had to do this step and save the animation (File, Save for Web &amp;amp; Device, Save).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The following image has been generated by the script.&lt;br /&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://lh3.googleusercontent.com/LFnYccUkziODa2bPr-nB8S5W4dyfBI-avnjTEIeRzmTHI4qLbYYd6Vbflel2A0O0flnkeHjUTVx4_a4IiC9N4BVtvg=s512&quot; /&gt;&lt;/div&gt;The API allows to write a code that is more concise and easier to read than the code generated by Photoshop. In some cases I was not always able to find what method to use from the API to execute a specific action, so I recorded some of these actions and incorporated the generated code into my script.&lt;br /&gt;
&lt;br /&gt;
Here are some web sites I found useful:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://www.adobe.com/devnet/photoshop/scripting.html&quot;&gt;&lt;b&gt;adobe.com - Photoshop Scripting API and documentation&lt;/b&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.adobepress.com/articles/article.asp?p=433750&quot;&gt;&lt;b&gt;adobepress.com - Learn How to Script Adobe Photoshop CS2&lt;/b&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.ps-scripts.com/index.html&quot;&gt;&lt;b&gt;ps-scripts.com - The Photoshop Scripting Community&lt;/b&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://photoshoptutorials.ws/photoshop-tutorials/technical/manipulate-an-image-with-scripting.html&quot;&gt;&lt;b&gt;photoshoptutorials.ws - Manipulate an Image with Scripting&lt;/b&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://morris-photographics.com/photoshop/tutorials/index.html&quot;&gt;&lt;b&gt;morris-photographics.com - Trevor Morris - Scripting Photoshop tutorials&lt;/b&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.kirupa.com/motiongraphics/ps_scripting.htm&quot;&gt;&lt;b&gt;kirupa.com - Photoshop Scripting tutorials&lt;/b&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.mydamnchannel.com/You_Suck_at_Photoshop/Season_1/YouSuckAtPhotoshop1DistortWarpandLayerEffects_1373.aspx&quot;&gt;&lt;b&gt;mydamnchannel.com - You suck at Photoshop&lt;/b&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
Also, if you don&#39;t get dizzy by looking at this animation, you can try this &lt;a href=&quot;http://html5demos.com/video-canvas&quot;&gt;one&lt;/a&gt; made in HTML 5.</content><link rel='replies' type='application/atom+xml' href='http://codebazaar.blogspot.com/feeds/5427924902276377227/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/8927794127513218467/5427924902276377227?isPopup=true' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8927794127513218467/posts/default/5427924902276377227'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8927794127513218467/posts/default/5427924902276377227'/><link rel='alternate' type='text/html' href='http://codebazaar.blogspot.com/2011/03/how-to-build-animated-gif-with.html' title='How to automate tasks in Photoshop with JavaScript'/><author><name>Matt Buchner</name><uri>http://www.blogger.com/profile/03993705703169676412</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGJBh157km2WvcRk9Fd0alqVRHYw3pldCvcehZRPx8NXBkVlqWclPGMXjjvP_CKoYtUwPQECmIfijWZo-2-O64i5ogn-LI4qplVUgMixVlbsXwbJgQrwlSr44Wxp3Cr4o/s113/headshot.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2fKjOHw5Tj5EhaaTmoR7vBCMKqbp8ekPCRtbQ0VjoJyzf-UA7TF1QaCr5WIqK4QMgt14K1N3DUccBDXqbVWUDYrVfFXLdDHpNZKcj_HCLkNLRhY6vU-XFxNlwhmG-QHysn46SslCyaP-G/s72-c/adobe-extended-toolkit-screenshot.png" height="72" width="72"/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8927794127513218467.post-3729991246812397586</id><published>2010-11-04T01:07:00.000+01:00</published><updated>2011-04-02T15:45:21.317+02:00</updated><title type='text'>Monkey see, GreaseMonkey do!</title><content type='html'>&lt;script src=&quot;http://connect.facebook.net/en_US/all.js#xfbml=1&quot;&gt;&lt;/script&gt;&lt;fb:like href=&quot;http://codebazaar.blogspot.com/2010/11/monkey-see-greasemonkey-do.html&quot; show_faces=&quot;true&quot; width=&quot;450&quot; font=&quot;&quot;&gt;&lt;/fb:like&gt;&lt;br /&gt;
&lt;a href=&quot;http://en.wikipedia.org/wiki/Greasemonkey&quot;&gt;&lt;b&gt;GreaseMonkey&lt;/b&gt;&lt;/a&gt; has been around for quite a while, but it is not known as much as it should! Originally, it started as a&lt;span class=&quot;Apple-style-span&quot;&gt; &lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/748/&quot;&gt;&lt;b&gt;browser extension for Firefox&lt;/b&gt;&lt;/a&gt;&lt;/span&gt;&amp;nbsp;but the userscripts are now&amp;nbsp;natively&amp;nbsp;&lt;a href=&quot;http://blog.chromium.org/2010/02/40000-more-extensions.html&quot;&gt;&lt;b&gt;supported in Chrome&lt;/b&gt;&lt;/a&gt;.&lt;br /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;In this video tutorial, I will&amp;nbsp;talk about:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;What GreaseMonkey is&lt;/li&gt;
&lt;li&gt;How I used it&lt;/li&gt;
&lt;li&gt;Fews tips regarding the development of userscript&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;&lt;br /&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;&lt;object height=&quot;344&quot; width=&quot;425&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://www.youtube.com/v/hAeWOOJPp0o?fs=1&amp;amp;hl=en_US&quot;&gt;&lt;/param&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot;&gt;&lt;/param&gt;&lt;param name=&quot;allowscriptaccess&quot; value=&quot;always&quot;&gt;&lt;/param&gt;&lt;embed src=&quot;http://www.youtube.com/v/hAeWOOJPp0o?fs=1&amp;amp;hl=en_US&quot; type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;true&quot; width=&quot;425&quot; height=&quot;344&quot;&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/div&gt;&lt;br /&gt;
The userscript I use as example is available here:&amp;nbsp;&lt;a href=&quot;http://userscripts.org/scripts/show/87653&quot;&gt;&lt;b&gt;http://userscripts.org/scripts/show/87653&lt;/b&gt;&lt;/a&gt;. userscript.org hosts about 60,000 userscripts as I am writing this! You can search the best rated or the most downloaded userscripts. The nature of the scripts that are available on this website is very diverse. It ranges from providing cheats on popular Facebook games to enhancing the look of your everyday news website.</content><link rel='replies' type='application/atom+xml' href='http://codebazaar.blogspot.com/feeds/3729991246812397586/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/8927794127513218467/3729991246812397586?isPopup=true' title='18 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8927794127513218467/posts/default/3729991246812397586'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8927794127513218467/posts/default/3729991246812397586'/><link rel='alternate' type='text/html' href='http://codebazaar.blogspot.com/2010/11/monkey-see-greasemonkey-do.html' title='Monkey see, GreaseMonkey do!'/><author><name>Matt Buchner</name><uri>http://www.blogger.com/profile/03993705703169676412</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGJBh157km2WvcRk9Fd0alqVRHYw3pldCvcehZRPx8NXBkVlqWclPGMXjjvP_CKoYtUwPQECmIfijWZo-2-O64i5ogn-LI4qplVUgMixVlbsXwbJgQrwlSr44Wxp3Cr4o/s113/headshot.jpg'/></author><thr:total>18</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8927794127513218467.post-8542083949205204390</id><published>2010-09-03T04:09:00.000+02:00</published><updated>2011-04-02T15:47:02.397+02:00</updated><title type='text'>Two Factor Authentication without the Overhead of Traditional OTP</title><content type='html'>&lt;script src=&quot;http://connect.facebook.net/en_US/all.js#xfbml=1&quot;&gt;&lt;/script&gt;&lt;fb:like href=&quot;http://codebazaar.blogspot.com/2010/09/i-published-with-two-colleagues-from.html&quot; show_faces=&quot;true&quot; width=&quot;450&quot; font=&quot;&quot;&gt;&lt;/fb:like&gt;&lt;br /&gt;
My colleagues and I published a paper where we discussed our design of a two-factor authentication taylored to lower the cost without compromising the security.&lt;br /&gt;
&lt;br /&gt;
Here is the abtract: &quot;&lt;i&gt;This paper describes a simple security architecture that supports two factor authentication for accessing Internet resources. Instead of utilizing the complex traditional OTP frameworks, which can be cumbersome to both deploy and use, we present a software architecture based on a shared knowledge between a token and a remote Internet resource; such as a web server. The confidentiality of this shared knowledge is protected by the smart card embedded in the token. The approach is explained in the context of initial token setup and a practical use-case for two factor online authentication. Despite its simplicity, this software optimization provides a comparable level of security for asserting the identity of users.&lt;/i&gt;&quot;&lt;br /&gt;
&lt;br /&gt;
We presented it at the &lt;a href=&quot;http://www.iasted.org/conferences/pastinfo-669.html&quot;&gt;&lt;b&gt;13th IASTED International Conference on Software Engineering and Applications 2009&lt;/b&gt;&lt;/a&gt;&amp;nbsp;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: Times; font-size: 31px; white-space: nowrap;&quot;&gt;&lt;span style=&quot;font-size: 25px;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Times New Roman&#39;;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-size: medium; white-space: normal;&quot;&gt;in Cambridge, MA.&lt;/span&gt;&lt;/span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;The full paper is also available on &lt;a href=&quot;http://actapress.com/&quot;&gt;&lt;b&gt;actapress.com&lt;/b&gt;&lt;/a&gt;, but it is not free :/</content><link rel='replies' type='application/atom+xml' href='http://codebazaar.blogspot.com/feeds/8542083949205204390/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/8927794127513218467/8542083949205204390?isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8927794127513218467/posts/default/8542083949205204390'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8927794127513218467/posts/default/8542083949205204390'/><link rel='alternate' type='text/html' href='http://codebazaar.blogspot.com/2010/09/i-published-with-two-colleagues-from.html' title='Two Factor Authentication without the Overhead of Traditional OTP'/><author><name>Matt Buchner</name><uri>http://www.blogger.com/profile/03993705703169676412</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGJBh157km2WvcRk9Fd0alqVRHYw3pldCvcehZRPx8NXBkVlqWclPGMXjjvP_CKoYtUwPQECmIfijWZo-2-O64i5ogn-LI4qplVUgMixVlbsXwbJgQrwlSr44Wxp3Cr4o/s113/headshot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8927794127513218467.post-1202880205850876720</id><published>2010-09-03T03:50:00.000+02:00</published><updated>2011-04-02T15:48:38.380+02:00</updated><title type='text'>We are featured on the GWT blog!</title><content type='html'>&lt;script src=&quot;http://connect.facebook.net/en_US/all.js#xfbml=1&quot;&gt;&lt;/script&gt;&lt;fb:like href=&quot;http://codebazaar.blogspot.com/2010/09/link-to-my-teams-guest-blog-post-on.html&quot; show_faces=&quot;true&quot; width=&quot;450&quot; font=&quot;&quot;&gt;&lt;/fb:like&gt;&lt;br /&gt;
I met Patrick Chanezon, Google developer advocate, at the &lt;a href=&quot;http://www.google.com/events/sxsw2010/hackathon.html&quot;&gt;&lt;b&gt;Google Hackathon in SXSW 2010&lt;/b&gt;&lt;/a&gt;.&amp;nbsp;As a former engineer at Sun, he has a clear understanding of the world of smart card. I showed him my team&#39;s work, where we married&lt;b&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;color: white;&quot;&gt; &lt;/span&gt;&lt;/b&gt;&lt;a href=&quot;http://code.google.com/webtoolkit/&quot;&gt;&lt;b&gt;GWT&lt;/b&gt;&lt;/a&gt;&amp;nbsp;and smart cards in an innovative application.&lt;br /&gt;
&lt;br /&gt;
Here is a video where Patrick interviewed me to talk about my company &lt;a href=&quot;http://gemalto.com/&quot;&gt;&lt;b&gt;Gemalto&lt;/b&gt;&lt;/a&gt;, &amp;nbsp;my team&#39;s work and explained how GWT helps us to meet our various project requirements.&lt;br /&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;&lt;object height=&quot;344&quot; style=&quot;background-image: url(http://i2.ytimg.com/vi/uPzuILcsERk/hqdefault.jpg);&quot; width=&quot;425&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://www.youtube.com/v/uPzuILcsERk?fs=1&amp;amp;hl=en_US&quot;&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot;&gt;&lt;param name=&quot;allowscriptaccess&quot; value=&quot;always&quot;&gt;&lt;embed src=&quot;http://www.youtube.com/v/uPzuILcsERk?fs=1&amp;amp;hl=en_US&quot; width=&quot;425&quot; height=&quot;344&quot; allowScriptAccess=&quot;never&quot; allowFullScreen=&quot;true&quot; wmode=&quot;transparent&quot; type=&quot;application/x-shockwave-flash&quot;&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/div&gt;&lt;br /&gt;
In addition to the video, our team was invited to guest blog on the&lt;span class=&quot;Apple-style-span&quot; style=&quot;color: white;&quot;&gt; &lt;/span&gt;&lt;a href=&quot;http://googlewebtoolkit.blogspot.com/2010/06/todays-guest-blog-post-comes-from.html&quot;&gt;&lt;b&gt;Google GWT blog&lt;/b&gt;&lt;/a&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;color: white;&quot;&gt; &lt;/span&gt;to share more application design and programming tips.</content><link rel='replies' type='application/atom+xml' href='http://codebazaar.blogspot.com/feeds/1202880205850876720/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/8927794127513218467/1202880205850876720?isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8927794127513218467/posts/default/1202880205850876720'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8927794127513218467/posts/default/1202880205850876720'/><link rel='alternate' type='text/html' href='http://codebazaar.blogspot.com/2010/09/link-to-my-teams-guest-blog-post-on.html' title='We are featured on the GWT blog!'/><author><name>Matt Buchner</name><uri>http://www.blogger.com/profile/03993705703169676412</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGJBh157km2WvcRk9Fd0alqVRHYw3pldCvcehZRPx8NXBkVlqWclPGMXjjvP_CKoYtUwPQECmIfijWZo-2-O64i5ogn-LI4qplVUgMixVlbsXwbJgQrwlSr44Wxp3Cr4o/s113/headshot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8927794127513218467.post-5617793911753160223</id><published>2010-08-22T23:37:00.000+02:00</published><updated>2011-04-02T15:49:05.721+02:00</updated><title type='text'>Video tutorial for JNI</title><content type='html'>&lt;script src=&quot;http://connect.facebook.net/en_US/all.js#xfbml=1&quot;&gt;&lt;/script&gt;&lt;fb:like href=&quot;http://codebazaar.blogspot.com/2010/08/package-codebazaar.html&quot; show_faces=&quot;true&quot; width=&quot;450&quot; font=&quot;&quot;&gt;&lt;/fb:like&gt;&lt;br /&gt;
&lt;div&gt;JNI (Java Native Interface) allows the communication between a JAVA program and a native program (C, C++). The objective of this first blog post is to give you a quick introduction to this technology. Hopefully, after reading this post and watching the video, you should be able to:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;set up your own environment with Eclipse and Visual Studio&lt;/li&gt;
&lt;li&gt;create a program using JNI&lt;/li&gt;
&lt;li&gt;debug while switching between JAVA and native code&lt;/li&gt;
&lt;li&gt;avoid memory leaks&lt;/li&gt;
&lt;li&gt;understand the risk of JVM crash&lt;/li&gt;
&lt;/ul&gt;&lt;div&gt;&lt;insert&gt;&lt;/insert&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;object height=&quot;385&quot; width=&quot;480&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://www.youtube.com/v/vmRUqajLIuM?fs=1&amp;amp;hl=en_US&quot;&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot;&gt;&lt;param name=&quot;allowscriptaccess&quot; value=&quot;always&quot;&gt;&lt;embed src=&quot;http://www.youtube.com/v/vmRUqajLIuM?fs=1&amp;amp;hl=en_US&quot; type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;true&quot; width=&quot;480&quot; height=&quot;385&quot;&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
I used Eclipse and Microsoft Visual Studio for this demonstration. Eclipse is a popular development IDE for JAVA. You can download it for free on &lt;a href=&quot;http://www.eclipse.org/&quot;&gt;&lt;b&gt;http://www.eclipse.org/&lt;/b&gt;&lt;/a&gt;. Visual Studio Express is the free version of Visual Studio and it is available here: &lt;a href=&quot;http://www.microsoft.com/express/&quot;&gt;&lt;b&gt;http://www.microsoft.com/express&lt;/b&gt;/&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
The example is using two classes Bean and JniExample. JniExample loads the native library (JniExampleLibrary.dll) and exposes the native methods implemented in the DLL. The bean is used to demonstrate how to exchange data through JNI.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;We used javah.exe to generate the header file declaring the native methods in the DLL as defined in JniExample.java. The command line is:&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: monospace; font-size: 100%;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-size: 13px; white-space: pre;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: Georgia, serif; font-size: 130%;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-size: 16px; white-space: normal;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;pre class=&quot;brush:plain&quot;&gt;javah -d C:\codebazaar\JniExample\cpp\JniExample codebazaar.example.JniExample
&lt;/pre&gt;We also used javap.exe to generate the method signatures. The command line is:&lt;br /&gt;
&lt;pre class=&quot;brush:plain&quot;&gt;javap -s codebazaar.example.JniExample
&lt;/pre&gt;As your program may evolve, I recommend you to save these commands as external tools in eclipse.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
To debug the library and the JAVA, in Visual Studio go to Debug, select Attach to Process, find javaw.exe and click on the Attach button.&lt;/div&gt;&lt;br /&gt;
As in any native code, you need to pay a special attention to memory leak. In the case of JNI, the JVM takes care of most of the job. Any instance passed to or returned by the DLL will be freed by the JVM. You need to free a buffer only if it has been allocated outside the JVM.&lt;br /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;Finally, we demonstrated how to get the JVM crash... That was the easy part :D If you are considering communicating with a native library from your web application, you need to realize that a problem in the native library might take the whole server down. As this is not great in term of avaibility, you may consider running the native library on a separate web server.&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;
I uploaded all the &lt;a href=&quot;http://www.box.net/shared/a22u7f56fe&quot;&gt;&lt;b&gt;source code&lt;/b&gt;&lt;/a&gt; used. But you can view it directly from here:&lt;br /&gt;
&lt;pre class=&quot;brush:java&quot;&gt;package codebazaar.example;

public class Bean {
//public members
public String dataString; 
public byte[] dataByteArray;

public Bean() {}

//getters and setters
public String getDataString() {
return dataString;
}

public void setDataString(String dataString) {
this.dataString = dataString;
}

public byte[] getDataByteArray() {
return dataByteArray;
}

public void setDataByteArray(byte[] dataByteArray) {
this.dataByteArray = dataByteArray;
} 

@Override
public String toString(){
String ret = &quot;string = &quot; + dataString;

ret += &quot; / byteArray =&quot;;
if ( dataByteArray != null ) {
for ( byte b : dataByteArray) {
ret += &quot; &quot; + b;
}
}

return  ret; 
}
}
&lt;/pre&gt;&lt;br /&gt;
&lt;pre class=&quot;brush:java&quot;&gt;package codebazaar.example;

public class JniExample {
static {
System.loadLibrary(&quot;JniExampleLibrary&quot;);
}

// native methods
/**
* this method calls printSomething
*/
public native void callJavaMethod();

/**
* this method creates an instance of Bean and returns it
*/
public native Bean createAndReturnBean();

/**
* this method takes an instance of Bean as parameter and changes the value of its members
*/
public native void modifyBean(Bean bean);

/**
* this method will the JVM when invoked 
*/
public native void crashTheJvm();

public void printSomething() {
System.out.println(&quot;Thanks for watching this video&quot;);
}

public void runExample1() {
System.out.println(&quot;starting runExample1...&quot;);
callJavaMethod();
}

public void runExample2() {
System.out.println(&quot;starting runExample2...&quot;);

Bean bean = createAndReturnBean();
System.out.println(&quot;returned= &quot; + bean.toString());
}

public void runExample3() {
System.out.println(&quot;starting runExample3...&quot;);

Bean bean = new Bean();
bean.setDataString(&quot;hello&quot;);

byte[] byteArray = new byte[] { 0x01, 0x02, 0x03 };
bean.setDataByteArray(byteArray);

System.out.println(&quot;before: &quot; + bean.toString());
modifyBean(bean);
System.out.println(&quot;after: &quot; + bean.toString());
}

public void runExample4() {
System.out.println(&quot;starting runExample4...&quot;);
crashTheJvm();
}
}
&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:java&quot;&gt;package codebazaar.example;

public class Main {

/**
* @param args
*/
public static void main(String[] args) {
System.out.println(&quot;Starting JavaMain...&quot;);

JniExample jniExample = new JniExample();
jniExample.runExample1();
jniExample.runExample2();
jniExample.runExample3();
jniExample.runExample4();
}

}
&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:c++&quot;&gt;/* DO NOT EDIT THIS FILE - it is machine generated */
#include &lt;jni.h&gt;
/* Header for class codebazaar_example_JniExample */

#ifndef _Included_codebazaar_example_JniExample
#define _Included_codebazaar_example_JniExample
#ifdef __cplusplus
extern &quot;C&quot; {
#endif
/*
* Class:     codebazaar_example_JniExample
* Method:    callJavaMethod
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_codebazaar_example_JniExample_callJavaMethod
(JNIEnv *, jobject);

/*
* Class:     codebazaar_example_JniExample
* Method:    createAndReturnBean
* Signature: ()Lcodebazaar/example/Bean;
*/
JNIEXPORT jobject JNICALL Java_codebazaar_example_JniExample_createAndReturnBean
(JNIEnv *, jobject);

/*
* Class:     codebazaar_example_JniExample
* Method:    modifyBean
* Signature: (Lcodebazaar/example/Bean;)V
*/
JNIEXPORT void JNICALL Java_codebazaar_example_JniExample_modifyBean
(JNIEnv *, jobject, jobject);

/*
* Class:     codebazaar_example_JniExample
* Method:    crashTheJvm
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_codebazaar_example_JniExample_crashTheJvm
(JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif
&lt;/jni.h&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:c++&quot;&gt;#include &quot;codebazaar_example_JniExample.h&quot;
#include &lt;cstring&gt;

JNIEXPORT void JNICALL Java_codebazaar_example_JniExample_callJavaMethod (JNIEnv * env, jobject obj) {
jclass jniExampleCls = env-&amp;gt;GetObjectClass(obj);

jmethodID mid = env-&amp;gt;GetMethodID(jniExampleCls, &quot;printSomething&quot;, &quot;()V&quot;);

env-&amp;gt;CallVoidMethod(obj, mid);
}

JNIEXPORT jobject JNICALL Java_codebazaar_example_JniExample_createAndReturnBean  (JNIEnv *env, jobject obj) {
jclass beanClass = env-&amp;gt;FindClass(&quot;codebazaar/example/Bean&quot;);
jmethodID constructorMethodId = env-&amp;gt;GetMethodID(beanClass, &quot;&lt;init&gt;&quot;, &quot;()V&quot;); 
jobject bean = env-&amp;gt;NewObject(beanClass, constructorMethodId);

jstring newString = env-&amp;gt;NewStringUTF(&quot;this bean has been created in Java_codebazaar_example_JniExample_createAndReturnBean&quot;);

jmethodID setStringMid = env-&amp;gt;GetMethodID(beanClass, &quot;setDataString&quot;, &quot;(Ljava/lang/String;)V&quot;);

env-&amp;gt;CallVoidMethod(bean, setStringMid, newString );

return bean;
}

JNIEXPORT void JNICALL Java_codebazaar_example_JniExample_modifyBean  (JNIEnv *env, jobject obj, jobject bean) {
jclass beanCls = env-&amp;gt;GetObjectClass(bean);

jmethodID setStringMid = env-&amp;gt;GetMethodID(beanCls, &quot;setDataString&quot;, &quot;(Ljava/lang/String;)V&quot;);

// set the bean member &quot;dataString&quot;
jstring newString = env-&amp;gt;NewStringUTF(&quot;world&quot;);
env-&amp;gt;CallVoidMethod(bean, setStringMid, newString );

// set the bean member &quot;dataByteArray&quot;
jbyteArray newByteArray = env-&amp;gt;NewByteArray(5);
jbyte buffer[5] = {5,4,3,2,1};
env-&amp;gt;SetByteArrayRegion( newByteArray, 0, 5, buffer);

jmethodID setByteArrayMid = env-&amp;gt;GetMethodID(beanCls, &quot;setDataByteArray&quot;, &quot;([B)V&quot;);

env-&amp;gt;CallVoidMethod(bean, setByteArrayMid, newByteArray );
}


JNIEXPORT void JNICALL Java_codebazaar_example_JniExample_crashTheJvm (JNIEnv *env, jobject obj) {
//stack overflow - http://en.wikipedia.org/wiki/Stack_overflow
double x[1000000];
}&lt;/init&gt;&lt;/cstring&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
UPDATE 04/02/11:&lt;br /&gt;
If you encounter the following error:&lt;br /&gt;
&lt;pre class=&quot;brush:plain&quot;&gt;java.lang.UnsatisfiedLinkError: ${path here}/library.dll: This application has failed to start because the application configuration is incorrect. Reinstalling the application may fix this problem
&lt;/pre&gt;I would recommend you to use &lt;a href=&quot;http://www.dependencywalker.com/&quot;&gt;Dependency Walker&lt;/a&gt; to verify your DLL can find all its dependencies. If you are missing msvcr90.dll, you may be missing the &lt;a href=&quot;http://www.microsoft.com/downloads/en/details.aspx?FamilyID=9b2da534-3e03-4391-8a4d-074b9f2bc1bf&amp;displaylang=en&quot;&gt;Microsoft Redistributable Merge Modules&lt;/a&gt;.</content><link rel='replies' type='application/atom+xml' href='http://codebazaar.blogspot.com/feeds/5617793911753160223/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/8927794127513218467/5617793911753160223?isPopup=true' title='25 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8927794127513218467/posts/default/5617793911753160223'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8927794127513218467/posts/default/5617793911753160223'/><link rel='alternate' type='text/html' href='http://codebazaar.blogspot.com/2010/08/package-codebazaar.html' title='Video tutorial for JNI'/><author><name>Matt Buchner</name><uri>http://www.blogger.com/profile/03993705703169676412</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGJBh157km2WvcRk9Fd0alqVRHYw3pldCvcehZRPx8NXBkVlqWclPGMXjjvP_CKoYtUwPQECmIfijWZo-2-O64i5ogn-LI4qplVUgMixVlbsXwbJgQrwlSr44Wxp3Cr4o/s113/headshot.jpg'/></author><thr:total>25</thr:total></entry></feed>