Recherche avancée

Médias (39)

Mot : - Tags -/audio

Autres articles (38)

  • Websites made ​​with MediaSPIP

    2 mai 2011, par

    This page lists some websites based on MediaSPIP.

  • Creating farms of unique websites

    13 avril 2011, par

    MediaSPIP platforms can be installed as a farm, with a single "core" hosted on a dedicated server and used by multiple websites.
    This allows (among other things) : implementation costs to be shared between several different projects / individuals rapid deployment of multiple unique sites creation of groups of like-minded sites, making it possible to browse media in a more controlled and selective environment than the major "open" (...)

  • Contribute to documentation

    13 avril 2011

    Documentation is vital to the development of improved technical capabilities.
    MediaSPIP welcomes documentation by users as well as developers - including : critique of existing features and functions articles contributed by developers, administrators, content producers and editors screenshots to illustrate the above translations of existing documentation into other languages
    To contribute, register to the project users’ mailing (...)

Sur d’autres sites (4118)

  • Revision 34537 : un pour englober le contenu principal de ...

    17 janvier 2010, par cedric@… — Log

    un pour englober le contenu principal de chaque objet. Permet de cibler le debut ou la fin du contenu principal, ou, en passant par le parent, la fin du contenu.

  • Cohort Analysis 101 : How-To, Examples & Top Tools

    13 novembre 2023, par Erin — Analytics Tips

    Imagine that a farmer is trying to figure out why certain hens are laying large brown eggs and others are laying average-sized white eggs.

    The farmer decides to group the hens into cohorts based on what kind of eggs they lay to make it easier to detect patterns in their day-to-day lives. After careful observation and analysis, she discovered that the hens laying big brown eggs ate more than the roost’s other hens.

    With this cohort analysis, the farmer deduced that a hen’s body weight directly corresponds to egg size. She can now develop a strategy to increase the body weight of her hens to sell more large brown eggs, which are very popular at the weekly farmers’ market.

    Cohort analysis has a myriad of applications in the world of web analytics. Like our farmer, you can use it to better understand user behaviour and reap the benefits of your efforts. This article will discuss the best practices for conducting an effective cohort analysis and compare the top cohort analysis tools for 2024. 

    What is cohort analysis ?

    By definition, cohort analysis refers to a technique where users are grouped based on shared characteristics or behaviours and then examined over a specified period.

    Think of it as a marketing superpower, enabling you to comprehend user behaviours, craft personalised campaigns and allocate resources wisely, ultimately resulting in improved performance and better ROI.

    Why does cohort analysis matter ?

    In web analytics, a cohort is a group of users who share a certain behaviour or characteristic. The goal of cohort analysis is to uncover patterns and compare the performance and behaviour of different cohorts over time.

    An example of a cohort is a group of users who made their first purchase during the holidays. By analysing this cohort, you could learn more about their behaviour and buying patterns. You may discover that this cohort is more likely to buy specific product categories as holiday gifts — you can then tailor future holiday marketing campaigns to include these categories. 

    Types of cohort analysis

    There are a few different types of notable cohorts : 

    1. Time-based cohorts are groups of users categorised by a specific time. The example of the farmer we went over at the beginning of this section is a great example of a time-based cohort.
    2. Acquisition cohorts are users acquired during a specific time frame, event or marketing channel. Analysing these cohorts can help you determine the value of different acquisition methods. 
    3. Behavioural cohorts consist of users who show similar patterns of behaviour. Examples include frequent purchases with your mobile app or digital content engagement. 
    4. Demographic cohorts share common demographic characteristics like age, gender, education level and income. 
    5. Churn cohorts are buyers who have cancelled a subscription/stopped using your service within a specific time frame. Analysing churn cohorts can help you understand why customers leave.
    6. Geographic cohorts are pretty self-explanatory — you can use them to tailor your marketing efforts to specific regions. 
    7. Customer journey cohorts are based on the buyer lifecycle — from acquisition to adoption to retention. 
    8. Product usage cohorts are buyers who use your product/service specifically (think basic users, power users or occasional users). 

    Best practices for conducting a cohort analysis 

    So, you’ve decided you want to understand your user base better but don’t know how to go about it. Perhaps you want to reduce churn and create a more engaging user experience. In this section, we’ll walk you through the dos and don’ts of conducting an effective cohort analysis. Remember that you should tailor your cohort analysis strategy for organisation-specific goals.

    A line graph depicting product usage cohort data with a blue line for new users and a green line for power users.

    1. Preparing for cohort analysis : 

      • First, define specific goals you want your cohort analysis to achieve. Examples include improving conversion rates or reducing churn.
      • Choosing the right time frame will help you compare short-term vs. long-term data trends. 

    2. Creating effective cohorts : 

      • Define your segmentation criteria — anything from demographics to location, purchase history or user engagement level. Narrowing in on your specific segments will make your cohort analysis more precise. 
      • It’s important to find a balance between cohort size and similarity. If your cohort is too small and diverse, you won’t be able to find specific behavioural patterns.

    3. Performing cohort analysis :

        • Study retention rates across cohorts to identify patterns in user behaviour and engagement over time. Pay special attention to cohorts with high retention or churn rates. 
        • Analysing cohorts can reveal interesting behavioural insights — how do specific cohorts interact with your website ? Do they have certain preferences ? Why ? 

    4. Visualising and interpreting data :

      • Visualising your findings can be a great way to reveal patterns. Line charts can help you spot trends, while bar charts can help you compare cohorts.
      • Guide your analytics team on how to interpret patterns in cohort data. Watch for sudden drops or spikes and what they could mean. 

    5. Continue improving :

      • User behaviour is constantly evolving, so be adaptable. Continuous tracking of user behaviour will help keep your strategies up to date. 
      • Encourage iterative analysis optimisation based on your findings. 
    wrench trying to hammer in a nail, and a hammer trying to screw in a screw to a piece of wood

    The top cohort analysis tools for 2024

    In this section, we’ll go over the best cohort analysis tools for 2024, including their key features, cohort analysis dashboards, cost and pros and cons.

    1. Matomo

    A screenshot of a cohorts graph in Matomo

    Matomo is an open-source, GDPR-compliant web analytics solution that offers cohort analysis as a standard feature in Matomo Cloud and is available as a plugin for Matomo On-Premise. Pairing traditional web analytics with cohort analysis will help you gain even deeper insights into understanding user behaviour over time. 

    You can use the data you get from web analytics to identify patterns in user behaviour and target your marketing strategies to specific cohorts. 

    Key features

    • Matomo offers a cohorts table that lets you compare cohorts side-by-side, and it comes with a time series.
      • All core session and conversion metrics are also available in the Cohorts report.
    • Create custom segments based on demographics, geography, referral sources, acquisition date, device types or user behaviour. 
    • Matomo provides retention analysis so you can track how many users from a specific cohort return to your website and when. 
    • Flexibly analyse your cohorts with custom reports. Customise your reports by combining metrics and dimensions specific to different cohorts. 
    • Create cohorts based on events or interactions with your website. 
    • Intuitive, colour-coded data visualisation, so you can easily spot patterns.

    Pros

    • No setup is needed if you use the JavaScript tracker
    • You can fetch cohort without any limit
    • 100% accurate data, no AI or Machine Learning data filling, and without the use of data sampling

    Cons

    • Matomo On-Premise (self-hosted) is free, but advanced features come with additional charges
    • Servers and technical know-how are required for Matomo On-Premise. Alternatively, for those not ready for self-hosting, Matomo Cloud presents a more accessible option and starts at $19 per month.

    Price : 

    • Matomo Cloud : 21-day free trial, then starts at $19 per month (includes Cohorts).
    • Matomo On-Premise : Free to self-host ; Cohorts plugin : 30-day free trial, then $99 per year.

    2. Mixpanel

    Mixpanel is a product analytics tool designed to help teams better understand user behaviour. It is especially well-suited for analysing user behaviour on iOS and Android apps. It offers various cohort analytics features that can be used to identify patterns and engage your users. 

    Key features

    • Create cohorts based on criteria such as sign-up date, first purchase date, referral source, geographic location, device type or another custom event/property. 
    • Compare how different cohorts engage with your app with Mixpanel’s comparative analysis features.
    • Create interactive dashboards, charts and graphs to visualise data.
    • Mixpanel provides retention analysis tools to see how often users return to your product over time. 
    • Send targeted messages and notifications to specific cohorts to encourage user engagement, announce new features, etc. 
    • Track and analyse user behaviours within cohorts — understand how different types of users engage with your product.

    Pros

    • Easily export cohort analysis data for further analysis
    • Combined with Mixpanel reports, cohorts can be a powerful tool for improving your product

    Cons

    • With the free Mixpanel plan, you can’t save cohorts for future use
    • Enterprise-level pricing is expensive
    • Time-consuming cohort creation process

    Price : Free basic version. The growth version starts at £16/month.

    3. Amplitude

    A screenshot of a cohorts graph in Amplitude

    Amplitude is another product analytics solution that can help businesses track user interactions across digital platforms. Amplitude offers a standard toolkit for in-depth cohort analysis.

    Key features

    • Create cohorts based on criteria such as sign-up date, first purchase date, referral source, geographic location, device type or another custom event/property. 
    • Conduct behavioural, time-based and retention analyses.
    • Create custom reports with custom data.
    • Segment cohorts further based on additional criteria and compare multiple cohorts side-by-side.

    Pros

    • Highly customisable and flexible
    • Quick and simple setup

    Cons

    • Steep learning curve — requires significant training 
    • Slow loading speed
    • High price point compared to other tools

    Price : Free basic version. Plus version starts at £40/month (billed annually).

    4. Kissmetrics

    A screenshot of a cohorts graph in Kissmetrics

    Kissmetrics is a customer engagement automation platform that offers powerful analytics features. Kissmetrics provides behavioural analytics, segmentation and email campaign automation. 

    Key features

    • Create cohorts based on demographics, user behaviour, referral sources, events and specific time frames.
    • The user path tool provides path visualisation so you can identify common paths users take and spot abandonment points. 
    • Create and optimise conversion funnels.
    • Customise events, user properties, funnels, segments, cohorts and more.

    Pros

    • Powerful data visualisation options
    • Highly customisable

    Cons

    • Difficult to install
    • Not well-suited for small businesses
    • Limited integration with other tools

    Price : Starting at £21/month for 10k events (billed monthly).

    Improve your cohort analysis with Matomo

    When choosing a cohort analysis tool, consider factors such as the tool’s ease of integration with your existing systems, data accuracy, the flexibility it offers in defining cohorts, the comprehensiveness of reporting features, and its scalability to accommodate the growth of your data and analysis needs over time. Moreover, it’s essential to confirm GDPR compliance to uphold rigorous privacy standards. 

    If you’re ready to understand your user’s behaviour, take Matomo for a test drive. Paired with web analytics, this powerful combination can advance your marketing efforts. Start your 21-day free trial today — no credit card required.

  • Matomo analytics for wordpress

    15 octobre 2019, par Matomo Core Team — Community

    Self-hosting web analytics got a whole lot easier ! Introducing Matomo for WordPress

    Be the first to try it out ! Your feedback is much needed and appreciated

    Get a fully functioning Matomo (which is comparable to Google Analytics) in seconds ! How ? With the new Matomo Analytics for WordPress plugin. 

    Web analytics in WordPress has never been easier to get, or more powerful. Matomo Analytics for WordPress is the one-stop problem solver. It’ll save you time, money and give you the insights to help your website or business succeed. 

    Best of all, we get to further the goal of decentralising the internet. Our hope is for Matomo Analytics for WordPress to spread far and wide. We’re so excited that more and more people can now get their hands on this powerful, free, open-source analytics platform, in a few clicks !

    Download now and check it out !

    What do you get ?

    • No more signing up to third party analytics service (like Google)
    • No more sending away your valuable data to a third party service (like Google)
    • Easy setup – install with a few clicks, no tracking code installation or developer knowledge needed
    • 100% accurate data – no data sampling and no data limits 
    • Full data ownership – all data is stored on your servers and no one else can see your data
    • Privacy protection / GDPR compliance
    • Ecommerce tracking out-of-the-box (Woocommerce, Easy Digital Downloads, and MemberPress) and we’re keen to add many more over time
    • Powerful features – segmenting, comparing reports, different visualisations, real-time reports, visit logs and visitor profiles, Matomo Tag Manager, dashboards, data export, APIs, and many more
    • Compared to other WordPress solutions we don’t charge you extra for basic features that should work out-of-the-box
    • Just like Matomo On-Premise, Matomo Analytics for WordPress is free

    We need your feedback !

    We all know and love the versatility of WordPress – with over 55,000 plugins and all the different ways of hosting it. However, with this great versatility comes the potential for things to be missed, so we’re keen to hear your feedback.

    Thank you ! We really appreciate your help on this ❤️

    How do you get Matomo Analytics for WordPress ?

    Log in to your WordPress and go to “Plugins => Add New”, search for “Matomo Analytics – Ethical Stats. Powerful Insights”, click on “Install” and then “Activate”.

    All you need is at least WordPress 4.8 and PHP 7.0 or later. MySQL 5.1+ is recommended. 

    The source code is available at : https://github.com/matomo-org/wp-matomo/

    In perfect harmony : Matomo and WordPress

    Matomo Analytics for WordPress

    The idea for this started two years ago when we realised the similarities between the Matomo and WordPress project. 

    Not only from a technological point of view – where both are based on PHP and MySQL and can be extended using plugins – but also from a philosophical, license and values point of view. We both believe in privacy, security, data ownership, openness, transparency, having things working out-of-the-box, simplicity etc. 

    WordPress is currently used on approximately 30% of all websites. Many of them use the self-hosted open-source WordPress version. Giving everyone in this market the opportunity to easily get a powerful web analytics platform for free, means a lot to us. We believe WordPress users get a real choice besides the standard solution of Google Analytics, and it furthers our effort and goal of decentralising the internet. 

    We’re hoping more people will be empowered to protect user privacy, have access to a great free and open-source tool, and keep control of data in their own hands.

    We hope you feel the same. Help us spread the word to your friends and get them in on this awesome new project !

    Share on facebook
    Share on twitter
    Share on linkedin

    FAQs

    Isn’t there already a WP-Matomo plugin for WordPress available ?

    Yes, the existing WP-Matomo (WP-Piwik) plugin is an awesome plugin to connect your existing Matomo On-Premise or Matomo Cloud account with WordPress. The difference is that this new plugin installs Matomo Analytics fully in your WordPress. So you get the convenience of having a powerful analytics platform within your WordPress.

    We highly recommend you install this new plugin if you use WordPress and are not running Matomo yet. 

    If you are already using Matomo on our Cloud or On-Premise, we’d still highly recommend you use WP-Matomo (WP-Piwik). So that you get an easier way of inserting the tracking code into your WordPress site and get insights faster.

    I have a high traffic website, will it be an issue ?

    If you have a lot of traffic, we’d advise you to install Matomo On-Premise separately. There’s no specific traffic threshold we can give you on when it’s better to use Matomo On-Premise. It really depends on your server. 

    We reckon if you have more than 500,000 page views a month, you may want to think about using Matomo On-Premise with WP-Matomo instead, but this is just an estimate. In general, if the load on your server is already quite high, then it might be better to install Matomo on a separate server. See also recommended server sizing for running Matomo.

    How do I report a bug or request a new feature in Matomo for WordPress ?

    Please create an issue, on our repository whenever you find a bug or if you have any suggestion or ideas of improvement. We want to build an outstanding analytics experience for WordPress !

    Have another question you’re dying to ask ? The Matomo for WordPress FAQ page might have the answer you need. 

    Matomo Analytics for WordPress newsletter

    Get ahead of the crowd – signup to our exclusive Matomo for WordPress newsletter to get the latest updates on this exciting new project.

    &lt;script type=&quot;text/javascript&quot;&gt;<br />
    (function(global) {<br />
     function serialize(form){if(!form||form.nodeName!==&quot;FORM&quot;){return }var i,j,q=[];for(i=form.elements.length-1;i&gt;=0;i=i-1){if(form.elements[i].name===&quot;&quot;){continue}switch(form.elements[i].nodeName){case&quot;INPUT&quot;:switch(form.elements[i].type){case&quot;text&quot;:case&quot;hidden&quot;:case&quot;password&quot;:case&quot;button&quot;:case&quot;reset&quot;:case&quot;submit&quot;:q.push(form.elements[i].name+&quot;=&quot;+encodeURIComponent(form.elements[i].value));break;case&quot;checkbox&quot;:case&quot;radio&quot;:if(form.elements[i].checked){q.push(form.elements[i].name+&quot;=&quot;+encodeURIComponent(form.elements[i].value))}break;case&quot;file&quot;:break}break;case&quot;TEXTAREA&quot;:q.push(form.elements[i].name+&quot;=&quot;+encodeURIComponent(form.elements[i].value));break;case&quot;SELECT&quot;:switch(form.elements[i].type){case&quot;select-one&quot;:q.push(form.elements[i].name+&quot;=&quot;+encodeURIComponent(form.elements[i].value));break;case&quot;select-multiple&quot;:for(j=form.elements[i].options.length-1;j&gt;=0;j=j-1){if(form.elements[i].options[j].selected){q.push(form.elements[i].name+&quot;=&quot;+encodeURIComponent(form.elements[i].options[j].value))}}break}break;case&quot;BUTTON&quot;:switch(form.elements[i].type){case&quot;reset&quot;:case&quot;submit&quot;:case&quot;button&quot;:q.push(form.elements[i].name+&quot;=&quot;+encodeURIComponent(form.elements[i].value));break}break}}return q.join(&quot;&amp;&quot;)};<br />
    <br />
    <br />
     function extend(destination, source) {<br />
       for (var prop in source) {<br />
         destination[prop] = source[prop];<br />
       }<br />
     }<br />
    <br />
     if (!Mimi) var Mimi = {};<br />
     if (!Mimi.Signups) Mimi.Signups = {};<br />
    <br />
     Mimi.Signups.EmbedValidation = function() {<br />
       this.initialize();<br />
    <br />
       var _this = this;<br />
       if (document.addEventListener) {<br />
         this.form.addEventListener('submit', function(e){<br />
           _this.onFormSubmit(e);<br />
         });<br />
       } else {<br />
         this.form.attachEvent('onsubmit', function(e){<br />
           _this.onFormSubmit(e);<br />
         });<br />
       }<br />
     };<br />
    <br />
     extend(Mimi.Signups.EmbedValidation.prototype, {<br />
       initialize: function() {<br />
         this.form         = document.getElementById('ema_signup_form');<br />
         this.submit       = document.getElementById('webform_submit_button');<br />
         this.callbackName = 'jsonp_callback_' + Math.round(100000 * Math.random());<br />
         this.validEmail   = /.+@.+\..+/<br />
       },<br />
    <br />
       onFormSubmit: function(e) {<br />
         e.preventDefault();<br />
    <br />
         this.validate();<br />
         if (this.isValid) {<br />
           this.submitForm();<br />
         } else {<br />
           this.revalidateOnChange();<br />
         }<br />
       },<br />
    <br />
       validate: function() {<br />
         this.isValid = true;<br />
         this.emailValidation();<br />
         this.fieldAndListValidation();<br />
         this.updateFormAfterValidation();<br />
       },<br />
    <br />
       emailValidation: function() {<br />
         var email = document.getElementById('signup_email');<br />
    <br />
         if (this.validEmail.test(email.value)) {<br />
           this.removeTextFieldError(email);<br />
         } else {<br />
           this.textFieldError(email);<br />
           this.isValid = false;<br />
         }<br />
       },<br />
    <br />
       fieldAndListValidation: function() {<br />
         var fields = this.form.querySelectorAll('.mimi_field.required');<br />
    <br />
         for (var i = 0; i &lt; fields.length; ++i) {<br />
           var field = fields[i],<br />
               type  = this.fieldType(field);<br />
           if (type === 'checkboxes' || type === 'radio_buttons' || type === 'age_check') {<br />
             this.checkboxAndRadioValidation(field);<br />
           } else {<br />
             this.textAndDropdownValidation(field, type);<br />
           }<br />
         }<br />
       },<br />
    <br />
       fieldType: function(field) {<br />
         var type = field.querySelectorAll('.field_type');<br />
    <br />
         if (type.length) {<br />
           return type[0].getAttribute('data-field-type');<br />
         } else if (field.className.indexOf('checkgroup') &gt;= 0) {<br />
           return 'checkboxes';<br />
         } else {<br />
           return 'text_field';<br />
         }<br />
       },<br />
    <br />
       checkboxAndRadioValidation: function(field) {<br />
         var inputs   = field.getElementsByTagName('input'),<br />
             selected = false;<br />
    <br />
         for (var i = 0; i &lt; inputs.length; ++i) {<br />
           var input = inputs[i];<br />
           if((input.type === 'checkbox' || input.type === 'radio') &amp;&amp; input.checked) {<br />
             selected = true;<br />
           }<br />
         }<br />
    <br />
         if (selected) {<br />
           field.className = field.className.replace(/ invalid/g, '');<br />
         } else {<br />
           if (field.className.indexOf('invalid') === -1) {<br />
             field.className += ' invalid';<br />
           }<br />
    <br />
           this.isValid = false;<br />
         }<br />
       },<br />
    <br />
       textAndDropdownValidation: function(field, type) {<br />
         var inputs = field.getElementsByTagName('input');<br />
    <br />
         for (var i = 0; i &lt; inputs.length; ++i) {<br />
           var input = inputs[i];<br />
           if (input.name.indexOf('signup') &gt;= 0) {<br />
             if (type === 'text_field') {<br />
               this.textValidation(input);<br />
             } else {<br />
               this.dropdownValidation(field, input);<br />
             }<br />
           }<br />
         }<br />
         this.htmlEmbedDropdownValidation(field);<br />
       },<br />
    <br />
       textValidation: function(input) {<br />
         if (input.id === 'signup_email') return;<br />
    <br />
         if (input.value) {<br />
           this.removeTextFieldError(input);<br />
         } else {<br />
           this.textFieldError(input);<br />
           this.isValid = false;<br />
         }<br />
       },<br />
    <br />
       dropdownValidation: function(field, input) {<br />
         if (input.value) {<br />
           field.className = field.className.replace(/ invalid/g, '');<br />
         } else {<br />
           if (field.className.indexOf('invalid') === -1) field.className += ' invalid';<br />
           this.onSelectCallback(input);<br />
           this.isValid = false;<br />
         }<br />
       },<br />
    <br />
       htmlEmbedDropdownValidation: function(field) {<br />
         var dropdowns = field.querySelectorAll('.mimi_html_dropdown');<br />
         var _this = this;<br />
    <br />
         for (var i = 0; i &lt; dropdowns.length; ++i) {<br />
           var dropdown = dropdowns[i];<br />
    <br />
           if (dropdown.value) {<br />
             field.className = field.className.replace(/ invalid/g, '');<br />
           } else {<br />
             if (field.className.indexOf('invalid') === -1) field.className += ' invalid';<br />
             this.isValid = false;<br />
             dropdown.onchange = (function(){ _this.validate(); });<br />
           }<br />
         }<br />
       },<br />
    <br />
       textFieldError: function(input) {<br />
         input.className   = 'required invalid';<br />
         input.placeholder = input.getAttribute('data-required-field');<br />
       },<br />
    <br />
       removeTextFieldError: function(input) {<br />
         input.className   = 'required';<br />
         input.placeholder = '';<br />
       },<br />
    <br />
       onSelectCallback: function(input) {<br />
         if (typeof Widget === 'undefined' || !Widget.BasicDropdown) return;<br />
    <br />
         var dropdownEl = input.parentNode,<br />
             instances  = Widget.BasicDropdown.instances,<br />
             _this = this;<br />
    <br />
         for (var i = 0; i &lt; instances.length; ++i) {<br />
           var instance = instances[i];<br />
           if (instance.wrapperEl === dropdownEl) {<br />
             instance.onSelect = function(){ _this.validate() };<br />
           }<br />
         }<br />
       },<br />
    <br />
       updateFormAfterValidation: function() {<br />
         this.form.className   = this.setFormClassName();<br />
         this.submit.value     = this.submitButtonText();<br />
         this.submit.disabled  = !this.isValid;<br />
         this.submit.className = this.isValid ? 'submit' : 'disabled';<br />
       },<br />
    <br />
       setFormClassName: function() {<br />
         var name = this.form.className;<br />
    <br />
         if (this.isValid) {<br />
           return name.replace(/\s?mimi_invalid/, '');<br />
         } else {<br />
           if (name.indexOf('mimi_invalid') === -1) {<br />
             return name += ' mimi_invalid';<br />
           } else {<br />
             return name;<br />
           }<br />
         }<br />
       },<br />
    <br />
       submitButtonText: function() {<br />
         var invalidFields = document.querySelectorAll('.invalid'),<br />
             text;<br />
    <br />
         if (this.isValid || !invalidFields) {<br />
           text = this.submit.getAttribute('data-default-text');<br />
         } else {<br />
           if (invalidFields.length || invalidFields[0].className.indexOf('checkgroup') === -1) {<br />
             text = this.submit.getAttribute('data-invalid-text');<br />
           } else {<br />
             text = this.submit.getAttribute('data-choose-list');<br />
           }<br />
         }<br />
         return text;<br />
       },<br />
    <br />
       submitForm: function() {<br />
         this.formSubmitting();<br />
    <br />
         var _this = this;<br />
         window[this.callbackName] = function(response) {<br />
           delete window[this.callbackName];<br />
           document.body.removeChild(script);<br />
           _this.onSubmitCallback(response);<br />
         };<br />
    <br />
         var script = document.createElement('script');<br />
         script.src = this.formUrl('json');<br />
         document.body.appendChild(script);<br />
       },<br />
    <br />
       formUrl: function(format) {<br />
         var action  = this.form.action;<br />
         if (format === 'json') action += '.json';<br />
         return action + '?callback=' + this.callbackName + '&amp;' + serialize(this.form);<br />
       },<br />
    <br />
       formSubmitting: function() {<br />
         this.form.className  += ' mimi_submitting';<br />
         this.submit.value     = this.submit.getAttribute('data-submitting-text');<br />
         this.submit.disabled  = true;<br />
         this.submit.className = 'disabled';<br />
       },<br />
    <br />
       onSubmitCallback: function(response) {<br />
         if (response.success) {<br />
           this.onSubmitSuccess(response.result);<br />
         } else {<br />
           top.location.href = this.formUrl('html');<br />
         }<br />
       },<br />
    <br />
       onSubmitSuccess: function(result) {<br />
         if (result.has_redirect) {<br />
           top.location.href = result.redirect;<br />
         } else if(result.single_opt_in || !result.confirmation_html) {<br />
           this.disableForm();<br />
           this.updateSubmitButtonText(this.submit.getAttribute('data-thanks'));<br />
         } else {<br />
           this.showConfirmationText(result.confirmation_html);<br />
         }<br />
       },<br />
    <br />
       showConfirmationText: function(html) {<br />
         var fields = this.form.querySelectorAll('.mimi_field');<br />
    <br />
         for (var i = 0; i &lt; fields.length; ++i) {<br />
           fields[i].style['display'] = 'none';<br />
         }<br />
    <br />
         (this.form.querySelectorAll('fieldset')[0] || this.form).innerHTML = html;<br />
       },<br />
    <br />
       disableForm: function() {<br />
         var elements = this.form.elements;<br />
         for (var i = 0; i &lt; elements.length; ++i) {<br />
           elements[i].disabled = true;<br />
         }<br />
       },<br />
    <br />
       updateSubmitButtonText: function(text) {<br />
         this.submit.value = text;<br />
       },<br />
    <br />
       revalidateOnChange: function() {<br />
         var fields = this.form.querySelectorAll(&quot;.mimi_field.required&quot;),<br />
             _this = this;<br />
    <br />
         var onTextFieldChange = function() {<br />
           if (this.getAttribute('name') === 'signup[email]') {<br />
             if (_this.validEmail.test(this.value)) _this.validate();<br />
           } else {<br />
             if (this.value.length === 1) _this.validate();<br />
           }<br />
         }<br />
    <br />
         for (var i = 0; i &lt; fields.length; ++i) {<br />
           var inputs = fields[i].getElementsByTagName('input');<br />
           for (var j = 0; j &lt; inputs.length; ++j) {<br />
             if (this.fieldType(fields[i]) === 'text_field') {<br />
               inputs[j].onkeyup = onTextFieldChange;<br />
               inputs[j].onchange = onTextFieldChange; <br />
             } else {<br />
               inputs[j].onchange = function(){ _this.validate() };<br />
             }<br />
           }<br />
         }<br />
       }<br />
     });<br />
    <br />
     if (document.addEventListener) {<br />
       document.addEventListener(&quot;DOMContentLoaded&quot;, function() {<br />
         new Mimi.Signups.EmbedValidation();<br />
       });<br />
     }<br />
     else {<br />
       window.attachEvent('onload', function() {<br />
         new Mimi.Signups.EmbedValidation();<br />
       });<br />
     }<br />
    })(this);<br />
    &lt;/script&gt;