text:
#####
##
## Rails5 template
##
## @author @tk_hamaguchi
## @examples Generate with template
##   $ rails new my_app -T --skip-bundle -m https://github.com/tk-hamaguchi/rails_templates/blob/master/rails5_template.rb
##
#

## Bootstrap?
bootstrap = yes?('Do you want to use bootstrap?')

## Create and initialize Git repository.
git :init
git add: '.'
git commit: '-a -m "first commit."'

email = `git config --get user.email`.strip

## Update gem source.
gsub_file 'Gemfile', /^# (gem 'therubyracer'.*)$/, '\1'
gsub_file 'Gemfile', /^# (gem 'bcrypt'.*)$/, '\1'
gsub_file 'Gemfile', /^# (gem 'redis'.*)$/, '\1'

## Add gem files.
gem 'rails-i18n'
gem 'config'
gem 'haml-rails'

gem 'devise'
gem 'devise-i18n'
gem 'email_validator'
gem 'simple_form'
gem 'kaminari'
gem 'figaro'

gem 'paranoia', '>= 2.2.0.pre'
  #github: 'rubysherpas/paranoia', branch: 'rails5'

if bootstrap
  gem 'bootstrap', '~> 4.0.0.alpha3'
  gem 'font-awesome-rails'
  gem 'rails-assets-tether', '>= 1.1.0', source: 'https://rails-assets.org'
end

gem_group :development, :test do
  gem 'pry-byebug'

  gem 'timecop'

  gem 'rspec-rails', '~> 3.5.0'
  gem 'rails-controller-testing', require: false
  gem 'factory_girl_rails'
  gem 'faker'
  gem 'faker-japanese'
  gem 'shoulda-matchers'
  gem 'simplecov'
  gem 'simplecov-rcov'

  gem 'coderay'

  gem 'cucumber-rails', require: false
  gem 'database_cleaner'
  gem 'aruba', require: false
  gem 'poltergeist'
  gem 'letter_opener'
end

gem_group :development do
  gem 'yard', require: false
  gem 'rubocop', require: false
  gem 'rubocop-checkstyle_formatter', require: false
  gem 'brakeman', require: false
  gem 'bullet'
end

## Execute bundle install
run 'bundle install'

## Configure rails.
gsub_file 'config/application.rb',
  /^# require "rails\/test_unit\/railtie"\n$/,
  ''
gsub_file 'config/application.rb', /"/, "'"

gsub_file 'config/environments/production.rb',
  /"(RAILS_LOG_TO_STDOUT)"/,
  '\'\1\''
gsub_file 'config/environments/production.rb',
  /config.log_tags = \[ :request_id \]/,
  'config.log_tags = [:request_id]'

file 'config/initializers/time_zone.rb', <<-CODE
Rails.application.config.time_zone = 'Tokyo'
CODE

file 'config/initializers/i18n.rb', <<-CODE
Rails.application.config.i18n.default_locale = :ja
CODE

file "config/locales/#{app_name}.en.yml", <<-CODE
en:
  app_name: #{app_name.camelize}
  sign_in: Sign in
  sign_up: Sign up
  sign_out: Sign out
  edit_user_registration: Edit Profile
  copyright_html: "Copyright © %{year} #{app_name.camelize} Project, All Rights Reserved."
CODE

file "config/locales/#{app_name}.ja.yml", <<-CODE
ja:
  app_name: #{app_name.camelize}
  sign_in: 'ログイン'
  sign_up: '新規登録'
  sign_out: 'ログアウト'
  edit_user_registration: 'ユーザ設定'
  copyright_html: "Copyright © %{year} #{app_name.camelize} Project, All Rights Reserved."

  activerecord:
    attributes:
      user:
        current_password: '現在のパスワード'
        username: 'ユーザ名'
        email: 'メールアドレス'
        password: 'パスワード'
        password_confirmation: '確認用パスワード'
        remember_me: 'ログインを記憶'
        reset_password_token:
        unlock_token:
    models:
      user: 'ユーザ'
CODE

## Configure git.
append_file '.gitignore', <<-CODE

*.swp
core
.ruby-gemset.*
.ruby-version.*
.DS_Store
config/database.yml
config/cable.yml
coverage
CODE

run 'figaro install'

## Convert to haml
run <<-CODE
rails haml:erb2haml << EOS
y
EOS
CODE

## Configure rails config
generate 'config:install'

gsub_file 'config/database.yml',
  /^production:.*/m,
  "production:\n  url: <%= ENV['DATABASE_URL'] %>\n"

## Configure bootstrap-sass
if bootstrap
  insert_into_file 'app/assets/stylesheets/application.css', " *= require bootstrap_custom\n", before: " *= require_tree .\n"

  file 'app/assets/stylesheets/bootstrap_custom.scss', <<-CODE
//$brand-primary: #428bca;
//$navbar-default-color: #777;
//$navbar-default-bg: #f8f8f8;
//$navbar-default-toggle-hover-bg: #ddd;
//$navbar-default-toggle-icon-bar-bg: #888;
//$navbar-default-toggle-border-color: #ddd;
//$navbar-default-link-color: #777;
//$navbar-default-link-hover-color: #333;
//$navbar-default-link-hover-bg: transparent;
//$navbar-default-link-disabled-color: #ccc;
//$navbar-default-link-disabled-bg: transparent;
//$navbar-default-link-active-color: #555;
@import "bootstrap";
  CODE

  ## Configure font-awesome-sass
  insert_into_file 'app/assets/stylesheets/application.css', " *= require font-awesome\n", before: " *= require_tree .\n"

  run 'rm -f app/views/layouts/application.html.haml'
  file 'app/views/layouts/application.html.haml', <<-CODE
!!!
%html{lang:'ja'}
  %head
    %meta{charset:'utf-8'}
    %meta{name:'viewport', content:'width=device-width, initial-scale=1, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no, shrink-to-fit=no'}
    %meta{'http-equiv' => 'x-ua-compatible', 'content' => 'ie=edge'}
    %title
      = t 'app_name'
    = csrf_meta_tags
    = action_cable_meta_tag
    = stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track' => 'reload'
    = yield :stylesheet_links
  %body
    - unless defined?(header) && header == false
      #header
        = render partial: '/layouts/navbar'
    = content_for?(:content) ? yield(:content) : yield
    = javascript_include_tag 'application', 'data-turbolinks-track' => 'reload'
    = yield :javascript_links
  CODE

  file 'app/views/layouts/_navbar.html.haml', <<-CODE
%nav.navbar.navbar-full.navbar-dark.bg-inverse
  = link_to t('app_name'), root_path, class:'navbar-brand'
  %ul.nav.navbar-nav.pull-xs-right
    %li.nav-item
      .dropdown.pull-xs-right
        - if user_signed_in?
          %a.nav-link.dropdown-toggle#dropdownMenu2{'data-toggle' => 'dropdown', 'aria-haspopup' => true, 'aria-expanded' => false}
            %i.fa.fa-user
            = current_user.username
          .dropdown-menu.dropdown-menu-right{'aria-labelledby' => 'dropdownMenu2'}
            = link_to edit_user_registration_path, {class:'dropdown-item'} do
              %i.fa.fa-edit
              = t('edit_user_registration')
            .dropdown-divider
            = link_to destroy_user_session_path, {class:'dropdown-item', method: :delete} do
              %i.fa.fa-power-off
              = t('sign_out')
        - else
          - unless controller.is_a?(Devise::SessionsController)
            = link_to new_user_session_path, {class:'btn btn-secondary', type:'button'} do
              %i.fa.fa-sign-in
              = t('sign_in')
  CODE

  file 'app/views/layouts/grid_system.html.haml', <<-CODE
- content_for :javascript_links do
  = javascript_include_tag 'grid_system_layout', 'data-turbolinks-track' => 'reload'

= content_for :content do
  .container-fluid
    .row
      .col-sm-12
        #main_contents
          = content_for?(:content) ? yield(:content) : yield
    .row
      .col-sm-12
        = render partial: '/layouts/footer'
  .clearfix
= render template: 'layouts/application'
  CODE

  file 'app/assets/javascripts/grid_system_layout.coffee', <<-'CODE'
jQuery(document).on 'ready page:load', ->

  $(window).on 'resize', ->
    content_height = $(window).height() - 30 - $('#header').height() - $('#footer').height()
    $('#main_contents').css('min-height', content_height + 'px')

  content_height = $(window).height() - 30 - $('#header').height() - $('#footer').height()
  $('#main_contents').css('min-height', content_height + 'px')
  CODE

  file 'app/views/layouts/home.html.haml', <<-CODE
= render template: 'layouts/grid_system'
  CODE

  file 'app/views/layouts/my.html.haml', <<-CODE
= render template: 'layouts/grid_system'
  CODE

  file 'app/views/layouts/center_middle.html.haml', <<-CODE
= content_for :content do
  .center-middle-layout
    .center-middle-layout-wrapper
      .container
        = content_for?(:content) ? yield(:content) : yield
      .center-middle-layout-footer
        = render partial: '/layouts/footer'
= render template: 'layouts/application', locals:{ header: header }
  CODE

  append_file 'config/initializers/assets.rb', <<-CODE
Rails.application.config.assets.precompile += %w(center_middle_layout.css grid_system_layout.coffee)
  CODE
else
  append_file 'config/initializers/assets.rb', <<-CODE
Rails.application.config.assets.precompile += %w(center_middle_layout.css)
  CODE
end

file 'app/views/layouts/devise.html.haml', <<-CODE
- content_for :stylesheet_links do
  = stylesheet_link_tag 'center_middle_layout', media: 'all', 'data-turbolinks-track' => 'reload'

= render template: 'layouts/center_middle', locals:{ header: true }
CODE

file 'app/views/layouts/users/registrations.html.haml', <<-CODE
= render template: 'layouts/grid_system'
CODE

file 'app/assets/stylesheets/center_middle_layout.scss', <<-CODE
.center-middle-layout {
  height: 100%;
  display: table;
  min-height: 100%;
  width: 100%;
  .center-middle-layout-wrapper {
    vertical-align: middle;
    display: table-cell;
    .container {
      margin-right: auto;
      margin-left: auto;
      padding-left: 15px;
      padding-right: 15px;
    }
  }
  .center-middle-layout-footer {
    position: fixed;
    bottom: 0px;
    width: 100%;
    padding: 0px 1rem;
    #footer {
      width: 100%;
    }
  }
}

#header {
  position: fixed;
  top: 0px;
  width: 100%;
}
CODE

file 'app/assets/stylesheets/base.css.scss', <<-CODE
html,body {
  height: 100%;
}

body {
  min-width: 320px;
}

#footer {
  width: 100%;
  margin: 0.4rem;
  text-align: center;
  font: {
    size: 0.6rem;
  }
  color: gray
}

.copylight {
  margin: 0px;
}

.version_no {
  float: right;
  margin: 0px;
}
CODE

insert_into_file 'app/assets/stylesheets/application.css',
  " *= require base\n",
  before: " *= require_tree .\n"
insert_into_file 'app/assets/javascripts/application.js',
  "//= require tether\n//= require bootstrap-sprockets\n",
  before: "//= require_tree .\n"

file "lib/#{app_name}.rb", <<-CODE
require '#{app_name}/version'
CODE

file "lib/#{app_name}/version.rb", <<-CODE
# {app_name.camelize}
module #{app_name.camelize}
  # VERSION
  VERSION = '0.1.0'.freeze
end
CODE

file "config/initializers/#{app_name}.rb", <<-CODE
require '#{app_name}'
CODE

file 'app/views/layouts/_footer.html.haml', <<-CODE
#footer
  .version_no
    Ver.
    = #{app_name.camelize}::VERSION
  %address.copylight
    = t 'copyright_html', year: Time.now.year
CODE

gsub_file 'app/assets/stylesheets/application.css',
  /^ \*= require_tree \.$/,
  ' *  require_tree .'
gsub_file 'app/assets/javascripts/application.js',
  /^\/\/= require_tree \.$/,
  '// require_tree .'

## Update test frameworks to rspec and cucumber with FactoryGirl.
generate 'rspec:install'
gsub_file 'spec/rails_helper.rb',
  /^\#\ (Dir\[Rails\.root\.join\('spec\/support\/\*\*\/\*\.rb'\)\]\.each\ \{\ \|f\|\ require\ f\ \})$/,
  '\1'
file 'spec/support/shoulda_matchers.rb', <<-CODE
Shoulda::Matchers.configure do |config|
  config.integrate do |with|
    with.test_framework :rspec
    with.library :rails
  end
end
CODE
file 'spec/support/devise.rb', <<-CODE
RSpec.configure do |config|
  config.include Devise::Test::ControllerHelpers, type: :controller
  config.include Devise::Test::ControllerHelpers, type: :helper
  config.include Devise::Test::ControllerHelpers, type: :view
end
CODE
file 'spec/support/rails-controller-testing.rb', <<-CODE
RSpec.configure do |config|
  require 'rails-controller-testing'
  [:controller, :view, :request].each do |type|
    config.include ::Rails::Controller::Testing::TestProcess, :type => type
    config.include ::Rails::Controller::Testing::TemplateAssertions, :type => type
    config.include ::Rails::Controller::Testing::Integration, :type => type
  end
end
CODE
prepend_file 'spec/rails_helper.rb', <<-CODE
require 'simplecov'
require 'simplecov-rcov'
SimpleCov.start 'rails'
SimpleCov.formatter = SimpleCov::Formatter::RcovFormatter

CODE
file 'spec/channels/application_cable/channel_spec.rb', <<-CODE
require 'rails_helper'

RSpec.describe ApplicationCable::Channel do
end
CODE
file 'spec/channels/application_cable/connection_spec.rb', <<-CODE
require 'rails_helper'

RSpec.describe ApplicationCable::Connection do
end
CODE
file 'spec/jobs/application_job_spec.rb', <<-CODE
require 'rails_helper'

RSpec.describe ApplicationJob do
end
CODE
file 'spec/mailers/application_mailer_spec.rb', <<-CODE
require 'rails_helper'

RSpec.describe ApplicationMailer do
end
CODE

generate 'cucumber:install'

## Configure simple_form

if bootstrap
  generate 'simple_form:install --bootstrap'
  gsub_file 'config/initializers/simple_form_bootstrap.rb',
    /^  config.button_class = '.*'$/,
    "  config.button_class = 'btn btn-primary btn-lg btn-block'"
  gsub_file 'config/initializers/simple_form_bootstrap.rb',
    /has-error/,
    'has-danger'
  gsub_file 'config/initializers/simple_form_bootstrap.rb',
    /^(.+:error, wrap_with: { tag: 'span', class: 'help-block)(' })$/,
    '\1 form-control-feedback\2'
else
  generate 'simple_form:install'
end
#gsub_file 'config/initializers/simple_form.rb',
#  /^(\s*config\.button_class = 'btn)'$/,
#  '\1 btn-default\''
#gsub_file 'config/initializers/simple_form.rb',
#  /^(\s*)#\s*(config\.form_class =) .+$/,
#  '\1\2 "form-horizontal"'
#gsub_file 'config/initializers/simple_form.rb',
#  /^(\s*config\.label_class = 'control-label)'$/,
#  '\1 col-sm-2\''
#gsub_file 'config/initializers/simple_form.rb',
#  /^(\s*)#?\s*(config\.error_notification_class =) .+$/,
#  '\1\2 \'alert alert-danger\''

#  /^  config.wrappers :bootstrap, .*\n(    .+\n){7}    end\n  end\n/,
#  <<-CODE
#  config.wrappers :bootstrap, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
#    b.use :html5
#    b.use :placeholder
#    b.use :label
#    b.wrapper tag: 'div', class: 'controls col-sm-10' do |row|
#      row.wrapper tag: 'div', class: 'row' do |ba|
#        ba.use :input
#        ba.use :error, wrap_with: { tag: 'span', class: 'help-block col-sm-4' }
#        ba.use :hint,  wrap_with: { tag: 'p', class: 'help-block' }
#      end
#    end
#  end
#CODE
#gsub_file 'config/initializers/simple_form.rb',
#  /^(\s*)#?\s*(config\.input_class =) .+$/,
#  '\1\2 \'form-control col-sm-8\''
#append_file "app/assets/stylesheets/base.css.scss", <<-CODE
#input.form-control{
#  width: auto;
#};
#CODE

## Configure kaminari
generate 'kaminari:config'

#=begin
#generate 'kaminari:views', 'bootstrap'
#
#gsub_file 'app/views/kaminari/_paginator.html.erb',
#  /^(\s*<div) .*>$/,
#  '\1>'
#gsub_file 'app/views/kaminari/_paginator.html.erb',
#  /^(\s*<ul)>$/,
#  '\1 class="pagination">'
#=end

## Configure Devise
generate 'devise:install', '-q'
environment "config.action_mailer.default_url_options = { host: 'localhost:3000' }"
environment 'config.action_mailer.delivery_method = :letter_opener',
  env: 'development'
gsub_file 'config/initializers/devise.rb',
  /^  # config.timeout_in = 30.minutes$/,
  '  config.timeout_in = Rails.env.test? ? 10.seconds : 30.minutes'
gsub_file 'config/initializers/devise.rb',
  /^  # config.remember_for = 2.weeks$/,
  '  config.remember_for = Rails.env.test? ? 30.seconds : 2.weeks'
gsub_file 'config/initializers/devise.rb',
  /^( +)# (config.secret_key = '.+')$/,
  '\1\2'
insert_into_file 'app/helpers/application_helper.rb',
  "  def resource_name\n    :user\n  end\n\n  def resource\n    @resource ||= User.new\n  end\n\n  def devise_mapping\n    @devise_mapping ||= Devise.mappings[:user]\n  end\n",
  before: 'end'

file 'app/views/shared/_alerts.html.haml', <<-'CODE'
- if notice
  .alert.alert-info#information_area
    = notice
- if !resource.errors.empty?
  .alert.alert-danger#warning_area{role:'alert'}
    = devise_error_messages!
- elsif alert
  .alert.alert-danger#warning_area{role:'alert'}
    = alert
CODE
generate :devise, 'User', 'username:string', 'deleted_at:datetime:index', 'lock_version:integer'
insert_into_file 'app/models/user.rb',
  "  validates :username,\n            presence: true,\n            length: { in: 2..40 }\n\n" +
    "  validates :email,\n            presence: true,\n            uniqueness: true,\n            email: true\n\n" +
    "  validates :password,\n            presence: true,\n            confirmation: true,\n            length: { minimum: 8, maximum: 120 },\n            on: :create\n\n" +
    "  validates :password,\n            confirmation: true,\n            length: { minimum: 8, maximum: 120 },\n            on: :update,\n            allow_blank: true\n\n" +
    "  acts_as_paranoid\n\n",
  after: "ApplicationRecord\n"
gsub_file 'app/models/user.rb',
  /(:registerable,)/,
  '\1 :timeoutable,'
insert_into_file 'spec/factories/users.rb',
  "    username { Faker::Japanese::Name.name }\n    email { Faker::Internet.email }\n    password 'P@ssw0rd'",
  after: "factory :user do\n"

gsub_file 'spec/models/user_spec.rb',
  /^.*pending.*$/,
  "  it { is_expected.to validate_presence_of(:username) }\n" +
  "  it { is_expected.to validate_length_of(:username).is_at_least(2).is_at_most(40) }\n\n" +
  "  it { is_expected.to validate_presence_of(:email) }\n" +
  "  it { is_expected.to validate_uniqueness_of(:email).case_insensitive }\n\n" +
  "  it { is_expected.to validate_presence_of(:password) }\n" +
  "  it { is_expected.to validate_confirmation_of(:password) }\n" +
  "  it { is_expected.to validate_length_of(:password).is_at_least(8).is_at_most(120) }\n\n"

generate :controller, 'users/registrations'
gsub_file 'app/controllers/users/registrations_controller.rb',
  /ApplicationController/,
  "Devise::RegistrationsController\n  include Users::RegistrationsHelper\n\n" +
    "  before_action :configure_permitted_parameters"
insert_into_file 'app/helpers/users/registrations_helper.rb',
  "  protected\n\n  def configure_permitted_parameters\n" +
    "    devise_parameter_sanitizer.permit(:sign_up) do |user_params|\n" +
    "      user_params.permit(:username, :email, :password, :password_confirmation)\n" +
    "    end\n  end\n",
  after: "Users::RegistrationsHelper\n"
file 'app/views/users/registrations/new.html.haml',
  <<-'CODE'
%h2
  = t('devise.registrations.new.sign_up')

= render 'shared/alerts'

= simple_form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f|
  .form-inputs
    = f.input :username, autofocus: true
    = f.input :email
    = f.input :password, required: true
    = f.input :password_confirmation, required: true
  .form-actions
    = f.button :submit, t('devise.registrations.new.sign_up')
= render 'devise/shared/links'
CODE
file 'app/views/users/registrations/edit.html.haml',
  <<-'CODE'
%h2
  = t('devise.registrations.edit.title', resource: resource.model_name.human)

= render 'shared/alerts'

= simple_form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f|
  .form-inputs
    = f.input :username, autofocus: true
    = f.input :email
    - if devise_mapping.confirmable? && resource.pending_reconfirmation?
      %p
        = t('.currently_waiting_confirmation_for_email', email: resource.unconfirmed_email)
    = f.input :password, autocomplete: 'off', hint: t('devise.registrations.edit.leave_blank_if_you_don_t_want_to_change_it'), required: false
    = f.input :password_confirmation, required: false
    = f.input :current_password, hint: t('devise.registrations.edit.we_need_your_current_password_to_confirm_your_changes'), required: true
  .form-actions
    = f.button :submit, t('devise.registrations.edit.update')

%hr

%h3
  = t('devise.registrations.edit.cancel_my_account')
%p
  = t('devise.registrations.edit.unhappy')
  ?
  = link_to(t('devise.registrations.edit.cancel_my_account'), registration_path(resource_name), data: { confirm: t('devise.registrations.edit.are_you_sure') }, method: :delete)
  \.
= link_to t('devise.shared.links.back'), :back
CODE
insert_into_file 'spec/controllers/users/registrations_controller_spec.rb',
  "  it { is_expected.to be_a_kind_of(Devise::RegistrationsController) }\n\n" +
  "  context 'class' do\n" +
  "    subject { described_class }\n" +
  "    it { is_expected.to be_include(Users::RegistrationsHelper) }\n" +
  "  end",
  before: "\nend"
gsub_file 'spec/helpers/users/registrations_helper_spec.rb',
  /^.*pending.*$/,
  ''

generate :controller, 'users/passwords'
gsub_file 'app/controllers/users/passwords_controller.rb',
  /ApplicationController/,
  "Devise::PasswordsController\n  include Users::PasswordsHelper"
file 'app/views/users/passwords/new.html.haml',
  <<-'CODE'
%h2
  = t('devise.passwords.new.forgot_your_password')

= render 'shared/alerts'

= simple_form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f|
  .form-inputs
    = f.input :email, autofocus: true
  .form-actions
    = f.button :submit, t('devise.passwords.new.send_me_reset_password_instructions')
= render 'devise/shared/links'
CODE
file 'app/views/users/passwords/edit.html.haml',
  <<-'CODE'
%h2
  = t('devise.passwords.edit.change_your_password')

= render 'shared/alerts'

= simple_form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f|
  = f.input :reset_password_token, as: :hidden
  = f.full_error :reset_password_token
  .form-inputs
    = f.input :password, label: t('devise.passwords.edit.new_password'), required: true, autofocus: true
    = f.input :password_confirmation, label: t('devise.passwords.edit.confirm_new_password'), required: true
  .form-actions
    = f.button :submit, t('devise.passwords.edit.change_my_password')
= render 'devise/shared/links'
CODE
insert_into_file 'spec/controllers/users/passwords_controller_spec.rb',
  "  it { is_expected.to be_a_kind_of(Devise::PasswordsController) }\n\n" +
  "  context 'class' do\n" +
  "    subject { described_class }\n" +
  "    it { is_expected.to be_include(Users::PasswordsHelper) }\n" +
  "  end",
  before: "\nend"
gsub_file 'spec/helpers/users/passwords_helper_spec.rb',
  /^.*pending.*$/,
  ''

generate :controller, 'users/sessions'
gsub_file 'app/controllers/users/sessions_controller.rb',
  /ApplicationController/,
  "Devise::SessionsController\n  include Users::SessionsHelper"
file 'app/views/users/sessions/new.html.haml',
  <<-'CODE'
%h2
  = t('devise.sessions.new.sign_in')

= render 'shared/alerts'

= simple_form_for(resource, as: resource_name, url: session_path(resource_name)) do |f|
  .form-inputs
    = f.input :email, required: false, autofocus: true
    = f.input :password, required: false
    = f.input :remember_me, as: :boolean if devise_mapping.rememberable?
  .form-actions
    = f.button :submit, t('devise.sessions.new.sign_in')
= render 'devise/shared/links'
CODE
insert_into_file 'spec/controllers/users/sessions_controller_spec.rb',
  "  it { is_expected.to be_a_kind_of(Devise::SessionsController) }\n\n" +
  "  context 'class' do\n" +
  "    subject { described_class }\n" +
  "    it { is_expected.to be_include(Users::SessionsHelper) }\n" +
  "  end",
  before: "\nend"
gsub_file 'spec/helpers/users/sessions_helper_spec.rb',
  /^.*pending.*$/,
  ''

gsub_file 'config/routes.rb',
  /^( +devise_for :users.*),?$/,
  '\1,' + "\n" +
    "             controllers: {\n" +
    "               sessions: 'users/sessions',\n" +
    "               registrations: 'users/registrations',\n" +
    "               passwords: 'users/passwords'\n" +
    "             }\n"

## Generate Home page
generate :controller, :home, :index
insert_into_file 'app/controllers/home_controller.rb',
  "    redirect_to my_top_path if user_signed_in?\n",
  after: "def index\n"
insert_into_file 'app/views/home/index.html.haml',
  "= render 'shared/alerts'\n\n",
  before: '%p '
route "root to: 'home#index'"
gsub_file 'config/routes.rb', /^ +get 'home\/index'\n$/, ''
gsub_file 'spec/controllers/home_controller_spec.rb',
  / +describe .+ +it .+ +end\n +end\n\n/m,
  "  context '#index' do\n" +
  "    subject { get :index ; response } \n" +
  "    it { is_expected.to be_success }\n" +
  "    it { is_expected.to render_template(:index) }\n\n" +
  "    context 'with logined user' do\n" +
  "      before { sign_in FactoryGirl.create(:user) }\n" +
  "      it { is_expected.to be_redirect }\n" +
  "      it { is_expected.to redirect_to(my_top_path) }\n" +
  "    end\n" +
  "  end\n"
gsub_file 'spec/helpers/home_helper_spec.rb',
  /^.*pending.*$/,
  ''
gsub_file 'spec/views/home/index.html.haml_spec.rb',
  /^.*pending.*$/,
  ''

## Generate My page
generate :controller, :my, :top
insert_into_file 'app/controllers/my_controller.rb', "  before_action :authenticate_user!\n\n", after: "ApplicationController\n"
insert_into_file 'app/views/my/top.html.haml',
  "= render 'shared/alerts'\n\n",
  before: '%p '
gsub_file 'config/routes.rb', /^ +get 'my\/top'$/, '  get \'my(.:format)\' => \'my#top\', as: \'my_top\''
gsub_file 'spec/controllers/my_controller_spec.rb',
  / +describe .+ +it .+ +end\n +end\n/m,
  'it { is_expected.to use_before_action(:authenticate_user!) }'
gsub_file 'spec/helpers/my_helper_spec.rb',
  /^.*pending.*$/,
  ''
gsub_file 'spec/views/my/top.html.haml_spec.rb',
  /^.*pending.*$/,
  ''

file 'spec/features/sign_up_spec.rb',
 <<-'CODE'
require 'rails_helper'

RSpec.feature "User's sign up", type: :feature do
  scenario 'Sign up new account' do
    @users_params = FactoryGirl.attributes_for(:user)

    visit new_user_registration_path
    fill_in      'user[username]', with: @users_params[:username]
    fill_in      'user[email]', with: @users_params[:email]
    fill_in      'user[password]', with: @users_params[:password]
    fill_in      'user[password_confirmation]', with: @users_params[:password]
    click_button I18n.t('devise.registrations.new.sign_up')

    expect(page).to have_text(I18n.t('devise.registrations.signed_up'))
    expect(page).to have_text('My#top')
  end
end
CODE

## Create databases
#rake 'db:create'

prepend_file 'app/controllers/application_controller.rb', <<-CODE
# ApplicationController
#
# @since 0.1.0
# @author #{email}
#
CODE
prepend_file 'app/controllers/home_controller.rb', <<-CODE
# HomeController
#
# @since 0.1.0
# @author #{email}
#
CODE
prepend_file 'app/controllers/my_controller.rb', <<-CODE
# MyController
#
# @since 0.1.0
# @author #{email}
#
CODE
prepend_file 'app/controllers/users/passwords_controller.rb', <<-CODE
# Users::PasswordsController
#
# @since 0.1.0
# @author #{email}
#
CODE
prepend_file 'app/controllers/users/registrations_controller.rb', <<-CODE
# Users::RegistrationsController
#
# @since 0.1.0
# @author #{email}
#
CODE
prepend_file 'app/controllers/users/sessions_controller.rb', <<-CODE
# Users::SessionsController
#
# @since 0.1.0
# @author #{email}
#
CODE
prepend_file 'app/helpers/application_helper.rb', <<-CODE
# ApplicationHelper
#
# @since 0.1.0
# @author #{email}
#
CODE
prepend_file 'app/helpers/home_helper.rb', <<-CODE
# HomeHelper
#
# @since 0.1.0
# @author #{email}
#
CODE
prepend_file 'app/helpers/my_helper.rb', <<-CODE
# MyHelper
#
# @since 0.1.0
# @author #{email}
#
CODE
prepend_file 'app/helpers/users/passwords_helper.rb', <<-CODE
# Users::PasswordsHelper
#
# @since 0.1.0
# @author #{email}
#
CODE
prepend_file 'app/helpers/users/registrations_helper.rb', <<-CODE
# Users::RegistrationsHelper
#
# @since 0.1.0
# @author #{email}
#
CODE
prepend_file 'app/helpers/users/sessions_helper.rb', <<-CODE
# Users::SessionsHelper
#
# @since 0.1.0
# @author #{email}
#
CODE
prepend_file 'app/mailers/application_mailer.rb', <<-CODE
# ApplicationMailer
#
# @since 0.1.0
# @author #{email}
#
CODE
prepend_file 'app/models/application_record.rb', <<-CODE
# ApplicationRecord
#
# @since 0.1.0
# @author #{email}
#
CODE
prepend_file 'app/models/user.rb', <<-CODE
# User
#
# @since 0.1.0
# @author #{email}
#
CODE
prepend_file 'config/application.rb', <<-CODE
# Application
#
# @since 0.1.0
# @author #{email}
#
CODE
gsub_file 'config/application.rb', /  class Application < Rails::Application\n/, <<-CODE
  # TemplateSample::Application
  #
  # @since 0.1.0
  # @author #{email}
  #
  class Application < Rails::Application
CODE
prepend_file 'app/channels/application_cable/channel.rb', <<-CODE
# ApplicationCable
#
# @since 0.1.0
# @author #{email}
#
CODE
gsub_file 'app/channels/application_cable/channel.rb',
  /    class Channel < ActionCable::Channel::Base\n/,
  <<-CODE
  # ApplicationCable::Channel
  #
  # @since 0.1.0
  # @author #{email}
  #
  class Channel < ActionCable::Channel::Base
CODE
prepend_file 'app/channels/application_cable/connection.rb', <<-CODE
# ApplicationCable
#
# @since 0.1.0
# @author #{email}
#
CODE
gsub_file 'app/channels/application_cable/connection.rb',
  /  class Connection < ActionCable::Connection::Base\n/,
  <<-CODE
  # ApplicationCable::Connection
  #
  # @since 0.1.0
  # @author #{email}
  #
  class Connection < ActionCable::Connection::Base
CODE
prepend_file 'app/jobs/application_job.rb', <<-CODE
# ApplicationJob
#
# @since 0.1.0
# @author #{email}
#
CODE

file '.rubocop.yml', <<-CODE
AllCops:
  Exclude:
    - 'Gemfile'
    - 'Rakefile'
    - 'db/schema.rb'
    - 'vendor/**/*'
    # for Devise
    - 'config/initializers/devise.rb'
    - 'db/migrate/*_devise_create_users.rb'
    # for SimpleForm
    - 'config/initializers/simple_form.rb'
    # for Puma
    - 'config/puma.rb'
    # for Cucumber
    - 'script/cucumber'
    - 'features/**/*'
    - 'lib/tasks/cucumber.rake'
    # for RSpec
    - 'spec/**/*'

Metrics/LineLength:
  Max: 120

Style/ClassAndModuleChildren:
  Enabled: false
CODE

file 'features/support/database_cleaner.rb', <<-CODE
begin
  require 'database_cleaner'
  require 'database_cleaner/cucumber'

  DatabaseCleaner.strategy = :truncation
rescue NameError
  raise "You need to add database_cleaner to your Gemfile (in the :test group) if you wish to use it."
end

Around do |scenario, block|
  DatabaseCleaner.cleaning(&block)
end
CODE
file 'features/support/names.rb', <<-'CODE'
def page_name_to_path(page_name, options = {})
  case page_name
  when 'トップページ'
    root_path
  when 'ログインページ'
    new_user_session_path
  when 'アカウント登録ページ'
    new_user_registration_path
  when 'パスワード再設定メール送信ページ'
    new_user_password_path
  when 'パスワード再設定ページ'
    edit_user_password_path
  when 'マイトップページ'
    my_top_path
  else
    raise "Unknown page name '#{page_name}'."
  end
end

def form_name_to_id(form_name)
  case form_name
  when 'アカウント登録フォーム'
    '#new_user'
  when 'ログインフォーム'
    '#new_user'
  when 'パスワード再設定フォーム'
    '#new_user'
  when 'パスワード再設定メール送信フォーム'
    '#new_user'
  else
    raise "Unknown form name '#{form_name}'."
  end
end

def area_name_to_id(area_name)
  case area_name
  when 'インフォメーションエリア'
    '#information_area'
  when 'ワーニングエリア'
    '#warning_area'
  else
    raise "Unknown area name '#{area_name}'."
  end
end

def menu_name_to_id(menu_name)
  case menu_name
  when 'ドロップダウンメニュー'
    '#dropdownMenu2'
  else
    raise "Unknown menu name '#{menu_name}'."
  end
end

def field_name_to_name(field_name)
  case field_name
  when 'メールアドレスフィールド'
    'user[email]'
  when 'ユーザ名フィールド'
    'user[username]'
  when 'パスワードフィールド'
    'user[password]'
  when '確認用パスワードフィールド'
    'user[password_confirmation]'
  when 'ログインを記憶フィールド'
    'user[remember_me]'
  else
    raise "Unknown field name '#{field_name}'."
  end
end
CODE
file 'features/support/driver.rb', <<-CODE
require 'capybara/poltergeist'
Capybara.default_driver = :poltergeist
CODE
file 'features/step_definitions/web_steps.rb', <<-'CODE'
When(/^"(.*)"を表示する$/)do |page_name|
  visit page_name_to_path(page_name)
end

Then(/スクリーンショットを撮って\"(.+)\"に保存/)do |filename|
  page.save_screenshot "./#{filename}"
end

When(/^"([^"]*)"に下記を入力する:$/) do |form_name, table|
  within(form_name_to_id(form_name)) do
    table.hashes.each do |set|
      field_name = set['field']  =~ /\]$/ ? set['field'] : field_name_to_name(set['field'] + 'フィールド')
      i = 0
      begin
        find(field_name)
      rescue => e
        raise e if i > 3
        i += 1
      end
      fill_in field_name, with: set['value']
    end
  end
end

Given(/^下記のユーザーが登録されている:$/) do |table|
  table.hashes.each do |user_params|
    User.create!(user_params)
  end
end

Then(/^"([^"]*)"が表示されている$/) do |page_name|
  uri = URI.parse(current_url)
  expect(uri.path).to eq page_name_to_path(page_name)
end

When(/^"([^"]*)"の"([^"]*)"をチェック(する|しない)$/) do |form_name, field_name, check|
  within(form_name_to_id(form_name)) do
    f_name = field_name =~ /\]$/ ? field_name : field_name_to_name(field_name + 'フィールド')
    if check == 'する'
      check(f_name)
    else
      uncheck(f_name)
    end
  end
end

When(/^"([^"]+)"をクリックする$/) do |label|
  if label =~ /メニュー$/
    target = menu_name_to_id(label)
    find(target).click
  else
    click_on label
  end
end

Then(/^"([^"]*)"に下記が表示されている:$/) do |area_name, string|
  within(area_name_to_id(area_name)) do
    expect(page).to have_content string
  end
end

Given(/^下記の認証情報でログインする$/) do |table|
  user_param = table.hashes.first
  step '"トップページ"を表示する'
  step '"ログイン"をクリックする'
  step '"ログインフォーム"に下記を入力する:', table(%{
    | field             | value                     |
    | user[email]       | #{user_param['email']}    |
    | user[password]    | #{user_param['password']} |
  })
  step '"ログインフォーム"の"user[remember_me]"をチェックしない'
  step '"ログイン"をクリックする'
  step '"マイトップページ"が表示されている'
end

Given(/^ログアウトする$/) do
  step '"ドロップダウンメニュー"をクリックする'
  step '"ログアウト"をクリックする'
  step '"トップページ"が表示されている'
end

Given(/^ログインの記憶時間が"(\d+)秒"となっている$/) do |sec|
  expect(Devise.remember_for).to eq ActiveSupport::Duration.new(sec.to_i, [[:seconds, sec.to_i]])
end

Given(/^セッションのタイムアウト時間が"(\d+)秒"となっている$/) do |sec|
  expect(Devise.timeout_in).to eq ActiveSupport::Duration.new(sec.to_i, [[:seconds, sec.to_i]])
end

Given(/^ログイン失敗時のロック回数が"(\d+)回"となっている$/) do |num|
  expect(Devise.maximum_attempts).to eq num.to_i
end

When(/^"(\d+)秒"待つ$/) do |sec|
  sleep(sec.to_i)
end

Then(/^下記のメールを受信している:$/) do |table|
  @last_mail ||= ActionMailer::Base.deliveries.last
  table.hashes.each do |mail_params|
    val = @last_mail.send(mail_params['field'].to_sym)
    if val.is_a?(Array)
      expect(val).to include mail_params['value']
    else
      expect(val).to eq mail_params['value']
    end
  end
end

Then(/^メール本文が下記の正規表現にマッチする:$/) do |string|
  @last_mail ||= ActionMailer::Base.deliveries.last
  expect(@last_mail.body.to_s).to match(/^#{string}/)
end

When(/^メールキューを空にする$/) do
  ActionMailer::Base.deliveries.clear
end

When(/^メールに含まれているパスワード再設定用URLを開く$/) do
  @last_mail ||= ActionMailer::Base.deliveries.last
  path = @last_mail.body.to_s.match(/"http.+(\/users\/password\/edit\?reset_password_token.+)"/)[1]
  visit path
end

Then(/^メールキューは空になっている$/) do
  expect(ActionMailer::Base.deliveries.empty?).to be_truthy
end

Then(/^"([^"]*)"の"([^"]*)"がハイライトされ、下記のエラーが表示されている:$/) do |form_name, field_name, message|
  within(form_name_to_id(form_name)) do
    field_elm = find_field(field_name_to_name(field_name)).find(:xpath, './..')
    expect(field_elm[:class].split(/\s+/)).to include 'has-danger'
    expect(field_elm).to have_content message
  end
end
CODE

file 'features/login.feature', <<-CODE
# language:ja

機能: ログイン/ログアウト

背景:
  前提 下記のユーザーが登録されている:
    | username  | email                | password |
    | Test User | testuser@example.com | testpass |

シナリオ: 管理者はトップページから正しい認証情報を使ってログインすることができる
  もし "トップページ"を表示する
  かつ"ログイン"をクリックする
  ならば "ログインページ"が表示されている
  もし "ログインフォーム"に下記を入力する:
    | field          | value                |
    | メールアドレス | testuser@example.com |
    | パスワード     | testpass             |
  かつ "ログインフォーム"の"ログインを記憶"をチェックしない
  かつ "ログイン"をクリックする
  ならば "マイトップページ"が表示されている
  かつ "インフォメーションエリア"に下記が表示されている:
    """
    ログインしました。
    """

シナリオ: 未登録者はトップページから未登録の認証情報を使ってログインすることができない
  もし "トップページ"を表示する
  かつ"ログイン"をクリックする
  ならば "ログインページ"が表示されている
  もし "ログインフォーム"に下記を入力する:
    | field          | value                   |
    | メールアドレス | unknownuser@example.com |
    | パスワード     | testpass                |
  かつ "ログインフォーム"の"ログインを記憶"をチェックしない
  かつ "ログイン"をクリックする
  ならば "ログインページ"が表示されている
  かつ "ワーニングエリア"に下記が表示されている:
    """
    メールアドレスまたはパスワードが違います。
    """

シナリオ: 管理者はトップページから誤った認証情報を使ってログインすることができない
  もし "トップページ"を表示する
  かつ"ログイン"をクリックする
  ならば "ログインページ"が表示されている
  もし "ログインフォーム"に下記を入力する:
    | field          | value                |
    | メールアドレス | testuser@example.com |
    | パスワード     | unknown              |
  かつ "ログインフォーム"の"ログインを記憶"をチェックしない
  かつ "ログイン"をクリックする
  ならば "ログインページ"が表示されている
  かつ "ワーニングエリア"に下記が表示されている:
    """
    メールアドレスまたはパスワードが違います。
    """

#ならば スクリーンショットを撮って"screen_shot.png"に保存

シナリオ: 管理者はログイン後にログアウトすることができる
  前提 下記の認証情報でログインする
    | username  | email                | password |
    | Test User | testuser@example.com | testpass |
  もし "ドロップダウンメニュー"をクリックする
  かつ "ログアウト"をクリックする
  ならば "トップページ"が表示されている
  かつ "インフォメーションエリア"に下記が表示されている:
    """
    ログアウトしました。
    """
CODE
file 'features/remember_login_info.feature', <<-CODE
# language:ja

機能: ログイン情報を記憶する

背景:
  前提 下記のユーザーが登録されている:
    | username  | email                | password |
    | Test User | testuser@example.com | testpass |
  かつ セッションのタイムアウト時間が"10秒"となっている
  かつ ログインの記憶時間が"30秒"となっている

シナリオ: 管理者はトップページから正しい認証情報を使ってログイン情報を保存してログインすることができる
  もし "トップページ"を表示する
  かつ"ログイン"をクリックする
  ならば "ログインページ"が表示されている
  もし "ログインフォーム"に下記を入力する:
    | field          | value                |
    | メールアドレス | testuser@example.com |
    | パスワード     | testpass             |
  かつ "ログインフォーム"の"ログインを記憶"をチェックする
  かつ "ログイン"をクリックする
  ならば "マイトップページ"が表示されている
  もし ログアウトする
  かつ "トップページ"を表示する
  #ならば スクリーンショットを撮って"screen_shot.png"に保存
CODE
file 'features/password_reminder.feature', <<-CODE
# language:ja

機能: パスワード再発行

背景:
  前提 下記のユーザーが登録されている:
    | username  | email                | password |
    | TEST USER | testuser@example.com | testpass |

シナリオ: 管理者はパスワード再設定メールからパスワードを再設定することができる
  前提 メールキューを空にする
  もし "トップページ"を表示する
  かつ "ログイン"をクリックする
  ならば "ログインページ"が表示されている
  もし "パスワードを忘れましたか?"をクリックする
  ならば "パスワード再設定メール送信ページ"が表示されている
  もし "パスワード再設定メール送信フォーム"に下記を入力する:
    | field          | value                |
    | メールアドレス | testuser@example.com |
  かつ "パスワードの再設定方法を送信する"をクリックする
  ならば "ログインページ"が表示されている
  かつ "インフォメーションエリア"に下記が表示されている:
    """
    パスワードの再設定について数分以内にメールでご連絡いたします。
    """
  もし メールに含まれているパスワード再設定用URLを開く
  ならば "パスワード再設定ページ"が表示されている
  もし "パスワード再設定メール送信フォーム"に下記を入力する:
    | field            | value       |
    | パスワード       | newpassword |
    | 確認用パスワード | newpassword |
  かつ "パスワードを変更する"をクリックする
  ならば "マイトップページ"が表示されている
  もし ログアウトする
  ならば "トップページ"が表示されている
  かつ "ログイン"をクリックする
  ならば "ログインページ"が表示されている
  もし "ログインフォーム"に下記を入力する:
    | field          | value                |
    | メールアドレス | testuser@example.com |
    | パスワード     | newpassword          |
  かつ "ログインフォーム"の"user[remember_me]"をチェックする
  かつ "ログイン"をクリックする
  ならば "マイトップページ"が表示されている

シナリオ: 管理者がパスワード再設定メール送信フォームに誤ったメールアドレス投入した場合
  前提 メールキューを空にする
  もし "トップページ"を表示する
  かつ "ログイン"をクリックする
  ならば "ログインページ"が表示されている
  もし "パスワードを忘れましたか?"をクリックする
  ならば "パスワード再設定メール送信ページ"が表示されている
  もし "パスワード再設定メール送信フォーム"に下記を入力する:
    | field          | value                |
    | メールアドレス | unknown@example.com |
  かつ "パスワードの再設定方法を送信する"をクリックする
  ならば "ワーニングエリア"に下記が表示されている:
    """
    1 件のエラーが発生したため ユーザ は保存されませんでした: メールアドレスは見つかりませんでした。
    """
  かつ メールキューは空になっている
  かつ "パスワード再設定メール送信フォーム"の"メールアドレスフィールド"がハイライトされ、下記のエラーが表示されている:
    """
    は見つかりませんでした。
    """

シナリオ: 管理者がパスワード再設定メール送信フォームにメールアドレス投入せずに送信した場合エラーになる
  前提 メールキューを空にする
  もし "トップページ"を表示する
  かつ "ログイン"をクリックする
  ならば "ログインページ"が表示されている
  もし "パスワードを忘れましたか?"をクリックする
  ならば "パスワード再設定メール送信ページ"が表示されている
  もし "パスワードの再設定方法を送信する"をクリックする
  ならば "ワーニングエリア"に下記が表示されている:
    """
    1 件のエラーが発生したため ユーザ は保存されませんでした: メールアドレスを入力してください
    """
  かつ メールキューは空になっている
  かつ "パスワード再設定メール送信フォーム"の"メールアドレスフィールド"がハイライトされ、下記のエラーが表示されている:
    """
    を入力してください
    """

シナリオ: 管理者はパスワード再設定メールからパスワードを再設定するときに確認入力を誤った場合、エラーが表示される
  前提 メールキューを空にする
  もし "トップページ"を表示する
  かつ "ログイン"をクリックする
  ならば "ログインページ"が表示されている
  もし "パスワードを忘れましたか?"をクリックする
  ならば "パスワード再設定メール送信ページ"が表示されている
  もし "パスワード再設定メール送信フォーム"に下記を入力する:
    | field          | value                |
    | メールアドレス | testuser@example.com |
  かつ "パスワードの再設定方法を送信する"をクリックする
  ならば "ログインページ"が表示されている
  かつ "インフォメーションエリア"に下記が表示されている:
    """
    パスワードの再設定について数分以内にメールでご連絡いたします。
    """
  もし メールに含まれているパスワード再設定用URLを開く
  ならば "パスワード再設定ページ"が表示されている
  もし "パスワード再設定メール送信フォーム"に下記を入力する:
    | field            | value       |
    | パスワード       | newpassword |
    | 確認用パスワード | hogehoge    |
  かつ "パスワードを変更する"をクリックする
  ならば "ワーニングエリア"に下記が表示されている:
    """
    2 件のエラーが発生したため ユーザ は保存されませんでした: 確認用パスワードとパスワードの入力が一致しません 確認用パスワードとパスワードの入力が一致しません
    """
CODE
file 'features/session_timeout.feature', <<-CODE
# language:ja

機能: セッションのタイムアウト

背景:
  前提 下記のユーザーが登録されている:
    | username  | email                | password |
    | Test User | testuser@example.com | testpass |
  かつ セッションのタイムアウト時間が"10秒"となっている

シナリオ: 管理者はトップページから正しい認証情報を使ってログインし、10秒以上放置すると自動ログアウトしている
  前提 下記の認証情報でログインする
    | email                | password |
    | testuser@example.com | testpass |
  もし "15秒"待つ
  かつ "マイトップページ"を表示する
  ならば "ログインページ"が表示されている
  かつ "ワーニングエリア"に下記が表示されている:
    """
    セッションがタイムアウトしました。もう一度ログインしてください。
    """
CODE
file 'features/sign_up.feature', <<-CODE
# language:ja

機能: ユーザのサインアップ

シナリオ: 登録希望者はアカウント登録をすることができる
  もし "トップページ"を表示する
  かつ "ログイン"をクリックする
  ならば "ログインページ"が表示されている
  もし "アカウント登録"をクリックする
  ならば "アカウント登録ページ"が表示されている
  もし "アカウント登録フォーム"に下記を入力する:
    | field            | value                |
    | ユーザ名         | TEST USER            |
    | メールアドレス   | testuser@example.com |
    | パスワード       | newpassword          |
    | 確認用パスワード | newpassword          |
  かつ "アカウント登録"をクリックする
  ならば "マイトップページ"が表示されている
  かつ "インフォメーションエリア"に下記が表示されている:
    """
    アカウント登録が完了しました。
    """
  もし ログアウトする
  ならば "トップページ"が表示されている
  かつ "ログイン"をクリックする
  ならば "ログインページ"が表示されている
  もし "ログインフォーム"に下記を入力する:
    | field          | value                |
    | メールアドレス | testuser@example.com |
    | パスワード     | newpassword          |
  かつ "ログインフォーム"の"ログインを記憶"をチェックしない
  かつ "ログイン"をクリックする
  ならば "マイトップページ"が表示されている

シナリオ: すでに登録されているメールアドレスではアカウント登録は失敗する
  前提 下記のユーザーが登録されている:
    | username   | email                   | password |
    | Exist User | existeduser@example.com | testpass |
  もし "トップページ"を表示する
  かつ "ログイン"をクリックする
  ならば "ログインページ"が表示されている
  もし "アカウント登録"をクリックする
  ならば "アカウント登録ページ"が表示されている
  もし "アカウント登録フォーム"に下記を入力する:
    | field            | value                   |
    | ユーザ名         | TEST USER               |
    | メールアドレス   | existeduser@example.com |
    | パスワード       | newpassword             |
    | 確認用パスワード | newpassword             |
  かつ "アカウント登録"をクリックする
  ならば "ワーニングエリア"に下記が表示されている:
    """
    エラーが発生したため ユーザ は保存されませんでした: メールアドレスはすでに存在します
    """
  かつ "アカウント登録フォーム"の"メールアドレスフィールド"がハイライトされ、下記のエラーが表示されている:
    """
    はすでに存在します
    """

シナリオ: 各フィールドを入力しなかった場合、アカウント登録は失敗する
  もし "トップページ"を表示する
  かつ "ログイン"をクリックする
  ならば "ログインページ"が表示されている
  もし "アカウント登録"をクリックする
  ならば "アカウント登録ページ"が表示されている
  もし "アカウント登録フォーム"に下記を入力する:
    | field            | value |
    | ユーザ名         |       |
    | メールアドレス   |       |
    | パスワード       |       |
    | 確認用パスワード |       |
  かつ "アカウント登録"をクリックする
  ならば "ワーニングエリア"に下記が表示されている:
    """
    エラーが発生したため ユーザ は保存されませんでした: ユーザ名を入力してください ユーザ名は2文字以上で入力してください メールアドレスを入力してください メールアドレスは不正な値です メールアドレスを入力してください パスワードを入力してください パスワードは8文字以上で入力してください パスワードを入力してください
    """
  かつ "アカウント登録フォーム"の"メールアドレスフィールド"がハイライトされ、下記のエラーが表示されている:
    """
    を入力してください
    """

シナリオ: パスワードの確認入力を誤った場合、エラーが表示される
  もし "トップページ"を表示する
  かつ "ログイン"をクリックする
  ならば "ログインページ"が表示されている
  もし "アカウント登録"をクリックする
  ならば "アカウント登録ページ"が表示されている
  もし "アカウント登録フォーム"に下記を入力する:
    | field            | value                |
    | ユーザ名         | TEST USER            |
    | メールアドレス   | testuser@example.com |
    | パスワード       | newpassword          |
    | 確認用パスワード | hogehoge             |
  かつ "アカウント登録"をクリックする
  ならば "ワーニングエリア"に下記が表示されている:
    """
    2 件のエラーが発生したため ユーザ は保存されませんでした: 確認用パスワードとパスワードの入力が一致しません 確認用パスワードとパスワードの入力が一致しません
    """
CODE

append_file 'Rakefile', <<-'EOS'

default_tasks = []

begin
  require 'rspec/core/rake_task'
  default_tasks << :spec
rescue LoadError
end

begin
  require 'cucumber/rake/task'
  default_tasks << :cucumber
rescue LoadError
end

begin
  require 'yard'
  require 'yard/rake/yardoc_task'
  YARD::Rake::YardocTask.new do |t|
    t.files   = ['app/controllers/**/*.rb','app/helpers/**/*.rb', 'app/mailers/**/*.rb', 'app/models/**/*.rb', 'lib/**/*.rb']
    t.options = []
    t.options << '--debug' << '--verbose' if $trace
  end
  default_tasks << :yard
rescue LoadError
end

begin
  require 'rubocop/rake_task'
  RuboCop::RakeTask.new
  default_tasks << :rubocop
rescue LoadError
end

begin
  require 'brakeman'

  desc "Check your code with Brakeman"
  task :brakeman do
    result = Brakeman.run app_path: '.', print_report: true
    exit Brakeman::Warnings_Found_Exit_Code unless result.filtered_warnings.empty?
  end
  default_tasks << :brakeman
rescue LoadError
end

desc 'Generate docs'
task :docs do
  system 'rm -rf docs'
  system 'rspec spec -fh -o docs/rspec/index.html'
  system 'mv coverage docs'
  system 'mkdir -p docs/cucumber/'
  system 'cucumber features -f html -o docs/cucumber/index.html'
  system 'yardoc -o docs/yard'
  system 'rubocop -fh -o docs/rubocop/index.html'
  system 'mkdir docs/brakeman/'
  system 'brakeman -f html -o docs/brakeman/index.html'
end

task default: default_tasks
EOS

run 'cp config/database.yml{,.example}'
run 'cp config/cable.yml{,.example}'
git rm: '--cached config/database.yml'
git rm: '--cached config/cable.yml'

file 'Dockerfile', <<-"CODE"
FROM ruby

ENV APP_ROOT /myapp
ENV RAILS_ENV production
ENV PORT 3000
ENV DATABASE_URL mysql2://root:mysql123@db/template_sample?reconnect=true
ENV TZ JST-9
ENV RAILS_SERVE_STATIC_FILES true
ENV RAILS_LOG_TO_STDOUT true
ENV RAILS_MAX_THREADS 5
ENV WEB_CONCURRENCY 2

RUN apt-get update -qq && apt-get install -y build-essential mysql-client postgresql-client nodejs --no-install-recommends && rm -rf /var/lib/apt/lists/*
RUN gem update && gem install bundler --no-ri --no-rdoc

RUN mkdir $APP_ROOT

WORKDIR $APP_ROOT
COPY Gemfile* ./

RUN bundle install --deployment --without development test

ADD . $APP_ROOT

RUN bundle exec rake assets:precompile

EXPOSE $PORT

CMD bundle exec rails s -p $PORT -b '0.0.0.0' -e $RAILS_ENV
CODE
file 'docker-compose.yml', <<-"CODE"
version: '2'

services:
  db:
    image: mysql
    expose:
     - '3306'
    environment:
      - MYSQL_ROOT_PASSWORD=mysql123
  redis:
    image: redis
  app:
    build: .
    depends_on:
      - db
      - redis
    environment:
      - DATABASE_URL=mysql2://root:mysql123@db/template_sample?reconnect=true
      - SECRET_KEY_BASE=#{SecureRandom.hex(64)}
      - RAILS_MAX_THREADS=5
      - WEB_CONCURRENCY=2
      - APP_ROOT=/myapp
    tmpfs:
      - /myapp/tmp
  web:
    image: nginx
    depends_on:
      - app
    ports:
      - '80:80'
    volumes:
      - './misc/nginx/default.conf:/etc/nginx/conf.d/default.conf'
CODE
file 'misc/nginx/default.conf', <<-'CODE'
server{
  listen       80;
  server_name _;

  location / {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_redirect off;
    proxy_read_timeout 300;

    proxy_pass http://app:3000;
  }
}
CODE


text:
package gov.tubitak.xoola.java.test;

import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;

@RunWith(Suite.class)
@SuiteClasses({InterruptTest.class,TestXoolaMulti.class, TestXoolaOneToOne.class, TestXoolaLargeMessage.class })
public class AllTests {

}

redpajama_set_name: RedPajamaGithub


text:
import { Back, Controller, Get, Route, Request, Response } from "../index";
const request = require("supertest");
const assert = require("assert");
import "mocha";
import bodyParser = require("body-parser");

describe("@Get", () => {
    describe("@Get simple", () => {
        it("should return the value", done => {
            Back.reset();

            @Controller
            @Route("/product")
            class ProductController {
                constructor() {}

                @Get("/")
                someMethod(req: Request, res: Response) {
                    res.end("I just received data");
                }
            }

            let app = Back.express();

            app.use(bodyParser.json());
            app.use(bodyParser.urlencoded({ extended: false }));

            Back.prepare(app);
            request(app)
                .get("/product/")
                .expect("I just received data", done);
        });
    });

    describe("@Get with /:param", () => {
        it("should return the value", done => {
            Back.reset();

            @Controller
            @Route("/product")
            class ProductController {
                constructor() {}

                @Get("/:id")
                someMethod(req: Request, res: Response, id: number) {
                    assert.equal(id, 45);
                    res.end("I just received data");
                }
            }

            let app = Back.express();

            app.use(bodyParser.json());
            app.use(bodyParser.urlencoded({ extended: false }));

            Back.prepare(app);
            request(app)
                .get("/product/45")
                .expect("I just received data", done);
        });
    });

    describe("@Get with ?param=value&param=value", () => {
        it("should return the value", done => {
            Back.reset();

            @Controller
            @Route("/product")
            class ProductController {
                constructor() {}

                @Get("/")
                someMethod(req: Request, res: Response, name: string, price: string) {
                    assert.equal(name, "bimo");
                    assert.equal(price, 78);
                    res.end("I just received data");
                }
            }

            let app = Back.express();

            app.use(bodyParser.json());
            app.use(bodyParser.urlencoded({ extended: false }));

            Back.prepare(app);
            request(app)
                .get("/product?name=bimo&price=78")
                .expect("I just received data", done);

        });
    });
});


text:
package org.apache.flink.runtime.scheduler.strategy;

import org.apache.flink.runtime.executiongraph.ExecutionVertex;
import org.apache.flink.runtime.jobgraph.JobVertexID;
import org.apache.flink.runtime.topology.VertexID;

import static org.apache.flink.util.Preconditions.checkArgument;
import static org.apache.flink.util.Preconditions.checkNotNull;

/**
 * Id identifying {@link ExecutionVertex}.
 */
public class ExecutionVertexID implements VertexID {
	private final JobVertexID jobVertexId;

	private final int subtaskIndex;

	public ExecutionVertexID(JobVertexID jobVertexId, int subtaskIndex) {
		checkArgument(subtaskIndex >= 0, "subtaskIndex must be greater than or equal to 0");

		this.jobVertexId = checkNotNull(jobVertexId);
		this.subtaskIndex = subtaskIndex;
	}

	public JobVertexID getJobVertexId() {
		return jobVertexId;
	}

	public int getSubtaskIndex() {
		return subtaskIndex;
	}

	@Override
	public boolean equals(Object o) {
		if (this == o) {
			return true;
		}

		if (o == null || getClass() != o.getClass()) {
			return false;
		}

		ExecutionVertexID that = (ExecutionVertexID) o;

		return subtaskIndex == that.subtaskIndex && jobVertexId.equals(that.jobVertexId);
	}

	@Override
	public int hashCode() {
		int result = jobVertexId.hashCode();
		result = 31 * result + subtaskIndex;
		return result;
	}

	@Override
	public String toString() {
		return jobVertexId + "_" + subtaskIndex;
	}
}


text:
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>java</artifactId>
        <groupId>me.huding</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>aop</artifactId>

    <name>aop</name>
    <url>http://www.huding.name</url>

    <dependencies>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>


text:
#ifndef HUF_H_2342354
#define HUF_H_2342354

#if defined (__cplusplus)
extern "C" {
#endif

/* *** Dependencies *** */
#include <stddef.h>    /* size_t */
#define HUF_STATIC_LINKING_ONLY
#include "huf.h"

/* *** Static allocation *** */
#define HUF_CREATE_STATIC_DTABLEX6(DTable, maxTableLog) \
        unsigned int DTable[HUF_DTABLE_SIZE(maxTableLog) * 3 / 2] = { maxTableLog }

/* *** Advanced decompression functions *** */
size_t HUF_decompress4X6 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);   /* quad-symbols decoder, only works for dstSize >= 64 */

/* *** HUF detailed API *** */
size_t HUF_readDTableX6 (unsigned* DTable, const void* src, size_t srcSize);
size_t HUF_decompress4X6_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const unsigned* DTable);

/* single stream variants */
size_t HUF_decompress1X6 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);   /* quad-symbols decoder, only works for dstSize >= 64 */
size_t HUF_decompress1X6_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const unsigned* DTable);

#if defined (__cplusplus)
}
#endif

#endif   /* HUF_H_2342354 */


text:
layout: post
title: Variable dasar python
tags: [Demo, Markdown]
comment: true
---

Sedikit belajar tentang variable pada python dan juga manipulasi variable
untuk programmer yang sudah mengerti basic pasti sudah mengetahui untuk belajar bahasa baru
harus mengerti fundamental (Dasar) dari programming dan variable sudah menjadi fundamental yang
wajib dipelajari.

Dan ini iseng-iseng sambil belajar ke tahap selanjutnya yaitu variable

```python
#Learn Python | Muhammad Naufal

counter = 25800 # Integer
miles = 1230.05 # Floating
name = "Muhammad Naufal" # String

print(counter) # Result : 25800
print(miles) # Result : 1230.05
print(name) # Muhammad Naufal

# Manipulate string

varName = "Belajar Python Pemula"
varAddres = "Cibinong"
varSkill = "Python"

print(varName) # Result :  Belajar Python Pemula
print(varName[0]) # Result : B
print(varName[0:6]) # Result : Belajar
print(varName[1:]) # Result : elajar
print(varName * 2) # Result : Belajar Python PemulaBelajar Python Pemula
print("Nama saya adalah : " + varName + " " + "Alamat = " + varAddres + " " + "Skill = " + varSkill)
# Result : Nama saya adalah : Belajar Python Pemula Alamat = Cibinong Skill = Python
```

Semoga bisa diulik lagi belajar codingnya.


text:
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { IPropertyPaneField, PropertyPaneFieldType } from "@microsoft/sp-property-pane";

import PropertyFieldAceEditorHost from './PropertyFieldMonacoEditorHost';

import { IPropertyFieldMonacoEditorPropsInternal, IPropertyFieldMonacoEditorProps } from './IPropertyFieldMonacoEditor';

class PropertyFieldMonacoEditorBuilder implements IPropertyPaneField<IPropertyFieldMonacoEditorPropsInternal> {
  public targetProperty: string;
  public type: PropertyPaneFieldType = PropertyPaneFieldType.Custom;
  public properties: IPropertyFieldMonacoEditorPropsInternal;
  public onPropertyChange(propertyPath: string, oldValue: any, newValue: any): void { }
  private onGetErrorMessage?: (value: string, annotations: string[]) => string | Promise<string>;

  //private _onChangeCallback: (targetProperty?: string, newValue?: any) => void;

  public constructor(_targetProperty: string, _properties: IPropertyFieldMonacoEditorPropsInternal) {
    this.targetProperty = _targetProperty;
    this.properties = _properties;
    this.onPropertyChange = _properties.onPropertyChange;
    this.properties.onRender = this._render.bind(this);
    this.properties.onDispose = this._dispose.bind(this);
  }

  private _render(elem: HTMLElement, context?: any, changeCallback?: (targetProperty?: string, newValue?: any) => void): void {

    const props: IPropertyFieldMonacoEditorProps = <IPropertyFieldMonacoEditorProps>this.properties;

    const element = React.createElement(PropertyFieldAceEditorHost, {
      ...props,
      targetProperty: this.targetProperty,
      onRender: this._render,
      onChange: changeCallback,
      onPropertyChange: this.onPropertyChange,
    });

    ReactDOM.render(element, elem);

    // if (changeCallback) {
    //   this._onChangeCallback = changeCallback;
    // }
  }

  private _dispose(elem: HTMLElement) {
    ReactDOM.unmountComponentAtNode(elem);
  }
}

/**
 * Use this property pane control to allow users to edit in-place code.
 *
 * To allow full-page code editing, please use the PnP codeeditor property control.
 *
 * @param targetProperty
 * @param properties
 */
export function PropertyFieldMonacoEditor(targetProperty: string, properties: IPropertyFieldMonacoEditorProps): IPropertyPaneField<IPropertyFieldMonacoEditorPropsInternal> {
  return new PropertyFieldMonacoEditorBuilder(targetProperty, {
    ...properties,
    targetProperty: targetProperty,
    onRender: null,
    onDispose: null
  });
}


text:
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
require 'slide_hero'

require 'minitest/autorun'
require 'minitest/spec'

def assert_dom_match(expected, actual)
  dom_clean(actual).must_equal(
    dom_clean(expected))
end

def assert_dom_includes(expected, actual)
  dom_clean(actual).must_include(
    dom_clean(expected))
end

def dom_clean(html)
  html.gsub!(/>\s*</, '><').strip
end


text:
package rs.configVault.server.manager;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Properties;

import javax.inject.Named;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.text.StrMatcher;
import org.apache.commons.lang3.text.StrSubstitutor;

@Named
public class VaultManager {

	private File vaultPath;
	private VaultHistory vaultHistory;

	public VaultManager(File vaultPath) {
		this.vaultPath = vaultPath;
		this.vaultHistory = new VaultHistory();
	}

	public String[] getEnvs() {
		return vaultPath.list();
	}

	public String[] getConfigs(String env) {
		return new File(vaultPath, env).list();
	}

	public String getConfig(String env, String configId) {
		File configFile = new File(vaultPath, env + "/" + configId);

		try {
			Properties envProperties = getEnvProperties(env);
			EnvLookup variableResolver = new EnvLookup(envProperties);
			StrSubstitutor strSubstitutor = new StrSubstitutor(variableResolver, StrMatcher.stringMatcher("${env:"), StrSubstitutor.DEFAULT_SUFFIX, StrSubstitutor.DEFAULT_ESCAPE);

			String configContent = FileUtils.readFileToString(configFile, Charset.forName("UTF-8"));

			return strSubstitutor.replace(configContent);
		}
		catch (FileNotFoundException e) {
			throw new RuntimeException("Unable to find the config file into: " + configFile.getAbsolutePath(), e);
		}
		catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	public void saveConfig(String env, String configId, InputStream inputStream) {
		try {
			File envVaultPath = new File(vaultPath, env);
			File file = new File(envVaultPath, configId);

			FileUtils.copyInputStreamToFile(inputStream, file);

			vaultHistory.createRevision(envVaultPath, file);
		}
		catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	public void saveConfig(String env, String configId, String fileContent) {
		try {
			File envVaultPath = new File(vaultPath, env);
			File file = new File(envVaultPath, configId);

			FileUtils.write(file, fileContent, Charset.forName("UTF-8"));

			vaultHistory.createRevision(envVaultPath, file);
		}
		catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	public Properties getEnvProperties(String env) throws IOException {
		File file = new File(vaultPath, env + "/vault.env.properties");

		FileInputStream fileInputStream = new FileInputStream(file);
		Properties envProperties = new Properties();
		envProperties.load(fileInputStream);

		fileInputStream.close();

		return envProperties;
	}

}


text:
package net.ontopia.topicmaps.classify;

import java.util.ArrayList;
import java.util.List;

/**
 * INTERNAL:
 */
public class DocumentClassifier {
  private TermDatabase tdb;
  private TermStemmerIF termStemmer;
  private List<DocumentAnalyzerIF> docAnalyzers = new ArrayList<DocumentAnalyzerIF>();
  private List<TermAnalyzerIF> termAnalyzers = new ArrayList<TermAnalyzerIF>();

  public DocumentClassifier(TermDatabase tdb) {
    this.tdb = tdb;
  }

  public TermDatabase getTermDatabase() {
    return tdb;
  }

  public void setTermDatabase(TermDatabase tdb) {
    this.tdb = tdb;
  }

  // --------------------------------------------------------------------------
  // configuration
  // --------------------------------------------------------------------------

  public void setTermStemmer(TermStemmerIF stemmer) {
    this.termStemmer = stemmer;
  }

  public void addDocumentAnalyzer(DocumentAnalyzerIF analyzer) {
    this.docAnalyzers.add(analyzer);
  }

  public void addTermAnalyzer(TermAnalyzerIF analyzer) {
    this.termAnalyzers.add(analyzer);
  }

  // --------------------------------------------------------------------------
  // term extraction
  // --------------------------------------------------------------------------

  protected void extractTerms(Document doc) {
    // turn text blocks into lists of terms
    extractTerms(doc.getRoot());
  }

  protected void extractTerms(Region region) {
    // loop over region's children
    for (Object child : region.getChildren()) {
      if (child instanceof TextBlock) {
        TextBlock tb = (TextBlock)child;
        extractTerms(region, tb);
      } else {
        Region tr = (Region)child;
        extractTerms(tr);
      }
    }
  }

  protected void extractTerms(Region parent, TextBlock tb) {
    for (Token token : tb.getTokens()) {
      if (token.getType() == Token.TYPE_VARIANT) {
        Variant variant = (Variant)token;
        Term term = variant.getTerm();
        if (term == null) {
          String normalized = token.getValue();
          String stem = termStemmer.stem(normalized);
          term = tdb.createTerm(stem);
          variant.setTerm(term);
        }
        term.addVariant(variant);
      }
    }
  }

  // --------------------------------------------------------------------------
  // document analysis
  // --------------------------------------------------------------------------

  public void analyzeDocument(Document doc) {
    // turn text blocks into lists of terms
    extractTerms(doc);
    // do document analysis
    if (docAnalyzers != null && !docAnalyzers.isEmpty()) {
      Region root = doc.getRoot();
      for (DocumentAnalyzerIF analyzer : docAnalyzers) {
        analyzer.startAnalysis();
        try {
          while (analyzer.doDocumentAnalysis()) {
            analyzer.startDocument(doc);
            analyzeRegion(root, analyzer);
            analyzer.endDocument(doc);
          }
        } finally {
          analyzer.endAnalysis();
        }
      }
    }
  }

  protected void analyzeRegion(Region region, DocumentAnalyzerIF analyzer) {
    analyzer.startRegion(region);
    // loop over region's children
    for (Object child : region.getChildren()) {
      if (child instanceof TextBlock) {
        TextBlock tb = (TextBlock)child;
        analyzeTextBlock(region, tb, analyzer);
      } else {
        Region tr = (Region)child;
        analyzeRegion(tr, analyzer);
      }
    }
    analyzer.endRegion(region);
  }

  protected void analyzeTextBlock(Region parent, TextBlock tb, DocumentAnalyzerIF analyzer) {
    // loop over terms in text block
    List<Token> tokens = tb.getTokens();
    int size = tokens.size();
    for (int i=0; i < size; i++) {
      Token t = tokens.get(i);
      analyzer.analyzeToken(tb, t, i);
    }
  }

  // --------------------------------------------------------------------------
  // term analysis
  // --------------------------------------------------------------------------

  public void analyzeTerms() {
    if (termAnalyzers != null && !termAnalyzers.isEmpty()) {
      for (TermAnalyzerIF analyzer : termAnalyzers) {
        analyzer.startAnalysis(tdb);
        try {
          Term[] terms = tdb.getTerms().toArray(new Term[] {}); // create array to avoid CME
          for (int x=0; x < terms.length; x++) {
            analyzer.analyzeTerm(terms[x]);
          }

        } finally {
          analyzer.endAnalysis();
        }
      }
    }
  }

  // --------------------------------------------------------------------------
  // debug
  // --------------------------------------------------------------------------

  public void dump() {
    for (TermAnalyzerIF ta : termAnalyzers) {
      if (ta instanceof CompoundAnalyzer) {
        CompoundAnalyzer ca = (CompoundAnalyzer)ta;
        Term[] terms = tdb.getTermsByRank();
        for (int i=0; i < terms.length; i++) {
          ca.dump(terms[i]);
        }
      }
    }
  }
}


text:
namespace nano
{
class node_observers final
{
public:
	using blocks_t = nano::observer_set<nano::election_status const &, nano::account const &, nano::uint128_t const &, bool>;
	blocks_t blocks;
	nano::observer_set<bool> wallet;
	nano::observer_set<std::shared_ptr<nano::vote>, std::shared_ptr<nano::transport::channel>> vote;
	nano::observer_set<nano::block_hash const &> active_stopped;
	nano::observer_set<nano::account const &, bool> account_balance;
	nano::observer_set<std::shared_ptr<nano::transport::channel>> endpoint;
	nano::observer_set<> disconnect;
	nano::observer_set<uint64_t> difficulty;
	nano::observer_set<nano::root const &> work_cancel;
};

std::unique_ptr<seq_con_info_component> collect_seq_con_info (node_observers & node_observers, const std::string & name);
}


text:
This is a quick port of "A first-person engine in 265 lines" from JavaScript to Java using the libGDX framework.

* http://www.playfuljs.com/a-first-person-engine-in-265-lines/
* http://libgdx.badlogicgames.com/

![Screenshot](https://pbs.twimg.com/media/Bpde8qACMAEoo_F.png:large)

## Porting details

Besides the obvious changes in rendering and input code there is four new types introduced that in the original code are represented either as an `Array` or `Object`.

* Point
* Projection
* Ray
* Step

## Building

To test it out download the repository and build it using gradle.

**Requirements**

* JDK - http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html
* Gradle - http://www.gradle.org/

The following instructions assumes you are in the root folder of the project, eg.

    $ git clone https://github.com/walle/raycaster.git
    $ cd raycaster

The first time you build the project is going to take a while since all dependencies are downloaded, will be faster after that.

### Building the desktop version

The easiest way to test the project is on desktop, just run

    $ ./gradlew desktop:run

### Building the Android version

Make sure you have the Android SDK and have created an AVD. http://developer.android.com/sdk/index.html#download
Start the emulator with your AVD and have it running before building the project. Eg.

    $ cd /path/to/android/sdk
    $ tools/emulator -avd my_avd_name -gpu on

When you see the emulated home screen, run the gradle task

    $ ./gradlew android:installDebug android:run

### Building the web version

    $ ./gradlew html:superDev

Then open your browser to http://localhost:8080/html/

### Building the IOS version

To build the IOS version it's required to use OS X. Also to have Xcode installed, install it from the AppStore.
When you have Xcode installed, make sure you have the iOS Simulator installed, otherwise install it. `Xcode -> Preferences -> Downloads`
Then run the gradle task to start the simulator.

    $ ./gradlew ios:assemble launchIPhoneSimulator

## License

The code is under MIT license, ported from JavaScript.

The images used are from the article http://www.playfuljs.com/a-first-person-engine-in-265-lines/.


text:
<?xml version="1.0" encoding="ISO-8859-1"?>

<rss version="2.0"
>

<channel>
<title>District of Maryland - Recent Entries</title>
<link>https://ecf.mdb.uscourts.gov</link>
<description>Docket entries of type: all</description>
<lastBuildDate>Tue, 24 Apr 2018 22:30:01 GMT</lastBuildDate>

<item>
<title>18-00079 Dozier v. A&E Television Networks</title>
<link>https://ecf.mdb.uscourts.gov/cgi-bin/DktRpt.pl?711557</link>
<description>Type: ap Office: 1 Chapter:   [Close Adversary Case] </description>
<guid isPermaLink="true">https://ecf.mdb.uscourts.gov/cgi-bin/DktRpt.pl?711557-19</guid>
<pubDate>Tue, 24 Apr 2018 11:25:12 GMT</pubDate>
</item>
</channel>
</rss>


text:
namespace DriverSolutions.ModuleFinance
{
    partial class XF_Holidays
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(XF_Holidays));
            DevExpress.Utils.SerializableAppearanceObject serializableAppearanceObject2 = new DevExpress.Utils.SerializableAppearanceObject();
            this.layoutControl1 = new DevExpress.XtraLayout.LayoutControl();
            this.btnSave = new DevExpress.XtraEditors.SimpleButton();
            this.btnCancel = new DevExpress.XtraEditors.SimpleButton();
            this.gridControlHolidays = new DevExpress.XtraGrid.GridControl();
            this.gridViewHolidays = new DevExpress.XtraGrid.Views.Grid.GridView();
            this.col_HolidayDate = new DevExpress.XtraGrid.Columns.GridColumn();
            this.rep_Date = new DevExpress.XtraEditors.Repository.RepositoryItemDateEdit();
            this.col_Remove = new DevExpress.XtraGrid.Columns.GridColumn();
            this.rep_Remove = new DevExpress.XtraEditors.Repository.RepositoryItemButtonEdit();
            this.layoutControlGroup1 = new DevExpress.XtraLayout.LayoutControlGroup();
            this.layoutControlItem1 = new DevExpress.XtraLayout.LayoutControlItem();
            this.layoutControlItem2 = new DevExpress.XtraLayout.LayoutControlItem();
            this.layoutControlItem3 = new DevExpress.XtraLayout.LayoutControlItem();
            this.emptySpaceItem1 = new DevExpress.XtraLayout.EmptySpaceItem();
            ((System.ComponentModel.ISupportInitialize)(this.layoutControl1)).BeginInit();
            this.layoutControl1.SuspendLayout();
            ((System.ComponentModel.ISupportInitialize)(this.gridControlHolidays)).BeginInit();
            ((System.ComponentModel.ISupportInitialize)(this.gridViewHolidays)).BeginInit();
            ((System.ComponentModel.ISupportInitialize)(this.rep_Date)).BeginInit();
            ((System.ComponentModel.ISupportInitialize)(this.rep_Date.CalendarTimeProperties)).BeginInit();
            ((System.ComponentModel.ISupportInitialize)(this.rep_Remove)).BeginInit();
            ((System.ComponentModel.ISupportInitialize)(this.layoutControlGroup1)).BeginInit();
            ((System.ComponentModel.ISupportInitialize)(this.layoutControlItem1)).BeginInit();
            ((System.ComponentModel.ISupportInitialize)(this.layoutControlItem2)).BeginInit();
            ((System.ComponentModel.ISupportInitialize)(this.layoutControlItem3)).BeginInit();
            ((System.ComponentModel.ISupportInitialize)(this.emptySpaceItem1)).BeginInit();
            this.SuspendLayout();
            //
            // layoutControl1
            //
            this.layoutControl1.Controls.Add(this.btnSave);
            this.layoutControl1.Controls.Add(this.btnCancel);
            this.layoutControl1.Controls.Add(this.gridControlHolidays);
            this.layoutControl1.Dock = System.Windows.Forms.DockStyle.Fill;
            this.layoutControl1.Location = new System.Drawing.Point(0, 0);
            this.layoutControl1.Name = "layoutControl1";
            this.layoutControl1.OptionsCustomizationForm.DesignTimeCustomizationFormPositionAndSize = new System.Drawing.Rectangle(470, 247, 250, 350);
            this.layoutControl1.Root = this.layoutControlGroup1;
            this.layoutControl1.Size = new System.Drawing.Size(666, 446);
            this.layoutControl1.TabIndex = 0;
            this.layoutControl1.Text = "layoutControl1";
            //
            // btnSave
            //
            this.btnSave.Image = ((System.Drawing.Image)(resources.GetObject("btnSave.Image")));
            this.btnSave.Location = new System.Drawing.Point(324, 400);
            this.btnSave.Name = "btnSave";
            this.btnSave.Size = new System.Drawing.Size(179, 41);
            this.btnSave.StyleController = this.layoutControl1;
            this.btnSave.TabIndex = 6;
            this.btnSave.Text = "Save";
            this.btnSave.Click += new System.EventHandler(this.btnSave_Click);
            //
            // btnCancel
            //
            this.btnCancel.Image = ((System.Drawing.Image)(resources.GetObject("btnCancel.Image")));
            this.btnCancel.Location = new System.Drawing.Point(507, 400);
            this.btnCancel.Name = "btnCancel";
            this.btnCancel.Size = new System.Drawing.Size(154, 41);
            this.btnCancel.StyleController = this.layoutControl1;
            this.btnCancel.TabIndex = 5;
            this.btnCancel.Text = "Cancel";
            this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
            //
            // gridControlHolidays
            //
            this.gridControlHolidays.Location = new System.Drawing.Point(5, 5);
            this.gridControlHolidays.MainView = this.gridViewHolidays;
            this.gridControlHolidays.Name = "gridControlHolidays";
            this.gridControlHolidays.RepositoryItems.AddRange(new DevExpress.XtraEditors.Repository.RepositoryItem[] {
            this.rep_Date,
            this.rep_Remove});
            this.gridControlHolidays.Size = new System.Drawing.Size(656, 391);
            this.gridControlHolidays.TabIndex = 4;
            this.gridControlHolidays.ViewCollection.AddRange(new DevExpress.XtraGrid.Views.Base.BaseView[] {
            this.gridViewHolidays});
            //
            // gridViewHolidays
            //
            this.gridViewHolidays.Columns.AddRange(new DevExpress.XtraGrid.Columns.GridColumn[] {
            this.col_HolidayDate,
            this.col_Remove});
            this.gridViewHolidays.GridControl = this.gridControlHolidays;
            this.gridViewHolidays.Name = "gridViewHolidays";
            this.gridViewHolidays.OptionsView.NewItemRowPosition = DevExpress.XtraGrid.Views.Grid.NewItemRowPosition.Bottom;
            this.gridViewHolidays.OptionsView.ShowGroupPanel = false;
            //
            // col_HolidayDate
            //
            this.col_HolidayDate.Caption = "Holiday";
            this.col_HolidayDate.ColumnEdit = this.rep_Date;
            this.col_HolidayDate.DisplayFormat.FormatString = "d";
            this.col_HolidayDate.DisplayFormat.FormatType = DevExpress.Utils.FormatType.DateTime;
            this.col_HolidayDate.FieldName = "HolidayDate";
            this.col_HolidayDate.GroupFormat.FormatString = "d";
            this.col_HolidayDate.GroupFormat.FormatType = DevExpress.Utils.FormatType.DateTime;
            this.col_HolidayDate.Name = "col_HolidayDate";
            this.col_HolidayDate.Visible = true;
            this.col_HolidayDate.VisibleIndex = 0;
            this.col_HolidayDate.Width = 442;
            //
            // rep_Date
            //
            this.rep_Date.AutoHeight = false;
            this.rep_Date.Buttons.AddRange(new DevExpress.XtraEditors.Controls.EditorButton[] {
            new DevExpress.XtraEditors.Controls.EditorButton(DevExpress.XtraEditors.Controls.ButtonPredefines.Combo)});
            this.rep_Date.CalendarTimeEditing = DevExpress.Utils.DefaultBoolean.False;
            this.rep_Date.CalendarTimeProperties.Buttons.AddRange(new DevExpress.XtraEditors.Controls.EditorButton[] {
            new DevExpress.XtraEditors.Controls.EditorButton(DevExpress.XtraEditors.Controls.ButtonPredefines.Combo)});
            this.rep_Date.Name = "rep_Date";
            //
            // col_Remove
            //
            this.col_Remove.Caption = "Remove";
            this.col_Remove.ColumnEdit = this.rep_Remove;
            this.col_Remove.Name = "col_Remove";
            this.col_Remove.OptionsColumn.AllowEdit = false;
            this.col_Remove.Visible = true;
            this.col_Remove.VisibleIndex = 1;
            this.col_Remove.Width = 196;
            //
            // rep_Remove
            //
            this.rep_Remove.AutoHeight = false;
            this.rep_Remove.Buttons.AddRange(new DevExpress.XtraEditors.Controls.EditorButton[] {
            new DevExpress.XtraEditors.Controls.EditorButton(DevExpress.XtraEditors.Controls.ButtonPredefines.Glyph, "Remove", -1, true, true, false, DevExpress.XtraEditors.ImageLocation.MiddleCenter, null, new DevExpress.Utils.KeyShortcut(System.Windows.Forms.Keys.None), serializableAppearanceObject2, "", null, null, true)});
            this.rep_Remove.Name = "rep_Remove";
            this.rep_Remove.TextEditStyle = DevExpress.XtraEditors.Controls.TextEditStyles.HideTextEditor;
            //
            // layoutControlGroup1
            //
            this.layoutControlGroup1.CustomizationFormText = "Root";
            this.layoutControlGroup1.EnableIndentsWithoutBorders = DevExpress.Utils.DefaultBoolean.True;
            this.layoutControlGroup1.GroupBordersVisible = false;
            this.layoutControlGroup1.Items.AddRange(new DevExpress.XtraLayout.BaseLayoutItem[] {
            this.layoutControlItem1,
            this.layoutControlItem2,
            this.layoutControlItem3,
            this.emptySpaceItem1});
            this.layoutControlGroup1.Location = new System.Drawing.Point(0, 0);
            this.layoutControlGroup1.Name = "Root";
            this.layoutControlGroup1.Padding = new DevExpress.XtraLayout.Utils.Padding(3, 3, 3, 3);
            this.layoutControlGroup1.Size = new System.Drawing.Size(666, 446);
            this.layoutControlGroup1.Text = "Root";
            this.layoutControlGroup1.TextVisible = false;
            //
            // layoutControlItem1
            //
            this.layoutControlItem1.Control = this.gridControlHolidays;
            this.layoutControlItem1.CustomizationFormText = "layoutControlItem1";
            this.layoutControlItem1.Location = new System.Drawing.Point(0, 0);
            this.layoutControlItem1.Name = "layoutControlItem1";
            this.layoutControlItem1.Size = new System.Drawing.Size(660, 395);
            this.layoutControlItem1.Text = "layoutControlItem1";
            this.layoutControlItem1.TextSize = new System.Drawing.Size(0, 0);
            this.layoutControlItem1.TextToControlDistance = 0;
            this.layoutControlItem1.TextVisible = false;
            //
            // layoutControlItem2
            //
            this.layoutControlItem2.Control = this.btnCancel;
            this.layoutControlItem2.CustomizationFormText = "layoutControlItem2";
            this.layoutControlItem2.Location = new System.Drawing.Point(502, 395);
            this.layoutControlItem2.MaxSize = new System.Drawing.Size(0, 45);
            this.layoutControlItem2.MinSize = new System.Drawing.Size(82, 45);
            this.layoutControlItem2.Name = "layoutControlItem2";
            this.layoutControlItem2.Size = new System.Drawing.Size(158, 45);
            this.layoutControlItem2.SizeConstraintsType = DevExpress.XtraLayout.SizeConstraintsType.Custom;
            this.layoutControlItem2.Text = "layoutControlItem2";
            this.layoutControlItem2.TextSize = new System.Drawing.Size(0, 0);
            this.layoutControlItem2.TextToControlDistance = 0;
            this.layoutControlItem2.TextVisible = false;
            //
            // layoutControlItem3
            //
            this.layoutControlItem3.Control = this.btnSave;
            this.layoutControlItem3.CustomizationFormText = "layoutControlItem3";
            this.layoutControlItem3.Location = new System.Drawing.Point(319, 395);
            this.layoutControlItem3.MaxSize = new System.Drawing.Size(0, 45);
            this.layoutControlItem3.MinSize = new System.Drawing.Size(82, 45);
            this.layoutControlItem3.Name = "layoutControlItem3";
            this.layoutControlItem3.Size = new System.Drawing.Size(183, 45);
            this.layoutControlItem3.SizeConstraintsType = DevExpress.XtraLayout.SizeConstraintsType.Custom;
            this.layoutControlItem3.Text = "layoutControlItem3";
            this.layoutControlItem3.TextSize = new System.Drawing.Size(0, 0);
            this.layoutControlItem3.TextToControlDistance = 0;
            this.layoutControlItem3.TextVisible = false;
            //
            // emptySpaceItem1
            //
            this.emptySpaceItem1.AllowHotTrack = false;
            this.emptySpaceItem1.CustomizationFormText = "emptySpaceItem1";
            this.emptySpaceItem1.Location = new System.Drawing.Point(0, 395);
            this.emptySpaceItem1.Name = "emptySpaceItem1";
            this.emptySpaceItem1.Size = new System.Drawing.Size(319, 45);
            this.emptySpaceItem1.Text = "emptySpaceItem1";
            this.emptySpaceItem1.TextSize = new System.Drawing.Size(0, 0);
            //
            // XF_Holidays
            //
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(666, 446);
            this.Controls.Add(this.layoutControl1);
            this.Name = "XF_Holidays";
            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
            this.Text = "Holidays";
            ((System.ComponentModel.ISupportInitialize)(this.layoutControl1)).EndInit();
            this.layoutControl1.ResumeLayout(false);
            ((System.ComponentModel.ISupportInitialize)(this.gridControlHolidays)).EndInit();
            ((System.ComponentModel.ISupportInitialize)(this.gridViewHolidays)).EndInit();
            ((System.ComponentModel.ISupportInitialize)(this.rep_Date.CalendarTimeProperties)).EndInit();
            ((System.ComponentModel.ISupportInitialize)(this.rep_Date)).EndInit();
            ((System.ComponentModel.ISupportInitialize)(this.rep_Remove)).EndInit();
            ((System.ComponentModel.ISupportInitialize)(this.layoutControlGroup1)).EndInit();
            ((System.ComponentModel.ISupportInitialize)(this.layoutControlItem1)).EndInit();
            ((System.ComponentModel.ISupportInitialize)(this.layoutControlItem2)).EndInit();
            ((System.ComponentModel.ISupportInitialize)(this.layoutControlItem3)).EndInit();
            ((System.ComponentModel.ISupportInitialize)(this.emptySpaceItem1)).EndInit();
            this.ResumeLayout(false);

        }

        #endregion

        private DevExpress.XtraLayout.LayoutControl layoutControl1;
        private DevExpress.XtraLayout.LayoutControlGroup layoutControlGroup1;
        private DevExpress.XtraEditors.SimpleButton btnSave;
        private DevExpress.XtraEditors.SimpleButton btnCancel;
        private DevExpress.XtraGrid.GridControl gridControlHolidays;
        private DevExpress.XtraGrid.Views.Grid.GridView gridViewHolidays;
        private DevExpress.XtraLayout.LayoutControlItem layoutControlItem1;
        private DevExpress.XtraLayout.LayoutControlItem layoutControlItem2;
        private DevExpress.XtraLayout.LayoutControlItem layoutControlItem3;
        private DevExpress.XtraLayout.EmptySpaceItem emptySpaceItem1;
        private DevExpress.XtraGrid.Columns.GridColumn col_HolidayDate;
        private DevExpress.XtraEditors.Repository.RepositoryItemDateEdit rep_Date;
        private DevExpress.XtraGrid.Columns.GridColumn col_Remove;
        private DevExpress.XtraEditors.Repository.RepositoryItemButtonEdit rep_Remove;
    }
}


text:
package ru.job4j.collections;

import java.util.HashMap;
import java.util.List;

/**
 * Class UserConvert.
 * @author Andrey Kustov
 * @version $1.0$
 * @since 30.04.2017
 */
public class UserConvert {
    /**
     * из списка в словарь.
     * @param list список.
     * @return словарь.
     */
    public static HashMap<Integer, User> process(List<User> list) {
        HashMap<Integer, User> map = new HashMap<>();
        for (User user : list) {
            map.put(user.getId(), user);
        }
        return map;
    }
}


text:
<?xml version="1.0" ?>

<srv:container xmlns="http://symfony.com/schema/dic/doctrine"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:srv="http://symfony.com/schema/dic/services"
    xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd
                        http://symfony.com/schema/dic/doctrine http://symfony.com/schema/dic/doctrine/doctrine-1.0.xsd">

    <config>
        <dbal auto-commit="false" />
    </config>
</srv:container>


text:
package com.intellij.javaee.oss.admin.jmx;

/**
 * @author VISTALL
 * @since 03-Jul-17
 */
public class JmxAdminException extends Exception
{
	public JmxAdminException()
	{
	}

	public JmxAdminException(String message)
	{
		super(message);
	}

	public JmxAdminException(String message, Throwable cause)
	{
		super(message, cause);
	}

	public JmxAdminException(Throwable cause)
	{
		super(cause);
	}

	public JmxAdminException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace)
	{
		super(message, cause, enableSuppression, writableStackTrace);
	}
}


text:
package ru.atott.combiq.service.question;

import ru.atott.combiq.service.bean.Questionnaire;
import ru.atott.combiq.service.bean.QuestionnaireHead;
import ru.atott.combiq.service.site.UserContext;

import java.io.OutputStream;
import java.util.List;

public interface QuestionnaireService {

    List<QuestionnaireHead> getQuestionnaires();

    QuestionnaireHead getQuestionnaireByLegacyId(String id);

    Questionnaire getQuestionnaire(UserContext uc, String id);

    Questionnaire exportQuestionnareToPdf(UserContext uc, String id, OutputStream outputStream);

    void updateQuestionnaireTitle(UserContext uc, String id, String title);

    void exportQuestionnareToPdf(Questionnaire questionnaire, OutputStream outputStream);
}


text:
namespace spaghetti::nodes::logic {

void Blinker::showProperties()
{
  showCommonProperties();
  showIOProperties(IOSocketsType::eOutputs);

  propertiesInsertTitle("Blinker");
}

} // namespace spaghetti::nodes::logic


text:
module.exports = function(opts) {
  opts = opts || {};
  if (opts.THREE) opts = {game:opts};
  var game = opts.game;
  var createPortal = require('voxel-portal')(game);
  var portals = [];

  function addBorder(mesh) {
    var black = new game.THREE.MeshBasicMaterial({color:0x000000});
    black.wireframe = true;
    mesh.material = new game.THREE.MeshFaceMaterial([
      black, black, black, black, mesh.material, black
    ]);
    mesh.needsUpdate = true;
  }

  function where() {
    var start = game.controls.yawObject.position.clone();
    var direction = game.camera.matrixWorld.multiplyVector3(new game.THREE.Vector3(0, 0, -1));
    var pos = game.intersectAllMeshes(start, direction);
    if (pos == false) {
      // this next part took me a valve length of time to figure out
      var r = 1000;
      var cam = game.cameraRotation();
      var phi = cam.x - (Math.PI/2);
      var theta = cam.y;
      pos = new game.THREE.Vector3(
        (r * Math.sin(phi) * Math.sin(theta)) + start.x,
        (r * Math.cos(phi)) + start.y,
        (r * Math.sin(phi) * Math.cos(theta)) + start.z
      );
    }
    return pos.addSelf(new game.THREE.Vector3(0, game.cubeSize, 0));
  }

  return function() {
    if (portals.length > 1) game.scene.remove(portals.shift().monitor);

    var w = where();

    var portal = createPortal({
      x: w.x, y: w.y, z: w.z,
      width: 70, height: 70 * 1.77
    });
    portals.push(portal);

    addBorder(portal.monitor);

    if (portals.length > 1) {
      portals[0].show(portal, { x: 0, y: 0, z: 1 });
      portal.show(portals[0], { x: 0, y: 0, z: -1 });
    }

    portal.monitor.lookAt(game.controls.yawObject.position);

    portal.on('enter', function() {
      var self = this;
      portals.forEach(function(p) {
        if (p != self) game.moveToPosition(p.position);
      });
    });
  }
}


text:
package edu.berkeley.lipstick.simpleserver;

import com.sun.tools.javac.util.Pair;

import org.apache.cassandra.thrift.NotFoundException;
import org.apache.thrift.TException;
import org.apache.thrift.transport.TTransportException;

import java.nio.ByteBuffer;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class SimpleServerServiceImpl implements SimpleServerService.Iface {

    private Map<String, Pair<Long, ByteBuffer>> storage;

    public SimpleServerServiceImpl()
    {
        storage = new ConcurrentHashMap<String, Pair<Long, ByteBuffer>>();
    }

    public ByteBuffer get(String key) throws TException{
        Pair<Long, ByteBuffer> ret = storage.get(key);
        if(ret == null)
            throw new TTransportException();
        return storage.get(key).snd;

    }

    public void put(String key, ByteBuffer value, long timestamp) throws TException {
        if(!storage.containsKey(key) || timestamp > storage.get(key).fst)
            storage.put(key, new Pair<Long, ByteBuffer>(timestamp, value));
    }
}


text:
- use `create-react-app` to create application skeleton
  - setup instructions at https://github.com/facebookincubator/create-react-app
- initialize local Git repository
- use `yarn start` and `yarn test`
- add needed packages: `redux`, `react-redux`, `react-router`, `storybook`

# Presentational Components

Prerequisites:
- graphical design, mockups or wireframes

Goals:
- get into business domain language
- breakdown graphical design into named components

Steps:
- put presentational components into `components/`
- route to presentational components directly (for now)
- create dumb presentational components, i.e. with data inside `render`

Deliverables:
- dumb presentational prototype deployed to server

# Container Components

Goals:
- design and implement data shape on a component level

Steps:
- put container components into `containers/`
- create _disconnected_ container components with mocked data
  - i.e. with mocked data in `mapStateToProps` instead of data from `state`
- use `storybook` for showcasing different states of components
- change dump presentational components to receive data via props

Deliverables:
- living Storybook showcasing components in different states

# State and Behavior

Goals:
- design and implement state shape at Redux level
- get into actions and behavior from business domain

Steps:
- think about shape of the state
- break it down into composed reducers
- connect container components to state

Deliverables:
- functioning prototype


text:
/**
 * This class handles table cell selection by faking it using a css class that gets applied
 * to cells when dragging the mouse from one cell to another.
 *
 * @class tinymce.table.selection.CellSelection
 * @private
 */
define(
  'tinymce.plugins.table.selection.CellSelection',
  [
    'tinymce.plugins.table.model.TableGrid',
    'tinymce.core.dom.TreeWalker',
    'tinymce.core.util.Tools'
  ],
  function (TableGrid, TreeWalker, Tools) {
    return function (editor, selectionChange) {
      var dom = editor.dom, tableGrid, startCell, startTable, lastMouseOverTarget, hasCellSelection = true, resizing, dragging;

      function clear(force) {
        // Restore selection possibilities
        editor.getBody().style.webkitUserSelect = '';

        if (force || hasCellSelection) {
          editor.$('td[data-mce-selected],th[data-mce-selected]').removeAttr('data-mce-selected');
          hasCellSelection = false;
        }
      }

      var endSelection = function () {
        startCell = tableGrid = startTable = lastMouseOverTarget = null;
        selectionChange(false);
      };

      function isCellInTable(table, cell) {
        if (!table || !cell) {
          return false;
        }

        return table === dom.getParent(cell, 'table');
      }

      function cellSelectionHandler(e) {
        var sel, target = e.target, currentCell;

        if (resizing || dragging) {
          return;
        }

        // Fake mouse enter by keeping track of last mouse over
        if (target === lastMouseOverTarget) {
          return;
        }

        lastMouseOverTarget = target;

        if (startTable && startCell) {
          currentCell = dom.getParent(target, 'td,th');

          if (!isCellInTable(startTable, currentCell)) {
            currentCell = dom.getParent(startTable, 'td,th');
          }

          // Selection inside first cell is normal until we have expanted
          if (startCell === currentCell && !hasCellSelection) {
            return;
          }

          selectionChange(true);

          if (isCellInTable(startTable, currentCell)) {
            e.preventDefault();

            if (!tableGrid) {
              tableGrid = new TableGrid(editor, startTable, startCell);
              editor.getBody().style.webkitUserSelect = 'none';
            }

            tableGrid.setEndCell(currentCell);
            hasCellSelection = true;

            // Remove current selection
            sel = editor.selection.getSel();

            try {
              if (sel.removeAllRanges) {
                sel.removeAllRanges();
              } else {
                sel.empty();
              }
            } catch (ex) {
              // IE9 might throw errors here
            }
          }
        }
      }

      editor.on('SelectionChange', function (e) {
        if (hasCellSelection) {
          e.stopImmediatePropagation();
        }
      }, true);

      // Add cell selection logic
      editor.on('MouseDown', function (e) {
        if (e.button != 2 && !resizing && !dragging) {
          clear();

          startCell = dom.getParent(e.target, 'td,th');
          startTable = dom.getParent(startCell, 'table');
        }
      });

      editor.on('mouseover', cellSelectionHandler);

      editor.on('remove', function () {
        dom.unbind(editor.getDoc(), 'mouseover', cellSelectionHandler);
        clear();
      });

      editor.on('MouseUp', function () {
        var rng, sel = editor.selection, selectedCells, walker, node, lastNode;

        function setPoint(node, start) {
          var walker = new TreeWalker(node, node);

          do {
            // Text node
            if (node.nodeType == 3 && Tools.trim(node.nodeValue).length !== 0) {
              if (start) {
                rng.setStart(node, 0);
              } else {
                rng.setEnd(node, node.nodeValue.length);
              }

              return;
            }

            // BR element
            if (node.nodeName == 'BR') {
              if (start) {
                rng.setStartBefore(node);
              } else {
                rng.setEndBefore(node);
              }

              return;
            }
          } while ((node = (start ? walker.next() : walker.prev())));
        }

        // Move selection to startCell
        if (startCell) {
          if (tableGrid) {
            editor.getBody().style.webkitUserSelect = '';
          }

          // Try to expand text selection as much as we can only Gecko supports cell selection
          selectedCells = dom.select('td[data-mce-selected],th[data-mce-selected]');
          if (selectedCells.length > 0) {
            rng = dom.createRng();
            node = selectedCells[0];
            rng.setStartBefore(node);
            rng.setEndAfter(node);

            setPoint(node, 1);
            walker = new TreeWalker(node, dom.getParent(selectedCells[0], 'table'));

            do {
              if (node.nodeName == 'TD' || node.nodeName == 'TH') {
                if (!dom.getAttrib(node, 'data-mce-selected')) {
                  break;
                }

                lastNode = node;
              }
            } while ((node = walker.next()));

            setPoint(lastNode);

            sel.setRng(rng);
          }

          editor.nodeChanged();
          endSelection();
        }
      });

      editor.on('KeyUp Drop SetContent', function (e) {
        clear(e.type == 'setcontent');
        endSelection();
        resizing = false;
      });

      editor.on('ObjectResizeStart ObjectResized', function (e) {
        resizing = e.type != 'objectresized';
      });

      editor.on('dragstart', function () {
        dragging = true;
      });

      editor.on('drop dragend', function () {
        dragging = false;
      });

      return {
        clear: clear
      };
    };
  }
);


text:
require "hamporter/command"
module Hamporter
  class Application
    def run(*args)
      command = args.shift.strip rescue "help"
      Hamporter::Command.load
      Hamporter::Command.run(command, args)
    end
  end

  class << self
    def application
      @application ||= Hamporter::Application.new
    end

    def application=(app)
      @application = app
    end
  end
end