text:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>FindClosestFacilitiesParameters</title>
<meta name="date" content="2015-01-13" />
<link rel="stylesheet" type="text/css" href="../../../../stylesheet.css" title="Style" />

 <meta name="generator" content="Adobe RoboHelp 10" />

概述
软件包
 类
树
已过时
索引
帮助

 上一个类   下一个类
    无框架     所有类

摘要: 嵌套 | 字段 | 构造方法 | 方法
详细信息: 字段 | 构造方法 | 方法

com.supermap.android.networkAnalyst

类 FindClosestFacilitiesParameters<T>

java.lang.Object
  com.supermap.android.networkAnalyst.FindClosestFacilitiesParameters<T>

所有已实现的接口:

java.io.Serializable

public class FindClosestFacilitiesParameters<T>

extends java.lang.Object

implements java.io.Serializable

最近设施分析参数类。

该类用于设置最近设施分析(FindClosestFacilitiesService)所需的参数。如:事件点、设施点、交通网络通用参数、分析半径等。

另请参见:

序列化表格

字段摘要

 T
event

           获取或设置事件点,一般为需要获得服务的事件位置,必设字段。

 int
expectFacilityCount

           获取或设置期望返回的最近设施个数。

 T[]
facilities

           获取或设置设施点集合,一般为提供服务的服务设施位置,必设字段。

 boolean
fromEvent

           获取或设置是否从事件点到设施点进行查找,默认值为 false。

 double
maxWeight

           获取或设置查找半径。

 TransportationAnalystParameter
parameter

           获取或设置交通网络分析通用参数。

构造方法摘要

FindClosestFacilitiesParameters()

           构造函数。

方法摘要

从类 java.lang.Object 继承的方法

clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

字段详细信息

event

public T event

获取或设置事件点,一般为需要获得服务的事件位置,必设字段。 可以通过两种方式赋予:事件点 ID号和事件点坐标(Point2D类型)。

expectFacilityCount

public int expectFacilityCount

获取或设置期望返回的最近设施个数。默认值为 1。

facilities

public T[] facilities

获取或设置设施点集合,一般为提供服务的服务设施位置,必设字段。 可以通过两种方式赋予:设施施点ID号集合和设施点坐标(Point2D类型)集合。

fromEvent

public boolean fromEvent

获取或设置是否从事件点到设施点进行查找,默认值为 false。 最近设施分析主要是通过设施点和事件点之间最优的路线来分析在一定范围内哪个或哪些设施与事件点有最优路线的关系。这个行走线路是通过网络图层进行网络分析算法计算出来的两点间的最优路线。由于存在从 A 点到 B 点与从 B 点到 A 点的耗费不一样的情况,因此起止点不同可能会得到不同的最优路线。因此在进行最近设施分析之前,需要设置获取的最优路线的方向,即是以事件点作为起点到最近设施点的方向分析,还是以最近设施点为起点到事件点的方向分析。如果需要以事件点作为起点到设施点方向进行查找,设置该字段值为 true;默认为 false,表示从设施点到事件点进行查找。

maxWeight

public double maxWeight

获取或设置查找半径。单位与该类中 parameter 字段(交通网络分析通用参数)中设置的权重字段一致。默认值为0,表示查找全网络。 例如事件发生点是一起交通事故,要求查找在10分钟内能到达的最近医院,超过10分钟能到达的都不予考虑。那么需要将属中 parameter 的 weightFieldName 设置为表示时间的权重字段,然后设置查找范围的半径值为 10。

parameter

public TransportationAnalystParameter parameter

获取或设置交通网络分析通用参数。用于设置障碍边、障碍点、权重字段、转向权重字段、分析结果内容等信息。

构造方法详细信息

FindClosestFacilitiesParameters

public FindClosestFacilitiesParameters()

构造函数。

概述
软件包
 类
树
已过时
索引
帮助

 上一个类   下一个类
    无框架     所有类

摘要: 嵌套 | 字段 | 构造方法 | 方法
详细信息: 字段 | 构造方法 | 方法


text:
{!admin-only.md!}

By default, any user can find and view the email address of any other
user. Organization administrators can restrict access so that only admins
can view other users' email addresses.

### Restrict visibility of email addresses

{start_tabs}

{settings_tab|organization-permissions}

2. Under **Organization permissions**, configure **Who can access user email addresses**.

{!save-changes.md!}

{end_tabs}

## Caveats

There are a few places in the app where Zulip shows fake email addresses (like
`Ada Starr <user1234@example.zulipchat.com>`) rather than just `Ada Starr`. This might
cause some confusion for users. The fake email addresses do not work, and
email sent to those addresses will bounce.

## Related articles

* [Moderating open organizations](/help/moderating-open-organizations)

redpajama_set_name: RedPajamaGithub


text:
namespace {

const char* kUserIDHash = "deadbeef";

#if defined(OS_CHROMEOS)
const char* kRelativeToDriveRoot = "/home/";
#endif

}  // namespace

class DownloadDirPolicyHandlerTest
    : public policy::ConfigurationPolicyPrefStoreTest {
 public:
  void SetUp() override {
    recommended_store_ = new policy::ConfigurationPolicyPrefStore(
        nullptr, policy_service_.get(), &handler_list_,
        policy::POLICY_LEVEL_RECOMMENDED);
    handler_list_.AddHandler(
        base::WrapUnique<policy::ConfigurationPolicyHandler>(
            new DownloadDirPolicyHandler));
  }

  void PopulatePolicyHandlerParameters(
      policy::PolicyHandlerParameters* parameters) override {
    parameters->user_id_hash = kUserIDHash;
  }

 protected:
  scoped_refptr<policy::ConfigurationPolicyPrefStore> recommended_store_;
};

TEST_F(DownloadDirPolicyHandlerTest, SetDownloadDirectory) {
  policy::PolicyMap policy;
  EXPECT_FALSE(store_->GetValue(prefs::kPromptForDownload, NULL));
  policy.Set(policy::key::kDownloadDirectory, policy::POLICY_LEVEL_MANDATORY,
             policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD,
             base::Value(std::string()), nullptr);
  UpdateProviderPolicy(policy);

  // Setting a DownloadDirectory should disable the PromptForDownload pref.
  const base::Value* value = NULL;
  EXPECT_TRUE(store_->GetValue(prefs::kPromptForDownload, &value));
  ASSERT_TRUE(value);
  ASSERT_TRUE(value->is_bool());
  EXPECT_FALSE(value->GetBool());
}

#if defined(OS_CHROMEOS)
TEST_F(DownloadDirPolicyHandlerTest, SetDownloadToDrive) {
  EXPECT_FALSE(store_->GetValue(prefs::kPromptForDownload, NULL));

  policy::PolicyMap policy;
  policy.Set(policy::key::kDownloadDirectory, policy::POLICY_LEVEL_MANDATORY,
             policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD,
             base::Value(download_dir_util::kDriveNamePolicyVariableName),
             nullptr);
  UpdateProviderPolicy(policy);

  const base::Value* value = NULL;
  EXPECT_TRUE(store_->GetValue(prefs::kPromptForDownload, &value));
  ASSERT_TRUE(value);
  ASSERT_TRUE(value->is_bool());
  EXPECT_FALSE(value->GetBool());

#if BUILDFLAG(IS_CHROMEOS_ASH)
  EXPECT_TRUE(store_->GetValue(drive::prefs::kDisableDrive, &value));
  ASSERT_TRUE(value);
  ASSERT_TRUE(value->is_bool());
  EXPECT_FALSE(value->GetBool());
#endif

  std::string download_directory;
  EXPECT_TRUE(store_->GetValue(prefs::kDownloadDefaultDirectory, &value));
  ASSERT_TRUE(value);
  EXPECT_TRUE(value->GetAsString(&download_directory));
  EXPECT_EQ(download_dir_util::kDriveNamePolicyVariableName,
            download_directory);

  policy.Set(policy::key::kDownloadDirectory, policy::POLICY_LEVEL_MANDATORY,
             policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD,
             base::Value(kUserIDHash), nullptr);
  UpdateProviderPolicy(policy);
  EXPECT_FALSE(recommended_store_->GetValue(drive::prefs::kDisableDrive, NULL));

  policy.Set(
      policy::key::kDownloadDirectory, policy::POLICY_LEVEL_RECOMMENDED,
      policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD,
      base::Value(std::string(download_dir_util::kDriveNamePolicyVariableName) +
                  kRelativeToDriveRoot),
      nullptr);
  UpdateProviderPolicy(policy);

  EXPECT_FALSE(recommended_store_->GetValue(prefs::kPromptForDownload, NULL));
  EXPECT_FALSE(recommended_store_->GetValue(drive::prefs::kDisableDrive, NULL));

  EXPECT_TRUE(
      recommended_store_->GetValue(prefs::kDownloadDefaultDirectory, &value));
  ASSERT_TRUE(value);
  EXPECT_TRUE(value->GetAsString(&download_directory));
  EXPECT_EQ(std::string(download_dir_util::kDriveNamePolicyVariableName) +
                kRelativeToDriveRoot,
            download_directory);

  policy.Set(policy::key::kDownloadDirectory, policy::POLICY_LEVEL_RECOMMENDED,
             policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD,
             base::Value(kUserIDHash), nullptr);
  UpdateProviderPolicy(policy);

  EXPECT_FALSE(recommended_store_->GetValue(prefs::kPromptForDownload, NULL));
  EXPECT_FALSE(recommended_store_->GetValue(drive::prefs::kDisableDrive, NULL));

  EXPECT_TRUE(
      recommended_store_->GetValue(prefs::kDownloadDefaultDirectory, &value));
  ASSERT_TRUE(value);
  EXPECT_TRUE(value->GetAsString(&download_directory));
  EXPECT_EQ(kUserIDHash, download_directory);
}
#endif


text:
module.exports = function(config) {
  config.set({

    // base path that will be used to resolve all patterns (eg. files, exclude)
    basePath: './',

    // frameworks to use
    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
    frameworks: ['mocha', 'chai', 'sinon', 'chai-sinon'],

    // list of files / patterns to load in the browser
    files: [
        /* LIB SCRIPTS */
        "public/dist/js/base.min.js",
        // "public/libs/jquery/dist/jquery.js",
        // "public/libs/angular/angular.js",
        "public/libs/angular-mocks/angular-mocks.js",
        // "public/libs/angular-animate/angular-animate.js",
        // "public/libs/angular-ui-router/release/angular-ui-router.js",

        /* APP SCRIPTS */
        "public/dist/js/app.js",

        /* SPEC HELPERS */
        "public/app/tests/mockData.js",
        "public/app/tests/specHelper.js",

        /* SPECS */
        "public/app/tests/specs/**/*.spec.js",
    ],

    // list of files to exclude
    exclude: [

    ],

    // preprocess matching files before serving them to the browser
    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
    preprocessors: {

    },

    // test results reporter to use
    // possible values: 'dots', 'progress'
    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
    reporters: ['spec'],

    // web server port
    port: 9876,

    // enable / disable colors in the output (reporters and logs)
    colors: true,

    // level of logging
    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_INFO,

    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,

    // start these browsers
    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
    browsers: [
        'PhantomJS'
        // , 'Chrome'
        // , 'Firefox'
        // , 'Safari'
    ],

    // Continuous Integration mode
    // if true, Karma captures browsers, runs the tests and exits
    singleRun: false
  });
};


text:
To run the example, simply type **mvn verify** from this directory, or **mvn -PnoServer verify** if you want to start and create the broker manually.

This example shows you how JMS resources such as connections, sessions and consumers in JMS 2 can be automatically closed on error.

In this instance we auto close a connection after a subsequent call to a JMS producer send fails.


text:
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Graphics.Urho3D.Graphics.Animation(
    Animation
  , AnimationChannel(..)
  , AnimationChannelFlags
  , AnimationKeyFrame(..)
  , HasTime(..)
  , HasPosition(..)
  , HasRotation(..)
  , HasScale(..)
  , VectorAnimationKeyFrame
  , vectorAnimationKeyFrameCntx
  , AnimationTrack(..)
  , HasName(..)
  , HasChannelMask(..)
  , HasKeyFrames(..)
  , AnimationTriggerPoint(..)
  , animationContext
  , SharedAnimation
  , HashMapStringHashAnimationTrack
  , channelPosition
  , channelRotation
  , channelScale
  , animationSetAnimationName
  , animationSetLength
  , animationCreateTrack
  , animationRemoveTrack
  , animationRemoveAllTracks
  , animationSetTrigger
  , animationAddTrigger
  , animationAddTrigger'
  , animationRemoveTrigger
  , animationRemoveAllTriggers
  , animationSetNumTriggers
  , animationGetAnimationName
  , animationGetAnimationNameHash
  , animationGetLength
  , animationGetTracks
  , animationGetNumTracks
  , AnimationGetTrack(..)
  , animationGetTriggers
  , animationGetNumTriggers
  , animationGetTrigger
  ) where

import qualified Language.C.Inline as C
import qualified Language.C.Inline.Cpp as C

import Graphics.Urho3D.Graphics.Internal.Animation
import Graphics.Urho3D.Container.FlagSet
import Graphics.Urho3D.Container.ForeignVector
import Graphics.Urho3D.Container.HashMap
import Graphics.Urho3D.Container.Ptr
import Graphics.Urho3D.Container.Vector
import Graphics.Urho3D.Creatable
import Graphics.Urho3D.Core.Context
import Graphics.Urho3D.Monad
import Data.Monoid
import Data.Typeable
import Foreign
import Foreign.C.String
import Text.RawString.QQ

import Graphics.Urho3D.Resource.Resource
import Graphics.Urho3D.Core.Object
import Graphics.Urho3D.Core.Variant
import Graphics.Urho3D.Parent
import Graphics.Urho3D.Math.Vector3
import Graphics.Urho3D.Math.Quaternion
import Graphics.Urho3D.Math.StringHash
import qualified Data.HashMap.Strict as H
import qualified Data.Vector as V
import Data.Maybe

C.context (C.cppCtx <> C.funConstCtx
  <> sharedAnimationPtrCntx
  <> vectorAnimationKeyFrameCntx
  <> hashMapStringHashAnimationTrackCntx
  <> animationCntx
  <> resourceContext
  <> objectContext
  <> contextContext
  <> vector3Context
  <> quaternionContext
  <> stringHashContext
  <> variantContext)

C.include "<Urho3D/Graphics/Animation.h>"
C.using "namespace Urho3D"

C.verbatim [r|
template <class T>
class Traits
{
public:
    struct AlignmentFinder
    {
      char a;
      T b;
    };

    enum {AlignmentOf = sizeof(AlignmentFinder) - sizeof(T)};
};
|]

C.verbatim "typedef Vector<AnimationKeyFrame> VectorAnimationKeyFrame;"

simpleVector "AnimationKeyFrame"
hashMapPOD "StringHash" "AnimationTrack"

animationContext :: C.Context
animationContext = animationCntx <> resourceContext <> sharedAnimationPtrCntx <> hashMapStringHashAnimationTrackCntx <> vectorAnimationKeyFrameCntx

instance Creatable (Ptr Animation) where
  type CreationOptions (Ptr Animation) = Ptr Context

  newObject ptr = liftIO [C.exp| Animation* { new Animation($(Context* ptr)) } |]
  deleteObject ptr = liftIO [C.exp| void { delete $(Animation* ptr) } |]

sharedPtr "Animation"
deriveParents [''Object, ''Resource] ''Animation

instance ResourceType Animation where
  resourceType _ = StringHash . fromIntegral $ [C.pure| unsigned int { Animation::GetTypeStatic().Value() } |]

instance Storable AnimationKeyFrame where
  sizeOf _ = fromIntegral $ [C.pure| int { (int)sizeof(AnimationKeyFrame) } |]
  alignment _ = fromIntegral $ [C.pure| int { (int)Traits<AnimationKeyFrame>::AlignmentOf } |]
  peek ptr = do
    _animationKeyFrameTime  <- realToFrac <$> [C.exp| float {$(AnimationKeyFrame* ptr)->time_} |]
    _animationKeyFramePosition <- peek =<< [C.exp| Vector3* {&$(AnimationKeyFrame* ptr)->position_} |]
    _animationKeyFrameRotation <- peek =<< [C.exp| Quaternion* {&$(AnimationKeyFrame* ptr)->rotation_} |]
    _animationKeyFrameScale <- peek =<< [C.exp| Vector3* {&$(AnimationKeyFrame* ptr)->scale_} |]
    return AnimationKeyFrame {..}
  poke ptr (AnimationKeyFrame {..}) =
    with _animationKeyFramePosition $ \_animationKeyFramePosition' ->
    with _animationKeyFrameRotation $ \_animationKeyFrameRotation' ->
    with _animationKeyFrameScale $ \_animationKeyFrameScale' ->
      [C.block| void {
        $(AnimationKeyFrame* ptr)->time_ = $(float _animationKeyFrameTime');
        $(AnimationKeyFrame* ptr)->position_ = *$(Vector3* _animationKeyFramePosition');
        $(AnimationKeyFrame* ptr)->rotation_ = *$(Quaternion* _animationKeyFrameRotation');
        $(AnimationKeyFrame* ptr)->scale_ = *$(Vector3* _animationKeyFrameScale');
      } |]
    where
    _animationKeyFrameTime' = realToFrac _animationKeyFrameTime

instance Storable AnimationTrack where
  sizeOf _ = fromIntegral $ [C.pure| int { (int)sizeof(AnimationTrack) } |]
  alignment _ = fromIntegral $ [C.pure| int { (int)Traits<AnimationTrack>::AlignmentOf } |]
  peek ptr = do
    _animationTrackName <- peekCString =<< [C.exp| const char* {$(AnimationTrack* ptr)->name_.CString()} |]
    _animationTrackNameHash <- peek =<< [C.exp| StringHash* {&$(AnimationTrack* ptr)->nameHash_} |]
    _animationTrackChannelMask <- FlagSet . fromIntegral <$> [C.exp| unsigned char {(unsigned char)$(AnimationTrack* ptr)->channelMask_} |]
    _animationTrackKeyFrames <- peekForeignVectorAs =<< [C.exp| VectorAnimationKeyFrame* {&$(AnimationTrack* ptr)->keyFrames_} |]
    return AnimationTrack {..}
  poke ptr (AnimationTrack {..}) =
    withCString _animationTrackName $ \_animationTrackName' ->
      with _animationTrackNameHash $ \_animationTrackHashName' ->
        withForeignVector () _animationTrackKeyFrames $ \_animationTrackKeyFrames' ->
        [C.block| void {
          $(AnimationTrack* ptr)->name_ = String($(const char* _animationTrackName'));
          $(AnimationTrack* ptr)->nameHash_ = *$(StringHash* _animationTrackHashName');
          $(AnimationTrack* ptr)->channelMask_ = AnimationChannelFlags($(unsigned char _animationTrackChannelMask'));
          $(AnimationTrack* ptr)->keyFrames_ = VectorAnimationKeyFrame(*$(VectorAnimationKeyFrame* _animationTrackKeyFrames'));
        } |]
    where
    _animationTrackChannelMask' = fromIntegral . unFlagSet $ _animationTrackChannelMask

instance (Typeable a, VariantStorable a) => Storable (AnimationTriggerPoint a) where
  sizeOf _ = fromIntegral $ [C.pure| int { (int)sizeof(AnimationTriggerPoint) } |]
  alignment _ = fromIntegral $ [C.pure| int { (int)Traits<AnimationTriggerPoint>::AlignmentOf } |]
  peek ptr = do
    let ptr' = castPtr ptr
    _animationTriggerPointTime <- realToFrac <$> [C.exp| float {$(AnimationTriggerPoint* ptr')->time_} |]
    _animationTriggerPointTriggerData <- getVariantOrError =<< [C.exp| Variant* {&$(AnimationTriggerPoint* ptr')->data_} |]
    return AnimationTriggerPoint {..}
  poke ptr (AnimationTriggerPoint {..}) =
    withVariant _animationTriggerPointTriggerData $ \_animationTriggerPointTriggerData' ->
    [C.block| void {
      $(AnimationTriggerPoint* ptr')->time_ = $(float _animationTriggerPointTime');
      $(AnimationTriggerPoint* ptr')->data_ = *$(Variant* _animationTriggerPointTriggerData');
    } |]
    where
    _animationTriggerPointTime' = realToFrac _animationTriggerPointTime
    ptr' = castPtr ptr

C.verbatim "typedef Vector<AnimationTriggerPoint> VectorAnimationTriggerPoint;"

instance Creatable (Ptr VectorAnimationTriggerPoint) where
  type CreationOptions (Ptr VectorAnimationTriggerPoint) = ()
  newObject _ = liftIO [C.exp| VectorAnimationTriggerPoint* {new VectorAnimationTriggerPoint() } |]
  deleteObject ptr = liftIO [C.exp| void { delete $(VectorAnimationTriggerPoint* ptr) } |]

instance ReadableVector VectorAnimationTriggerPoint where
  type ReadVecElem VectorAnimationTriggerPoint = Ptr AnimationTriggerPointImpl
  foreignVectorLength ptr = liftIO $ fromIntegral <$> [C.exp| int {$(VectorAnimationTriggerPoint* ptr)->Size() } |]
  foreignVectorElement ptr i = liftIO $ [C.exp| AnimationTriggerPoint* { &((*$(VectorAnimationTriggerPoint* ptr))[$(unsigned int i')]) } |]
    where i' = fromIntegral i

instance WriteableVector VectorAnimationTriggerPoint where
  type WriteVecElem VectorAnimationTriggerPoint = Ptr AnimationTriggerPointImpl
  foreignVectorAppend ptr e = liftIO $ [C.exp| void {$(VectorAnimationTriggerPoint* ptr)->Push(*$(AnimationTriggerPoint* e)) } |]

-- | Helper to avoid throwing bad typing in 'peek'
peekTriggerPoint :: (Typeable a, VariantStorable a, MonadIO m)
  => Ptr AnimationTriggerPointImpl
  -> m (Maybe (AnimationTriggerPoint a))
peekTriggerPoint ptr = liftIO $ do
  let ptr' = castPtr ptr
  _animationTriggerPointTime <- realToFrac <$> [C.exp| float {$(AnimationTriggerPoint* ptr')->time_} |]
  md <- getVariant =<< [C.exp| Variant* {&$(AnimationTriggerPoint* ptr')->data_} |]
  case md of
    Nothing -> return Nothing
    Just _animationTriggerPointTriggerData -> return $ Just AnimationTriggerPoint {..}

instance Functor AnimationTriggerPoint where
  fmap f tr = tr { _animationTriggerPointTriggerData = f $ _animationTriggerPointTriggerData tr}

channelPosition :: Word8
channelPosition = fromIntegral [C.pure| unsigned char {CHANNEL_POSITION} |]

channelRotation :: Word8
channelRotation = fromIntegral [C.pure| unsigned char {CHANNEL_ROTATION} |]

channelScale :: Word8
channelScale = fromIntegral [C.pure| unsigned char {CHANNEL_SCALE} |]

-- | Set animation name.
animationSetAnimationName :: (Parent Animation a, Pointer p a, MonadIO m)
  => p -- ^ Pointer to Animation or ascentor
  -> String -- ^ name
  -> m ()
animationSetAnimationName p n = liftIO $ withCString n $ \n' -> do
  let ptr = parentPointer p
  [C.exp| void {$(Animation* ptr)->SetAnimationName(String($(const char* n')))} |]

-- | Set animation length.
animationSetLength :: (Parent Animation a, Pointer p a, MonadIO m)
  => p -- ^ Pointer to Animation or ascentor
  -> Float -- ^ length
  -> m ()
animationSetLength p l = liftIO $ do
  let ptr = parentPointer p
      l' = realToFrac l
  [C.exp| void {$(Animation* ptr)->SetLength($(float l'))} |]

-- | Create and return a track by name. If track by same name already exists, returns the existing.
animationCreateTrack :: (Parent Animation a, Pointer p a, MonadIO m)
  => p -- ^ Pointer to Animation or ascentor
  -> String -- ^ name
  -> m (Ptr AnimationTrack)
animationCreateTrack p n = liftIO $ withCString n $ \n' -> do
  let ptr = parentPointer p
  [C.exp| AnimationTrack* {$(Animation* ptr)->CreateTrack(String($(const char* n')))} |]

-- | Remove a track by name. Return true if was found and removed successfully. This is unsafe if the animation is currently used in playback.
animationRemoveTrack :: (Parent Animation a, Pointer p a, MonadIO m)
  => p -- ^ Pointer to Animation or ascentor
  -> String -- ^ name
  -> m ()
animationRemoveTrack p n = liftIO $ withCString n $ \n' -> do
  let ptr = parentPointer p
  [C.exp| void {$(Animation* ptr)->RemoveTrack(String($(const char* n')))} |]

-- | Remove all tracks. This is unsafe if the animation is currently used in playback.
animationRemoveAllTracks :: (Parent Animation a, Pointer p a, MonadIO m)
  => p -- ^ Pointer to Animation or ascentor
  -> m ()
animationRemoveAllTracks p = liftIO $ do
  let ptr = parentPointer p
  [C.exp| void {$(Animation* ptr)->RemoveAllTracks()} |]

-- | Set a trigger point at index.
animationSetTrigger :: (Parent Animation a, Pointer p a, MonadIO m, Typeable b, VariantStorable b)
  => p -- ^ Pointer to Animation or ascentor
  -> Word -- ^ index
  -> AnimationTriggerPoint b -- ^ trigger
  -> m ()
animationSetTrigger p i tp = liftIO $ with tp $ \tp' -> do
  let ptr = parentPointer p
      i' = fromIntegral i
      tp'' = castPtr tp'
  [C.exp| void {$(Animation* ptr)->SetTrigger($(unsigned int i'), *$(AnimationTriggerPoint* tp''))} |]

-- | Add a trigger point.
animationAddTrigger :: (Parent Animation a, Pointer p a, MonadIO m, Typeable b, VariantStorable b)
  => p -- ^ Pointer to Animation or ascentor
  -> AnimationTriggerPoint b -- ^ trigger
  -> m ()
animationAddTrigger p tp = liftIO $ with tp $ \tp' -> do
  let ptr = parentPointer p
      tp'' = castPtr tp'
  [C.exp| void {$(Animation* ptr)->AddTrigger(*$(AnimationTriggerPoint* tp''))} |]

-- | Add a trigger point.
animationAddTrigger' :: (Parent Animation a, Pointer p a, MonadIO m, VariantStorable b)
  => p -- ^ Pointer to Animation or ascentor
  -> Float -- ^ time
  -> Bool -- ^ time is normalized
  -> b -- ^ data
  -> m ()
animationAddTrigger' p t n b = liftIO $ withVariant b $ \b' -> do
  let ptr = parentPointer p
      t' = realToFrac t
      n' = fromBool n
  [C.exp| void {$(Animation* ptr)->AddTrigger($(float t'), $(int n') != 0, *$(Variant* b'))} |]

-- | Remove a trigger point by index.
animationRemoveTrigger :: (Parent Animation a, Pointer p a, MonadIO m)
  => p -- ^ Pointer to Animation or ascentor
  -> Word -- ^ index
  -> m ()
animationRemoveTrigger p i = liftIO $ do
  let ptr = parentPointer p
      i' = fromIntegral i
  [C.exp| void {$(Animation* ptr)->RemoveTrigger($(unsigned int i'))} |]

-- | Remove all trigger points.
animationRemoveAllTriggers :: (Parent Animation a, Pointer p a, MonadIO m)
  => p -- ^ Pointer to Animation or ascentor
  -> m ()
animationRemoveAllTriggers p = liftIO $ do
  let ptr = parentPointer p
  [C.exp| void {$(Animation* ptr)->RemoveAllTriggers()} |]

-- | Resize trigger point vector.
animationSetNumTriggers :: (Parent Animation a, Pointer p a, MonadIO m)
  => p -- ^ Pointer to Animation or ascentor
  -> Word -- ^ num
  -> m ()
animationSetNumTriggers p n = liftIO $ do
  let ptr = parentPointer p
      n' = fromIntegral n
  [C.exp| void {$(Animation* ptr)->SetNumTriggers($(unsigned int n'))} |]

-- | Return animation name.
animationGetAnimationName :: (Parent Animation a, Pointer p a, MonadIO m)
  => p -- ^ Pointer to Animation or ascentor
  -> m String
animationGetAnimationName p = liftIO $ do
  let ptr = parentPointer p
  peekCString =<< [C.exp| const char* {$(Animation* ptr)->GetAnimationName().CString()} |]

-- | Return animation name hash.
animationGetAnimationNameHash :: (Parent Animation a, Pointer p a, MonadIO m)
  => p -- ^ Pointer to Animation or ascentor
  -> m StringHash
animationGetAnimationNameHash p = liftIO $ do
  let ptr = parentPointer p
  peek =<< [C.block| StringHash* {
    static StringHash h = $(Animation* ptr)->GetAnimationNameHash();
    return &h;
    } |]

-- | Return animation length.
animationGetLength :: (Parent Animation a, Pointer p a, MonadIO m)
  => p -- ^ Pointer to Animation or ascentor
  -> m Float
animationGetLength p = liftIO $ do
  let ptr = parentPointer p
  realToFrac <$> [C.exp| float {$(Animation* ptr)->GetLength()} |]

-- | Return all animation tracks.
animationGetTracks :: (Parent Animation a, Pointer p a, MonadIO m)
  => p -- ^ Pointer to Animation or ascentor
  -> m (H.HashMap StringHash AnimationTrack)
animationGetTracks p = liftIO $ do
  let ptr = parentPointer p
  peekForeignHashMap =<< [C.exp| const HashMapStringHashAnimationTrack* {&$(Animation* ptr)->GetTracks()} |]

-- | Return number of animation tracks.
animationGetNumTracks :: (Parent Animation a, Pointer p a, MonadIO m)
  => p -- ^ Pointer to Animation or ascentor
  -> m Word
animationGetNumTracks p = liftIO $ do
  let ptr = parentPointer p
  fromIntegral <$> [C.exp| unsigned int {$(Animation* ptr)->GetNumTracks()} |]

class AnimationGetTrack a where
  animationGetTrack :: (Parent Animation b, Pointer p b, MonadIO m)
    => p -- ^ Pointer to Animation or ascentor
    -> a -- ^ identification value
    -> m (Ptr AnimationTrack)

-- | Return animation track by name.
instance AnimationGetTrack String where
  animationGetTrack p s = liftIO $ withCString s $ \s' -> do
    let ptr = parentPointer p
    [C.exp| AnimationTrack* {$(Animation* ptr)->GetTrack(String($(const char* s')))} |]

-- | Return animation track by name hash.
instance AnimationGetTrack StringHash where
  animationGetTrack p s = liftIO $ with s $ \s' -> do
    let ptr = parentPointer p
    [C.exp| AnimationTrack* {$(Animation* ptr)->GetTrack(*$(StringHash* s'))} |]

-- | Return animation trigger points. Note: you need to have trigger points of single type, all bad typed values are filtered out.
animationGetTriggers :: (Parent Animation a, Pointer p a, MonadIO m, Typeable b, VariantStorable b)
  => p -- ^ Pointer to Animation or ascentor
  -> m (V.Vector (AnimationTriggerPoint b))
animationGetTriggers p = liftIO $ do
  let ptr = parentPointer p
  vtemp <- peekForeignVectorAs =<< [C.exp| const VectorAnimationTriggerPoint* {&$(Animation* ptr)->GetTriggers()} |]
  catMaybesVec <$> V.mapM peekTriggerPoint vtemp
  where
  catMaybesVec = V.map fromJust . V.filter isJust

-- | Return number of animation trigger points.
animationGetNumTriggers :: (Parent Animation a, Pointer p a, MonadIO m)
  => p -- ^ Pointer to Animation or ascentor
  -> m Word
animationGetNumTriggers p = liftIO $ do
  let ptr = parentPointer p
  fromIntegral <$> [C.exp| unsigned int {$(Animation* ptr)->GetNumTriggers()} |]

-- | Return a trigger point by index.
animationGetTrigger :: (Parent Animation a, Pointer p a, MonadIO m, Typeable b, VariantStorable b)
  => p -- ^ Pointer to Animation or ascentor
  -> Word -- ^ index
  -> m (Maybe (AnimationTriggerPoint b))
animationGetTrigger p i = liftIO $ do
  let ptr = parentPointer p
      i' = fromIntegral i
  tmp <- [C.exp| AnimationTriggerPoint* {$(Animation* ptr)->GetTrigger($(unsigned int i'))} |]
  join <$> checkNullPtr' tmp peekTriggerPoint


text:
layout: post
title: Curved Lines using SVG and JavaScript
date: 2016-03-01
comments: true
sitemap: false
---

This post deals with implementing an evenly curved line using SVG and
JavaScript. SVG supports quadratic and cubic bezier curves using the `C`, `S`
and `Q` path commands but those leave you with the calculation of the control
points.

## Calculating the control points

To obtain a consistent and even curve one needs to place the control points like
the following figure illustrates.

![Curved line control points](/media/curved-line.svg)

Given are the outer control points *A* and *D*, as the line starting and ending
points, as well as the curviness expressed by the degree *a*.

```
function curvedLine(Ax, Ay, Dx, Dy, a) {
```

*d* is the calculated distance between the outer control points.

```
  const d = Math.sqrt(Math.pow(Ax-Dx, 2) + Math.pow(Ay-Dy, 2));
```

*rad* is the radian measure of the degree *a*.

```
  const rad = a / 180.0 * 2.0 * Math.PI;
```

*r* is the distance from the outer to the inner control points.

```
  const r = (0.3 * d) / Math.cos(rad);
```

*theta* is the calculated angle of the line passing through both outer control
points in radian.

```
const theta = Math.atan2(Ay - Dy, Ax - Dx);
```

*aO* and *aD* are two angles in radian that are required to calculate the inner
control points.

```
  const aO = theta - rad + Math.PI,
        aD = theta + rad;
```

The inner control points *B* and *C*, respectively, are calculated based on the
line connecting the outer control points using the angle *a* and *r* as illustrated in the figure.

```
  const Bx = Ax + r*Math.cos(aO),
        By = Ay + r*Math.sin(aO),
        Cx = Dx + r*Math.cos(aD),
        Cy = Dy + r*Math.sin(aD);
```

Last but not least, the SVG path is built from the control points.

```
  return `M${Ax},${Ay} C${Bx},${By} ${Cx},${Cy} ${Dx},${Dy}`
}
```

## Using the function

You can use an SVG library like D3.js to use the function result in an SVG path.

```
let svg = d3.select("body").append("svg")
  .attr("width", 500)
  .attr("height", 200);

svg.append('path')
  .attr('stroke', '#000')
  .attr('fill', 'none')
  .attr('d', curvedLine(30, 160, 470, 160, 20));
```


text:
// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef VIRTIO_SOLO5NET_HPP
#define VIRTIO_SOLO5NET_HPP

#include <common>
#include <hw/pci_device.hpp>
#include <net/buffer_store.hpp>
#include <net/link_layer.hpp>
#include <net/ethernet/ethernet.hpp>
#include <delegate>
#include <deque>
#include <statman>

extern "C" {
#include <solo5.h>
}

class Solo5Net : public net::Link_layer<net::Ethernet> {
public:
  using Link          = net::Link_layer<net::Ethernet>;
  using Link_protocol = Link::Protocol;

  static std::unique_ptr<Nic> new_instance()
  {
    return std::make_unique<Solo5Net>();
  }

  /** Human readable name. */
  const char* driver_name() const override;

  /** Mac address. */
  const MAC::Addr& mac() const noexcept override {
    return mac_addr;
  }

  uint16_t MTU() const noexcept override
  { return 1500; }

  uint16_t packet_len() const noexcept {
    return sizeof(net::ethernet::Header) + MTU();
  }

  net::downstream create_physical_downstream() override
  { return {this, &Solo5Net::transmit}; }

  /** Linklayer input. Hooks into IP-stack bottom, w.DOWNSTREAM data.*/
  void transmit(net::Packet_ptr pckt);

  /** Constructor. @param pcidev an initialized PCI device. */
  Solo5Net();

  /** Space available in the transmit queue, in packets */
  size_t transmit_queue_available() override {
    return 1000; // any big random number for now
  }

  /** Number of incoming packets waiting in the RX-queue */
  size_t receive_queue_waiting() {
    return 0;
  }

  net::Packet_ptr create_packet(int) override;

  void move_to_this_cpu() override {};

  void deactivate() override;

  void flush() override {};

  void poll() override;

private:
  MAC::Addr mac_addr;
  std::unique_ptr<net::Packet> recv_packet();
  /** Stats */
  uint64_t& packets_rx_;
  uint64_t& packets_tx_;

  net::BufferStore bufstore_;

};

#endif


text:
Template.navigation.events({
  "click #logout": function(event, template){
     Meteor.logout(function(){

     });
  }
});


text:
<!DOCTYPE html>
<meta charset='utf-8'>
<title>Vibration API: cancel ongoing vibrate() with [0]</title>
<link rel='author' title='Intel' href='http://www.intel.com'>
<link rel='help' href='http://dev.w3.org/2009/dap/vibration/#vibration-interface'>
<meta name='flags' content='interact'>
<meta name='assert' content='If pattern contains a single entry with a value of 0, cancel the pre-existing instance of the processing vibration patterns algorithm'>

Description

  After hitting the button below, your device must vibrate for a short period of time (roughly one
  second). If it vibrates for a longer time (roughly five seconds, it should feel somewhat long) then
  the test has failed.

<button id='vib'>Vibrate!</button>


text:
<?php

/************************************************************************/
/* PHP-NUKE: Web Portal System                                          */
/* ===========================                                          */
/*                                                                      */
/* Copyright (c) 2001 by Francisco Burzi (fbc@mandrakesoft.com)         */
/* http://phpnuke.org                                                   */
/*                                                                      */
/* This program is free software. You can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 2 of the License.       */
/************************************************************************/

if (($radminsuper==1) OR ($radminsurvey==1)) {
    adminmenu("admin.php?op=create", ""._ADMPOLLS."", "newpoll.gif");
}

?>


text:
<!DOCTYPE html>

  <link href="http://gmpg.org/xfn/11" rel="profile">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta http-equiv="content-type" content="text/html; charset=utf-8">

  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1">

  <title>

      Ingenia o Programa · Otro blog más de otro programador cualquiera

  </title>

  <link rel="stylesheet" href="/public/css/poole.css">
  <link rel="stylesheet" href="/public/css/syntax.css">
  <link rel="stylesheet" href="/public/css/hyde.css">

  <link href='https://fonts.googleapis.com/css?family=PT+Sans:400,700,400italic' rel='stylesheet' type='text/css'>
  <link href='https://fonts.googleapis.com/css?family=Josefin+Slab:700,600,600italic' rel='stylesheet' type='text/css'>

  <link rel="apple-touch-icon-precomposed" sizes="144x144" href="/public/apple-touch-icon-144-precomposed.png">
                                 <link rel="shortcut icon" href="/public/favicon.ico">

  <link rel="alternate" type="application/rss+xml" title="RSS" href="/atom.xml">

          Ingenia o Programa

Blog sobre programación. Android y Java, Scala, C-family, (casi)todo tiene cabida. Y por supuesto Python, mucho Python.

            Acerca de

            Archivo

      GitHub
      Twitter
      Currently v0.3.0

© 2017. Some rights reserved.

        Valoración de la UOC: año 2

    28 Dec 2017

Introducción

Primer Semestre

Redes y aplicaciones de internet

Inteligencia artificial

Diseño de estructuras de datos

Minería de datos

Segundo Semestre

Representación del conocimiento

Autómatas y gramáticas

Aprendizaje computacional

Ingeniería de componentes de Software

Introducción

Cuando terminó mi primer año en la UOC hice un pequeño repaso de las asignaturas de las cuales me matriculé. El segundo año quise hacer lo mismo, pero por unas cosas o por otras lo fui retrasando. Como más vale tarde que nunca, aquí estamos de nuevo.

Así como el primer año disfruté la mayoría de asignaturas, incluso aquellas que a priori me interesaban menos, el segundo ha sido un poco más decepcionante. Y no precisamente por los temas tratados, sino fundamentalmente por por el enfoque de las mismas.

Primer Semestre

Redes y aplicaciones de internet

Temario

Unidad 1: Redes de ordenadores e Internet

Unidad 2: Aplicaciones de Internet

Unidad 3: Redes multimedia

Unidad 4: Principios de seguridad en aplicaciones de Internet

El temario es muy completo. Se tocan muchos palos, y aunque en teoría es difícil profundizar en todos, las PACs y las prácticas se emplean de forma, siempre en mi opinión, muy inteligente. Se busca que el alumno profundice sobre algunos temas en ambas, bien investigando sobre tecnologías en las PAC, bien aplicando o poniendo en marcha algunos de los servicios estudiados en la teoría.

Apuntes Muy buenos. Sobre todo, porque se da un libro, bastante bueno, sobre el tema. No se ve entero, pero tanto lo estudiado como algunos otros temas no incluidos en la asignatura están fantásticamente explicados.

También hay una serie de apuntes, sobre programación de sockets y arquitecturas web. No los he trabajado lo suficiente como para poder dar una opinión formada sobre ellos.

PACs Sencillas, teóricas, son tres, constan de diez preguntas cada una. Generalmente éstas son de dos tipos: bien resumen/explicación de conceptos vistos en teoría, bien para indagación sobre algún aspecto no tratado directamente en el libro. Muchas preguntas tienen respuesta abierta, y a poco que se trabajen es fácil conseguir una A en todas.

Prácticas Largas pero no difíciles, aunque hay que echarles horas. Muy interesantes, constan de varios apartados que permiten alcanzar una nota cada vez mayor. Esto es, si se responde correctamente el primer apartado se puede llegar a la C-, si también al segundo a la C+, etc.

Este año han sido muy diversas: programación de sockets en Java, programación de clientes y servidores también en Java (sencillos eso sí), analizar con wireshark el tráfico generado por aplicaciones de voip, poner en funcionamiento un servicio de streaming, usar pgp, etc.

Consultores Muy buenas ambas, tanto la consultora de teoría como la de laboratorio. Ha habido bastante actividad en los foros y han respondido siempre de forma rápida y clara. Se les observa un dominio de la materia, o al menos lo parece.

Exámenes Este año han cambiado el formato, y más que un examen es una especie de prueba de síntesis larga. Dejan el libro para hacerlo, y sirve de ayuda. Sí es cierto que si no tienes idea y has de buscar todas las respuestas en él posiblemente no te dé tiempo a acabar el examen, pero sí al menos a aprobarlo. En definitiva, sencillo.

Conclusión Muy buena asignatura. Lo dice una persona que tiene poco interés en estos temas. De hecho, podría decirse que, de todos los palos que se tocan en la carrera, es posiblemente el campo que menos me interesa. Y aún así la he disfrutado bastante.

Inteligencia artificial

Temario

Módulo 1: Qué es la inteligencia artificial

Módulo 2: Resolución de problemas y búsqueda

Módulo 3: Sistemas basados en conocimiento

Módulo 4: Incertidumbre y razonamiento aproximado

Módulo 5: Introducción a Lisp

Temario típico de esta asignatura, en principio es bastante amplio, incluyéndose algoritmos genéticos, reyes bayesianas, etc.

Apuntes Horribles. Por ahora, los peores que he tenido que estudiarme en la UOC. Duele mucho gastarse 75€ para esto, y más cuando por ese dinero podemos hacernos con la referencia de este campo. Están mal explicados, tienen innumerables fallos, el código que presenta en Lisp es lioso1... en definitiva, no hay por donde cogerlos.

La parte de redes bayesianas directamente no puede leerse, y nos dan un documento (ni recuerdo si era un ejemplo o teoría) para poder estudiarla. Supongo que en los años que llevan empleándose estos apuntes no ha habido tiempo para rehacer ese apartado.

PACs Sencillas, alguna extremadamente sencilla (la tercera, y en la que menos nota saqué). Al menos las dos primeras eran pequeños retos a los que había que dedicarles algunas horas. La segunda fue de hecho muy divertida, posiblemente el punto álgido del semestre. Consistía en hacer una búsqueda a\star* y comparar entre varios heurísticos.

Prácticas No hay.

Consultores Bueno, con bastante dominio del tema, muy dispuesto, animando a participar, y rápido y claro en las respuestas. De hecho, lo mejor de la asignatura.

Exámenes Prueba de síntesis, todas las preguntas basadas en las PAC salvo un apartado de una de ellas, en el que había que resolver un árbol minimax usando poda alfa-beta.

Conclusión La mayor decepción hasta ahora en mi experiencia en la UOC. Si piensas que  esta es una universidad de pinta y colorea, no será esta asignatura la que te haga cambiar de opinión. No es que quiera que sea un infierno, pero un poco de esfuerzo para aprobar sería deseable. Contadas de forma exacta, le dediqué 28 horas, y de las 28, 12 fueron a la PAC 2. Y no soy un tío especialmente inteligente. La asignatura es de seis créditos (como todas en el grado), lo que se traduce en 150 horas de trabajo. Creo que queda todo dicho.

Lo más extraño de todo es la no obligatoriedad de programar. Esto es, puedes pasar por la asignatura sin picar código, ya no en Lisp, sino en cualquier lenguaje. Y en este campo, y en una asignatura con un módulo de programación en un lenguaje concreto, se hace extraño. Me da la sensación que en el pasado sí era necesario, pero ante las quejas por suspensos, o por el trabajo extra que supone ponerse con un lenguaje tan distinto a C y Java como Lisp, decidieron correr un tupido velo.

En resumen, grandísimo chasco.

Diseño de estructuras de datos

Temario

Módulo 1: Tipos Abstractos de Datos

Módulo 2: Complejidad algorítmica

Módulo 3: Contenedores secuenciales

Módulo 4: Árboles

Módulo 5: Colas con prioridad

Módulo 6: El TAD Tabla

Módulo 7: Árboles de busca

Módulo 8: Grafos

Módulo 9: Bibliotecas de colecciones

Apuntes De los mejores que he tenido hasta ahora en la UOC. Cierto es que este tema está muy bien tratado en multitud de referencias, tanto en inglés como en español, pero estos apuntes merecen realmente la pena: bien explicados, amplios, tratan la mayor parte de las estructuras de datos que hay que conocer. Además se entrega la implementación de las estructuras a través de la plataforma web y, aunque son implementaciones un poco complejas y que no usan algunas de las características más modernas de Java , es en conjunto bastante completa y muy imaginativa en algunas de las soluciones que propone. Se nota el bagaje en C/C++ del autor de dicha implementación.

PACs Sencillas, cortas, sin mucha complicación, aunque a veces un poco abstractas y sin soluciones bien definidas. De hecho, en algunas de las soluciones propuestas por el equipo docente estaba bastante en desacuerdo.

Prácticas Compuesta de dos partes, la primera larga aunque no muy difícil, pero interesante. La segunda se hace en 2 horas si has hecho la primera. Pero la baremación era algo similar a 30/70, muy poca lógica.

Consultores Bien, sin destacar especialmente, correcto y cumplidor, respondía con brevedad y de forma bastante clara.

Exámenes No hay, solo evaluación continua.

Conclusión Asignatura clasicota donde las haya, es un must que me extraña que no sea obligatoria para todas las especialidades. Añadiría más programación, un examen, y poder optar por otro lenguaje que no fuese Java.

Minería de datos

Temario El temario es bastante amplio. No se practican todos los métodos y técnicas explicadas en los distintos módulos.

Módulo 1: El proceso de Minería de Datos.

Módulo 2: Preparación de datos.

Módulo 3: Clasificación: árboles de decisión.

Módulo 4: Clasificación: redes neuronales.

Módulo 5: Métodos de agregación.

Módulo 6: Reglas de asociación.

Módulo 7: Redes bayesianas.

Módulo 8: Evaluación de modelos.

Módulo 9: Caso de Estudio.

Apuntes

Bastante completos pero extremadamente teóricos, hay cierta desconexión entre lo que se pide en la asignatura2 y ellos.

PACs

Bastante interesantes. Son cinco, y salvo la primera, las otras cuatro siguen un formato similar: aplicar alguna técnica (la del módulo concreto que estemos practicando en dicha PAC) al conjunto de datos que se entrega.

No son ni mucho menos imposibles pero exigen tiempo, sino para aprobar, sí al menos para presentar conclusiones interesantes. Todas se realizan con R, pero con la ayuda del profesor en el foro y google se coge rápidamente el tono para poder realizarlas.

Prácticas

Una, menos guiada que las PAC, consiste en emplear un par de métodos a nuestra elección sobre un conjunto de datos en bruto, y sacar nuestras propias conclusiones.

Consultores

Bastante bueno, activo, animaba constantemente a participar.

Exámenes

No hay.

Conclusión

Muy recomendable, quizás demasiado sencilla. No implementaremos las técnicas que se estudian, como sí haremos en aprendizaje automático, sino que directamente las usaremos.

Como pero más importante, y aunque no específico de esta asignatura, la desconexión que hay entre ellas. Los temas aquí tratados se vuelven a ver en otras, y aunque el enfoque es muy distinto, podría aprovecharse el tiempo parar ver alguna otra técnica, o para profundizar más en las no repetidas.

Segundo Semestre

Representación del conocimiento

Asignatura incógnita. Como se puede ver a continuación, con el temario es bastante difícil saber qué se trata en la misma, sobretodo si es la primera vez que nos enfrentamos a estos temas.

Temario

Módulo 1: Introducción a la representación del conocimiento

Módulo 2: Ontologías y web semántica

Apuntes Bastante cortos, son más descriptivos que útiles. Hay que emplear mucho google para profundizar en los temas tratados en las PAC.

PACs Muy distintas entre sí. La primera versa sobre conceptos generales y esquemas de representación. Aquí se ve de forma muy superficial Prolog. Maravilloso. Aunque las preguntas eran sencillas y el código a desarrollar muy corto, disfruté mucho aprendiendo y poniendo en práctica lo estudiado.

La segunda trata sobre ontologias y web semántica, usándose protege. Lo puesto en práctica en esta PAC es posiblemente el conocimiento más único e independiente que he visto en toda la carrera. Cuando se empieza, todo es demasiado abstracto, pero ha medido que vas adentrándote todos los conceptos empiezan a tener sentido. Es realmente interesante.

Por último, en la última PAC se profundiza en los temas de la segunda práctica, empleando ahora JAVA y SPARQL para trabajar sobre ontologías. También muy interesante.

Prácticas No hay.

Consultores Muy bueno. Tanto las PAC que propone como su implicación hacen, de una asignatura a priori obligada para cumplir el expediente de la especialización, la que posiblemente sea la más interesante de la misma.

Exámenes No hay.

Conclusión Completamente recomendable. Si vuestra especialidad no es computación, deberíais cogerla como optativa.

Autómatas y gramáticas

Temario

Módulo 1: Alfabetos, palabras y lenguajes

Módulo 2: Autómatas finitos y lenguajes regulares

Módulo 3: Gramáticas incontextuales y autómatas con pila

Apuntes Bastante correctos y concretos. Este, al igual que diseño de estructuras de datos, es un tema muy clásico del que podemos encontrar mil referencias, MOOCs, etc, por si queremos profundizar o ver otros enfoques.

PACs Muy cortas y sencillas, la primera sobre módulo 1 y 2, la segunda sobre módulo 3. Aún así, me dejé la segunda para el último día, la lié por no haber estudiado y saqué mala nota. Y con el peso que tienen, y siendo solo dos, sacar menos de una A en cualquiera de las dos te baja mucho la media.

Prácticas No hay.

Consultores Bastante bueno, en la media de la UOC.

Exámenes Una de las mejores pruebas de síntesis. Muy similar a las PAC, larga (daba el tiempo justo para acabarla) y en cierta medida desafiante. Hay que controlar bien el temario para poder realizarla en la hora asignada.

Conclusión Interesante, bastante sencilla. El temario es el clásico de esta asignatura en cualquier universidad, quizás habría que meterse más en profundidad, se hace un poco corta.

Aprendizaje computacional

Temario

Módulo didáctico 1. Aprendizaje

1. Introducción

2. Extracción de características

3. Aprendizaje no supervisado

4. Aprendizaje supervisado

5. Representación del conocimiento y aprendizaje

Módulo didáctico 2. Agentes y sistemas multiagente

1. Agentes inteligentes

2. Sistemas multiagente

Apuntes No los recuerdo mucho, sinceramente los usé muy poco. Creo que no es lo mejor que puede decirse de ellos.

PACs Consistentes en desarrollar algoritmos a mano, útil para realmente entenderlos. Algo que me ha resultado sorprendente es que no se ha trabajo sobre aprendizaje supervisado.

Prácticas Bastante entretenida, consistió en implementar el algoritmo PAM. Posiblemente deberían realizarse dos, una sobre aprendizaje supervisado y otra (esta) sobre no supervisado, más si pensamos que no se realiza examen.

Consultores Muy bueno, aunque los temas que se dan son posiblemente los menos interesantes que pueden estudiarse en este campo. No tengo muy claro si esto es responsabilidad suya o del profesor responsable. Muy claro en sus respuestas.

Exámenes No hay.

Conclusión Hay que cogerla. Guste el tema o no, pocas cosas hay actualmente más de moda. Fácil, demasiado fácil, tónica general en las asignaturas de la especialidad de computación.

Ingeniería de componentes de Software

No voy a extenderme mucho. Me matriculé como optativa para ver algo de jee. Cuando estaba haciendo la segunda práctica, que consistía básicamente en coger código tanto de otras prácticas que se entregan como ejemplo como de los apuntes y hacerlo funcionar, sin tener muy claro qué es lo que estaba haciendo, decidí dejarla. Ni la necesitaba para completar el plan de estudios, ni me gustaba ni estaba aprendiendo mucho. Eso sí, posiblemente sea la asignatura más parecida el trabajo más realizada por los programadores en este país. Así que, aunque parezca contradictorio, recomiendo cogerla.

Para ser justos, mi conocimiento de Lisp/Clojure es escaso, y puede ser que el problema no sea el código, sino yo. ↩

Usar en R algunos de estos algoritmos para extraer conocimiento de los conjuntos de datos empleados en las prácticas. ↩

        Namedtuple en Python

    19 Feb 2017

Índice

Introducción

Opciones para almaceneamiento

Objetos

Diccionarios

Listas-tuplas

Tuplas con nombre

Resultados

Introducción

La programación orientada a objetos se basa en asociar en un mismo elemento (un objeto) tanto un estado como las operaciones asociadas a dicho estado. Como dice Martin Fowler:

In programming, the fundamental notion of an object is the bundling of data and behavior.

Como resultado de dichas operaciones podremos obtener, o bien el mismo objeto con distinto estado1, o bien un objeto distinto con el estado modificado. Obviamente habrá operaciones, como pueden ser imprimir u obtener el hash de un objeto, que no devuelvan ningún resultado o modifiquen el estado del objeto con el que estemos trabajando.

Es muy típico que, en ocasiones, lo único que nos interese sea tener una serie de datos dentro de un contenedor por estar relacionados entre sí. Para almacenar dichos datos podemos usar estructuras de datos. Si queremos acceder a ellos emplearemos formas distintas según la estructura: en el caso de que simplemente queramos almacenarlos en un contenedor secuencial (lista, vector, etc) usaremos los índices de los elementos.

Si por ejemplo queremos almacenar los datos de los nodos de un grafo, en los cuales almacenamos tanto un estado asociado a cada nodo, como un enlace al nodo que generó el nodo actual (el padre del nodo), la profundidad a la que se encuentra cada nodo en el grafo, y su coste, para acceder a sus elementos empleando índices haremos:

node = [state father d c]
node-state  = node[0]
node-father = node[1]
node-depth  = node[2]
node-cost   = node[3]

Esto tiene varios problemas:

necesitamos una estructura de datos que nos permita almacenar elementos de distinto tipo2; y

la forma de acceder a los elementos del nodo dista mucho de ser cómoda y/o legible.

Por estos motivos, es bastante común el uso de objetos3. Esta solución es tan habitual que en Kotlin tenemos el concepto de data class, las cuales simplemente sirven como almacén de datos heterogéneos. Incluso en Scala es bastante común el uso de case class únicamente con atributos, sin definir ningún método.

Pero esta solución no es (imo) correcta. Ni conceptualmente, ni a nivel de coste: tanto la creación de objetos como el acceso a sus atributos distan mucho de ser arbitrarias computacionalmente hablando, y son desde luego mucho más costosas que el acceso a las posiciones correlativas de una estructura de datos secuencial.

Sobre todo esto, la legibilidad y el rendimiento de las distintas opciones que encontramos en Python para el almecenamiento de los atributos de alguna entidad, es de lo que he venido a hablar hoy aquí. Para poder estudiar el tiempo de ejecución de cada una de las opciones, de las distintas herramientos que disponemos para medir el rendimiento emplearemos la más sencilla de todas, un decorador, en concreto el definido por la siguiente función:

def time_measurement_loop(f, times=100000):
    @wraps(f)
    def measure_time(*args, **kwargs):
        total_time = 0
        t_loop = sys.maxsize
        for idx in range(times):
            t1  = time.time()
            res = f(*args, **kwargs)
            t2  = time.time()
            t   = t2 - t1
            if t_loop > t:
                t_loop = t
            total_time += t
        print("-----------------------------")
        print("@time_measurement: [{}]".format(f.__name__))
        print("\t{} executions take {} s".format(times, total_time))
        print("\ttotal loops: {}".format(times))
        print("\tthe best loop takes {} s".format(t_loop))
        print("-----------------------------")

        return total_time

    return measure_time

def wrap(times):
    def deco(fn):
        return time_measurement_loop(fn, times)
    return deco

Opciones para almacenamiento heterogéneo

Vamos a hablar de algunas de las opciones más comunes que Python nos ofrece. Nos dejamos algunas, como por ejemplo crear una clase a partir de los struct de C, no por que no sea útil, sino porque jamás la he empleado. Tampoco tiene sentido emplear otras estructuras de datos secuenciales como deque, las cuales para este problema no nos aportan ventaja respecto a las listas o tuplas.

Objetos

Definamos primero la clase descrita anteriormente:

class Node(object):
    def __init__(self, state, father=None, depth=0, cost=0):
        self.__state = state
        self.__father = father
        self.__depth = depth
        self.__cost = cost

    @property
    def state(self):
        return self.__state

    @state.setter
    def state(self, value):
        self.__state = value

    # The other attributes will have also the same kind of getter/setter methods.
    ...

Aunque todos sabemos como, dejemos constancia de cómo crear un nodo y acceder a sus atributos:

node = Node((1, 2, 3, 4), Node(0, 0, 0), 1)
state, father, depth, cost = node.state, node.father, node.depth, node.cost
node == node.father
node.state = (4, 3, 2, 1)

Diccionarios

Otra opción que podemos emplear es un diccionario. Creo sinceramente que son el mayor hallazgo del lenguaje, y que su facilidad de creación y uso son de largo más sencillas que las de la estructura equivalente en cualquier otro lenguaje en los que tengo un mínimo de experiencia.

Para crear un nodo equivalente al anterior mediante la definición de una clase, crearemos un diccionario en el cual las claves serán los nombre de los atributos, y los valores obviamente los valores que tomará cada uno de ellos:

node = { "state": (1, 2, 3, 4),
         "father": {"state": (0, 0, 0, 0), "father": None, "depth": 0, "cost": 0},
         "depth": 1,
         "cost": 0}
state, father = node["state"], node["father"]
depth, cost = node["depth"], node["cost"]
node == node["father"]
node["state"] = (4, 3, 2, 1)

Esta opción, para este caso concreto, tiene serias desventajas:

la referencia al padre se pierde si reusamos el nombre del objeto en la creación de los nodos (si no tenemos que guardar referencia a otro elemento previo, no tendremos ningún problema);

es bastante más verbosa, y facilita mucho el cometer errores; y

si trabajamos con un ide o con algún plugin para facilitar la escritura de código, no tendremos ayuda a la hora de mostrar los elementos existentes.

Como ventaja... es más eficiente. Aunque en este caso no es útil (por el problema comentado de la reutilización de referencias), en otros casos será la estructura a elegir.

Listas-tuplas

Poco que explicar, la diferencia entre ambas (mutable/inmutable) nos hará cambiar la forma de trabajar, pero el acceso será igual:

node = [(1, 2, 3, 4), [(0, 0, 0, 0), None, 0, 0], 1, 0]
[state, father, depth, cost] = node
node == node[1]
node[0] = (4, 3, 2, 1)
# If we use tuples...
node = ((4, 3, 2, 1), node[1], node[2], node[3])

Las desventajas son parecidas a las del diccionario:

imposibilidad de llevar registro de nodos anteriores;

poca legibilidad a la hora acceder a los elementos; y

no poder disfrutar de las ventajas de entornos de desarrollo o plugins, por lo tanto mayor tendencia a cometer errores.

La ventaja, igual que con el diccionario, es la eficiencia. Si necesitamos reasignar valores a una tupla, como el proceso será crear una nueva con el mismo nombre a partir de la antigua con los valores modificados, será más eficiente la lista. En caso de no necesitar reasignar, será más eficiente la tupla. Podemos resumirlo diciendo que si en el primer caso optaremos pr la lista, y en el segundo por la tupla.

Tuplas con nombre

Las tuplas con nombre o namedtuple nos van a permitir acceder a los elementos almacenados en las mismas tanto con el índice como con el nombre de los campos. En este caso se empleará la  dot notation4 típica de la programación orientada a objetos, por lo que el código será muchísimo más legible.

Para trabajar con ellas, la importaremos del módulo correspondiente, y crearemos una especie de constructor que nos servirá para crearlas. A este constructor hemos de pasar tanto el nombre de la estructura (lo que vendría siendo el nombre de la clase) como los nombres de los campos por los cuales queremos acceder a las posiciones dentro de la tupla:

from collections import namedtuple

Node = namedtuple('Node', ['state', 'father', 'depth', 'cost'])
root = Node((), None, 0, 0)
node = Node((1), root, root.depth + 1, root[3] + 1)

Hemos visto como en efecto podemos acceder de ambas formas a los atributos. También, a la hora de crear las instancias, podemos emplear keywords:

node = Node(state=(1), father=root, depth=root.depth+1, cost=root.cost+1)

Como siempre en Python, una vez empleamos palabras clave hemos de emplearlas hasta el final. Esto es, podemos emplear campos posicionales hasta el momento en que empleamos keywords, momento a partir del cual estamos obligados a usar éstas. Por eso esto es correcto:

node = Node((1), root, depth=root.depth+1, cost=root.cost+1)

pero esto no:

node = Node(state=(1), father=root, root.depth+1, root.cost+1)

Para más información, nada mejor que la documentación del lenguaje.

Resultados

Para medir el rendimiento de cada estructura, vamos a emplear las siguientes funciones (adaptadas a cada una de las estructuras empleadas):

# With reassignment
@wrap(rep)
def class_way():
    node = Node((5, 6, 7, 8), root_node, root_node.depth + 1, root_node.cost + 1)
    node.state = tuple([e**5 for e in root_node.state])
    node == node.father

# Without reassignment
@wrap(rep)
def class_way():
    node = Node((5, 6, 7, 8), root_node, root_node.depth + 1, root_node.cost + 1)
    state = tuple([e**5 for e in root_node.state])
    node == node.father

Como una imagen vale más que mil palabras, en las siguientes podemos ver los resultados obtenidos al ejecutar el código presente en este notebook de ipython:

Vemos como, al haber reasignación, las tuplas con nombre tienen el peor comportamiento, con un rendimiento peor incluso que la solución empleando objetos. Aunque esto ocurre para un número elevado de repeticiones de la operación (aproximadamente a partir de 200000 operaciones). En este caso, tal y como dijimos, la lista tiene mejor comportamiento que la tupla, al requerir esta la creación de una nueva cada vez que queremos llevar a cabo un cambio en algún valor.

En cambio, cuando no hay reasignación, las tuplas con nombre trabajan mucho mejor que la solución empleando objetos y, aunque funcionan peor que diccionarios y estructuras secuenciales básicas, la mejora en la legibilidad hacen muy recomendable su uso.

Conclusión

He intentado con este artículo dar a conocer un elemento que, aunque goza de mucha publicidad (y artículos) en literatura anglosajona, no está tan presente en blogs en español.

Sinceramente recomiento su uso, la mejora en el rendimiento es enorme frente a objetos, y en aplicaciones de cálculo intensivo (por ejemplo en problemas de búsqueda, juegos o cálculo numérico), puede convertir un código inutilizable, por lento, en un programa aceptable. En mi caso, en la resolución en su momento del algoritmo minimax, supuso una mejora sustancial.

Podríamos discutir si, ante estados distintos (si tenemos distintos atributos), estamos ante el mismo objeto, o por contra estamos ante objetos distintos. De hecho, al comparar objetos, si definimos la función de igualdad como igualdad de sus atributos, obviamente estaremos ante objetos distintos. Obviamente me refiero aquí, por igualdad, a que la referencia es la misma, esto es, a que lo que almacenamos en el stack no varía, aunque sí lo hagan los datos en el heap. ↩

En python nos servirán tanto la lista como la tupla para este fin. En otros lenguajes, como Java o C, esto es bien imposible bien bastante costoso, con uso de arrays de punteros a void y conversión entre tipos cada vez que queremos acceder a algún valor.  ↩

Obviamente no en C, pero en él disponemos de los struct para este fin. ↩

Sinceramente no sé cómo traducir esta expresión. ↩

        Scala en Sublime Text (y dos)

    12 Dec 2016

Índice

Plugins para sublime:

Package Control

SublimeREPL

Origami

Ensime

Plugins para sbt:

Sbt coursier

Sbt ensime

Script

Instalación

Introducción

Escribí, en uno de mis primeros artículos, una explicación de qué paquetes empleaba para desarrollar en scala usando sublime. Desde entonces, y aunque no fue hace mucho, mi instalación ha cambiado bastante. Así que en este artículo voy a explicar qué empleo actualmente. Todo lo dicho aquí tiene su contrapartido tanto en atom como en emacs.

Aunque este último es para valientes, hay que reconocer que las funcionalidades de ensime sobre él són más y mejores. En su propia página se puede entrever simplemente ojeando los manuales de uso de cada aplicación con dicho paquete. Qué es ensime lo veremos un poco más adelante.

En atom, aunque las funcionalidades son similares, ensime tiene un mejor aspecto que en sublime: los errores se muestran en un popup (en sublime en la miniventana de estado), los errores están mejor marcados, etc. Hay una página de un desarrollador francés (no la tengo en favoritos, pero es fácil de encontrar) donde explica cuál es su flujo de trabajo y cuáles los paquetes que emplea con este editor: realmente consigue un entorno de desarrollo fantástico.

Pero aunque con sublime no queda tan molón, como siempre, su estabilidad, rapidez y ligereza le da un plus que ni atom ni emacs logran.

Package Control

Creo que no hace falta presentar este paquete, y que cualquiera que trabaje con sublime text lo tiene instalado. Pero por si acaso queda algún despistado, package control nos permite de forma muy sencilla (increíblemente sencilla), gestionar los paquetes (plugins) que tenemos en nuestra instalación de sublime. Añado aquí también la recomendación de instalar side bar enhancements tras aquél, paquete que nos permitirá gestionar la side bar de forma mucho más completa.

Package Control

Sublime REPL

Otro must, nos permite tener directamente una pestaña con un REPL1. De prácticamente cualquier cosa: bash, scala, ipython, etc. Si bien no es tan manejable como trabajar directamente con lo emulado (problemas para navegar por la historia y problemas de autocompletado por ejemplo), es cierto que para algunas cosas concretas viene muy bien que esté directamente en la misma ventana. Por ejemplo, es muy cómodo poder lanzar directamente el código que haya en una línea de código simplemente tecleando C-, l, o la región que seleccionemos con C-, s.

También nos permite tener un panel con sbt corriendo, muy útil para compilar, lanzar los autotest, ejecutar, etc. Aunque hay un plugin propio para ejecutar directamente sbt, los resultados son los mismos.

Aunque insisto, no puede compararse con trabajar directamente con la terminal.

Sublime REPL

Origami

Aunque sublime incorpora un gestor para particionar la ventana y que podamos mostrar varias pestañas a la vez con varias configuracions, origami nos permite hacerlo de forma más flexible y sencilla, permitiéndonos crear un layout debajo del que estamos trabajando, a la derecha, etc.

Origami

Ensime

La joya de la corona, nos va a permitir tener casi un IDE de scala en nuestra editor de textos. Es extremadamente amplio, os recomiendo encarecidamente que os metáis en su página para saber exactamente todo lo que puede hacer por vosotros, aquí (quiero decir yo) solo rascamos la superficie.

Además, nos descarga las dependencias y nos permite inspeccionar el código fuente tanto del núcleo de scala como de cualquier otra librería que empleemos.

Ensime

SBT Coursier

Bueno, no es que lo emplee, pero sé de su existencia. Permite, entre otras muchas cosas, que sbt descargue más rápido sus dependencias (código compilado para nuestro proyecto, no archivos fuente como hace sbt-sublime), al permitir conexiones en paralelo.

SBT Coursier

SBT Ensime

Nos va a crear el archivo de configuración de ensime que vamos a necesitar en sublime para poder trabajar correctamente.

Al final, nuestro archivo ~/.sbt/0.13/plugins/plugins.sbt ha de quedarnos tal que:

addSbtPlugin("com.orrsella" % "sbt-sublime" % "1.1.1")

if (sys.props("java.version").startsWith("1.6"))
  addSbtPlugin("org.ensime" % "sbt-ensime" % "1.0.0")
else
  addSbtPlugin("org.ensime" % "sbt-ensime" % "1.12.4")

Script

Anteriormente (hace más de un año), hablaba del plugin sbt-eclipse para crear una estructura de carpetas para el proyecto. Ya no lo empleo, ahora con un sencillo script resuelvo el problema y me creo un build.sbt para el proyecto con lo mínimo imprescindible.

mkdir -p src/main/resources
mkdir src/main/scala
mkdir src/main/java

mkdir -p src/test/resources
mkdir src/test/scala
mkdir src/test/java

mkdir lib
touch build.sbt

echo "libraryDependencies += \"org.scalactic\" %% \"scalactic\" % \"3.0.0\"" >> build.sbt
echo "libraryDependencies += \"org.scalatest\" %% \"scalatest\" % \"3.0.0\" % \"test\"" >> build.sbt

echo "lazy val commonSettings = Seq(" >> build.sbt
echo "  organization := \"iop.scala\"," >> build.sbt
echo "  version := \"0.1.0\"," >> build.sbt
echo "  scalaVersion := \"2.11.8\"" >> build.sbt
echo ")" >> build.sbt
echo "" >> build.sbt
echo "lazy val root = (project in file(\".\"))." >> build.sbt
echo "  settings(commonSettings: _*)." >> build.sbt
echo "  settings(" >> build.sbt
echo "    name := \"$1\"" >> build.sbt
echo ")" >> build.sbt

Las dependencias son las necesarias para poder realizar los test al código, y establecemos la versión del programa y de escala que consideremos oportuna. En mi caso, aunque actualmente scala va por la 2.12.1, pongo la que hay en los repositorios de Stretch, la 2.11.8, suficientemente actualizada como para emplearla.

Instalación

La verdad es que no hay que hacer nada especial. Solo un par de cosas:

Si empleamos una instalación de scala que no está en /usr/bin o /usr/local/bin, es decir, si descargamos de scala.org y colocamos en una carpeta del home, aunque la incluyamos en el PATH, tendremos que modificar el archivo de configuración de sublime repl, poniendo donde corresponda la ruta completa donde encontrar el binario.

Si lanzamos el launcher en sublime con C-S-p, no se abrirá. Hemos de lanzarlo de manera gráfica: Tools > SublimeREPL > scala > sublime scala. Lo mismo para el repl de sbt.

La primera vez que vayamos a trabajar con ensime, tendremos que, en la carpeta donde tengamos el build.sbt del proyecto (en la raíz del mismo), ejecutar en sbt lo siguiente:

$ sbt
> ensimeConfig

Así tendremos creado el archivo de configuración para ensime que comentamos anteriormente.
+ Y ya solo nos queda lanzar el servidor. Como siempre, C-S-p, y buscamos Ensime:start.

Para despistados Read, Eval, Print, Loop. ↩

        Valoración de la UOC: año 1

    29 Jul 2016

Índice

Introducción

Comparación con UNED

Primer semestre

Ingeniería del software

Estructura de computadores

Competencia comunicativa para profesionales de las TIC

Segundo semestre

Grafos y complejidad

Sistemas operativos

Gestión de proyectos

Diseño de bases de datos

Análisis y diseño con patrones

Introducción

Ahora que ya no está la sangre caliente creo que es buen momento para hacer balance de mi primer año en la UOC. No voy a hablar de mi deriva profesional de los últimos meses que me aleja más y más de la programación y me devuelvo a mis orígenes, lo que hizo que el final del segundo semestre se me hiciese un poco cuesta arriba, con bajada de notas en los trabajos entregados generalizada; en cambio intentaré hacer un pequeño análisis general de lo que me ha parecido, una pequeña comparación con mis otras experiencias universitarias (presencial y a distancia), qué veo bueno y qué mejorable de la UOC en general y de cada asignatura en particular.

Primero de todo, me encanta aprender, me encanta estudiar (que no empollar). Creo que es algo a tener en cuenta, no todo el mundo tiene la misma facilidad para dejar de verse una serie, leerse un libro, echarse unas cervezas o una partida, y ponerse delante de libros, apuntes, tabletas o libros electrónicos. Creo que hay que tener súper claro a qué estás dispuesto a renunciar y a qué no antes de empezar con una carrera a distancia. Como a mí no me supone en general mucho esfuerzo, el tiempo de estudio lo acabas encontrando de forma natural. Si te supone un suplicio, te costará dios y ayuda sacar horas de trabajo, y siempre tendrás excusas para evitarlo.

Segundo, me la pone morcillona la informática, lo he descubierto tarde, pero lo he descubierto. Empecé la carrera por aprovechar el tiempo y mejorar tanto conocimientos como currículum, pero aunque a día de hoy posiblemente no me sirva ya para esto último, seguiré con ella. Me gusta la carrera y me gusta el currículum de la misma que tienen en la UOC. Podría ser mejor, podría ser más avanzada en algunos aspectos, pero en general me parece súper interesante.

Comparación con UNED

1No he probado informática en la UNED2. Todo lo que leí al respecto no me gustaba. Conozco gente muy seria (pero mucho), que han programado toda la vida (más de quince años), con títulos universitarios muy valorados por lo general, que se han metido en la UNED por placer y salvo contadas asignaturas3 echan pestes de casi todas. No digo que la UOC sea distinta, pero ya la información que tenía de la UNED me tiró para atrás. Pero aún así voy a comparar... porque sí he estudiado en la UNED.

Tengo (soy muy friki) una carrera en stand-by hasta que termina esta: física. Y es una carrera maravillosa. Tengo un poco menos de 60 créditos aprobados (decidí no convalidar) de la misma, pero creo que son suficientes como para poder comparar. El sistema de la UNED es como era antiguamente la universidad presencial: tienes tus temarios (en algunos casos enormes, como en Métodos I, contrarrestado por ser bonita y tener un profesor cojonudo). Y tienes tus convocatorias. Y ya está. Hay pruebas durante el curso, pero salvo excepciones no son obligatorias. Todos sabemos que en ese caso al final te lo acabas dejando, y es un gran error porque se te acaba haciendo un mundo.

Pero no venía a hablar de mi libro, sino a comparar. Tal como lo veo, las ventajas de la UOC son:

PACs y prácticas. Fundamentales, te obligan a llevar todo muy trabajado, y cuando llegan los exámenes prácticamente te lo sabes todo. Creedme que es así. Grafos, cuando empecé a estudiar para el examen, y salvo los primeros temas, tenía muy frescos todos los algoritmos y conceptos de la asignatura.

Equipo docente. En la UOC hay consultores, personal contratado para gestionar un grupo (en el que te toca). Comparado con la UNED, y salvo honrosas excepciones (el equipo de Métodos I, II y III, la gente de Física Computacional II, y para de contar que yo recuerde), son infinitamente más dispuestos, atienden mejor y se preocupan de que la gente siga el ritmo. Las excepciones las hay, pero son (en mi caso lo han sido) muy pocas. Y según leí cuando me decidía entre una y otra, en la carrera de informática en la UNED pasa tres cuartos de lo mismo que en la de física.

Temarios. Son bastante modernos, y bastante completos. Salvo en grafos (penalizado porque han de dar una introducción a la combinatoria y se quedan un poco cortos en otros temas) y en ingeniería del software, los temas cubiertos no son pocos, y se cubran con una profundidad suficiente. En algunos casos, por ejemplo en procesos dentro de la asignatura de Sistemas Operativos, con más profundidad que en algunos libros de texto de bastante fama.

Libertad para matricularse de asignaturas generales (básicas y obligatorias) del primer y segundo semestre en cualquier momento. Es decir, puedes coger del segundo semestre de primer curso en el primer semestre de un año o viceversa (ojo, esto no pasa en la especialidad, hay que ver antes de plantearse la matrícula las asignaturas que se ofertan cada semestre). Esto facilita mucho la matrícula, sobretodo cuando tienes opciones de que te convaliden asignaturas y se te queda algún semestre algo cojo en cuanto a opciones de matrícula.

Pero no es oro todo lo que reluce, y nos encontramos con bastantes inconvenientes:

Precio. Bastante más cara que la UNED. Aunque en la UNED hay que sumar el impuesto revolucionario de los materiales (en mi opinión hechos por los profesores para sacarse un sobresueldo4), lo de pagar 80 euros por los materiales de cada asignatura en la UOC es vergonzoso. Con ese dinero se puede comprar cualquier libro puntero del campo que corresponde a la asignatura. Y en algunos casos es especialmente sangrante. Estoy pensando en Análisis y diseño con patrones ~~y en Redes e internet, la cual cursaré el año que viene y, como no nos envíen algún libro (que va a ser que no) es como para cortarse las venas~~5.

Catalán. Yo no tengo ningún problema, pero hay gente que sí, y aunque puedes tener los apuntes en castellano, la política de la universidad es la que es y en los foros el lenguaje a emplear por los profesores es el que es. Piénsalo mucho porque puede suponer un problema. Según he podido ver en la web, están intentando implantar un sistema para hacer este tema más llevadero. Hay que reconocerles que al menos intentan modificar y mejorar.

Traducción de nombres a catalán (supongo que en castellano también en el caso de los apuntes en esa lengua). En serio, objecte compost? Hay más casos que eran sangrantes y no recuerdo en concreto, pero joder, toda la terminología en este campo se usa en inglés.

No hay septiembre. Lo que viene significando que, en cuanto no entregas una práctica, ya sabes que te toca volverte a matricular al año siguiente. En asignaturas como sistemas operativos o diseño de bases de datos, al mes y medio de clases más del 30% de los alumnos de mi grupo ya sabían que les tocaba volver a pagar.

Compañeros. Una queja que supongo que también podría hacerse en la UNED. El perfil del estudiante de este carrera supongo que debe ser gente que ha hecho un grado superior de FP y quiere sacarse el título universitario. Y muchos me da la sensación que no tienen mucha pasión por esto de programar6, además tienen trabajo y no tienen tiempo para florituras. Así se ve poca participación en foros para aportar cosas distintas o para responder a los compañeros, no se plantean actividades extra, etc. En grafos propuse crear un hilo para que la gente compartiese sus implementaciones de los algoritmos y las comentásemos, el profesor creó una carpeta específica, puse un par de implementaciones (en python y fsharp, para ver si la gente se picaba)... y murió. Me sentí súper frustrado sinceramente.

Voy a hablar por fin de las asignaturas que cogí, de qué me han parecido, virtudes, defectos, etc. Intentaré usar en todas una estructura similar.

Primer Semestre

Ingenieria del software

Temario En la web podemos ver que sus contenidos son:

Módulo 1: Introducción a la ingeniería del software

Módulo 2: Orientación a objetos

Módulo 3: Requisitos

Módulo 4: Análisis UML

Se queda un poco corto. Se echan en falta algunos temas sobre testeo, cobertura, integración, etc, que creo que no se tocan salvo en las asignaturas más aplicadas de la especialidad homónima.

Apuntes Sencillos, van al grano. Poca explicación y pocos ejemplos prácticos de cualquier otro diagrama que no sea el diagrama de clases.

PACs Muy fáciles, no puedo decir otra cosa. Hay un par de debates bastantes interesantes entre compañeros sobre casos prácticos que propone el equipo docente.

Prácticas Sencillas, creo recordar que más largas que las PAC (lo habitual en cualquier asignatura).

Consultor7 Muy bueno, muy dispuesto a ayudar, dio un listado de bibliografía comentada muy interesante.

Exámenes Muy sencillo, casos muy parecidos a los de las PAC, algo más cortos en su desarrollo.

Conclusión Asignatura interesante pero demasiado sencilla, se queda corta de material. Se complementa con programación orientada a objetos (la cual tengo convalidada). Lo más importante de la asignatura, los diagramas de clases dentro del análisis UML, se machaca bastante en otras asignaturas de la carrera (herramienta fundamental en diseño de bases de datos y en análisis con patrones), así que es mejor trabajarlos bien en esta y ampliar en la medida de lo posible, puesto que aquí no se pasan con el nivel de exigencia.

Estructura de computadores

Temario

Módulo 1: El computador

Módulo 2: Juego de instrucciones

Módulo 3: El procesador

Módulo 4: Sistema de memoria

Módulo 5: Sistemas de E/S

Módulo 6: Programación en ensamblador

Módulo 7: Arquitectura CISCA

Temario muy completo, muy interesante. Por mi eliminaría la arquitectura CISCA (una arquitectura con la que se trabaja a nivel teórico para eliminar ciertas complicaciones de x86) y trabajaría siempre con ensamblador, pero es solo mi opinión.

Apuntes Muy buenos, completos, bastante trabajados, bien explicados... no tengo queja la verdad.

PACs Fáciles, creo que la segunda fue bastante larga. Hay que trabajar antes los temas que se preguntan para que no se hagan muy cuesta arriba.

Prácticas Divertidísima, consistió en desarrollar el juego de 2048 en ensamblador. Muy larga pero no muy difícil puesto que teníamos el código en C y la mayor parte de la práctica consiste en traducirlo, pero al final de tanto trabajarla te sientes muy cómodo y aprendes bastante bien como se trabaja a este nivel, como se pasan valores por registro, por pila, como devolver valores, control de flujo, invocar a otras funciones, etc. La forma de puntuar es muy buena puesto que al ser tan larga, mucha gente no puede llegar a la primera entrega y para la segunda se les permite entregar lo que había que entregar en la primera, con penalización en la puntuación, pero al menos no te encuentras suspendido al primer mes del curso como pasa en otras asignaturas.

Consultor Bueno, amable, atento, tiempo de respuesta adecuado, nada que objetar.

Exámenes Sencillo si has trabajado, son preguntas similares a las de las PAC. Si no has practicado mucho es bastante fácil fallar en pequeños detalles.

Conclusión Asignatura fantástica, del primer semestre que hice la mejor. Si no fuese porque me interesan como optativas asignaturas de la especialidad de ingeniería del software, me cogería sin dudarlo como optativas las asignaturas que continúan a ésta (arquitectura de computadores y arquitectura avanzada de computadores).

Competencia comunicativa para profesionales de las TIC

Temario

Módulo 1. Competencia comunicativa y producción de textos.

Módulo 2. Los textos de las tecnologías de la información y de la comunicación: caracterización y aspectos de adecuación.

Módulo 3. Técnicas de producción de textos especializados I: aspectos de coherencia.

Módulo 4. Técnicas de producción de textos especializados II: léxico y aspectos de cohesión.

Módulo 5. Técnicas de producción de textos especializados III: puntuación y aspectos formales.

Módulo de síntesis. El proceso de producción de textos.

Apuntes Bastante completos, bien explicados y con bastantes ejemplos.

PACs Fáciles, llevan bastante trabajo.

Prácticas Iguales que las PAC.

Consultor Poco que decir, prácticamente no miré el foro en todo el semestre.

Exámenes Aquí se funciona bien con examen si no has pasado las prácticas, bien con prueba de síntesis (examen corto básicamente) si las has pasado. Este fue mi último caso.

Conclusión Asignatura para saber cómo redactar, puede ser interesante pero a mi sinceramente no me lo pareció. Mi nota más baja con mucho de este año, hay que entregar en catalán los ejercicios y aunque soy bilingüe hablándolo, escribiendo ya es harina de otro costal (desde COU que no lo escribía). Para gente únicamente castellanohablante supongo que puede llegar a ser frustrante.

Segundo Semestre

Grafos y complejidad

Temario

Módulo 1. Conceptos previos: funciones y algoritmos

Módulo 2. Fundamentos de grafos

Módulo 3. Recorridos y conectividad

Módulo 4. Árboles

Módulo 5. Grafos eulerianos y grafos hamiltonianos

Módulo 6. Complejidad computacional

Módulo 7. Problemas intratables

Se queda un poco corto en el tema de los grafos y los problemas intratables por el hecho de tener que meter el primero de conceptos previos, y porque al final la asignatura es un poco cajón desastre. Aún así todos y cada uno de los temas merecen la pena.

Apuntes Bastante buenos, pecan de traducir ciertos términos que uno está más que acostumbrado a leer en inglés. Además de los apuntes los profesores dan un pdf con ejercicios de exámenes de años anteriores, con lo que hay material más que de sobra para practicar.

PACs Complicadas, nada que objetar. No son obligatorias y solamente pueden subir la nota. En algunos problemas llegas a calentarte bastante la cabeza. Algún enunciado deja un poco que desear en su redacción (no queda muy claro qué se pide o qué condiciones se tienen), pero nada importante.

Prácticas No hay.

Consultor Muy bueno, muy atento, animando continuamente a la gente a participar.

Exámenes Fácil, metí un par de gambazos por tener prisa en irme, pero fue un regalo.

Conclusión Asignatura muy interesante, fundamental para programación (estructuras de datos) e informática teórica, es la base de asignaturas futuras y de la especialidad de computación.

Sistemas operativos

Temario

Módulo 1: Introducción a los sistemas operativos

Módulo 2: El sistema operativo: una máquina virtual

Módulo 3: La gestión de la memoria

Módulo 4: Entrada/salida

Módulo 5: El sistema de ficheros

Módulo 6: La gestión de procesos

Módulo 7: Comunicación y sincronización

Muy completo, algunos temas, en especial el sexto, bastante densos y exigentes. Ese tema y el último (concurrencia) están muy bien explicados.

Apuntes Muy buenos. Aún con esas, los 80 euros siguen siendo abusivos (por eso la indignación en aquellas asignaturas que directamente son pésimos). Y más cuando hay cosas tan buenas como el Operating Systems: Three Easy Pieces completamente gratuitas.

PACs Sencillas, largas, se ve un poquito de bash. Algunas preguntas no están demasiado bien formuladas8, nada grave.

Prácticas Largas y desafiantes, la cantidad de abandonos que hubo tras la primera no fue despreciable. En la primera se trabajó mucho con redirección de entrada y salida, en la segunda con procesos y su coordinación. Muy divertidas.

Consultor Bueno, se le veía un control de la asignatura importante. Bastante serio, atendía con rapidez y respondía de forma bastante clara.

Exámenes El mío fue un regalazo, no saqué más nota por no entender bien una pregunta (fallo mío, la pregunta era obvia) y por ir con prisas (toda mi vida he sido Billy the Kid haciendo exámenes). Digo lo de regalazo porque la asignatura tiene fama de ser uno de los huesos de la carrera, en parte por el examen, pero en mi caso nada más lejos de la realidad.

Conclusión Muy buena, también hay que decir que este tema me encanta (estoy haciendo ahora la serie de Introduction to OS y Advanced OS en Udacity, para que se entienda que en verdad me gusta). No creo que haga como optativa la asignatura de diseño de OS, pero por falta de créditos optativos.

Gestión de proyectos

Temario

Módulo 1. La gestión de proyectos. Conceptos básicos

Módulo 2. Componentes de la gestión de proyectos: las áreas de conocimiento

Módulo 3. Iniciación del proyecto y trabajos previos

Módulo 4. Planificación del proyecto

Módulo 5. Ejecución del proyecto

Módulo 6. Seguimiento y control del proyecto

Módulo 7. Cierre del proyecto

Módulo 8. El lado humano de la gestión de proyectos

Apuntes Bastante completos y con un caso práctico desarrollado que es sobre lo que se trabaja durante la asignatura.

PACs Muy largas. Mucho. A la primera le dediqué casi 25 horas. Me quedó muy bien la verdad, pero para la segunda fui incapaz de pegarme esa paliza y me le dediqué menos de la mitad de horas. Hay además dos debates, pero que más que debates parecen monólogos. Deberían de replantearlo y hacerlo similar al de Ingeniería del Software, porque al final son casi siempre opiniones sin feedback.

Prácticas Más largas que las PAC, consisten en buscar información en el caso práctico y plantear soluciones a modificaciones e imprevistos sobre el mismo.

Consultor Bastante buena, muy participativa, anima mucho a la gente a comentar y exponer dudas.

Exámenes No hay, solo puede aprobarse mediante evaluación continua.

Conclusión Personalmente me interesa poco este tema, pero tal y como está enfocada se hace bastante llevadera, y de practicar te quedan conceptos e ideas claras de cómo afrontar ciertos problemas. Bien es cierto que no sé hasta qué punto todo lo que se comenta es cierto, puesto que si hay que documentar un proyecto tanto como se dice en los apuntes, se dedicaría probablemente más tiempo a escribir dicha documentación que al desarrollo en sí. Podría verse alguna metodología ágil, demasiado centrado en el PMBOK.

Diseño de bases de datos

Temario

Módulo 1. Introducción al diseño de bases de datos

Módulo 2. Diseño conceptual de bases de datos

Módulo 3. Diseño lógico de bases de datos

Módulo 4. Diseño físico de bases de datos

Módulo 5. Procesamiento de consultas

Apuntes Muy buenos y completos, igual faltan algunos ejemplos más al final de cada tema, pero merecen la pena.

PACs Fáciles y rápidas. Algunas personas se quejaron que la segunda era muy larga (es una especie de simulacro de examen en casa) pero para nada estoy de acuerdo. En dos horas se podía hacer, y una PAC que se puede hacer en dos horas es eso, un regalo.

Prácticas La primera fue muy fácil y corta, la segunda fue difícil y extremadamente larga. Se planteaban algunas consultas en SQL que eran cuasi demenciales, y que no tengo muy claro qué sentido tienen en esta asignatura (pues el tema de consultas se ve en un asignatura anterior).

Consultor Muy buena. Fenomenal, un control de la materia brutal, animando a participar, respondiendo rápido, y con una paciencia de santa: aguantó algunas impertinencias que en muchas ocasiones en mis experiencias universitarias anteriores habrían supuesto algo más que palabras por parte del profesor. Su velocidad a la hora de responder era increíble, algún domingo a las 9 de la mañana tenías la respuesta a una pregunta planteada una hora antes.

Exámenes Fue complicado la verdad, la primera pregunta (diseño conceptual) tuvo algún punto complejo, el resto tenían la dificultad asociada al tema (diseño lógico, normalización, etc). Hubo muchas quejas por parte de compañeros por esa primera pregunta, pero curiosamente nadie se quejó del regalo que fue la segunda (que en 5 minutos te aseguraba dos puntos).

Conclusión Buena asignatura en general, posiblemente la más exigente en mi opinión de las que he cursado este año, pero asequible si se trabaja de forma continua.

Análisis y diseño con patrones

Temario

Módulo 1: Introducción a los patrones

Módulo 2: Catálogo de patrones

Módulo 3: Caso práctico de desarrollo de patrones

Bastante completo, se ven los patrones más clásicos.

Apuntes Muy malos, no por mal explicados, sino por escasos. Con los 80 euros te da para comprarte el GOF y el HFDP.

PACs No muy claras algunas preguntas. Se agradece que en la corrección la respuesta no sea única, y se admitan otras siempre que tengan sentido.

Prácticas Similares a las PAC pero más largas. No se programa absolutamente nada, cuando (al menos a mi entender) parece de sentido común que en una asignatura como esta debería primar la implementación y uso de alguno de estos patrones en algún lenguaje concreto.

Consultor El peor de los que tuve, empezó mal (prácticamente ni aparecía por el foro, tardaba varios días en responder) aunque con el tiempo mejoró. Sentía el hombre una necesidad por responder con terminología típica de esta materia que me recordaba a algún profesor que tuve a principios de siglo hablando de teoría de campos como si estuviese en un universo paralelo. Que no digo que no haya que hablar de forma técnica, pero algunas de las respuestas que daba en el foro eran bastante crípticas.

Exámenes Fácil, ejemplos sencillos parecidos a las PAC. La teoría tiene bastante peso, pero tampoco hay gran cantidad de material, y no son temas conceptualmente complejos.

Conclusión Asignatura optativa para mí, la hice porque sinceramente me encanta. Un poco decepcionado, no se pica código, no hay que saber nada de programación para hacerla (aunque en los prerrequisitos que tiene se diga lo contrario). Un poco desfasado en algunos aspectos, una práctica iba sobre la aplicación del MVC a móviles, cuando prácticamente todo el mundo (creo) usa MVP o MVVM, que son parecidos pero no lo mismo. Aún así, para nada arrepentido, volvería a hacerla, muy entretenida.

Disculpad por la falta de acentos en los títulos, pero para que funcionen con jekyll los enlaces he de eliminarlos de las referencias.   ↩

Haría una comparación con la universidad presencial, pero me parece algo bastante trillado. Esto es un acto de fe. Cada uno habla de lo que sabe y la experiencia que tiene, que suele ser bastante limitada (nadie o casi nadie ha probado cinco carreras distintas para comparar con criterio). Así que lo que yo diga estará tan limitado a mi experiencia como cualquier otro y tendrá validez nula. Personalmente prefiero el sistema de trabajos continuos (lo que plantea Bolonia, lo que sigue la UOC) que el sistema que viví de toma el libro y/o apuntes, toma la bibliografía, ven a clase (no en mi caso), y en enero nos vemos.   ↩

Lógica de primero tiene muy buena fama, el libro electrónico que tienen de la primera parte es muy bueno.   ↩

Para ser justo, esto en la carrera de física no pasa. Salvo contadas excepciones (mecánica clásica, electrónica, y encima son buenos libros), los libros recomendados son siempre literatura externa a la universidad. Te cuesta un dinero, pero al menos te llevas libros muy contrastados. Es un punto que hace a mi entender de física una especie de oasis dentro del mamoneo que supone los materiales en la UNED.   ↩

Zasca histórico, acabo de llegarme, atrevida es la ignorancia. ↩

En España, dentro de nuestra santa idiosincracia, tenemos esta carrera de informática que es un cajón de sastre de bastantes más cosas a parte de programar. Sé por lo tanto que hay gente que cursa la carrera y le interesa cero este tema, pero como a mí es lo que me gusta a veces me es difícil abstraerme.   ↩

Por razones creo que obvias no pondré el nombre de ningún consultor.   ↩

En una pregunta de la segunda PAC jamás habría imaginado lo que se supone que había que suponer por más años que me hubiesen dado, y por lo que se vio en los foros no fui el único. ↩

    Older

    Newer


text:
package com.riversoft.weixin.mp.jsapi;

import com.riversoft.weixin.common.jsapi.JsAPISignature;
import org.junit.Assert;
import org.junit.Test;

/**
 * Created by exizhai on 1/28/2016.
 */
public class JsAPIsTest {

    @Test
    public void testCreateJsAPISignature(){
        JsAPISignature signature = JsAPIs.defaultJsAPIs().createJsAPISignature("http://test.com/test.jsp?abc=123");
        Assert.assertNotNull(signature);
    }
}


text:
import {TalkGroup, TalkGroupMessage, TalkUserMessage, TalkUserHistory, TalkGroupHistory, User} from '../../../db/db';
import * as interfaces from '../../../db/interfaces';
import getAlbumFile from '../../../core/get-album-file';
import createNotification from '../../../core/create-notification';
import event from '../../../event';

/**
 * Talkメッセージを作成します
 * @param app API利用App
 * @param user API利用ユーザー
 * @param userId 宛先のユーザーのID
 * @param text 本文
 * @param fileId 添付ファイルのID
 * @return 作成されたTalkメッセージ
 */
export default function(
	app: interfaces.IApplication,
	user: interfaces.IUser,
	text: string,
	fileId: string = null,
	userId: string = null,
	groupId: string = null
): Promise<Object> {
	if (user === undefined || user === null) {
		return <Promise<any>>Promise.reject('plz-authenticate');
	} else if (user.isSuspended) {
		return <Promise<any>>Promise.reject('access-denied');
	}

	const maxTextLength = 500;
	text = text.trim();

	// ファイルが添付されていないかつテキストも空だったらエラー
	if (fileId === null && (text === undefined || text === null || text === '')) {
		return <Promise<any>>Promise.reject('empty-text');
	}

	if (text.length > maxTextLength) {
		return <Promise<any>>Promise.reject('too-long-text');
	}

	if (userId !== null) {
		const otherpartyId = userId;
		if (otherpartyId === user.id.toString())  {
			return <Promise<any>>Promise.reject('no-yourself');
		}

		return new Promise<Object>((resolve, reject) => {
			// 作成する対象のユーザーが実在するかチェック
			User.findById(otherpartyId, (checkErr: any, recipient: interfaces.IUser) => {
				if (checkErr !== null) {
					return reject(checkErr);
				} else if (recipient === null) {
					return reject('recipient-not-found');
				}

				if (fileId !== null) {
					// ファイルチェック & 取得
					getAlbumFile(user.id, fileId).then(file => {
						createUserMessage(resolve, reject, user, recipient, text, file);
					}, reject);
				} else {
					createUserMessage(resolve, reject, user, recipient, text);
				}
			});
		});
	} else if (groupId !== null) {
		return new Promise<Object>((resolve, reject) => {
			// グループ取得
			TalkGroup.findById(groupId, (checkErr: any, group: interfaces.ITalkGroup) => {
				if (checkErr !== null) {
					return reject(checkErr);
				} else if (group === null) {
					return reject('group-not-found');
				} else if (
					(<any[]>group.members)
					.map(member => member.toString())
					.indexOf(user.id.toString()) === -1
				) {
					return reject('access-denied');
				}

				if (fileId !== null) {
					// ファイルチェック & 取得
					getAlbumFile(user.id, fileId).then(file => {
						createGroupMessage(resolve, reject, user, group, text, file);
					}, reject);
				} else {
					createGroupMessage(resolve, reject, user, group, text);
				}
			});
		});
	} else {
		return <Promise<any>>Promise.reject('empty-destination-query');
	}
}

function createUserMessage(
	resolve: any,
	reject: any,
	me: interfaces.IUser,
	recipient: interfaces.IUser,
	text: string,
	file: interfaces.IAlbumFile = null
): void {
	TalkUserMessage.create({
		user: me.id,
		recipient: recipient.id,
		text,
		file: file !== null ? file.id : null
	}, (createErr: any, createdMessage: interfaces.ITalkUserMessage) => {
		if (createErr !== null) {
			return reject(createErr);
		}

		resolve(createdMessage.toObject());

		event.publishUserTalkMessage(me.id, recipient.id, createdMessage);

		// 履歴を作成しておく(自分)
		TalkUserHistory.findOne({
			type: 'user',
			user: me.id,
			recipient: recipient.id
		}, (findHistoryErr: any, history: interfaces.ITalkUserHistory) => {
			if (findHistoryErr !== null) {
				return;
			}
			if (history === null) {
				TalkUserHistory.create({
					user: me.id,
					recipient: recipient.id,
					message: createdMessage.id
				});
			} else {
				history.updatedAt = <any>Date.now();
				history.message = createdMessage.id;
				history.save();
			}
		});

		// 履歴を作成しておく(相手)
		TalkUserHistory.findOne({
			type: 'user',
			user: recipient.id,
			recipient: me.id
		}, (findHistoryErr: any, history: interfaces.ITalkUserHistory) => {
			if (findHistoryErr !== null) {
				return;
			}
			if (history === null) {
				TalkUserHistory.create({
					user: recipient.id,
					recipient: me.id,
					message: createdMessage.id
				});
			} else {
				history.updatedAt = <any>Date.now();
				history.message = createdMessage.id;
				history.save();
			}
		});

		// 今から3秒後に未読であった場合通知する
		setTimeout(() => {
			TalkUserMessage.findById(createdMessage.id, (reloadErr: any, reloadedMessage: interfaces.ITalkUserMessage) => {
				if (reloadErr !== null) {
					return;
				} else if (reloadedMessage.isRead) {
					return;
				}
				// 通知を作成
				createNotification(null, recipient.id, 'talk-user-message', {
					messageId: createdMessage.id
				});
			});
		}, 3000);
	});
}

function createGroupMessage(
	resolve: any,
	reject: any,
	me: interfaces.IUser,
	group: interfaces.ITalkGroup,
	text: string,
	file: interfaces.IAlbumFile = null
): void {
	TalkGroupMessage.create({
		user: me.id,
		group: group.id,
		text,
		file: file !== null ? file.id : null
	}, (createErr: any, createdMessage: interfaces.ITalkGroupMessage) => {
		if (createErr !== null) {
			return reject(createErr);
		}

		resolve(createdMessage.toObject());

		event.publishGroupTalkMessage(<interfaces.ITalkMessage>createdMessage, group);

		// 履歴を作成しておく
		(<string[]>group.members).forEach(member => {
			TalkGroupHistory.findOne({
				type: 'group',
				user: member,
				group: group.id
			}, (findHistoryErr: any, history: interfaces.ITalkGroupHistory) => {
				if (findHistoryErr !== null) {
					return;
				}
				if (history === null) {
					TalkGroupHistory.create({
						user: member,
						group: group.id,
						message: createdMessage.id
					});
				} else {
					history.updatedAt = <any>Date.now();
					history.message = createdMessage.id;
					history.save();
				}
			});
		});
	});
}