Pivotal tracker story is not getting updated after code push - tfs

We had pivotal tracker integrated with GitHub and when we used to commit with story id, it used to update the story with a commit message update story status.
We recently migrated to Team Foundation Server from GitHub and that integration is not working anymore.
Looks like there is no integration App exists yet.
Is there a programmatic way of doing it?

Create file named pre-push (without any extension) and put it under ./.git/hooks/ folder inside your repo. This folder should already exist if it's a valid repo. Copy paste following code in the file. Don't forget to replace the API token value in the following code -
#!/usr/bin/env ruby
# encoding: UTF-8
require 'net/https'
require 'json'
class GitLogs
attr_accessor :raw_log, :commit_data, :commit, :author, :message, :refs
def initialize
self.commit = 'Commit: ' + `git log -1 --pretty=format:%h`.force_encoding('utf-8')
self.author = 'Author: ' + `git log -1 --pretty=format:%aN`.force_encoding('utf-8')
self.message = 'Message: ' + `git log -1 --pretty=format:%s`.force_encoding('utf-8')
self.refs = 'Refs: ' + `git log -1 --pretty=format:%d`.force_encoding('utf-8')
# Example git formatted log output:
#
# Commit: 8872e8fe03a10238d7be84d78813874d79ce0c3d
# Author: John Doe <john.doe#unknown.com>
# Message: [#90743834] test new v5 hook addition
# Refs: (HEAD, feature/hook-test)
parse!
self
end
def parse!
self.commit_data = GitLog.new(self.commit, self.author, self.message, self.refs)
end
def pivotal_sync!
Pivotal.new(commit_data).send! if commit_has_story_id?
end
def commit_has_story_id?
# somewhere between square brackets there has to be a hash followed by multiple digits
!commit_data.message.scan(/\[*+\#(\d+)\D?(.*)\]/).empty?
end
end
class GitLog
attr_accessor :hash, :author, :message, :refs
def initialize hash, author, message, refs
self.hash = hash
self.author = author
self.refs = refs
self.message = message
updated_message
end
def updated_message
return message
end
def to_json
{ source_commit:
{ commit_id: self.hash,
author: self.author,
message: self.message,
}
}.to_json
end
end
class Pivotal
attr_accessor :git_log, :tracker_token
BASE_URI = URI('https://www.pivotaltracker.com/')
def initialize git_log
self.git_log = git_log
self.tracker_token = get_token
end
def get_token
'YOUR APT TOKEN GOES HERE. CAN GET IT FROM https://www.pivotaltracker.com/profile'
end
def send!
https = Net::HTTP.start(BASE_URI.host, 443, {
use_ssl: true,
verify_mode: OpenSSL::SSL::VERIFY_NONE
})
request = Net::HTTP::Post.new('/services/v5/source_commits')
request['X-TrackerToken'] = tracker_token
request['Content-type'] = 'application/json'
request.body = git_log.to_json
response = https.request(request)
end
end
GitLogs.new().pivotal_sync!

Related

Rails Job loses reference to module randomly

EDIT: same things happens when I fork a process manually...
I'm getting some weird behavior with a Rails Job that calls a module of mine called RedisService.
I've added lib/modules to my autoload_paths but the TextService module that calls the RedisService one loses reference to it, sometimes immediately, sometimes 3 or 4 job calls in...
I've even required the module in my TextService to no avail, even added some puts to check that always show the module is defined and responds to the method I'm calling...!
Something escapes me...
Here's a gist to the backtrace
Repo: https://gitlab.com/thomasbromehead/snmp-simulator-ruby-manager.
ruby --version: 2.6.5
rails version: 6.1.3.1
My "service" objects:
Module that calls RedisService
require_relative 'redis_service'
module TextService
def self.write_to_file(dataObject, redis, path: "./")
begin
file_with_path = path + dataObject.filename
# Store all lines prior to the one being modified, File.read closes the file
f = File.read(file_with_path)
new_content = f.gsub(dataObject.old_set_value, dataObject.new_set_value)
# File.open closes the file when passed a block
File.open(file_with_path, "w") { |file| file.puts new_content }
puts "Redis is: #{redis}" ======> RedisService
puts "Redis responds to multi: #{redis.respond_to?(:multi)}" ======> true
redis.multi do
redis.zrem("#{dataObject.name}-sorted-set", dataObject.old_set_value)
redis.hset("#{dataObject.name}-offsets", "#{dataObject.start_index}:#{dataObject.oid}:#{dataObject.end_index}", dataObject.new_set_value)
redis.zadd("#{dataObject.name}-sorted-set", dataObject.start_index, dataObject.new_set_value)
end
rescue EOFError
end
end
Variation class called from VariateJob
require_relative '../../../lib/modules/redis_service'
module Snmp
class Variation
include ActiveModel::Model
attr_reader :oid, :type, :duration, :to, :from, :filename, :redis
def initialize(oid:nil, duration:nil, type:nil, to:nil, filename: nil, from:nil)
#to = to
#from = from
#oid = oid
#type = type
#filename = filename
#redis = RedisService
end
def run(data)
current_value, new_set_value, start_index, end_index = prepare_values(JSON.parse(data))
transferData = Snmp::TransferData.new({
filename: #filename,
old_set_value: current_value,
new_set_value: new_set_value,
start_index: start_index,
end_index: end_index,
name: #name,
oid: oid
})
TextService.write_to_file(transferData, #redis)
end
VariateJob
class VariateJob < ApplicationJob
queue_as :default
def perform(dumped_variation, data)
Marshal.load(dumped_variation).run(Marshal.load(data))
end
end
VariationsController
class VariationsController < ApplicationController
before_action :set_file_name, only: :start
def start
if params["linear"]
type = :linear
elsif params["random"]
type = :random
end
data = redis.hscan_each("##name-offsets", match: "*:#{params["snmp_variation"]["oid"]}*")
# data is an Enumerator, transform it to an array and dump to JSON
variation = Snmp::Variation.new(params_to_keywords(params["snmp_variation"]).merge({type: type}))
VariateJob.perform_later(Marshal.dump(variation), Marshal.dump(JSON.generate(data.to_a.first)))
end
RedisService
require 'redis'
module RedisService
include GlobalID::Identification
[...]
def self.multi(&block)
#redis.multi { block.call() }
end
[...]
end
You are not losing the reference to the RedisService, but to Redis in your RedisService. Probably because you use a server or worker that forks new processes and you don't initialize a new connection after the fork.
To fix this issue I would replace this method
def self.start(host,port)
#redis ||= Redis.new(host: host, port: port)
self
end
with
def self.redis
#redis ||= Redis.new(host: ::Snmpapp.redis_config[:host], port: ::Snmpapp.redis_config[:port])
end
And then I would replace all call to the #redis with a redis call to the new method.

What could cause performance issue(s) when using roadie-rails for our case?

Originally posted as
https://github.com/Mange/roadie-rails/issues/75
We are seeing performance issue for our daily email jobs
By using NewRelic custom instrumentation,
we found out that most time is spent in calling Roadies
Screenshot of our NewRelic data for an example worker:
The integration code:
# frozen_string_literal: true
require "rails"
require "action_controller"
require "contracts"
require "memoist"
require "roadie"
require "roadie-rails"
require "new_relic/agent/method_tracer"
module Shared::MailerMixins
module WithRoadieIntegration
# I don't want to include the constants into the class as well
module Concern
def self.included(base)
base.extend ClassMethods
end
include ::NewRelic::Agent::MethodTracer
def mail(*args, &block)
super.tap do |m|
options = roadie_options
next unless options
trace_execution_scoped(
[
[
"WithRoadieIntegration",
"Roadie::Rails::MailInliner.new(m, options).execute",
].join("/"),
],
) do
Roadie::Rails::MailInliner.new(m, options).execute
end
end
end
private
def roadie_options
::Rails.application.config.roadie.tap do |options|
options.asset_providers = [UserAssetsProvider.new]
options.external_asset_providers = [UserAssetsProvider.new]
options.keep_uninlinable_css = false
options.url_options = url_options.slice(*[
:host,
:port,
:path,
:protocol,
:scheme,
])
end
end
add_method_tracer(
:roadie_options,
"WithRoadieIntegration/roadie_options",
)
end
class UserAssetsProvider
extend(
::Memoist,
)
include(
::Contracts::Core,
::Contracts::Builtin,
)
include ::NewRelic::Agent::MethodTracer
ABSOLUTE_ASSET_PATH_REGEXP = /\A#{Regexp.escape("//")}.+#{Regexp.escape("/assets/")}/i
Contract String => Maybe[Roadie::Stylesheet]
def find_stylesheet(name)
return nil unless file_exists?(name)
Roadie::Stylesheet.new("whatever", stylesheet_content(name))
end
add_method_tracer(
:find_stylesheet,
"UserAssetsProvider/find_stylesheet",
)
Contract String => Roadie::Stylesheet
def find_stylesheet!(name)
stylesheet = find_stylesheet(name)
if stylesheet.nil?
raise Roadie::CssNotFound.new(
name,
"does not exists",
self,
)
end
stylesheet
end
add_method_tracer(
:find_stylesheet!,
"UserAssetsProvider/find_stylesheet!",
)
private
def file_exists?(name)
if assets_precompiled?
File.exists?(local_file_path(name))
else
sprockets_asset(name)
end
end
memoize :file_exists?
# If on-the-fly asset compilation is disabled, we must be precompiling assets.
def assets_precompiled?
!Rails.configuration.assets.compile
rescue
false
end
def local_file_path(name)
asset_path = asset_path(name)
if asset_path.match(ABSOLUTE_ASSET_PATH_REGEXP)
asset_path.gsub!(ABSOLUTE_ASSET_PATH_REGEXP, "assets/")
end
File.join(Rails.public_path, asset_path)
end
memoize :local_file_path
add_method_tracer(
:local_file_path,
"UserAssetsProvider/local_file_path",
)
def sprockets_asset(name)
asset_path = asset_path(name)
if asset_path.match(ABSOLUTE_ASSET_PATH_REGEXP)
asset_path.gsub!(ABSOLUTE_ASSET_PATH_REGEXP, "")
end
# Strange thing is since rails 4.2
# name is passed in like
# `/assets/mailer-a9c96bd713d0b091297b82053ccd9155b933c00a53595812d755825d1747f42d.css`
# Before any processing
# And since `sprockets_asset` is used for preview
# We just "fix" the name by removing the
#
# Regexp taken from gem `asset_sync`
# https://github.com/AssetSync/asset_sync/blob/v1.2.1/lib/asset_sync/storage.rb#L142
#
# Modified to match what we need here (we need `.css` suffix)
if asset_path =~ /-[0-9a-fA-F]{32,}\.css$/
asset_path.gsub!(/-[0-9a-fA-F]{32,}\.css$/, ".css")
end
Rails.application.assets.find_asset(asset_path)
end
add_method_tracer(
:sprockets_asset,
"UserAssetsProvider/sprockets_asset",
)
def asset_path(name)
name.gsub(%r{^[/]?assets/}, "")
end
Contract String => String
def stylesheet_content(name)
if assets_precompiled?
File.read(local_file_path(name))
else
# This will compile and return the asset
sprockets_asset(name).to_s
end.strip
end
memoize :stylesheet_content
add_method_tracer(
:stylesheet_content,
"UserAssetsProvider/stylesheet_content",
)
end
end
end
I would like to report my own findings
With NewRelic data, we think most of the time is spent on
Roadies::Inliner/selector_elements => Roadie::Inliner/elements_matching_selector
And it seems a stylesheet with more style rules will make the style inlining takes longer
Benchmark code will be something like:
# frozen_string_literal: true
require "benchmark/ips"
class TestMailer < ::ActionMailer::Base
def show(benchmark_file_path:)
return mail(
from: "somewhere#test.com",
to: ["somewhere#test.com"],
subject: "some subject",
# This is trying to workaround a strange bug in `mail` gem
# https://github.com/mikel/mail/issues/912#issuecomment-156186383
content_type: "text/html",
) do |format|
format.html do
render(
file: benchmark_file_path,
layout: false,
)
end
end
end
end
Benchmark.ips do |x|
x.warmup = 5
x.time = 60
options = Roadie::Rails::Options.new(
# Use your own provider or use built-in providers
# I use a custom provider which can be used inside a rails app,
# See https://github.com/Mange/roadie for built-in providers
#
# options.asset_providers = [UserAssetsProvider.new]
# options.external_asset_providers = [UserAssetsProvider.new]
options.keep_uninlinable_css = false
)
# Need to prepare html_file yourself with
# different stylesheet tag pointing to two different stylesheet files
x.report("fat") do
message = ::TestMailer.
show(
benchmark_file_path: "benchmark-fat-stylesheet.html",
).message.tap do |m|
Roadie::Rails::MailInliner.new(m, options).execute
end
if message.body.to_s =~ /stylesheet/
raise "stylesheet not processed"
end
end
x.report("slim") do
message = ::TestMailer.
show(
benchmark_file_path: "benchmark-slim-stylesheet.html",
).message
if message.body.to_s =~ /stylesheet/
raise "stylesheet not processed"
end
end
# Compare the iterations per second of the various reports!
x.compare!
end

Ruby LoadError issue with 'require'

I have researched this for quite some time, and have yet to solve my issue. Here is the error that I am receiving:
C:/Ruby23/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in `require': cannot load such file -- nexpose-runner/constants (LoadError)
from C:/Ruby23/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in require'
from scan.rb:4:in `<main>'
Here is my code:
require 'nexpose'
require 'csv'
require 'json'
require 'nexpose-runner/constants'
require 'nexpose-runner/scan_run_description'
module NexposeRunner
module Scan
def Scan.start(options)
run_details = ScanRunDescription.new(options)
run_details.verify
nsc = get_new_nexpose_connection(run_details)
site = create_site(run_details, nsc)
start_scan(nsc, site, run_details)
reports = generate_reports(nsc, site, run_details)
verify_run(reports[0])
end
def self.generate_reports(nsc, site, run_details)
puts "Scan complete for #{run_details.site_name}, Generating Vulnerability Report"
vulnerbilities = generate_report(CONSTANTS::VULNERABILITY_REPORT_QUERY, site.id, nsc)
generate_csv(vulnerbilities, CONSTANTS::VULNERABILITY_REPORT_NAME)
puts "Scan complete for #{run_details.site_name}, Generating Vulnerability Detail Report"
vuln_details = generate_report(CONSTANTS:: VULNERABILITY_DETAIL_REPORT_QUERY, site.id, nsc)
generate_csv(vuln_details, CONSTANTS::VULNERABILITY_DETAIL_REPORT_NAME)
puts "Scan complete for #{run_details.site_name}, Generating Software Report"
software = generate_report(CONSTANTS::SOFTWARE_REPORT_QUERY, site.id, nsc)
generate_csv(software, CONSTANTS::SOFTWARE_REPORT_NAME)
puts "Scan complete for #{run_details.site_name}, Generating Policy Report"
policies = generate_report(CONSTANTS::POLICY_REPORT_QUERY, site.id, nsc)
generate_csv(policies, CONSTANTS::POLICY_REPORT_NAME)
puts "Scan complete for #{run_details.site_name}, Generating Audit Report"
generate_template_report(nsc, site.id, CONSTANTS::AUDIT_REPORT_FILE_NAME, CONSTANTS::AUDIT_REPORT_NAME, CONSTANTS::AUDIT_REPORT_FORMAT)
puts "Scan complete for #{run_details.site_name}, Generating Xml Report"
generate_template_report(nsc, site.id, CONSTANTS::XML_REPORT_FILE_NAME, CONSTANTS::XML_REPORT_NAME, CONSTANTS::XML_REPORT_FORMAT)
[vulnerbilities, software, policies]
end
def self.verify_run(vulnerabilities)
raise StandardError, CONSTANTS::VULNERABILITY_FOUND_MESSAGE if vulnerabilities.count > 0
end
def self.start_scan(nsc, site, run_details)
puts "Starting scan for #{run_details.site_name} using the #{run_details.scan_template} scan template"
scan = site.scan nsc
begin
sleep(3)
stats = nsc.scan_statistics(scan.id)
status = stats.status
puts "Current #{run_details.site_name} scan status: #{status.to_s} -- PENDING: #{stats.tasks.pending.to_s} ACTIVE: #{stats.tasks.active.to_s} COMPLETED #{stats.tasks.completed.to_s}"
end while status == Nexpose::Scan::Status::RUNNING
end
def self.create_site(run_details, nsc)
puts "Creating a nexpose site named #{run_details.site_name}"
site = Nexpose::Site.new run_details.site_name, run_details.scan_template
run_details.ip_addresses.each { |address|
site.add_ip address
}
if run_details.engine
site.engine = run_details.engine
end
site.save nsc
puts "Created site #{run_details.site_name} successfully with the following host(s) #{run_details.ip_addresses.join(', ')}"
site
end
def self.get_new_nexpose_connection(run_details)
nsc = Nexpose::Connection.new run_details.connection_url, run_details.username, run_details.password, run_details.port
nsc.login
puts 'Successfully logged into the Nexpose Server'
nsc
end
def self.generate_report(sql, site, nsc)
report = Nexpose::AdhocReportConfig.new(nil, 'sql')
report.add_filter('version', '1.3.0')
report.add_filter('query', sql)
report.add_filter('site', site)
report_output = report.generate(nsc)
CSV.parse(report_output.chomp, {:headers => :first_row})
end
def self.generate_template_report(nsc, site, file_name, report_name, report_format)
adhoc = Nexpose::AdhocReportConfig.new(report_name, report_format, site)
data = adhoc.generate(nsc)
File.open(file_name, 'w') { |file| file.write(data) }
end
def self.generate_csv(csv_output, name)
CSV.open(name, 'w') do |csv_file|
csv_file << csv_output.headers
csv_output.each do |row|
csv_file << row
if name == CONSTANTS::VULNERABILITY_REPORT_NAME
puts '--------------------------------------'
puts "IP: #{row[0]}"
puts "Vulnerability: #{row[1]}"
puts "Date Vulnerability was Published: #{row[2]}"
puts "Severity: #{row[3]}"
puts "Summary: #{row[4]}"
puts '--------------------------------------'
end
end
end
end
end
end
In the command prompt, I am entering in the following code to run it (this file is called scan.rb):
ruby scan.rb "http://localhost:3780" "username" "password" "3780" "webpage" "ip-address" "full-audit-widget-corp"
So far, I've tried changing require to require_relative, as well as re-arranging the paths (like putting the whole path, for example). Neither has worked.
I also made sure to have the Ruby Development Kit installed.
Thanks!
please check the local gem list: gem list --local

Ruby on Rails, Zendesk API integration not loading the client

I am trying to set up the Zendesk API in my app, I have decided to go with the API that was built by Zendesk
I have set up the initializer object to load the client.
config/initializers/zendesk.rb
require 'zendesk_api'
client = ZendeskAPI::Client.new do |config|
# Mandatory:
config.url = Rails.application.secrets[:zendesk][:url]
# Basic / Token Authentication
config.username = Rails.application.secrets[:zendesk][:username]
config.token = Rails.application.secrets[:zendesk][:token]
# Optional:
# Retry uses middleware to notify the user
# when hitting the rate limit, sleep automatically,
# then retry the request.
config.retry = true
# Logger prints to STDERR by default, to e.g. print to stdout:
require 'logger'
config.logger = Logger.new(STDOUT)
# Changes Faraday adapter
# config.adapter = :patron
# Merged with the default client options hash
# config.client_options = { :ssl => false }
# When getting the error 'hostname does not match the server certificate'
# use the API at https://yoursubdomain.zendesk.com/api/v2
end
This is pretty much copy paste from the site, but I have decided on using the token + username combination.
I then created a service object that I pass a JSON object and have it construct tickets. This service object is called from a controller.
app/services/zendesk_notifier.rb
class ZendeskNotifier
attr_reader :data
def initialize(data)
#data = data
end
def create_ticket
options = {:comment => { :value => data[:reasons] }, :priority => "urgent" }
if for_operations?
options[:subject] = "Ops to get additional info for CC"
options[:requester] = { :email => 'originations#testing1.com' }
elsif school_in_usa_or_canada?
options[:subject] = "SRM to communicate with student"
options[:requester] = { :email => 'srm#testing2.com' }
else
options[:subject] = "SRM to communicate with student"
options[:requester] = { :email => 'srm_row#testing3.com' }
end
ZendeskAPI::Ticket.create!(client, options)
end
private
def for_operations?
data[:delegate] == 1
end
def school_in_usa_or_canada?
data[:campus_country] == "US" || "CA"
end
end
But now I am getting
NameError - undefined local variable or method `client' for #<ZendeskNotifier:0x007fdc7e5882b8>:
app/services/zendesk_notifier.rb:20:in `create_ticket'
app/controllers/review_queue_applications_controller.rb:46:in `post_review'
I thought that the client was the same one defined in my config initializer. Somehow I think this is a different object now. I have tried looking at their documentation for more information but I am lost as to what this is?
If you want to use the client that is defined in the initializer you would need to make it global by changing it to $client. Currently you have it setup as a local variable.
I used a slightly different way of initializing the client, copying from this example rails app using the standard Zendesk API gem:
https://github.com/devarispbrown/zendesk_help_rails/blob/master/app/controllers/application_controller.rb
As danielrsmith noted, the client variable is out of scope. You could instead have an initializer like this:
config/initializers/zendesk_client.rb:
class ZendeskClient < ZendeskAPI::Client
def self.instance
#instance ||= new do |config|
config.url = Rails.application.secrets[:zendesk][:url]
config.username = Rails.application.secrets[:zendesk][:username]
config.token = Rails.application.secrets[:zendesk][:token]
config.retry = true
config.logger = Logger.new(STDOUT)
end
end
end
Then return the client elsewhere by client = ZendeskClient.instance (abridged for brevity):
app/services/zendesk_notifier.rb:
class ZendeskNotifier
attr_reader :data
def initialize(data)
#data = data
#client = ZendeskClient.instance
end
def create_ticket
options = {:comment => { :value => data[:reasons] }, :priority => "urgent" }
...
ZendeskAPI::Ticket.create!(#client, options)
end
...
end
Hope this helps.

JRuby Oracle connection failing

I am following a tutorial to establish ojdbc connection in JRuby so that I can execute some SQL statements. But it is failing to connect to the database. Below are the steps:
Copied ojdbc6.jar under working directory where the ruby files reside.
Created oracle_connection.rb file
Create test_connection.rb file as the driver class
oracle_connection.rb
require 'java'
require 'ojdbc6.jar'
java_import 'oracle.jdbc.OracleDriver'
java_import 'java.sql.DriverManager'
class OracleConnection
#conn = nil
#user = nil
#pwd = nil
def initialize(user, pwd, url)
#user = user
#pwd = pwd
#url = url
#Load driver class
ora_driver = OracleDriver.new
DriverManager.registerDriver ora_driver
#conn = DriverManager.get_connection url, user, pwd
#conn.auto_commit = false
end
#Add getters and setters for all attributes we wish to expose
attr_reader :user, :pwd, :url, :connection
def close_connection()
#conn.close() unless #conn
end
def prepare_call(call)
#conn.prepare_call call
end
def create_statement()
#conn.create_statement
end
def prepare_statement(sql)
#conn.prepare_statement sql
end
def commit()
#conn.commit
end
def to_s
"OracleConnection [user=#{#user}, url=#{#url}]"
end
alias_method :to_string, :to_s
end
#test_connection.rb
require 'oracle_connection'
#Edit these for your database schema
user = "ABC"
pwd = "EFG"
url = "jdbc:oracle:thin:#host_name:1520/db_instance"
print "Run at #{Time.now} using JRuby #{RUBY_VERSION}\n\n"
begin
conn = OracleConnection.new.create(user, pwd, url)
puts conn, "\n"
end
print "\nEnded at #{Time.now}\n"
While running test_connection.rb, I see the below error:
ruby test_connection.rb
Run at 2013-09-16 10:11:05 -0700 using JRuby 1.9.2
NoMethodError: undefined method `create' for OracleConnection:Class
(root) at test_connection.rb:11
I don't know what is causing the problem. Guidance on this is really appreciated. Thanks!
In "test_connection.rb" I was calling "create" method whereas in OracleConnection class "create" method is not defined. Hence it was failing.
Replacing conn = OracleConnection.new.create(user, pwd, url) with conn = OracleConnection.new(user, pwd, url) fixes the issue.
Below I am re-writing the working test_connection.rb
#test_connection.rb
require 'oracle_connection'
#Edit these for your database schema
user = "ABC"
pwd = "EFG"
url = "jdbc:oracle:thin:#host_name:1520/db_instance"
print "Run at #{Time.now} using JRuby #{RUBY_VERSION}\n\n"
begin
conn = OracleConnection.new(user, pwd, url)
puts conn, "\n"
end
print "\nEnded at #{Time.now}\n"

Resources