diff --git a/Gemfile b/Gemfile
index 4000259..9fe15d8 100644
--- a/Gemfile
+++ b/Gemfile
@@ -80,6 +80,9 @@ group :test do
gem 'minitest-spec-rails'
end
+#ask
+gem 'gotcha'
+
#desktop
gem 'angularjs-rails', '~> 1.2.20'
gem 'angular-ui-bootstrap-rails', '~> 0.11.0'
diff --git a/app/controllers/admin/dashboards_controller.rb b/app/controllers/admin/dashboards_controller.rb
index fec9da1..543cf34 100644
--- a/app/controllers/admin/dashboards_controller.rb
+++ b/app/controllers/admin/dashboards_controller.rb
@@ -8,6 +8,7 @@ class Admin::DashboardsController < ApplicationController
@module_app_contents, @module_app_contents_total = get_module_app_count(apps)
@recent_updated = get_recently_updated(apps)
@most_visited = get_most_visited(apps)
+ render_401 and return if !current_user.is_approved? rescue false
end
def get_cpu_usage
@@ -30,10 +31,12 @@ class Admin::DashboardsController < ApplicationController
a = {}
total = 0
args.each do |module_app|
- module_app_class = module_app.classify.constantize
- count = module_app_class.count
- a.merge!(module_app => count)
- total += count
+ module_app_class = module_app.classify.constantize rescue nil
+ if !module_app_class.nil?
+ count = module_app_class.count
+ a.merge!(module_app => count)
+ total += count
+ end
end
[Kaminari.paginate_array(a.sort {|a,b| b[1]<=>a[1]}).page(params[:page]).per(5), total]
end
@@ -41,10 +44,12 @@ class Admin::DashboardsController < ApplicationController
def get_recently_updated(args)
a = {}
args.each do |module_app|
- module_app_class = module_app.classify.constantize
- objects = module_app_class.order_by([:updated_at, :desc]).limit(20)
- objects.each do |object|
- a.merge!(object => object.updated_at) unless (object.archived rescue nil)
+ module_app_class = module_app.classify.constantize rescue nil
+ if !module_app_class.nil?
+ objects = module_app_class.order_by([:updated_at, :desc]).limit(20)
+ objects.each do |object|
+ a.merge!(object => object.updated_at) unless (object.archived rescue nil)
+ end
end
end
sorted_objects = a.sort {|a,b| b[1]<=>a[1]}
@@ -55,17 +60,18 @@ class Admin::DashboardsController < ApplicationController
def get_most_visited(args)
a = {}
args.each do |module_app|
- module_app_class = module_app.classify.constantize
- objects = module_app_class.order_by([:view_count, :desc]).limit(20)
- objects.each do |object|
- a.merge!(object => object.view_count) if object.view_count > 0 && (!object.archived rescue true)
+ module_app_class = module_app.classify.constantize rescue nil
+ if !module_app_class.nil?
+ objects = module_app_class.order_by([:view_count, :desc]).limit(20)
+ objects.each do |object|
+ a.merge!(object => object.view_count) if object.view_count > 0 && (!object.archived rescue true)
+ end
end
end
sorted_objects = a.sort {|a,b| b[1]<=>a[1]}
sorted_objects[0..19]
Kaminari.paginate_array(sorted_objects).page(params[:page]).per(5)
end
-
private
def check_backend_openness
diff --git a/app/controllers/admin/import_controller.rb b/app/controllers/admin/import_controller.rb
index 3c81cce..e65970b 100644
--- a/app/controllers/admin/import_controller.rb
+++ b/app/controllers/admin/import_controller.rb
@@ -528,7 +528,8 @@ class Admin::ImportController < OrbitAdminController
end
end
- new_member.save
+ new_member.save(:validate => false)
+
if member["user_id"].present?
user = User.new
user.user_name = member["user_id"]
diff --git a/app/controllers/admin/members_controller.rb b/app/controllers/admin/members_controller.rb
index 6c8da99..b3963ee 100644
--- a/app/controllers/admin/members_controller.rb
+++ b/app/controllers/admin/members_controller.rb
@@ -29,7 +29,9 @@ class Admin::MembersController < OrbitMemberController
@filter = {@new_filter[:type] => [@new_filter[:id].to_s]}
end
- if @filter.blank? and @mq.blank?
+ render_401 and return if current_user.nil? || !current_user.is_approved?
+
+ if @filter.blank? and @mq.blank?
render case params[:at]
when 'summary'
@@ -72,7 +74,7 @@ class Admin::MembersController < OrbitMemberController
end
end
-
+
end
def show
@@ -92,6 +94,7 @@ class Admin::MembersController < OrbitMemberController
end
get_info_and_roles
+ render_401 and return if current_user.nil? || (@member.id.to_s != current_user.member_profile.id.to_s && !current_user.is_approved?)
end
@@ -464,6 +467,7 @@ class Admin::MembersController < OrbitMemberController
if user_params["user_name"] != ""
@user = User.new(user_params) rescue nil
@user.member_profile = @member
+ @user.save
end
if @member.save
if !params[:member_profile_field_values].nil?
@@ -492,11 +496,14 @@ class Admin::MembersController < OrbitMemberController
@user = @member.user
@user.update(user_params)
else
- @user = User.new(user_params)
- @user.member_profile = @member
+ if user_params["user_name"] != ""
+ @user = User.new(user_params) rescue nil
+ @user.member_profile = @member
+ @user.save
+ end
end
- if @member.update_attributes(member_profile_params) and @user.save
+ if @member.update_attributes(member_profile_params)
if params[:edit_type]!="edit_privilege" and (params[:member_profile].nil? or params[:member_profile][:role_status_ids].nil?)
@member.update_attributes(role_status_ids: [])
end
diff --git a/app/controllers/admin/sites_controller.rb b/app/controllers/admin/sites_controller.rb
index 06559c9..f418a82 100644
--- a/app/controllers/admin/sites_controller.rb
+++ b/app/controllers/admin/sites_controller.rb
@@ -75,6 +75,8 @@ class Admin::SitesController < OrbitAdminController
else
redirect_to :back
end
+ %x(kill -s USR2 `cat tmp/pids/unicorn.pid`)
+ sleep 5
end
def update_manager
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index cd5d683..bfbc6cf 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -134,7 +134,9 @@ class ApplicationController < ActionController::Base
redirect_to new_session_path if @current_user.nil?
return true
- else
+ elsif current_site.backend_openness_on
+ return true
+ elsif
session[:login_referer] = request.url
redirect_to new_session_path
return false
diff --git a/app/controllers/orbit_admin_controller.rb b/app/controllers/orbit_admin_controller.rb
index 3e2ae71..5d56a00 100644
--- a/app/controllers/orbit_admin_controller.rb
+++ b/app/controllers/orbit_admin_controller.rb
@@ -77,7 +77,7 @@ class OrbitAdminController < ApplicationController
end
def load_authorized_categories
- @user_authenticated_categories = current_user.is_admin? ? ["all"] : current_user.approved_categories.collect{|c| c.id}
+ @user_authenticated_categories = current_user.is_admin? ? ["all"] : current_user.approved_categories.collect{|c| c.id} rescue []
end
diff --git a/app/controllers/orbit_member_controller.rb b/app/controllers/orbit_member_controller.rb
index b553ab9..038ac80 100644
--- a/app/controllers/orbit_member_controller.rb
+++ b/app/controllers/orbit_member_controller.rb
@@ -6,14 +6,14 @@ class OrbitMemberController < ApplicationController
def check_aceess_rights
@user_has_privileges = false
- if current_user.is_admin?
+ if (current_user.is_admin? rescue false)
@user_has_privileges = true
else
visited_user = MemberProfile.find_by(:uid => params[:id].split("-").last).user.id rescue nil
- visited_user = MemberProfile.find_by(:uid => params[:member_id].split("-").last).user.id if visited_user.nil? rescue nil
+ visited_user = MemberProfile.find_by(:uid => params[:member_id].split("-").last).user.id if visited_user.nil? rescue nil
visited_user = MemberProfile.find_by(:uid => params[:uid]).user.id if visited_user.nil? rescue nil
visited_user = MemberProfile.find(params[:member_profile_id]).user.id if visited_user.nil? rescue nil
- if current_user.id == visited_user
+ if (current_user.id == visited_user rescue false)
@user_has_privileges = true
else
@user_has_privileges = false
diff --git a/app/controllers/pages_controller.rb b/app/controllers/pages_controller.rb
index 29aad4f..0caef1f 100644
--- a/app/controllers/pages_controller.rb
+++ b/app/controllers/pages_controller.rb
@@ -392,8 +392,8 @@ class PagesController < ApplicationController
p = params.require(:page).permit(:number, :page_type, :page_id, :module, :layout, :parent_page, :data_count, :enabled_for_mobile, :member_sort_position, enabled_for_sitemap: [], enabled_for: [], menu_enabled_for: [], categories: [], tags: [], role_status: [], name_translations: [:en, :zh_tw],external_url_translations: [:en, :zh_tw])
p["url"] = @url
if p["external_url_translations"]
- p["external_url_translations"]["en"] = p["external_url_translations"]["en"].sub("http://" + request.host_with_port,"")
- p["external_url_translations"]["zh_tw"] = p["external_url_translations"]["zh_tw"].sub("http://" + request.host_with_port,"")
+ p["external_url_translations"]["en"] = p["external_url_translations"]["en"].sub("http://" + request.host_with_port,"") if p["external_url_translations"]["en"].present?
+ p["external_url_translations"]["zh_tw"] = p["external_url_translations"]["zh_tw"].sub("http://" + request.host_with_port,"") if p["external_url_translations"]["zh_tw"].present?
end
p
end
@@ -407,8 +407,8 @@ class PagesController < ApplicationController
p["enabled_for_sitemap"] = p["enabled_for_sitemap"] || []
p["enabled_for_mobile"] = p["enabled_for_mobile"] || 0
if p["external_url_translations"]
- p["external_url_translations"]["en"] = p["external_url_translations"]["en"].sub("http://" + request.host_with_port,"")
- p["external_url_translations"]["zh_tw"] = p["external_url_translations"]["zh_tw"].sub("http://" + request.host_with_port,"")
+ p["external_url_translations"]["en"] = p["external_url_translations"]["en"].sub("http://" + request.host_with_port,"") if p["external_url_translations"]["en"].present?
+ p["external_url_translations"]["zh_tw"] = p["external_url_translations"]["zh_tw"].sub("http://" + request.host_with_port,"") if p["external_url_translations"]["zh_tw"].present?
end
p
end
diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb
index d3c7e2b..23d1456 100644
--- a/app/controllers/sessions_controller.rb
+++ b/app/controllers/sessions_controller.rb
@@ -20,7 +20,6 @@ class SessionsController < ApplicationController
user = User.find_by(user_name: @LDAP_USER) rescue nil
if (user && user.authenticate(@LDAP_PASS) && user.is_confirmed?.eql?(true))
- if user.is_approved? || user.is_admin?
session[:user_id] = user.id
session[:login_referer] = nil
if params[:referer_url]
@@ -28,15 +27,10 @@ class SessionsController < ApplicationController
else
redirect_to admin_dashboards_path
end
- else
- flash.now.alert = "User not approved."
- render "new"
- end
else
flash.now.alert = "Invalid username or password"
render "new"
end
-
else
errors = ["很抱歉,您無此權限或帳號登入本站,請洽本站管理員", "Sorry, you don't have the account or authority to login. Please contact the website administrator."]
diff --git a/app/helpers/orbit_backend_helper.rb b/app/helpers/orbit_backend_helper.rb
index 74bcb79..0145e85 100644
--- a/app/helpers/orbit_backend_helper.rb
+++ b/app/helpers/orbit_backend_helper.rb
@@ -141,7 +141,7 @@ module OrbitBackendHelper
if @user_authenticated_categories.first == "all"
return true
else
- @user_authenticated_categories.include?obj.category_id rescue current_user.is_manager?(@module_app)
+ @user_authenticated_categories.include?obj.category_id rescue (current_user.is_manager?(@module_app) rescue false)
end
end
diff --git a/app/helpers/orbit_helper.rb b/app/helpers/orbit_helper.rb
index c11e63c..e87e788 100644
--- a/app/helpers/orbit_helper.rb
+++ b/app/helpers/orbit_helper.rb
@@ -300,6 +300,10 @@ module OrbitHelper
else
res << "
#{params[:type].underscore.humanize.capitalize} #{t(:authorization_)} "
end
+ when 'images'
+ id = AlbumImage.find(params[:id]).album.id.to_s rescue ""
+ res << "#{t('module_name.'+@module_app.key)} #{divider} "
+ res << "#{t(:theater)} "
when 'categories'
if @module_app.key!='category'
res << "#{t('module_name.'+@module_app.key)}#{divider} "
diff --git a/app/models/site.rb b/app/models/site.rb
index cfe8242..fbd8b3f 100644
--- a/app/models/site.rb
+++ b/app/models/site.rb
@@ -21,7 +21,7 @@ class Site
field :desktop_closed, :type => Boolean, :default => false
field :enable_language_detection, :type => Boolean, :default => false
field :enable_zh_cn, :type => Boolean, :default => true
- field :default_locale, :default => "en"
+ field :default_locale, :default => "zh_tw"
field :mobile_on, :type => Boolean, :default => false
field :announcement_category, :type => Array, :default=>[]
field :mobile_bar_color, :type => Array, :default=>[]
diff --git a/app/uploaders/asset_uploader.rb b/app/uploaders/asset_uploader.rb
index 0ed1d48..8db6f57 100644
--- a/app/uploaders/asset_uploader.rb
+++ b/app/uploaders/asset_uploader.rb
@@ -21,6 +21,29 @@ class AssetUploader < CarrierWave::Uploader::Base
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
+ # override
+ def filename
+ @original_filename
+ end
+
+ # override
+ def original_filename=(filename)
+ @original_filename = super(filename)
+
+ if(@original_filename.bytesize > 200)
+ original_file_extension = File.extname(@original_filename)
+
+ @original_filename.force_encoding("ascii-8bit")
+ @original_filename = @original_filename[0, (200 - original_file_extension.bytesize)]
+ @original_filename.encode!("UTF-16BE", "UTF-8", :invalid => :replace, :undef => :replace, :replace => '')
+ @original_filename.encode!("UTF-8")
+
+ @original_filename += original_file_extension
+ end
+
+ @original_filename
+ end
+
# Provide a default URL as a default if there hasn't been a file uploaded:
# def default_url
# "/images/fallback/" + [version_name, "default.png"].compact.join('_')
diff --git a/app/uploaders/image_uploader.rb b/app/uploaders/image_uploader.rb
index 61a699b..8ad579d 100644
--- a/app/uploaders/image_uploader.rb
+++ b/app/uploaders/image_uploader.rb
@@ -19,6 +19,28 @@ class ImageUploader < CarrierWave::Uploader::Base
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
+ # override
+ def filename
+ @original_filename
+ end
+
+ # override
+ def original_filename=(filename)
+ @original_filename = super(filename)
+
+ if(@original_filename.bytesize > 200)
+ original_file_extension = File.extname(@original_filename)
+
+ @original_filename.force_encoding("ascii-8bit")
+ @original_filename = @original_filename[0, (200 - original_file_extension.bytesize)]
+ @original_filename.encode!("UTF-16BE", "UTF-8", :invalid => :replace, :undef => :replace, :replace => '')
+ @original_filename.encode!("UTF-8")
+
+ @original_filename += original_file_extension
+ end
+
+ @original_filename
+ end
# Provide a default URL as a default if there hasn't been a file uploaded:
# def default_url
# # For Rails 3.1+ asset pipeline compatibility:
diff --git a/app/views/admin/dashboards/index.html.erb b/app/views/admin/dashboards/index.html.erb
index f111e36..210cd7a 100644
--- a/app/views/admin/dashboards/index.html.erb
+++ b/app/views/admin/dashboards/index.html.erb
@@ -5,7 +5,7 @@
- <% if current_user.is_admin? %>
+ <% if (current_user.is_admin? rescue false) %>
<%= render 'server_loading' %>
diff --git a/app/views/admin/members/_member_for_listing.html.erb b/app/views/admin/members/_member_for_listing.html.erb
index 3c67867..9c1d21c 100644
--- a/app/views/admin/members/_member_for_listing.html.erb
+++ b/app/views/admin/members/_member_for_listing.html.erb
@@ -1,5 +1,4 @@
<% if member_for_listing.present? && (!member_for_listing.user.present? || member_for_listing.user.approved) %>
-
<%
if member_for_listing.sex == 'male'
@member_gender = 'gender-man'
@@ -9,7 +8,7 @@
@member_gender = 'gender-none'
end
%>
-
+ <% if (member_for_listing.user.user_name != "rulingcom" rescue true) %>
@@ -32,4 +31,5 @@
<%= member_for_listing.email %>
+ <% end %>
<% end %>
\ No newline at end of file
diff --git a/app/views/admin/members/_member_for_summary.html.erb b/app/views/admin/members/_member_for_summary.html.erb
index f39a439..cd04ff4 100644
--- a/app/views/admin/members/_member_for_summary.html.erb
+++ b/app/views/admin/members/_member_for_summary.html.erb
@@ -1,4 +1,5 @@
<% if member_for_summary.present? && (!member_for_summary.user.present? || member_for_summary.user.approved) %>
+ <% if (member_for_summary.user.user_name != "rulingcom" rescue true) %>
<%
@@ -36,5 +37,5 @@
<% end %>
-
+<% end %>
diff --git a/app/views/admin/members/_member_for_thumbnail.html.erb b/app/views/admin/members/_member_for_thumbnail.html.erb
index 2581b4f..56a4cdc 100644
--- a/app/views/admin/members/_member_for_thumbnail.html.erb
+++ b/app/views/admin/members/_member_for_thumbnail.html.erb
@@ -8,6 +8,7 @@
@user_sex = 'gender-none'
end
%>
+ <% if (member_for_thumbnail.user.user_name != "rulingcom" rescue true) %>
@@ -20,4 +21,5 @@
<%= link_to (member_for_thumbnail.name != (member_for_thumbnail.email) ? member_for_thumbnail.name : member_for_thumbnail.id),admin_member_path(member_for_thumbnail) %>
+<% end %>
<% end %>
\ No newline at end of file
diff --git a/app/views/admin/members/_user_basic_passwd.html.erb b/app/views/admin/members/_user_basic_passwd.html.erb
index 035746d..429e73d 100644
--- a/app/views/admin/members/_user_basic_passwd.html.erb
+++ b/app/views/admin/members/_user_basic_passwd.html.erb
@@ -12,7 +12,7 @@
<%= t("users.user_id")%>
diff --git a/config/environment.rb b/config/environment.rb
index 8c47b1d..c022e23 100644
--- a/config/environment.rb
+++ b/config/environment.rb
@@ -246,4 +246,20 @@ if User.count==0
user.email = "orbit@rulingcom.com"
user.approved = true
user.save
+
+ profile = MemberProfile.new
+ profile.first_name_translations = {:en=>'Admin', :zh_tw=>'Admin'}
+ profile.last_name_translations = {:en=>'Admin', :zh_tw=>'Admin'}
+ profile.email = "service@rulingcom.com"
+ profile.save
+
+ user = User.new
+ user.workgroup = group
+ user.member_profile = profile
+ user.user_name = "admin"
+ user.password = "Ab-5508881"
+ user.email = "servicet@rulingcom.com"
+ user.approved = true
+ user.save
+
end
\ No newline at end of file
diff --git a/lib/orbit_app/helper/context_link_renderer.rb b/lib/orbit_app/helper/context_link_renderer.rb
index 72ac5d0..33ef2b4 100644
--- a/lib/orbit_app/helper/context_link_renderer.rb
+++ b/lib/orbit_app/helper/context_link_renderer.rb
@@ -6,6 +6,7 @@ module ContextLinkRenderer
@belong_module_app = belong_module_app
@request = request
@params = params
+ @site = Site.first
@current_user = current_user
@available_for = available_for
if can_display?
@@ -15,7 +16,9 @@ module ContextLinkRenderer
def can_display?
status = "users"
- if @current_user.is_admin?
+ if @site.backend_openness_on && @current_user.nil?
+ status = "users"
+ elsif @current_user.is_admin?
status = "admin"
elsif @current_user.is_manager?(@belong_module_app)
status = "managers"
diff --git a/lib/orbit_app/helper/side_bar_renderer.rb b/lib/orbit_app/helper/side_bar_renderer.rb
index 1d7e4dd..e4fe6a9 100644
--- a/lib/orbit_app/helper/side_bar_renderer.rb
+++ b/lib/orbit_app/helper/side_bar_renderer.rb
@@ -8,6 +8,7 @@ module SideBarRenderer
@current_module_app = current_module_app
@request = request
@params = params
+ @site = Site.first
@current_user = user
@app_available_for = af
if display?
@@ -27,6 +28,7 @@ module SideBarRenderer
@current_module_app = current_module_app
@request = request
@params = params
+ @site = Site.first
@current_user = user
@app_available_for = available_for
if display?
@@ -44,7 +46,9 @@ module SideBarRenderer
def display? #控制sidebar 要不要算圖
status = "users"
- if @current_user.is_admin?
+ if @site.backend_openness_on && @current_user.nil?
+ status = "users"
+ elsif @current_user.is_admin?
status = "admin"
elsif @current_user.is_manager?(@belong_module_app)
status = "managers"
diff --git a/lib/orbit_core_lib.rb b/lib/orbit_core_lib.rb
index cc53914..5001c64 100644
--- a/lib/orbit_core_lib.rb
+++ b/lib/orbit_core_lib.rb
@@ -57,7 +57,7 @@ module OrbitCoreLib
end
@module_authorized_users ||= Authorization.module_authorized_users(@module_app.id).pluck(:user_id) rescue nil
- if current_user.nil?
+ if current_user.nil? && !current_site.backend_openness_on
redirect_to new_session_path
return
end
@@ -65,7 +65,7 @@ module OrbitCoreLib
if !@module_app.nil?
check_user_can_use
else
- if !current_user.is_admin?
+ if current_user.nil? || !current_user.is_admin?
render "public/401"
end
end
@@ -89,7 +89,7 @@ module OrbitCoreLib
end
def allow?(af)
- if !current_user.nil?
+ if !current_user.nil? && current_user.is_approved?
status = "users"
if current_user.is_admin?
status = "admin"
diff --git a/lib/tasks/upgrade.rake b/lib/tasks/upgrade.rake
index 8dd6516..128d845 100644
--- a/lib/tasks/upgrade.rake
+++ b/lib/tasks/upgrade.rake
@@ -49,7 +49,11 @@ namespace :upgrade do
bulletin.email_sentdate = announcement["email_sentdate"]
bulletin.other_mailaddress = announcement["other_mailaddress"]
bulletin.public = announcement["public"]
+ bulletin.postdate = announcement["postdate"]
+ bulletin.deadline = announcement["deadline"]
bulletin.subtitle_translations = announcement["subtitle"]
+ announcement["text"]["en"] = smart_downloader(announcement["text"]["en"], args.url.chomp("/"))
+ announcement["text"]["zh_tw"] = smart_downloader(announcement["text"]["zh_tw"], args.url.chomp("/"))
bulletin.text_translations = announcement["text"]
bulletin.title_translations = announcement["title"]
bulletin.remote_image_url = announcement["image"]
@@ -84,4 +88,33 @@ namespace :upgrade do
puts "Import has some problem."
end
end
-end
\ No newline at end of file
+end
+
+def smart_downloader(data,url)
+ @data = data
+ @user = User.where(:user_name => "rulingcom").first
+ excluded_extensions = ["php","/"]
+ regex = /https?:\/\/[\S]+/
+ # @links = URI.extract(@data) rescue []
+ @links = @data.scan(regex) rescue []
+ @links = @links.map{|link| link.chomp("\"") if (link.include?url rescue false)}.reject{|link| link.nil?}.uniq
+ @links.each do |link|
+ link = link.gsub("\&\;","&")
+ temp = link.gsub(url,"")
+ extension = temp.split(".").last rescue nil
+ if (extension.nil? || excluded_extensions.include?(extension))
+ @data = @data.sub(link,"#")
+ else
+ a = Asset.new
+ a.remote_data_url = link
+ a.title_translations = {"en" => a.data.filename, "zh_tw" => a.data.filename}
+ if (a.save! rescue false)
+ @user.assets << a
+ @user.save
+ link = link.gsub("&","\&\;")
+ @data = @data.sub(link, a.data.url)
+ end
+ end
+ end
+ @data
+ end
\ No newline at end of file