<commit_before>require('colors');

var version = "Shows azk version";
var systems_options = "Targets systems of action";

module.exports = {
  errors: {
    not_vm_start: "Unable to install and configure virtual machine",
    not_connect_docker: "Could not initialize balancer because Docker was not available",
    agent_not_running: "Azk agent is required but is not running (try `azk agent status`)",
    agent_start: "Azk agent start error: %(error)s",
    not_been_implemented: "This feature: `%(feature)s` has not been implemented yet",
    system_not_found: "System `%(system)s` not found in `%(manifest)s`",
    manifest_required: "Manifest is required, but was not found in `%(cwd)s`",
    manifest_error: "Manifest not valid (see http://doc.azk.io), error:\n%(err_message)s",
    required_option_error: "Option %(option)s is required",
    system_depend_error: "System `%(system)s` depends on the system `%(depend)s`",
    system_run_error: "Run system `%(system)s` return: (%(exitCode)d), for command: %(command)s:\n%(log)s",
    system_not_scalable: "System `%(system)s is not scalable only one instance is allowed.",
    image_not_available: "System `%(system)s` requires image `%(image)s` which is not avaible",
    run_command_error: "Run `%(command)s` in system `%(system)s` error:\n`%(output)s`",
    provision_pull_error: "Error downloading/pulling docker image `%(image)s`, message: %(msg)s.",
    invalid_option_error: "Invalid argument option: %(option)s",
    invalid_value_error: "Invalid value: %(value)s in option %(option)s",
    image_not_exist: "Image from '%(image)s' not found",
    provision_not_found: "Not found '%(image)s' image",
  },

  status: {
    agent: {
      running: "Agent is running...",
      not_running: "Agent is not running (try: `azk agent start`).",
      starting: "Agent is being started...",
      already: "Agent is already running.",
      started: "Agent has been successfully started.",
      // TODO: stopping
      stoping: "Agent is being stopped...",
      // TODO: stopped
      stoped: "Agent has been successfully stopped.",
      error: "Agent starting error: %(data)s.",
      wait: "Wait, this process may take several minutes",
    },

    vm: {
      installing: "installing virtual machine...",
      installed : "virtual machine has been successfully installed.",
      starting  : "starting virtual machine...",
      started   : "virtual machine has been successfully started.",
      // TODO: stopping
      stoping   : "stopping virtual machine...",
      // TODO: stopped
      stoped    : "virtual machine has been successfully stopped.",
      removing  : "removing virtual machine...",
      removed   : "virtual machine has been successfully removed.",
      // TODO: waiting
      wait      : "waiting for initialization of virtual machine...",
      initialized : "virtual machine is ready to use.",
      progress    : "trying connect to vm (%(host)s:%(port)d) (%(attempts)d/%(max)d)...",
    },

    socat: {
      progress : "trying to connect to docker (%(attempts)d/%(max)d)...",
    },

    balancer: {
      starting_memcached: "starting memcached...",
      started_memcached : "memcached started.",
      starting_hipache  : "starting hipache...",
      started_hipache   : "hipache started.",
      starting_socat    : "starting socat...",
      started_socat     : "socat started.",
    },

    unsfd: {
      starting : "starting unsfd...",
      started  : "unsfd started in %(port)s port with file config: %(file)s.",
      stopping : "stopping unsfd...",
      // TODO: stopped
      stoped   : "unsfd has been successfully stopped.",
      mounting : "mounting the unsfd shared folder in virtual machine...",
      mounted  : "unsfd shared folder has been successfully mounted.",
    },
  },

  generator: {
    found: "A system of the `%(__type)s` type found in '%(dir)s'",
  },

  manifest: {
    not_found: "no such '%s' in current project",
    circular_depends: "Circular dependency between %(system1)s and %(system2)s",
    image_required: "Not image set for the `%(system)s' system",
    system_name_invalid: "The system name `%(system)s` is not valid.",
    depends_not_declared: "The `%(system)s` system depends on the `%(depend)s` system, which was not stated.",
    balancer_depreciation: "The `balancer` option used in the `%(system)s` is deprecated, use `http` and `scalable` to replace",
  },

  system: {
    cmd_not_set: "Command not set in system \\`%(system)s\\`",
    seelog: "See the back log",
  },

  commands: {
    not_found: "Command '%s' not found",
    azk: {
      description: "Azk short help",
      options: {
        command: {
          name: "command".yellow
        },
        log: "Sets a log level",
        help: "Shows this help",
        version: version,
      },
      examples: [
        '$ azk agent start --daemon',
        '$ azk shell --image azukiapp/busybox',
        '$ azk shell --mount ~/Home:/azk/user -e HOME=/azk/user',
        '$ azk status -s [system_name]',
        '$ azk scale --instances 2',
      ],
    },
    version: {
      description: version
    },
    agent: {
      description: "Controls azk agent",
      start_fail: "Agent start fail: %s",
      options: {
        action: {
          name: "actions".magenta,
          options: {
            start: "Start azk agent",
            status: "Show the azk agent status",
            stop: "Stop the azk agent running in the background",
          }
        },
        daemon: "Runs azk agent in background mode",
      }
    },
    shell: {
      description: "Initializes a shell with instance context or runs a arbitrary command",
      invalid_mount: "Invalid mount parameter: `%(value)s`, use `origin=target`",
      invalid_env: "Invalid env variable: `%(value)s`, use `VARIABLE=VALUE`",
      options: {
        T: "Disables pseudo-tty allocation",
        t: "Forces pseudo-tty allocation",
        system  : "A system context to execute a shell or command",
        command : "Runs a specific command",
        shell   : "The path to shell binary",
        verbose : "Shows details about command execution",
        mount   : "Points for additional mounting (ex:./origin:/azk/target)",
        cwd     : "Default directory",
        image   : "Defines the image in which the command will be executed",
        env     : "Additional environment variables",
      },
      examples: [
        '$ azk shell --shell /bin/bash',
        '$ azk shell --mount /:/azk/root -e RAILS_ENV=dev',
        '$ azk shell -c "ls -l /"',
        '$ azk shell --image azukiapp/budybox -t -c "/bin/bash"',
      ]
    },
    help: {
      description: "Shows help about the specific command",
      usage: 'Usage:'.blue + ' $ %s',
      options: "options:".green,
      examples: "examples:".yellow,
    },
    helpers: {
      pull: {
        pulling: 'Pulling repository %s...',
        bar_progress: '  :title [:bar] :percent :progress',
        bar_status: '  :title :msg',
      }
    },
    init: {
      description: "Initializes a project by adding the file Azkfile.js",
      already: "'%s' already exists (try: `--force`)",
      generated: "'%s' generated",
      github: "\nTip:\n  Adds the `.azk` in .gitignore\n  echo '.azk' >> .gitignore \n",
      not_found: "Not found a system(s), generating with example system.",
      options: {
        force: "Forces the overlay file Azkfile.js",
      }
    },
    start: {
      description: "Starts an instance of the system(s)",
      already: "System `%(name)s` already started",
      options: {
        system: systems_options,
      }
    },
    stop: {
      description: "Stops an instance of the system(s)",
      not_running: "System `%(name)s` not running",
      options: {
        system: systems_options,
      }
    },
    scale: {
      instances   : "from " + "%(from)d".red + " to " + "%(to)d".green + " instances",
      description : "Scales (up or down) an instance of the system(s)",
      wait_port   : "◴".magenta + " waiting start `"+ "%(system)s".blue  + "` system, try connect port %(name)s/%(protocol)s...",
      check_image : "✓".cyan    + " checking `"     + "%(image)s".yellow + "` image...",
      pull_image  : "⇲".blue    + " downloading `"  + "%(image)s".yellow + "` image...",
      provision   : "↻".yellow  + " provisioning `" + "%(system)s".blue  + "` system...",
      starting    : "↑".green   + " starting `"     + "%(system)s".blue  + "` system, " + "%(to)d".green + " new instances...",
      stopping    : "↓".red     + " stopping `"     + "%(system)s".blue  + "` system, " + "%(from)d".red + " instances...",
      scaling_up  : "↑".green   + " scaling `"      + "%(system)s".blue  + "` system %(instances)s...",
      scaling_down: "↓".red     + " scaling `"      + "%(system)s".blue  + "` system %(instances)s...",
      options: {
        system: systems_options,
        instances: "Number of instances",
      }
    },
    reload: {
      description: "Stops all system, re-provisions and starts again",
      options: {
        system: systems_options,
      }
    },
    up: {
      description: "Starts all systems following the proper sequence according to dependencies",
    },
    status: {
      description: "Shows systems(s) instances status(es)",
      status: "%(system)s: %(instances)d instances - %(hosts)s",
      status_with_dead: "%(system)s: %(instances)d up and %(down)d down - %(hosts)s",
      options: {
        system: "System(s) name(s)",
        instances: "Shows details about instances",
        all: "Includes all instances (including those terminated)",
      }
    },
    vm: {
      description  : "Controls a virtual machine.",
      already      : "virtual machine already installed.",
      not_installed: "virtual machine is not installed, try `azk vm install`.",
      running      : "virtual machine running.",
      already_running : "virtual machine already running.",
      // TODO not_running
      not_runnig   : "virtual machine is not running, try `azk vm start`.",
      error        : "vm error: %(error)s.",
      not_requires : "this system not requires virtual machine, to try force this behavior set `AZK_USE_VM=true`",
    }
  },

  docker: {
    connect: "connecting to docker: %s..."
  },

  proxy: {
    adding_backend: "adding backend:%(backend)s to hostname:%(hostname)s...",
    removing_backend: "removing backend:%(backend)s to hostname:%(hostname)s...",
    request: "proxy request %s => %s",
    started: "proxy started in %s port",
    not_configured: "host '%s' not configured in proxy"
  },

  test: {
    before: "Before all tasks:",
    remove_containers: "- Removing %s containers before running tests...",
    remove_images: "- Removing %s images before running tests...",
    check_vm: "- Checking for required vm...",
    i18n_test: "test i18n module",
    commands: {
      test_help: {
        description: "Test help description",
        options: {
          verbose: "Verbose mode",
          string: "String option",
          flag: "Boolean flag",
          'flag-default': "Flag with default",
          subcommand: {
            name: "subcommand",
            options: {
              start: "Start service",
              stop: "Stop service",
            },
          }
        },
      },
    },
  }
}
<commit_msg>Adding `help` documentations for new commands and options.<commit_after>require('colors');

var version = "Shows azk version";
var verbose = "Sets the level of detail";
var systems_options = "Targets systems of action";
var reprovision = "Force the provisioning actions before starting an instance";

module.exports = {
  errors: {
    not_vm_start: "Unable to install and configure virtual machine",
    not_connect_docker: "Could not initialize balancer because Docker was not available",
    agent_not_running: "Azk agent is required but is not running (try `azk agent status`)",
    agent_start: "Azk agent start error: %(error)s",
    not_been_implemented: "This feature: `%(feature)s` has not been implemented yet",
    system_not_found: "System `%(system)s` not found in `%(manifest)s`",
    manifest_required: "Manifest is required, but was not found in `%(cwd)s`",
    manifest_error: "Manifest not valid (see http://doc.azk.io), error:\n%(err_message)s",
    required_option_error: "Option %(option)s is required",
    system_depend_error: "System `%(system)s` depends on the system `%(depend)s`",
    system_run_error: "Run system `%(system)s` return: (%(exitCode)d), for command: %(command)s:\n%(log)s",
    system_not_scalable: "System `%(system)s is not scalable only one instance is allowed.",
    image_not_available: "System `%(system)s` requires image `%(image)s` which is not avaible",
    run_command_error: "Run `%(command)s` in system `%(system)s` error:\n`%(output)s`",
    provision_pull_error: "Error downloading/pulling docker image `%(image)s`, message: %(msg)s.",
    invalid_option_error: "Invalid argument option: %(option)s",
    invalid_value_error: "Invalid value: %(value)s in option %(option)s",
    image_not_exist: "Image from '%(image)s' not found",
    provision_not_found: "Not found '%(image)s' image",
  },

  status: {
    agent: {
      running: "Agent is running...",
      not_running: "Agent is not running (try: `azk agent start`).",
      starting: "Agent is being started...",
      already: "Agent is already running.",
      started: "Agent has been successfully started.",
      // TODO: stopping
      stoping: "Agent is being stopped...",
      // TODO: stopped
      stoped: "Agent has been successfully stopped.",
      error: "Agent starting error: %(data)s.",
      wait: "Wait, this process may take several minutes",
    },

    vm: {
      installing: "installing virtual machine...",
      installed : "virtual machine has been successfully installed.",
      starting  : "starting virtual machine...",
      started   : "virtual machine has been successfully started.",
      // TODO: stopping
      stoping   : "stopping virtual machine...",
      // TODO: stopped
      stoped    : "virtual machine has been successfully stopped.",
      removing  : "removing virtual machine...",
      removed   : "virtual machine has been successfully removed.",
      // TODO: waiting
      wait      : "waiting for initialization of virtual machine...",
      initialized : "virtual machine is ready to use.",
      progress    : "trying connect to vm (%(host)s:%(port)d) (%(attempts)d/%(max)d)...",
    },

    socat: {
      progress : "trying to connect to docker (%(attempts)d/%(max)d)...",
    },

    balancer: {
      starting_memcached: "starting memcached...",
      started_memcached : "memcached started.",
      starting_hipache  : "starting hipache...",
      started_hipache   : "hipache started.",
      starting_socat    : "starting socat...",
      started_socat     : "socat started.",
    },

    unsfd: {
      starting : "starting unsfd...",
      started  : "unsfd started in %(port)s port with file config: %(file)s.",
      stopping : "stopping unsfd...",
      // TODO: stopped
      stoped   : "unsfd has been successfully stopped.",
      mounting : "mounting the unsfd shared folder in virtual machine...",
      mounted  : "unsfd shared folder has been successfully mounted.",
    },
  },

  generator: {
    found: "A system of the `%(__type)s` type found in '%(dir)s'",
  },

  manifest: {
    not_found: "no such '%s' in current project",
    circular_depends: "Circular dependency between %(system1)s and %(system2)s",
    image_required: "Not image set for the `%(system)s' system",
    system_name_invalid: "The system name `%(system)s` is not valid.",
    depends_not_declared: "The `%(system)s` system depends on the `%(depend)s` system, which was not stated.",
    balancer_depreciation: "The `balancer` option used in the `%(system)s` is deprecated, use `http` and `scalable` to replace",
  },

  system: {
    cmd_not_set: "Command not set in system \\`%(system)s\\`",
    seelog: "See the back log",
  },

  commands: {
    not_found: "Command '%s' not found",
    azk: {
      description: "Azk short help",
      options: {
        command: {
          name: "command".yellow
        },
        log: "Sets a log level",
        help: "Shows this help",
        version: version,
      },
      examples: [
        '$ azk agent start --daemon',
        '$ azk shell --image azukiapp/busybox',
        '$ azk shell --mount ~/Home:/azk/user -e HOME=/azk/user',
        '$ azk status -s [system_name]',
        '$ azk scale --instances 2',
      ],
    },
    version: {
      description: version
    },
    agent: {
      description: "Controls azk agent",
      start_fail: "Agent start fail: %s",
      options: {
        action: {
          name: "actions".magenta,
          options: {
            start: "Start azk agent",
            status: "Show the azk agent status",
            stop: "Stop the azk agent running in the background",
          }
        },
        'reload-vm': "Reloads the virtual machine settings",
        daemon: "Runs azk agent in background mode",
      }
    },
    configs: {
      description: "Shows the azk configs values",
    },
    docker: {
      description: "Alias for calling the docker in 'azk' scope configurations",
    },
    doctor: {
      description: "Shows an analysis of the health of `azk`",
      options: {
        logo: "Shows the `azk` logo before show health informations",
      },
    },
    info: {
      description: "Shows systems informactions for the current `Azkfile.js`",
      options: {
        colored: "Outputs with colors",
      },
    },
    logs: {
      description: "Shows logs for the systems",
      options: {
        follow: "Follow log output",
        lines: "Output the specified number of lines at the end of logs",
        timestamps: "Show timestamps",
      },
    },
    shell: {
      description: "Initializes a shell with instance context or runs a arbitrary command",
      invalid_mount: "Invalid mount parameter: `%(value)s`, use `origin=target`",
      invalid_env: "Invalid env variable: `%(value)s`, use `VARIABLE=VALUE`",
      options: {
        T: "Disables pseudo-tty allocation",
        t: "Forces pseudo-tty allocation",
        system  : "A system context to execute a shell or command",
        command : "Runs a specific command",
        shell   : "The path to shell binary",
        verbose : "Shows details about command execution",
        mount   : "Points for additional mounting (ex:./origin:/azk/target)",
        cwd     : "Default directory",
        image   : "Defines the image in which the command will be executed",
        env     : "Additional environment variables",
      },
      examples: [
        '$ azk shell --shell /bin/bash',
        '$ azk shell --mount /:/azk/root -e RAILS_ENV=dev',
        '$ azk shell -c "ls -l /"',
        '$ azk shell --image azukiapp/budybox -t -c "/bin/bash"',
      ]
    },
    help: {
      description: "Shows help about the specific command",
      usage: 'Usage:'.blue + ' $ %s',
      options: "options:".green,
      examples: "examples:".yellow,
    },
    helpers: {
      pull: {
        pulling: 'Pulling repository %s...',
        bar_progress: '  :title [:bar] :percent :progress',
        bar_status: '  :title :msg',
      }
    },
    init: {
      description: "Initializes a project by adding the file Azkfile.js",
      already: "'%s' already exists (try: `--force`)",
      generated: "'%s' generated",
      github: "\nTip:\n  Adds the `.azk` in .gitignore\n  echo '.azk' >> .gitignore \n",
      not_found: "Not found a system(s), generating with example system.",
      options: {
        force: "Forces the overlay file Azkfile.js",
      }
    },
    start: {
      description: "Starts an instance of the system(s)",
      already: "System `%(name)s` already started",
      options: {
        verbose: verbose,
        reprovision: reprovision,
      }
    },
    stop: {
      description: "Stops an instance of the system(s)",
      not_running: "System `%(name)s` not running",
      options: {
        verbose: verbose,
        remove: "Removes the instances before stop",
      }
    },
    scale: {
      instances   : "from " + "%(from)d".red + " to " + "%(to)d".green + " instances",
      description : "Scales (up or down) an instance of the system(s)",
      wait_port   : "◴".magenta + " waiting start `"+ "%(system)s".blue  + "` system, try connect port %(name)s/%(protocol)s...",
      check_image : "✓".cyan    + " checking `"     + "%(image)s".yellow + "` image...",
      pull_image  : "⇲".blue    + " downloading `"  + "%(image)s".yellow + "` image...",
      provision   : "↻".yellow  + " provisioning `" + "%(system)s".blue  + "` system...",
      starting    : "↑".green   + " starting `"     + "%(system)s".blue  + "` system, " + "%(to)d".green + " new instances...",
      stopping    : "↓".red     + " stopping `"     + "%(system)s".blue  + "` system, " + "%(from)d".red + " instances...",
      scaling_up  : "↑".green   + " scaling `"      + "%(system)s".blue  + "` system %(instances)s...",
      scaling_down: "↓".red     + " scaling `"      + "%(system)s".blue  + "` system %(instances)s...",
      options: {
        remove: "Removes the instances before stop",
        verbose: verbose,
      }
    },
    reload: {
      description: "Stops all system, re-provisions and starts again",
      options: {
        verbose: verbose,
        reprovision: reprovision,
      }
    },
    up: {
      description: "Starts all systems following the proper sequence according to dependencies",
    },
    status: {
      description: "Shows systems(s) instances status(es)",
      status: "%(system)s: %(instances)d instances - %(hosts)s",
      status_with_dead: "%(system)s: %(instances)d up and %(down)d down - %(hosts)s",
      options: {
        system: "System(s) name(s)",
        instances: "Shows details about instances",
        all: "Includes all instances (including those terminated)",
      }
    },
    vm: {
      description  : "Controls a virtual machine.",
      already      : "virtual machine already installed.",
      not_installed: "virtual machine is not installed, try `azk vm install`.",
      running      : "virtual machine running.",
      already_running : "virtual machine already running.",
      // TODO not_running
      not_runnig   : "virtual machine is not running, try `azk vm start`.",
      error        : "vm error: %(error)s.",
      not_requires : "this system not requires virtual machine, to try force this behavior set `AZK_USE_VM=true`",
    }
  },

  docker: {
    connect: "connecting to docker: %s..."
  },

  proxy: {
    adding_backend: "adding backend:%(backend)s to hostname:%(hostname)s...",
    removing_backend: "removing backend:%(backend)s to hostname:%(hostname)s...",
    request: "proxy request %s => %s",
    started: "proxy started in %s port",
    not_configured: "host '%s' not configured in proxy"
  },

  test: {
    before: "Before all tasks:",
    remove_containers: "- Removing %s containers before running tests...",
    remove_images: "- Removing %s images before running tests...",
    check_vm: "- Checking for required vm...",
    i18n_test: "test i18n module",
    commands: {
      test_help: {
        description: "Test help description",
        options: {
          verbose: "Verbose mode",
          string: "String option",
          flag: "Boolean flag",
          'flag-default': "Flag with default",
          subcommand: {
            name: "subcommand",
            options: {
              start: "Start service",
              stop: "Stop service",
            },
          }
        },
      },
    },
  }
}
<|endoftext|>


<commit_before>(function($)
{

  $.widget('ui.dmAdminForm', {

    _init: function()
    {
      this.$ = $("#dm_admin_content");

      this.focusFirstInput();
      this.markdown();
      this.selectObject();
      this.checkBoxList();
      this.droppableInput();
      this.hotKeys();
    },

    droppableInput: function()
    {
      $('input.dm_link_droppable, .dm_link_droppable input', this.element).dmDroppableInput();
    },

    focusFirstInput: function()
    {
      if ($firstInput = $('div.sf_admin_form_row_inner input:first', this.$))
      {
        $firstInput.focus();
      }
    },

    hotKeys: function()
    {
      if ($save = $('li.sf_admin_action_save:first input', this.$).orNot())
      {
        var self = this;

        setTimeout(function()
        {
          self.$.bindKey('Ctrl+s', function()
          {
            $save.trigger('click');
            return false;
          });
        }, 1000);
      }
    },

    markdown: function()
    {
      var form = this;

      $('textarea.dm_markdown', form.element).each(function()
      {
        var $editor = $(this);
        var $preview = $('#dm_markdown_preview_'+$editor.metadata().code);
        var value = $editor.val();

				$editor.dmMarkdown();

        var $container = $editor.closest('div.markItUpContainer');

        var resize = function()
        {
          $preview.height($container.innerHeight() - 13);

          $editor.resizable({
            alsoResize: $preview,
            handles: 's'
          }).width($container.width()-6);
        };

        $container.find('div.markItUpHeader ul').append(
          $('
Full Screen
')
          .click(function() {
            $container.toggleClass('dm_markdown_full_screen');

            if($container.hasClass('dm_markdown_full_screen'))
            {
              $editor
              .data('old_height', $editor.height())
              .resizable('destroy').height($(window).height()-90);
              resize();
              window.scrollTo(0, Math.round($container.offset().top) - 40);
            }
            else
            {
              $editor.resizable('destroy').height($editor.data('old_height'));
              resize();
            }
          })
        );

        setInterval(function()
        {
          if ($editor.val() != value)
          {
            value = $editor.val();
            $.ajax({
              type: "POST",
              mode: "abort",
              url: $.dm.ctrl.getHref('+/dmCore/markdown')+"?dm_nolog=1",
              data: {
                text: value
              },
              success: function(html)
              {
                $preview.html(html);
              }
            });
          }
        }, 500);

        resize();
      });
    },

    selectObject: function()
    {
      // Switch to another object
      $("#dm_select_object").bind('change', function()
      {
        location.href = $(this).metadata().href.replace('_ID_', $(this).val());
      });
    },

    checkBoxList: function()
    {
      var $list = $('ul.checkbox_list', this.element);

      $('> li > label, > li > input', $list).click(function(e)
      {
        e.stopPropagation();
      });

      $('> li', $list).click(function()
      {
        var $input = $('> input', $(this));
        $input.attr('checked', !$input.attr('checked')).trigger('change');
      });

      $('> li > input', $list).change(function()
      {
        $(this).parent()[($(this).attr('checked') ? 'add' : 'remove') + 'Class']('active');
        return true;
      }).trigger('change');

      $('div.control span.select_all, div.control span.unselect_all', $list.parent().parent()).each(function()
      {
        $(this).click(function()
        {
          $(this).closest('div.sf_admin_form_row_inner').find('input:checkbox').attr('checked', $(this).hasClass('select_all')).trigger('change');
        });
      });
    }

  });

})(jQuery);
<commit_msg>[Diem] - admin markdown editor and preview scrolls are synced when at the bottom<commit_after>(function($)
{

  $.widget('ui.dmAdminForm', {

    _init: function()
    {
      this.$ = $("#dm_admin_content");

      this.focusFirstInput();
      this.markdown();
      this.selectObject();
      this.checkBoxList();
      this.droppableInput();
      this.hotKeys();
    },

    droppableInput: function()
    {
      $('input.dm_link_droppable, .dm_link_droppable input', this.element).dmDroppableInput();
    },

    focusFirstInput: function()
    {
      if ($firstInput = $('div.sf_admin_form_row_inner input:first', this.$))
      {
        $firstInput.focus();
      }
    },

    hotKeys: function()
    {
      if ($save = $('li.sf_admin_action_save:first input', this.$).orNot())
      {
        var self = this;

        setTimeout(function()
        {
          self.$.bindKey('Ctrl+s', function()
          {
            $save.trigger('click');
            return false;
          });
        }, 1000);
      }
    },

    markdown: function()
    {
      var form = this;

      $('textarea.dm_markdown', form.element).each(function()
      {
        var $editor = $(this);
        var $preview = $('#dm_markdown_preview_'+$editor.metadata().code);
        var value = $editor.val();

				$editor.dmMarkdown();

        var $container = $editor.closest('div.markItUpContainer');

        $editor.bind('scroll', function()
        {
          if($editor.scrollTop()+$editor.height() == $editor[0].scrollHeight)
          {
            $preview.scrollTop($preview[0].scrollHeight - $preview.height());
          }
        });

        var resize = function()
        {
          $preview.height($container.innerHeight() - 13);

          $editor.resizable({
            alsoResize: $preview,
            handles: 's'
          }).width($container.width()-6);
        };

        $container.find('div.markItUpHeader ul').append(
          $('
Full Screen
')
          .click(function() {
            $container.toggleClass('dm_markdown_full_screen');

            if($container.hasClass('dm_markdown_full_screen'))
            {
              $editor
              .data('old_height', $editor.height())
              .resizable('destroy').height($(window).height()-90);
              resize();
              window.scrollTo(0, Math.round($container.offset().top) - 40);
            }
            else
            {
              $editor.resizable('destroy').height($editor.data('old_height'));
              resize();
            }
          })
        );

        setInterval(function()
        {
          if ($editor.val() != value)
          {
            value = $editor.val();
            $.ajax({
              type: "POST",
              mode: "abort",
              url: $.dm.ctrl.getHref('+/dmCore/markdown')+"?dm_nolog=1",
              data: {
                text: value
              },
              success: function(html)
              {
                $preview.html(html);
              }
            });
          }
        }, 500);

        resize();
      });
    },

    selectObject: function()
    {
      // Switch to another object
      $("#dm_select_object").bind('change', function()
      {
        location.href = $(this).metadata().href.replace('_ID_', $(this).val());
      });
    },

    checkBoxList: function()
    {
      var $list = $('ul.checkbox_list', this.element);

      $('> li > label, > li > input', $list).click(function(e)
      {
        e.stopPropagation();
      });

      $('> li', $list).click(function()
      {
        var $input = $('> input', $(this));
        $input.attr('checked', !$input.attr('checked')).trigger('change');
      });

      $('> li > input', $list).change(function()
      {
        $(this).parent()[($(this).attr('checked') ? 'add' : 'remove') + 'Class']('active');
        return true;
      }).trigger('change');

      $('div.control span.select_all, div.control span.unselect_all', $list.parent().parent()).each(function()
      {
        $(this).click(function()
        {
          $(this).closest('div.sf_admin_form_row_inner').find('input:checkbox').attr('checked', $(this).hasClass('select_all')).trigger('change');
        });
      });
    }

  });

})(jQuery);
<|endoftext|>


<commit_before>/* eslint-disable */
import { useStrict, observe } from "mobx";
import ProjectStore from "../../stores/domain/ProjectStore";
import Suite from "../../models/Suite";
import TestCase from "../../models/TestCase";

useStrict(true);

describe("Suite model", () => {
  it("new suite should be named 'Utitled Suite'", () => {
    expect((new Suite()).name).toBe("Untitled Suite");
  });
  it("should observe name changes", () => {
    const suite = new Suite();
    const disposer = observe(suite, "name", (change) => {
      expect(change.newValue).toBe("changed");
    });
    suite.name = "changed";
    disposer();
  });
  it("Suites should have randomly generated identifiers", () => {
    expect((new Suite()).id).not.toBe((new Suite()).id);
  });
  it("should observe when a new Test Case is added", () => {
    const suite = new Suite();
    const disposer = observe(suite, "tests", (change) => {
      expect(change.newValue.length).toBe(1);
    });
    suite.tests.push(new TestCase());
  });
  it("should add a new Test Case", () => {
    const store = new ProjectStore();
    const suite = new Suite();
    const test = new TestCase();
    store.addTestCase(test);
    expect(suite.tests.length).toBe(0);
    suite.addTestCase(test);
    expect(suite.tests.length).toBe(1);
  });
  it("should throw if no Test Case was given", () => {
    const suite = new Suite();
    expect(() => suite.addTestCase()).toThrowError("Expected to receive TestCase instead received undefined");
  });
  it("should throw if a different type was given", () => {
    const suite = new Suite();
    expect(() => suite.addTestCase(1)).toThrowError("Expected to receive TestCase instead received Number");
  });
  it("should remove a Test Case from the suite", () => {
    const store = new ProjectStore();
    const suite = new Suite();
    const test = new TestCase();
    store.addTestCase(test);
    suite.addTestCase(test);
    expect(suite.tests.length).toBe(1);
    suite.removeTestCase(test);
    expect(suite.tests.length).toBe(0);
  });
  it("should do nothing if removed a non-existent test", () => {
    const store = new ProjectStore();
    const suite = new Suite();
    const test = new TestCase();
    store.addTestCase(test);
    suite.addTestCase(test);
    expect(suite.tests.length).toBe(1);
    suite.removeTestCase(new TestCase());
    expect(suite.tests.length).toBe(1);
  });
});
<commit_msg>tests replacement test<commit_after>/* eslint-disable */
import { useStrict, observe } from "mobx";
import ProjectStore from "../../stores/domain/ProjectStore";
import Suite from "../../models/Suite";
import TestCase from "../../models/TestCase";

useStrict(true);

describe("Suite model", () => {
  it("new suite should be named 'Utitled Suite'", () => {
    expect((new Suite()).name).toBe("Untitled Suite");
  });
  it("should observe name changes", () => {
    const suite = new Suite();
    const disposer = observe(suite, "name", (change) => {
      expect(change.newValue).toBe("changed");
    });
    suite.name = "changed";
    disposer();
  });
  it("Suites should have randomly generated identifiers", () => {
    expect((new Suite()).id).not.toBe((new Suite()).id);
  });
  it("should observe when a new Test Case is added", () => {
    const suite = new Suite();
    const disposer = observe(suite, "tests", (change) => {
      expect(change.newValue.length).toBe(1);
    });
    suite.tests.push(new TestCase());
  });
  it("should add a new Test Case", () => {
    const store = new ProjectStore();
    const suite = new Suite();
    const test = new TestCase();
    store.addTestCase(test);
    expect(suite.tests.length).toBe(0);
    suite.addTestCase(test);
    expect(suite.tests.length).toBe(1);
  });
  it("should throw if no Test Case was given", () => {
    const suite = new Suite();
    expect(() => suite.addTestCase()).toThrowError("Expected to receive TestCase instead received undefined");
  });
  it("should throw if a different type was given", () => {
    const suite = new Suite();
    expect(() => suite.addTestCase(1)).toThrowError("Expected to receive TestCase instead received Number");
  });
  it("should remove a Test Case from the suite", () => {
    const store = new ProjectStore();
    const suite = new Suite();
    const test = new TestCase();
    store.addTestCase(test);
    suite.addTestCase(test);
    expect(suite.tests.length).toBe(1);
    suite.removeTestCase(test);
    expect(suite.tests.length).toBe(0);
  });
  it("should do nothing if removed a non-existent test", () => {
    const store = new ProjectStore();
    const suite = new Suite();
    const test = new TestCase();
    store.addTestCase(test);
    suite.addTestCase(test);
    expect(suite.tests.length).toBe(1);
    suite.removeTestCase(new TestCase());
    expect(suite.tests.length).toBe(1);
  });
  it("should replace the tests in the suite", () => {
    const store = new ProjectStore();
    const suite = new Suite();
    store.createTestCase();
    store.createTestCase();
    store.createTestCase();
    expect(suite.tests.length).toBe(0);
    suite.replaceTests(store.tests.peek());
    expect(suite.tests.length).toBe(3);
  });
});
<|endoftext|>


<commit_before>// ==========================================================================
// Project:   SproutCore Statechart - Hierarchical State Machine Library
// Copyright: ©2009 Sprout Systems, Inc. and contributors.
//            Portions ©2009 Apple, Inc. All rights reserved.
// License:   Licened under MIT license (see license.js)
// ==========================================================================

sc_require('system/dispatch') ;

var _sc_log = function(text) {
  console.log(text) ;
};

var _sc_alert = function(text) {
  alert(text) ;
};

SC.mixin(SC.Object.prototype,
/** SC.Object.prototype */ {

  /** @private
    Enters a given state. This method is overriden in debug mode to implement
    state tracing.

    @param {String} state a local property containing a state handler
    @returns {SC.EVT_HANDLED_RES or undefined}
  */
  _sc_statechart_enter: function(state) {
    var depth = this._sc_state_depth++ ;

    var pre = '' ;
    while (--depth >= 0) pre = pre + '  ' ;

    if (this.get('sc_trace')) {
      var fun = this.get('sc_singleStep') ? _sc_alert : _sc_log ;
      fun(pre + "-> entering \"" + state + '"') ;
    }
    return this[state](SC.EVT_ENTER) ;
  },

  /** @private
    Exits a given state. This method is overriden in debug mode to implement
    state tracing.

    @param {String} state a local property containing a state handler
    @returns {SC.EVT_HANDLED_RES or undefined}
  */
  _sc_statechart_exit: function(state) {
    var depth = this._sc_state_depth-- ;

    var pre = '' ;
    while (--depth > 0) pre = pre + '  ' ;

    if (this.get('sc_trace')) {
      var fun = this.get('sc_singleStep') ? _sc_alert : _sc_log ;
      fun(pre + "<- leaving  \"" + state + '"') ;
    }
    return this[state](SC.EVT_EXIT) ;
  },

  /** @private
    Inits a given state. This method is overriden in debug mode to implement
    state tracing.

    @param {String} state a local property containing a state handler
    @returns {SC.EVT_TRANSITION_RES or undefined}
  */
  _sc_statechart_init: function(state) {
    var depth = this._sc_state_depth ;

    var pre = '' ;
    while (--depth > 0) pre = pre + '  ' ;

    var res = this[state](SC.EVT_INIT), stateKey = this.get('stateKey') ;
    if (this.get('sc_trace') && res === SC.EVT_TRANSITION_RES) {
      var fun = this.get('sc_singleStep') ? _sc_alert : _sc_log ;
      fun(pre + "  (taking default transition to \"" + this[stateKey] + '")') ;
    }
    return res ;
  },

  /** @private
    Sends an event to the given state. This method is overriden in debug mode
    to implement state tracing.

    @param {String} state a local property containing a state handler
    @returns {SC.EVT_HANDLED_RES, SC.EVT_TRANSITION_RES, or undefined}
  */
  _sc_statechart_event: function(state, evt, depth) {
    var pre = '' ;
    while (--depth > 0) pre = pre + '  ' ;

    var res = this[state](evt), stateKey = this.get('stateKey') ;
    if (this.get('sc_trace')) {
      var fun = this.get('sc_singleStep') ? _sc_alert : _sc_log ;
      if (res) {
        if (res === SC.EVT_HANDLED_RES) {
          fun(pre + '"' + state + '" handled event \'' + evt.sig + '\' (no transition)') ;
        } else if (res === SC.EVT_TRANSITION_RES) {
          fun(pre + '"' + state + '" handled event \'' + evt.sig + '\' with a transition to \"' + this[stateKey] + '"') ;
        }
      } else fun(pre + '"' + state + '" ignored event \'' + evt.sig + "'") ;
    }
    return res ;
  }

});
<commit_msg>update to use StatechartDebugger when present<commit_after>// ==========================================================================
// Project:   SproutCore Statechart - Hierarchical State Machine Library
// Copyright: ©2009 Sprout Systems, Inc. and contributors.
//            Portions ©2009 Apple, Inc. All rights reserved.
// License:   Licened under MIT license (see license.js)
// ==========================================================================

sc_require('system/dispatch') ;

var _sc_log = function(text) {
  if (StatechartDebugger) {
    this.set('sc_lastMessage', text) ;
  } else console.log(text) ;
};

var _sc_alert = function(text) {
  alert(text) ;
};

SC.mixin(SC.Object.prototype,
/** SC.Object.prototype */ {

  /** @private
    Enters a given state. This method is overriden in debug mode to implement
    state tracing.

    @param {String} state a local property containing a state handler
    @returns {SC.EVT_HANDLED_RES or undefined}
  */
  _sc_statechart_enter: function(state) {
    var depth = this._sc_state_depth++ ;

    var pre = '' ;
    while (--depth >= 0) pre = pre + '  ' ;

    if (this.get('sc_trace')) {
      var fun = this.get('sc_singleStep') ? _sc_alert : _sc_log ;
      fun.call(this, pre + "-> entering \"" + state + '"') ;
    }
    return this[state](SC.EVT_ENTER) ;
  },

  /** @private
    Exits a given state. This method is overriden in debug mode to implement
    state tracing.

    @param {String} state a local property containing a state handler
    @returns {SC.EVT_HANDLED_RES or undefined}
  */
  _sc_statechart_exit: function(state) {
    var depth = this._sc_state_depth-- ;

    var pre = '' ;
    while (--depth > 0) pre = pre + '  ' ;

    if (this.get('sc_trace')) {
      var fun = this.get('sc_singleStep') ? _sc_alert : _sc_log ;
      fun.call(this, pre + "<- leaving  \"" + state + '"') ;
    }
    return this[state](SC.EVT_EXIT) ;
  },

  /** @private
    Inits a given state. This method is overriden in debug mode to implement
    state tracing.

    @param {String} state a local property containing a state handler
    @returns {SC.EVT_TRANSITION_RES or undefined}
  */
  _sc_statechart_init: function(state) {
    var depth = this._sc_state_depth ;

    var pre = '' ;
    while (--depth > 0) pre = pre + '  ' ;

    var res = this[state](SC.EVT_INIT), stateKey = this.get('stateKey') ;
    if (this.get('sc_trace') && res === SC.EVT_TRANSITION_RES) {
      var fun = this.get('sc_singleStep') ? _sc_alert : _sc_log ;
      fun.call(this, pre + "  (taking default transition to \"" + this[stateKey] + '")') ;
    }
    return res ;
  },

  /** @private
    Sends an event to the given state. This method is overriden in debug mode
    to implement state tracing.

    @param {String} state a local property containing a state handler
    @returns {SC.EVT_HANDLED_RES, SC.EVT_TRANSITION_RES, or undefined}
  */
  _sc_statechart_event: function(state, evt, depth) {
    var pre = '' ;
    while (--depth > 0) pre = pre + '  ' ;

    var res = this[state](evt), stateKey = this.get('stateKey') ;
    if (this.get('sc_trace')) {
      var fun = this.get('sc_singleStep') ? _sc_alert : _sc_log ;
      if (res) {
        if (res === SC.EVT_HANDLED_RES) {
          fun.call(this, pre + '"' + state + '" handled event \'' + evt.sig + '\' (no transition)') ;
        } else if (res === SC.EVT_TRANSITION_RES) {
          fun.call(this, pre + '"' + state + '" handled event \'' + evt.sig + '\' with a transition to \"' + this[stateKey] + '"') ;
        }
      } else fun.call(this, pre + '"' + state + '" ignored event \'' + evt.sig + "'") ;
    }
    return res ;
  }

});
<|endoftext|>


<commit_before>var gpio = require("pi-gpio");

var inPin = 7;

blink(1);

function blink(status) {
	console.log('GPIO set to: ' + status);
    gpio.open(inPin, "output", function(err) {
	    gpio.write(inPin, status, function() {
	        gpio.close(inPin);
	        setTimeout(function() {
	        	status = (status + 1) % 2;
    			blink(status);
			}, 2000);
	    });
	});
}

process.on('SIGINT', function() {
    console.log('Caught interrupt signal, turning LED off!');
    gpio.write(inPin, 0, function() {
	    gpio.close(inPin);
	    process.exit();
	});
});<commit_msg>Adding blink<commit_after>var gpio = require("pi-gpio");

var inPin = 7;

blink(1);

function blink(status) {
	console.log('GPIO set to: ' + status);
    gpio.open(inPin, "output", function(err) {
	    gpio.write(inPin, status, function() {
	        gpio.close(inPin);
	        setTimeout(function() {
	        	status = (status + 1) % 2;
    			blink(status);
			}, 2000);
	    });
	});
}

process.on('SIGINT', function() {
    gpio.write(inPin, 0, function() {
	    gpio.close(inPin);
	    console.log('Bye, bye!')
	    process.exit();
	});
});<|endoftext|>


<commit_before>import React from 'react';
import {
	View,
	Dimensions,
	ScrollView,
	Text,
	StyleSheet,
	TouchableOpacity,
	Switch
} from 'react-native';
import { connect } from 'react-redux';
import ElevatedView from 'react-native-elevated-view';
import SideMenu from 'react-native-side-menu';
import Icon from 'react-native-vector-icons/FontAwesome';

import SearchBar from './SearchBar';
import SearchMap from './SearchMap';
import SearchResults from './SearchResults';
import SearchHistoryCard from './SearchHistoryCard';
import NearbyService from '../../services/nearbyService';

const css = require('../../styles/css');
const logger = require('../../util/logger');
const shuttle = require('../../util/shuttle');
const AppSettings = 		require('../../AppSettings');

import general, { getPRM } from '../../util/general';

let navBarMarginTop = 64;
let searchMargin = navBarMarginTop;

if (general.platformAndroid()) {
	navBarMarginTop = 64;
	searchMargin = 0;
}

const deviceHeight = Dimensions.get('window').height;
const deviceWidth = Dimensions.get('window').width;

const MAXIMUM_HEIGHT = deviceHeight - navBarMarginTop;
const MINUMUM_HEIGHT = navBarMarginTop;

const shuttle_stops = require('../../json/shuttle_stops_master_map.json');
const shuttle_routes = require('../../json/shuttle_routes_master_map.json');

class NearbyMapView extends React.Component {

	constructor(props) {
		super(props);

		this.state = {
			searchInput: null,
			searchResults: null,
			selectedResult: null,
			sliding: false,
			typing: false,
			allowScroll: true,
			iconStatus: 'menu',
			showBar: true,
			showMenu: false,
		};
	}

	componentWillMount() {
		Object.keys(shuttle_routes).map((key, index) => {
			this.setState({ ['route' + key] : true });
			return null;
		});
	}

	shouldComponentUpdate(nextProps, nextState) {
		// return true;
		// Don't re-render if location hasn't changed
		if (((this.props.location.coords.latitude !== nextProps.location.coords.latitude) ||
			(this.props.location.coords.longitude !== nextProps.location.coords.longitude)) ||
			this.state !== nextState) {
			/*
			(this.state.selectedResult !== nextState.selectedResult) ||
			(this.state.iconStatus !== nextState.iconStatus) ||
			(this.state.showBar !== nextState.showBar) ||
			(this.state.showMenu !== nextState.showMenu) ||
			(this.state.route1 !== nextState.route1)) {*/

			return true;
		} else {
			return false;
		}
	}

	pressIcon = () => {
		if (this.state.iconStatus === 'back') {
			this.setState({
				iconStatus: 'menu',
				showBar: true
			});
			this.scrollRef.scrollTo({ x: 0, y: 0, animated: true });
			// this.barRef.clear();
			this.barRef.blur();
		} else if (this.state.iconStatus === 'menu') {
			console.log("Hello");
			this.updateMenuState(true);
		}
	}

	pressHistory = (text) => {
		this.pressIcon();
		this.updateSearch(text);
	}

	gotoResults = () => {
		this.setState({
			iconStatus: 'back',
			showBar: false
		});
		this.scrollRef.scrollTo({ x: 0, y: deviceHeight - Math.round(44 * getPRM()) + 6, animated: true });
	}

	focusSearch = () => {
		this.scrollRef.scrollTo({ x: 0, y: (2 * deviceHeight) - Math.round(2 * 44 * getPRM()) - 12, animated: true });
		this.setState({
			iconStatus: 'back',
			showBar: false
		});
	}

	updateSearch = (text) => {
		NearbyService.FetchSearchResults(text).then((result) => {
			if (result.results) {
				this.setState({
					searchInput: text,
					searchResults: result.results,
					selectedResult: result.results[0],
					showBar: true
				});
				this.scrollRef.scrollTo({ x: 0, y: 0, animated: true });
			} else {
				// handle no results
			}
		});
	}

	updateSelectedResult = (index) => {
		const newSelect = this.state.searchResults[index];
		this.setState({
			iconStatus: 'menu',
			selectedResult: newSelect,
			showBar: true
		});
		this.scrollRef.scrollTo({ x: 0, y: 0, animated: true });
	}

	updateMenuState = (showMenu) => {
		this.setState({ showMenu, });
	}

	toggleRoute = (value, key) => {
		if (value === false) {
			// Delete route from every stop
			Object.keys(shuttle_routes[key].stops).map((key2, index2) => {
				console.log("Deleting");
				if (shuttle_stops[key2])
					delete shuttle_stops[key2].routes[key];
				return null;
			});
		} else {
			// Add route to every stop
			Object.keys(shuttle_routes[key].stops).map((key2, index2) => {
				console.log("Adding " + key2);
				//console.log(JSON.stringify(shuttle_stops[key2]));
				if (shuttle_stops[key2])
					shuttle_stops[key2].routes[key] = shuttle_routes[key];
				return null;
			});
		}
		this.setState({ ['route' + key] : value });
	}

	render() {
		const menu = (
			<ScrollView scrollsToTop={false} style={styles.menu}>
				<View>
					{
						// Create switch for every shuttle route
						Object.keys(shuttle_routes).map((key, index) => (
							<View>
								<Text>{shuttle_routes[key].name.trim()}</Text>
								<Switch
									onValueChange={(val) => this.toggleRoute(val, key)}
									value={this.state['route' + key]}
								/>
							</View>
							)
						)
					}
				</View>
			</ScrollView>
		);

		if (this.props.location.coords) {
			return (
				<SideMenu
					menu={menu}
					isOpen={this.state.showMenu}
					onChange={(isOpen) => this.updateMenuState(isOpen)}
				>
					<View style={css.main_container}>
						<View
							// Only necessary for ios?
							style={{
								zIndex: 1
							}}
						>
							<SearchBar
								update={this.updateSearch}
								onFocus={this.focusSearch}
								pressIcon={this.pressIcon}
								iconStatus={this.state.iconStatus}
								searchInput={this.state.searchInput}
								reff={
									(ref) => { this.barRef = ref; }
								}
							/>
						</View>
						<ScrollView
							ref={
								(ref) => {
									this.scrollRef = ref;
								}
							}
							showsVerticalScrollIndicator={false}
							scrollEnabled={this.state.allowScroll}
						>
							<SearchMap
								location={this.props.location}
								selectedResult={this.state.selectedResult}
								style={styles.map_container}
								hideMarker={this.state.sliding}
								shuttle={shuttle_stops}
							/>
							<View
								style={styles.bottomContainer}
							>
								<View
									style={styles.spacer}
								/>
								<SearchResults
									results={this.state.searchResults}
									onSelect={(index) => this.updateSelectedResult(index)}
								/>
								<View
									style={styles.spacer}
								/>
								<SearchHistoryCard
									pressHistory={this.pressHistory}
								/>
								<View
									style={styles.spacer}
								/>
							</View>
						</ScrollView>
						{(this.state.showBar) ? (
								<ElevatedView
									style={styles.bottomBarContainer}
									elevation={5}
								>
									<TouchableOpacity
										onPress={
											this.gotoResults
										}
									>
										<Text
											style={styles.bottomBarText}
										>
											See More Results
										</Text>
									</TouchableOpacity>
								</ElevatedView>
								) : (null)
							}
					</View>
				</SideMenu>
			);
		} else {
			return null;
		}
	}
}

function mapStateToProps(state, props) {
	return {
		location: state.location.position,
		locationPermission: state.location.permission
	};
}

module.exports = connect(mapStateToProps)(NearbyMapView);

const styles = StyleSheet.create({
	bottomBarContainer: { flex: 1, alignItems: 'center', justifyContent: 'center', position: 'absolute', bottom: 0, width: deviceWidth, height: Math.round(44 * getPRM()), borderWidth: 0, backgroundColor: 'white', },
	bottomBarContent: { flex:1, alignItems:'center', justifyContent:'center' },
	bottomBarText: { textAlign: 'center', },

	bottomContainer: { minHeight: deviceHeight },
	map_container : { flex: 1, width: deviceWidth, height: deviceHeight - Math.round(44 * getPRM()), },
	spacer: { height: Math.round(44 * getPRM()) + 12 },
});
<commit_msg>Fixed positioning for mapsearch bottombar<commit_after>import React from 'react';
import {
	View,
	Dimensions,
	ScrollView,
	Text,
	StyleSheet,
	TouchableOpacity,
	Switch
} from 'react-native';
import { connect } from 'react-redux';
import ElevatedView from 'react-native-elevated-view';
import SideMenu from 'react-native-side-menu';
import Icon from 'react-native-vector-icons/FontAwesome';

import SearchBar from './SearchBar';
import SearchMap from './SearchMap';
import SearchResults from './SearchResults';
import SearchHistoryCard from './SearchHistoryCard';
import NearbyService from '../../services/nearbyService';

const css = require('../../styles/css');
const logger = require('../../util/logger');
const shuttle = require('../../util/shuttle');
const AppSettings = 		require('../../AppSettings');

import general, { getPRM } from '../../util/general';

let navBarMarginTop = 64;
let searchMargin = navBarMarginTop;

if (general.platformAndroid()) {
	navBarMarginTop = 64;
	searchMargin = 0;
}

const deviceHeight = Dimensions.get('window').height;
const deviceWidth = Dimensions.get('window').width;

const MAXIMUM_HEIGHT = deviceHeight - navBarMarginTop;
const MINUMUM_HEIGHT = navBarMarginTop;

const shuttle_stops = require('../../json/shuttle_stops_master_map.json');
const shuttle_routes = require('../../json/shuttle_routes_master_map.json');

class NearbyMapView extends React.Component {

	constructor(props) {
		super(props);

		this.state = {
			searchInput: null,
			searchResults: null,
			selectedResult: null,
			sliding: false,
			typing: false,
			allowScroll: true,
			iconStatus: 'menu',
			showBar: true,
			showMenu: false,
		};
	}

	componentWillMount() {
		Object.keys(shuttle_routes).map((key, index) => {
			this.setState({ ['route' + key] : true });
			return null;
		});
	}

	shouldComponentUpdate(nextProps, nextState) {
		// return true;
		// Don't re-render if location hasn't changed
		if (((this.props.location.coords.latitude !== nextProps.location.coords.latitude) ||
			(this.props.location.coords.longitude !== nextProps.location.coords.longitude)) ||
			this.state !== nextState) {
			/*
			(this.state.selectedResult !== nextState.selectedResult) ||
			(this.state.iconStatus !== nextState.iconStatus) ||
			(this.state.showBar !== nextState.showBar) ||
			(this.state.showMenu !== nextState.showMenu) ||
			(this.state.route1 !== nextState.route1)) {*/

			return true;
		} else {
			return false;
		}
	}

	pressIcon = () => {
		if (this.state.iconStatus === 'back') {
			this.setState({
				iconStatus: 'menu',
				showBar: true
			});
			this.scrollRef.scrollTo({ x: 0, y: 0, animated: true });
			// this.barRef.clear();
			this.barRef.blur();
		} else if (this.state.iconStatus === 'menu') {
			this.updateMenuState(true);
		}
	}

	pressHistory = (text) => {
		this.pressIcon();
		this.updateSearch(text);
	}

	gotoResults = () => {
		this.setState({
			iconStatus: 'back',
			showBar: false
		});
		this.scrollRef.scrollTo({ x: 0, y: deviceHeight - Math.round(44 * getPRM()) + 6, animated: true });
	}

	focusSearch = () => {
		this.scrollRef.scrollTo({ x: 0, y: (2 * deviceHeight) - Math.round(2 * 44 * getPRM()) - 12, animated: true });
		this.setState({
			iconStatus: 'back',
			showBar: false
		});
	}

	updateSearch = (text) => {
		NearbyService.FetchSearchResults(text).then((result) => {
			if (result.results) {
				this.setState({
					searchInput: text,
					searchResults: result.results,
					selectedResult: result.results[0],
					showBar: true
				});
				this.scrollRef.scrollTo({ x: 0, y: 0, animated: true });
			} else {
				// handle no results
			}
		});
	}

	updateSelectedResult = (index) => {
		const newSelect = this.state.searchResults[index];
		this.setState({
			iconStatus: 'menu',
			selectedResult: newSelect,
			showBar: true
		});
		this.scrollRef.scrollTo({ x: 0, y: 0, animated: true });
	}

	updateMenuState = (showMenu) => {
		this.setState({ showMenu, });
	}

	toggleRoute = (value, key) => {
		if (value === false) {
			// Delete route from every stop
			Object.keys(shuttle_routes[key].stops).map((key2, index2) => {
				console.log("Deleting");
				if (shuttle_stops[key2])
					delete shuttle_stops[key2].routes[key];
				return null;
			});
		} else {
			// Add route to every stop
			Object.keys(shuttle_routes[key].stops).map((key2, index2) => {
				console.log("Adding " + key2);
				//console.log(JSON.stringify(shuttle_stops[key2]));
				if (shuttle_stops[key2])
					shuttle_stops[key2].routes[key] = shuttle_routes[key];
				return null;
			});
		}
		this.setState({ ['route' + key] : value });
	}

	render() {
		const menu = (
			<ScrollView scrollsToTop={false} style={styles.menu}>
				<View>
					{
						// Create switch for every shuttle route
						Object.keys(shuttle_routes).map((key, index) => (
							<View>
								<Text>{shuttle_routes[key].name.trim()}</Text>
								<Switch
									onValueChange={(val) => this.toggleRoute(val, key)}
									value={this.state['route' + key]}
								/>
							</View>
							)
						)
					}
				</View>
			</ScrollView>
		);
		console.log("SHOWBAR: " + this.state.showBar);

		if (this.props.location.coords) {
			return (
				<SideMenu
					menu={menu}
					isOpen={this.state.showMenu}
					onChange={(isOpen) => this.updateMenuState(isOpen)}
				>
					<View style={css.main_container}>
						<View
							// Only necessary for ios?
							style={{
								zIndex: 1
							}}
						>
							<SearchBar
								update={this.updateSearch}
								onFocus={this.focusSearch}
								pressIcon={this.pressIcon}
								iconStatus={this.state.iconStatus}
								searchInput={this.state.searchInput}
								reff={
									(ref) => { this.barRef = ref; }
								}
							/>
						</View>
						<ScrollView
							ref={
								(ref) => {
									this.scrollRef = ref;
								}
							}
							showsVerticalScrollIndicator={false}
							scrollEnabled={this.state.allowScroll}
						>
							<SearchMap
								location={this.props.location}
								selectedResult={this.state.selectedResult}
								style={styles.map_container}
								hideMarker={this.state.sliding}
								shuttle={shuttle_stops}
							/>
							<View
								style={styles.bottomContainer}
							>
								<View
									style={styles.spacer}
								/>
								<SearchResults
									results={this.state.searchResults}
									onSelect={(index) => this.updateSelectedResult(index)}
								/>
								<View
									style={styles.spacer}
								/>
								<SearchHistoryCard
									pressHistory={this.pressHistory}
								/>
								<View
									style={styles.spacer}
								/>
							</View>
						</ScrollView>
						{(this.state.showBar) ? (
							<ElevatedView
								style={styles.bottomBarContainer}
								elevation={5}
							>
								<TouchableOpacity
									onPress={
										this.gotoResults
									}
								>
									<Text
										style={styles.bottomBarText}
									>
										See More Results
									</Text>
								</TouchableOpacity>
							</ElevatedView>
							) : (null)
						}
					</View>
				</SideMenu>
			);
		} else {
			return null;
		}
	}
}

function mapStateToProps(state, props) {
	return {
		location: state.location.position,
		locationPermission: state.location.permission
	};
}

module.exports = connect(mapStateToProps)(NearbyMapView);

const styles = StyleSheet.create({
	bottomBarContainer: { zIndex: 1, flex: 1, alignItems: 'center', justifyContent: 'center', position: 'absolute', bottom: Math.round(44 * getPRM()) + 24, width: deviceWidth, height: Math.round(44 * getPRM()), borderWidth: 0, backgroundColor: 'white', },
	bottomBarContent: { flex:1, alignItems:'center', justifyContent:'center' },
	bottomBarText: { textAlign: 'center', },

	bottomContainer: { minHeight: deviceHeight },
	map_container : { flex: 1, width: deviceWidth, height: deviceHeight - Math.round(44 * getPRM()), },
	spacer: { height: Math.round(44 * getPRM()) + 12 },
});
<|endoftext|>


<commit_before>jdata {
    int y as broadcaster;
    struct{
    	int apple;
    	float pear;
    } s as broadcaster;
}

setInterval(function() {
    y = Math.floor((Math.random() * 100) + 1);
    s = {.apple:y, .pear:y+0.1};
}, 1000);
<commit_msg>Updated broadcaster samples<commit_after>jdata {
    int y as broadcaster;
    struct myType{
    	int apple;
    	float pear;
    } s as broadcaster;
}

setInterval(function() {
    y = Math.floor((Math.random() * 100) + 1);
    s = {apple:y, pear:y+0.1};
}, 1000);
<|endoftext|>


<commit_before>var http = require("http");
var os = require("os");
var url = process.argv[2] || "http://localhost:8090";

process.stdin.setEncoding('utf8');

http.get(url, function(res) {
    if (res.statusCode === 200) {
        console.log("Connected to " + url + ".");
        repl();
    }
    else
        console.log("Got code " + res.statusCode + ".");
}).on('error', function(e) {
    console.log("Got error: " + e.message);
});

function repl() {
    process.stdout.write("> ");

    process.stdin.on('readable', function() {
        var chunk = process.stdin.read();

        if (chunk === null)
            return;

        if (chunk === "quit" + os.EOL
            || chunk === "exit" + os.EOL
            || chunk === "q" + os.EOL)
            process.exit();

        process.stdout.write('data: ' + chunk);
        process.stdout.write("> ");
    });
}<commit_msg>Client should work now.<commit_after>var http = require("http");
var rl = require("readline");
var url = process.argv[2] || "http://localhost:8090";

process.stdin.setEncoding('utf8');

var prompt = rl.createInterface({
    input: process.stdin,
    output: process.stdout
});

http.get(url, function(res) {
    if (res.statusCode === 200) {
        console.log("Connected to " + url + ".");
        prompt.question("> ", get_input);
    }
    else
        console.log("Got code " + res.statusCode + ".");
}).on('error', function(e) {
    console.log("Got error: " + e.message);
});

// Matches ["http"/"https", hostname, path, port].
var url_parser_regex = /(http|https):\/\/([^:\/]*)([^:]*)?:(\d*)/;
var parsed_url = url.match(url_parser_regex);

if (parsed_url === null) {
    console.log("Could not parse " + url + "!");
}

var post_options = {
    host: parsed_url[2],
    path: parsed_url[3] || "",
    port: parsed_url[4] || 80,
    method: 'POST',
    headers: {
        'Content-Type': "text/javascript",
        'Content-Length': 0
    }
};

function send_command(command) {
    post_options.headers["Content-Length"] = command.length;

    var post_req = http.request(post_options, function(res) {
        res.setEncoding("utf8");
        res.on("data", function (chunk) {
            if (chunk[chunk.length - 1] === "\n")
                prompt.write("Received:" + chunk);
            else
                prompt.write("Received: " + chunk + "\n");
        });
        res.on("end", function() {
            prompt.question("> ", get_input);
        });
    });

    post_req.write(command);
    post_req.end();
}

function get_input(str) {
    if (str === null)
        return;

    if (str === "quit"
        || str === "exit")
        process.exit();

    prompt.write("Sending: " + str + "\n");
    send_command(str);
    prompt.pause();
}<|endoftext|>


<commit_before>#!/usr/bin/env node

/* Writes files for JSON representation of all individuals on tracks with a given individual */

var EventEmitter = require("events").EventEmitter;
var argv = require("minimist")(process.argv.slice(2));
var fs = require("graceful-fs");

var logger = new EventEmitter();

if (! argv.q) {
  logger.on("log", function (msg) {
    console.log(msg);
  });
}

var sourceDataDir = __dirname + "/../node_modules/music-routes-data/data";
var individuals = require(sourceDataDir + "/individuals.json");
var individualIds = individuals.map(function(elem) { return elem._id; });
var individual_track = require(sourceDataDir + "/individual_track.json");
var tracks = require(sourceDataDir + "/tracks.json");
var releases = require(sourceDataDir + "/releases.json");
var track_release = require(sourceDataDir + "/track_release.json");

var getName = function (id) {
  return individuals.filter(function(elem) {
    return elem._id === id;
  })[0].names[0];
};

var generateJson = function (individualId) {
  logger.emit("log", "Generating JSON data for individual with ID of " + individualId + "...");

  var sourceLabel = getName(individualId);

  var tracksWithIndividual = individual_track.filter(function (elem) {
    return elem.individual_id === individualId;
  }).map(function (elem) {
    return elem.track_id;
  });

  var tracksDetailsForIndividual = tracks.filter(function (elem) {
    return tracksWithIndividual.indexOf(elem._id) > -1;
  });

  tracksDetailsForIndividual.forEach(function (track) {
    var trackReleaseIds = track_release.filter(function (relation) {
      return relation.track_id === track._id;
    }).map(function(elem) { return elem.release_id; });

    track.releases = releases.filter(function (release) {
      return trackReleaseIds.indexOf(release._id) > -1;
    });

  });

  //TODO: add a tracks array that contains just the ids in common with the source individual
  var trackCounts = {};
  var connectedIndividuals = individual_track.filter(function (elem) {
    if (tracksWithIndividual.indexOf(elem.track_id) > -1) {
      if (elem.individual_id != individualId) {
        if (trackCounts[elem.individual_id]) {
          trackCounts[elem.individual_id]++;
          return false;
        }
        trackCounts[elem.individual_id] = 1;
        return true;
      }
    }

    return false;
  }).map(function (elem) {
    return {
      name: getName(elem.individual_id),
      targetId: elem.individual_id,
      trackCount: trackCounts[elem.individual_id]
    };
  });

  var file = individualId + ".json";
  var formattedOutput = JSON.stringify({
    source: sourceLabel,
    trackCount: tracksWithIndividual.length,
    tracks: tracksDetailsForIndividual,
    targets: connectedIndividuals
  }, null, 2);

  fs.writeFile(__dirname + "/../data/" + file, formattedOutput,
    function (err) {
      if (err) {
        throw err;
      }
      logger.emit("log", "Wrote JSON file for individual with ID of " + individualId);
    }
  );
};

generateJson(individualIds[0]);

// individualIds.forEach(function (individualId) {
//   generateJson(individualId);
// });
<commit_msg>whoops, do all the individuals, not just the one for testing<commit_after>#!/usr/bin/env node

/* Writes files for JSON representation of all individuals on tracks with a given individual */

var EventEmitter = require("events").EventEmitter;
var argv = require("minimist")(process.argv.slice(2));
var fs = require("graceful-fs");

var logger = new EventEmitter();

if (! argv.q) {
  logger.on("log", function (msg) {
    console.log(msg);
  });
}

var sourceDataDir = __dirname + "/../node_modules/music-routes-data/data";
var individuals = require(sourceDataDir + "/individuals.json");
var individualIds = individuals.map(function(elem) { return elem._id; });
var individual_track = require(sourceDataDir + "/individual_track.json");
var tracks = require(sourceDataDir + "/tracks.json");
var releases = require(sourceDataDir + "/releases.json");
var track_release = require(sourceDataDir + "/track_release.json");

var getName = function (id) {
  return individuals.filter(function(elem) {
    return elem._id === id;
  })[0].names[0];
};

var generateJson = function (individualId) {
  logger.emit("log", "Generating JSON data for individual with ID of " + individualId + "...");

  var sourceLabel = getName(individualId);

  var tracksWithIndividual = individual_track.filter(function (elem) {
    return elem.individual_id === individualId;
  }).map(function (elem) {
    return elem.track_id;
  });

  var tracksDetailsForIndividual = tracks.filter(function (elem) {
    return tracksWithIndividual.indexOf(elem._id) > -1;
  });

  tracksDetailsForIndividual.forEach(function (track) {
    var trackReleaseIds = track_release.filter(function (relation) {
      return relation.track_id === track._id;
    }).map(function(elem) { return elem.release_id; });

    track.releases = releases.filter(function (release) {
      return trackReleaseIds.indexOf(release._id) > -1;
    });

  });

  //TODO: add a tracks array that contains just the ids in common with the source individual
  var trackCounts = {};
  var connectedIndividuals = individual_track.filter(function (elem) {
    if (tracksWithIndividual.indexOf(elem.track_id) > -1) {
      if (elem.individual_id != individualId) {
        if (trackCounts[elem.individual_id]) {
          trackCounts[elem.individual_id]++;
          return false;
        }
        trackCounts[elem.individual_id] = 1;
        return true;
      }
    }

    return false;
  }).map(function (elem) {
    return {
      name: getName(elem.individual_id),
      targetId: elem.individual_id,
      trackCount: trackCounts[elem.individual_id]
    };
  });

  var file = individualId + ".json";
  var formattedOutput = JSON.stringify({
    source: sourceLabel,
    trackCount: tracksWithIndividual.length,
    tracks: tracksDetailsForIndividual,
    targets: connectedIndividuals
  }, null, 2);

  fs.writeFile(__dirname + "/../data/" + file, formattedOutput,
    function (err) {
      if (err) {
        throw err;
      }
      logger.emit("log", "Wrote JSON file for individual with ID of " + individualId);
    }
  );
};

individualIds.forEach(function (individualId) {
  generateJson(individualId);
});
<|endoftext|>


<commit_before>var EE = require('events').EventEmitter;
var crypto = require('crypto');
var url = require('url');
var util = require('util');
var path = require('path');
var fs = require('fs');
var Counter = require('stream-counter');
var mkdirp = require('mkdirp');
var rimraf = require('rimraf');
var follow = require('follow');
var SeqFile = require('seq-file');
var http = require('http-https');
var parse = require('parse-json-response');

var version = require('./package.json').version;
var ua = 'npm-ev-source/' + version + ' node/' + process.version;

var noop = function () {}

module.exports = EventSource;

util.inherits(EventSource, EE);

function EventSource(options) {
  if (!(this instanceof EventSource)) { return new EventSource(options) }

  //
  // URLs and such
  //
  this.skim = options.skim || 'https://skimdb.npmjs.com/registry';

  if (!options.eventSource) { throw new Error('Need eventSource DB to populate') }
  //
  // Setup both public and private urls (public needed for attachment creation)
  //
  var es = url.parse(options.eventSource);
  this.eventSource = es.href.replace(/\/+$/, '');
  delete es.auth;
  this.pubEventSource = url.format(es).replace(/\/+$/, '');

  this.seqFile = new SeqFile(options.seqFile || 'sequence.seq');
  this.missingLog = options.missingLog || false;

  //
  // Follow Opts
  //
  this.inactivity_ms = options.inactivity_ms || 60 * 60 * 1000;
  this.since = 0;
  this.follow = undefined;

  //
  // optional things
  //
  this.ua = options.ua || ua;
  this.tmp = options.tmp;
  this.registry = options.registry || undefined;

  //
  // Prefix for _ keys that are currently in the nested level documents.
  // This is bad practice with couchdb and it rejects them in most cases
  //
  this._prefix = 'npm:';
  //
  // Default boundary for multipart/related requests
  //
  this.boundary = 'npm-ev-source-' + crypto.randomBytes(6).toString('base64');
  //
  // Randomish dir so we donr reuse one potentially when debugging
  //
  if(!this.tmp) {
    var c = crypto.randomBytes(6).toString('hex');
    this.tmp = 'npm-ev-source-tmp-' + process.pid + '-' + c;
  }

  this.seqFile.read(this.onSeq.bind(this));

};

//
// Callback of SeqFile function that reads from the specified file
//
EventSource.prototype.onSeq = function (err, data) {
  //
  // Errors don't matter, we just default to `this.since`
  //
  this.since = +data || this.since;
  this.start();
};

//
// Start following the skimdb database and get the changes!
//
EventSource.prototype.start = function () {
  this.emit('start');

  this.follow = follow({
    db: this.skim,
    since: this.since,
    inactivity_ms: this.inactivity_ms
  }, this.onChange.bind(this));

  this.follow.on('restart', this.emit.bind(this, 'restart'));
};

EventSource.prototype.onChange = function (err, change) {
  if (err) { return this.emit('error', err) }

  if(!change.id) {
    return;
  }

  this.pause();
  this.since = change.seq;

  //
  // We don't REALLY care about design but in the future we
  // do need the rewrites element. Might as well just store this separately
  // though.
  //
  if (/^_design/.test(change.id)) {
    return this.resume();
  }

  return change.deleted
    ? this.delete(change)
    : this.getDoc(change);

};

EventSource.prototype.delete = function (change) {
  //
  // Not implemented yet
  //
  this.resume();
};

EventSource.prototype.getDoc = function (change) {
  var q = '?revs=true&att_encoding_info=true';
  var opts = url.parse(this.skim + '/' + change.id + q);

  opts.method = 'GET';
  opts.agent = false;
  opts.headers = {
    'content-type': 'application/json',
    'connection': 'close'
  };

  var req = http.get(opts);
  //
  // TODO: Implement generic retries for ALL errors, this is especially
  // important when it comes to attachments because we must ENSURE we fetch
  // them
  //
  req.on('error', this.emit.bind(this, 'error'));
  req.on('response', parse(this.onGet.bind(this, change)));

};

EventSource.prototype.onGet = function (change, err, doc, res) {
  if (err) {
    return this.emit('error', err);
  }
  change.doc = doc;
  this.split(change);
};

//
// Iterate through document versions and split it into separate documents to
// insert into the database
//
EventSource.prototype.split = function (change) {
  //
  // TODO: handle diffing which versions we need to fetch instead of assuming
  // all
  //
  var doc = change.doc;
  var versions = Object.keys(doc.versions);
  var tmp = path.resolve(this.tmp, change.id + '-' + change.seq);

  //
  // Setup count for how many iterations to expect
  //
  change.count = versions.length;
  //
  // TODO: Handle stars
  //
  // TODO: check if it exists in database
  // First iteration we are just going to populate this
  // so we have data to write some views with
  //
  mkdirp(tmp, function (err) {
    if (err) {
      return this.emit('error', err);
    }
    versions.forEach(this.fetchAtt.bind(this, change))
  }.bind(this));

};

//
// Fetch the attachment for the specified version that we are iterating through
//
EventSource.prototype.fetchAtt = function (change, v) {
  var doc = change.doc;
  var vDoc = doc.versions[v];
  var reg = url.parse(vDoc.dist.tarball);
  //
  // May need to specify registry depending on the situation which is the
  // direct url to whatever tarball service
  //
  if (this.registry) {
    var p = '/' + change.id + '/-/' + path.basename(reg.pathname)
    reg = url.parse(this.registry + p)
  }

  reg.method = 'GET';
  reg.agent = false;
  reg.headers = {
    'user-agent': this.ua,
    'connection': 'close'
  };

  var req = http.request(reg);
  req.on('error', this.emit.bind(this, 'error'));
  req.on('response', this.onAttRes.bind(this, change, v));
  req.end();

};

//
// Check the files and make sure they match what the document says while
// streaming them to the file system
//
EventSource.prototype.onAttRes = function (change, v, res) {
  var doc = change.doc;
  var vDoc = doc.versions[v];
  var att = vDoc.dist.tarball;
  var sum = vDoc.dist.shasum;
  var filename = change.id + '-' + v + '.tgz';
  var file = path.join(this.tmp, change.id + '-' + change.seq, filename);

  if (res.statusCode != 200) {
    //
    // TODO: Retry
    //
    return this.missingLog
      ? fs.appendFile(this.missingLog, att + '\n', this.isFinished.bind(this, change))
      : this.emit('error', new Error('Unable to properly fetch attachment ' + filename));
  }

  //
  // Make them streams for some crazy pipe action
  //
  var fileStream = fs.createWriteStream(file);
  var sha = crypto.createHash('sha1');
  var shaOk = false;
  var errState = null;

  sha.on('data', function (data) {
    data = data.toString('hex');
    if (data === sum) {
      shaOk = true;
    }
  });
  if (!res.headers['content-length']) {
    var counter = new Counter();
    res.pipe(counter);
  }

  res.pipe(sha);
  res.pipe(fileStream);

  //
  // Add some extra info to the error obj if this happens and emit
  // TODO: This shouldn't really happen but we should refetch if this is the
  // case
  //
  fileStream.on('error', function (err) {
    err.change = change;
    err.version = v;
    err.path = file;
    err.url = att;
    errState = err;
    this.emit('error', err);
  }.bind(this));

  //
  // See if we to stop here because the stream errored
  //
  fileStream.on('close', function () {
    if (errState || !shaOk) {
      //
      // Hmm so this will definitely be hit maybe do the refetch here
      // for both cases if the sha is not the same AND if we failed to write to
      // the filesystem
      //
      // just gonna throw an error for now cause shit is fucked
      //
      return this.emit('error', new Error('Sha did not match or we are in a bad state ' + errState));
    }

    //
    // Remark: I guess keep the name of the attachment the same as before?
    // **note** at least we know that we can form this name from the name
    // property and the version property
    //
    var name = path.basename(filename);
    this.emit('download', name);

    //
    // Hmm should these be the same urls as before? I think so
    //
    var newAtt = this.pubEventSource + '/' + change.id +
                  '/' + change.id + '-' + v + '.tgz';

    //
    // Remark: Setup the new document that we are forming with any necessary
    // attributes from the old behemoth doc.
    //
    vDoc.dist.tarball = newAtt
    vDoc.time = doc.time && doc.time[v] || null;
    //
    // Attach the default readme to the version document so we ensure
    // each version has one at least
    //
    vDoc.readmeFilename = vDoc.readmeFilename || doc.readmeFilename;
    vDoc.readme = vDoc.readme || doc.readme;
    //
    // Remark: So these tricksy little underscore based keys can cause problems
    // for couchDB as it uses them internally. In reality we shouldnt use these
    // AT ALL but lets see with what we can get away with prefixing.
    //
    vDoc = Object.keys(vDoc).reduce(function (doc, key) {
      if (key !== '_id' && /^_/.test(key)) {
        var k = this._prefix + key;
        doc[k] = vDoc[key];
        return doc;
      }
      doc[key] = vDoc[key];
      return doc;
    }.bind(this), {});

    //
    // Ensure we get content length to append to the data structure we use to
    // send the actual request.
    //
    var cl = res.headers['content-length']
      ? +res.headers['content-length']
      : counter.bytes;

    //
    // Create the attachment here and form the final doc when we do a PUT
    // as we need the attachment values to do all the crazy boundary shit
    //
    var attachment = {
      length: cl,
      follows: true,
      // We make an assumption here but this should be safe (in theory);
      content_type: res.headers['content-type'] || 'application/octet-stream'
    };
    this.putDoc(change, vDoc, name, attachment);
  }.bind(this));
};

//
// Insert the single document with its one attachment as a single
// multipart/related request so it is much more efficient
//
EventSource.prototype.putDoc = function (change, vDoc, name, att)  {
  var id = encodeURIComponent(vDoc._id);
  var file = path.join(this.tmp, change.id + '-' + change.seq, name);

  //
  // Oh yea add attachment shit to the actual vDoc
  //
  vDoc._attachments = {};
  vDoc._attachments[name] = att;
  //
  // Start setting up request related things;
  //
  var opts = url.parse(this.eventSource + '/' + id);
  opts.method = 'PUT';
  opts.agent = false;
  opts.headers = {
    'user-agent': this.ua,
    'content-type': 'multipart/related;boundary="' + this.boundary + '"',
    'connection': 'close'
  };

  //
  // Make a doc buffer to write to the stream
  //
  var doc = new Buffer(JSON.stringify(vDoc), 'utf8');

  //
  // Ridiculous boundary strings that we need to separate the pieces of our request with.
  //
  var docBoundary = '--' + this.boundary + '\r\n' +
    'content-type: application/json\r\n' +
    'content-length: ' + doc.length + '\r\n\r\n';

  var attBoundary = '\r\n--' + this.boundary + '\r\n' +
    'content-length: ' + att.length + '\r\n' +
    'content-disposition: attachment; filename=' +
    JSON.stringify(name) + '\r\n' +
    'content-type: ' + att.content_type + '\r\n\r\n';

  var finalBoundary = '\r\n--' + this.boundary + '--';

  //
  // Add all the length values so we know what we are dealing with here
  //
  opts.headers['content-length'] = doc.length + att.length
    + docBoundary.length + attBoundary.length + finalBoundary.length;

  //
  // Create that request for the big PUT!
  //
  var req = http.request(opts);
  req.on('error', this.emit.bind(this, 'error'));
  req.on('response', parse(this.onPutRes.bind(this, change, vDoc)));

  //
  // Start the boundary -> data chain. Pipe some shit, then write the last
  // boundary
  //
  req.write(docBoundary, 'ascii');
  req.write(doc);
  req.write(attBoundary, 'ascii');

  //
  // Setup the readStream and finish it off with a pipe!
  //
  var rs = fs.createReadStream(file);
  rs.on('error', this.emit.bind(this, 'error'));

  //
  // Since we technically need to write a last boundary after the stream,
  // we listen for end and do that here
  //
  rs.on('end', function () {
    req.write(finalBoundary, 'ascii');
    req.end();
  }.bind(this));
  //
  // Don't auto end so that we can write the final boundary
  //
  rs.pipe(req, { end: false });

};

//
// Check for errors and such after we attempt our crazy multipart/related PUT
//
EventSource.prototype.onPutRes = function (change, doc, err, data, res) {
  if (err && err.statusCode != 409) {
    return this.emit('error', err);
  }
  //
  // Jut ignore because it means it was inserted and we crashed for whatever
  // reason
  // TODO: Don't let this case exist and use retries and record skip failures
  //
  if (res.statusCode == 409) {
    this.emit('skip', err.message);
  }
  else {
    this.emit('put', doc, data);
  }
  this.isFinished(change)

};

//
// Check if we are finished with our iteration since we are doing `n` PUTs
// based on the number of versions each document has
//
EventSource.prototype.isFinished = function (change) {
  if (--change.count === 0) {
    rimraf(this.tmp + '/' + change.id + '-' + change.seq, noop);
    return this.resume();
  }
};

//
// Follow pause helper, just cause its nice
//
EventSource.prototype.pause = function () {
  this.follow.pause();
};
//
// Since we assume a concurrency of 1, on each resume save the seq that we just
// inserted into the database so we know where to start from if something
// terrible happens
//
EventSource.prototype.resume = function () {
  this.seqFile.save(this.since);
  this.follow.resume();
};
<commit_msg>[fix] properly emit change event for logging<commit_after>var EE = require('events').EventEmitter;
var crypto = require('crypto');
var url = require('url');
var util = require('util');
var path = require('path');
var fs = require('fs');
var Counter = require('stream-counter');
var mkdirp = require('mkdirp');
var rimraf = require('rimraf');
var follow = require('follow');
var SeqFile = require('seq-file');
var http = require('http-https');
var parse = require('parse-json-response');

var version = require('./package.json').version;
var ua = 'npm-ev-source/' + version + ' node/' + process.version;

var noop = function () {}

module.exports = EventSource;

util.inherits(EventSource, EE);

function EventSource(options) {
  if (!(this instanceof EventSource)) { return new EventSource(options) }

  //
  // URLs and such
  //
  this.skim = options.skim || 'https://skimdb.npmjs.com/registry';

  if (!options.eventSource) { throw new Error('Need eventSource DB to populate') }
  //
  // Setup both public and private urls (public needed for attachment creation)
  //
  var es = url.parse(options.eventSource);
  this.eventSource = es.href.replace(/\/+$/, '');
  delete es.auth;
  this.pubEventSource = url.format(es).replace(/\/+$/, '');

  this.seqFile = new SeqFile(options.seqFile || 'sequence.seq');
  this.missingLog = options.missingLog || false;

  //
  // Follow Opts
  //
  this.inactivity_ms = options.inactivity_ms || 60 * 60 * 1000;
  this.since = 0;
  this.follow = undefined;

  //
  // optional things
  //
  this.ua = options.ua || ua;
  this.tmp = options.tmp;
  this.registry = options.registry || undefined;

  //
  // Prefix for _ keys that are currently in the nested level documents.
  // This is bad practice with couchdb and it rejects them in most cases
  //
  this._prefix = 'npm:';
  //
  // Default boundary for multipart/related requests
  //
  this.boundary = 'npm-ev-source-' + crypto.randomBytes(6).toString('base64');
  //
  // Randomish dir so we donr reuse one potentially when debugging
  //
  if(!this.tmp) {
    var c = crypto.randomBytes(6).toString('hex');
    this.tmp = 'npm-ev-source-tmp-' + process.pid + '-' + c;
  }

  this.seqFile.read(this.onSeq.bind(this));

};

//
// Callback of SeqFile function that reads from the specified file
//
EventSource.prototype.onSeq = function (err, data) {
  //
  // Errors don't matter, we just default to `this.since`
  //
  this.since = +data || this.since;
  this.start();
};

//
// Start following the skimdb database and get the changes!
//
EventSource.prototype.start = function () {
  this.emit('start');

  this.follow = follow({
    db: this.skim,
    since: this.since,
    inactivity_ms: this.inactivity_ms
  }, this.onChange.bind(this));

  this.follow.on('restart', this.emit.bind(this, 'restart'));
};

EventSource.prototype.onChange = function (err, change) {
  if (err) { return this.emit('error', err) }

  if(!change.id) {
    return;
  }

  this.pause();
  this.since = change.seq;

  this.emit('change', change);
  //
  // We don't REALLY care about design but in the future we
  // do need the rewrites element. Might as well just store this separately
  // though.
  //
  if (/^_design/.test(change.id)) {
    return this.resume();
  }

  return change.deleted
    ? this.delete(change)
    : this.getDoc(change);

};

EventSource.prototype.delete = function (change) {
  //
  // Not implemented yet
  //
  this.resume();
};

EventSource.prototype.getDoc = function (change) {
  var q = '?revs=true&att_encoding_info=true';
  var opts = url.parse(this.skim + '/' + change.id + q);

  opts.method = 'GET';
  opts.agent = false;
  opts.headers = {
    'content-type': 'application/json',
    'connection': 'close'
  };

  var req = http.get(opts);
  //
  // TODO: Implement generic retries for ALL errors, this is especially
  // important when it comes to attachments because we must ENSURE we fetch
  // them
  //
  req.on('error', this.emit.bind(this, 'error'));
  req.on('response', parse(this.onGet.bind(this, change)));

};

EventSource.prototype.onGet = function (change, err, doc, res) {
  if (err) {
    return this.emit('error', err);
  }
  change.doc = doc;
  this.split(change);
};

//
// Iterate through document versions and split it into separate documents to
// insert into the database
//
EventSource.prototype.split = function (change) {
  //
  // TODO: handle diffing which versions we need to fetch instead of assuming
  // all
  //
  var doc = change.doc;
  var versions = Object.keys(doc.versions);
  var tmp = path.resolve(this.tmp, change.id + '-' + change.seq);

  //
  // Setup count for how many iterations to expect
  //
  change.count = versions.length;
  //
  // TODO: Handle stars
  //
  // TODO: check if it exists in database
  // First iteration we are just going to populate this
  // so we have data to write some views with
  //
  mkdirp(tmp, function (err) {
    if (err) {
      return this.emit('error', err);
    }
    versions.forEach(this.fetchAtt.bind(this, change))
  }.bind(this));

};

//
// Fetch the attachment for the specified version that we are iterating through
//
EventSource.prototype.fetchAtt = function (change, v) {
  var doc = change.doc;
  var vDoc = doc.versions[v];
  var reg = url.parse(vDoc.dist.tarball);
  //
  // May need to specify registry depending on the situation which is the
  // direct url to whatever tarball service
  //
  if (this.registry) {
    var p = '/' + change.id + '/-/' + path.basename(reg.pathname)
    reg = url.parse(this.registry + p)
  }

  reg.method = 'GET';
  reg.agent = false;
  reg.headers = {
    'user-agent': this.ua,
    'connection': 'close'
  };

  var req = http.request(reg);
  req.on('error', this.emit.bind(this, 'error'));
  req.on('response', this.onAttRes.bind(this, change, v));
  req.end();

};

//
// Check the files and make sure they match what the document says while
// streaming them to the file system
//
EventSource.prototype.onAttRes = function (change, v, res) {
  var doc = change.doc;
  var vDoc = doc.versions[v];
  var att = vDoc.dist.tarball;
  var sum = vDoc.dist.shasum;
  var filename = change.id + '-' + v + '.tgz';
  var file = path.join(this.tmp, change.id + '-' + change.seq, filename);

  if (res.statusCode != 200) {
    //
    // TODO: Retry
    //
    return this.missingLog
      ? fs.appendFile(this.missingLog, att + '\n', this.isFinished.bind(this, change))
      : this.emit('error', new Error('Unable to properly fetch attachment ' + filename));
  }

  //
  // Make them streams for some crazy pipe action
  //
  var fileStream = fs.createWriteStream(file);
  var sha = crypto.createHash('sha1');
  var shaOk = false;
  var errState = null;

  sha.on('data', function (data) {
    data = data.toString('hex');
    if (data === sum) {
      shaOk = true;
    }
  });
  if (!res.headers['content-length']) {
    var counter = new Counter();
    res.pipe(counter);
  }

  res.pipe(sha);
  res.pipe(fileStream);

  //
  // Add some extra info to the error obj if this happens and emit
  // TODO: This shouldn't really happen but we should refetch if this is the
  // case
  //
  fileStream.on('error', function (err) {
    err.change = change;
    err.version = v;
    err.path = file;
    err.url = att;
    errState = err;
    this.emit('error', err);
  }.bind(this));

  //
  // See if we to stop here because the stream errored
  //
  fileStream.on('close', function () {
    if (errState || !shaOk) {
      //
      // Hmm so this will definitely be hit maybe do the refetch here
      // for both cases if the sha is not the same AND if we failed to write to
      // the filesystem
      //
      // just gonna throw an error for now cause shit is fucked
      //
      return this.emit('error', new Error('Sha did not match or we are in a bad state ' + errState));
    }

    //
    // Remark: I guess keep the name of the attachment the same as before?
    // **note** at least we know that we can form this name from the name
    // property and the version property
    //
    var name = path.basename(filename);
    this.emit('download', name);

    //
    // Hmm should these be the same urls as before? I think so
    //
    var newAtt = this.pubEventSource + '/' + change.id +
                  '/' + change.id + '-' + v + '.tgz';

    //
    // Remark: Setup the new document that we are forming with any necessary
    // attributes from the old behemoth doc.
    //
    vDoc.dist.tarball = newAtt
    vDoc.time = doc.time && doc.time[v] || null;
    //
    // Attach the default readme to the version document so we ensure
    // each version has one at least
    //
    vDoc.readmeFilename = vDoc.readmeFilename || doc.readmeFilename;
    vDoc.readme = vDoc.readme || doc.readme;
    //
    // Remark: So these tricksy little underscore based keys can cause problems
    // for couchDB as it uses them internally. In reality we shouldnt use these
    // AT ALL but lets see with what we can get away with prefixing.
    //
    vDoc = Object.keys(vDoc).reduce(function (doc, key) {
      if (key !== '_id' && /^_/.test(key)) {
        var k = this._prefix + key;
        doc[k] = vDoc[key];
        return doc;
      }
      doc[key] = vDoc[key];
      return doc;
    }.bind(this), {});

    //
    // Ensure we get content length to append to the data structure we use to
    // send the actual request.
    //
    var cl = res.headers['content-length']
      ? +res.headers['content-length']
      : counter.bytes;

    //
    // Create the attachment here and form the final doc when we do a PUT
    // as we need the attachment values to do all the crazy boundary shit
    //
    var attachment = {
      length: cl,
      follows: true,
      // We make an assumption here but this should be safe (in theory);
      content_type: res.headers['content-type'] || 'application/octet-stream'
    };
    this.putDoc(change, vDoc, name, attachment);
  }.bind(this));
};

//
// Insert the single document with its one attachment as a single
// multipart/related request so it is much more efficient
//
EventSource.prototype.putDoc = function (change, vDoc, name, att)  {
  var id = encodeURIComponent(vDoc._id);
  var file = path.join(this.tmp, change.id + '-' + change.seq, name);

  //
  // Oh yea add attachment shit to the actual vDoc
  //
  vDoc._attachments = {};
  vDoc._attachments[name] = att;
  //
  // Start setting up request related things;
  //
  var opts = url.parse(this.eventSource + '/' + id);
  opts.method = 'PUT';
  opts.agent = false;
  opts.headers = {
    'user-agent': this.ua,
    'content-type': 'multipart/related;boundary="' + this.boundary + '"',
    'connection': 'close'
  };

  //
  // Make a doc buffer to write to the stream
  //
  var doc = new Buffer(JSON.stringify(vDoc), 'utf8');

  //
  // Ridiculous boundary strings that we need to separate the pieces of our request with.
  //
  var docBoundary = '--' + this.boundary + '\r\n' +
    'content-type: application/json\r\n' +
    'content-length: ' + doc.length + '\r\n\r\n';

  var attBoundary = '\r\n--' + this.boundary + '\r\n' +
    'content-length: ' + att.length + '\r\n' +
    'content-disposition: attachment; filename=' +
    JSON.stringify(name) + '\r\n' +
    'content-type: ' + att.content_type + '\r\n\r\n';

  var finalBoundary = '\r\n--' + this.boundary + '--';

  //
  // Add all the length values so we know what we are dealing with here
  //
  opts.headers['content-length'] = doc.length + att.length
    + docBoundary.length + attBoundary.length + finalBoundary.length;

  //
  // Create that request for the big PUT!
  //
  var req = http.request(opts);
  req.on('error', this.emit.bind(this, 'error'));
  req.on('response', parse(this.onPutRes.bind(this, change, vDoc)));

  //
  // Start the boundary -> data chain. Pipe some shit, then write the last
  // boundary
  //
  req.write(docBoundary, 'ascii');
  req.write(doc);
  req.write(attBoundary, 'ascii');

  //
  // Setup the readStream and finish it off with a pipe!
  //
  var rs = fs.createReadStream(file);
  rs.on('error', this.emit.bind(this, 'error'));

  //
  // Since we technically need to write a last boundary after the stream,
  // we listen for end and do that here
  //
  rs.on('end', function () {
    req.write(finalBoundary, 'ascii');
    req.end();
  }.bind(this));
  //
  // Don't auto end so that we can write the final boundary
  //
  rs.pipe(req, { end: false });

};

//
// Check for errors and such after we attempt our crazy multipart/related PUT
//
EventSource.prototype.onPutRes = function (change, doc, err, data, res) {
  if (err && err.statusCode != 409) {
    return this.emit('error', err);
  }
  //
  // Jut ignore because it means it was inserted and we crashed for whatever
  // reason
  // TODO: Don't let this case exist and use retries and record skip failures
  //
  if (res.statusCode == 409) {
    this.emit('skip', err.message);
  }
  else {
    this.emit('put', doc, data);
  }
  this.isFinished(change)

};

//
// Check if we are finished with our iteration since we are doing `n` PUTs
// based on the number of versions each document has
//
EventSource.prototype.isFinished = function (change) {
  if (--change.count === 0) {
    rimraf(this.tmp + '/' + change.id + '-' + change.seq, noop);
    return this.resume();
  }
};

//
// Follow pause helper, just cause its nice
//
EventSource.prototype.pause = function () {
  this.follow.pause();
};
//
// Since we assume a concurrency of 1, on each resume save the seq that we just
// inserted into the database so we know where to start from if something
// terrible happens
//
EventSource.prototype.resume = function () {
  this.seqFile.save(this.since);
  this.follow.resume();
};
<|endoftext|>