Kaikki on kiinni tekniikasta, ei voimasta. Liikkuvia osia on paljon: tukijalan paikka ja asento, potkaisevan jalan liike ja asento, ylävartalon asento, nilkkalukko, käsien asento, potkun saatto ja liikkeen jatkuminen.
Tärkeimpiä asioita on potkaiseminen pallon läpi, ei palloon. Potkaisevan jalan liike jatkuu pitkälle potkun jälkeen ja koko kroppa jatkaa askeleen eteenpäin ja usein laskeudutaan potkaisevalle jalalle. Tällöin saadaan koko kropasta voimaa potkuun. Tukijalka ei siis jää paikalleen ja ime energiaa.
Nilkka lukkoon
Joustava nilkka imee energiaa kuin pallon lyöminen patongilla. Nilkkaa ei ole helppoa pitää lukossa. Toisille se tulee ajattelematta, toisten pitää keskittyä siihen, kunnes se tulee automaattisesti. Kun nilkka on jäykkänä, muu jalasta pitää olla edelleen normaalin rentona. Jos osumapaikka on nilkan yläosassa, ison luun kohdalla, lukko ei ole niin tärkeä, koska siinä ei ole joustoa ilmankaan sitä. Osumapaikoista enemmän alempana.
Ohjeita nilkan treenaamiseen:
Lukkotesti ja ohjeita:
Muita perusasioita:
Palloa pitäisi potkia mahdollisimman paljon liikkeessä. Harjoittele kuitenkin alkuasentoja laittamalla pallo tiettyyn paikkaan ja merkkaa tukijalan paikka. Kokeile sitten eri paikkoja tukijalalle, potkaisevan jalan asentoa ja potkuasentoa, kunnes löytyy sopiva yhdistelmä. Vauhdinotto on yksilöllistä, mutta yleensä etäisyys on 3-5 askelta taakse ja 1-3 sivulle. Nämä ovat yksilöllisiä asioita eikä voi suoraan sanoa, että ”tee juuri näin”
Yleisiä perusasioita on kuitenkin monta:
pitkä viimeinen askel luo lisää voimaa. Älä sipsuta pallolle.
potkaisevan jalan swingin pituus tuo lisää energiaa. Nosta nilkka polven yli.
tukijalka osoittaa kohti maalia
kun pallo liikkuu, tukijalan paikassa on otettava huomioon, että pallo ehtii liikkua lisää ennen potkun osumista. Eli tukijalka normaalia edemmäksi.
pidä katse pallossa
Ja vielä kertauksena yllä mainitut asiat:
nilkka lukkoon
tukijalka joustaa
liike pallon läpi
kädet tasapainottavat
potku pallon läpi
Potkaisevan jalan asento ja osumapaikka nilkassa määräävät sen miten pallo lähtee. Jos tukijalkasi on betonipylväs eikä liiku potkun jälkeen, harjoittele hyppäämällä tukijalalla, kun potkaiset. Potkaisemista voi auttaa kropan nostaminen ylemmäksi varvastamalla 2 viimeistä askelta ennen potkua.
Kropan asento potkaistaessa
Vino asento ei ole toki pakollinen ja sekin on yksilöllistä. Vinous auttaa saamaan potkaisevan jalan tarpeeksi alas ja estää ojentunutta, lukittua nilkkaa osumasta maahan. Vastapuolen ojentunut käsi auttaa tasapainottamaan.
Kropan asento potkun jälkeen
Potkun jälkeen potkaiseva jalka ei pysähdy vaan jatkaa matkaa pallon läpi. Saatto tuo myös energiaa sen pituus ja suunta ylä/alakierrettä. Vetoon saa lisää energiaa, kun sivulla ollut käsi tekee vastaliikeen potkaisevan jalan kanssa.
Hieman tämän vaiheen jälkeen tukijalka irtoaa maasta ja laskeudutaan potkaisevalle jalalle.
Korkeat/pitkät keskityspallot ja maalipotkut
Korkeaa palloa varten jalka on saatava pallon alle. Tämä onnistuu joustamalla tukijalan polvesta, viemällä tukijalka hieman kauemmaksi pallosta ja kääntämällä potkaisevaa jalkaterää enemmän sivuttain.
Jousta potkaisevalla jalalla, jolloin lonkka laskee ja sen liike suuntautuu eteen. Pitkä viimeinen askel kasvattaa myös liike-energiaa eteenpäin.
Osumakohta jalassa on melko alhaalla, jopa päkiän kohdalla. Tämä on taas yksilöllistä. Alempi osumakohta joustaa enemmän, joten nilkkalukon tärkeys korostuu. Vedä olkapäät taakse ja tasapainoita vastakkaisella kädellä.
Harjoitellessa paikallaan olevaan palloon ota 3-4 askelta taa, 1-2 sivulle ja lähesty noin 45 asteen kulmassa.
Vinkki: takakierrettä saa lisää pyyhkäisemällä potkun jälkeen potkaisevaa jalkaa sivuttain. Oikeaa jalkaa vasemmalle ja päinvastoin vasenjalkaisille.
Tukijalan paikka on korkeissa palloissa kauempana.
Osumakohta alhaalla ja nilkka hieman käännettynä alaspäin:
Jousta tukijalasta
Hyvä teoriavideo:
Ohjeita lonkan ja yläkropan käyttöön:
Esimerkkejä rennosta chippauksesta:
Kovat laukaukset
Erona edelliseen eli korkeisiin potkuihin:
tukijalka lähellä
polvi pallon päällä
yläkroppa mukaan eli rinta eteen ja ylös
ei takakenoa
Osumapaikan pitäisi olla mahdollisimman kova osa nilkasta. Tämä on yleensä nauhojen yläosassa hieman jalan sisäpuolella oleva iso luu.
Potkaiseva jalka suunnilleen tässä asennossa, mutta tarkka asento on yksilöllistä!
Tukijalka lähellä osumakohta hieman keskikohtaa alempana.
Harjoittelua:
Hyvä video tekniikasta:
Toinen hyvä video tekniikasta:
Suomenkielinen video tekniikasta. Toisin kuin muissa, osumapaikka on eri. Yksilöllistähän se on.
Harjoittelujärjestys
Liike läpi. Pompauta palloa parin kanssa ja potkaise hieman ilmassa olevaan palloon, niin että jatkat matkaa ja pallo jatkaa eteen eikä ylös. Potkaiseva jalka jatkaa matkaa kovaa eteenpäin.
Tukijalka mukaan. Jos tukijalkasi jää paikalleen, harjoittele hyppäämällä ilmaan.
Nilkka lukkoon! Harjoittele kentän ulkopuolellakin, vaikka vessanpöntöllä.
Käännä nilkkaa jotta osumakohta on oikein. Toista niin kauan, että liike on sulava. Löydä sinulle sopivat asennot vaihtelemalla tukijalan paikkaa ja joustamalla sen polvesta.
Kädet mukaan! Voima vaatii energiaa ja vauhtia ja niitä pitää tasapainottaa.
Potki palloa ensin paikaltaan samanlaisissa olosuhteissa, jotta voit korjata yhtä asiaa kerralla.
Opettele rentoutta. Yliyrittäminen pilaa suurimman osan yrityksistä.
Täydellisten henkilötietojen tallentaminen pitäisi kieltää ja sen sijaan tarjota ilmainen ja turvallinen Facebook-loginin tyyppinen tapa kirjautua palveluihin. Henkilötietoja ei tallennettaisi vaan ulkopuoliset tahot saisivat vain avaimia, joilla voi myöhemmin tarvittaessa hakea käyttäjän tietoja.
Identiteettini varastettiin jonkin aikaa sitten. Muutin hieman ennen ensimmäistä tietojen hyväksikäyttöä ja muutettaessahan osoitteeen lisäksi myös sosiaaliturvatunnus täytyy ilmoittaa muutamaan paikkaan. Osoitteen ja sotun yhdistelmällä saakin jo paljon pahaa aikaan. Varas teki lukuisia tilauksia tällä uudella osoitteellani eikä vanhalla, joten vuoto liittyi varmasti ilmoituksiin joita tein huoltoyhtiöille ja väestörekisterikeskukselle.
Ikäväkseni huomasin, että tavaroiden tilaaminen toisen tiedoilla on helppoa. Jotkut rahoitusyhtiöt eivät tarkasta edes luottotietoja vaan pistävät vain laskua perään. Eikä omia tietoja voi poistaa käytöstä tai kuolettaa mitenkään kuten luottokorttivarkauden yhteydessä. Omat luottotiedot voi tosin lukita, kunhan ensin tiedät, että niitä käytetään hyväksi. Siksi suosittelen ehdottomasti, että asetat tietovahdin luottotiedoillesi, jolloin tiedät heti luottotietokyselyiden lisääntyessä, että jotain on vialla.
Parissa viikossa tein useita rikosilmoituksia, jahtasin paketteja ja valvoin milloin luottotietojani on kyselty. Kaikki vain sen takia, että jostain rekisteristä voitiin nähdä täydelliset henkilötiedot. Kuten monesti käy, uhriksi joutuminen sai miettimään voisiko asioita tehdä paremmin!? Kyllä voisi eikä tässä tapauksessa tarvitsisi kuluttaa miljoonia ja keksiä pyörää uudelleen.
Onko tietoni tallennettava?
On selvää miksi esim. huoltoyhtiön pitää tietää sotu ja osoite. Mutta tarvitseeko tietojen itse asiassa olla tallennettuna heidän rekisterissään? Ties miten heikkojen tietosuojien takana ja käytännössä kenen vain luettavissa? Tietojahan tarvitaan harvoin, eikä niiden siksi tarvitsisi olla tallennettuna. EU:n uusi tietosuoja-asetus parantaa yksityisyyttämme, mutta perusongelma tietojemme tallentamisesta säilyy edelleen. Asetus lähinnä lisää omia oikeuksiamme hallita tietojamme.
Pitäisi olla keskitetty henkilötietorekisteri, josta tietoa jaetaan vain henkilön pyynnöstä tai erityisluvalla.
Kuulostaa vaikealta, kalliilta ja utopistiselta? Ei. Ajatellaan esimerkkinä vaikka Facebook-loginia. Samalla lailla voitaisiin rakentaa kirjautumis- ja tunnistautumisjärjestelmä, jonka avulla kirjaudutaan palveluihin ja luovutetaan vain haluttuja tietoja. Keskitetyssä rekisterissä olisi kattavat tiedot käyttäjästä ja vaikkapa kaksi kuvaa: virallinen kuva tunnistamiseen ja toinen, jaettavampi versio, käytettäväksi vaikka keskustelupalstoille. Käyttäjä itse hallinnoisi tietoja ja määrittelisi mitä ulkopuoliset palvelut saisivat lukea.
Need-to-know basis
Miten edellä mainittu case Huoltoyhtiö muuttuisi, jos rekisteristä kuitenkin luovutettaisiin sotu ja muut tiedot? Ideana olisi, että tietoja saisi lukea, mutta yksilöiviä tietoja, kuten sotua, ei ikinä luovutettaisi huoltoyhtiön tallennettavaksi. Lähes kaikissa tapauksissa riittää, että käyttäjä tunnistetaan ja voidaan tunnistaa myöhemmin uudelleen. Tämä tehdään antamalla palveluille vain yksilöiviä, salattuja avaimia, joilla henkilöllisyys voidaan tunnistaa myöhemmin. Ei anneta sotua tai muita hyväksikäytettäviä tietoja, joita voidaan lukea selkokielisesti ja käyttää hyväksi toisaalla.
Rekisteriä lukevien palveluiden pitäisi toki rekisteröityäkin eikä tietoja voi lukea kuka tahansa. Jokaisella palveluilla olisi oma tunniste ja yhdistämällä se käyttäjän tunnisteen kanssa palvelu saisi tämän salatun avaimen, jolla pääsisi myöhemmin käsiksi valittuihin tietoihin. Vuodon sattuessa tunnisteet voidaan resetoida. Joissain tapauksessa avain voisi olla kertakäyttöinen eivätkä toiset palvelut voisi käyttää toisten avaimia.
Käyttäjä menisi siis palveluun ja kirjautuisi rekisterin kautta juuri kuten Facebook- ja Google-loginit tekevät nykyään. Palvelu saisi varmennuksen, että käyttäjä on tunnistettu ja käyttäjään liittyvän avaimen. Tämän palvelu voi tallentaa. Toki käyttäjä voisi erikseen antaa nimimerkin tai muuta tietoja, joita myöskin tallennettaisiin palveluun. Verkkokauppojen tapauksessa voisi antaa luvan lukea kerran osoite eikä sitäkään tarvitsisi olla tallennettuna verkkokaupan rekistereissä. Saati sitten luottokortin numeroa.
Nykyään menet huoltoyhtiön verkkosivuille ja annat kaikki tietosi verkkolomakkeella. Kaikkialla näitä lomakkeita ei ole edes salattu. Uutta rekisteriä käytettäessä menisit huoltoyhtiön sivuille ja kirjautuisit rekisterin kautta ja tieto liikkuisi täysin turvallisesti:
Huoltoyhtiö tietää nyt riittävät perustiedot eli osoitteen, käyttäjän nimen sekä avaimen, joka on yhdistetty tähän käyttäjään.
Myöhemmin olet unohtanut avaimesi ja tarvitset huoltomiehen apua ja sinut pitää tietenkin tunnistaa. Nykyään huoltomies tarkistaa nimen, sotun ja osoitteen yhtiön omasta rekisteristä ja vertaa niitä vaikkapa ajokorttiin. Uudessa järjestelmässä sotua ei näe, joten varmistus tehdään rekisterin kautta. Nykyään SIM-kortteihin saa mobiilivarmenteen, joten tunnistamiseen voisi käyttää myös sitä.
Henkilötiedot on suojattava täysin
Täydellisten henkilötietojen avulla voidaan tehdä paljon ikäviä asioita. Väärinkäyttö lisääntyy jatkuvasti ja henkilöjen tietoja on yhä useammassa rekisterissä ja niitä vuotaa myös yhä useammin. Koska sotua ei voi vaihtaa, sitä ei pitäisi koskaan verkossa ilmoittaa missään. Käyttäjille luodaan palvelukohtaisen avaimen lisäksi sotua vastaava tunniste jota käytetään kuten sotua on käytetty tähän asti. Sen voisi halutessaan vaihtaa, jos tuntuu, että se on väärissä käsissä. Tunnisteen ei tarvitse olla ihan kryptattua, vaikeasti muistettavaa siansaksaa vaan se voisi olla vaikka etunimi.sukunimi.syntymävuosi.käyttäjän_valitsema_numerosarja. Tätä voisi käyttää puhelinpalveluissakin, jotka lyövät sen järjestelmäänsä ja käyttäjä varmistaa sitten sieltä tulleen varmistuspyynnön.
Tietojen lukemisesta pitää tulla ilmoitus
Käyttäjän pitää myös saada tietää, kun joku lukee hänen tietojaan. Viranomaiset, lääkärit ja vaikka pankitkin voisivat lukea käyttäjän tietoja ilman lupaa, mutta aina muuten tietojen lukemiseen pitää antaa lupa. Kaikissa tapauksissa lukemisesta jäisi tieto historiaan. Näin mahdollisia väärinkäyttöjä voi seurata.
Nykyiset varmenteet
Nykyäänhän on pankkien käyttämä tupas, Väestörekisterin kansalaisvarmenne ja monien teleoperaattoreiden tarjoama mobiilivarmenne. Ne toimivat kaikki erinomaisesti tunnistautumisessa ja osan avulla voi myös allekirjoittaa. Mutta ne välittävät monesti henkilötiedot eteenpäin.
Käyttäjän turvallinen varmentaminen on maksullista ja suurien massojen kanssa todella kallista, joten sitä ei haluta käyttää vaikka se olisi suositeltavaa ja järkevää. Niin kauan, kun ei ole halpaa tai ilmaista tapaa tehdä varmennuksia, ei voi myöskään verkkokauppoja velvoittaa tekemään niitä. Yhteiskunnan varoin rakennettu rekisteri säästäisi itsensä takaisin, koska rikosilmoitusten tutkinta ja oikeusprosessit maksavat paljon.
Mihin muuhun tunnistautumista voitaisiin käyttää?
Vahva ja varma tunnistus olisi tarpeen lukuisissa palveluissa ja sovelluksissa. Netissä on trollaajia, vihapuhetta ja monenlaisia huijareita, joita ei nykykeinoin saada kuriin tai valvottua. Varma tunnistus estää esimerkiksi rekisteröitymisen useampaan kertaan, jos käyttäjä kerran estetään.
Allekirjoitukset
On hämmästyttävää, että nimen raapustaminen paperiin on vieläkin käytössä varmenteena. Toisaalta digitaaliset allekirjoitukset ovat edelleen hankalia käyttää eikä yhtenäistä prosessia tai työkalua ole. Uudessa rekisterissä kaikki osapuolet olisivat jo varmennettuja, joten voidaan tarjota varma tapa tehdä digitaalinen allekirjoitus.
Käyttäjä A lähettää palveluun tiedoston, jonka käyttäjä B lukee ja verifioi tunnuksillaan. Tiedosto on tallennettuna järjestelmään eikä sitä ei voi muuttaa.
Vihapuheen vähentäminen
Jos keskustelupalstalle rekisteröidyttäisiin tämän kautta, käyttäjät eivät voisi tehdä useita tilejä tai lähettää viestejä ilman, että heidät voisi tarvittaessa tunnistaa. Nimimerkkejä voisi toki käyttää, mutta rikoskynnyksen ylittyessä viranomaiset saavat tietää kuka on kirjoittanut viestit. Trollaaminen, uhkaileminen jne vähentyisivät.
Hätäviestintä
Järjestelmä toimisi verkossa, mutta helppokäyttöisyyden lisäämiseksi siitä tehtäisiin myös applikaatio. Se tietäisi toki sijaintinsa ja sitä voisi käyttää sijaintiin liittyvien hätäviestien näyttämiseen. Se toimisi myös toiseen suuntaan viranomaisille, kun käyttäjä tarvitsisi apua.
Nettimyyjien verifiointi
Huutokaupat ja myyntipalstat ovat huijareiden vakiopaikkoja löytää uhreja. Palvelun kautta käyttäjät voisivat verifioida toisensa. Palveluun rekisteröityminen voisi tietenkin olla rekisterin kautta, jolloin käyttäjät on identifioitu varmuudella.
Taustatietojen tarkistus
Esimerkiksi eläintenpitokieltojen tarkistaminen ei ole niin kätevä prosessi, että eläinten myyjät sitä käyttäisivät. Palvelussa voisi olla tapa tarkistaa erilaisia taustatietoja. Kohteen pitäisi toki hyväksyä kysely.
Tiedostojen ja tietojen tallennus
Sähköiset reseptit, lääkärinlausunnot, sopimukset, asiakirjat ja muut tiedostot voisivat olla kaikki tässä palvelussa.
Sijaintitiedot
Palvelusta voisi tarkistaa asuuko käyttäjä tietyllä alueella. Tarkkaa sijaintia ei paljastettaisi, mutta esimerkiksi ”Kuopion alueen virkistystoiminta”-ryhmän jäseneksi pyrkiviltä voisi palvelusta kysyä sijaitseeko pyrkijä 30km säteellä Kuopiosta.
Maksaminen
Myöhemmässä vaiheessa palveluun voisi liittää kolmansien osapuolien rajapintoja kuten maksaminen. Verkkomaksamisesta saa paljon turvallisempaa mm. kertakäyttöisillä luottokorttinumeroilla, joita tarjoaa mm. Aktia Wallet. Tällaisten palveluiden integroinnista pitäisi tehdä helppoa.
Verifioitu viestintä
Sähköpostin käyttäminen on vähentynyt Facebookin ja WhatsAppin ansiosta. Se on nykyään lähes täysin työhön liittyvää viestintää ja suuri osa siitä on roskapostia ja mukana on paljon huijausviestejä ja phishingiä. Vain rekisteröidyt yritykset ja niiden verifioidut käyttäjät voisivat lähettää viestejä tässä järjestelmässä. Ei enää pankkitunnusten urkkimista tai spämmiä. Ja kaikki olisi kryptattua kuten WhatsApissa.
Mitä rakentaminen vaatii
Järjestelmän rakentamisessa ei ole sinänsä uutta, kun puhutaan vain rekisteröitymisestä ja henkilön varmistamisesta eikä maksamisesta tai tiedostojen tallentamisesta. Vastaavia järjestelmiä on jo, kuten monet sosiaalisten medioiden kirjautumisjärjestelmät. Tällaiset rajapinnat, joissa on vaikkapa oAuth-varmennus, ovat arkipäivää nykyään.
Jotta järjestelmän käyttöönotto olisi yrityksille ja palveluille helppoa, niin pitäisi toki tehdä kirjastot, joilla palvelua voi käyttää helposti. Tässäkään ei ole vielä mitään mullistavaa.
Jos järjestelmään halutaan ottaa mukaan allekirjoittaminen, maksaminen ja tiedostojen tallentaminen niin siihenkin on tullut varma ratkaisu: lohkoketjut.
Rekisterin hyödyt olisivat huimat ja niihin verrattuna kustannukset erittäin pienet. Kaikenlainen verkkorikollisuus vähenisi ja henkilötiedot olisivat täysin turvassa ja niiden käyttäminen olisi valvottua.
Turvallisesta tunnistautumisesta ja omien tietojen salaamisesta pitäisi tulla helppoa ja arkipäiväistä. Näin se onnistuisi.
I removed flickering of an 2400px wide element while animating it by adding -webkit-backface-visibility:hidden; to the CSS. It worked fine. Later on a collegue reported that the Safari of his iPhone4S crashes everytime a section of the page is renderer. I managed to pinpoint the crash to the that line in the CSS. The fix was to replace it with -webkit-transform:translate3d(0,0,0);. No flickering or crashing after that!
Listening to the scroll event with jQuery and resetting the scroll with window.scrollTo triggers a new scroll event on iOS. That of course resets the scroll again and trigger a new event and so on and so on… So don’t do this:
But changing the orientation of the device eventually caused the content to scroll mysteriously, so I added a simple JS to prevent scrolling. It worked on all other platforms.
I’ve used Modernizr to detect browser features. It’s easy and awesome. Now I’ve been developing a site and testing it with Windows Phone 8 with Internet Explorer 10. The new IE does not support touch events, it supports pointer events. That’s why IE10 has ”no-touch” class in the HTML element.
To detect touch capability with IE10 support, use:
Flash is still the best tool for online video and there are more and more gorgeous videos where external media like images from user’s Facebook profile are embedded to a video. World famous examples are Tackfilm, Take this lollipop and Lost in val Sinestra.
I participated in a similar campaign and our technical partner had a lot of problems with video sync. How can you tell with 100% reliability which video frame is currently shown? Zeh Fernando writes about possible solutions in this article. The solutions (and their cons) are:
– embedding the video inside a SWF and getting the current frame of that movieclip (very inconvenient and cumbersome)
– use Netstream’s time property (very inaccurate)
– use NetStream’s decodedFrames + droppedFrames (works until Flash player hangs for one frame or the video is restarted or rewinded)
– check cue points (requires old video codec)
Eric Decker came up with a better solution. Ingenious! Embed the the frame number to each frame with a barcode. Sounds very tedious, but quite easy task once the ExtendScript and ActionScript are ready. I didn’t find good examples, so I had to make one.
Frame numbers cannot be plain text, because decoding shapes would be too heavy for the CPU (nevermind the coder) and would not be 100% reliable. So the frame numbers are embedded as a binary number, ergo ones and zeros. My solution uses pixels of certain color, because it is very easy to get the color value of a pixel with ActionScript. If the color value exceeds a threshod value, the pixel equals ”1”. First I tried a simple 1px high row of pixels below the video, but compression causes pixels to blend with adjacent pixels so that is not even 70% reliable. So the blocks presenting binary value must be larger than 1*1px. In my tests even 3*3px blocks weren’t enough, if the compression is set to medium. 5×5 pixels with 7px gaps between blocks work with 100% reliability. I bet smaller gaps work too, but I didn’t test it.
Compression, and the blending caused by it, also fades the color, so the 100% color value (like 255,0,0 for pure red) cannot be used either. That’s why the AS3 script has a threshold parameter for the color value. If the parameter is 50, colors values decoded as ”1” would be 127 (255*50%) and above. You can easily test which threshold value is the best.
Here’s a screenshot of the video with some explanation:
The After Effects ExtendScript
I’ve never used After Effects before, but the script is so simple there probably isn’t a simpler way to add a barcode to a video. The script increases the height of the composition by certain amount (block height +bitOffsetFromBottom +bitOffsetFromTop) and adds a solid colored bar in that position. Then the number of frames is calculated from the frame rate and length of the video. That number is converted to binary (eg. 10010011) and one shape is added to the bar for each needed number (8 in this example).
The script adds an expression to each shape which controls the opacity of each shape as the playhead moves. Each shape is linked to a position in the binary number and if the number in that position is ”0” the opacity is 0 and vice versa.
The AS3 script
After the AE script is run, it shows an alert box with used parameters and those should be copied to Flash. This way the parameters between AE and AS3 match and you don’t have to set them by hand. Parameters are:
bitWidth: width of the shape
bitHeight: height of the shape
bitSpacing: : spacing between shapes
bgColor: background color
bitColor: shape color, this value is 0, 1 or 2. 0 indicates pure red, 1 pure green and 2 pure blue
bitOffsetFromBottom: shape distance from the bottom
bitOffsetFromTop: shape distance from the top of the background bar
AS3 has also the threshold parameter mentioned above.
It is also quite easy to test if the barcode works. The AS3 script warns if frames are skipped or the calculated frame number is smaller that previous, indicating that the barcode was calculated incorrectly. This is caused by too small shapes for the compression level and the solution is to increase the shape size and/or spacing.
One problem: the height of the video increases and we don’t want to show the binary shapes to the user. The AS3 script includes three solutions for this: mask the video, draw a shape over the barcode or capture each frame as a bitmap and cut off the barcode. Of course you can just make the height of the HTML element smaller and disable scaling.
Here is a demo. Note that I’ve added a text field to the video that displays the current frame as a binary. The AS3 script adds a textfield too that show the binary calculated from the shapes. This is just for debugging purposes and those can be disabled in AE and Flash.
Demo
Source files and downloads
Here’s the AE script:
{
// FrameNumberToBinary.jsx
// copyright Niko Helle, nikohelle.net
var bitWidth = 5; // width of the shape representing binary
var bitHeight = 8; // height of the shape representing binary
var bitSpacing = 7; // spacing between shapes
var bitBGHeight = 0; // do not set, calculated below
var bitColor = [1,0,0]; /// color of the shape [R,G,B] Use only full color values: [1,0,0] or [0,1,0] or [0,0,1]. Other values will not work.
var fillColor = [0,0,0]; /// color of the bar [R,G,B]
var bitOffsetFromTop = 3; // shape distance from the top of the bar
var bitOffsetFromBottom = 3; // shape distance from the bottom of the bar
function FrameNumbering(thisObj)
{
//calculate height of the bar
bitBGHeight = bitOffsetFromTop+bitHeight+bitOffsetFromBottom;
//get the composition
var firstComp = app.project.item(1);
//increase the height by the bar height
firstComp.height = firstComp.height+bitBGHeight;
// check if the there is enough space for the binary numbers. If shapes and spacing are wide, the numbers may not fit the video
if(!checkFrames(firstComp)){
return;
};
//create the bar
var bar = firstComp.layers.addSolid(fillColor,"bitBG", firstComp.width, bitBGHeight, 1)
// reset anchor for easier positioning
resetAnchor(bar);
//position the bar to the bottom of the composition
setPosition(bar,0,firstComp.height-bitBGHeight,false);
//create shapes
calcBits(firstComp,bitColor);
// determine which color is used, and alert it for the AS3, 0=R, 1=G, 2=B. Only solid, full colors can be used!
if(bitColor[0] == 1) bitColor = 0;
else if(bitColor[1] == 1) bitColor = 1;
else bitColor = 2;
//alert used parameters so they can be copied to AS3
var alertTxt = "Copy these values to the ActionScript file: \n";
alertTxt +="_bitWidth="+bitWidth+";\n";
alertTxt +="_bitHeight="+bitHeight+";\n";
alertTxt +="_bitSpacing="+bitSpacing+";\n";
alertTxt +="_bgHeight="+bitBGHeight+";\n";
alertTxt +="_bitColor="+bitColor+";\n";
alertTxt +="_bitOffsetFromBottom="+bitOffsetFromBottom+";\n";
alertTxt +="_bitOffsetFromTop="+bitOffsetFromTop+";\n";
alertTxt +="_frames="+(firstComp.frameRate*firstComp.duration)+";\n";
alert(alertTxt);
}
//sets position of an element
function setPosition(element,x,y,z){
var pos =element.transform.position.value;
if(x !== false) pos[0] = x;
if(y !== false) pos[1] = y;
if(z !== false) pos[2] = z;
element.transform.position.setValue(pos)
}
// resets anchor to top left corner
function resetAnchor(element){
element.transform.anchorPoint.setValue([0,0,0])
}
//calculate wether the binary fits the video
function checkFrames(comp){
var fps = comp.frameRate*comp.duration;
var bitSpace = bitWidth*bitSpacing;
var binaryLen = fps.toString(2).split("").length;
bitSpace = bitSpace*binaryLen;
if(bitSpace > comp.width) {
alert("The video is not wide enough for the bit size and spacing. Required width is "+bitSpace+"px and video is "+comp.width+"px wide.");
return false;
}
return true;
}
//create shapes
function calcBits(comp,bitColor){
var fps = comp.frameRate*comp.duration;
var bin = "1"+fps.toString(2);
var bit;
for(var i =0; i<bin.length;i++){
createBit(comp,bitColor,i)
}
}
//create shape
function createBit(comp,bitColor,pos){
var gfx = comp.layers.addSolid(bitColor,"bit"+pos, bitWidth, bitHeight, 1)
resetAnchor(gfx);
setPosition(gfx,comp.width-(bitWidth+bitSpacing)*(pos)-bitWidth,comp.height-bitHeight-bitOffsetFromBottom,false);
//add the expression
var expression = 'bitpos = '+pos+';frame = timeToFrames();frame = parseInt(frame,10).toString(2).split("").reverse().join("");if(frame.length < bitpos) bit = "0";else bit = frame.substr(bitpos,1);if(bit == "1") value = 100;else value = 0;';
gfx.opacity.expression = expression;
}
//run the code
FrameNumbering(this);
}
Here’s the AS3:
/*
Capture current frame from video with a barcode
Copyright Niko Helle, nikohelle.net
*/
package
{
import com.nhe.video.VideoPlayer;
import com.nhe.utils.Utils;
import com.nhe.utils.ContentLoader;
import flash.display.Sprite;
import flash.display.BitmapData;
import flash.display.Bitmap;
import flash.display.DisplayObject;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.text.TextFieldAutoSize;
import flash.events.Event;
import flash.geom.*;
public class Main extends Sprite
{
// ignore all variables
// set them in Main()
// or copy them from AE's alert box after the ExtendScript is run
private var _videoPlayer:VideoPlayer;
private var _cl:ContentLoader;
private var _blocker:Bitmap;
private var _view:Bitmap;
private var _bmd:BitmapData;
private var _byteSlice:Bitmap;
private var _tf:TextField;
private var _lastBin:int = -1;
private var _lastValues:Array = [];
private var _threshold:uint = 50;
private var _bgHeight:uint = 0;
private var _frames = 0;
private var _bitColor:uint = 0;
private var _bitWidth = 0;
private var _bitHeight = 0;
private var _bitSpacing = 0;
private var _bitOffsetFromBottom = 0;
private var _bitOffsetFromTop = 0;
public function Main() {
/* Copy below parameters from the AE alert window after you have run the script*/
_bitWidth=5;
_bitHeight=8;
_bitSpacing=7;
_bgHeight=14;
_bitColor=0;
_bitOffsetFromBottom=3;
_bitOffsetFromTop=3;
_frames=3600;
/* copy above */
// set the threshold. If the value is 50, pixel with color value of 255*50% ( = 127) or higher is decoded as "1"
_threshold = 50;
// calculate how many bits are used
_frames = _frames.toString(2).length;
//create a videoplayer
_videoPlayer = new VideoPlayer();
_videoPlayer.addEventListener(VideoPlayer.READY_TO_PLAY,video_READY_TO_PLAY);
_videoPlayer.addEventListener(VideoPlayer.PLAY_PROGRESS,video_PLAY_PROGRESS);
// load the video from given path
_videoPlayer.load("FrameNumberedVideo.flv");
//create a contentLoader and load an image with it if you want to test with a screen capture first
_cl = new ContentLoader();
_cl.addEventListener(Event.COMPLETE,cl_COMPLETE);
//_cl.load("screenshot.png");
}
// video is loaded, add trackers etc
public function video_READY_TO_PLAY(e:Event){
_videoPlayer.playVideo(1);
// 3 ways to remove bits from view:
// 1: addView (copies pixels from the video and never shows the actual video)
// 2: addBlocker adds a solid colored block over the added pixels
// 3. addMask masks the video
// add video child ONLY if addView is not used!!!
addChild(_videoPlayer);
//addView(_videoPlayer,_bgHeight);
//addBlocker(_videoPlayer,_bgHeight,0xffffff);
//addMask(_videoPlayer,_bgHeight);
// show the calculated binaries and frames number over the video
addBitTracker(_videoPlayer,_bgHeight);
// show the slice cut from the video that is used for detecting binaries. Slice is placed under the video
addByteSlice(_videoPlayer);
}
// image is loaded, calculate bits and frame
public function cl_COMPLETE(e:Event){
addChild(_cl.content);
//get the slice where bits are drawn and read
slice(_bmd,_cl.content,_bitHeight,_bitOffsetFromBottom);
//read bits
var pixelBits = readPixels(_bmd,_frames,_bitWidth,_bitSpacing,_bitColor,_threshold);
//covert to integer
var frame = parseInt(String(pixelBits), 2);
//trace(bin+"/"+pixelBits );
// see function video_READY_TO_PLAY for explanation about function class below
//addMask(_cl.content,_bgHeight);
//addBlocker(_cl.content,_bgHeight,0xffffff);
addBitTracker(_cl.content,_bgHeight);
addByteSlice(_cl.content);
// if addByteSlice is run, draw the slice
if(_byteSlice)_byteSlice.bitmapData = _bmd;
//if addBitTracker is run, show the binary and frame
if(_tf) _tf.text = "Frame:"+frame+", binary:"+pixelBits
}
public function video_PLAY_PROGRESS(e:Event){
//save color values in case error occurs
_lastValues = [];
//get the slice where bits are drawn and read
slice(_bmd,_videoPlayer.videoLoader,_bitHeight,_bitOffsetFromBottom);
//read bits
var pixelBits = readPixels(_bmd,_frames,_bitWidth,_bitSpacing,_bitColor,_threshold);
//covert to integer
var frame = parseInt(String(pixelBits), 2);
//trace("frame:"+frame+",pixelBits:"+pixelBits);
// if frame is smaller that before and error has occured
if(frame < _lastBin) {
trace("##### current frame went backwards from "+_lastBin+" to "+frame);
//stop the video so you can check the pixels and error, comment this out later
//frame = _lastBin++; //error correction
_videoPlayer.pause();
for(var i=0;i<_lastValues.length;i++){
var px = _lastValues[i];
trace("color:"+px);
}
}
else if(_lastBin > -1 && Math.abs(_lastBin-frame) != 1){
//trace("##### current frame skipped frames from "+_lastBin+" to "+frame);
}
_lastBin = frame;
// if addByteSlice is run, draw the slice
if(_byteSlice) _byteSlice.bitmapData = _bmd;
// if addView() is run, draw the video frame to it
if(_view) drawView(_videoPlayer,_bgHeight);
//if addBitTracker is run, show the binary and frame
if(_tf) _tf.text = "Frame:"+frame+", binary:"+pixelBits
}
//mask out the added slice
public function addMask(obj:DisplayObject,bgh:uint){
var mask:Sprite = new Sprite();
mask.graphics.beginFill(0xFF0000);
mask.graphics.drawRect(0, 0, obj.width, obj.height-bgh);
mask.x = obj.x;
mask.y = obj.y;
addChild(mask);
obj.mask = mask;
}
//draw over the added slice
public function addBlocker(obj:DisplayObject,bgh:uint,color:uint){
_blocker = new Bitmap();
_blocker.bitmapData = new BitmapData(obj.width, bgh,false,color);
_blocker.x = obj.x;
_blocker.y = obj.y+obj.height-bgh;
addChild(_blocker);
}
//dont show video, copy paste pixels without the added slice
public function addView(obj:DisplayObject,bgh:uint){
_view = new Bitmap();
_view.bitmapData = new BitmapData(obj.width, obj.height-bgh,false,0x000000);
addChild(_view);
}
//get new frame as video plays on
public function drawView(obj:DisplayObject,bgh:uint){
var mat:Matrix = new Matrix();
var rect = new Rectangle(0,0,obj.width,obj.height-bgh);
_view.bitmapData.draw(obj, mat,new ColorTransform(),null,rect,false);
}
//show the frame and binary over the video
public function addBitTracker(obj:DisplayObject,bgh:uint){
_tf = new TextField();
var textFormat = new TextFormat();
textFormat.size = 10;
textFormat.color = 0xFFFFFF;
textFormat.font = "Arial";
textFormat.align = "right";
_tf.autoSize = TextFieldAutoSize.NONE;
_tf.selectable = false;
_tf.defaultTextFormat = textFormat;
_tf.width = 200;
_tf.height = 40;
_tf.x = obj.width-_tf.width ;
_tf.y = obj.height-bgh-_tf.height;
//_tf.border = true;
addChild(_tf);
}
// show the slice used for binary calculation
public function addByteSlice(obj:DisplayObject){
_byteSlice = new Bitmap();
addChild(_byteSlice);
_byteSlice.x = 0;
_byteSlice.y = obj.height;
}
// get the slice used for binary calculation
public function slice(bmd:BitmapData,obj:DisplayObject,bh:uint,bob:uint){
if(!bmd) bmd = _bmd = new BitmapData(obj.width,1,false,0x000000);
var mat:Matrix = new Matrix();
mat.translate(0,-obj.height+bob+Math.floor(bh/2));
var rect = new Rectangle(0,0,obj.width,1);
bmd.draw(obj, mat,new ColorTransform(),null,rect,false);
}
// calculation binaries from color values
public function readPixels(bmd:BitmapData,bits:uint,bw:uint,bs:uint,color:uint,threshold:uint):String{
var px;
var bin = "";
var xpos
for(var i=0; i<bits;i++){
xpos = bmd.width - Math.ceil(bw/2)-((bw+bs)*i)
px = bmd.getPixel(xpos,0);
if(color == 0) px = (px >> 16) & 0xFF // RED
else if(color == 1) px = (px >> 8) & 0xFF //GREEN
else px = px & 0xFF //BLUE
_lastValues.push(px);
if(px >= 255*threshold/100){
bmd.setPixel(xpos,0,0xFFFF00);
bin = "1"+bin;
}
else {
bin = "0"+bin;
bmd.setPixel(xpos,0,0x0000FF);
}
}
return bin
}
}
}
– make a new AE project
– import the video
– run the AE script
– copy parameters to Flash
– render the video
– insert the file path to Flash
– Publish Flash and watch the Flash decode the frame numbers in real time
– check if Flash traces any warnings
– if there are warnings, adjust shape size and height and run the AE script again
Every company is in Facebook nowadays. It is a powerful, easy-to-use and free platform that enables companies to connect with customers, promote products and services, get attention and, alas, abuse it as a promotional tool. Recently I’ve come across more and more advertisements, where the company is promoting their products via Facebook Pages and requiring people to like their page to win prizes. Well, this is not allowed according to Facebook’s Promotion Guidelines:
You cannot: Administer a promotion that users automatically enter by becoming a fan of your Page.
You cannot: Condition entry in the promotion upon a user providing content on Facebook, such as making a post on a profile or Page, status comment or photo upload.
Most people do not know these rules. They probably won’t even think that rules exist, because so many pages are breaking them so it seems that you can do anything you like. Audi Finland was the first major company in Finland who broke the rules with a very appealing competition (become a fan and win an Audi), Facebook grunted and Audi made an excellent save by apologizing in public and making a new competition that didn’t break the rules. Very good job Audi, but it seems that elsewhere the vastly growing tribe of social media ”gurus” didn’t learn from this.
When I met a presentative of the Facebook few months ago, he said that these kind of ”become a fan and win”-promotions are a problem mainly in Finland. Why? Don’t we have more creative ideas? Is the main target of the advertising/marketing agencies just to get 5 ooo fans and then the client has a firm grip on social media and the campaign is a success? The presentative said that Facebook don’t want to be a promotion platform. Facebook is about real relationships and meaningful dialog. I agree shouting ”Pick me! Pick me and win! I don’t care who you are, but I can give you something for FREE” won’t result in real fans that you could engage with and gain something new. You get few thousand mute fans that don’t give you anything. Yes, of course you get new contacts and a new way to spam them, but that’s not what Facebook is about.
A couple of weeks ago Booky.fi started their promotion in Facebook and radio which says (translated from Finnish): ”everyone who likes our page between 15.-28.11. participates in a sweepstake and we raffle off one book everyday”. That was such a blatant abuse that I had to comment. Their answer was ”No, people don’t automatically attend the sweepstake by liking our page. They have to fill a form which is the way Facebook prefers.” True, but I asked isn’t saying ”everybody who likes our page can win” misleading if a form has to be filled too. They didn’t answer after that.
I did a quick search and found quite many pages that brake the rules: ElamysLahjat, Aqvia, FullMoon, Arpanappula, ON24, Lentovertailu, Matkalehti and KotiMikro. Most likely they are not doing it on purpose, but some of these are surely designed by a SoMe guru promising great results with ridiculously low costs. Facebook is a gold mine for out-of-the-box consultants. But so what if they brake the rules?
Facebook’s Promotion Guidelines states: We may remove any materials relating to the promotion or disable your Page or account if we determine that you violate these Promotions Guidelines, the Statement of Rights and Responsibilities or any other of our policies.
I hope some new marketing people read this and don’t create a campaign that could ban their client from Facebook.
PS. Here is a poor, self-promoting post about how to select a good SoMe expert.
Search on a large webshop site usually returns a lot of unwanted results. Especially searching with general terms when you don’t know or remember exactly what you are looking for (i.a. ”shirt”, ”shoes”). In this example the user is looking for a pair of sneakers. Searching with ”sneakers” in Amazon returns over 50 000 results. And specifying your search isn’t very easy.
An adaptive search would make the next steps toward discovering the correct product easier and faster. Each item on the search results would have 2 options: remove an item from results and narrow results down to certain items. Jatka lukemista ”Adaptive search for easy and fast discovery”
CSS sprites is a very convenient way to use images. Graphics are placed into one file and CSS defines which part of the image is shown on mouse over and mouse click. One image could hold all graphics used on a website.
Flash has skins for components and the SimpleButton class is quite close to CSS Sprites. I wanted a simpler way to create buttons and use graphics. My IconButton class extends the SimpleButton and slices the given image and sets those slices as upState, overState and downState. HitState is always the upState. IconButton has one extra state: disabled.
MultiIconButton is an extended IconButton. Like its name implies, it has multiple IconButtons. Well, code-wise it has only one, but it has different phases so one image can have multiple different icons for various uses. The illustration below explains the principle. Jatka lukemista ”CSS sprites with AS3”
Modernizr detects which HTML5 and CSS3 features user’s browser supports and reports them in a very convenient way: it adds classes to the body tag. The supported features can be checked with javascript, but reporting features with CSS classes is ingenious! Developer don’t have to write if…else -conditions all over javascript because validation can be done in the stylesheet. Jatka lukemista ”Very handy HTML5 & CSS3 checker: Modernizr.js”